The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / src / string_bytes.cc @ f230a1cf

History | View | Annotate | Download (19.3 KB)

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 "node.h"
25
#include "node_buffer.h"
26
#include "v8.h"
27

    
28
#include <assert.h>
29
#include <limits.h>
30
#include <string.h>  // memcpy
31

    
32
// When creating strings >= this length v8's gc spins up and consumes
33
// most of the execution time. For these cases it's more performant to
34
// use external string resources.
35
#define EXTERN_APEX 0xFBEE9
36

    
37
namespace node {
38

    
39
using v8::Handle;
40
using v8::HandleScope;
41
using v8::Local;
42
using v8::String;
43
using v8::Value;
44

    
45

    
46
template <typename ResourceType, typename TypeName>
47
class ExternString: public ResourceType {
48
  public:
49
    ~ExternString() {
50
      delete[] data_;
51
      node_isolate->AdjustAmountOfExternalAllocatedMemory(-length_);
52
    }
53

    
54
    const TypeName* data() const {
55
      return data_;
56
    }
57

    
58
    size_t length() const {
59
      return length_;
60
    }
61

    
62
    static Local<String> NewFromCopy(const TypeName* data, size_t length) {
63
      HandleScope scope(node_isolate);
64

    
65
      if (length == 0)
66
        return scope.Close(String::Empty(node_isolate));
67

    
68
      TypeName* new_data = new TypeName[length];
69
      memcpy(new_data, data, length * sizeof(*new_data));
70

    
71
      return scope.Close(ExternString<ResourceType, TypeName>::New(new_data,
72
                                                                   length));
73
    }
74

    
75
    // uses "data" for external resource, and will be free'd on gc
76
    static Local<String> New(const TypeName* data, size_t length) {
77
      HandleScope scope(node_isolate);
78

    
79
      if (length == 0)
80
        return scope.Close(String::Empty(node_isolate));
81

    
82
      ExternString* h_str = new ExternString<ResourceType, TypeName>(data,
83
                                                                     length);
84
      Local<String> str = String::NewExternal(h_str);
85
      node_isolate->AdjustAmountOfExternalAllocatedMemory(length);
86

    
87
      return scope.Close(str);
88
    }
89

    
90
  private:
91
    ExternString(const TypeName* data, size_t length)
92
      : data_(data), length_(length) { }
93
    const TypeName* data_;
94
    size_t length_;
95
};
96

    
97

    
98
typedef ExternString<String::ExternalAsciiStringResource,
99
                     char> ExternOneByteString;
100
typedef ExternString<String::ExternalStringResource,
101
                     uint16_t> ExternTwoByteString;
102

    
103

    
104
//// Base 64 ////
105

    
106
#define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4)
107

    
108

    
109
// Doesn't check for padding at the end.  Can be 1-2 bytes over.
110
static inline size_t base64_decoded_size_fast(size_t size) {
111
  size_t remainder = size % 4;
112

    
113
  size = (size / 4) * 3;
114
  if (remainder) {
115
    if (size == 0 && remainder == 1) {
116
      // special case: 1-byte input cannot be decoded
117
      size = 0;
118
    } else {
119
      // non-padded input, add 1 or 2 extra bytes
120
      size += 1 + (remainder == 3);
121
    }
122
  }
123

    
124
  return size;
125
}
126

    
127
template <typename TypeName>
128
size_t base64_decoded_size(const TypeName* src, size_t size) {
129
  if (size == 0)
130
    return 0;
131

    
132
  if (src[size - 1] == '=')
133
    size--;
134
  if (size > 0 && src[size - 1] == '=')
135
    size--;
136

    
137
  return base64_decoded_size_fast(size);
138
}
139

    
140

    
141
// supports regular and URL-safe base64
142
static const int unbase64_table[] =
143
  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
144
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
145
    -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
146
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
147
    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
148
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
149
    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
150
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
151
    -1, -1, -1, -1, -1, -1, -1, -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, -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
  };
