GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/string_bytes.cc Lines: 251 297 84.5 %
Date: 2016-09-05 Branches: 156 217 71.9 %

Line Branch Exec Source
1
#include "string_bytes.h"
2
3
#include "base64.h"
4
#include "node.h"
5
#include "node_buffer.h"
6
#include "v8.h"
7
8
#include <limits.h>
9
#include <string.h>  // memcpy
10
#include <vector>
11
12
// When creating strings >= this length v8's gc spins up and consumes
13
// most of the execution time. For these cases it's more performant to
14
// use external string resources.
15
#define EXTERN_APEX 0xFBEE9
16
17
namespace node {
18
19
using v8::EscapableHandleScope;
20
using v8::HandleScope;
21
using v8::Isolate;
22
using v8::Local;
23
using v8::MaybeLocal;
24
using v8::Object;
25
using v8::String;
26
using v8::Value;
27
28
template <typename ResourceType, typename TypeName>
29
class ExternString: public ResourceType {
30
 public:
31
64
  ~ExternString() override {
32
32
    free(const_cast<TypeName*>(data_));
33
64
    isolate()->AdjustAmountOfExternalAllocatedMemory(-byte_length());
34
128
  }
35
36
138
  const TypeName* data() const override {
37
138
    return data_;
38
  }
39
40
179
  size_t length() const override {
41
179
    return length_;
42
  }
43
44
  int64_t byte_length() const {
45
64
    return length() * sizeof(*data());
46
  }
47
48
15
  static Local<String> NewFromCopy(Isolate* isolate,
49
                                   const TypeName* data,
50
                                   size_t length) {
51
30
    EscapableHandleScope scope(isolate);
52
53

15
    if (length == 0)
54
      return scope.Escape(String::Empty(isolate));
55
56
    TypeName* new_data =
57
15
        static_cast<TypeName*>(malloc(length * sizeof(*new_data)));
58

15
    if (new_data == nullptr) {
59
      return Local<String>();
60
    }
61
30
    memcpy(new_data, data, length * sizeof(*new_data));
62
63
    return scope.Escape(ExternString<ResourceType, TypeName>::New(isolate,
64
                                                                  new_data,
65
15
                                                                  length));
66
  }
67
68
  // uses "data" for external resource, and will be free'd on gc
69
32
  static Local<String> New(Isolate* isolate,
70
                           const TypeName* data,
71
                           size_t length) {
72
64
    EscapableHandleScope scope(isolate);
73
74

32
    if (length == 0)
75
      return scope.Escape(String::Empty(isolate));
76
77
    ExternString* h_str = new ExternString<ResourceType, TypeName>(isolate,
78
                                                                   data,
79
64
                                                                   length);
80
32
    MaybeLocal<String> str = NewExternal(isolate, h_str);
81
64
    isolate->AdjustAmountOfExternalAllocatedMemory(h_str->byte_length());
82
83

32
    if (str.IsEmpty()) {
84

5
      delete h_str;
85
5
      return Local<String>();
86
    }
87
88
27
    return scope.Escape(str.ToLocalChecked());
89
  }
90
91
  inline Isolate* isolate() const { return isolate_; }
92
93
 private:
94
  ExternString(Isolate* isolate, const TypeName* data, size_t length)
95
64
    : isolate_(isolate), data_(data), length_(length) { }
96
  static MaybeLocal<String> NewExternal(Isolate* isolate,
97
                                        ExternString* h_str);
98
99
  Isolate* isolate_;
100
  const TypeName* data_;
101
  size_t length_;
102
};
103
104
105
typedef ExternString<String::ExternalOneByteStringResource,
106
                     char> ExternOneByteString;
107
typedef ExternString<String::ExternalStringResource,
108
                     uint16_t> ExternTwoByteString;
109
110
111
template <>
112
MaybeLocal<String> ExternOneByteString::NewExternal(
113
    Isolate* isolate, ExternOneByteString* h_str) {
114
26
  return String::NewExternalOneByte(isolate, h_str);
115
}
116
117
118
template <>
119
MaybeLocal<String> ExternTwoByteString::NewExternal(
120
    Isolate* isolate, ExternTwoByteString* h_str) {
121
6
  return String::NewExternalTwoByte(isolate, h_str);
122
}
123
124
125
// supports regular and URL-safe base64
126
const int8_t unbase64_table[256] =
127
  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
128
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
129
    -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
130
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
131
    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
132
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
133
    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
134
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
135
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
136
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
137
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
138
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
139
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
140
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
141
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
142
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
143
  };
