1// Copyright 2010 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/extensions/externalize-string-extension.h"
6
7#include "src/api-inl.h"
8#include "src/handles.h"
9#include "src/isolate.h"
10#include "src/objects-inl.h"
11
12namespace v8 {
13namespace internal {
14
15template <typename Char, typename Base>
16class SimpleStringResource : public Base {
17 public:
18 // Takes ownership of |data|.
19 SimpleStringResource(Char* data, size_t length)
20 : data_(data),
21 length_(length) {}
22
23 ~SimpleStringResource() override { delete[] data_; }
24
25 const Char* data() const override { return data_; }
26
27 size_t length() const override { return length_; }
28
29 private:
30 Char* const data_;
31 const size_t length_;
32};
33
34
35typedef SimpleStringResource<char, v8::String::ExternalOneByteStringResource>
36 SimpleOneByteStringResource;
37typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
38 SimpleTwoByteStringResource;
39
40const char* const ExternalizeStringExtension::kSource =
41 "native function externalizeString();"
42 "native function isOneByteString();"
43 "function x() { return 1; }";
44
45v8::Local<v8::FunctionTemplate>
46ExternalizeStringExtension::GetNativeFunctionTemplate(
47 v8::Isolate* isolate, v8::Local<v8::String> str) {
48 if (strcmp(*v8::String::Utf8Value(isolate, str), "externalizeString") == 0) {
49 return v8::FunctionTemplate::New(isolate,
50 ExternalizeStringExtension::Externalize);
51 } else {
52 DCHECK_EQ(strcmp(*v8::String::Utf8Value(isolate, str), "isOneByteString"),
53 0);
54 return v8::FunctionTemplate::New(isolate,
55 ExternalizeStringExtension::IsOneByte);
56 }
57}
58
59
60void ExternalizeStringExtension::Externalize(
61 const v8::FunctionCallbackInfo<v8::Value>& args) {
62 if (args.Length() < 1 || !args[0]->IsString()) {
63 args.GetIsolate()->ThrowException(
64 v8::String::NewFromUtf8(
65 args.GetIsolate(),
66 "First parameter to externalizeString() must be a string.",
67 NewStringType::kNormal).ToLocalChecked());
68 return;
69 }
70 bool force_two_byte = false;
71 if (args.Length() >= 2) {
72 if (args[1]->IsBoolean()) {
73 force_two_byte = args[1]->BooleanValue(args.GetIsolate());
74 } else {
75 args.GetIsolate()->ThrowException(
76 v8::String::NewFromUtf8(
77 args.GetIsolate(),
78 "Second parameter to externalizeString() must be a boolean.",
79 NewStringType::kNormal).ToLocalChecked());
80 return;
81 }
82 }
83 bool result = false;
84 Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
85 if (!string->SupportsExternalization()) {
86 args.GetIsolate()->ThrowException(
87 v8::String::NewFromUtf8(args.GetIsolate(),
88 "string does not support externalization.",
89 NewStringType::kNormal)
90 .ToLocalChecked());
91 return;
92 }
93 if (string->IsOneByteRepresentation() && !force_two_byte) {
94 uint8_t* data = new uint8_t[string->length()];
95 String::WriteToFlat(*string, data, 0, string->length());
96 SimpleOneByteStringResource* resource = new SimpleOneByteStringResource(
97 reinterpret_cast<char*>(data), string->length());
98 result = Utils::ToLocal(string)->MakeExternal(resource);
99 if (!result) delete resource;
100 } else {
101 uc16* data = new uc16[string->length()];
102 String::WriteToFlat(*string, data, 0, string->length());
103 SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
104 data, string->length());
105 result = Utils::ToLocal(string)->MakeExternal(resource);
106 if (!result) delete resource;
107 }
108 if (!result) {
109 args.GetIsolate()->ThrowException(
110 v8::String::NewFromUtf8(args.GetIsolate(),
111 "externalizeString() failed.",
112 NewStringType::kNormal).ToLocalChecked());
113 return;
114 }
115}
116
117
118void ExternalizeStringExtension::IsOneByte(
119 const v8::FunctionCallbackInfo<v8::Value>& args) {
120 if (args.Length() != 1 || !args[0]->IsString()) {
121 args.GetIsolate()->ThrowException(
122 v8::String::NewFromUtf8(
123 args.GetIsolate(),
124 "isOneByteString() requires a single string argument.",
125 NewStringType::kNormal).ToLocalChecked());
126 return;
127 }
128 bool is_one_byte =
129 Utils::OpenHandle(*args[0].As<v8::String>())->IsOneByteRepresentation();
130 args.GetReturnValue().Set(is_one_byte);
131}
132
133} // namespace internal
134} // namespace v8
135