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