GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/string_bytes.cc Lines: 260 292 89.0 %
Date: 2016-12-18 Branches: 161 213 75.6 %

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
15
    TypeName* new_data = node::UncheckedMalloc<TypeName>(length);
57

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

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

32
    if (str.IsEmpty()) {
83

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


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

22608654
    if (!~a || !~b)
178
      return i;
179
22608647
    buf[i] = (a << 4) | b;
180
  }
181
182
  return i;
183
}
184
185
186
74399
bool StringBytes::GetExternalParts(Isolate* isolate,
187
                                   Local<Value> val,
188
                                   const char** data,
189
                                   size_t* len) {
190
74399
  if (Buffer::HasInstance(val)) {
191
18
    *data = Buffer::Data(val);
192
18
    *len = Buffer::Length(val);
193
18
    return true;
194
  }
195
196
148762
  if (!val->IsString())
197
    return false;
198
199
74381
  Local<String> str = val.As<String>();
200
201
74381
  if (str->IsExternalOneByte()) {
202
    const String::ExternalOneByteStringResource* ext;
203
52
    ext = str->GetExternalOneByteStringResource();
204
52
    *data = ext->data();
205
52
    *len = ext->length();
206
52
    return true;
207
208
74329
  } else if (str->IsExternal()) {
209
    const String::ExternalStringResource* ext;
210
8
    ext = str->GetExternalStringResource();
211
4
    *data = reinterpret_cast<const char*>(ext->data());
212
4
    *len = ext->length() * sizeof(*ext->data());
213
4
    return true;
214
  }
215
216
  return false;
217
}
218
219
220
139
size_t StringBytes::WriteUCS2(char* buf,
221
                              size_t buflen,
222
                              size_t nbytes,
223
                              const char* data,
224
                              Local<String> str,
225
                              int flags,
226
                              size_t* chars_written) {
227
139
  uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
228
229
139
  size_t max_chars = (buflen / sizeof(*dst));
230
  size_t nchars;
231
139
  size_t alignment = reinterpret_cast<uintptr_t>(dst) % sizeof(*dst);
232
139
  if (alignment == 0) {
233
135
    nchars = str->Write(dst, 0, max_chars, flags);
234
135
    *chars_written = nchars;
235
135
    return nchars * sizeof(*dst);
236
  }
237
238
  uint16_t* aligned_dst =
239
4
      reinterpret_cast<uint16_t*>(buf + sizeof(*dst) - alignment);
240
4
  ASSERT_EQ(reinterpret_cast<uintptr_t>(aligned_dst) % sizeof(*dst), 0);
241
242
  // Write all but the last char
243
4
  nchars = str->Write(aligned_dst, 0, max_chars - 1, flags);
244
245
  // Shift everything to unaligned-left
246
8
  memmove(dst, aligned_dst, nchars * sizeof(*dst));
247
248
  // One more char to be written
249
  uint16_t last;
250

4
  if (nchars == max_chars - 1 && str->Write(&last, nchars, 1, flags) != 0) {
251
8
    memcpy(buf + nchars * sizeof(*dst), &last, sizeof(last));
252
4
    nchars++;
253
  }
254
255
4
  *chars_written = nchars;
256
4
  return nchars * sizeof(*dst);
257
}
258
259
260
71250
size_t StringBytes::Write(Isolate* isolate,
261
                          char* buf,
262
                          size_t buflen,
263
                          Local<Value> val,
264
                          enum encoding encoding,
265
                          int* chars_written) {
266
142500
  HandleScope scope(isolate);
267
71250
  const char* data = nullptr;
268
71250
  size_t nbytes = 0;
269
71250
  const bool is_extern = GetExternalParts(isolate, val, &data, &nbytes);
270
71250
  const size_t external_nbytes = nbytes;
271
272
142500
  CHECK(val->IsString() == true);
273
71250
  Local<String> str = val.As<String>();
274
275
71250
  if (nbytes > buflen)
276
2
    nbytes = buflen;
277
278
  int flags = String::HINT_MANY_WRITES_EXPECTED |
279
              String::NO_NULL_TERMINATION |
280
71250
              String::REPLACE_INVALID_UTF8;
281
282

71250
  switch (encoding) {
283
    case ASCII:
284
    case LATIN1:
285

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

140
      if (is_extern && !str->IsOneByte()) {
304
2
        memcpy(buf, data, nbytes);
305
1
        nchars = nbytes / sizeof(uint16_t);
306
      } else {
307
139
        nbytes = WriteUCS2(buf, buflen, nbytes, data, str, flags, &nchars);
308
      }
309
140
      if (chars_written != nullptr)
310
        *chars_written = nchars;
311
312
      // Node's "ucs2" encoding wants LE character data stored in
313
      // the Buffer, so we need to reorder on BE platforms.  See
314
      // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
315
      // encoding specification
316
140
      if (IsBigEndian())
317
        SwapBytes16(buf, nbytes);
318
319
      break;
320
    }
321
322
    case BASE64:
323
102
      if (is_extern) {
324
4
        nbytes = base64_decode(buf, buflen, data, external_nbytes);
325
      } else {
326
196
        String::Value value(str);
327
98
        nbytes = base64_decode(buf, buflen, *value, value.length());
328
      }
329
102
      if (chars_written != nullptr) {
330
        *chars_written = nbytes;
331
      }
332
      break;
333
334
    case HEX:
335
1857
      if (is_extern) {
336
22
        nbytes = hex_decode(buf, buflen, data, external_nbytes);
337
      } else {
338
3670
        String::Value value(str);
339
1835
        nbytes = hex_decode(buf, buflen, *value, value.length());
340
      }
341
1857
      if (chars_written != nullptr) {
342
        *chars_written = nbytes;
343
      }
344
      break;
345
346
    default:
347
      CHECK(0 && "unknown encoding");
348
      break;
349
  }
