1/**
2 * Copied from node_buffer.cc
3 * see http://www.nodejs.org/
4 *
5 * Node's license follows:
6 *
7 * Copyright 2009, 2010 Ryan Lienhart Dahl. All rights reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
26
27#include "node_buffer.h"
28
29#include <assert.h>
30#include <stdlib.h> // malloc, free
31#include <v8.h>
32
33#include <string.h> // memcpy
34
35#include <arpa/inet.h>  // htons, htonl
36
37#include "logging.h"
38#include "node_util.h"
39#include "util.h"
40
41//#define BUFFER_DEBUG
42#ifdef  BUFFER_DEBUG
43
44#define DBG(...) LOGD(__VA_ARGS__)
45
46#else
47
48#define DBG(...)
49
50#endif
51
52#define MIN(a,b) ((a) < (b) ? (a) : (b))
53
54using namespace v8;
55
56#define SLICE_ARGS(start_arg, end_arg)                                   \
57  if (!start_arg->IsInt32() || !end_arg->IsInt32()) {                    \
58    return ThrowException(Exception::TypeError(                          \
59          v8::String::New("Bad argument.")));                            \
60  }                                                                      \
61  int32_t start = start_arg->Int32Value();                               \
62  int32_t end = end_arg->Int32Value();                                   \
63  if (start < 0 || end < 0) {                                            \
64    return ThrowException(Exception::TypeError(                          \
65          v8::String::New("Bad argument.")));                            \
66  }                                                                      \
67  if (!(start <= end)) {                                                 \
68    return ThrowException(Exception::Error(                              \
69          v8::String::New("Must have start <= end")));                   \
70  }                                                                      \
71  if ((size_t)end > parent->length_) {                                   \
72    return ThrowException(Exception::Error(                              \
73          v8::String::New("end cannot be longer than parent.length")));  \
74  }
75
76static Persistent<String> length_symbol;
77static Persistent<String> chars_written_sym;
78static Persistent<String> write_sym;
79Persistent<FunctionTemplate> Buffer::constructor_template;
80
81
82// Each javascript Buffer object is backed by a Blob object.
83// the Blob is just a C-level chunk of bytes.
84// It has a reference count.
85struct Blob_ {
86  unsigned int refs;
87  size_t length;
88  char *data;
89};
90typedef struct Blob_ Blob;
91
92
93static inline Blob * blob_new(size_t length) {
94  DBG("blob_new E");
95  Blob * blob  = (Blob*) malloc(sizeof(Blob));
96  if (!blob) return NULL;
97
98  blob->data = (char*) malloc(length);
99  if (!blob->data) {
100    DBG("blob_new X no memory for data");
101    free(blob);
102    return NULL;
103  }
104
105  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Blob) + length);
106  blob->length = length;
107  blob->refs = 0;
108  DBG("blob_new X");
109  return blob;
110}
111
112
113static inline void blob_ref(Blob *blob) {
114  blob->refs++;
115}
116
117
118static inline void blob_unref(Blob *blob) {
119  assert(blob->refs > 0);
120  if (--blob->refs == 0) {
121    DBG("blob_unref == 0");
122    //fprintf(stderr, "free %d bytes\n", blob->length);
123    V8::AdjustAmountOfExternalAllocatedMemory(-(sizeof(Blob) + blob->length));
124    free(blob->data);
125    free(blob);
126    DBG("blob_unref blob and its data freed");
127  }
128}
129
130#if 0
131// When someone calls buffer.asciiSlice, data is not copied. Instead V8
132// references in the underlying Blob with this ExternalAsciiStringResource.
133class AsciiSliceExt: public String::ExternalAsciiStringResource {
134 friend class Buffer;
135 public:
136  AsciiSliceExt(Buffer *parent, size_t start, size_t end) {
137    blob_ = parent->blob();
138    blob_ref(blob_);
139
140    assert(start <= end);
141    length_ = end - start;
142    assert(start + length_ <= parent->length());
143    data_ = parent->data() + start;
144  }
145
146
147  ~AsciiSliceExt() {
148    //fprintf(stderr, "free ascii slice (%d refs left)\n", blob_->refs);
149    blob_unref(blob_);
150  }
151
152
153  const char* data() const { return data_; }
154  size_t length() const { return length_; }
155
156 private:
157  const char *data_;
158  size_t length_;
159  Blob *blob_;
160};
161#endif
162
163Buffer* Buffer::New(size_t size) {
164  DBG("Buffer::New(size) E");
165  HandleScope scope;
166
167  Local<Value> arg = Integer::NewFromUnsigned(size);
168  Local<Object> b = constructor_template->GetFunction()->NewInstance(1, &arg);
169
170  DBG("Buffer::New(size) X");
171  return ObjectWrap::Unwrap<Buffer>(b);
172}
173
174
175Handle<Value> Buffer::New(const Arguments &args) {
176  DBG("Buffer::New(args) E");
177  HandleScope scope;
178
179  Buffer *buffer;
180  if ((args.Length() == 0) || args[0]->IsInt32()) {
181    size_t length = 0;
182    if (args[0]->IsInt32()) {
183      length = args[0]->Uint32Value();
184    }
185    buffer = new Buffer(length);
186  } else if (args[0]->IsArray()) {
187    Local<Array> a = Local<Array>::Cast(args[0]);
188    buffer = new Buffer(a->Length());
189    char *p = buffer->data();
190    for (int i = 0; i < a->Length(); i++) {
191      Handle<Value> index = v8::Number::New(i);
192      p[i] = a->Get(index)->Uint32Value();
193      //p[i] = a->Get(i)->Uint32Value();
194    }
195  } else if (args[0]->IsString()) {
196    Local<String> s = args[0]->ToString();
197    enum encoding e = ParseEncoding(args[1], UTF8);
198    int length = e == UTF8 ? s->Utf8Length() : s->Length();
199    buffer = new Buffer(length);
200  } else if (Buffer::HasInstance(args[0]) && args.Length() > 2) {
201    // var slice = new Buffer(buffer, 123, 130);
202    // args: parent, start, end
203    Buffer *parent = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
204    SLICE_ARGS(args[1], args[2])
205    buffer = new Buffer(parent, start, end);
206  } else {
207    DBG("Buffer::New(args) X Bad argument");
208    return ThrowException(Exception::TypeError(String::New("Bad argument")));
209  }
210
211  buffer->Wrap(args.This());
212  args.This()->SetIndexedPropertiesToExternalArrayData(buffer->data(),
213                                                       kExternalUnsignedByteArray,
214                                                       buffer->length());
215  args.This()->Set(length_symbol, Integer::New(buffer->length_));
216
217  if (args[0]->IsString()) {
218    if (write_sym.IsEmpty()) {
219      write_sym = Persistent<String>::New(String::NewSymbol("write"));
220    }
221
222    Local<Value> write_v = args.This()->Get(write_sym);
223    assert(write_v->IsFunction());
224    Local<Function> write = Local<Function>::Cast(write_v);
225
226    Local<Value> argv[2] = { args[0], args[1] };
227
228    TryCatch try_catch;
229
230    write->Call(args.This(), 2, argv);
231
232    if (try_catch.HasCaught()) {
233      ReportException(&try_catch);
234    }
235  }
236
237  DBG("Buffer::New(args) X");
238  return args.This();
239}
240
241
242Buffer::Buffer(size_t length) : ObjectWrap() {
243  DBG("Buffer::Buffer(length) E");
244  blob_ = blob_new(length);
245  off_ = 0;
246  length_ = length;
247
248  blob_ref(blob_);
249
250  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
251  DBG("Buffer::Buffer(length) X");
252}
253
254
255Buffer::Buffer(Buffer *parent, size_t start, size_t end) : ObjectWrap() {
256  DBG("Buffer::Buffer(parent, start, end) E");
257  blob_ = parent->blob_;
258  assert(blob_->refs > 0);
259  blob_ref(blob_);
260
261  assert(start <= end);
262  off_ = parent->off_ + start;
263  length_ = end - start;
264  assert(length_ <= parent->length_);
265
266  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
267  DBG("Buffer::Buffer(parent, start, end) X");
268}
269
270
271Buffer::~Buffer() {
272  DBG("Buffer::~Buffer() E");
273  assert(blob_->refs > 0);
274  //fprintf(stderr, "free buffer (%d refs left)\n", blob_->refs);
275  blob_unref(blob_);
276  V8::AdjustAmountOfExternalAllocatedMemory(-static_cast<long int>(sizeof(Buffer)));
277  DBG("Buffer::~Buffer() X");
278}
279
280
281char* Buffer::data() {
282  char *p = blob_->data + off_;
283  DBG("Buffer::data() EX p=%p", p);
284  return p;
285}
286
287void Buffer::NewBlob(size_t length) {
288  DBG("Buffer::NewBlob(length) E");
289  blob_unref(blob_);
290  blob_ = blob_new(length);
291  off_ = 0;
292  length_ = length;
293
294  blob_ref(blob_);
295
296  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
297  DBG("Buffer::NewBlob(length) X");
298}
299
300
301Handle<Value> Buffer::BinarySlice(const Arguments &args) {
302  DBG("Buffer::BinarySlice(args) E");
303  HandleScope scope;
304  Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
305  SLICE_ARGS(args[0], args[1])
306
307  const char *data = const_cast<char*>(parent->data() + start);
308  //Local<String> string = String::New(data, end - start);
309
310  Local<Value> b =  Encode(data, end - start, BINARY);
311
312  DBG("Buffer::BinarySlice(args) X");
313  return scope.Close(b);
314}
315
316
317Handle<Value> Buffer::AsciiSlice(const Arguments &args) {
318  DBG("Buffer::AsciiSlice(args) E");
319  HandleScope scope;
320  Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
321  SLICE_ARGS(args[0], args[1])
322
323#if 0
324  AsciiSliceExt *ext = new AsciiSliceExt(parent, start, end);
325  Local<String> string = String::NewExternal(ext);
326  // There should be at least two references to the blob now - the parent
327  // and the slice.
328  assert(parent->blob_->refs >= 2);
329#endif
330
331  const char *data = const_cast<char*>(parent->data() + start);
332  Local<String> string = String::New(data, end - start);
333
334
335  DBG("Buffer::AsciiSlice(args) X");
336  return scope.Close(string);
337}
338
339
340Handle<Value> Buffer::Utf8Slice(const Arguments &args) {
341  DBG("Buffer::Utf8Slice(args) E");
342  HandleScope scope;
343  Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
344  SLICE_ARGS(args[0], args[1])
345  const char *data = const_cast<char*>(parent->data() + start);
346  Local<String> string = String::New(data, end - start);
347  DBG("Buffer::Utf8Slice(args) X");
348  return scope.Close(string);
349}
350
351
352Handle<Value> Buffer::Slice(const Arguments &args) {
353  DBG("Buffer::Slice(args) E");
354  HandleScope scope;
355  Local<Value> argv[3] = { args.This(), args[0], args[1] };
356  Local<Object> slice =
357    constructor_template->GetFunction()->NewInstance(3, argv);
358  DBG("Buffer::Slice(args) X");
359  return scope.Close(slice);
360}
361
362
363// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd);
364Handle<Value> Buffer::Copy(const Arguments &args) {
365  DBG("Buffer::Copy(args) E");
366  HandleScope scope;
367
368  Buffer *source = ObjectWrap::Unwrap<Buffer>(args.This());
369
370  if (!Buffer::HasInstance(args[0])) {
371    DBG("Buffer::Copy(args) X arg[0] not buffer");
372    return ThrowException(Exception::TypeError(String::New(
373            "First arg should be a Buffer")));
374  }
375
376  Buffer *target = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
377
378  ssize_t target_start = args[1]->Int32Value();
379  ssize_t source_start = args[2]->Int32Value();
380  ssize_t source_end = args[3]->IsInt32() ? args[3]->Int32Value()
381                                          : source->length();
382
383  if (source_end < source_start) {
384    DBG("Buffer::Copy(args) X end < start");
385    return ThrowException(Exception::Error(String::New(
386            "sourceEnd < sourceStart")));
387  }
388
389  if (target_start < 0 || ((size_t)target_start) > target->length()) {
390    DBG("Buffer::Copy(args) X targetStart bad");
391    return ThrowException(Exception::Error(String::New(
392            "targetStart out of bounds")));
393  }
394
395  if (source_start < 0 || ((size_t)source_start) > source->length()) {
396    DBG("Buffer::Copy(args) X base source start");
397    return ThrowException(Exception::Error(String::New(
398            "sourceStart out of bounds")));
399  }
400
401  if (source_end < 0 || ((size_t)source_end) > source->length()) {
402    DBG("Buffer::Copy(args) X bad source");
403    return ThrowException(Exception::Error(String::New(
404            "sourceEnd out of bounds")));
405  }
406
407  ssize_t to_copy = MIN(source_end - source_start,
408                        target->length() - target_start);
409
410  memcpy((void*)(target->data() + target_start),
411         (const void*)(source->data() + source_start),
412         to_copy);
413
414  DBG("Buffer::Copy(args) X");
415  return scope.Close(Integer::New(to_copy));
416}
417
418
419// var charsWritten = buffer.utf8Write(string, offset);
420Handle<Value> Buffer::Utf8Write(const Arguments &args) {
421  DBG("Buffer::Utf8Write(args) X");
422  HandleScope scope;
423  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
424
425  if (!args[0]->IsString()) {
426  DBG("Buffer::Utf8Write(args) X arg[0] not string");
427    return ThrowException(Exception::TypeError(String::New(
428            "Argument must be a string")));
429  }
430
431  Local<String> s = args[0]->ToString();
432
433  size_t offset = args[1]->Int32Value();
434
435  if (offset >= buffer->length_) {
436    DBG("Buffer::Utf8Write(args) X offset bad");
437    return ThrowException(Exception::TypeError(String::New(
438            "Offset is out of bounds")));
439  }
440
441  const char *p = buffer->data() + offset;
442
443  int char_written;
444
445  int written = s->WriteUtf8((char*)p,
446                             buffer->length_ - offset);
447//                             &char_written,
448//                             String::HINT_MANY_WRITES_EXPECTED);
449
450  constructor_template->GetFunction()->Set(chars_written_sym,
451                                           Integer::New(written));
452
453  if (written > 0 && p[written-1] == '\0') written--;
454
455  DBG("Buffer::Utf8Write(args) X");
456  return scope.Close(Integer::New(written));
457}
458
459
460// var charsWritten = buffer.asciiWrite(string, offset);
461Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
462  DBG("Buffer::AsciiWrite(args) E");
463  HandleScope scope;
464
465  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
466
467  if (!args[0]->IsString()) {
468    DBG("Buffer::AsciiWrite(args) X arg[0] not string");
469    return ThrowException(Exception::TypeError(String::New(
470            "Argument must be a string")));
471  }
472
473  Local<String> s = args[0]->ToString();
474
475  size_t offset = args[1]->Int32Value();
476
477  if (offset >= buffer->length_) {
478    DBG("Buffer::AsciiWrite(args) X bad offset");
479    return ThrowException(Exception::TypeError(String::New(
480            "Offset is out of bounds")));
481  }
482
483  const char *p = buffer->data() + offset;
484
485  size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset);
486
487  int written = s->WriteAscii((char*)p, 0, towrite);
488  DBG("Buffer::AsciiWrite(args) X");
489  return scope.Close(Integer::New(written));
490}
491
492
493Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
494  DBG("Buffer::BinaryWrite(args) E");
495  HandleScope scope;
496
497  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
498
499  if (!args[0]->IsString()) {
500    DBG("Buffer::BinaryWrite(args) X arg[0] not string");
501    return ThrowException(Exception::TypeError(String::New(
502            "Argument must be a string")));
503  }
504
505  Local<String> s = args[0]->ToString();
506
507  size_t offset = args[1]->Int32Value();
508
509  if (offset >= buffer->length_) {
510    DBG("Buffer::BinaryWrite(args) X offset bad");
511    return ThrowException(Exception::TypeError(String::New(
512            "Offset is out of bounds")));
513  }
514
515  char *p = (char*)buffer->data() + offset;
516
517  size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset);
518
519  int written = DecodeWrite(p, towrite, s, BINARY);
520  DBG("Buffer::BinaryWrite(args) X");
521  return scope.Close(Integer::New(written));
522}
523
524
525// buffer.unpack(format, index);
526// Starting at 'index', unpacks binary from the buffer into an array.
527// 'format' is a string
528//
529//  FORMAT  RETURNS
530//    N     uint32_t   a 32bit unsigned integer in network byte order
531//    n     uint16_t   a 16bit unsigned integer in network byte order
532//    o     uint8_t    a 8bit unsigned integer
533Handle<Value> Buffer::Unpack(const Arguments &args) {
534  DBG("Buffer::Unpack(args) E");
535  HandleScope scope;
536  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
537
538  if (!args[0]->IsString()) {
539    DBG("Buffer::Unpack(args) X arg[0] not string");
540    return ThrowException(Exception::TypeError(String::New(
541            "Argument must be a string")));
542  }
543
544  String::AsciiValue format(args[0]->ToString());
545  uint32_t index = args[1]->Uint32Value();
546
547#define OUT_OF_BOUNDS ThrowException(Exception::Error(String::New("Out of bounds")))
548
549  Local<Array> array = Array::New(format.length());
550
551  uint8_t  uint8;
552  uint16_t uint16;
553  uint32_t uint32;
554
555  for (int i = 0; i < format.length(); i++) {
556    switch ((*format)[i]) {
557      // 32bit unsigned integer in network byte order
558      case 'N':
559        if (index + 3 >= buffer->length_) return OUT_OF_BOUNDS;
560        uint32 = htonl(*(uint32_t*)(buffer->data() + index));
561        array->Set(Integer::New(i), Integer::NewFromUnsigned(uint32));
562        index += 4;
563        break;
564
565      // 16bit unsigned integer in network byte order
566      case 'n':
567        if (index + 1 >= buffer->length_) return OUT_OF_BOUNDS;
568        uint16 = htons(*(uint16_t*)(buffer->data() + index));
569        array->Set(Integer::New(i), Integer::NewFromUnsigned(uint16));
570        index += 2;
571        break;
572
573      // a single octet, unsigned.
574      case 'o':
575        if (index >= buffer->length_) return OUT_OF_BOUNDS;
576        uint8 = (uint8_t)buffer->data()[index];
577        array->Set(Integer::New(i), Integer::NewFromUnsigned(uint8));
578        index += 1;
579        break;
580
581      default:
582        DBG("Buffer::Unpack(args) X unknown format character");
583        return ThrowException(Exception::Error(
584              String::New("Unknown format character")));
585    }
586  }
587
588  DBG("Buffer::Unpack(args) X");
589  return scope.Close(array);
590}
591
592
593// var nbytes = Buffer.byteLength("string", "utf8")
594Handle<Value> Buffer::ByteLength(const Arguments &args) {
595  DBG("Buffer::ByteLength(args) E");
596  HandleScope scope;
597
598  if (!args[0]->IsString()) {
599    DBG("Buffer::ByteLength(args) X arg[0] not a string");
600    return ThrowException(Exception::TypeError(String::New(
601            "Argument must be a string")));
602  }
603
604  Local<String> s = args[0]->ToString();
605  enum encoding e = ParseEncoding(args[1], UTF8);
606
607  Local<Integer> length =
608    Integer::New(e == UTF8 ? s->Utf8Length() : s->Length());
609
610  DBG("Buffer::ByteLength(args) X");
611  return scope.Close(length);
612}
613
614void Buffer::InitializeObjectTemplate(Handle<ObjectTemplate> target) {
615  DBG("InitializeObjectTemplate(target) E:");
616  HandleScope scope;
617
618  length_symbol = Persistent<String>::New(String::NewSymbol("length"));
619  chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));
620
621  Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
622  constructor_template = Persistent<FunctionTemplate>::New(t);
623  constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
624  constructor_template->SetClassName(String::NewSymbol("Buffer"));
625
626  // copy free
627  SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
628  SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
629  SET_PROTOTYPE_METHOD(constructor_template, "slice", Buffer::Slice);
630  // TODO SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
631  // copy
632  SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
633
634  SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
635  SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
636  SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
637  SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack);
638  SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
639
640  SET_PROTOTYPE_METHOD(constructor_template, "byteLength", Buffer::ByteLength);
641
642  target->Set(String::NewSymbol("Buffer"), constructor_template);
643  DBG("InitializeObjectTemplate(target) X:");
644}
645