144
145
146
static const int8_t unhex_table[256] =
147
  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
148
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
149
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
150
     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
151
    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
152
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
153
    -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
154
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
155
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
156
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
157
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
158
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
159
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
160
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
161
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
162
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
163
  };
164
165
#define unhex(x)                                                              \
166
  static_cast<unsigned>(unhex_table[static_cast<uint8_t>(x)])
167
168
169
template <typename TypeName>
170
1474
size_t hex_decode(char* buf,
171
                  size_t len,
172
                  const TypeName* src,
173
                  const size_t srcLen) {
174
  size_t i;
175


22601659
  for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
176
22600192
    unsigned a = unhex(src[i * 2 + 0]);
177
22600192
    unsigned b = unhex(src[i * 2 + 1]);
178

22600192
    if (!~a || !~b)
179
      return i;
180
22600185
    buf[i] = (a << 4) | b;
181
  }
182
183
  return i;
184
}
185
186
187
78986
bool StringBytes::GetExternalParts(Isolate* isolate,
188
                                   Local<Value> val,
189
                                   const char** data,
190
                                   size_t* len) {
191
78986
  if (Buffer::HasInstance(val)) {
192
18
    *data = Buffer::Data(val);
193
18
    *len = Buffer::Length(val);
194
18
    return true;
195
  }
196
197
157936
  if (!val->IsString())
198
    return false;
199
200
78968
  Local<String> str = val.As<String>();
201
202
78968
  if (str->IsExternalOneByte()) {
203
    const String::ExternalOneByteStringResource* ext;
204
52
    ext = str->GetExternalOneByteStringResource();
205
52
    *data = ext->data();
206
52
    *len = ext->length();
207
52
    return true;
208
209
78916
  } else if (str->IsExternal()) {
210
    const String::ExternalStringResource* ext;
211
8
    ext = str->GetExternalStringResource();
212
4
    *data = reinterpret_cast<const char*>(ext->data());
213
4
    *len = ext->length() * sizeof(*ext->data());
214
4
    return true;
215
  }
216
217
  return false;
218
}
219
220
221
131
size_t StringBytes::WriteUCS2(char* buf,
222
                              size_t buflen,
223
                              size_t nbytes,
224
                              const char* data,
225
                              Local<String> str,
226
                              int flags,
227
                              size_t* chars_written) {
228
131
  uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
229
230
131
  size_t max_chars = (buflen / sizeof(*dst));
231
  size_t nchars;
232
131
  size_t alignment = reinterpret_cast<uintptr_t>(dst) % sizeof(*dst);
233
131
  if (alignment == 0) {
234
131
    nchars = str->Write(dst, 0, max_chars, flags);
235
131
    *chars_written = nchars;
236
131
    return nchars * sizeof(*dst);
237
  }
238
239
  uint16_t* aligned_dst =
240
      reinterpret_cast<uint16_t*>(buf + sizeof(*dst) - alignment);
241
  ASSERT_EQ(reinterpret_cast<uintptr_t>(aligned_dst) % sizeof(*dst), 0);
242
243
  // Write all but the last char
244
  nchars = str->Write(aligned_dst, 0, max_chars - 1, flags);
245
246
  // Shift everything to unaligned-left
247
  memmove(dst, aligned_dst, nchars * sizeof(*dst));
248
249
  // One more char to be written
250
  uint16_t last;
251
  if (nchars == max_chars - 1 && str->Write(&last, nchars, 1, flags) != 0) {
252
    memcpy(buf + nchars * sizeof(*dst), &last, sizeof(last));
253
    nchars++;
254
  }
255
256
  *chars_written = nchars;
257
  return nchars * sizeof(*dst);
258
}
259
260
261
75946
size_t StringBytes::Write(Isolate* isolate,
262
                          char* buf,
263
                          size_t buflen,
264
                          Local<Value> val,
265
                          enum encoding encoding,
266
                          int* chars_written) {
267
151892
  HandleScope scope(isolate);
268
75946
  const char* data = nullptr;
269
75946
  size_t nbytes = 0;
270
75946
  const bool is_extern = GetExternalParts(isolate, val, &data, &nbytes);
271
75946
  const size_t external_nbytes = nbytes;
272
273
151892
  CHECK(val->IsString() == true);
274
75946
  Local<String> str = val.As<String>();
275
276
75946
  if (nbytes > buflen)
277
2
    nbytes = buflen;
278
279
  int flags = String::HINT_MANY_WRITES_EXPECTED |
280
              String::NO_NULL_TERMINATION |
281
75946
              String::REPLACE_INVALID_UTF8;
282
283

75946
  switch (encoding) {
284
    case ASCII:
285
    case LATIN1:
286

24564
      if (is_extern && str->IsOneByte()) {
287
1
        memcpy(buf, data, nbytes);
288
      } else {
289
24563
        uint8_t* const dst = reinterpret_cast<uint8_t*>(buf);
290
24563
        nbytes = str->WriteOneByte(dst, 0, buflen, flags);
291
      }
292
24564
      if (chars_written != nullptr)
293
        *chars_written = nbytes;
294
      break;
295
296
    case BUFFER:
297
    case UTF8:
298
49674
      nbytes = str->WriteUtf8(buf, buflen, chars_written, flags);
299
49674
      break;
300
301
    case UCS2: {
302
      size_t nchars;
303
304

132
      if (is_extern && !str->IsOneByte()) {
305
2
        memcpy(buf, data, nbytes);
306
1
        nchars = nbytes / sizeof(uint16_t);
307
      } else {
308
131
        nbytes = WriteUCS2(buf, buflen, nbytes, data, str, flags, &nchars);
309
      }
310
132
      if (chars_written != nullptr)
311
        *chars_written = nchars;
312
313
132
      if (!IsBigEndian())
314
        break;
315
316
      // Node's "ucs2" encoding wants LE character data stored in
317
      // the Buffer, so we need to reorder on BE platforms.  See
318
      // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
319
      // encoding specification
320
321
      const bool is_aligned =
322
          reinterpret_cast<uintptr_t>(buf) % sizeof(uint16_t);
323
      if (is_aligned) {
324
        uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
325
        SwapBytes(dst, dst, nchars);
326
      }
327
328
      ASSERT_EQ(sizeof(uint16_t), 2);
329
      for (size_t i = 0; i < nchars; i++) {
330
        char tmp = buf[i * 2];
331
        buf[i * 2] = buf[i * 2 + 1];
332
        buf[i * 2 + 1] = tmp;
333
      }
334
      break;
335
    }
336
337
    case BASE64:
338
102
      if (is_extern) {
339
4
        nbytes = base64_decode(buf, buflen, data, external_nbytes);
340
      } else {
341
196
        String::Value value(str);
342
98
        nbytes = base64_decode(buf, buflen, *value, value.length());
343
      }
344
102
      if (chars_written != nullptr) {
345
        *chars_written = nbytes;
346
      }
347
      break;
348
349
    case HEX:
350
1474
      if (is_extern) {
351
22
        nbytes = hex_decode(buf, buflen, data, external_nbytes);
352
      } else {
353
2904
        String::Value value(str);
354
1452
        nbytes = hex_decode(buf, buflen, *value, value.length());
355
      }
356
1474
      if (chars_written != nullptr) {
357
        *chars_written = nbytes;
358
      }
359
      break;
360
361
    default:
362
      CHECK(0 && "unknown encoding");
363
      break;
364
  }
365
366
151892
  return nbytes;
367
}
368
369
370
358
bool StringBytes::IsValidString(Isolate* isolate,
371
                                Local<String> string,
372
                                enum encoding enc) {
373

383
  if (enc == HEX && string->Length() % 2 != 0)
374
    return false;
375
  // TODO(bnoordhuis) Add BASE64 check?
376
353
  return true;
377
}
378
379
380
// Quick and dirty size calculation
381
// Will always be at least big enough, but may have some extra
382
// UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
383
374387
size_t StringBytes::StorageSize(Isolate* isolate,
384
                                Local<Value> val,
385
                                enum encoding encoding) {
386
748774
  HandleScope scope(isolate);
387
374387
  size_t data_size = 0;
388
374387
  bool is_buffer = Buffer::HasInstance(val);
389
390

374387
  if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) {
391
    return Buffer::Length(val);
392
  }
