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 SlowBuffer = process.binding('buffer').SlowBuffer;
26 if (n < 16) return '0' + n.toString(16);
27 return n.toString(16);
31 SlowBuffer.prototype.inspect = function() {
34 for (var i = 0; i < len; i++) {
35 out[i] = toHex(this[i]);
37 return '<SlowBuffer ' + out.join(' ') + '>';
41 SlowBuffer.prototype.hexSlice = function(start, end) {
42 var len = this.length;
44 if (!start || start < 0) start = 0;
45 if (end < 0 || start + end > len) end = len - start;
48 for (var i = start; i < end; i ++) {
49 out += toHex(this[i]);
56 SlowBuffer.prototype.toString = function(encoding, start, end) {
57 encoding = String(encoding || 'utf8').toLowerCase();
59 if (typeof end == 'undefined') end = this.length;
61 // Fastpath empty strings
68 return this.hexSlice(start, end);
72 return this.utf8Slice(start, end);
75 return this.asciiSlice(start, end);
78 return this.binarySlice(start, end);
81 return this.base64Slice(start, end);
85 return this.ucs2Slice(start, end);
88 throw new Error('Unknown encoding');
93 SlowBuffer.prototype.hexWrite = function(string, offset) {
94 var len = string.length;
95 offset = +offset || 0;
97 // must be an even number of digits
99 throw new Error('Invalid hex string');
101 for (var i = 0; i < len / 2; i ++) {
102 var byte = parseInt(string.substr(i * 2, 2), 16);
103 if (isNaN(byte)) throw new Error('Invalid hex string');
104 this[offset + i] = byte;
110 SlowBuffer.prototype.write = function(string, offset, encoding) {
111 // Support both (string, offset, encoding)
112 // and the legacy (string, encoding, offset)
113 if (!isFinite(offset)) {
119 offset = +offset || 0;
120 encoding = String(encoding || 'utf8').toLowerCase();
124 return this.hexWrite(string, offset);
128 return this.utf8Write(string, offset);
131 return this.asciiWrite(string, offset);
134 return this.binaryWrite(string, offset);
137 return this.base64Write(string, offset);
141 return this.ucs2Write(start, end);
144 throw new Error('Unknown encoding');
150 SlowBuffer.prototype.slice = function(start, end) {
151 if (end > this.length) {
152 throw new Error('oob');
155 throw new Error('oob');
158 return new Buffer(this, end - start, +start);
164 function Buffer(subject, encoding, offset) {
165 if (!(this instanceof Buffer)) {
166 return new Buffer(subject, encoding, offset);
172 if (typeof offset === 'number') {
173 this.length = encoding;
174 this.parent = subject;
175 this.offset = offset;
178 switch (type = typeof subject) {
180 this.length = subject;
184 this.length = Buffer.byteLength(subject, encoding);
187 case 'object': // Assume object is an array
188 this.length = subject.length;
192 throw new Error('First argument needs to be a number, ' +
196 if (this.length > Buffer.poolSize) {
197 // Big buffer, just alloc one.
198 this.parent = new SlowBuffer(this.length);
203 if (!pool || pool.length - pool.used < this.length) allocPool();
205 this.offset = pool.used;
206 pool.used += this.length;
209 // Treat array-ish objects as a byte array.
210 if (isArrayIsh(subject)) {
211 for (var i = 0; i < this.length; i++) {
212 this.parent[i + this.offset] = subject[i];
214 } else if (type == 'string') {
216 this.length = this.write(subject, 0, encoding);
220 SlowBuffer.makeFastBuffer(this.parent, this, this.offset, this.length);
223 function isArrayIsh(subject) {
224 return Array.isArray(subject) || Buffer.isBuffer(subject) ||
225 subject && typeof subject === 'object' &&
226 typeof subject.length === 'number';
229 exports.SlowBuffer = SlowBuffer;
230 exports.Buffer = Buffer;
232 Buffer.poolSize = 8 * 1024;
235 function allocPool() {
236 pool = new SlowBuffer(Buffer.poolSize);
242 Buffer.isBuffer = function isBuffer(b) {
243 return b instanceof Buffer || b instanceof SlowBuffer;
248 Buffer.prototype.inspect = function inspect() {
251 for (var i = 0; i < len; i++) {
252 out[i] = toHex(this.parent[i + this.offset]);
254 return '<Buffer ' + out.join(' ') + '>';
258 Buffer.prototype.get = function get(i) {
259 if (i < 0 || i >= this.length) throw new Error('oob');
260 return this.parent[this.offset + i];
264 Buffer.prototype.set = function set(i, v) {
265 if (i < 0 || i >= this.length) throw new Error('oob');
266 return this.parent[this.offset + i] = v;
270 // write(string, offset = 0, encoding = 'utf8')
271 Buffer.prototype.write = function(string, offset, encoding) {
272 if (!isFinite(offset)) {
278 offset = +offset || 0;
279 encoding = String(encoding || 'utf8').toLowerCase();
281 // Make sure we are not going to overflow
282 var maxLength = this.length - offset;
287 ret = this.parent.hexWrite(string, this.offset + offset, maxLength);
292 ret = this.parent.utf8Write(string, this.offset + offset, maxLength);
296 ret = this.parent.asciiWrite(string, this.offset + offset, maxLength);
300 ret = this.parent.binaryWrite(string, this.offset + offset, maxLength);
304 // Warning: maxLength not taken into account in base64Write
305 ret = this.parent.base64Write(string, this.offset + offset, maxLength);
310 ret = this.parent.ucs2Write(string, this.offset + offset, maxLength);
314 throw new Error('Unknown encoding');
317 Buffer._charsWritten = SlowBuffer._charsWritten;
323 // toString(encoding, start=0, end=buffer.length)
324 Buffer.prototype.toString = function(encoding, start, end) {
325 encoding = String(encoding || 'utf8').toLowerCase();
327 if (typeof start == 'undefined' || start < 0) {
329 } else if (start > this.length) {
333 if (typeof end == 'undefined' || end > this.length) {
335 } else if (end < 0) {
339 start = start + this.offset;
340 end = end + this.offset;
344 return this.parent.hexSlice(start, end);
348 return this.parent.utf8Slice(start, end);
351 return this.parent.asciiSlice(start, end);
354 return this.parent.binarySlice(start, end);
357 return this.parent.base64Slice(start, end);
361 return this.parent.ucs2Slice(start, end);
364 throw new Error('Unknown encoding');
370 Buffer.byteLength = SlowBuffer.byteLength;
373 // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
374 Buffer.prototype.copy = function(target, target_start, start, end) {
376 start || (start = 0);
377 end || (end = this.length);
378 target_start || (target_start = 0);
380 if (end < start) throw new Error('sourceEnd < sourceStart');
382 // Copy 0 bytes; we're done
383 if (end === start) return 0;
384 if (target.length == 0 || source.length == 0) return 0;
386 if (target_start < 0 || target_start >= target.length) {
387 throw new Error('targetStart out of bounds');
390 if (start < 0 || start >= source.length) {
391 throw new Error('sourceStart out of bounds');
394 if (end < 0 || end > source.length) {
395 throw new Error('sourceEnd out of bounds');
399 if (end > this.length) {
403 if (target.length - target_start < end - start) {
404 end = target.length - target_start + start;
407 return this.parent.copy(target.parent,
408 target_start + target.offset,
415 Buffer.prototype.slice = function(start, end) {
416 if (end === undefined) end = this.length;
417 if (end > this.length) throw new Error('oob');
418 if (start > end) throw new Error('oob');
420 return new Buffer(this.parent, end - start, +start + this.offset);
424 // Legacy methods for backwards compatibility.
426 Buffer.prototype.utf8Slice = function(start, end) {
427 return this.toString('utf8', start, end);
430 Buffer.prototype.binarySlice = function(start, end) {
431 return this.toString('binary', start, end);
434 Buffer.prototype.asciiSlice = function(start, end) {
435 return this.toString('ascii', start, end);
438 Buffer.prototype.utf8Write = function(string, offset) {
439 return this.write(string, offset, 'utf8');
442 Buffer.prototype.binaryWrite = function(string, offset) {
443 return this.write(string, offset, 'binary');
446 Buffer.prototype.asciiWrite = function(string, offset) {
447 return this.write(string, offset, 'ascii');