160
#define unbase64(x) unbase64_table[(uint8_t)(x)]
161

    
162

    
163
template <typename TypeName>
164
size_t base64_decode(char* buf,
165
                     size_t len,
166
                     const TypeName* src,
167
                     const size_t srcLen) {
168
  char a, b, c, d;
169
  char* dst = buf;
170
  char* dstEnd = buf + len;
171
  const TypeName* srcEnd = src + srcLen;
172

    
173
  while (src < srcEnd && dst < dstEnd) {
174
    int remaining = srcEnd - src;
175

    
176
    while (unbase64(*src) < 0 && src < srcEnd)
177
      src++, remaining--;
178
    if (remaining == 0 || *src == '=')
179
      break;
180
    a = unbase64(*src++);
181

    
182
    while (unbase64(*src) < 0 && src < srcEnd)
183
      src++, remaining--;
184
    if (remaining <= 1 || *src == '=')
185
      break;
186
    b = unbase64(*src++);
187

    
188
    *dst++ = (a << 2) | ((b & 0x30) >> 4);
189
    if (dst == dstEnd)
190
      break;
191

    
192
    while (unbase64(*src) < 0 && src < srcEnd)
193
      src++, remaining--;
194
    if (remaining <= 2 || *src == '=')
195
      break;
196
    c = unbase64(*src++);
197

    
198
    *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
199
    if (dst == dstEnd)
200
      break;
201

    
202
    while (unbase64(*src) < 0 && src < srcEnd)
203
      src++, remaining--;
204
    if (remaining <= 3 || *src == '=')
205
      break;
206
    d = unbase64(*src++);
207

    
208
    *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
209
  }
210

    
211
  return dst - buf;
212
}
213

    
214

    
215
//// HEX ////
216

    
217
template <typename TypeName>
218
unsigned hex2bin(TypeName c) {
219
  if (c >= '0' && c <= '9')
220
    return c - '0';
221
  if (c >= 'A' && c <= 'F')
222
    return 10 + (c - 'A');
223
  if (c >= 'a' && c <= 'f')
224
    return 10 + (c - 'a');
225
  return static_cast<unsigned>(-1);
226
}
227

    
228

    
229
template <typename TypeName>
230
size_t hex_decode(char* buf,
231
                  size_t len,
232
                  const TypeName* src,
233
                  const size_t srcLen) {
234
  size_t i;
235
  for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
236
    unsigned a = hex2bin(src[i * 2 + 0]);
237
    unsigned b = hex2bin(src[i * 2 + 1]);
238
    if (!~a || !~b)
239
      return i;
240
    buf[i] = a * 16 + b;
241
  }
242

    
243
  return i;
244
}
245

    
246

    
247
bool StringBytes::GetExternalParts(Handle<Value> val,
248
                                   const char** data,
249
                                   size_t* len) {
250
  if (Buffer::HasInstance(val)) {
251
    *data = Buffer::Data(val);
252
    *len = Buffer::Length(val);
253
    return true;
254
  }
255

    
256
  if (!val->IsString())
257
    return false;
258

    
259
  Local<String> str = val.As<String>();
260

    
261
  if (str->IsExternalAscii()) {
262
    const String::ExternalAsciiStringResource* ext;
263
    ext = str->GetExternalAsciiStringResource();
264
    *data = ext->data();
265
    *len = ext->length();
266
    return true;
267

    
268
  } else if (str->IsExternal()) {
269
    const String::ExternalStringResource* ext;
270
    ext = str->GetExternalStringResource();
271
    *data = reinterpret_cast<const char*>(ext->data());
272
    *len = ext->length();
273
    return true;
274
  }
275

    
276
  return false;
277
}
278

    
279

    
280
size_t StringBytes::Write(char* buf,
281
                          size_t buflen,
282
                          Handle<Value> val,
283
                          enum encoding encoding,
284
                          int* chars_written) {
285
  HandleScope scope(node_isolate);
286
  const char* data;
287
  size_t len = 0;
288
  bool is_extern = GetExternalParts(val, &data, &len);
289

    
290
  Local<String> str = val.As<String>();
291
  len = len < buflen ? len : buflen;
292

    
293
  int flags = String::NO_NULL_TERMINATION |
294
              String::HINT_MANY_WRITES_EXPECTED;
295

    
296
  switch (encoding) {
297
    case ASCII:
298
    case BINARY:
299
    case BUFFER:
300
      if (is_extern)
301
        memcpy(buf, data, len);
302
      else
303
        len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
304
                                0,
305
                                buflen,
306
                                flags);
307
      if (chars_written != NULL)
308
        *chars_written = len;
309
      break;
310

    
311
    case UTF8:
312
      if (is_extern)
313
        memcpy(buf, data, len);
314
      else
315
        len = str->WriteUtf8(buf, buflen, chars_written, flags);
316
      break;
317

    
318
    case UCS2:
319
      if (is_extern)
320
        memcpy(buf, data, len * 2);
321
      else
322
        len = str->Write(reinterpret_cast<uint16_t*>(buf), 0, buflen, flags);
323
      if (chars_written != NULL)
324
        *chars_written = len;
325
      len = len * sizeof(uint16_t);
326
      break;
327

    
328
    case BASE64:
329
      if (is_extern) {
330
        base64_decode(buf, buflen, data, len);
331
      } else {
332
        String::Value value(str);
333
        len = base64_decode(buf, buflen, *value, value.length());
334
      }
335
      if (chars_written != NULL) {
336
        *chars_written = len;
337
      }
338
      break;
339

    
340
    case HEX:
341
      if (is_extern) {
342
        hex_decode(buf, buflen, data, len);
343
      } else {
344
        String::Value value(str);
345
        len = hex_decode(buf, buflen, *value, value.length());
346
      }
347
      if (chars_written != NULL) {
348
        *chars_written = len * 2;
349
      }
350
      break;
351

    
352
    default:
353
      assert(0 && "unknown encoding");
354
      break;
355
  }
