blob: 41a06e6348d9651078520fac4c42fefb5b0530d4 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/dartutils.h"
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "platform/assert.h"
#include "platform/globals.h"
#include "bin/extensions.h"
#include "bin/directory.h"
#include "bin/file.h"
#include "bin/io_buffer.h"
#include "bin/utils.h"
#include "bin/socket.h"
namespace dart {
namespace bin {
const char* DartUtils::original_working_directory = NULL;
const char* DartUtils::kDartScheme = "dart:";
const char* DartUtils::kDartExtensionScheme = "dart-ext:";
const char* DartUtils::kAsyncLibURL = "dart:async";
const char* DartUtils::kBuiltinLibURL = "dart:builtin";
const char* DartUtils::kCoreLibURL = "dart:core";
const char* DartUtils::kIOLibURL = "dart:io";
const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
const char* DartUtils::kUriLibURL = "dart:uri";
const char* DartUtils::kHttpScheme = "http:";
const char* DartUtils::kIdFieldName = "_id";
uint8_t DartUtils::magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
static bool IsWindowsHost() {
#if defined(TARGET_OS_WINDOWS)
return true;
#else // defined(TARGET_OS_WINDOWS)
return false;
#endif // defined(TARGET_OS_WINDOWS)
}
const char* DartUtils::MapLibraryUrl(CommandLineOptions* url_mapping,
const char* url_string) {
ASSERT(url_mapping != NULL);
// We need to check if the passed in url is found in the url_mapping array,
// in that case use the mapped entry.
intptr_t len = strlen(url_string);
for (intptr_t idx = 0; idx < url_mapping->count(); idx++) {
const char* url_name = url_mapping->GetArgument(idx);
if (!strncmp(url_string, url_name, len) && (url_name[len] == ',')) {
const char* url_mapped_name = url_name + len + 1;
if (strlen(url_mapped_name) != 0) {
return url_mapped_name; // Found a mapping for this URL.
}
}
}
return NULL; // Did not find a mapping for this URL.
}
int64_t DartUtils::GetIntegerValue(Dart_Handle value_obj) {
ASSERT(Dart_IsInteger(value_obj));
int64_t value = 0;
Dart_Handle result = Dart_IntegerToInt64(value_obj, &value);
ASSERT(!Dart_IsError(result));
return value;
}
intptr_t DartUtils::GetIntptrValue(Dart_Handle value_obj) {
ASSERT(Dart_IsInteger(value_obj));
int64_t value = 0;
Dart_Handle result = Dart_IntegerToInt64(value_obj, &value);
ASSERT(!Dart_IsError(result));
return static_cast<intptr_t>(value);
}
bool DartUtils::GetInt64Value(Dart_Handle value_obj, int64_t* value) {
bool valid = Dart_IsInteger(value_obj);
if (valid) {
Dart_Handle result = Dart_IntegerFitsIntoInt64(value_obj, &valid);
ASSERT(!Dart_IsError(result));
}
if (!valid) return false;
Dart_Handle result = Dart_IntegerToInt64(value_obj, value);
ASSERT(!Dart_IsError(result));
return true;
}
const char* DartUtils::GetStringValue(Dart_Handle str_obj) {
const char* cstring = NULL;
Dart_Handle result = Dart_StringToCString(str_obj, &cstring);
ASSERT(!Dart_IsError(result));
return cstring;
}
bool DartUtils::GetBooleanValue(Dart_Handle bool_obj) {
bool value = false;
Dart_Handle result = Dart_BooleanValue(bool_obj, &value);
ASSERT(!Dart_IsError(result));
return value;
}
void DartUtils::SetIntegerField(Dart_Handle handle,
const char* name,
intptr_t val) {
Dart_Handle result = Dart_SetField(handle,
NewString(name),
Dart_NewInteger(val));
ASSERT(!Dart_IsError(result));
}
intptr_t DartUtils::GetIntegerField(Dart_Handle handle,
const char* name) {
Dart_Handle result = Dart_GetField(handle, NewString(name));
ASSERT(!Dart_IsError(result));
intptr_t value = DartUtils::GetIntegerValue(result);
return value;
}
void DartUtils::SetStringField(Dart_Handle handle,
const char* name,
const char* val) {
Dart_Handle result = Dart_SetField(handle, NewString(name), NewString(val));
ASSERT(!Dart_IsError(result));
}
bool DartUtils::IsDartSchemeURL(const char* url_name) {
static const intptr_t kDartSchemeLen = strlen(kDartScheme);
// If the URL starts with "dart:" then it is considered as a special
// library URL which is handled differently from other URLs.
return (strncmp(url_name, kDartScheme, kDartSchemeLen) == 0);
}
bool DartUtils::IsHttpSchemeURL(const char* url_name) {
static const intptr_t kHttpSchemeLen = strlen(kHttpScheme);
return (strncmp(url_name, kHttpScheme, kHttpSchemeLen) == 0);
}
bool DartUtils::IsDartExtensionSchemeURL(const char* url_name) {
static const intptr_t kDartExtensionSchemeLen = strlen(kDartExtensionScheme);
// If the URL starts with "dartext:" then it is considered as a special
// extension library URL which is handled differently from other URLs.
return
(strncmp(url_name, kDartExtensionScheme, kDartExtensionSchemeLen) == 0);
}
bool DartUtils::IsDartIOLibURL(const char* url_name) {
return (strcmp(url_name, kIOLibURL) == 0);
}
bool DartUtils::IsDartBuiltinLibURL(const char* url_name) {
return (strcmp(url_name, kBuiltinLibURL) == 0);
}
Dart_Handle DartUtils::CanonicalizeURL(CommandLineOptions* url_mapping,
Dart_Handle library,
const char* url_str) {
// Get the url of the including library.
Dart_Handle library_url = Dart_LibraryUrl(library);
if (Dart_IsError(library_url)) {
return Dart_Error("accessing library url failed");
}
if (!Dart_IsString(library_url)) {
return Dart_Error("library url is not a string");
}
const char* library_url_str = NULL;
Dart_Handle result = Dart_StringToCString(library_url, &library_url_str);
if (Dart_IsError(result)) {
return Dart_Error("accessing library url characters failed");
}
if (url_mapping != NULL) {
const char* mapped_library_url_str = MapLibraryUrl(url_mapping,
library_url_str);
if (mapped_library_url_str != NULL) {
library_url_str = mapped_library_url_str;
}
}
// Calculate the canonical path.
const char* canon_url_str = GetCanonicalPath(library_url_str, url_str);
Dart_Handle canon_url = NewString(canon_url_str);
free(const_cast<char*>(canon_url_str));
return canon_url;
}
void* DartUtils::OpenFile(const char* name, bool write) {
File* file = File::Open(name, write ? File::kWriteTruncate : File::kRead);
return reinterpret_cast<void*>(file);
}
void DartUtils::ReadFile(const uint8_t** data,
intptr_t* file_len,
void* stream) {
ASSERT(data != NULL);
ASSERT(file_len != NULL);
ASSERT(stream != NULL);
File* file_stream = reinterpret_cast<File*>(stream);
*file_len = file_stream->Length();
ASSERT(*file_len > 0);
uint8_t* text_buffer = reinterpret_cast<uint8_t*>(malloc(*file_len));
ASSERT(text_buffer != NULL);
if (!file_stream->ReadFully(text_buffer, *file_len)) {
*data = NULL;
*file_len = -1; // Indicates read was not successful.
return;
}
*data = text_buffer;
}
void DartUtils::WriteFile(const void* buffer,
intptr_t num_bytes,
void* stream) {
ASSERT(stream != NULL);
File* file_stream = reinterpret_cast<File*>(stream);
bool bytes_written = file_stream->WriteFully(buffer, num_bytes);
ASSERT(bytes_written);
}
void DartUtils::CloseFile(void* stream) {
delete reinterpret_cast<File*>(stream);
}
static Dart_Handle SingleArgDart_Invoke(Dart_Handle lib, const char* method,
Dart_Handle arg) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = arg;
return Dart_Invoke(lib, DartUtils::NewString(method), kNumArgs, dart_args);
}
// TODO(iposva): Allocate from the zone instead of leaking error string
// here. On the other hand the binary is about to exit anyway.
#define SET_ERROR_MSG(error_msg, format, ...) \
intptr_t len = snprintf(NULL, 0, format, __VA_ARGS__); \
char* msg = reinterpret_cast<char*>(malloc(len + 1)); \
snprintf(msg, len + 1, format, __VA_ARGS__); \
*error_msg = msg
Dart_Handle MakeHttpRequest(Dart_Handle uri, Dart_Handle builtin_lib,
uint8_t** buffer, intptr_t* buffer_len) {
const intptr_t HttpResponseCodeOK = 200;
ASSERT(buffer != NULL);
ASSERT(buffer_len != NULL);
ASSERT(!Dart_HasLivePorts());
SingleArgDart_Invoke(builtin_lib, "_makeHttpRequest", uri);
// Run until all ports to isolate are closed.
Dart_Handle result = Dart_RunLoop();
if (Dart_IsError(result)) {
return result;
}
result = Dart_Invoke(builtin_lib,
DartUtils::NewString("_getHttpRequestResponseCode"),
0,
NULL);
if (Dart_IsError(result)) {
return result;
}
intptr_t responseCode = DartUtils::GetIntegerValue(result);
if (responseCode != HttpResponseCodeOK) {
// Return error.
Dart_Handle responseStatus =
Dart_Invoke(builtin_lib,
DartUtils::NewString("_getHttpRequestStatusString"),
0,
NULL);
if (Dart_IsError(responseStatus)) {
return responseStatus;
}
if (Dart_IsNull(responseStatus)) {
return Dart_Error("HTTP error.");
}
return Dart_Error(DartUtils::GetStringValue(responseStatus));
}
Dart_Handle response =
Dart_Invoke(builtin_lib, DartUtils::NewString("_getHttpRequestResponse"),
0, NULL);
if (Dart_IsError(response)) {
return response;
}
if (Dart_IsString(response)) {
// Received response as string.
uint8_t* responseString = NULL;
intptr_t responseStringLength;
Dart_Handle r = Dart_StringToUTF8(response, &responseString,
&responseStringLength);
if (Dart_IsError(r)) {
*buffer = NULL;
*buffer_len = 0;
return r;
}
// Get payload as bytes.
*buffer_len = responseStringLength;
*buffer = reinterpret_cast<uint8_t*>(malloc(responseStringLength));
memmove(*buffer, responseString, responseStringLength);
} else {
// Received response as list of bytes.
ASSERT(Dart_IsList(response));
// Query list length.
result = Dart_ListLength(response, buffer_len);
if (Dart_IsError(result)) {
*buffer_len = 0;
*buffer = NULL;
return result;
}
// Get payload as bytes.
*buffer = reinterpret_cast<uint8_t*>(malloc(*buffer_len));
result = Dart_ListGetAsBytes(response, 0, *buffer, *buffer_len);
if (Dart_IsError(result)) {
free(*buffer);
*buffer_len = 0;
*buffer = NULL;
return result;
}
}
return result;
}
Dart_Handle DartUtils::ReadStringFromHttp(const char* script_uri) {
Dart_Handle uri = NewString(script_uri);
if (Dart_IsError(uri)) {
return uri;
}
Dart_Handle builtin_lib =
Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
uint8_t* buffer;
intptr_t bufferLen;
Dart_Handle result = MakeHttpRequest(uri, builtin_lib, &buffer, &bufferLen);
if (Dart_IsError(result)) {
return result;
}
Dart_Handle str = Dart_NewStringFromUTF8(buffer,
bufferLen);
free(buffer);
return str;
}
static const uint8_t* ReadFileFully(const char* filename,
intptr_t* file_len,
const char** error_msg) {
*file_len = -1;
void* stream = DartUtils::OpenFile(filename, false);
if (stream == NULL) {
SET_ERROR_MSG(error_msg, "Unable to open file: %s", filename);
return NULL;
}
const uint8_t* text_buffer = NULL;
DartUtils::ReadFile(&text_buffer, file_len, stream);
if (text_buffer == NULL || *file_len == -1) {
*error_msg = "Unable to read file contents";
text_buffer = NULL;
}
DartUtils::CloseFile(stream);
return text_buffer;
}
Dart_Handle DartUtils::ReadStringFromFile(const char* filename) {
const char* error_msg = NULL;
intptr_t len;
const uint8_t* text_buffer = ReadFileFully(filename, &len, &error_msg);
if (text_buffer == NULL) {
return Dart_Error(error_msg);
}
Dart_Handle str = Dart_NewStringFromUTF8(text_buffer, len);
free(const_cast<uint8_t *>(text_buffer));
return str;
}
Dart_Handle DartUtils::SetWorkingDirectory(Dart_Handle builtin_lib) {
Dart_Handle directory = NewString(original_working_directory);
return SingleArgDart_Invoke(builtin_lib, "_setWorkingDirectory", directory);
}
Dart_Handle DartUtils::ResolveScriptUri(Dart_Handle script_uri,
Dart_Handle builtin_lib) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = script_uri;
return Dart_Invoke(builtin_lib,
NewString("_resolveScriptUri"),
kNumArgs,
dart_args);
}
Dart_Handle DartUtils::FilePathFromUri(Dart_Handle script_uri,
Dart_Handle builtin_lib) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = script_uri;
return Dart_Invoke(builtin_lib,
NewString("_filePathFromUri"),
kNumArgs,
dart_args);
}
Dart_Handle DartUtils::ResolveUri(Dart_Handle library_url,
Dart_Handle url,
Dart_Handle builtin_lib) {
const int kNumArgs = 2;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = library_url;
dart_args[1] = url;
return Dart_Invoke(
builtin_lib, NewString("_resolveUri"), kNumArgs, dart_args);
}
Dart_Handle DartUtils::LibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
if (!Dart_IsLibrary(library)) {
return Dart_Error("not a library");
}
if (!Dart_IsString(url)) {
return Dart_Error("url is not a string");
}
const char* url_string = NULL;
Dart_Handle result = Dart_StringToCString(url, &url_string);
if (Dart_IsError(result)) {
return result;
}
Dart_Handle library_url = Dart_LibraryUrl(library);
const char* library_url_string = NULL;
result = Dart_StringToCString(library_url, &library_url_string);
if (Dart_IsError(result)) {
return result;
}
bool is_dart_scheme_url = DartUtils::IsDartSchemeURL(url_string);
bool is_io_library = DartUtils::IsDartIOLibURL(library_url_string);
bool is_dart_extension_url = DartUtils::IsDartExtensionSchemeURL(url_string);
// Handle URI canonicalization requests.
if (tag == Dart_kCanonicalizeUrl) {
// If this is a Dart Scheme URL or 'part' of a io library
// then it is not modified as it will be handled internally.
if (is_dart_scheme_url || is_io_library) {
return url;
}
// Resolve the url within the context of the library's URL.
Dart_Handle builtin_lib =
Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
Dart_Handle library_url = Dart_LibraryUrl(library);
if (Dart_IsError(library_url)) {
return library_url;
}
return ResolveUri(library_url, url, builtin_lib);
}
// Handle 'import' of dart scheme URIs (i.e they start with 'dart:').
if (is_dart_scheme_url) {
if (tag == Dart_kImportTag) {
// Handle imports of other built-in libraries present in the SDK.
if (DartUtils::IsDartIOLibURL(url_string)) {
return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
}
return Dart_Error("The built-in library '%s' is not available"
" on the stand-alone VM.\n", url_string);
} else {
ASSERT(tag == Dart_kSourceTag);
return Dart_Error("Unable to load source '%s' ", url_string);
}
}
// Handle 'part' of IO library.
if (is_io_library) {
if (tag == Dart_kSourceTag) {
return Dart_LoadSource(
library, url, Builtin::PartSource(Builtin::kIOLibrary, url_string));
} else {
ASSERT(tag == Dart_kImportTag);
return Dart_Error("Unable to import '%s' ", url_string);
}
}
// Handle 'import' or 'part' requests for all other URIs.
// Get the file path out of the url.
Dart_Handle builtin_lib =
Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
Dart_Handle file_path = FilePathFromUri(url, builtin_lib);
if (Dart_IsError(file_path)) {
return file_path;
}
Dart_StringToCString(file_path, &url_string);
if (is_dart_extension_url) {
if (tag != Dart_kImportTag) {
return Dart_Error("Dart extensions must use import: '%s'", url_string);
}
return Extensions::LoadExtension(url_string, library);
}
result = DartUtils::LoadSource(NULL,
library,
url,
tag,
url_string);
return result;
}
const uint8_t* DartUtils::SniffForMagicNumber(const uint8_t* text_buffer,
intptr_t* buffer_len,
bool* is_snapshot) {
intptr_t len = sizeof(magic_number);
for (intptr_t i = 0; i < len; i++) {
if (text_buffer[i] != magic_number[i]) {
*is_snapshot = false;
return text_buffer;
}
}
*is_snapshot = true;
ASSERT(*buffer_len > len);
*buffer_len -= len;
return text_buffer + len;
}
void DartUtils::WriteMagicNumber(File* file) {
// Write a magic number and version information into the snapshot file.
bool bytes_written = file->WriteFully(magic_number, sizeof(magic_number));
ASSERT(bytes_written);
}
Dart_Handle DartUtils::LoadScriptHttp(Dart_Handle uri,
Dart_Handle builtin_lib) {
intptr_t len = 0;
uint8_t* buffer = NULL;
Dart_Handle result = MakeHttpRequest(uri, builtin_lib, &buffer, &len);
if (Dart_IsError(result)) {
return result;
}
const uint8_t* payload = buffer;
bool is_snapshot = false;
payload = SniffForMagicNumber(payload, &len, &is_snapshot);
if (is_snapshot) {
return Dart_LoadScriptFromSnapshot(payload, len);
} else {
Dart_Handle source = Dart_NewStringFromUTF8(payload, len);
free(buffer);
if (Dart_IsError(source)) {
return source;
}
return Dart_LoadScript(uri, source, 0, 0);
}
}
Dart_Handle DartUtils::LoadScript(const char* script_uri,
Dart_Handle builtin_lib) {
Dart_Handle resolved_script_uri =
ResolveScriptUri(NewString(script_uri), builtin_lib);
if (Dart_IsError(resolved_script_uri)) {
return resolved_script_uri;
}
// Handle http: requests separately.
if (DartUtils::IsHttpSchemeURL(script_uri)) {
return LoadScriptHttp(resolved_script_uri, builtin_lib);
}
Dart_Handle script_path = DartUtils::FilePathFromUri(resolved_script_uri,
builtin_lib);
if (Dart_IsError(script_path)) {
return script_path;
}
const char* script_path_cstr;
Dart_StringToCString(script_path, &script_path_cstr);
const char* error_msg = NULL;
intptr_t len;
const uint8_t* buffer = ReadFileFully(script_path_cstr,
&len,
&error_msg);
if (buffer == NULL) {
return Dart_Error(error_msg);
}
bool is_snapshot = false;
const uint8_t *payload = SniffForMagicNumber(buffer, &len, &is_snapshot);
Dart_Handle returnValue;
if (is_snapshot) {
returnValue = Dart_LoadScriptFromSnapshot(payload, len);
} else {
Dart_Handle source = Dart_NewStringFromUTF8(buffer, len);
if (Dart_IsError(source)) {
returnValue = source;
} else {
returnValue = Dart_LoadScript(resolved_script_uri, source, 0, 0);
}
}
free(const_cast<uint8_t *>(buffer));
return returnValue;
}
Dart_Handle DartUtils::LoadSource(CommandLineOptions* url_mapping,
Dart_Handle library,
Dart_Handle url,
Dart_LibraryTag tag,
const char* url_string) {
bool is_http_scheme_url = DartUtils::IsHttpSchemeURL(url_string);
if (url_mapping != NULL && IsDartSchemeURL(url_string)) {
const char* mapped_url_string = MapLibraryUrl(url_mapping, url_string);
if (mapped_url_string == NULL) {
return Dart_Error("Do not know how to load %s", url_string);
}
// We have a URL mapping specified, just read the file that the
// URL mapping specifies and load it.
url_string = mapped_url_string;
}
Dart_Handle source;
if (is_http_scheme_url) {
// Read the file over http.
source = DartUtils::ReadStringFromHttp(url_string);
} else {
// Read the file.
source = DartUtils::ReadStringFromFile(url_string);
}
if (Dart_IsError(source)) {
return source; // source contains the error string.
}
// The tag is either an import or a source tag.
// Load it according to the specified tag.
if (tag == Dart_kImportTag) {
// Return library object or an error string.
return Dart_LoadLibrary(url, source);
} else if (tag == Dart_kSourceTag) {
return Dart_LoadSource(library, url, source);
}
return Dart_Error("wrong tag");
}
Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root,
Dart_Handle builtin_lib) {
// Setup the internal library's 'internalPrint' function.
Dart_Handle internal_lib =
Dart_LookupLibrary(NewString("dart:_collection-dev"));
DART_CHECK_VALID(internal_lib);
Dart_Handle print = Dart_Invoke(
builtin_lib, NewString("_getPrintClosure"), 0, NULL);
Dart_Handle result = Dart_SetField(internal_lib,
NewString("_printClosure"),
print);
DART_CHECK_VALID(result);
// Setup the 'timer' factory.
Dart_Handle url = NewString(kAsyncLibURL);
DART_CHECK_VALID(url);
Dart_Handle async_lib = Dart_LookupLibrary(url);
DART_CHECK_VALID(async_lib);
Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
Dart_Handle timer_closure =
Dart_Invoke(io_lib, NewString("_getTimerFactoryClosure"), 0, NULL);
Dart_Handle args[1];
args[0] = timer_closure;
DART_CHECK_VALID(Dart_Invoke(
async_lib, NewString("_setTimerFactoryClosure"), 1, args));
// Setup the corelib 'Uri.base' getter.
Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core"));
DART_CHECK_VALID(corelib);
Dart_Handle uri_base = Dart_Invoke(
builtin_lib, NewString("_getUriBaseClosure"), 0, NULL);
DART_CHECK_VALID(uri_base);
result = Dart_SetField(corelib,
NewString("_uriBaseClosure"),
uri_base);
DART_CHECK_VALID(result);
if (IsWindowsHost()) {
// Set running on Windows flag.
result = Dart_Invoke(builtin_lib, NewString("_setWindows"), 0, NULL);
if (Dart_IsError(result)) {
return result;
}
}
// Set current working directory.
result = SetWorkingDirectory(builtin_lib);
if (Dart_IsError(result)) {
return result;
}
// Set up package root if specified.
if (package_root != NULL) {
result = NewString(package_root);
if (!Dart_IsError(result)) {
const int kNumArgs = 1;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = result;
return Dart_Invoke(builtin_lib,
NewString("_setPackageRoot"),
kNumArgs,
dart_args);
}
}
return result;
}
const char* DartUtils::GetCanonicalPath(const char* reference_dir,
const char* filename) {
if (File::IsAbsolutePath(filename)) {
return strdup(filename);
}
char* canonical_path = File::GetCanonicalPath(reference_dir);
if (canonical_path == NULL) {
canonical_path = strdup(reference_dir);
ASSERT(canonical_path != NULL);
}
ASSERT(File::PathSeparator() != NULL && strlen(File::PathSeparator()) == 1);
char* path_sep = strrchr(canonical_path, File::PathSeparator()[0]);
if (path_sep == NULL) {
// No separator found: Reference is a file in local directory.
free(canonical_path);
return strdup(filename);
}
*path_sep = '\0';
intptr_t len = snprintf(NULL, 0, "%s%s%s",
canonical_path, File::PathSeparator(), filename);
char* absolute_filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT(absolute_filename != NULL);
snprintf(absolute_filename, len + 1, "%s%s%s",
canonical_path, File::PathSeparator(), filename);
free(canonical_path);
canonical_path = File::GetCanonicalPath(absolute_filename);
if (canonical_path == NULL) {
return absolute_filename;
}
free(absolute_filename);
return canonical_path;
}
bool DartUtils::PostNull(Dart_Port port_id) {
// Post a message with just the null object.
return Dart_PostCObject(port_id, CObject::Null()->AsApiCObject());
}
bool DartUtils::PostInt32(Dart_Port port_id, int32_t value) {
// Post a message with the integer value.
int32_t min = 0xc0000000; // -1073741824
int32_t max = 0x3fffffff; // 1073741823
ASSERT(min <= value && value < max);
Dart_CObject object;
object.type = Dart_CObject_kInt32;
object.value.as_int32 = value;
return Dart_PostCObject(port_id, &object);
}
Dart_Handle DartUtils::GetDartType(const char* library_url,
const char* class_name) {
return Dart_GetType(Dart_LookupLibrary(NewString(library_url)),
NewString(class_name), 0, NULL);
}
Dart_Handle DartUtils::NewDartOSError() {
// Extract the current OS error.
OSError os_error;
return NewDartOSError(&os_error);
}
Dart_Handle DartUtils::NewDartOSError(OSError* os_error) {
// Create a dart:io OSError object with the information retrieved from the OS.
Dart_Handle type = GetDartType(kIOLibURL, "OSError");
ASSERT(!Dart_IsError(type));
Dart_Handle args[2];
args[0] = NewString(os_error->message());
args[1] = Dart_NewInteger(os_error->code());
return Dart_New(type, Dart_Null(), 2, args);
}
Dart_Handle DartUtils::NewDartExceptionWithOSError(const char* library_url,
const char* exception_name,
const char* message,
Dart_Handle os_error) {
// Create a Dart Exception object with a message and an OSError.
Dart_Handle type = GetDartType(library_url, exception_name);
ASSERT(!Dart_IsError(type));
Dart_Handle args[2];
args[0] = NewString(message);
args[1] = os_error;
return Dart_New(type, Dart_Null(), 2, args);
}
Dart_Handle DartUtils::NewDartExceptionWithMessage(const char* library_url,
const char* exception_name,
const char* message) {
// Create a Dart Exception object with a message.
Dart_Handle type = GetDartType(library_url, exception_name);
ASSERT(!Dart_IsError(type));
if (message != NULL) {
Dart_Handle args[1];
args[0] = NewString(message);
return Dart_New(type, Dart_Null(), 1, args);
} else {
return Dart_New(type, Dart_Null(), 0, NULL);
}
}
Dart_Handle DartUtils::NewDartArgumentError(const char* message) {
return NewDartExceptionWithMessage(kCoreLibURL,
"ArgumentError",
message);
}
Dart_Handle DartUtils::NewDartIOException(const char* exception_name,
const char* message,
Dart_Handle os_error) {
// Create a dart:io exception object of the given type.
return NewDartExceptionWithOSError(kIOLibURL,
exception_name,
message,
os_error);
}
Dart_Handle DartUtils::NewInternalError(const char* message) {
return NewDartExceptionWithMessage(kCoreLibURL, "_InternalError", message);
}
bool DartUtils::SetOriginalWorkingDirectory() {
original_working_directory = Directory::Current();
return original_working_directory != NULL;
}
// Statically allocated Dart_CObject instances for immutable
// objects. As these will be used by different threads the use of
// these depends on the fact that the marking internally in the
// Dart_CObject structure is not marking simple value objects.
Dart_CObject CObject::api_null_ = { Dart_CObject_kNull , { 0 } };
Dart_CObject CObject::api_true_ = { Dart_CObject_kBool , { true } };
Dart_CObject CObject::api_false_ = { Dart_CObject_kBool, { false } };
CObject CObject::null_ = CObject(&api_null_);
CObject CObject::true_ = CObject(&api_true_);
CObject CObject::false_ = CObject(&api_false_);
CObject* CObject::Null() {
return &null_;
}
CObject* CObject::True() {
return &true_;
}
CObject* CObject::False() {
return &false_;
}
CObject* CObject::Bool(bool value) {
return value ? &true_ : &false_;
}
Dart_CObject* CObject::New(Dart_CObject_Type type, int additional_bytes) {
Dart_CObject* cobject = reinterpret_cast<Dart_CObject*>(
Dart_ScopeAllocate(sizeof(Dart_CObject) + additional_bytes));
cobject->type = type;
return cobject;
}
Dart_CObject* CObject::NewInt32(int32_t value) {
Dart_CObject* cobject = New(Dart_CObject_kInt32);
cobject->value.as_int32 = value;
return cobject;
}
Dart_CObject* CObject::NewInt64(int64_t value) {
Dart_CObject* cobject = New(Dart_CObject_kInt64);
cobject->value.as_int64 = value;
return cobject;
}
Dart_CObject* CObject::NewIntptr(intptr_t value) {
// Pointer values passed as intptr_t are always send as int64_t.
Dart_CObject* cobject = New(Dart_CObject_kInt64);
cobject->value.as_int64 = value;
return cobject;
}
Dart_CObject* CObject::NewDouble(double value) {
Dart_CObject* cobject = New(Dart_CObject_kDouble);
cobject->value.as_double = value;
return cobject;
}
Dart_CObject* CObject::NewString(intptr_t length) {
Dart_CObject* cobject = New(Dart_CObject_kString, length + 1);
cobject->value.as_string = reinterpret_cast<char*>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewString(const char* str) {
intptr_t length = strlen(str);
Dart_CObject* cobject = NewString(length);
memmove(cobject->value.as_string, str, length + 1);
return cobject;
}
Dart_CObject* CObject::NewArray(intptr_t length) {
Dart_CObject* cobject =
New(Dart_CObject_kArray, length * sizeof(Dart_CObject*)); // NOLINT
cobject->value.as_array.length = length;
cobject->value.as_array.values =
reinterpret_cast<Dart_CObject**>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewUint8Array(intptr_t length) {
Dart_CObject* cobject = New(Dart_CObject_kTypedData, length);
cobject->value.as_typed_data.type = Dart_TypedData_kUint8;
cobject->value.as_typed_data.length = length;
cobject->value.as_typed_data.values = reinterpret_cast<uint8_t*>(cobject + 1);
return cobject;
}
Dart_CObject* CObject::NewExternalUint8Array(
intptr_t length, uint8_t* data, void* peer,
Dart_WeakPersistentHandleFinalizer callback) {
Dart_CObject* cobject = New(Dart_CObject_kExternalTypedData);
cobject->value.as_external_typed_data.type = Dart_TypedData_kUint8;
cobject->value.as_external_typed_data.length = length;
cobject->value.as_external_typed_data.data = data;
cobject->value.as_external_typed_data.peer = peer;
cobject->value.as_external_typed_data.callback = callback;
return cobject;
}
Dart_CObject* CObject::NewIOBuffer(int64_t length) {
// Make sure that we do not have an integer overflow here. Actual check
// against max elements will be done at the time of writing, as the constant
// is not part of the public API.
if (length > kIntptrMax) {
return NULL;
}
uint8_t* data = IOBuffer::Allocate(length);
ASSERT(data != NULL);
return NewExternalUint8Array(
static_cast<intptr_t>(length), data, data, IOBuffer::Finalizer);
}
void CObject::FreeIOBufferData(Dart_CObject* cobject) {
ASSERT(cobject->type == Dart_CObject_kExternalTypedData);
cobject->value.as_external_typed_data.callback(
NULL, cobject->value.as_external_typed_data.peer);
cobject->value.as_external_typed_data.data = NULL;
}
CObject* CObject::IllegalArgumentError() {
CObjectArray* result = new CObjectArray(CObject::NewArray(1));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(kArgumentError)));
return result;
}
CObject* CObject::FileClosedError() {
CObjectArray* result = new CObjectArray(CObject::NewArray(1));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(kFileClosedError)));
return result;
}
CObject* CObject::NewOSError() {
OSError os_error;
return NewOSError(&os_error);
}
CObject* CObject::NewOSError(OSError* os_error) {
CObject* error_message =
new CObjectString(CObject::NewString(os_error->message()));
CObjectArray* result = new CObjectArray(CObject::NewArray(3));
result->SetAt(0, new CObjectInt32(CObject::NewInt32(kOSError)));
result->SetAt(1, new CObjectInt32(CObject::NewInt32(os_error->code())));
result->SetAt(2, error_message);
return result;
}
} // namespace bin
} // namespace dart