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(...) ALOGD(__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 (unsigned int i = 0; i < a->Length(); i++) {
191      p[i] = a->Get(i)->Uint32Value();
192    }
193  } else if (args[0]->IsString()) {
194    Local<String> s = args[0]->ToString();
195    enum encoding e = ParseEncoding(args[1], UTF8);
196    int length = e == UTF8 ? s->Utf8Length() : s->Length();
197    buffer = new Buffer(length);
198  } else if (Buffer::HasInstance(args[0]) && args.Length() > 2) {
199    // var slice = new Buffer(buffer, 123, 130);
200    // args: parent, start, end
201    Buffer *parent = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
202    SLICE_ARGS(args[1], args[2])
203    buffer = new Buffer(parent, start, end);
204  } else {
205    DBG("Buffer::New(args) X Bad argument");
206    return ThrowException(Exception::TypeError(String::New("Bad argument")));
207  }
208
209  buffer->Wrap(args.This());
210  args.This()->SetIndexedPropertiesToExternalArrayData(buffer->data(),
211                                                       kExternalUnsignedByteArray,
212                                                       buffer->length());
213  args.This()->Set(length_symbol, Integer::New(buffer->length_));
214
215  if (args[0]->IsString()) {
216    if (write_sym.IsEmpty()) {
217      write_sym = Persistent<String>::New(String::NewSymbol("write"));
218    }
219
220    Local<Value> write_v = args.This()->Get(write_sym);
221    assert(write_v->IsFunction());
222    Local<Function> write = Local<Function>::Cast(write_v);
223
224    Local<Value> argv[2] = { args[0], args[1] };
225
226    TryCatch try_catch;
227
228    write->Call(args.This(), 2, argv);
229
230    if (try_catch.HasCaught()) {
231      ReportException(&try_catch);
232    }
233  }
234
235  DBG("Buffer::New(args) X");
236  return args.This();
237}
238
239
240Buffer::Buffer(size_t length) : ObjectWrap() {
241  DBG("Buffer::Buffer(length) E");
242  blob_ = blob_new(length);
243  off_ = 0;
244  length_ = length;
245
246  blob_ref(blob_);
247
248  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
249  DBG("Buffer::Buffer(length) X");
250}
251
252
253Buffer::Buffer(Buffer *parent, size_t start, size_t end) : ObjectWrap() {
254  DBG("Buffer::Buffer(parent, start, end) E");
255  blob_ = parent->blob_;
256  assert(blob_->refs > 0);
257  blob_ref(blob_);
258
259  assert(start <= end);
260  off_ = parent->off_ + start;
261  length_ = end - start;
262  assert(length_ <= parent->length_);
263
264  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
265  DBG("Buffer::Buffer(parent, start, end) X");
266}
267
268
269Buffer::~Buffer() {
270  DBG("Buffer::~Buffer() E");
271  assert(blob_->refs > 0);
272  //fprintf(stderr, "free buffer (%d refs left)\n", blob_->refs);
273  blob_unref(blob_);
274  V8::AdjustAmountOfExternalAllocatedMemory(-static_cast<long int>(sizeof(Buffer)));
275  DBG("Buffer::~Buffer() X");
276}
277
278
279char* Buffer::data() {
280  char *p = blob_->data + off_;
281  DBG("Buffer::data() EX p=%p", p);
282  return p;
283}
284
285void Buffer::NewBlob(size_t length) {
286  DBG("Buffer::NewBlob(length) E");
287  blob_unref(blob_);
288  blob_ = blob_new(length);
289  off_ = 0;
290  length_ = length;
291
292  blob_ref(blob_);
293
294  V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer));
295  DBG("Buffer::NewBlob(length) X");
296}
297
298
299Handle<Value> Buffer::BinarySlice(const Arguments &args) {
300  DBG("Buffer::BinarySlice(args) E");
301  HandleScope scope;
302  Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
303  SLICE_ARGS(args[0], args[1])
304
305  const char *data = const_cast<char*>(parent->data() + start);
306  //Local<String> string = String::New(data, end - start);
307
308  Local<Value> b =  Encode(data, end - start, BINARY);
309
310  DBG("Buffer::BinarySlice(args) X");
311  return scope.Close(b);
312}
313
314
315Handle<Value> Buffer::AsciiSlice(const Arguments &args) {
316  DBG("Buffer::AsciiSlice(args) E");
317  HandleScope scope;
318  Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
319  SLICE_ARGS(args[0], args[1])
320
321#if 0
322  AsciiSliceExt *ext = new AsciiSliceExt(parent, start, end);
323  Local<String> string = String::NewExternal(ext);
324  // There should be at least two references to the blob now - the parent
325  // and the slice.
326  assert(parent->blob_->refs >= 2);
327#endif
328
329  const char *data = const_cast<char*>(parent->data() + start);
330  Local<String> string = String::New(data, end - start);
331
332
333  DBG("Buffer::AsciiSlice(args) X");
334  return scope.Close(string);
335}
336
337
338Handle<Value> Buffer::Utf8Slice(const Arguments &args) {
339  DBG("Buffer::Utf8Slice(args) E");
340  HandleScope scope;
341  Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
342  SLICE_ARGS(args[0], args[1])
343  const char *data = const_cast<char*>(parent->data() + start);
344  Local<String> string = String::New(data, end - start);
345  DBG("Buffer::Utf8Slice(args) X");
346  return scope.Close(string);
347}
348
349
350Handle<Value> Buffer::Slice(const Arguments &args) {
351  DBG("Buffer::Slice(args) E");
352  HandleScope scope;
353  Local<Value> argv[3] = { args.This(), args[0], args[1] };
354  Local<Object> slice =
355    constructor_template->GetFunction()->NewInstance(3, argv);
356  DBG("Buffer::Slice(args) X");
357  return scope.Close(slice);
358}
359
360
361// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd);
362Handle<Value> Buffer::Copy(const Arguments &args) {
363  DBG("Buffer::Copy(args) E");
364  HandleScope scope;
365
366  Buffer *source = ObjectWrap::Unwrap<Buffer>(args.This());
367
368  if (!Buffer::HasInstance(args[0])) {
369    DBG("Buffer::Copy(args) X arg[0] not buffer");
370    return ThrowException(Exception::TypeError(String::New(
371            "First arg should be a Buffer")));
372  }
373
374  Buffer *target = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
375
376  ssize_t target_start = args[1]->Int32Value();
377  ssize_t source_start = args[2]->Int32Value();
378  ssize_t source_end = args[3]->IsInt32() ? args[3]->Int32Value()
379                                          : source->length();
380
381  if (source_end < source_start) {
382    DBG("Buffer::Copy(args) X end < start");
383    return ThrowException(Exception::Error(String::New(
384            "sourceEnd < sourceStart")));
385  }
386
387  if (target_start < 0 || ((size_t)target_start) > target->length()) {
388    DBG("Buffer::Copy(args) X targetStart bad");
389    return ThrowException(Exception::Error(String::New(
390            "targetStart out of bounds")));
391  }
392
393  if (source_start < 0 || ((size_t)source_start) > source->length()) {
394    DBG("Buffer::Copy(args) X base source start");
395    return ThrowException(Exception::Error(String::New(
396            "sourceStart out of bounds")));
397  }
398
399  if (source_end < 0 || ((size_t)source_end) > source->length()) {
400    DBG("Buffer::Copy(args) X bad source");
401    return ThrowException(Exception::Error(String::New(
402            "sourceEnd out of bounds")));
403  }
404
405  ssize_t to_copy = MIN(source_end - source_start,
406                        target->length() - target_start);
407
408  memcpy((void*)(target->data() + target_start),
409         (const void*)(source->data() + source_start),
410         to_copy);
411
412  DBG("Buffer::Copy(args) X");
413  return scope.Close(Integer::New(to_copy));
414}
415
416
417// var charsWritten = buffer.utf8Write(string, offset);
418Handle<Value> Buffer::Utf8Write(const Arguments &args) {
419  DBG("Buffer::Utf8Write(args) X");
420  HandleScope scope;
421  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
422
423  if (!args[0]->IsString()) {
424  DBG("Buffer::Utf8Write(args) X arg[0] not string");
425    return ThrowException(Exception::TypeError(String::New(
426            "Argument must be a string")));
427  }
428
429  Local<String> s = args[0]->ToString();
430
431  size_t offset = args[1]->Int32Value();
432
433  if (offset >= buffer->length_) {
434    DBG("Buffer::Utf8Write(args) X offset bad");
435    return ThrowException(Exception::TypeError(String::New(
436            "Offset is out of bounds")));
437  }
438
439  const char *p = buffer->data() + offset;
440
441  int char_written;
442
443  int written = s->WriteUtf8((char*)p,
444                             buffer->length_ - offset,
445                             &char_written,
446                             String::HINT_MANY_WRITES_EXPECTED);
447
448  constructor_template->GetFunction()->Set(chars_written_sym,
449                                           Integer::New(char_written));
450
451  if (written > 0 && p[written-1] == '\0') written--;
452
453  DBG("Buffer::Utf8Write(args) X");
454  return scope.Close(Integer::New(written));
455}
456
457
458// var charsWritten = buffer.asciiWrite(string, offset);
459Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
460  DBG("Buffer::AsciiWrite(args) E");
461  HandleScope scope;
462
463  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
464
465  if (!args[0]->IsString()) {
466    DBG("Buffer::AsciiWrite(args) X arg[0] not string");
467    return ThrowException(Exception::TypeError(String::New(
468            "Argument must be a string")));
469  }
470
471  Local<String> s = args[0]->ToString();
472
473  size_t offset = args[1]->Int32Value();
474
475  if (offset >= buffer->length_) {
476    DBG("Buffer::AsciiWrite(args) X bad offset");
477    return ThrowException(Exception::TypeError(String::New(
478            "Offset is out of bounds")));
479  }
480
481  const char *p = buffer->data() + offset;
482
483  size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset);
484
485  int written = s->WriteAscii((char*)p, 0, towrite, String::HINT_MANY_WRITES_EXPECTED);
486  DBG("Buffer::AsciiWrite(args) X");
487  return scope.Close(Integer::New(written));
488}
489
490
491Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
492  DBG("Buffer::BinaryWrite(args) E");
493  HandleScope scope;
494
495  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
496
497  if (!args[0]->IsString()) {
498    DBG("Buffer::BinaryWrite(args) X arg[0] not string");
499    return ThrowException(Exception::TypeError(String::New(
500            "Argument must be a string")));
501  }
502
503  Local<String> s = args[0]->ToString();
504
505  size_t offset = args[1]->Int32Value();
506
507  if (offset >= buffer->length_) {
508    DBG("Buffer::BinaryWrite(args) X offset bad");
509    return ThrowException(Exception::TypeError(String::New(
510            "Offset is out of bounds")));
511  }
512
513  char *p = (char*)buffer->data() + offset;
514
515  size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset);
516
517  int written = DecodeWrite(p, towrite, s, BINARY);
518  DBG("Buffer::BinaryWrite(args) X");
519  return scope.Close(Integer::New(written));
520}
521
522
523// buffer.unpack(format, index);
524// Starting at 'index', unpacks binary from the buffer into an array.
525// 'format' is a string
526//
527//  FORMAT  RETURNS
528//    N     uint32_t   a 32bit unsigned integer in network byte order
529//    n     uint16_t   a 16bit unsigned integer in network byte order
530//    o     uint8_t    a 8bit unsigned integer
531Handle<Value> Buffer::Unpack(const Arguments &args) {
532  DBG("Buffer::Unpack(args) E");
533  HandleScope scope;
534  Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
535
536  if (!args[0]->IsString()) {
537    DBG("Buffer::Unpack(args) X arg[0] not string");
538    return ThrowException(Exception::TypeError(String::New(
539            "Argument must be a string")));
540  }
541
542  String::AsciiValue format(args[0]->ToString());
543  uint32_t index = args[1]->Uint32Value();
544
545#define OUT_OF_BOUNDS ThrowException(Exception::Error(String::New("Out of bounds")))
546
547  Local<Array> array = Array::New(format.length());
548
549  uint8_t  uint8;
550  uint16_t uint16;
551  uint32_t uint32;
552
553  for (int i = 0; i < format.length(); i++) {
554    switch ((*format)[i]) {
555      // 32bit unsigned integer in network byte order
556      case 'N':
557        if (index + 3 >= buffer->length_) return OUT_OF_BOUNDS;
558        uint32 = htonl(*(uint32_t*)(buffer->data() + index));
559        array->Set(Integer::New(i), Integer::NewFromUnsigned(uint32));
560        index += 4;
561        break;
562
563      // 16bit unsigned integer in network byte order
564      case 'n':
565        if (index + 1 >= buffer->length_) return OUT_OF_BOUNDS;
566        uint16 = htons(*(uint16_t*)(buffer->data() + index));
567        array->Set(Integer::New(i), Integer::NewFromUnsigned(uint16));
568        index += 2;
569        break;
570
571      // a single octet, unsigned.
572      case 'o':
573        if (index >= buffer->length_) return OUT_OF_BOUNDS;
574        uint8 = (uint8_t)buffer->data()[index];
575        array->Set(Integer::New(i), Integer::NewFromUnsigned(uint8));
576        index += 1;
577        break;
578
579      default:
580        DBG("Buffer::Unpack(args) X unknown format character");
581        return ThrowException(Exception::Error(
582              String::New("Unknown format character")));
583    }
584  }
585
586  DBG("Buffer::Unpack(args) X");
587  return scope.Close(array);
588}
589
590
591// var nbytes = Buffer.byteLength("string", "utf8")
592Handle<Value> Buffer::ByteLength(const Arguments &args) {
593  DBG("Buffer::ByteLength(args) E");
594  HandleScope scope;
595
596  if (!args[0]->IsString()) {
597    DBG("Buffer::ByteLength(args) X arg[0] not a string");
598    return ThrowException(Exception::TypeError(String::New(
599            "Argument must be a string")));
600  }
601
602  Local<String> s = args[0]->ToString();
603  enum encoding e = ParseEncoding(args[1], UTF8);
604
605  Local<Integer> length =
606    Integer::New(e == UTF8 ? s->Utf8Length() : s->Length());
607
608  DBG("Buffer::ByteLength(args) X");
609  return scope.Close(length);
610}
611
612void Buffer::InitializeObjectTemplate(Handle<ObjectTemplate> target) {
613  DBG("InitializeObjectTemplate(target) E:");
614  HandleScope scope;
615
616  length_symbol = Persistent<String>::New(String::NewSymbol("length"));
617  chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));
618
619  Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
620  constructor_template = Persistent<FunctionTemplate>::New(t);
621  constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
622  constructor_template->SetClassName(String::NewSymbol("Buffer"));
623
624  // copy free
625  SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
626  SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
627  SET_PROTOTYPE_METHOD(constructor_template, "slice", Buffer::Slice);
628  // TODO SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
629  // copy
630  SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
631
632  SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
633  SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
634  SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
635  SET_PROTOTYPE_METHOD(constructor_template, "unpack", Buffer::Unpack);
636  SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
637
638  SET_PROTOTYPE_METHOD(constructor_template, "byteLength", Buffer::ByteLength);
639
640  target->Set(String::NewSymbol("Buffer"), constructor_template);
641  DBG("InitializeObjectTemplate(target) X:");
642}
643