94502c10ea
Also converts the API to use intptr_t instead of a mixture of int64_t and int. Internally all variable length objects have lengths and maximum values represented as intptr_t (actually Smi ranges). In order to check for these maximum lengths we need to have a common type for 32 and 64 bit platforms. Helping constructs like IOBuffer can still use 64bit lengths, but have to check that there values are actually in the domain of intptr_t as soon as internal objects are created. Addresses issue 4314. BUG= R=asiva@google.com, sgjesse@google.com Review URL: https://codereview.chromium.org//23532048 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27395 260f80e4-7a28-3924-810f-c04153c831b5
1021 lines
32 KiB
C++
1021 lines
32 KiB
C++
// 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.
|
|
int len = strlen(url_string);
|
|
for (int 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("Do not know how to load '%s'", 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 corelib 'print' function.
|
|
Dart_Handle print = Dart_Invoke(
|
|
builtin_lib, NewString("_getPrintClosure"), 0, NULL);
|
|
Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core"));
|
|
Dart_Handle result = Dart_SetField(corelib,
|
|
NewString("_printClosure"),
|
|
print);
|
|
|
|
// 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));
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
void DartUtils::SetOriginalWorkingDirectory() {
|
|
original_working_directory = Directory::Current();
|
|
}
|
|
|
|
|
|
// 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) {
|
|
int 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
|