356

    
357
  return len;
358
}
359

    
360

    
361
bool StringBytes::IsValidString(Handle<String> string, enum encoding enc) {
362
  if (enc == HEX && string->Length() % 2 != 0)
363
    return false;
364
  // TODO(bnoordhuis) Add BASE64 check?
365
  return true;
366
}
367

    
368

    
369
// Quick and dirty size calculation
370
// Will always be at least big enough, but may have some extra
371
// UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
372
size_t StringBytes::StorageSize(Handle<Value> val, enum encoding encoding) {
373
  HandleScope scope(node_isolate);
374
  size_t data_size = 0;
375
  bool is_buffer = Buffer::HasInstance(val);
376

    
377
  if (is_buffer && (encoding == BUFFER || encoding == BINARY)) {
378
    return Buffer::Length(val);
379
  }
380

    
381
  Local<String> str = val->ToString();
382

    
383
  switch (encoding) {
384
    case BINARY:
385
    case BUFFER:
386
    case ASCII:
387
      data_size = str->Length();
388
      break;
389

    
390
    case UTF8:
391
      // A single UCS2 codepoint never takes up more than 3 utf8 bytes.
392
      // It is an exercise for the caller to decide when a string is
393
      // long enough to justify calling Size() instead of StorageSize()
394
      data_size = 3 * str->Length();
395
      break;
396

    
397
    case UCS2:
398
      data_size = str->Length() * sizeof(uint16_t);
399
      break;
400

    
401
    case BASE64:
402
      data_size = base64_decoded_size_fast(str->Length());
403
      break;
404

    
405
    case HEX:
406
      assert(str->Length() % 2 == 0 && "invalid hex string length");
407
      data_size = str->Length() / 2;
408
      break;
409

    
410
    default:
411
      assert(0 && "unknown encoding");
412
      break;
413
  }
414

    
415
  return data_size;
416
}
417

    
418

    
419
size_t StringBytes::Size(Handle<Value> val, enum encoding encoding) {
420
  HandleScope scope(node_isolate);
421
  size_t data_size = 0;
422
  bool is_buffer = Buffer::HasInstance(val);
423

    
424
  if (is_buffer && (encoding == BUFFER || encoding == BINARY))
425
    return Buffer::Length(val);
426

    
427
  const char* data;
428
  if (GetExternalParts(val, &data, &data_size))
429
    return data_size;
430

    
431
  Local<String> str = val->ToString();
432

    
433
  switch (encoding) {
434
    case BINARY:
435
    case BUFFER:
436
    case ASCII:
437
      data_size = str->Length();
438
      break;
439

    
440
    case UTF8:
441
      data_size = str->Utf8Length();
442
      break;
443

    
444
    case UCS2:
445
      data_size = str->Length() * sizeof(uint16_t);
446
      break;
447

    
448
    case BASE64: {
449
      String::Value value(str);
450
      data_size = base64_decoded_size(*value, value.length());
451
      break;
452
    }
453

    
454
    case HEX:
455
      data_size = str->Length() / 2;
456
      break;
457

    
458
    default:
459
      assert(0 && "unknown encoding");
460
      break;
461
  }
462

    
463
  return data_size;
464
}
465

    
466

    
467

    
468

    
469
static bool contains_non_ascii_slow(const char* buf, size_t len) {
470
  for (size_t i = 0; i < len; ++i) {
471
    if (buf[i] & 0x80)
472
      return true;
473
  }
474
  return false;
475
}
476

    
477

    
478
static bool contains_non_ascii(const char* src, size_t len) {
479
  if (len < 16) {
480
    return contains_non_ascii_slow(src, len);
481
  }
482

    
483
  const unsigned bytes_per_word = sizeof(uintptr_t);
484
  const unsigned align_mask = bytes_per_word - 1;
485
  const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
486

    
487
  if (unaligned > 0) {
488
    const unsigned n = bytes_per_word - unaligned;
489
    if (contains_non_ascii_slow(src, n))
490
      return true;
491
    src += n;
492
    len -= n;
493
  }
494

    
495

    
496
#if defined(__x86_64__) || defined(_WIN64)
497
  const uintptr_t mask = 0x8080808080808080ll;
498
#else
499
  const uintptr_t mask = 0x80808080l;
500
#endif
501

    
502
  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
503

    
504
  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
505
    if (srcw[i] & mask)
506
      return true;
507
  }