350
351
142500
  return nbytes;
352
}
353
354
355
439
bool StringBytes::IsValidString(Isolate* isolate,
356
                                Local<String> string,
357
                                enum encoding enc) {
358

503
  if (enc == HEX && string->Length() % 2 != 0)
359
    return false;
360
  // TODO(bnoordhuis) Add BASE64 check?
361
434
  return true;
362
}
363
364
365
// Quick and dirty size calculation
366
// Will always be at least big enough, but may have some extra
367
// UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
368
394941
size_t StringBytes::StorageSize(Isolate* isolate,
369
                                Local<Value> val,
370
                                enum encoding encoding) {
371
789882
  HandleScope scope(isolate);
372
394941
  size_t data_size = 0;
373
394941
  bool is_buffer = Buffer::HasInstance(val);
374
375

394941
  if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) {
376
    return Buffer::Length(val);
377
  }
378
379
394941
  Local<String> str = val->ToString(isolate);
380
381

394941
  switch (encoding) {
382
    case ASCII:
383
    case LATIN1:
384
24673
      data_size = str->Length();
385
24673
      break;
386
387
    case BUFFER:
388
    case UTF8:
389
      // A single UCS2 codepoint never takes up more than 3 utf8 bytes.
390
      // It is an exercise for the caller to decide when a string is
391
      // long enough to justify calling Size() instead of StorageSize()
392
369173
      data_size = 3 * str->Length();
393
369173
      break;
394
395
    case UCS2:
396
1
      data_size = str->Length() * sizeof(uint16_t);
397
1
      break;
398
399
    case BASE64:
400
20
      data_size = base64_decoded_size_fast(str->Length());
401
10
      break;
402
403
    case HEX:
404
1084
      CHECK(str->Length() % 2 == 0 && "invalid hex string length");
405
1084
      data_size = str->Length() / 2;
406
1084
      break;
407
408
    default:
409
      CHECK(0 && "unknown encoding");
410
      break;
411
  }
412
413
  return data_size;
