2 * Implementation of a subset of node.js Buffer methods for the browser.
3 * Based on https://github.com/feross/buffer
6 /* eslint-disable no-proto */
10 var isArray = require('isarray')
12 function typedArraySupport () {
13 // Can typed array instances be augmented?
15 var arr = new Uint8Array(1)
16 arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
17 return arr.foo() === 42
23 Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
25 var K_MAX_LENGTH = Buffer.TYPED_ARRAY_SUPPORT
29 function Buffer (arg, offset, length) {
30 if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
31 return new Buffer(arg, offset, length)
34 if (typeof arg === 'number') {
35 return allocUnsafe(this, arg)
38 return from(this, arg, offset, length)
41 if (Buffer.TYPED_ARRAY_SUPPORT) {
42 Buffer.prototype.__proto__ = Uint8Array.prototype
43 Buffer.__proto__ = Uint8Array
45 // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
46 if (typeof Symbol !== 'undefined' && Symbol.species &&
47 Buffer[Symbol.species] === Buffer) {
48 Object.defineProperty(Buffer, Symbol.species, {
57 function checked (length) {
58 // Note: cannot use `length < K_MAX_LENGTH` here because that fails when
59 // length is NaN (which is otherwise coerced to zero.)
60 if (length >= K_MAX_LENGTH) {
61 throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
62 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
67 function isnan (val) {
68 return val !== val // eslint-disable-line no-self-compare
71 function createBuffer (that, length) {
73 if (Buffer.TYPED_ARRAY_SUPPORT) {
74 buf = new Uint8Array(length)
75 buf.__proto__ = Buffer.prototype
77 // Fallback: Return an object instance of the Buffer class
80 buf = new Buffer(length)
88 function allocUnsafe (that, size) {
89 var buf = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
91 if (!Buffer.TYPED_ARRAY_SUPPORT) {
92 for (var i = 0; i < size; ++i) {
100 function fromString (that, string) {
101 var length = byteLength(string) | 0
102 var buf = createBuffer(that, length)
104 var actual = buf.write(string)
106 if (actual !== length) {
107 // Writing a hex string, for example, that contains invalid characters will
108 // cause everything after the first invalid character to be ignored. (e.g.
109 // 'abxxcd' will be treated as 'ab')
110 buf = buf.slice(0, actual)
116 function fromArrayLike (that, array) {
117 var length = array.length < 0 ? 0 : checked(array.length) | 0
118 var buf = createBuffer(that, length)
119 for (var i = 0; i < length; i += 1) {
120 buf[i] = array[i] & 255
125 function fromArrayBuffer (that, array, byteOffset, length) {
126 if (byteOffset < 0 || array.byteLength < byteOffset) {
127 throw new RangeError('\'offset\' is out of bounds')
130 if (array.byteLength < byteOffset + (length || 0)) {
131 throw new RangeError('\'length\' is out of bounds')
135 if (byteOffset === undefined && length === undefined) {
136 buf = new Uint8Array(array)
137 } else if (length === undefined) {
138 buf = new Uint8Array(array, byteOffset)
140 buf = new Uint8Array(array, byteOffset, length)
143 if (Buffer.TYPED_ARRAY_SUPPORT) {
144 // Return an augmented `Uint8Array` instance, for best performance
145 buf.__proto__ = Buffer.prototype
147 // Fallback: Return an object instance of the Buffer class
148 buf = fromArrayLike(that, buf)
154 function fromObject (that, obj) {
155 if (Buffer.isBuffer(obj)) {
156 var len = checked(obj.length) | 0
157 var buf = createBuffer(that, len)
159 if (buf.length === 0) {
163 obj.copy(buf, 0, 0, len)
168 if ((typeof ArrayBuffer !== 'undefined' &&
169 obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
170 if (typeof obj.length !== 'number' || isnan(obj.length)) {
171 return createBuffer(that, 0)
173 return fromArrayLike(that, obj)
176 if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
177 return fromArrayLike(that, obj.data)
181 throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
184 function utf8ToBytes (string, units) {
185 units = units || Infinity
187 var length = string.length
188 var leadSurrogate = null
191 for (var i = 0; i < length; ++i) {
192 codePoint = string.charCodeAt(i)
194 // is surrogate component
195 if (codePoint > 0xD7FF && codePoint < 0xE000) {
196 // last char was a lead
197 if (!leadSurrogate) {
199 if (codePoint > 0xDBFF) {
201 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
203 } else if (i + 1 === length) {
205 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
210 leadSurrogate = codePoint
216 if (codePoint < 0xDC00) {
217 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
218 leadSurrogate = codePoint
222 // valid surrogate pair
223 codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
224 } else if (leadSurrogate) {
225 // valid bmp char, but last char was a lead
226 if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
232 if (codePoint < 0x80) {
233 if ((units -= 1) < 0) break
234 bytes.push(codePoint)
235 } else if (codePoint < 0x800) {
236 if ((units -= 2) < 0) break
238 codePoint >> 0x6 | 0xC0,
239 codePoint & 0x3F | 0x80
241 } else if (codePoint < 0x10000) {
242 if ((units -= 3) < 0) break
244 codePoint >> 0xC | 0xE0,
245 codePoint >> 0x6 & 0x3F | 0x80,
246 codePoint & 0x3F | 0x80
248 } else if (codePoint < 0x110000) {
249 if ((units -= 4) < 0) break
251 codePoint >> 0x12 | 0xF0,
252 codePoint >> 0xC & 0x3F | 0x80,
253 codePoint >> 0x6 & 0x3F | 0x80,
254 codePoint & 0x3F | 0x80
257 throw new Error('Invalid code point')
264 function byteLength (string) {
265 if (Buffer.isBuffer(string)) {
268 if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
269 (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
270 return string.byteLength
272 if (typeof string !== 'string') {
276 var len = string.length
277 if (len === 0) return 0
279 return utf8ToBytes(string).length
282 function blitBuffer (src, dst, offset, length) {
283 for (var i = 0; i < length; ++i) {
284 if ((i + offset >= dst.length) || (i >= src.length)) break
285 dst[i + offset] = src[i]
290 function utf8Write (buf, string, offset, length) {
291 return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
294 function from (that, value, offset, length) {
295 if (typeof value === 'number') {
296 throw new TypeError('"value" argument must not be a number')
299 if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
300 return fromArrayBuffer(that, value, offset, length)
303 if (typeof value === 'string') {
304 return fromString(that, value, offset)
307 return fromObject(that, value)
310 Buffer.prototype.write = function write (string, offset, length) {
311 // Buffer#write(string)
312 if (offset === undefined) {
315 // Buffer#write(string, encoding)
316 } else if (length === undefined && typeof offset === 'string') {
319 // Buffer#write(string, offset[, length])
320 } else if (isFinite(offset)) {
322 if (isFinite(length)) {
329 var remaining = this.length - offset
330 if (length === undefined || length > remaining) length = remaining
332 if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
333 throw new RangeError('Attempt to write outside buffer bounds')
336 return utf8Write(this, string, offset, length)
339 Buffer.prototype.slice = function slice (start, end) {
340 var len = this.length
342 end = end === undefined ? len : ~~end
346 if (start < 0) start = 0
347 } else if (start > len) {
354 } else if (end > len) {
358 if (end < start) end = start
361 if (Buffer.TYPED_ARRAY_SUPPORT) {
362 newBuf = this.subarray(start, end)
363 // Return an augmented `Uint8Array` instance
364 newBuf.__proto__ = Buffer.prototype
366 var sliceLen = end - start
367 newBuf = new Buffer(sliceLen, undefined)
368 for (var i = 0; i < sliceLen; ++i) {
369 newBuf[i] = this[i + start]
376 Buffer.prototype.copy = function copy (target, targetStart, start, end) {
377 if (!start) start = 0
378 if (!end && end !== 0) end = this.length
379 if (targetStart >= target.length) targetStart = target.length
380 if (!targetStart) targetStart = 0
381 if (end > 0 && end < start) end = start
383 // Copy 0 bytes; we're done
384 if (end === start) return 0
385 if (target.length === 0 || this.length === 0) return 0
387 // Fatal error conditions
388 if (targetStart < 0) {
389 throw new RangeError('targetStart out of bounds')
391 if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
392 if (end < 0) throw new RangeError('sourceEnd out of bounds')
395 if (end > this.length) end = this.length
396 if (target.length - targetStart < end - start) {
397 end = target.length - targetStart + start
400 var len = end - start
403 if (this === target && start < targetStart && targetStart < end) {
404 // descending copy from end
405 for (i = len - 1; i >= 0; --i) {
406 target[i + targetStart] = this[i + start]
408 } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
409 // ascending copy from start
410 for (i = 0; i < len; ++i) {
411 target[i + targetStart] = this[i + start]
414 Uint8Array.prototype.set.call(
416 this.subarray(start, start + len),
424 Buffer.prototype.fill = function fill (val, start, end) {
425 // Handle string cases:
426 if (typeof val === 'string') {
427 if (typeof start === 'string') {
430 } else if (typeof end === 'string') {
433 if (val.length === 1) {
434 var code = val.charCodeAt(0)
439 } else if (typeof val === 'number') {
443 // Invalid ranges are not set to a default, so can range check early.
444 if (start < 0 || this.length < start || this.length < end) {
445 throw new RangeError('Out of range index')
453 end = end === undefined ? this.length : end >>> 0
458 if (typeof val === 'number') {
459 for (i = start; i < end; ++i) {
463 var bytes = Buffer.isBuffer(val)
466 var len = bytes.length
467 for (i = 0; i < end - start; ++i) {
468 this[i + start] = bytes[i % len]
475 Buffer.concat = function concat (list, length) {
476 if (!isArray(list)) {
477 throw new TypeError('"list" argument must be an Array of Buffers')
480 if (list.length === 0) {
481 return createBuffer(null, 0)
485 if (length === undefined) {
487 for (i = 0; i < list.length; ++i) {
488 length += list[i].length
492 var buffer = allocUnsafe(null, length)
494 for (i = 0; i < list.length; ++i) {
496 if (!Buffer.isBuffer(buf)) {
497 throw new TypeError('"list" argument must be an Array of Buffers')
499 buf.copy(buffer, pos)
505 Buffer.byteLength = byteLength
507 Buffer.prototype._isBuffer = true
508 Buffer.isBuffer = function isBuffer (b) {
509 return !!(b != null && b._isBuffer)
512 module.exports.alloc = function (size) {
513 var buffer = new Buffer(size)
518 module.exports.from = function (data) {
519 return new Buffer(data)