508

    
509
  const unsigned remainder = len & align_mask;
510
  if (remainder > 0) {
511
    const size_t offset = len - remainder;
512
    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
  for (size_t i = 0; i < len; ++i) {
522
    dst[i] = src[i] & 0x7f;
523
  }
524
}
525

    
526

    
527
static void force_ascii(const char* src, char* dst, size_t len) {
528
  if (len < 16) {
529
    force_ascii_slow(src, dst, len);
530
    return;
531
  }
532

    
533
  const unsigned bytes_per_word = sizeof(uintptr_t);
534
  const unsigned align_mask = bytes_per_word - 1;
535
  const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
536
  const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
537

    
538
  if (src_unalign > 0) {
539
    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(__x86_64__) || defined(_WIN64)
552
  const uintptr_t mask = ~0x8080808080808080ll;
553
#else
554
  const uintptr_t mask = ~0x80808080l;
555
#endif
556

    
557
  const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
558
  uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
559

    
560
  for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
561
    dstw[i] = srcw[i] & mask;
562
  }
563

    
564
  const unsigned remainder = len & align_mask;
565
  if (remainder > 0) {
566
    const size_t offset = len - remainder;
567
    force_ascii_slow(src + offset, dst + offset, remainder);
568
  }
569
}
570

    
571

    
572
static size_t base64_encode(const char* src,
573
                            size_t slen,
574
                            char* dst,
575
                            size_t dlen) {
576
  // We know how much we'll write, just make sure that there's space.
577
  assert(dlen >= base64_encoded_size(slen) &&
578
      "not enough space provided for base64 encode");
579

    
580
  dlen = base64_encoded_size(slen);
581

    
582
  unsigned a;
583
  unsigned b;
584
  unsigned c;
585
  unsigned i;
586
  unsigned k;
587
  unsigned n;
588

    
589
  static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
590
                              "abcdefghijklmnopqrstuvwxyz"
591
                              "0123456789+/";
592

    
593
  i = 0;
594
  k = 0;
595
  n = slen / 3 * 3;
596

    
597
  while (i < n) {
598
    a = src[i + 0] & 0xff;
599
    b = src[i + 1] & 0xff;
600
    c = src[i + 2] & 0xff;
601

    
602
    dst[k + 0] = table[a >> 2];
603
    dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
604
    dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
605
    dst[k + 3] = table[c & 0x3f];
606

    
607
    i += 3;
608
    k += 4;
609
  }
610

    
611
  if (n != slen) {
612
    switch (slen - n) {
613
      case 1:
614
        a = src[i + 0] & 0xff;
615
        dst[k + 0] = table[a >> 2];
616
        dst[k + 1] = table[(a & 3) << 4];
617
        dst[k + 2] = '=';
618
        dst[k + 3] = '=';
619
        break;
620

    
621
      case 2:
622
        a = src[i + 0] & 0xff;
623
        b = src[i + 1] & 0xff;
624
        dst[k + 0] = table[a >> 2];
625
        dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
626
        dst[k + 2] = table[(b & 0x0f) << 2];
627
        dst[k + 3] = '=';
628
        break;
629
    }
630
  }
631

    
632
  return dlen;
633
}
634

    
635

    
636
static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
637
  // We know how much we'll write, just make sure that there's space.
