1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 var buffer = process.binding('buffer');
23 var smalloc = process.binding('smalloc');
24 var util = require('util');
25 var alloc = smalloc.alloc;
26 var truncate = smalloc.truncate;
27 var sliceOnto = smalloc.sliceOnto;
28 var kMaxLength = smalloc.kMaxLength;
31 exports.Buffer = Buffer;
32 exports.SlowBuffer = SlowBuffer;
33 exports.INSPECT_MAX_BYTES = 50;
36 Buffer.poolSize = 8 * 1024;
37 var poolSize, poolOffset, allocPool;
40 function createPool() {
41 poolSize = Buffer.poolSize;
42 allocPool = alloc({}, poolSize);
48 function Buffer(subject, encoding) {
49 if (!util.isBuffer(this))
50 return new Buffer(subject, encoding);
52 if (util.isNumber(subject))
53 this.length = subject > 0 ? subject >>> 0 : 0;
54 else if (util.isString(subject))
55 this.length = Buffer.byteLength(subject, encoding = encoding || 'utf8');
56 else if (util.isObject(subject)) {
57 if (subject.type === 'Buffer' && util.isArray(subject.data))
58 subject = subject.data;
60 this.length = +subject.length > 0 ? Math.floor(+subject.length) : 0;
62 throw new TypeError('must start with number, buffer, array or string');
64 if (this.length > kMaxLength) {
65 throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
66 'size: 0x' + kMaxLength.toString(16) + ' bytes');
69 if (this.length <= (Buffer.poolSize >>> 1) && this.length > 0) {
70 if (this.length > poolSize - poolOffset)
72 this.parent = sliceOnto(allocPool,
75 poolOffset + this.length);
76 poolOffset += this.length;
78 alloc(this, this.length);
81 if (!util.isNumber(subject)) {
82 if (util.isString(subject)) {
83 // In the case of base64 it's possible that the size of the buffer
84 // allocated was slightly too large. In this case we need to rewrite
85 // the length to the actual length written.
86 var len = this.write(subject, encoding);
88 // Buffer was truncated after decode, realloc internal ExternalArray
89 if (len !== this.length) {
91 truncate(this, this.length);
94 if (util.isBuffer(subject))
95 subject.copy(this, 0, 0, this.length);
96 else if (util.isNumber(subject.length) || util.isArray(subject))
97 for (var i = 0; i < this.length; i++)
104 function SlowBuffer(length) {
105 length = length >>> 0;
106 if (length > kMaxLength) {
107 throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
108 'size: 0x' + kMaxLength.toString(16) + ' bytes');
110 var b = new NativeBuffer(length);
116 // Bypass all checks for instantiating unallocated Buffer required for
117 // Objects created in C++. Significantly faster than calling the Buffer
119 function NativeBuffer(length) {
120 this.length = length;
122 NativeBuffer.prototype = Buffer.prototype;
125 // add methods to Buffer prototype
126 buffer.setupBufferJS(NativeBuffer, internal);
131 Buffer.isBuffer = function isBuffer(b) {
132 return util.isBuffer(b);
136 Buffer.compare = function compare(a, b) {
137 if (!(a instanceof Buffer) ||
138 !(b instanceof Buffer))
139 throw new TypeError('Arguments must be Buffers');
141 return internal.compare(a, b);
145 Buffer.isEncoding = function(encoding) {
146 switch ((encoding + '').toLowerCase()) {
166 Buffer.concat = function(list, length) {
167 if (!util.isArray(list))
168 throw new TypeError('Usage: Buffer.concat(list[, length])');
170 if (util.isUndefined(length)) {
172 for (var i = 0; i < list.length; i++)
173 length += list[i].length;
175 length = length >>> 0;
178 if (list.length === 0)
179 return new Buffer(0);
180 else if (list.length === 1)
183 var buffer = new Buffer(length);
185 for (var i = 0; i < list.length; i++) {
187 buf.copy(buffer, pos);
195 Buffer.byteLength = function(str, enc) {
208 ret = str.length * 2;
211 ret = str.length >>> 1;
214 ret = internal.byteLength(str, enc);
220 // pre-set for values that may exist in the future
221 Buffer.prototype.length = undefined;
222 Buffer.prototype.parent = undefined;
225 // toString(encoding, start=0, end=buffer.length)
226 Buffer.prototype.toString = function(encoding, start, end) {
227 var loweredCase = false;
230 end = util.isUndefined(end) || end === Infinity ? this.length : end >>> 0;
232 if (!encoding) encoding = 'utf8';
233 if (start < 0) start = 0;
234 if (end > this.length) end = this.length;
235 if (end <= start) return '';
240 return this.hexSlice(start, end);
244 return this.utf8Slice(start, end);
247 return this.asciiSlice(start, end);
250 return this.binarySlice(start, end);
253 return this.base64Slice(start, end);
259 return this.ucs2Slice(start, end);
263 throw new TypeError('Unknown encoding: ' + encoding);
264 encoding = (encoding + '').toLowerCase();
271 Buffer.prototype.equals = function equals(b) {
272 if (!(b instanceof Buffer))
273 throw new TypeError('Argument must be a Buffer');
275 return internal.compare(this, b) === 0;
280 Buffer.prototype.inspect = function inspect() {
282 var max = exports.INSPECT_MAX_BYTES;
283 if (this.length > 0) {
284 str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
285 if (this.length > max)
288 return '<' + this.constructor.name + ' ' + str + '>';
292 Buffer.prototype.compare = function compare(b) {
293 if (!(b instanceof Buffer))
294 throw new TypeError('Argument must be a Buffer');
296 return internal.compare(this, b);
300 // XXX remove in v0.13
301 Buffer.prototype.get = util.deprecate(function get(offset) {
303 if (offset < 0 || offset >= this.length)
304 throw new RangeError('index out of range');
306 }, '.get() is deprecated. Access using array indexes instead.');
309 // XXX remove in v0.13
310 Buffer.prototype.set = util.deprecate(function set(offset, v) {
312 if (offset < 0 || offset >= this.length)
313 throw new RangeError('index out of range');
314 return this[offset] = v;
315 }, '.set() is deprecated. Set using array indexes instead.');
318 // TODO(trevnorris): fix these checks to follow new standard
319 // write(string, offset = 0, length = buffer.length, encoding = 'utf8')
320 var writeWarned = false;
321 var writeMsg = '.write(string, encoding, offset, length) is deprecated.' +
322 ' Use write(string[, offset[, length]][, encoding]) instead.';
323 Buffer.prototype.write = function(string, offset, length, encoding) {
324 // Buffer#write(string);
325 if (util.isUndefined(offset)) {
327 length = this.length;
330 // Buffer#write(string, encoding)
331 } else if (util.isUndefined(length) && util.isString(offset)) {
333 length = this.length;
336 // Buffer#write(string, offset[, length][, encoding])
337 } else if (isFinite(offset)) {
338 offset = offset >>> 0;
339 if (isFinite(length)) {
340 length = length >>> 0;
341 if (util.isUndefined(encoding))
348 // XXX legacy write(string, encoding, offset, length) - remove in v0.13
351 if (process.throwDeprecation)
352 throw new Error(writeMsg);
353 else if (process.traceDeprecation)
354 console.trace(writeMsg);
356 console.error(writeMsg);
362 offset = length >>> 0;
366 var remaining = this.length - offset;
367 if (util.isUndefined(length) || length > remaining)
370 encoding = !!encoding ? (encoding + '').toLowerCase() : 'utf8';
372 if (string.length > 0 && (length < 0 || offset < 0))
373 throw new RangeError('attempt to write outside buffer bounds');
378 ret = this.hexWrite(string, offset, length);
383 ret = this.utf8Write(string, offset, length);
387 ret = this.asciiWrite(string, offset, length);
391 ret = this.binaryWrite(string, offset, length);
395 // Warning: maxLength not taken into account in base64Write
396 ret = this.base64Write(string, offset, length);
403 ret = this.ucs2Write(string, offset, length);
407 throw new TypeError('Unknown encoding: ' + encoding);
414 Buffer.prototype.toJSON = function() {
417 data: Array.prototype.slice.call(this, 0)
422 // TODO(trevnorris): currently works like Array.prototype.slice(), which
423 // doesn't follow the new standard for throwing on out of range indexes.
424 Buffer.prototype.slice = function(start, end) {
425 var len = this.length;
427 end = util.isUndefined(end) ? len : ~~end;
433 } else if (start > len) {
441 } else if (end > len) {
448 var buf = new NativeBuffer();
449 sliceOnto(this, buf, start, end);
450 buf.length = end - start;
452 buf.parent = util.isUndefined(this.parent) ? this : this.parent;
458 function checkOffset(offset, ext, length) {
459 if (offset + ext > length)
460 throw new RangeError('index out of range');
464 Buffer.prototype.readUInt8 = function(offset, noAssert) {
465 offset = offset >>> 0;
467 checkOffset(offset, 1, this.length);
472 Buffer.prototype.readUInt16LE = function(offset, noAssert) {
473 offset = offset >>> 0;
475 checkOffset(offset, 2, this.length);
476 return this[offset] | (this[offset + 1] << 8);
480 Buffer.prototype.readUInt16BE = function(offset, noAssert) {
481 offset = offset >>> 0;
483 checkOffset(offset, 2, this.length);
484 return (this[offset] << 8) | this[offset + 1];
488 Buffer.prototype.readUInt32LE = function(offset, noAssert) {
489 offset = offset >>> 0;
491 checkOffset(offset, 4, this.length);
493 return ((this[offset]) |
494 (this[offset + 1] << 8) |
495 (this[offset + 2] << 16)) +
496 (this[offset + 3] * 0x1000000);
500 Buffer.prototype.readUInt32BE = function(offset, noAssert) {
501 offset = offset >>> 0;
503 checkOffset(offset, 4, this.length);
505 return (this[offset] * 0x1000000) +
506 ((this[offset + 1] << 16) |
507 (this[offset + 2] << 8) |
512 Buffer.prototype.readInt8 = function(offset, noAssert) {
513 offset = offset >>> 0;
515 checkOffset(offset, 1, this.length);
516 var val = this[offset];
517 return !(val & 0x80) ? val : (0xff - val + 1) * -1;
521 Buffer.prototype.readInt16LE = function(offset, noAssert) {
522 offset = offset >>> 0;
524 checkOffset(offset, 2, this.length);
525 var val = this[offset] | (this[offset + 1] << 8);
526 return (val & 0x8000) ? val | 0xFFFF0000 : val;
530 Buffer.prototype.readInt16BE = function(offset, noAssert) {
531 offset = offset >>> 0;
533 checkOffset(offset, 2, this.length);
534 var val = this[offset + 1] | (this[offset] << 8);
535 return (val & 0x8000) ? val | 0xFFFF0000 : val;
539 Buffer.prototype.readInt32LE = function(offset, noAssert) {
540 offset = offset >>> 0;
542 checkOffset(offset, 4, this.length);
544 return (this[offset]) |
545 (this[offset + 1] << 8) |
546 (this[offset + 2] << 16) |
547 (this[offset + 3] << 24);
551 Buffer.prototype.readInt32BE = function(offset, noAssert) {
552 offset = offset >>> 0;
554 checkOffset(offset, 4, this.length);
556 return (this[offset] << 24) |
557 (this[offset + 1] << 16) |
558 (this[offset + 2] << 8) |
563 function checkInt(buffer, value, offset, ext, max, min) {
564 if (!(buffer instanceof Buffer))
565 throw new TypeError('buffer must be a Buffer instance');
566 if (value > max || value < min)
567 throw new TypeError('value is out of bounds');
568 if (offset + ext > buffer.length)
569 throw new RangeError('index out of range');
573 Buffer.prototype.writeUInt8 = function(value, offset, noAssert) {
575 offset = offset >>> 0;
577 checkInt(this, value, offset, 1, 0xff, 0);
578 this[offset] = value;
583 Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) {
585 offset = offset >>> 0;
587 checkInt(this, value, offset, 2, 0xffff, 0);
588 this[offset] = value;
589 this[offset + 1] = (value >>> 8);
594 Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) {
596 offset = offset >>> 0;
598 checkInt(this, value, offset, 2, 0xffff, 0);
599 this[offset] = (value >>> 8);
600 this[offset + 1] = value;
605 Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) {
607 offset = offset >>> 0;
609 checkInt(this, value, offset, 4, 0xffffffff, 0);
610 this[offset + 3] = (value >>> 24);
611 this[offset + 2] = (value >>> 16);
612 this[offset + 1] = (value >>> 8);
613 this[offset] = value;
618 Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) {
620 offset = offset >>> 0;
622 checkInt(this, value, offset, 4, 0xffffffff, 0);
623 this[offset] = (value >>> 24);
624 this[offset + 1] = (value >>> 16);
625 this[offset + 2] = (value >>> 8);
626 this[offset + 3] = value;
631 Buffer.prototype.writeInt8 = function(value, offset, noAssert) {
633 offset = offset >>> 0;
635 checkInt(this, value, offset, 1, 0x7f, -0x80);
636 this[offset] = value;
641 Buffer.prototype.writeInt16LE = function(value, offset, noAssert) {
643 offset = offset >>> 0;
645 checkInt(this, value, offset, 2, 0x7fff, -0x8000);
646 this[offset] = value;
647 this[offset + 1] = (value >>> 8);
652 Buffer.prototype.writeInt16BE = function(value, offset, noAssert) {
654 offset = offset >>> 0;
656 checkInt(this, value, offset, 2, 0x7fff, -0x8000);
657 this[offset] = (value >>> 8);
658 this[offset + 1] = value;
663 Buffer.prototype.writeInt32LE = function(value, offset, noAssert) {
665 offset = offset >>> 0;
667 checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
668 this[offset] = value;
669 this[offset + 1] = (value >>> 8);
670 this[offset + 2] = (value >>> 16);
671 this[offset + 3] = (value >>> 24);
676 Buffer.prototype.writeInt32BE = function(value, offset, noAssert) {
678 offset = offset >>> 0;
680 checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
681 this[offset] = (value >>> 24);
682 this[offset + 1] = (value >>> 16);
683 this[offset + 2] = (value >>> 8);
684 this[offset + 3] = value;