393
394
374387
  Local<String> str = val->ToString(isolate);
395
396

374387
  switch (encoding) {
397
    case ASCII:
398
    case LATIN1:
399
24311
      data_size = str->Length();
400
24311
      break;
401
402
    case BUFFER:
403
    case UTF8:
404
      // A single UCS2 codepoint never takes up more than 3 utf8 bytes.
405
      // It is an exercise for the caller to decide when a string is
406
      // long enough to justify calling Size() instead of StorageSize()
407
349020
      data_size = 3 * str->Length();
408
349020
      break;
409
410
    case UCS2:
411
1
      data_size = str->Length() * sizeof(uint16_t);
412
1
      break;
413
414
    case BASE64:
415
20
      data_size = base64_decoded_size_fast(str->Length());
416
10
      break;
417
418
    case HEX:
419
1045
      CHECK(str->Length() % 2 == 0 && "invalid hex string length");
420
1045
      data_size = str->Length() / 2;
421
1045
      break;
422
423
    default:
424
      CHECK(0 && "unknown encoding");
425
      break;
426
  }
427
428
  return data_size;
429
}
430
431
432
2548
size_t StringBytes::Size(Isolate* isolate,
433
                         Local<Value> val,
434
                         enum encoding encoding) {
435
5096
  HandleScope scope(isolate);
436
2548
  size_t data_size = 0;
437
2548
  bool is_buffer = Buffer::HasInstance(val);
438
439

2548
  if (is_buffer && (encoding == BUFFER || encoding == LATIN1))
440
    return Buffer::Length(val);
441
442
  const char* data;
443
2548
  if (GetExternalParts(isolate, val, &data, &data_size))
444
45
    return data_size;
445
446
2503
  Local<String> str = val->ToString(isolate);
447
448

2503
  switch (encoding) {
449
    case ASCII:
450
    case LATIN1:
451
16
      data_size = str->Length();
452
16
      break;
453
454
    case BUFFER:
455
    case UTF8:
456
2387
      data_size = str->Utf8Length();
457
2387
      break;
458
459
    case UCS2:
460
95
      data_size = str->Length() * sizeof(uint16_t);
461
95
      break;
462
463
    case BASE64: {
464
6
      String::Value value(str);
465
3
      data_size = base64_decoded_size(*value, value.length());
466
      break;
467
    }
468
469
    case HEX:
470
2
      data_size = str->Length() / 2;
471
2
      break;
472
473
    default:
474
      CHECK(0 && "unknown encoding");
475
      break;
476
  }
477
478
2503
  return data_size;
479
}
480
481
482
483
484
static bool contains_non_ascii_slow(const char* buf, size_t len) {
485

37835
  for (size_t i = 0; i < len; ++i) {
486

17050
    if (buf[i] & 0x80)
487
      return true;
488
  }
489
  return false;
490
}
491
492
493
4305
static bool contains_non_ascii(const char* src, size_t len) {
494
4305
  if (len < 16) {
495
4130
    return contains_non_ascii_slow(src, len);
496
  }
497
498
175
  const unsigned bytes_per_word = sizeof(uintptr_t);
499
175
  const unsigned align_mask = bytes_per_word - 1;
500
175
  const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
501
502
175
  if (unaligned > 0) {
503
51
    const unsigned n = bytes_per_word - unaligned;
504
102
    if (contains_non_ascii_slow(src, n))
505
      return true;
506
34
    src += n;
507
34
    len -= n;
508
  }
509
510
511
#if defined(_WIN64) || defined(_LP64)
512
158
  const uintptr_t mask = 0x8080808080808080ll;
513
#else
514
  const uintptr_t mask = 0x80808080l;
515
#endif
516
517
158
  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
518
519
33557860
  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
520
33557743
    if (srcw[i] & mask)
521
      return true;
522
  }
