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 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 113 static inline void blob_ref(Blob *blob) { 114 blob->refs++; 115 } 116 117 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 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 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 (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 242 Buffer::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 255 Buffer::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 271 Buffer::~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 281 char* Buffer::data() { 282 char *p = blob_->data + off_; 283 DBG("Buffer::data() EX p=%p", p); 284 return p; 285 } 286 287 void 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 301 Handle<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 317 Handle<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 340 Handle<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 352 Handle<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); 364 Handle<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); 420 Handle<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); 461 Handle<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 493 Handle<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 533 Handle<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") 594 Handle<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 614 void 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