Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
string_bytes.cc
Go to the documentation of this file.
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #include "string_bytes.h"
23 
24 #include "base64.h"
25 #include "node.h"
26 #include "node_buffer.h"
27 #include "v8.h"
28 
29 #include <limits.h>
30 #include <string.h> // memcpy
31 #include <vector>
32 
33 // When creating strings >= this length v8's gc spins up and consumes
34 // most of the execution time. For these cases it's more performant to
35 // use external string resources.
36 #define EXTERN_APEX 0xFBEE9
37 
38 // TODO(addaleax): These should all have better error messages. In particular,
39 // they should mention what the actual limits are.
40 #define SB_MALLOC_FAILED_ERROR \
41  v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
42 
43 #define SB_STRING_TOO_LONG_ERROR \
44  v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
45 
46 #define SB_BUFFER_CREATION_ERROR \
47  v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
48 
49 #define SB_BUFFER_SIZE_EXCEEDED_ERROR \
50  v8::Exception::Error(OneByteString(isolate, "\"toString()\" failed"))
51 
52 namespace node {
53 
54 using v8::HandleScope;
55 using v8::Isolate;
56 using v8::Local;
57 using v8::MaybeLocal;
58 using v8::String;
59 using v8::Value;
60 
61 namespace {
62 
63 template <typename ResourceType, typename TypeName>
64 class ExternString: public ResourceType {
65  public:
66  ~ExternString() override {
67  free(const_cast<TypeName*>(data_));
68  isolate()->AdjustAmountOfExternalAllocatedMemory(-byte_length());
69  }
70 
71  const TypeName* data() const override {
72  return data_;
73  }
74 
75  size_t length() const override {
76  return length_;
77  }
78 
79  int64_t byte_length() const {
80  return length() * sizeof(*data());
81  }
82 
83  static MaybeLocal<Value> NewFromCopy(Isolate* isolate,
84  const TypeName* data,
85  size_t length,
86  Local<Value>* error) {
87  if (length == 0)
88  return String::Empty(isolate);
89 
90  if (length < EXTERN_APEX)
91  return NewSimpleFromCopy(isolate, data, length, error);
92 
93  TypeName* new_data = node::UncheckedMalloc<TypeName>(length);
94  if (new_data == nullptr) {
95  *error = SB_MALLOC_FAILED_ERROR;
96  return MaybeLocal<Value>();
97  }
98  memcpy(new_data, data, length * sizeof(*new_data));
99 
101  new_data,
102  length,
103  error);
104  }
105 
106  // uses "data" for external resource, and will be free'd on gc
107  static MaybeLocal<Value> New(Isolate* isolate,
108  TypeName* data,
109  size_t length,
110  Local<Value>* error) {
111  if (length == 0)
112  return String::Empty(isolate);
113 
114  if (length < EXTERN_APEX) {
115  MaybeLocal<Value> str = NewSimpleFromCopy(isolate, data, length, error);
116  free(data);
117  return str;
118  }
119 
120  ExternString* h_str = new ExternString<ResourceType, TypeName>(isolate,
121  data,
122  length);
123  MaybeLocal<Value> str = NewExternal(isolate, h_str);
124  isolate->AdjustAmountOfExternalAllocatedMemory(h_str->byte_length());
125 
126  if (str.IsEmpty()) {
127  delete h_str;
128  *error = SB_STRING_TOO_LONG_ERROR;
129  return MaybeLocal<Value>();
130  }
131 
132  return str.ToLocalChecked();
133  }
134 
135  inline Isolate* isolate() const { return isolate_; }
136 
137  private:
138  ExternString(Isolate* isolate, const TypeName* data, size_t length)
139  : isolate_(isolate), data_(data), length_(length) { }
140  static MaybeLocal<Value> NewExternal(Isolate* isolate,
141  ExternString* h_str);
142 
143  // This method does not actually create ExternString instances.
144  static MaybeLocal<Value> NewSimpleFromCopy(Isolate* isolate,
145  const TypeName* data,
146  size_t length,
147  Local<Value>* error);
148 
149  Isolate* isolate_;
150  const TypeName* data_;
151  size_t length_;
152 };
153 
154 
155 typedef ExternString<String::ExternalOneByteStringResource,
156  char> ExternOneByteString;
157 typedef ExternString<String::ExternalStringResource,
158  uint16_t> ExternTwoByteString;
159 
160 
161 template <>
162 MaybeLocal<Value> ExternOneByteString::NewExternal(
163  Isolate* isolate, ExternOneByteString* h_str) {
164  return String::NewExternalOneByte(isolate, h_str).FromMaybe(Local<Value>());
165 }
166 
167 
168 template <>
169 MaybeLocal<Value> ExternTwoByteString::NewExternal(
170  Isolate* isolate, ExternTwoByteString* h_str) {
171  return String::NewExternalTwoByte(isolate, h_str).FromMaybe(Local<Value>());
172 }
173 
174 template <>
175 MaybeLocal<Value> ExternOneByteString::NewSimpleFromCopy(Isolate* isolate,
176  const char* data,
177  size_t length,
178  Local<Value>* error) {
179  MaybeLocal<String> str =
180  String::NewFromOneByte(isolate,
181  reinterpret_cast<const uint8_t*>(data),
182  v8::NewStringType::kNormal,
183  length);
184  if (str.IsEmpty()) {
185  *error = SB_STRING_TOO_LONG_ERROR;
186  return MaybeLocal<Value>();
187  }
188  return str.ToLocalChecked();
189 }
190 
191 
192 template <>
193 MaybeLocal<Value> ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate,
194  const uint16_t* data,
195  size_t length,
196  Local<Value>* error) {
197  MaybeLocal<String> str =
198  String::NewFromTwoByte(isolate,
199  data,
200  v8::NewStringType::kNormal,
201  length);
202  if (str.IsEmpty()) {
203  *error = SB_STRING_TOO_LONG_ERROR;
204  return MaybeLocal<Value>();
205  }
206  return str.ToLocalChecked();
207 }
208 
209 } // anonymous namespace
210 
211 // supports regular and URL-safe base64
212 const int8_t unbase64_table[256] =
213  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
214  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
215  -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
216  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
217  -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
218  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
219  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
220  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
221  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
222  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
223  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
224  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
225  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
226  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
227  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
228  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
229  };
230 
231 
232 static const int8_t unhex_table[256] =
233  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
234  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
235  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
236  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
237  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
238  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
239  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
240  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
241  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
242  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
243  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
244  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
245  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
246  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
247  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
248  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
249  };
250 
251 static inline unsigned unhex(uint8_t x) {
252  return unhex_table[x];
253 }
254 
255 template <typename TypeName>
256 static size_t hex_decode(char* buf,
257  size_t len,
258  const TypeName* src,
259  const size_t srcLen) {
260  size_t i;
261  for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
262  unsigned a = unhex(src[i * 2 + 0]);
263  unsigned b = unhex(src[i * 2 + 1]);
264  if (!~a || !~b)
265  return i;
266  buf[i] = (a << 4) | b;
267  }
268 
269  return i;
270 }
271 
272 
273 bool StringBytes::GetExternalParts(Local<Value> val,
274  const char** data,
275  size_t* len) {
276  if (Buffer::HasInstance(val)) {
277  *data = Buffer::Data(val);
278  *len = Buffer::Length(val);
279  return true;
280  }
281 
282  if (!val->IsString())
283  return false;
284 
285  Local<String> str = val.As<String>();
286 
287  if (str->IsExternalOneByte()) {
288  const String::ExternalOneByteStringResource* ext;
289  ext = str->GetExternalOneByteStringResource();
290  *data = ext->data();
291  *len = ext->length();
292  return true;
293 
294  } else if (str->IsExternal()) {
295  const String::ExternalStringResource* ext;
296  ext = str->GetExternalStringResource();
297  *data = reinterpret_cast<const char*>(ext->data());
298  *len = ext->length() * sizeof(*ext->data());
299  return true;
300  }
301 
302  return false;
303 }
304 
305 
306 size_t StringBytes::WriteUCS2(char* buf,
307  size_t buflen,
308  Local<String> str,
309  int flags,
310  size_t* chars_written) {
311  uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
312 
313  size_t max_chars = (buflen / sizeof(*dst));
314  size_t nchars;
315  size_t alignment = reinterpret_cast<uintptr_t>(dst) % sizeof(*dst);
316  if (alignment == 0) {
317  nchars = str->Write(dst, 0, max_chars, flags);
318  *chars_written = nchars;
319  return nchars * sizeof(*dst);
320  }
321 
322  uint16_t* aligned_dst =
323  reinterpret_cast<uint16_t*>(buf + sizeof(*dst) - alignment);
324  CHECK_EQ(reinterpret_cast<uintptr_t>(aligned_dst) % sizeof(*dst), 0);
325 
326  // Write all but the last char
327  nchars = str->Write(aligned_dst, 0, max_chars - 1, flags);
328 
329  // Shift everything to unaligned-left
330  memmove(dst, aligned_dst, nchars * sizeof(*dst));
331 
332  // One more char to be written
333  uint16_t last;
334  if (nchars == max_chars - 1 && str->Write(&last, nchars, 1, flags) != 0) {
335  memcpy(buf + nchars * sizeof(*dst), &last, sizeof(last));
336  nchars++;
337  }
338 
339  *chars_written = nchars;
340  return nchars * sizeof(*dst);
341 }
342 
343 
344 size_t StringBytes::Write(Isolate* isolate,
345  char* buf,
346  size_t buflen,
347  Local<Value> val,
348  enum encoding encoding,
349  int* chars_written) {
350  HandleScope scope(isolate);
351  const char* data = nullptr;
352  size_t nbytes = 0;
353  const bool is_extern = GetExternalParts(val, &data, &nbytes);
354  const size_t external_nbytes = nbytes;
355 
356  CHECK(val->IsString() == true);
357  Local<String> str = val.As<String>();
358 
359  if (nbytes > buflen)
360  nbytes = buflen;
361 
362  int flags = String::HINT_MANY_WRITES_EXPECTED |
363  String::NO_NULL_TERMINATION |
364  String::REPLACE_INVALID_UTF8;
365 
366  switch (encoding) {
367  case ASCII:
368  case LATIN1:
369  if (is_extern && str->IsOneByte()) {
370  memcpy(buf, data, nbytes);
371  } else {
372  uint8_t* const dst = reinterpret_cast<uint8_t*>(buf);
373  nbytes = str->WriteOneByte(dst, 0, buflen, flags);
374  }
375  if (chars_written != nullptr)
376  *chars_written = nbytes;
377  break;
378 
379  case BUFFER:
380  case UTF8:
381  nbytes = str->WriteUtf8(buf, buflen, chars_written, flags);
382  break;
383 
384  case UCS2: {
385  size_t nchars;
386 
387  if (is_extern && !str->IsOneByte()) {
388  memcpy(buf, data, nbytes);
389  nchars = nbytes / sizeof(uint16_t);
390  } else {
391  nbytes = WriteUCS2(buf, buflen, str, flags, &nchars);
392  }
393  if (chars_written != nullptr)
394  *chars_written = nchars;
395 
396  // Node's "ucs2" encoding wants LE character data stored in
397  // the Buffer, so we need to reorder on BE platforms. See
398  // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
399  // encoding specification
400  if (IsBigEndian())
401  SwapBytes16(buf, nbytes);
402 
403  break;
404  }
405 
406  case BASE64:
407  if (is_extern) {
408  nbytes = base64_decode(buf, buflen, data, external_nbytes);
409  } else {
410  String::Value value(str);
411  nbytes = base64_decode(buf, buflen, *value, value.length());
412  }
413  if (chars_written != nullptr) {
414  *chars_written = nbytes;
415  }
416  break;
417 
418  case HEX:
419  if (is_extern) {
420  nbytes = hex_decode(buf, buflen, data, external_nbytes);
421  } else {
422  String::Value value(str);
423  nbytes = hex_decode(buf, buflen, *value, value.length());
424  }
425  if (chars_written != nullptr) {
426  *chars_written = nbytes;
427  }
428  break;
429 
430  default:
431  CHECK(0 && "unknown encoding");
432  break;
433  }
434 
435  return nbytes;
436 }
437 
438 
439 bool StringBytes::IsValidString(Local<String> string,
440  enum encoding enc) {
441  if (enc == HEX && string->Length() % 2 != 0)
442  return false;
443  // TODO(bnoordhuis) Add BASE64 check?
444  return true;
445 }
446 
447 
448 // Quick and dirty size calculation
449 // Will always be at least big enough, but may have some extra
450 // UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
451 size_t StringBytes::StorageSize(Isolate* isolate,
452  Local<Value> val,
453  enum encoding encoding) {
454  HandleScope scope(isolate);
455  size_t data_size = 0;
456  bool is_buffer = Buffer::HasInstance(val);
457 
458  if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) {
459  return Buffer::Length(val);
460  }
461 
462  Local<String> str = val->ToString(isolate);
463 
464  switch (encoding) {
465  case ASCII:
466  case LATIN1:
467  data_size = str->Length();
468  break;
469 
470  case BUFFER:
471  case UTF8:
472  // A single UCS2 codepoint never takes up more than 3 utf8 bytes.
473  // It is an exercise for the caller to decide when a string is
474  // long enough to justify calling Size() instead of StorageSize()
475  data_size = 3 * str->Length();
476  break;
477 
478  case UCS2:
479  data_size = str->Length() * sizeof(uint16_t);
480  break;
481 
482  case BASE64:
483  data_size = base64_decoded_size_fast(str->Length());
484  break;
485 
486  case HEX:
487  CHECK(str->Length() % 2 == 0 && "invalid hex string length");
488  data_size = str->Length() / 2;
489  break;
490 
491  default:
492  CHECK(0 && "unknown encoding");
493  break;
494  }
495 
496  return data_size;
497 }
498 
499 
500 size_t StringBytes::Size(Isolate* isolate,
501  Local<Value> val,
502  enum encoding encoding) {
503  HandleScope scope(isolate);
504  size_t data_size = 0;
505  bool is_buffer = Buffer::HasInstance(val);
506 
507  if (is_buffer && (encoding == BUFFER || encoding == LATIN1))
508  return Buffer::Length(val);
509 
510  const char* data;
511  if (GetExternalParts(val, &data, &data_size))
512  return data_size;
513 
514  Local<String> str = val->ToString(isolate);
515 
516  switch (encoding) {
517  case ASCII:
518  case LATIN1:
519  data_size = str->Length();
520  break;
521 
522  case BUFFER:
523  case UTF8:
524  data_size = str->Utf8Length();
525  break;
526 
527  case UCS2:
528  data_size = str->Length() * sizeof(uint16_t);
529  break;
530 
531  case BASE64: {
532  String::Value value(str);
533  data_size = base64_decoded_size(*value, value.length());
534  break;
535  }
536 
537  case HEX:
538  data_size = str->Length() / 2;
539  break;
540 
541  default:
542  CHECK(0 && "unknown encoding");
543  break;
544  }
545 
546  return data_size;
547 }
548 
549 
550 
551 
552 static bool contains_non_ascii_slow(const char* buf, size_t len) {
553  for (size_t i = 0; i < len; ++i) {
554  if (buf[i] & 0x80)
555  return true;
556  }
557  return false;
558 }
559 
560 
561 static bool contains_non_ascii(const char* src, size_t len) {
562  if (len < 16) {
563  return contains_non_ascii_slow(src, len);
564  }
565 
566  const unsigned bytes_per_word = sizeof(uintptr_t);
567  const unsigned align_mask = bytes_per_word - 1;
568  const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
569 
570  if (unaligned > 0) {
571  const unsigned n = bytes_per_word - unaligned;
572  if (contains_non_ascii_slow(src, n))
573  return true;
574  src += n;
575  len -= n;
576  }
577 
578 
579 #if defined(_WIN64) || defined(_LP64)
580  const uintptr_t mask = 0x8080808080808080ll;
581 #else
582  const uintptr_t mask = 0x80808080l;
583 #endif
584 
585  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
586 
587  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
588  if (srcw[i] & mask)
589  return true;
590  }
591 
592  const unsigned remainder = len & align_mask;
593  if (remainder > 0) {
594  const size_t offset = len - remainder;
595  if (contains_non_ascii_slow(src + offset, remainder))
596  return true;
597  }
598 
599  return false;
600 }
601 
602 
603 static void force_ascii_slow(const char* src, char* dst, size_t len) {
604  for (size_t i = 0; i < len; ++i) {
605  dst[i] = src[i] & 0x7f;
606  }
607 }
608 
609 
610 static void force_ascii(const char* src, char* dst, size_t len) {
611  if (len < 16) {
612  force_ascii_slow(src, dst, len);
613  return;
614  }
615 
616  const unsigned bytes_per_word = sizeof(uintptr_t);
617  const unsigned align_mask = bytes_per_word - 1;
618  const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
619  const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
620 
621  if (src_unalign > 0) {
622  if (src_unalign == dst_unalign) {
623  const unsigned unalign = bytes_per_word - src_unalign;
624  force_ascii_slow(src, dst, unalign);
625  src += unalign;
626  dst += unalign;
627  len -= src_unalign;
628  } else {
629  force_ascii_slow(src, dst, len);
630  return;
631  }
632  }
633 
634 #if defined(_WIN64) || defined(_LP64)
635  const uintptr_t mask = ~0x8080808080808080ll;
636 #else
637  const uintptr_t mask = ~0x80808080l;
638 #endif
639 
640  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
641  uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
642 
643  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
644  dstw[i] = srcw[i] & mask;
645  }
646 
647  const unsigned remainder = len & align_mask;
648  if (remainder > 0) {
649  const size_t offset = len - remainder;
650  force_ascii_slow(src + offset, dst + offset, remainder);
651  }
652 }
653 
654 
655 static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
656  // We know how much we'll write, just make sure that there's space.
657  CHECK(dlen >= slen * 2 &&
658  "not enough space provided for hex encode");
659 
660  dlen = slen * 2;
661  for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
662  static const char hex[] = "0123456789abcdef";
663  uint8_t val = static_cast<uint8_t>(src[i]);
664  dst[k + 0] = hex[val >> 4];
665  dst[k + 1] = hex[val & 15];
666  }
667 
668  return dlen;
669 }
670 
671 
672 #define CHECK_BUFLEN_IN_RANGE(len) \
673  do { \
674  if ((len) > Buffer::kMaxLength) { \
675  *error = SB_BUFFER_SIZE_EXCEEDED_ERROR; \
676  return MaybeLocal<Value>(); \
677  } \
678  } while (0)
679 
680 
681 MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
682  const char* buf,
683  size_t buflen,
684  enum encoding encoding,
685  Local<Value>* error) {
686  CHECK_NE(encoding, UCS2);
687  CHECK_BUFLEN_IN_RANGE(buflen);
688 
689  *error = Local<Value>();
690  if (!buflen && encoding != BUFFER) {
691  return String::Empty(isolate);
692  }
693 
694  MaybeLocal<String> val;
695 
696  switch (encoding) {
697  case BUFFER:
698  {
699  auto maybe_buf = Buffer::Copy(isolate, buf, buflen);
700  if (maybe_buf.IsEmpty()) {
701  *error = SB_BUFFER_CREATION_ERROR;
702  return MaybeLocal<Value>();
703  }
704  return maybe_buf.ToLocalChecked();
705  }
706 
707  case ASCII:
708  if (contains_non_ascii(buf, buflen)) {
709  char* out = node::UncheckedMalloc(buflen);
710  if (out == nullptr) {
711  *error = SB_MALLOC_FAILED_ERROR;
712  return MaybeLocal<Value>();
713  }
714  force_ascii(buf, out, buflen);
715  return ExternOneByteString::New(isolate, out, buflen, error);
716  } else {
717  return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
718  }
719 
720  case UTF8:
721  val = String::NewFromUtf8(isolate,
722  buf,
723  v8::NewStringType::kNormal,
724  buflen);
725  if (val.IsEmpty()) {
726  *error = SB_STRING_TOO_LONG_ERROR;
727  return MaybeLocal<Value>();
728  }
729  return val.ToLocalChecked();
730 
731  case LATIN1:
732  return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
733 
734  case BASE64: {
735  size_t dlen = base64_encoded_size(buflen);
736  char* dst = node::UncheckedMalloc(dlen);
737  if (dst == nullptr) {
738  *error = SB_MALLOC_FAILED_ERROR;
739  return MaybeLocal<Value>();
740  }
741 
742  size_t written = base64_encode(buf, buflen, dst, dlen);
743  CHECK_EQ(written, dlen);
744 
745  return ExternOneByteString::New(isolate, dst, dlen, error);
746  }
747 
748  case HEX: {
749  size_t dlen = buflen * 2;
750  char* dst = node::UncheckedMalloc(dlen);
751  if (dst == nullptr) {
752  *error = SB_MALLOC_FAILED_ERROR;
753  return MaybeLocal<Value>();
754  }
755  size_t written = hex_encode(buf, buflen, dst, dlen);
756  CHECK_EQ(written, dlen);
757 
758  return ExternOneByteString::New(isolate, dst, dlen, error);
759  }
760 
761  default:
762  CHECK(0 && "unknown encoding");
763  break;
764  }
765 
766  UNREACHABLE();
767 }
768 
769 
770 MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
771  const uint16_t* buf,
772  size_t buflen,
773  Local<Value>* error) {
774  CHECK_BUFLEN_IN_RANGE(buflen);
775  *error = Local<Value>();
776 
777  // Node's "ucs2" encoding expects LE character data inside a
778  // Buffer, so we need to reorder on BE platforms. See
779  // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
780  // encoding specification
781  std::vector<uint16_t> dst;
782  if (IsBigEndian()) {
783  dst.assign(buf, buf + buflen);
784  size_t nbytes = buflen * sizeof(dst[0]);
785  SwapBytes16(reinterpret_cast<char*>(&dst[0]), nbytes);
786  buf = &dst[0];
787  }
788 
789  return ExternTwoByteString::NewFromCopy(isolate, buf, buflen, error);
790 }
791 
792 MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
793  const char* buf,
794  enum encoding encoding,
795  Local<Value>* error) {
796  const size_t len = strlen(buf);
797  MaybeLocal<Value> ret;
798  if (encoding == UCS2) {
799  // In Node, UCS2 means utf16le. The data must be in little-endian
800  // order and must be aligned on 2-bytes. This returns an empty
801  // value if it's not aligned and ensures the appropriate byte order
802  // on big endian architectures.
803  const bool be = IsBigEndian();
804  if (len % 2 != 0)
805  return ret;
806  std::vector<uint16_t> vec(len / 2);
807  for (size_t i = 0, k = 0; i < len; i += 2, k += 1) {
808  const uint8_t hi = static_cast<uint8_t>(buf[i + 0]);
809  const uint8_t lo = static_cast<uint8_t>(buf[i + 1]);
810  vec[k] = be ?
811  static_cast<uint16_t>(hi) << 8 | lo
812  : static_cast<uint16_t>(lo) << 8 | hi;
813  }
814  ret = vec.empty() ?
815  static_cast< Local<Value> >(String::Empty(isolate))
816  : StringBytes::Encode(isolate, &vec[0], vec.size(), error);
817  } else {
818  ret = StringBytes::Encode(isolate, buf, len, encoding, error);
819  }
820  return ret;
821 }
822 
823 } // namespace node
bool HasInstance(Local< Value > val)
Definition: node_buffer.cc:201
unsigned char * buf
Definition: cares_wrap.cc:483
#define SB_STRING_TOO_LONG_ERROR
Definition: string_bytes.cc:43
int len
Definition: cares_wrap.cc:485
union node::cares_wrap::@8::CaresAsyncData::@0 data
const int8_t unbase64_table[256]
size_t Length(Local< Value > val)
Definition: node_buffer.cc:227
dtrace a
Definition: v8ustack.d:531
#define EXTERN_APEX
Definition: string_bytes.cc:36
encoding
Definition: node.h:322
char * Data(Local< Value > val)
Definition: node_buffer.cc:211
#define SB_BUFFER_CREATION_ERROR
Definition: string_bytes.cc:46
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
dtrace n
Definition: v8ustack.d:531
#define SB_MALLOC_FAILED_ERROR
Definition: string_bytes.cc:40
#define CHECK_BUFLEN_IN_RANGE(len)
NODE_DEPRECATED("Use ParseEncoding(isolate, ...)", inline enum encoding ParseEncoding(v8::Local< v8::Value > encoding_v, enum encoding default_encoding=LATIN1) { return ParseEncoding(v8::Isolate::GetCurrent(), encoding_v, default_encoding);}) NODE_EXTERN void FatalException(v8 NODE_DEPRECATED("Use FatalException(isolate, ...)", inline void FatalException(const v8::TryCatch &try_catch) { return FatalException(v8::Isolate::GetCurrent(), try_catch);}) NODE_EXTERN v8 NODE_EXTERN v8::Local< v8::Value > Encode(v8::Isolate *isolate, const uint16_t *buf, size_t len)
Definition: node.h:350
MaybeLocal< Object > Copy(Isolate *isolate, const char *data, size_t length)
Definition: node_buffer.cc:320