523
524
117
  const unsigned remainder = len & align_mask;
525
117
  if (remainder > 0) {
526
81
    const size_t offset = len - remainder;
527
162
    if (contains_non_ascii_slow(src + offset, remainder))
528
      return true;
529
  }
530
531
  return false;
532
}
533
534
535
static void force_ascii_slow(const char* src, char* dst, size_t len) {
536


4827
  for (size_t i = 0; i < len; ++i) {
537
2408
    dst[i] = src[i] & 0x7f;
538
  }
539
}
540
541
542
59
static void force_ascii(const char* src, char* dst, size_t len) {
543
59
  if (len < 16) {
544
    force_ascii_slow(src, dst, len);
545
    return;
546
  }
547
548
58
  const unsigned bytes_per_word = sizeof(uintptr_t);
549
58
  const unsigned align_mask = bytes_per_word - 1;
550
58
  const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
551
58
  const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
552
553
58
  if (src_unalign > 0) {
554
50
    if (src_unalign == dst_unalign) {
555
      const unsigned unalign = bytes_per_word - src_unalign;
556
      force_ascii_slow(src, dst, unalign);
557
      src += unalign;
558
      dst += unalign;
559
      len -= src_unalign;
560
    } else {
561
      force_ascii_slow(src, dst, len);
562
      return;
563
    }
564
  }
565
566
#if defined(_WIN64) || defined(_LP64)
567
8
  const uintptr_t mask = ~0x8080808080808080ll;
568
#else
569
  const uintptr_t mask = ~0x80808080l;
570
#endif
571
572
8
  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
573
8
  uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
574
575
52
  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
576
44
    dstw[i] = srcw[i] & mask;
577
  }
