61b80c622a809ecf0bee9ed8dd4e549b6a79619b
[platform/upstream/nodejs.git] / src / node_buffer.cc
1 #include "node.h"
2 #include "node_buffer.h"
3
4 #include "env.h"
5 #include "env-inl.h"
6 #include "smalloc.h"
7 #include "string_bytes.h"
8 #include "v8-profiler.h"
9 #include "v8.h"
10
11 #include <string.h>
12 #include <limits.h>
13
14 #define MIN(a, b) ((a) < (b) ? (a) : (b))
15
16 #define CHECK_NOT_OOB(r)                                                    \
17   do {                                                                      \
18     if (!(r)) return env->ThrowRangeError("out of range index");            \
19   } while (0)
20
21 #define ARGS_THIS(argT)                                                     \
22   Local<Object> obj = argT;                                                 \
23   size_t obj_length = obj->GetIndexedPropertiesExternalArrayDataLength();   \
24   char* obj_data = static_cast<char*>(                                      \
25     obj->GetIndexedPropertiesExternalArrayData());                          \
26   if (obj_length > 0)                                                       \
27     CHECK_NE(obj_data, nullptr);
28
29 #define SLICE_START_END(start_arg, end_arg, end_max)                        \
30   size_t start;                                                             \
31   size_t end;                                                               \
32   CHECK_NOT_OOB(ParseArrayIndex(start_arg, 0, &start));                     \
33   CHECK_NOT_OOB(ParseArrayIndex(end_arg, end_max, &end));                   \
34   if (end < start) end = start;                                             \
35   CHECK_NOT_OOB(end <= end_max);                                            \
36   size_t length = end - start;
37
38 namespace node {
39 namespace Buffer {
40
41 using v8::Context;
42 using v8::EscapableHandleScope;
43 using v8::Function;
44 using v8::FunctionCallbackInfo;
45 using v8::FunctionTemplate;
46 using v8::Handle;
47 using v8::HandleScope;
48 using v8::Isolate;
49 using v8::Local;
50 using v8::Number;
51 using v8::Object;
52 using v8::String;
53 using v8::Uint32;
54 using v8::Value;
55
56
57 bool HasInstance(Handle<Value> val) {
58   return val->IsObject() && HasInstance(val.As<Object>());
59 }
60
61
62 bool HasInstance(Handle<Object> obj) {
63   if (!obj->HasIndexedPropertiesInExternalArrayData())
64     return false;
65   v8::ExternalArrayType type = obj->GetIndexedPropertiesExternalArrayDataType();
66   return type == v8::kExternalUint8Array;
67 }
68
69
70 char* Data(Handle<Value> val) {
71   CHECK(val->IsObject());
72   // Use a fully qualified name here to work around a bug in gcc 4.2.
73   // It mistakes an unadorned call to Data() for the v8::String::Data type.
74   return node::Buffer::Data(val.As<Object>());
75 }
76
77
78 char* Data(Handle<Object> obj) {
79   CHECK(obj->HasIndexedPropertiesInExternalArrayData());
80   return static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData());
81 }
82
83
84 size_t Length(Handle<Value> val) {
85   CHECK(val->IsObject());
86   return Length(val.As<Object>());
87 }
88
89
90 size_t Length(Handle<Object> obj) {
91   CHECK(obj->HasIndexedPropertiesInExternalArrayData());
92   return obj->GetIndexedPropertiesExternalArrayDataLength();
93 }
94
95
96 Local<Object> New(Isolate* isolate, Handle<String> string, enum encoding enc) {
97   EscapableHandleScope scope(isolate);
98
99   size_t length = StringBytes::Size(isolate, string, enc);
100
101   Local<Object> buf = New(length);
102   char* data = Buffer::Data(buf);
103   StringBytes::Write(isolate, data, length, string, enc);
104
105   return scope.Escape(buf);
106 }
107
108
109 Local<Object> New(Isolate* isolate, size_t length) {
110   EscapableHandleScope handle_scope(isolate);
111   Local<Object> obj = Buffer::New(Environment::GetCurrent(isolate), length);
112   return handle_scope.Escape(obj);
113 }
114
115
116 // TODO(trevnorris): these have a flaw by needing to call the Buffer inst then
117 // Alloc. continue to look for a better architecture.
118 Local<Object> New(Environment* env, size_t length) {
119   EscapableHandleScope scope(env->isolate());
120
121   CHECK_LE(length, kMaxLength);
122
123   Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
124   Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
125
126   smalloc::Alloc(env, obj, length);
127
128   return scope.Escape(obj);
129 }
130
131
132 Local<Object> New(Isolate* isolate, const char* data, size_t length) {
133   Environment* env = Environment::GetCurrent(isolate);
134   EscapableHandleScope handle_scope(env->isolate());
135   Local<Object> obj = Buffer::New(env, data, length);
136   return handle_scope.Escape(obj);
137 }
138
139
140 // TODO(trevnorris): for backwards compatibility this is left to copy the data,
141 // but for consistency w/ the other should use data. And a copy version renamed
142 // to something else.
143 Local<Object> New(Environment* env, const char* data, size_t length) {
144   EscapableHandleScope scope(env->isolate());
145
146   CHECK_LE(length, kMaxLength);
147
148   Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
149   Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
150
151   // TODO(trevnorris): done like this to handle HasInstance since only checks
152   // if external array data has been set, but would like to use a better
153   // approach if v8 provided one.
154   char* new_data;
155   if (length > 0) {
156     new_data = static_cast<char*>(malloc(length));
157     if (new_data == nullptr)
158       FatalError("node::Buffer::New(const char*, size_t)", "Out Of Memory");
159     memcpy(new_data, data, length);
160   } else {
161     new_data = nullptr;
162   }
163
164   smalloc::Alloc(env, obj, new_data, length);
165
166   return scope.Escape(obj);
167 }
168
169
170 Local<Object> New(Isolate* isolate,
171                   char* data,
172                   size_t length,
173                   smalloc::FreeCallback callback,
174                   void* hint) {
175   Environment* env = Environment::GetCurrent(isolate);
176   EscapableHandleScope handle_scope(env->isolate());
177   Local<Object> obj = Buffer::New(env, data, length, callback, hint);
178   return handle_scope.Escape(obj);
179 }
180
181
182 Local<Object> New(Environment* env,
183                   char* data,
184                   size_t length,
185                   smalloc::FreeCallback callback,
186                   void* hint) {
187   EscapableHandleScope scope(env->isolate());
188
189   CHECK_LE(length, kMaxLength);
190
191   Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
192   Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
193
194   smalloc::Alloc(env, obj, data, length, callback, hint);
195
196   return scope.Escape(obj);
197 }
198
199
200 Local<Object> Use(Isolate* isolate, char* data, uint32_t length) {
201   Environment* env = Environment::GetCurrent(isolate);
202   EscapableHandleScope handle_scope(env->isolate());
203   Local<Object> obj = Buffer::Use(env, data, length);
204   return handle_scope.Escape(obj);
205 }
206
207
208 Local<Object> Use(Environment* env, char* data, uint32_t length) {
209   EscapableHandleScope scope(env->isolate());
210
211   CHECK_LE(length, kMaxLength);
212
213   Local<Value> arg = Uint32::NewFromUnsigned(env->isolate(), length);
214   Local<Object> obj = env->buffer_constructor_function()->NewInstance(1, &arg);
215
216   smalloc::Alloc(env, obj, data, length);
217
218   return scope.Escape(obj);
219 }
220
221
222 template <encoding encoding>
223 void StringSlice(const FunctionCallbackInfo<Value>& args) {
224   Environment* env = Environment::GetCurrent(args);
225
226   ARGS_THIS(args.This())
227   SLICE_START_END(args[0], args[1], obj_length)
228
229   args.GetReturnValue().Set(
230       StringBytes::Encode(env->isolate(), obj_data + start, length, encoding));
231 }
232
233
234 template <>
235 void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
236   Environment* env = Environment::GetCurrent(args);
237
238   ARGS_THIS(args.This())
239   SLICE_START_END(args[0], args[1], obj_length)
240   length /= 2;
241
242   const char* data = obj_data + start;
243   const uint16_t* buf;
244   bool release = false;
245
246   // Node's "ucs2" encoding expects LE character data inside a Buffer, so we
247   // need to reorder on BE platforms.  See http://nodejs.org/api/buffer.html
248   // regarding Node's "ucs2" encoding specification.
249   const bool aligned = (reinterpret_cast<uintptr_t>(data) % sizeof(*buf) == 0);
250   if (IsLittleEndian() && aligned) {
251     buf = reinterpret_cast<const uint16_t*>(data);
252   } else {
253     // Make a copy to avoid unaligned accesses in v8::String::NewFromTwoByte().
254     uint16_t* copy = new uint16_t[length];
255     for (size_t i = 0, k = 0; i < length; i += 1, k += 2) {
256       // Assumes that the input is little endian.
257       const uint8_t lo = static_cast<uint8_t>(data[k + 0]);
258       const uint8_t hi = static_cast<uint8_t>(data[k + 1]);
259       copy[i] = lo | hi << 8;
260     }
261     buf = copy;
262     release = true;
263   }
264
265   args.GetReturnValue().Set(StringBytes::Encode(env->isolate(), buf, length));
266
267   if (release)
268     delete[] buf;
269 }
270
271
272 void BinarySlice(const FunctionCallbackInfo<Value>& args) {
273   StringSlice<BINARY>(args);
274 }
275
276
277 void AsciiSlice(const FunctionCallbackInfo<Value>& args) {
278   StringSlice<ASCII>(args);
279 }
280
281
282 void Utf8Slice(const FunctionCallbackInfo<Value>& args) {
283   StringSlice<UTF8>(args);
284 }
285
286
287 void Ucs2Slice(const FunctionCallbackInfo<Value>& args) {
288   StringSlice<UCS2>(args);
289 }
290
291
292 void HexSlice(const FunctionCallbackInfo<Value>& args) {
293   StringSlice<HEX>(args);
294 }
295
296
297 void Base64Slice(const FunctionCallbackInfo<Value>& args) {
298   StringSlice<BASE64>(args);
299 }
300
301
302 // bytesCopied = buffer.copy(target[, targetStart][, sourceStart][, sourceEnd]);
303 void Copy(const FunctionCallbackInfo<Value> &args) {
304   Environment* env = Environment::GetCurrent(args);
305
306   Local<Object> target = args[0]->ToObject(env->isolate());
307
308   if (!HasInstance(target))
309     return env->ThrowTypeError("first arg should be a Buffer");
310
311   ARGS_THIS(args.This())
312   size_t target_length = target->GetIndexedPropertiesExternalArrayDataLength();
313   char* target_data = static_cast<char*>(
314       target->GetIndexedPropertiesExternalArrayData());
315   size_t target_start;
316   size_t source_start;
317   size_t source_end;
318
319   CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &target_start));
320   CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &source_start));
321   CHECK_NOT_OOB(ParseArrayIndex(args[3], obj_length, &source_end));
322
323   // Copy 0 bytes; we're done
324   if (target_start >= target_length || source_start >= source_end)
325     return args.GetReturnValue().Set(0);
326
327   if (source_start > obj_length)
328     return env->ThrowRangeError("out of range index");
329
330   if (source_end - source_start > target_length - target_start)
331     source_end = source_start + target_length - target_start;
332
333   uint32_t to_copy = MIN(MIN(source_end - source_start,
334                              target_length - target_start),
335                              obj_length - source_start);
336
337   memmove(target_data + target_start, obj_data + source_start, to_copy);
338   args.GetReturnValue().Set(to_copy);
339 }
340
341
342 void Fill(const FunctionCallbackInfo<Value>& args) {
343   ARGS_THIS(args[0].As<Object>())
344
345   size_t start = args[2]->Uint32Value();
346   size_t end = args[3]->Uint32Value();
347   size_t length = end - start;
348   CHECK(length + start <= obj_length);
349
350   if (args[1]->IsNumber()) {
351     int value = args[1]->Uint32Value() & 255;
352     memset(obj_data + start, value, length);
353     return;
354   }
355
356   node::Utf8Value str(args.GetIsolate(), args[1]);
357   size_t str_length = str.length();
358   size_t in_there = str_length;
359   char* ptr = obj_data + start + str_length;
360
361   if (str_length == 0)
362     return;
363
364   memcpy(obj_data + start, *str, MIN(str_length, length));
365
366   if (str_length >= length)
367     return;
368
369   while (in_there < length - in_there) {
370     memcpy(ptr, obj_data + start, in_there);
371     ptr += in_there;
372     in_there *= 2;
373   }
374
375   if (in_there < length) {
376     memcpy(ptr, obj_data + start, length - in_there);
377     in_there = length;
378   }
379 }
380
381
382 template <encoding encoding>
383 void StringWrite(const FunctionCallbackInfo<Value>& args) {
384   Environment* env = Environment::GetCurrent(args);
385
386   ARGS_THIS(args.This())
387
388   if (!args[0]->IsString())
389     return env->ThrowTypeError("Argument must be a string");
390
391   Local<String> str = args[0]->ToString(env->isolate());
392
393   if (encoding == HEX && str->Length() % 2 != 0)
394     return env->ThrowTypeError("Invalid hex string");
395
396   size_t offset;
397   size_t max_length;
398
399   CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &offset));
400   CHECK_NOT_OOB(ParseArrayIndex(args[2], obj_length - offset, &max_length));
401
402   max_length = MIN(obj_length - offset, max_length);
403
404   if (max_length == 0)
405     return args.GetReturnValue().Set(0);
406
407   if (offset >= obj_length)
408     return env->ThrowRangeError("Offset is out of bounds");
409
410   uint32_t written = StringBytes::Write(env->isolate(),
411                                         obj_data + offset,
412                                         max_length,
413                                         str,
414                                         encoding,
415                                         nullptr);
416   args.GetReturnValue().Set(written);
417 }
418
419
420 void Base64Write(const FunctionCallbackInfo<Value>& args) {
421   StringWrite<BASE64>(args);
422 }
423
424
425 void BinaryWrite(const FunctionCallbackInfo<Value>& args) {
426   StringWrite<BINARY>(args);
427 }
428
429
430 void Utf8Write(const FunctionCallbackInfo<Value>& args) {
431   StringWrite<UTF8>(args);
432 }
433
434
435 void Ucs2Write(const FunctionCallbackInfo<Value>& args) {
436   StringWrite<UCS2>(args);
437 }
438
439
440 void HexWrite(const FunctionCallbackInfo<Value>& args) {
441   StringWrite<HEX>(args);
442 }
443
444
445 void AsciiWrite(const FunctionCallbackInfo<Value>& args) {
446   StringWrite<ASCII>(args);
447 }
448
449
450 static inline void Swizzle(char* start, unsigned int len) {
451   char* end = start + len - 1;
452   while (start < end) {
453     char tmp = *start;
454     *start++ = *end;
455     *end-- = tmp;
456   }
457 }
458
459
460 template <typename T, enum Endianness endianness>
461 void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
462   ARGS_THIS(args[0].As<Object>());
463
464   uint32_t offset = args[1]->Uint32Value();
465   CHECK_LE(offset + sizeof(T), obj_length);
466
467   union NoAlias {
468     T val;
469     char bytes[sizeof(T)];
470   };
471
472   union NoAlias na;
473   const char* ptr = static_cast<const char*>(obj_data) + offset;
474   memcpy(na.bytes, ptr, sizeof(na.bytes));
475   if (endianness != GetEndianness())
476     Swizzle(na.bytes, sizeof(na.bytes));
477
478   args.GetReturnValue().Set(na.val);
479 }
480
481
482 void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
483   ReadFloatGeneric<float, kLittleEndian>(args);
484 }
485
486
487 void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
488   ReadFloatGeneric<float, kBigEndian>(args);
489 }
490
491
492 void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
493   ReadFloatGeneric<double, kLittleEndian>(args);
494 }
495
496
497 void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
498   ReadFloatGeneric<double, kBigEndian>(args);
499 }
500
501
502 template <typename T, enum Endianness endianness>
503 uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
504   ARGS_THIS(args[0].As<Object>())
505
506   T val = args[1]->NumberValue();
507   uint32_t offset = args[2]->Uint32Value();
508   CHECK_LE(offset + sizeof(T), obj_length);
509
510   union NoAlias {
511     T val;
512     char bytes[sizeof(T)];
513   };
514
515   union NoAlias na = { val };
516   char* ptr = static_cast<char*>(obj_data) + offset;
517   if (endianness != GetEndianness())
518     Swizzle(na.bytes, sizeof(na.bytes));
519   memcpy(ptr, na.bytes, sizeof(na.bytes));
520   return offset + sizeof(na.bytes);
521 }
522
523
524 void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
525   args.GetReturnValue().Set(WriteFloatGeneric<float, kLittleEndian>(args));
526 }
527
528
529 void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
530   args.GetReturnValue().Set(WriteFloatGeneric<float, kBigEndian>(args));
531 }
532
533
534 void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
535   args.GetReturnValue().Set(WriteFloatGeneric<double, kLittleEndian>(args));
536 }
537
538
539 void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
540   args.GetReturnValue().Set(WriteFloatGeneric<double, kBigEndian>(args));
541 }
542
543
544 void ByteLength(const FunctionCallbackInfo<Value> &args) {
545   Environment* env = Environment::GetCurrent(args);
546
547   if (!args[0]->IsString())
548     return env->ThrowTypeError("Argument must be a string");
549
550   Local<String> s = args[0]->ToString(env->isolate());
551   enum encoding e = ParseEncoding(env->isolate(), args[1], UTF8);
552
553   uint32_t size = StringBytes::Size(env->isolate(), s, e);
554   args.GetReturnValue().Set(size);
555 }
556
557
558 void Compare(const FunctionCallbackInfo<Value> &args) {
559   Local<Object> obj_a = args[0].As<Object>();
560   char* obj_a_data =
561       static_cast<char*>(obj_a->GetIndexedPropertiesExternalArrayData());
562   size_t obj_a_len = obj_a->GetIndexedPropertiesExternalArrayDataLength();
563
564   Local<Object> obj_b = args[1].As<Object>();
565   char* obj_b_data =
566       static_cast<char*>(obj_b->GetIndexedPropertiesExternalArrayData());
567   size_t obj_b_len = obj_b->GetIndexedPropertiesExternalArrayDataLength();
568
569   size_t cmp_length = MIN(obj_a_len, obj_b_len);
570
571   int32_t val = memcmp(obj_a_data, obj_b_data, cmp_length);
572
573   // Normalize val to be an integer in the range of [1, -1] since
574   // implementations of memcmp() can vary by platform.
575   if (val == 0) {
576     if (obj_a_len > obj_b_len)
577       val = 1;
578     else if (obj_a_len < obj_b_len)
579       val = -1;
580   } else {
581     if (val > 0)
582       val = 1;
583     else
584       val = -1;
585   }
586
587   args.GetReturnValue().Set(val);
588 }
589
590
591 int32_t IndexOf(const char* haystack,
592                 size_t h_length,
593                 const char* needle,
594                 size_t n_length) {
595   CHECK_GE(h_length, n_length);
596   // TODO(trevnorris): Implement Boyer-Moore string search algorithm.
597   for (size_t i = 0; i < h_length - n_length + 1; i++) {
598     if (haystack[i] == needle[0]) {
599       if (memcmp(haystack + i, needle, n_length) == 0)
600         return i;
601     }
602   }
603   return -1;
604 }
605
606
607 void IndexOfString(const FunctionCallbackInfo<Value>& args) {
608   ASSERT(args[0]->IsObject());
609   ASSERT(args[1]->IsString());
610   ASSERT(args[2]->IsNumber());
611
612   ARGS_THIS(args[0].As<Object>());
613   node::Utf8Value str(args.GetIsolate(), args[1]);
614   int32_t offset_i32 = args[2]->Int32Value();
615   uint32_t offset;
616
617   if (offset_i32 < 0) {
618     if (offset_i32 + static_cast<int32_t>(obj_length) < 0)
619       offset = 0;
620     else
621       offset = static_cast<uint32_t>(obj_length + offset_i32);
622   } else {
623     offset = static_cast<uint32_t>(offset_i32);
624   }
625
626   if (str.length() == 0 ||
627       obj_length == 0 ||
628       (offset != 0 && str.length() + offset <= str.length()) ||
629       str.length() + offset > obj_length)
630     return args.GetReturnValue().Set(-1);
631
632   int32_t r =
633       IndexOf(obj_data + offset, obj_length - offset, *str, str.length());
634   args.GetReturnValue().Set(r == -1 ? -1 : static_cast<int32_t>(r + offset));
635 }
636
637
638 void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
639   ASSERT(args[0]->IsObject());
640   ASSERT(args[1]->IsObject());
641   ASSERT(args[2]->IsNumber());
642
643   ARGS_THIS(args[0].As<Object>());
644   Local<Object> buf = args[1].As<Object>();
645   int32_t offset_i32 = args[2]->Int32Value();
646   size_t buf_length = buf->GetIndexedPropertiesExternalArrayDataLength();
647   char* buf_data =
648       static_cast<char*>(buf->GetIndexedPropertiesExternalArrayData());
649   uint32_t offset;
650
651   if (buf_length > 0)
652     CHECK_NE(buf_data, nullptr);
653
654   if (offset_i32 < 0) {
655     if (offset_i32 + static_cast<int32_t>(obj_length) < 0)
656       offset = 0;
657     else
658       offset = static_cast<uint32_t>(obj_length + offset_i32);
659   } else {
660     offset = static_cast<uint32_t>(offset_i32);
661   }
662
663   if (buf_length == 0 ||
664       obj_length == 0 ||
665       (offset != 0 && buf_length + offset <= buf_length) ||
666       buf_length + offset > obj_length)
667     return args.GetReturnValue().Set(-1);
668
669   int32_t r =
670     IndexOf(obj_data + offset, obj_length - offset, buf_data, buf_length);
671   args.GetReturnValue().Set(r == -1 ? -1 : static_cast<int32_t>(r + offset));
672 }
673
674
675 void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
676   ASSERT(args[0]->IsObject());
677   ASSERT(args[1]->IsNumber());
678   ASSERT(args[2]->IsNumber());
679
680   ARGS_THIS(args[0].As<Object>());
681   uint32_t needle = args[1]->Uint32Value();
682   int32_t offset_i32 = args[2]->Int32Value();
683   uint32_t offset;
684
685   if (offset_i32 < 0) {
686     if (offset_i32 + static_cast<int32_t>(obj_length) < 0)
687       offset = 0;
688     else
689       offset = static_cast<uint32_t>(obj_length + offset_i32);
690   } else {
691     offset = static_cast<uint32_t>(offset_i32);
692   }
693
694   if (obj_length == 0 || offset + 1 > obj_length)
695     return args.GetReturnValue().Set(-1);
696
697   void* ptr = memchr(obj_data + offset, needle, obj_length - offset);
698   char* ptr_char = static_cast<char*>(ptr);
699   args.GetReturnValue().Set(
700       ptr ? static_cast<int32_t>(ptr_char - obj_data) : -1);
701 }
702
703
704 // pass Buffer object to load prototype methods
705 void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
706   Environment* env = Environment::GetCurrent(args);
707
708   CHECK(args[0]->IsFunction());
709
710   Local<Function> bv = args[0].As<Function>();
711   env->set_buffer_constructor_function(bv);
712   Local<Value> proto_v = bv->Get(env->prototype_string());
713
714   CHECK(proto_v->IsObject());
715
716   Local<Object> proto = proto_v.As<Object>();
717
718   env->SetMethod(proto, "asciiSlice", AsciiSlice);
719   env->SetMethod(proto, "base64Slice", Base64Slice);
720   env->SetMethod(proto, "binarySlice", BinarySlice);
721   env->SetMethod(proto, "hexSlice", HexSlice);
722   env->SetMethod(proto, "ucs2Slice", Ucs2Slice);
723   env->SetMethod(proto, "utf8Slice", Utf8Slice);
724
725   env->SetMethod(proto, "asciiWrite", AsciiWrite);
726   env->SetMethod(proto, "base64Write", Base64Write);
727   env->SetMethod(proto, "binaryWrite", BinaryWrite);
728   env->SetMethod(proto, "hexWrite", HexWrite);
729   env->SetMethod(proto, "ucs2Write", Ucs2Write);
730   env->SetMethod(proto, "utf8Write", Utf8Write);
731
732   env->SetMethod(proto, "copy", Copy);
733
734   // for backwards compatibility
735   proto->ForceSet(env->offset_string(),
736                   Uint32::New(env->isolate(), 0),
737                   v8::ReadOnly);
738 }
739
740
741 void Initialize(Handle<Object> target,
742                 Handle<Value> unused,
743                 Handle<Context> context) {
744   Environment* env = Environment::GetCurrent(context);
745
746   env->SetMethod(target, "setupBufferJS", SetupBufferJS);
747
748   env->SetMethod(target, "byteLength", ByteLength);
749   env->SetMethod(target, "compare", Compare);
750   env->SetMethod(target, "fill", Fill);
751   env->SetMethod(target, "indexOfBuffer", IndexOfBuffer);
752   env->SetMethod(target, "indexOfNumber", IndexOfNumber);
753   env->SetMethod(target, "indexOfString", IndexOfString);
754
755   env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
756   env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
757   env->SetMethod(target, "readFloatBE", ReadFloatBE);
758   env->SetMethod(target, "readFloatLE", ReadFloatLE);
759
760   env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
761   env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
762   env->SetMethod(target, "writeFloatBE", WriteFloatBE);
763   env->SetMethod(target, "writeFloatLE", WriteFloatLE);
764 }
765
766
767 }  // namespace Buffer
768 }  // namespace node
769
770 NODE_MODULE_CONTEXT_AWARE_BUILTIN(buffer, node::Buffer::Initialize)