• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
54 using 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 
76 static Persistent<String> length_symbol;
77 static Persistent<String> chars_written_sym;
78 static Persistent<String> write_sym;
79 Persistent<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.
85 struct Blob_ {
86   unsigned int refs;
87   size_t length;
88   char *data;
89 };
90 typedef struct Blob_ Blob;
91 
92 
blob_new(size_t length)93 static 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 
blob_ref(Blob * blob)113 static inline void blob_ref(Blob *blob) {
114   blob->refs++;
115 }
116 
117 
blob_unref(Blob * blob)118 static 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.
133 class 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 
New(size_t size)163 Buffer* 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 
New(const Arguments & args)175 Handle<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 
Buffer(size_t length)240 Buffer::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 
Buffer(Buffer * parent,size_t start,size_t end)253 Buffer::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 
~Buffer()269 Buffer::~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 
data()279 char* Buffer::data() {
280   char *p = blob_->data + off_;
281   DBG("Buffer::data() EX p=%p", p);
282   return p;
283 }
284 
NewBlob(size_t length)285 void 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 
BinarySlice(const Arguments & args)299 Handle<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 
AsciiSlice(const Arguments & args)315 Handle<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 
Utf8Slice(const Arguments & args)338 Handle<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 
Slice(const Arguments & args)350 Handle<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);
Copy(const Arguments & args)362 Handle<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);
Utf8Write(const Arguments & args)418 Handle<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);
AsciiWrite(const Arguments & args)459 Handle<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 
BinaryWrite(const Arguments & args)491 Handle<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
Unpack(const Arguments & args)531 Handle<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")
ByteLength(const Arguments & args)592 Handle<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 
InitializeObjectTemplate(Handle<ObjectTemplate> target)612 void 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