GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/string_bytes.cc Lines: 249 297 83.8 %
Date: 2016-07-23 Branches: 155 217 71.4 %

Line 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
62
  ~ExternString() override {
32
31
    free(const_cast<TypeName*>(data_));
33
62
    isolate()->AdjustAmountOfExternalAllocatedMemory(-byte_length());
34
124
  }
35
36
96
  const TypeName* data() const override {
37
96
    return data_;
38
  }
39
40
135
  size_t length() const override {
41
135
    return length_;
42
  }
43
44
  int64_t byte_length() const {
45
62
    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
31
  static Local<String> New(Isolate* isolate,
70
                           const TypeName* data,
71
                           size_t length) {
72
62
    EscapableHandleScope scope(isolate);
73
74
31
    if (length == 0)
75
      return scope.Escape(String::Empty(isolate));
76
77
    ExternString* h_str = new ExternString<ResourceType, TypeName>(isolate,
78
                                                                   data,
79
62
                                                                   length);
80
31
    MaybeLocal<String> str = NewExternal(isolate, h_str);
81
62
    isolate->AdjustAmountOfExternalAllocatedMemory(h_str->byte_length());
82
83
31
    if (str.IsEmpty()) {
84
5
      delete h_str;
85
5
      return Local<String>();
86
    }
87
88
26
    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
62
    : 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
25
  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
1452
size_t hex_decode(char* buf,
171
                  size_t len,
172
                  const TypeName* src,
173
                  const size_t srcLen) {
174
  size_t i;
175
2601749
  for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
176
2600304
    unsigned a = unhex(src[i * 2 + 0]);
177
2600304
    unsigned b = unhex(src[i * 2 + 1]);
178
2600304
    if (!~a || !~b)
179
      return i;
180
2600297
    buf[i] = (a << 4) | b;
181
  }
182
183
  return i;
184
}
185
186
187
74207
bool StringBytes::GetExternalParts(Isolate* isolate,
188
                                   Local<Value> val,
189
                                   const char** data,
190
                                   size_t* len) {
191
74207
  if (Buffer::HasInstance(val)) {
192
18
    *data = Buffer::Data(val);
193
18
    *len = Buffer::Length(val);
194
18
    return true;
195
  }
196
197
148378
  if (!val->IsString())
198
    return false;
199
200
74189
  Local<String> str = val.As<String>();
201
202
74189
  if (str->IsExternalOneByte()) {
203
    const String::ExternalOneByteStringResource* ext;
204
12
    ext = str->GetExternalOneByteStringResource();
205
12
    *data = ext->data();
206
12
    *len = ext->length();
207
12
    return true;
208
209
74177
  } 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
153
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
153
  uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
229
230
153
  size_t max_chars = (buflen / sizeof(*dst));
231
  size_t nchars;
232
153
  size_t alignment = reinterpret_cast<uintptr_t>(dst) % sizeof(*dst);
233
153
  if (alignment == 0) {
234
153
    nchars = str->Write(dst, 0, max_chars, flags);
235
153
    *chars_written = nchars;
236
153
    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
71653
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
143306
  HandleScope scope(isolate);
268
71653
  const char* data = nullptr;
269
71653
  size_t nbytes = 0;
270
71653
  const bool is_extern = GetExternalParts(isolate, val, &data, &nbytes);
271
71653
  const size_t external_nbytes = nbytes;
272
273
143306
  CHECK(val->IsString() == true);
274
71653
  Local<String> str = val.As<String>();
275
276
71653
  if (nbytes > buflen)
277
2
    nbytes = buflen;
278
279
  int flags = String::HINT_MANY_WRITES_EXPECTED |
280
              String::NO_NULL_TERMINATION |
281
71653
              String::REPLACE_INVALID_UTF8;
282
283
71653
  switch (encoding) {
284
    case ASCII:
285
    case LATIN1:
286
24573
      if (is_extern && str->IsOneByte()) {
287
1
        memcpy(buf, data, nbytes);
288
      } else {
289
24572
        uint8_t* const dst = reinterpret_cast<uint8_t*>(buf);
290
24572
        nbytes = str->WriteOneByte(dst, 0, buflen, flags);
291
      }
292
24573
      if (chars_written != nullptr)
293
        *chars_written = nbytes;
294
      break;
295
296
    case BUFFER:
297
    case UTF8:
298
45316
      nbytes = str->WriteUtf8(buf, buflen, chars_written, flags);
299
45316
      break;
300
301
    case UCS2: {
302
      size_t nchars;
303
304
154
      if (is_extern && !str->IsOneByte()) {
305
2
        memcpy(buf, data, nbytes);
306
1
        nchars = nbytes / sizeof(uint16_t);
307
      } else {
308
153
        nbytes = WriteUCS2(buf, buflen, nbytes, data, str, flags, &nchars);
309
      }
310
154
      if (chars_written != nullptr)
311
        *chars_written = nchars;
312
313
154
      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
158
      if (is_extern) {
339
4
        nbytes = base64_decode(buf, buflen, data, external_nbytes);
340
      } else {
341
308
        String::Value value(str);
342
154
        nbytes = base64_decode(buf, buflen, *value, value.length());
343
      }
344
158
      if (chars_written != nullptr) {
345
        *chars_written = nbytes;
346
      }
347
      break;
348
349
    case HEX:
350
1452
      if (is_extern) {
351
2
        nbytes = hex_decode(buf, buflen, data, external_nbytes);
352
      } else {
353
2900
        String::Value value(str);
354
1450
        nbytes = hex_decode(buf, buflen, *value, value.length());
355
      }
356
1452
      if (chars_written != nullptr) {
357
        *chars_written = nbytes;
358
      }
359
      break;
360
361
    default:
362
      CHECK(0 && "unknown encoding");
363
      break;
364
  }
365
366
143306
  return nbytes;
367
}
368
369
370
354
bool StringBytes::IsValidString(Isolate* isolate,
371
                                Local<String> string,
372
                                enum encoding enc) {
373
379
  if (enc == HEX && string->Length() % 2 != 0)
374
    return false;
375
  // TODO(bnoordhuis) Add BASE64 check?
376
349
  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
278724
size_t StringBytes::StorageSize(Isolate* isolate,
384
                                Local<Value> val,
385
                                enum encoding encoding) {
386
557448
  HandleScope scope(isolate);
387
278724
  size_t data_size = 0;
388
278724
  bool is_buffer = Buffer::HasInstance(val);
389
390
278724
  if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) {
391
    return Buffer::Length(val);
392
  }
393
394
278724
  Local<String> str = val->ToString(isolate);
395
396
278724
  switch (encoding) {
397
    case ASCII:
398
    case LATIN1:
399
24308
      data_size = str->Length();
400
24308
      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
253364
      data_size = 3 * str->Length();
408
253364
      break;
409
410
    case UCS2:
411
      data_size = str->Length() * sizeof(uint16_t);
412
      break;
413
414
    case BASE64:
415
14
      data_size = base64_decoded_size_fast(str->Length());
416
7
      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
2530
size_t StringBytes::Size(Isolate* isolate,
433
                         Local<Value> val,
434
                         enum encoding encoding) {
435
5060
  HandleScope scope(isolate);
436
2530
  size_t data_size = 0;
437
2530
  bool is_buffer = Buffer::HasInstance(val);
438
439
2530
  if (is_buffer && (encoding == BUFFER || encoding == LATIN1))
440
    return Buffer::Length(val);
441
442
  const char* data;
443
2530
  if (GetExternalParts(isolate, val, &data, &data_size))
444
25
    return data_size;
445
446
2505
  Local<String> str = val->ToString(isolate);
447
448
2505
  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
2388
      data_size = str->Utf8Length();
457
2388
      break;
458
459
    case UCS2:
460
95
      data_size = str->Length() * sizeof(uint16_t);
461
95
      break;
462
463
    case BASE64: {
464
8
      String::Value value(str);
465
4
      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
2505
  return data_size;
479
}
480
481
482
483
484
static bool contains_non_ascii_slow(const char* buf, size_t len) {
485
38087
  for (size_t i = 0; i < len; ++i) {
486
17143
    if (buf[i] & 0x80)
487
      return true;
488
  }
489
  return false;
490
}
491
492
493
4337
static bool contains_non_ascii(const char* src, size_t len) {
494
4337
  if (len < 16) {
495
4169
    return contains_non_ascii_slow(src, len);
496
  }
497
498
168
  const unsigned bytes_per_word = sizeof(uintptr_t);
499
168
  const unsigned align_mask = bytes_per_word - 1;
500
168
  const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
501
502
168
  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
151
  const uintptr_t mask = 0x8080808080808080ll;
513
#else
514
  const uintptr_t mask = 0x80808080l;
515
#endif
516
517
151
  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
518
519
33558587
  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
520
33558477
    if (srcw[i] & mask)
521
      return true;
522
  }
523
524
110
  const unsigned remainder = len & align_mask;
525
110
  if (remainder > 0) {
526
80
    const size_t offset = len - remainder;
527
160
    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
974
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
974
  CHECK(dlen >= slen * 2 &&
590
      "not enough space provided for hex encode");
591
592
  dlen = slen * 2;
593
545201492
  for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
594
    static const char hex[] = "0123456789abcdef";
595
272600259
    uint8_t val = static_cast<uint8_t>(src[i]);
596
272600259
    dst[k + 0] = hex[val >> 4];
597
272600259
    dst[k + 1] = hex[val & 15];
598
  }
599
600
974
  return dlen;
601
}
602
603
604
605
32041
Local<Value> StringBytes::Encode(Isolate* isolate,
606
                                 const char* buf,
607
                                 size_t buflen,
608
                                 enum encoding encoding) {
609
64082
  EscapableHandleScope scope(isolate);
610
611
32041
  CHECK_NE(encoding, UCS2);
612
32041
  CHECK_LE(buflen, Buffer::kMaxLength);
613
32041
  if (!buflen && encoding != BUFFER)
614
    return scope.Escape(String::Empty(isolate));
615
616
32041
  Local<String> val;
617
32041
  switch (encoding) {
618
    case BUFFER:
619
      {
620
        Local<Object> vbuf =
621
832
            Buffer::Copy(isolate, buf, buflen).ToLocalChecked();
622
832
        return scope.Escape(vbuf);
623
      }
624
625
    case ASCII:
626
4337
      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
4278
        if (buflen < EXTERN_APEX)
640
4277
          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
26050
                                buflen);
651
26050
      break;
652
653
    case LATIN1:
654
86
      if (buflen < EXTERN_APEX)
655
78
        val = OneByteString(isolate, buf, buflen);
656
      else
657
8
        val = ExternOneByteString::NewFromCopy(isolate, buf, buflen);
658
      break;
659
660
    case BASE64: {
661
178
      size_t dlen = base64_encoded_size(buflen);
662
178
      char* dst = static_cast<char*>(malloc(dlen));
663
178
      if (dst == nullptr) {
664
        return Local<String>();
665
      }
666
667
178
      size_t written = base64_encode(buf, buflen, dst, dlen);
668
178
      CHECK_EQ(written, dlen);
669
670
178
      if (dlen < EXTERN_APEX) {
671
169
        val = OneByteString(isolate, dst, dlen);
672
169
        free(dst);
673
      } else {
674
9
        val = ExternOneByteString::New(isolate, dst, dlen);
675
      }
676
      break;
677
    }
678
679
    case HEX: {
680
974
      size_t dlen = buflen * 2;
681
974
      char* dst = static_cast<char*>(malloc(dlen));
682
974
      if (dst == nullptr) {
683
        return Local<String>();
684
      }
685
974
      size_t written = hex_encode(buf, buflen, dst, dlen);
686
974
      CHECK_EQ(written, dlen);
687
688
974
      if (dlen < EXTERN_APEX) {
689
967
        val = OneByteString(isolate, dst, dlen);
690
967
        free(dst);
691
      } else {
692
7
        val = ExternOneByteString::New(isolate, dst, dlen);
693
      }
694
      break;
695
    }
696
697
    default:
698
      CHECK(0 && "unknown encoding");
699
      break;
700
  }
701
702
63250
  return scope.Escape(val);
703
}
704
705
706
2674
Local<Value> StringBytes::Encode(Isolate* isolate,
707
                                 const uint16_t* buf,
708
                                 size_t buflen) {
709
2674
  Local<String> val;
710
5348
  std::vector<uint16_t> dst;
711
2674
  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
2674
  if (buflen < EXTERN_APEX) {
721
    val = String::NewFromTwoByte(isolate,
722
                                 buf,
723
                                 String::kNormalString,
724
2668
                                 buflen);
725
  } else {
726
6
    val = ExternTwoByteString::NewFromCopy(isolate, buf, buflen);
727
  }
728
729
5348
  return val;
730
}
731
732
8771
Local<Value> StringBytes::Encode(Isolate* isolate,
733
                                 const char* buf,
734
                                 enum encoding encoding) {
735
8771
  const size_t len = strlen(buf);
736
8771
  Local<Value> ret;
737
8771
  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
8770
    ret = StringBytes::Encode(isolate, buf, len, encoding);
758
  }
759
8771
  return ret;
760
}
761
762
}  // namespace node