414
}
415
416
417
2653
size_t StringBytes::Size(Isolate* isolate,
418
                         Local<Value> val,
419
                         enum encoding encoding) {
420
5306
  HandleScope scope(isolate);
421
2653
  size_t data_size = 0;
422
2653
  bool is_buffer = Buffer::HasInstance(val);
423
424

2653
  if (is_buffer && (encoding == BUFFER || encoding == LATIN1))
425
    return Buffer::Length(val);
426
427
  const char* data;
428
2653
  if (GetExternalParts(isolate, val, &data, &data_size))
429
45
    return data_size;
430
431
2608
  Local<String> str = val->ToString(isolate);
432
433

2608
  switch (encoding) {
434
    case ASCII:
435
    case LATIN1:
436
16
      data_size = str->Length();
437
16
      break;
438
439
    case BUFFER:
440
    case UTF8:
441
2491
      data_size = str->Utf8Length();
442
2491
      break;
443
444
    case UCS2:
445
96
      data_size = str->Length() * sizeof(uint16_t);
446
96
      break;
447
448
    case BASE64: {
449
6
      String::Value value(str);
450
3
      data_size = base64_decoded_size(*value, value.length());
451
      break;
452
    }
453
454
    case HEX:
455
2
      data_size = str->Length() / 2;
456
2
      break;
457
458
    default:
459
      CHECK(0 && "unknown encoding");
460
      break;
461
  }
462
463
2608
  return data_size;
464
}
465
466
467
468
469
static bool contains_non_ascii_slow(const char* buf, size_t len) {
470

37940
  for (size_t i = 0; i < len; ++i) {
471

17122
    if (buf[i] & 0x80)
472
      return true;
473
  }
474
  return false;
475
}
476
477
478
4319
static bool contains_non_ascii(const char* src, size_t len) {
479
4319
  if (len < 16) {
480
4133
    return contains_non_ascii_slow(src, len);
481
  }
482
483
186
  const unsigned bytes_per_word = sizeof(uintptr_t);
484
186
  const unsigned align_mask = bytes_per_word - 1;
485
186
  const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
486
487
186
  if (unaligned > 0) {
488
51
    const unsigned n = bytes_per_word - unaligned;
489
102
    if (contains_non_ascii_slow(src, n))
490
      return true;
491
34
    src += n;
492
34
    len -= n;
493
  }
494
495
496
#if defined(_WIN64) || defined(_LP64)
497
169
  const uintptr_t mask = 0x8080808080808080ll;
498
#else
499
  const uintptr_t mask = 0x80808080l;
500
#endif
501
502
169
  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
503
504
33557916
  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
505
33557788
    if (srcw[i] & mask)
506
      return true;
507
  }
508
509
128
  const unsigned remainder = len & align_mask;
510
128
  if (remainder > 0) {
511
90
    const size_t offset = len - remainder;
512
180
    if (contains_non_ascii_slow(src + offset, remainder))
513
      return true;
514
  }
515
516
  return false;