578
579
8
  const unsigned remainder = len & align_mask;
580
8
  if (remainder > 0) {
581
8
    const size_t offset = len - remainder;
582
8
    force_ascii_slow(src + offset, dst + offset, remainder);
583
  }
584
}
585
586
587
953
static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
588
  // We know how much we'll write, just make sure that there's space.
589
953
  CHECK(dlen >= slen * 2 &&
590
      "not enough space provided for hex encode");
591
592
  dlen = slen * 2;
593
547202107
  for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
594
    static const char hex[] = "0123456789abcdef";
595
273600577
    uint8_t val = static_cast<uint8_t>(src[i]);
596
273600577
    dst[k + 0] = hex[val >> 4];
597
273600577
    dst[k + 1] = hex[val & 15];
598
  }
599
600
953
  return dlen;
601
}
602
603
604
605
30975
Local<Value> StringBytes::Encode(Isolate* isolate,
606
                                 const char* buf,
607
                                 size_t buflen,
608
                                 enum encoding encoding) {
609
61950
  EscapableHandleScope scope(isolate);
610
611
30975
  CHECK_NE(encoding, UCS2);
612
30975
  CHECK_LE(buflen, Buffer::kMaxLength);
613
30975
  if (!buflen && encoding != BUFFER)
614
    return scope.Escape(String::Empty(isolate));
615
616
30975
  Local<String> val;
617

30975
  switch (encoding) {
618
    case BUFFER:
619
      {
620
        Local<Object> vbuf =
621
932
            Buffer::Copy(isolate, buf, buflen).ToLocalChecked();
622
932
        return scope.Escape(vbuf);
623
      }
624
625
    case ASCII:
626
4305
      if (contains_non_ascii(buf, buflen)) {
627
59
        char* out = static_cast<char*>(malloc(buflen));
628
59
        if (out == nullptr) {
629
          return Local<String>();
630
        }
631
59
        force_ascii(buf, out, buflen);
632
59
        if (buflen < EXTERN_APEX) {
633
59
          val = OneByteString(isolate, out, buflen);
634
59
          free(out);
635
        } else {
636
          val = ExternOneByteString::New(isolate, out, buflen);
637
        }
638
      } else {
639
4246
        if (buflen < EXTERN_APEX)
640
4245
          val = OneByteString(isolate, buf, buflen);
641
        else
642
1
          val = ExternOneByteString::NewFromCopy(isolate, buf, buflen);
643
      }
644
      break;
645
646
    case UTF8:
647
      val = String::NewFromUtf8(isolate,
648
                                buf,
649
                                String::kNormalString,
650
24970
                                buflen);
651
24970
      break;
652
653
    case LATIN1:
654
93
      if (buflen < EXTERN_APEX)
655
85
        val = OneByteString(isolate, buf, buflen);
656
      else
657
8
        val = ExternOneByteString::NewFromCopy(isolate, buf, buflen);
658
      break;
659
660
    case BASE64: {
661
188
      size_t dlen = base64_encoded_size(buflen);
662
188
      char* dst = static_cast<char*>(malloc(dlen));
663
188
      if (dst == nullptr) {
664
        return Local<String>();
665
      }
666
667
188
      size_t written = base64_encode(buf, buflen, dst, dlen);
668
188
      CHECK_EQ(written, dlen);
669
670
188
      if (dlen < EXTERN_APEX) {
671
179
        val = OneByteString(isolate, dst, dlen);
672
179
        free(dst);
673
      } else {
674
9
        val = ExternOneByteString::New(isolate, dst, dlen);
675
      }
676
      break;
677
    }
678
679
    case HEX: {
680
953
      size_t dlen = buflen * 2;
681
953
      char* dst = static_cast<char*>(malloc(dlen));
682
953
      if (dst == nullptr) {
683
        return Local<String>();
684
      }
685
953
      size_t written = hex_encode(buf, buflen, dst, dlen);
686
953
      CHECK_EQ(written, dlen);
687
688
953
      if (dlen < EXTERN_APEX) {
689
945
        val = OneByteString(isolate, dst, dlen);
690
945
        free(dst);
691
      } else {
692
8
        val = ExternOneByteString::New(isolate, dst, dlen);
693
      }
694
      break;
695
    }
696
697
    default:
698
      CHECK(0 && "unknown encoding");
699
      break;
700
  }
701
702
61018
  return scope.Escape(val);
703
}
704
705
706
2690
Local<Value> StringBytes::Encode(Isolate* isolate,
707
                                 const uint16_t* buf,
708
                                 size_t buflen) {
709
2690
  Local<String> val;
710
5380
  std::vector<uint16_t> dst;
711
2690
  if (IsBigEndian()) {
712
    // Node's "ucs2" encoding expects LE character data inside a
713
    // Buffer, so we need to reorder on BE platforms.  See
714
    // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
715
    // encoding specification
716
    dst.resize(buflen);
717
    SwapBytes(&dst[0], buf, buflen);
718
    buf = &dst[0];
719
  }
720
2690
  if (buflen < EXTERN_APEX) {
721
    val = String::NewFromTwoByte(isolate,
722
                                 buf,
723
                                 String::kNormalString,
724
2684
                                 buflen);
725
  } else {
726
6
    val = ExternTwoByteString::NewFromCopy(isolate, buf, buflen);
727
  }
728
729
5380
  return val;
730
}
731
732
5181
Local<Value> StringBytes::Encode(Isolate* isolate,
733
                                 const char* buf,
734
                                 enum encoding encoding) {
735
5181
  const size_t len = strlen(buf);
736
5181
  Local<Value> ret;
737
5181
  if (encoding == UCS2) {
738
    // In Node, UCS2 means utf16le. The data must be in little-endian
739
    // order and must be aligned on 2-bytes. This returns an empty
740
    // value if it's not aligned and ensures the appropriate byte order
741
    // on big endian architectures.
742
1
    const bool be = IsBigEndian();
743
1
    if (len % 2 != 0)
744
      return ret;
745
3
    std::vector<uint16_t> vec(len / 2);
746
3
    for (size_t i = 0, k = 0; i < len; i += 2, k += 1) {
747
2
      const uint8_t hi = static_cast<uint8_t>(buf[i + 0]);
748
2
      const uint8_t lo = static_cast<uint8_t>(buf[i + 1]);
749
4
      vec[k] = be ?
750
          static_cast<uint16_t>(hi) << 8 | lo
751
2
          : static_cast<uint16_t>(lo) << 8 | hi;
752
    }
753
1
    ret = vec.empty() ?
754
        static_cast< Local<Value> >(String::Empty(isolate))
755
2
        : StringBytes::Encode(isolate, &vec[0], vec.size());
756
  } else {
757
5180
    ret = StringBytes::Encode(isolate, buf, len, encoding);
758
  }
759
5181
  return ret;
760
}
761
762
}  // namespace node