638
  assert(dlen >= slen * 2 &&
639
      "not enough space provided for hex encode");
640

    
641
  dlen = slen * 2;
642
  for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
643
    static const char hex[] = "0123456789abcdef";
644
    uint8_t val = static_cast<uint8_t>(src[i]);
645
    dst[k + 0] = hex[val >> 4];
646
    dst[k + 1] = hex[val & 15];
647
  }
648

    
649
  return dlen;
650
}
651

    
652

    
653

    
654
Local<Value> StringBytes::Encode(const char* buf,
655
                                 size_t buflen,
656
                                 enum encoding encoding) {
657
  HandleScope scope(node_isolate);
658

    
659
  assert(buflen <= Buffer::kMaxLength);
660
  if (!buflen && encoding != BUFFER)
661
    return scope.Close(String::Empty(node_isolate));
662

    
663
  Local<String> val;
664
  switch (encoding) {
665
    case BUFFER:
666
      return scope.Close(Buffer::New(buf, buflen));
667

    
668
    case ASCII:
669
      if (contains_non_ascii(buf, buflen)) {
670
        char* out = new char[buflen];
671
        force_ascii(buf, out, buflen);
672
        if (buflen < EXTERN_APEX) {
673
          val = OneByteString(node_isolate, out, buflen);
674
          delete[] out;
675
        } else {
676
          val = ExternOneByteString::New(out, buflen);
677
        }
678
      } else {
679
        if (buflen < EXTERN_APEX)
680
          val = OneByteString(node_isolate, buf, buflen);
681
        else
682
          val = ExternOneByteString::NewFromCopy(buf, buflen);
683
      }
684
      break;
685

    
686
    case UTF8:
687
      val = String::NewFromUtf8(node_isolate,
688
                                buf,
689
                                String::kNormalString,
690
                                buflen);
691
      break;
692

    
693
    case BINARY:
694
      if (buflen < EXTERN_APEX)
695
        val = OneByteString(node_isolate, buf, buflen);
696
      else
697
        val = ExternOneByteString::NewFromCopy(buf, buflen);
698
      break;
699

    
700
    case BASE64: {
701
      size_t dlen = base64_encoded_size(buflen);
702
      char* dst = new char[dlen];
703

    
704
      size_t written = base64_encode(buf, buflen, dst, dlen);
705
      assert(written == dlen);
706

    
707
      if (dlen < EXTERN_APEX) {
708
        val = OneByteString(node_isolate, dst, dlen);
709
        delete[] dst;
710
      } else {
711
        val = ExternOneByteString::New(dst, dlen);
712
      }
713
      break;
714
    }
715

    
716
    case UCS2: {
717
      const uint16_t* out = reinterpret_cast<const uint16_t*>(buf);
718
      if (buflen < EXTERN_APEX)
719
        val = String::NewFromTwoByte(node_isolate,
720
                                     out,
721
                                     String::kNormalString,
722
                                     buflen / 2);
723
      else
724
        val = ExternTwoByteString::NewFromCopy(out, buflen / 2);
725
      break;
726
    }
727

    
728
    case HEX: {
729
      size_t dlen = buflen * 2;
730
      char* dst = new char[dlen];
731
      size_t written = hex_encode(buf, buflen, dst, dlen);
732
      assert(written == dlen);
733

    
734
      if (dlen < EXTERN_APEX) {
735
        val = OneByteString(node_isolate, dst, dlen);
736
        delete[] dst;
737
      } else {
738
        val = ExternOneByteString::New(dst, dlen);
739
      }
740
      break;
741
    }
742

    
743
    default:
744
      assert(0 && "unknown encoding");
745
      break;
746
  }
747

    
748
  return scope.Close(val);
749
}
750

    
751
}  // namespace node