517
}
518
519
520
static void force_ascii_slow(const char* src, char* dst, size_t len) {
521


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

34476
  switch (encoding) {
603
    case BUFFER:
604
      {
605
        Local<Object> vbuf =
606
926
            Buffer::Copy(isolate, buf, buflen).ToLocalChecked();
607
926
        return scope.Escape(vbuf);
608
      }
609
610
    case ASCII:
611
4319
      if (contains_non_ascii(buf, buflen)) {
612
61
        char* out = node::UncheckedMalloc(buflen);
613
61
        if (out == nullptr) {
614
          return Local<String>();
615
        }
616
61
        force_ascii(buf, out, buflen);
617
61
        if (buflen < EXTERN_APEX) {
618
61
          val = OneByteString(isolate, out, buflen);
619
61
          free(out);
620
        } else {
621
          val = ExternOneByteString::New(isolate, out, buflen);
622
        }
623
      } else {
624
4258
        if (buflen < EXTERN_APEX)
625
4257
          val = OneByteString(isolate, buf, buflen);
626
        else
627
1
          val = ExternOneByteString::NewFromCopy(isolate, buf, buflen);
628
      }
629
      break;
630
631
    case UTF8:
632
      val = String::NewFromUtf8(isolate,
633
                                buf,
634
                                String::kNormalString,
635
28384
                                buflen);
636
28384
      break;
637
638
    case LATIN1:
639
95
      if (buflen < EXTERN_APEX)
640
87
        val = OneByteString(isolate, buf, buflen);
641
      else
642
8
        val = ExternOneByteString::NewFromCopy(isolate, buf, buflen);
643
      break;
644
645
    case BASE64: {
646
189
      size_t dlen = base64_encoded_size(buflen);
647
189
      char* dst = node::UncheckedMalloc(dlen);
648
189
      if (dst == nullptr) {
649
        return Local<String>();
650
      }
651
652
189
      size_t written = base64_encode(buf, buflen, dst, dlen);
653
189
      CHECK_EQ(written, dlen);
654
655
189
      if (dlen < EXTERN_APEX) {
656
180
        val = OneByteString(isolate, dst, dlen);
657
180
        free(dst);
658
      } else {
659
9
        val = ExternOneByteString::New(isolate, dst, dlen);
660
      }
661
      break;
662
    }
663
664
    case HEX: {
665
1026
      size_t dlen = buflen * 2;
666
1026
      char* dst = node::UncheckedMalloc(dlen);
667
1026
      if (dst == nullptr) {
668
        return Local<String>();
669
      }
670
1026
      size_t written = hex_encode(buf, buflen, dst, dlen);
671
1026
      CHECK_EQ(written, dlen);
672
673
1026
      if (dlen < EXTERN_APEX) {
674
1018
        val = OneByteString(isolate, dst, dlen);
675
1018
        free(dst);
676
      } else {
677
8
        val = ExternOneByteString::New(isolate, dst, dlen);
678
      }
679
      break;
680
    }
681
682
    default:
683
      CHECK(0 && "unknown encoding");
684
      break;
685
  }
686
687
68026
  return scope.Escape(val);
688
}
689
690
691
2697
Local<Value> StringBytes::Encode(Isolate* isolate,
692
                                 const uint16_t* buf,
693
                                 size_t buflen) {
694
  // Node's "ucs2" encoding expects LE character data inside a
695
  // Buffer, so we need to reorder on BE platforms.  See
696
  // http://nodejs.org/api/buffer.html regarding Node's "ucs2"
697
  // encoding specification
698
5394
  std::vector<uint16_t> dst;
699
2697
  if (IsBigEndian()) {
700
    dst.assign(buf, buf + buflen);
701
    size_t nbytes = buflen * sizeof(dst[0]);
702
    SwapBytes16(reinterpret_cast<char*>(&dst[0]), nbytes);
703
    buf = &dst[0];
704
  }
705
706
2697
  Local<String> val;
707
2697
  if (buflen < EXTERN_APEX) {
708
    val = String::NewFromTwoByte(isolate,
709
                                 buf,
710
                                 String::kNormalString,
711
2691
                                 buflen);
712
  } else {
713
6
    val = ExternTwoByteString::NewFromCopy(isolate, buf, buflen);
714
  }
715
716
5394
  return val;
717
}
718
719
7805
Local<Value> StringBytes::Encode(Isolate* isolate,
720
                                 const char* buf,
721
                                 enum encoding encoding) {
722
7805
  const size_t len = strlen(buf);
723
7805
  Local<Value> ret;
724
7805
  if (encoding == UCS2) {
725
    // In Node, UCS2 means utf16le. The data must be in little-endian
726
    // order and must be aligned on 2-bytes. This returns an empty
727
    // value if it's not aligned and ensures the appropriate byte order
728
    // on big endian architectures.
729
1
    const bool be = IsBigEndian();
730
1
    if (len % 2 != 0)
731
      return ret;
732
3
    std::vector<uint16_t> vec(len / 2);
733
3
    for (size_t i = 0, k = 0; i < len; i += 2, k += 1) {
734
2
      const uint8_t hi = static_cast<uint8_t>(buf[i + 0]);
735
2
      const uint8_t lo = static_cast<uint8_t>(buf[i + 1]);
736
4
      vec[k] = be ?
737
          static_cast<uint16_t>(hi) << 8 | lo
738
2
          : static_cast<uint16_t>(lo) << 8 | hi;
739
    }
740
1
    ret = vec.empty() ?
741
        static_cast< Local<Value> >(String::Empty(isolate))
742
2
        : StringBytes::Encode(isolate, &vec[0], vec.size());
743
  } else {
744
7804
    ret = StringBytes::Encode(isolate, buf, len, encoding);
745
  }
746
7805
  return ret;
747
}
748
749
}  // namespace node