[apps/tidep0084.git] / example / iot-gateway / node_modules / bytebuffer / dist / bytebuffer-node.js
1 /*
2 Copyright 2013-2014 Daniel Wirtz <dcode@dcode.io>
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
17 /**
18 * @license bytebuffer.js (c) 2015 Daniel Wirtz <dcode@dcode.io>
19 * Backing buffer / Accessor: node Buffer
20 * Released under the Apache License, Version 2.0
21 * see: https://github.com/dcodeIO/bytebuffer.js for details
22 */
23 module.exports = (function() {
24 "use strict";
26 var buffer = require("buffer"),
27 Buffer = buffer["Buffer"],
28 Long = require("long"),
29 memcpy = null; try { memcpy = require("memcpy"); } catch (e) {}
31 /**
32 * Constructs a new ByteBuffer.
33 * @class The swiss army knife for binary data in JavaScript.
34 * @exports ByteBuffer
35 * @constructor
36 * @param {number=} capacity Initial capacity. Defaults to {@link ByteBuffer.DEFAULT_CAPACITY}.
37 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
38 * {@link ByteBuffer.DEFAULT_ENDIAN}.
39 * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
40 * {@link ByteBuffer.DEFAULT_NOASSERT}.
41 * @expose
42 */
43 var ByteBuffer = function(capacity, littleEndian, noAssert) {
44 if (typeof capacity === 'undefined')
45 capacity = ByteBuffer.DEFAULT_CAPACITY;
46 if (typeof littleEndian === 'undefined')
47 littleEndian = ByteBuffer.DEFAULT_ENDIAN;
48 if (typeof noAssert === 'undefined')
49 noAssert = ByteBuffer.DEFAULT_NOASSERT;
50 if (!noAssert) {
51 capacity = capacity | 0;
52 if (capacity < 0)
53 throw RangeError("Illegal capacity");
54 littleEndian = !!littleEndian;
55 noAssert = !!noAssert;
56 }
58 /**
59 * Backing node Buffer.
60 * @type {!Buffer}
61 * @expose
62 */
63 this.buffer = capacity === 0 ? EMPTY_BUFFER : new Buffer(capacity);
65 /**
66 * Absolute read/write offset.
67 * @type {number}
68 * @expose
69 * @see ByteBuffer#flip
70 * @see ByteBuffer#clear
71 */
72 this.offset = 0;
74 /**
75 * Marked offset.
76 * @type {number}
77 * @expose
78 * @see ByteBuffer#mark
79 * @see ByteBuffer#reset
80 */
81 this.markedOffset = -1;
83 /**
84 * Absolute limit of the contained data. Set to the backing buffer's capacity upon allocation.
85 * @type {number}
86 * @expose
87 * @see ByteBuffer#flip
88 * @see ByteBuffer#clear
89 */
90 this.limit = capacity;
92 /**
93 * Whether to use little endian byte order, defaults to `false` for big endian.
94 * @type {boolean}
95 * @expose
96 */
97 this.littleEndian = littleEndian;
99 /**
100 * Whether to skip assertions of offsets and values, defaults to `false`.
101 * @type {boolean}
102 * @expose
103 */
104 this.noAssert = noAssert;
105 };
107 /**
108 * ByteBuffer version.
109 * @type {string}
110 * @const
111 * @expose
112 */
113 ByteBuffer.VERSION = "5.0.1";
115 /**
116 * Little endian constant that can be used instead of its boolean value. Evaluates to `true`.
117 * @type {boolean}
118 * @const
119 * @expose
120 */
121 ByteBuffer.LITTLE_ENDIAN = true;
123 /**
124 * Big endian constant that can be used instead of its boolean value. Evaluates to `false`.
125 * @type {boolean}
126 * @const
127 * @expose
128 */
129 ByteBuffer.BIG_ENDIAN = false;
131 /**
132 * Default initial capacity of `16`.
133 * @type {number}
134 * @expose
135 */
136 ByteBuffer.DEFAULT_CAPACITY = 16;
138 /**
139 * Default endianess of `false` for big endian.
140 * @type {boolean}
141 * @expose
142 */
143 ByteBuffer.DEFAULT_ENDIAN = ByteBuffer.BIG_ENDIAN;
145 /**
146 * Default no assertions flag of `false`.
147 * @type {boolean}
148 * @expose
149 */
150 ByteBuffer.DEFAULT_NOASSERT = false;
152 /**
153 * A `Long` class for representing a 64-bit two's-complement integer value.
154 * @type {!Long}
155 * @const
156 * @see https://npmjs.org/package/long
157 * @expose
158 */
159 ByteBuffer.Long = Long;
161 /**
162 * @alias ByteBuffer.prototype
163 * @inner
164 */
165 var ByteBufferPrototype = ByteBuffer.prototype;
167 /**
168 * An indicator used to reliably determine if an object is a ByteBuffer or not.
169 * @type {boolean}
170 * @const
171 * @expose
172 * @private
173 */
174 ByteBufferPrototype.__isByteBuffer__;
176 Object.defineProperty(ByteBufferPrototype, "__isByteBuffer__", {
177 value: true,
178 enumerable: false,
179 configurable: false
180 });
182 // helpers
184 /**
185 * @type {!Buffer}
186 * @inner
187 */
188 var EMPTY_BUFFER = new Buffer(0);
190 /**
191 * String.fromCharCode reference for compile-time renaming.
192 * @type {function(...number):string}
193 * @inner
194 */
195 var stringFromCharCode = String.fromCharCode;
197 /**
198 * Creates a source function for a string.
199 * @param {string} s String to read from
200 * @returns {function():number|null} Source function returning the next char code respectively `null` if there are
201 * no more characters left.
202 * @throws {TypeError} If the argument is invalid
203 * @inner
204 */
205 function stringSource(s) {
206 var i=0; return function() {
207 return i < s.length ? s.charCodeAt(i++) : null;
208 };
209 }
211 /**
212 * Creates a destination function for a string.
213 * @returns {function(number=):undefined|string} Destination function successively called with the next char code.
214 * Returns the final string when called without arguments.
215 * @inner
216 */
217 function stringDestination() {
218 var cs = [], ps = []; return function() {
219 if (arguments.length === 0)
220 return ps.join('')+stringFromCharCode.apply(String, cs);
221 if (cs.length + arguments.length > 1024)
222 ps.push(stringFromCharCode.apply(String, cs)),
223 cs.length = 0;
224 Array.prototype.push.apply(cs, arguments);
225 };
226 }
228 /**
229 * Gets the accessor type.
230 * @returns {Function} `Buffer` under node.js, `Uint8Array` respectively `DataView` in the browser (classes)
231 * @expose
232 */
233 ByteBuffer.accessor = function() {
234 return Buffer;
235 };
236 /**
237 * Allocates a new ByteBuffer backed by a buffer of the specified capacity.
238 * @param {number=} capacity Initial capacity. Defaults to {@link ByteBuffer.DEFAULT_CAPACITY}.
239 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
240 * {@link ByteBuffer.DEFAULT_ENDIAN}.
241 * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
242 * {@link ByteBuffer.DEFAULT_NOASSERT}.
243 * @returns {!ByteBuffer}
244 * @expose
245 */
246 ByteBuffer.allocate = function(capacity, littleEndian, noAssert) {
247 return new ByteBuffer(capacity, littleEndian, noAssert);
248 };
250 /**
251 * Concatenates multiple ByteBuffers into one.
252 * @param {!Array.<!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string>} buffers Buffers to concatenate
253 * @param {(string|boolean)=} encoding String encoding if `buffers` contains a string ("base64", "hex", "binary",
254 * defaults to "utf8")
255 * @param {boolean=} littleEndian Whether to use little or big endian byte order for the resulting ByteBuffer. Defaults
256 * to {@link ByteBuffer.DEFAULT_ENDIAN}.
257 * @param {boolean=} noAssert Whether to skip assertions of offsets and values for the resulting ByteBuffer. Defaults to
258 * {@link ByteBuffer.DEFAULT_NOASSERT}.
259 * @returns {!ByteBuffer} Concatenated ByteBuffer
260 * @expose
261 */
262 ByteBuffer.concat = function(buffers, encoding, littleEndian, noAssert) {
263 if (typeof encoding === 'boolean' || typeof encoding !== 'string') {
264 noAssert = littleEndian;
265 littleEndian = encoding;
266 encoding = undefined;
267 }
268 var capacity = 0;
269 for (var i=0, k=buffers.length, length; i<k; ++i) {
270 if (!ByteBuffer.isByteBuffer(buffers[i]))
271 buffers[i] = ByteBuffer.wrap(buffers[i], encoding);
272 length = buffers[i].limit - buffers[i].offset;
273 if (length > 0) capacity += length;
274 }
275 if (capacity === 0)
276 return new ByteBuffer(0, littleEndian, noAssert);
277 var bb = new ByteBuffer(capacity, littleEndian, noAssert),
278 bi;
279 i=0; while (i<k) {
280 bi = buffers[i++];
281 length = bi.limit - bi.offset;
282 if (length <= 0) continue;
283 bi.buffer.copy(bb.buffer, bb.offset, bi.offset, bi.limit);
284 bb.offset += length;
285 }
286 bb.limit = bb.offset;
287 bb.offset = 0;
288 return bb;
289 };
291 /**
292 * Tests if the specified type is a ByteBuffer.
293 * @param {*} bb ByteBuffer to test
294 * @returns {boolean} `true` if it is a ByteBuffer, otherwise `false`
295 * @expose
296 */
297 ByteBuffer.isByteBuffer = function(bb) {
298 return (bb && bb["__isByteBuffer__"]) === true;
299 };
300 /**
301 * Gets the backing buffer type.
302 * @returns {Function} `Buffer` under node.js, `ArrayBuffer` in the browser (classes)
303 * @expose
304 */
305 ByteBuffer.type = function() {
306 return Buffer;
307 };
308 /**
309 * Wraps a buffer or a string. Sets the allocated ByteBuffer's {@link ByteBuffer#offset} to `0` and its
310 * {@link ByteBuffer#limit} to the length of the wrapped data.
311 * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string|!Array.<number>} buffer Anything that can be wrapped
312 * @param {(string|boolean)=} encoding String encoding if `buffer` is a string ("base64", "hex", "binary", defaults to
313 * "utf8")
314 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
315 * {@link ByteBuffer.DEFAULT_ENDIAN}.
316 * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
317 * {@link ByteBuffer.DEFAULT_NOASSERT}.
318 * @returns {!ByteBuffer} A ByteBuffer wrapping `buffer`
319 * @expose
320 */
321 ByteBuffer.wrap = function(buffer, encoding, littleEndian, noAssert) {
322 if (typeof encoding !== 'string') {
323 noAssert = littleEndian;
324 littleEndian = encoding;
325 encoding = undefined;
326 }
327 if (typeof buffer === 'string') {
328 if (typeof encoding === 'undefined')
329 encoding = "utf8";
330 switch (encoding) {
331 case "base64":
332 return ByteBuffer.fromBase64(buffer, littleEndian);
333 case "hex":
334 return ByteBuffer.fromHex(buffer, littleEndian);
335 case "binary":
336 return ByteBuffer.fromBinary(buffer, littleEndian);
337 case "utf8":
338 return ByteBuffer.fromUTF8(buffer, littleEndian);
339 case "debug":
340 return ByteBuffer.fromDebug(buffer, littleEndian);
341 default:
342 throw Error("Unsupported encoding: "+encoding);
343 }
344 }
345 if (buffer === null || typeof buffer !== 'object')
346 throw TypeError("Illegal buffer");
347 var bb;
348 if (ByteBuffer.isByteBuffer(buffer)) {
349 bb = ByteBufferPrototype.clone.call(buffer);
350 bb.markedOffset = -1;
351 return bb;
352 }
353 var i = 0,
354 k = 0,
355 b;
356 if (buffer instanceof Uint8Array) { // Extract bytes from Uint8Array
357 b = new Buffer(buffer.length);
358 if (memcpy) { // Fast
359 memcpy(b, 0, buffer.buffer, buffer.byteOffset, buffer.byteOffset + buffer.length);
360 } else { // Slow
361 for (i=0, k=buffer.length; i<k; ++i)
362 b[i] = buffer[i];
363 }
364 buffer = b;
365 } else if (buffer instanceof ArrayBuffer) { // Convert ArrayBuffer to Buffer
366 b = new Buffer(buffer.byteLength);
367 if (memcpy) { // Fast
368 memcpy(b, 0, buffer, 0, buffer.byteLength);
369 } else { // Slow
370 buffer = new Uint8Array(buffer);
371 for (i=0, k=buffer.length; i<k; ++i) {
372 b[i] = buffer[i];
373 }
374 }
375 buffer = b;
376 } else if (!(buffer instanceof Buffer)) { // Create from octets if it is an error, otherwise fail
377 if (Object.prototype.toString.call(buffer) !== "[object Array]")
378 throw TypeError("Illegal buffer");
379 buffer = new Buffer(buffer);
380 }
381 bb = new ByteBuffer(0, littleEndian, noAssert);
382 if (buffer.length > 0) { // Avoid references to more than one EMPTY_BUFFER
383 bb.buffer = buffer;
384 bb.limit = buffer.length;
385 }
386 return bb;
387 };
389 /**
390 * Writes the array as a bitset.
391 * @param {Array<boolean>} value Array of booleans to write
392 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `length` if omitted.
393 * @returns {!ByteBuffer}
394 * @expose
395 */
396 ByteBufferPrototype.writeBitSet = function(value, offset) {
397 var relative = typeof offset === 'undefined';
398 if (relative) offset = this.offset;
399 if (!this.noAssert) {
400 if (!(value instanceof Array))
401 throw TypeError("Illegal BitSet: Not an array");
402 if (typeof offset !== 'number' || offset % 1 !== 0)
403 throw TypeError("Illegal offset: "+offset+" (not an integer)");
404 offset >>>= 0;
405 if (offset < 0 || offset + 0 > this.buffer.length)
406 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
407 }
409 var start = offset,
410 bits = value.length,
411 bytes = (bits >> 3),
412 bit = 0,
413 k;
415 offset += this.writeVarint32(bits,offset);
417 while(bytes--) {
418 k = (!!value[bit++] & 1) |
419 ((!!value[bit++] & 1) << 1) |
420 ((!!value[bit++] & 1) << 2) |
421 ((!!value[bit++] & 1) << 3) |
422 ((!!value[bit++] & 1) << 4) |
423 ((!!value[bit++] & 1) << 5) |
424 ((!!value[bit++] & 1) << 6) |
425 ((!!value[bit++] & 1) << 7);
426 this.writeByte(k,offset++);
427 }
429 if(bit < bits) {
430 var m = 0; k = 0;
431 while(bit < bits) k = k | ((!!value[bit++] & 1) << (m++));
432 this.writeByte(k,offset++);
433 }
435 if (relative) {
436 this.offset = offset;
437 return this;
438 }
439 return offset - start;
440 }
442 /**
443 * Reads a BitSet as an array of booleans.
444 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `length` if omitted.
445 * @returns {Array<boolean>
446 * @expose
447 */
448 ByteBufferPrototype.readBitSet = function(offset) {
449 var relative = typeof offset === 'undefined';
450 if (relative) offset = this.offset;
452 var ret = this.readVarint32(offset),
453 bits = ret.value,
454 bytes = (bits >> 3),
455 bit = 0,
456 value = [],
457 k;
459 offset += ret.length;
461 while(bytes--) {
462 k = this.readByte(offset++);
463 value[bit++] = !!(k & 0x01);
464 value[bit++] = !!(k & 0x02);
465 value[bit++] = !!(k & 0x04);
466 value[bit++] = !!(k & 0x08);
467 value[bit++] = !!(k & 0x10);
468 value[bit++] = !!(k & 0x20);
469 value[bit++] = !!(k & 0x40);
470 value[bit++] = !!(k & 0x80);
471 }
473 if(bit < bits) {
474 var m = 0;
475 k = this.readByte(offset++);
476 while(bit < bits) value[bit++] = !!((k >> (m++)) & 1);
477 }
479 if (relative) {
480 this.offset = offset;
481 }
482 return value;
483 }
484 /**
485 * Reads the specified number of bytes.
486 * @param {number} length Number of bytes to read
487 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `length` if omitted.
488 * @returns {!ByteBuffer}
489 * @expose
490 */
491 ByteBufferPrototype.readBytes = function(length, offset) {
492 var relative = typeof offset === 'undefined';
493 if (relative) offset = this.offset;
494 if (!this.noAssert) {
495 if (typeof offset !== 'number' || offset % 1 !== 0)
496 throw TypeError("Illegal offset: "+offset+" (not an integer)");
497 offset >>>= 0;
498 if (offset < 0 || offset + length > this.buffer.length)
499 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+length+") <= "+this.buffer.length);
500 }
501 var slice = this.slice(offset, offset + length);
502 if (relative) this.offset += length;
503 return slice;
504 };
506 /**
507 * Writes a payload of bytes. This is an alias of {@link ByteBuffer#append}.
508 * @function
509 * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string} source Data to write. If `source` is a ByteBuffer, its
510 * offsets will be modified according to the performed read operation.
511 * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8")
512 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
513 * written if omitted.
514 * @returns {!ByteBuffer} this
515 * @expose
516 */
517 ByteBufferPrototype.writeBytes = ByteBufferPrototype.append;
519 // types/ints/int8
521 /**
522 * Writes an 8bit signed integer.
523 * @param {number} value Value to write
524 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
525 * @returns {!ByteBuffer} this
526 * @expose
527 */
528 ByteBufferPrototype.writeInt8 = function(value, offset) {
529 var relative = typeof offset === 'undefined';
530 if (relative) offset = this.offset;
531 if (!this.noAssert) {
532 if (typeof value !== 'number' || value % 1 !== 0)
533 throw TypeError("Illegal value: "+value+" (not an integer)");
534 value |= 0;
535 if (typeof offset !== 'number' || offset % 1 !== 0)
536 throw TypeError("Illegal offset: "+offset+" (not an integer)");
537 offset >>>= 0;
538 if (offset < 0 || offset + 0 > this.buffer.length)
539 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
540 }
541 offset += 1;
542 var capacity0 = this.buffer.length;
543 if (offset > capacity0)
544 this.resize((capacity0 *= 2) > offset ? capacity0 : offset);
545 offset -= 1;
546 this.buffer[offset] = value;
547 if (relative) this.offset += 1;
548 return this;
549 };
551 /**
552 * Writes an 8bit signed integer. This is an alias of {@link ByteBuffer#writeInt8}.
553 * @function
554 * @param {number} value Value to write
555 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
556 * @returns {!ByteBuffer} this
557 * @expose
558 */
559 ByteBufferPrototype.writeByte = ByteBufferPrototype.writeInt8;
561 /**
562 * Reads an 8bit signed integer.
563 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
564 * @returns {number} Value read
565 * @expose
566 */
567 ByteBufferPrototype.readInt8 = function(offset) {
568 var relative = typeof offset === 'undefined';
569 if (relative) offset = this.offset;
570 if (!this.noAssert) {
571 if (typeof offset !== 'number' || offset % 1 !== 0)
572 throw TypeError("Illegal offset: "+offset+" (not an integer)");
573 offset >>>= 0;
574 if (offset < 0 || offset + 1 > this.buffer.length)
575 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
576 }
577 var value = this.buffer[offset];
578 if ((value & 0x80) === 0x80) value = -(0xFF - value + 1); // Cast to signed
579 if (relative) this.offset += 1;
580 return value;
581 };
583 /**
584 * Reads an 8bit signed integer. This is an alias of {@link ByteBuffer#readInt8}.
585 * @function
586 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
587 * @returns {number} Value read
588 * @expose
589 */
590 ByteBufferPrototype.readByte = ByteBufferPrototype.readInt8;
592 /**
593 * Writes an 8bit unsigned integer.
594 * @param {number} value Value to write
595 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
596 * @returns {!ByteBuffer} this
597 * @expose
598 */
599 ByteBufferPrototype.writeUint8 = function(value, offset) {
600 var relative = typeof offset === 'undefined';
601 if (relative) offset = this.offset;
602 if (!this.noAssert) {
603 if (typeof value !== 'number' || value % 1 !== 0)
604 throw TypeError("Illegal value: "+value+" (not an integer)");
605 value >>>= 0;
606 if (typeof offset !== 'number' || offset % 1 !== 0)
607 throw TypeError("Illegal offset: "+offset+" (not an integer)");
608 offset >>>= 0;
609 if (offset < 0 || offset + 0 > this.buffer.length)
610 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
611 }
612 offset += 1;
613 var capacity1 = this.buffer.length;
614 if (offset > capacity1)
615 this.resize((capacity1 *= 2) > offset ? capacity1 : offset);
616 offset -= 1;
617 this.buffer[offset] = value;
618 if (relative) this.offset += 1;
619 return this;
620 };
622 /**
623 * Writes an 8bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint8}.
624 * @function
625 * @param {number} value Value to write
626 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
627 * @returns {!ByteBuffer} this
628 * @expose
629 */
630 ByteBufferPrototype.writeUInt8 = ByteBufferPrototype.writeUint8;
632 /**
633 * Reads an 8bit unsigned integer.
634 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
635 * @returns {number} Value read
636 * @expose
637 */
638 ByteBufferPrototype.readUint8 = function(offset) {
639 var relative = typeof offset === 'undefined';
640 if (relative) offset = this.offset;
641 if (!this.noAssert) {
642 if (typeof offset !== 'number' || offset % 1 !== 0)
643 throw TypeError("Illegal offset: "+offset+" (not an integer)");
644 offset >>>= 0;
645 if (offset < 0 || offset + 1 > this.buffer.length)
646 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
647 }
648 var value = this.buffer[offset];
649 if (relative) this.offset += 1;
650 return value;
651 };
653 /**
654 * Reads an 8bit unsigned integer. This is an alias of {@link ByteBuffer#readUint8}.
655 * @function
656 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `1` if omitted.
657 * @returns {number} Value read
658 * @expose
659 */
660 ByteBufferPrototype.readUInt8 = ByteBufferPrototype.readUint8;
662 // types/ints/int16
664 /**
665 * Writes a 16bit signed integer.
666 * @param {number} value Value to write
667 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
668 * @throws {TypeError} If `offset` or `value` is not a valid number
669 * @throws {RangeError} If `offset` is out of bounds
670 * @expose
671 */
672 ByteBufferPrototype.writeInt16 = function(value, offset) {
673 var relative = typeof offset === 'undefined';
674 if (relative) offset = this.offset;
675 if (!this.noAssert) {
676 if (typeof value !== 'number' || value % 1 !== 0)
677 throw TypeError("Illegal value: "+value+" (not an integer)");
678 value |= 0;
679 if (typeof offset !== 'number' || offset % 1 !== 0)
680 throw TypeError("Illegal offset: "+offset+" (not an integer)");
681 offset >>>= 0;
682 if (offset < 0 || offset + 0 > this.buffer.length)
683 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
684 }
685 offset += 2;
686 var capacity2 = this.buffer.length;
687 if (offset > capacity2)
688 this.resize((capacity2 *= 2) > offset ? capacity2 : offset);
689 offset -= 2;
690 if (this.littleEndian) {
691 this.buffer[offset+1] = (value & 0xFF00) >>> 8;
692 this.buffer[offset ] = value & 0x00FF;
693 } else {
694 this.buffer[offset] = (value & 0xFF00) >>> 8;
695 this.buffer[offset+1] = value & 0x00FF;
696 }
697 if (relative) this.offset += 2;
698 return this;
699 };
701 /**
702 * Writes a 16bit signed integer. This is an alias of {@link ByteBuffer#writeInt16}.
703 * @function
704 * @param {number} value Value to write
705 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
706 * @throws {TypeError} If `offset` or `value` is not a valid number
707 * @throws {RangeError} If `offset` is out of bounds
708 * @expose
709 */
710 ByteBufferPrototype.writeShort = ByteBufferPrototype.writeInt16;
712 /**
713 * Reads a 16bit signed integer.
714 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
715 * @returns {number} Value read
716 * @throws {TypeError} If `offset` is not a valid number
717 * @throws {RangeError} If `offset` is out of bounds
718 * @expose
719 */
720 ByteBufferPrototype.readInt16 = function(offset) {
721 var relative = typeof offset === 'undefined';
722 if (relative) offset = this.offset;
723 if (!this.noAssert) {
724 if (typeof offset !== 'number' || offset % 1 !== 0)
725 throw TypeError("Illegal offset: "+offset+" (not an integer)");
726 offset >>>= 0;
727 if (offset < 0 || offset + 2 > this.buffer.length)
728 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.length);
729 }
730 var value = 0;
731 if (this.littleEndian) {
732 value = this.buffer[offset ];
733 value |= this.buffer[offset+1] << 8;
734 } else {
735 value = this.buffer[offset ] << 8;
736 value |= this.buffer[offset+1];
737 }
738 if ((value & 0x8000) === 0x8000) value = -(0xFFFF - value + 1); // Cast to signed
739 if (relative) this.offset += 2;
740 return value;
741 };
743 /**
744 * Reads a 16bit signed integer. This is an alias of {@link ByteBuffer#readInt16}.
745 * @function
746 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
747 * @returns {number} Value read
748 * @throws {TypeError} If `offset` is not a valid number
749 * @throws {RangeError} If `offset` is out of bounds
750 * @expose
751 */
752 ByteBufferPrototype.readShort = ByteBufferPrototype.readInt16;
754 /**
755 * Writes a 16bit unsigned integer.
756 * @param {number} value Value to write
757 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
758 * @throws {TypeError} If `offset` or `value` is not a valid number
759 * @throws {RangeError} If `offset` is out of bounds
760 * @expose
761 */
762 ByteBufferPrototype.writeUint16 = function(value, offset) {
763 var relative = typeof offset === 'undefined';
764 if (relative) offset = this.offset;
765 if (!this.noAssert) {
766 if (typeof value !== 'number' || value % 1 !== 0)
767 throw TypeError("Illegal value: "+value+" (not an integer)");
768 value >>>= 0;
769 if (typeof offset !== 'number' || offset % 1 !== 0)
770 throw TypeError("Illegal offset: "+offset+" (not an integer)");
771 offset >>>= 0;
772 if (offset < 0 || offset + 0 > this.buffer.length)
773 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
774 }
775 offset += 2;
776 var capacity3 = this.buffer.length;
777 if (offset > capacity3)
778 this.resize((capacity3 *= 2) > offset ? capacity3 : offset);
779 offset -= 2;
780 if (this.littleEndian) {
781 this.buffer[offset+1] = (value & 0xFF00) >>> 8;
782 this.buffer[offset ] = value & 0x00FF;
783 } else {
784 this.buffer[offset] = (value & 0xFF00) >>> 8;
785 this.buffer[offset+1] = value & 0x00FF;
786 }
787 if (relative) this.offset += 2;
788 return this;
789 };
791 /**
792 * Writes a 16bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint16}.
793 * @function
794 * @param {number} value Value to write
795 * @param {number=} offset Offset to write to. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
796 * @throws {TypeError} If `offset` or `value` is not a valid number
797 * @throws {RangeError} If `offset` is out of bounds
798 * @expose
799 */
800 ByteBufferPrototype.writeUInt16 = ByteBufferPrototype.writeUint16;
802 /**
803 * Reads a 16bit unsigned integer.
804 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
805 * @returns {number} Value read
806 * @throws {TypeError} If `offset` is not a valid number
807 * @throws {RangeError} If `offset` is out of bounds
808 * @expose
809 */
810 ByteBufferPrototype.readUint16 = function(offset) {
811 var relative = typeof offset === 'undefined';
812 if (relative) offset = this.offset;
813 if (!this.noAssert) {
814 if (typeof offset !== 'number' || offset % 1 !== 0)
815 throw TypeError("Illegal offset: "+offset+" (not an integer)");
816 offset >>>= 0;
817 if (offset < 0 || offset + 2 > this.buffer.length)
818 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+2+") <= "+this.buffer.length);
819 }
820 var value = 0;
821 if (this.littleEndian) {
822 value = this.buffer[offset ];
823 value |= this.buffer[offset+1] << 8;
824 } else {
825 value = this.buffer[offset ] << 8;
826 value |= this.buffer[offset+1];
827 }
828 if (relative) this.offset += 2;
829 return value;
830 };
832 /**
833 * Reads a 16bit unsigned integer. This is an alias of {@link ByteBuffer#readUint16}.
834 * @function
835 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `2` if omitted.
836 * @returns {number} Value read
837 * @throws {TypeError} If `offset` is not a valid number
838 * @throws {RangeError} If `offset` is out of bounds
839 * @expose
840 */
841 ByteBufferPrototype.readUInt16 = ByteBufferPrototype.readUint16;
843 // types/ints/int32
845 /**
846 * Writes a 32bit signed integer.
847 * @param {number} value Value to write
848 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
849 * @expose
850 */
851 ByteBufferPrototype.writeInt32 = function(value, offset) {
852 var relative = typeof offset === 'undefined';
853 if (relative) offset = this.offset;
854 if (!this.noAssert) {
855 if (typeof value !== 'number' || value % 1 !== 0)
856 throw TypeError("Illegal value: "+value+" (not an integer)");
857 value |= 0;
858 if (typeof offset !== 'number' || offset % 1 !== 0)
859 throw TypeError("Illegal offset: "+offset+" (not an integer)");
860 offset >>>= 0;
861 if (offset < 0 || offset + 0 > this.buffer.length)
862 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
863 }
864 offset += 4;
865 var capacity4 = this.buffer.length;
866 if (offset > capacity4)
867 this.resize((capacity4 *= 2) > offset ? capacity4 : offset);
868 offset -= 4;
869 if (this.littleEndian) {
870 this.buffer[offset+3] = (value >>> 24) & 0xFF;
871 this.buffer[offset+2] = (value >>> 16) & 0xFF;
872 this.buffer[offset+1] = (value >>> 8) & 0xFF;
873 this.buffer[offset ] = value & 0xFF;
874 } else {
875 this.buffer[offset ] = (value >>> 24) & 0xFF;
876 this.buffer[offset+1] = (value >>> 16) & 0xFF;
877 this.buffer[offset+2] = (value >>> 8) & 0xFF;
878 this.buffer[offset+3] = value & 0xFF;
879 }
880 if (relative) this.offset += 4;
881 return this;
882 };
884 /**
885 * Writes a 32bit signed integer. This is an alias of {@link ByteBuffer#writeInt32}.
886 * @param {number} value Value to write
887 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
888 * @expose
889 */
890 ByteBufferPrototype.writeInt = ByteBufferPrototype.writeInt32;
892 /**
893 * Reads a 32bit signed integer.
894 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
895 * @returns {number} Value read
896 * @expose
897 */
898 ByteBufferPrototype.readInt32 = function(offset) {
899 var relative = typeof offset === 'undefined';
900 if (relative) offset = this.offset;
901 if (!this.noAssert) {
902 if (typeof offset !== 'number' || offset % 1 !== 0)
903 throw TypeError("Illegal offset: "+offset+" (not an integer)");
904 offset >>>= 0;
905 if (offset < 0 || offset + 4 > this.buffer.length)
906 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
907 }
908 var value = 0;
909 if (this.littleEndian) {
910 value = this.buffer[offset+2] << 16;
911 value |= this.buffer[offset+1] << 8;
912 value |= this.buffer[offset ];
913 value += this.buffer[offset+3] << 24 >>> 0;
914 } else {
915 value = this.buffer[offset+1] << 16;
916 value |= this.buffer[offset+2] << 8;
917 value |= this.buffer[offset+3];
918 value += this.buffer[offset ] << 24 >>> 0;
919 }
920 value |= 0; // Cast to signed
921 if (relative) this.offset += 4;
922 return value;
923 };
925 /**
926 * Reads a 32bit signed integer. This is an alias of {@link ByteBuffer#readInt32}.
927 * @param {number=} offset Offset to read from. Will use and advance {@link ByteBuffer#offset} by `4` if omitted.
928 * @returns {number} Value read
929 * @expose
930 */
931 ByteBufferPrototype.readInt = ByteBufferPrototype.readInt32;
933 /**
934 * Writes a 32bit unsigned integer.
935 * @param {number} value Value to write
936 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
937 * @expose
938 */
939 ByteBufferPrototype.writeUint32 = function(value, offset) {
940 var relative = typeof offset === 'undefined';
941 if (relative) offset = this.offset;
942 if (!this.noAssert) {
943 if (typeof value !== 'number' || value % 1 !== 0)
944 throw TypeError("Illegal value: "+value+" (not an integer)");
945 value >>>= 0;
946 if (typeof offset !== 'number' || offset % 1 !== 0)
947 throw TypeError("Illegal offset: "+offset+" (not an integer)");
948 offset >>>= 0;
949 if (offset < 0 || offset + 0 > this.buffer.length)
950 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
951 }
952 offset += 4;
953 var capacity5 = this.buffer.length;
954 if (offset > capacity5)
955 this.resize((capacity5 *= 2) > offset ? capacity5 : offset);
956 offset -= 4;
957 if (this.littleEndian) {
958 this.buffer[offset+3] = (value >>> 24) & 0xFF;
959 this.buffer[offset+2] = (value >>> 16) & 0xFF;
960 this.buffer[offset+1] = (value >>> 8) & 0xFF;
961 this.buffer[offset ] = value & 0xFF;
962 } else {
963 this.buffer[offset ] = (value >>> 24) & 0xFF;
964 this.buffer[offset+1] = (value >>> 16) & 0xFF;
965 this.buffer[offset+2] = (value >>> 8) & 0xFF;
966 this.buffer[offset+3] = value & 0xFF;
967 }
968 if (relative) this.offset += 4;
969 return this;
970 };
972 /**
973 * Writes a 32bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint32}.
974 * @function
975 * @param {number} value Value to write
976 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
977 * @expose
978 */
979 ByteBufferPrototype.writeUInt32 = ByteBufferPrototype.writeUint32;
981 /**
982 * Reads a 32bit unsigned integer.
983 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
984 * @returns {number} Value read
985 * @expose
986 */
987 ByteBufferPrototype.readUint32 = function(offset) {
988 var relative = typeof offset === 'undefined';
989 if (relative) offset = this.offset;
990 if (!this.noAssert) {
991 if (typeof offset !== 'number' || offset % 1 !== 0)
992 throw TypeError("Illegal offset: "+offset+" (not an integer)");
993 offset >>>= 0;
994 if (offset < 0 || offset + 4 > this.buffer.length)
995 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
996 }
997 var value = 0;
998 if (this.littleEndian) {
999 value = this.buffer[offset+2] << 16;
1000 value |= this.buffer[offset+1] << 8;
1001 value |= this.buffer[offset ];
1002 value += this.buffer[offset+3] << 24 >>> 0;
1003 } else {
1004 value = this.buffer[offset+1] << 16;
1005 value |= this.buffer[offset+2] << 8;
1006 value |= this.buffer[offset+3];
1007 value += this.buffer[offset ] << 24 >>> 0;
1008 }
1009 if (relative) this.offset += 4;
1010 return value;
1011 };
1013 /**
1014 * Reads a 32bit unsigned integer. This is an alias of {@link ByteBuffer#readUint32}.
1015 * @function
1016 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
1017 * @returns {number} Value read
1018 * @expose
1019 */
1020 ByteBufferPrototype.readUInt32 = ByteBufferPrototype.readUint32;
1022 // types/ints/int64
1024 if (Long) {
1026 /**
1027 * Writes a 64bit signed integer.
1028 * @param {number|!Long} value Value to write
1029 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1030 * @returns {!ByteBuffer} this
1031 * @expose
1032 */
1033 ByteBufferPrototype.writeInt64 = function(value, offset) {
1034 var relative = typeof offset === 'undefined';
1035 if (relative) offset = this.offset;
1036 if (!this.noAssert) {
1037 if (typeof value === 'number')
1038 value = Long.fromNumber(value);
1039 else if (typeof value === 'string')
1040 value = Long.fromString(value);
1041 else if (!(value && value instanceof Long))
1042 throw TypeError("Illegal value: "+value+" (not an integer or Long)");
1043 if (typeof offset !== 'number' || offset % 1 !== 0)
1044 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1045 offset >>>= 0;
1046 if (offset < 0 || offset + 0 > this.buffer.length)
1047 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1048 }
1049 if (typeof value === 'number')
1050 value = Long.fromNumber(value);
1051 else if (typeof value === 'string')
1052 value = Long.fromString(value);
1053 offset += 8;
1054 var capacity6 = this.buffer.length;
1055 if (offset > capacity6)
1056 this.resize((capacity6 *= 2) > offset ? capacity6 : offset);
1057 offset -= 8;
1058 var lo = value.low,
1059 hi = value.high;
1060 if (this.littleEndian) {
1061 this.buffer[offset+3] = (lo >>> 24) & 0xFF;
1062 this.buffer[offset+2] = (lo >>> 16) & 0xFF;
1063 this.buffer[offset+1] = (lo >>> 8) & 0xFF;
1064 this.buffer[offset ] = lo & 0xFF;
1065 offset += 4;
1066 this.buffer[offset+3] = (hi >>> 24) & 0xFF;
1067 this.buffer[offset+2] = (hi >>> 16) & 0xFF;
1068 this.buffer[offset+1] = (hi >>> 8) & 0xFF;
1069 this.buffer[offset ] = hi & 0xFF;
1070 } else {
1071 this.buffer[offset ] = (hi >>> 24) & 0xFF;
1072 this.buffer[offset+1] = (hi >>> 16) & 0xFF;
1073 this.buffer[offset+2] = (hi >>> 8) & 0xFF;
1074 this.buffer[offset+3] = hi & 0xFF;
1075 offset += 4;
1076 this.buffer[offset ] = (lo >>> 24) & 0xFF;
1077 this.buffer[offset+1] = (lo >>> 16) & 0xFF;
1078 this.buffer[offset+2] = (lo >>> 8) & 0xFF;
1079 this.buffer[offset+3] = lo & 0xFF;
1080 }
1081 if (relative) this.offset += 8;
1082 return this;
1083 };
1085 /**
1086 * Writes a 64bit signed integer. This is an alias of {@link ByteBuffer#writeInt64}.
1087 * @param {number|!Long} value Value to write
1088 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1089 * @returns {!ByteBuffer} this
1090 * @expose
1091 */
1092 ByteBufferPrototype.writeLong = ByteBufferPrototype.writeInt64;
1094 /**
1095 * Reads a 64bit signed integer.
1096 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1097 * @returns {!Long}
1098 * @expose
1099 */
1100 ByteBufferPrototype.readInt64 = function(offset) {
1101 var relative = typeof offset === 'undefined';
1102 if (relative) offset = this.offset;
1103 if (!this.noAssert) {
1104 if (typeof offset !== 'number' || offset % 1 !== 0)
1105 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1106 offset >>>= 0;
1107 if (offset < 0 || offset + 8 > this.buffer.length)
1108 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length);
1109 }
1110 var lo = 0,
1111 hi = 0;
1112 if (this.littleEndian) {
1113 lo = this.buffer[offset+2] << 16;
1114 lo |= this.buffer[offset+1] << 8;
1115 lo |= this.buffer[offset ];
1116 lo += this.buffer[offset+3] << 24 >>> 0;
1117 offset += 4;
1118 hi = this.buffer[offset+2] << 16;
1119 hi |= this.buffer[offset+1] << 8;
1120 hi |= this.buffer[offset ];
1121 hi += this.buffer[offset+3] << 24 >>> 0;
1122 } else {
1123 hi = this.buffer[offset+1] << 16;
1124 hi |= this.buffer[offset+2] << 8;
1125 hi |= this.buffer[offset+3];
1126 hi += this.buffer[offset ] << 24 >>> 0;
1127 offset += 4;
1128 lo = this.buffer[offset+1] << 16;
1129 lo |= this.buffer[offset+2] << 8;
1130 lo |= this.buffer[offset+3];
1131 lo += this.buffer[offset ] << 24 >>> 0;
1132 }
1133 var value = new Long(lo, hi, false);
1134 if (relative) this.offset += 8;
1135 return value;
1136 };
1138 /**
1139 * Reads a 64bit signed integer. This is an alias of {@link ByteBuffer#readInt64}.
1140 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1141 * @returns {!Long}
1142 * @expose
1143 */
1144 ByteBufferPrototype.readLong = ByteBufferPrototype.readInt64;
1146 /**
1147 * Writes a 64bit unsigned integer.
1148 * @param {number|!Long} value Value to write
1149 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1150 * @returns {!ByteBuffer} this
1151 * @expose
1152 */
1153 ByteBufferPrototype.writeUint64 = function(value, offset) {
1154 var relative = typeof offset === 'undefined';
1155 if (relative) offset = this.offset;
1156 if (!this.noAssert) {
1157 if (typeof value === 'number')
1158 value = Long.fromNumber(value);
1159 else if (typeof value === 'string')
1160 value = Long.fromString(value);
1161 else if (!(value && value instanceof Long))
1162 throw TypeError("Illegal value: "+value+" (not an integer or Long)");
1163 if (typeof offset !== 'number' || offset % 1 !== 0)
1164 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1165 offset >>>= 0;
1166 if (offset < 0 || offset + 0 > this.buffer.length)
1167 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1168 }
1169 if (typeof value === 'number')
1170 value = Long.fromNumber(value);
1171 else if (typeof value === 'string')
1172 value = Long.fromString(value);
1173 offset += 8;
1174 var capacity7 = this.buffer.length;
1175 if (offset > capacity7)
1176 this.resize((capacity7 *= 2) > offset ? capacity7 : offset);
1177 offset -= 8;
1178 var lo = value.low,
1179 hi = value.high;
1180 if (this.littleEndian) {
1181 this.buffer[offset+3] = (lo >>> 24) & 0xFF;
1182 this.buffer[offset+2] = (lo >>> 16) & 0xFF;
1183 this.buffer[offset+1] = (lo >>> 8) & 0xFF;
1184 this.buffer[offset ] = lo & 0xFF;
1185 offset += 4;
1186 this.buffer[offset+3] = (hi >>> 24) & 0xFF;
1187 this.buffer[offset+2] = (hi >>> 16) & 0xFF;
1188 this.buffer[offset+1] = (hi >>> 8) & 0xFF;
1189 this.buffer[offset ] = hi & 0xFF;
1190 } else {
1191 this.buffer[offset ] = (hi >>> 24) & 0xFF;
1192 this.buffer[offset+1] = (hi >>> 16) & 0xFF;
1193 this.buffer[offset+2] = (hi >>> 8) & 0xFF;
1194 this.buffer[offset+3] = hi & 0xFF;
1195 offset += 4;
1196 this.buffer[offset ] = (lo >>> 24) & 0xFF;
1197 this.buffer[offset+1] = (lo >>> 16) & 0xFF;
1198 this.buffer[offset+2] = (lo >>> 8) & 0xFF;
1199 this.buffer[offset+3] = lo & 0xFF;
1200 }
1201 if (relative) this.offset += 8;
1202 return this;
1203 };
1205 /**
1206 * Writes a 64bit unsigned integer. This is an alias of {@link ByteBuffer#writeUint64}.
1207 * @function
1208 * @param {number|!Long} value Value to write
1209 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1210 * @returns {!ByteBuffer} this
1211 * @expose
1212 */
1213 ByteBufferPrototype.writeUInt64 = ByteBufferPrototype.writeUint64;
1215 /**
1216 * Reads a 64bit unsigned integer.
1217 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1218 * @returns {!Long}
1219 * @expose
1220 */
1221 ByteBufferPrototype.readUint64 = function(offset) {
1222 var relative = typeof offset === 'undefined';
1223 if (relative) offset = this.offset;
1224 if (!this.noAssert) {
1225 if (typeof offset !== 'number' || offset % 1 !== 0)
1226 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1227 offset >>>= 0;
1228 if (offset < 0 || offset + 8 > this.buffer.length)
1229 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length);
1230 }
1231 var lo = 0,
1232 hi = 0;
1233 if (this.littleEndian) {
1234 lo = this.buffer[offset+2] << 16;
1235 lo |= this.buffer[offset+1] << 8;
1236 lo |= this.buffer[offset ];
1237 lo += this.buffer[offset+3] << 24 >>> 0;
1238 offset += 4;
1239 hi = this.buffer[offset+2] << 16;
1240 hi |= this.buffer[offset+1] << 8;
1241 hi |= this.buffer[offset ];
1242 hi += this.buffer[offset+3] << 24 >>> 0;
1243 } else {
1244 hi = this.buffer[offset+1] << 16;
1245 hi |= this.buffer[offset+2] << 8;
1246 hi |= this.buffer[offset+3];
1247 hi += this.buffer[offset ] << 24 >>> 0;
1248 offset += 4;
1249 lo = this.buffer[offset+1] << 16;
1250 lo |= this.buffer[offset+2] << 8;
1251 lo |= this.buffer[offset+3];
1252 lo += this.buffer[offset ] << 24 >>> 0;
1253 }
1254 var value = new Long(lo, hi, true);
1255 if (relative) this.offset += 8;
1256 return value;
1257 };
1259 /**
1260 * Reads a 64bit unsigned integer. This is an alias of {@link ByteBuffer#readUint64}.
1261 * @function
1262 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1263 * @returns {!Long}
1264 * @expose
1265 */
1266 ByteBufferPrototype.readUInt64 = ByteBufferPrototype.readUint64;
1268 } // Long
1271 // types/floats/float32
1273 /**
1274 * Writes a 32bit float.
1275 * @param {number} value Value to write
1276 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
1277 * @returns {!ByteBuffer} this
1278 * @expose
1279 */
1280 ByteBufferPrototype.writeFloat32 = function(value, offset) {
1281 var relative = typeof offset === 'undefined';
1282 if (relative) offset = this.offset;
1283 if (!this.noAssert) {
1284 if (typeof value !== 'number')
1285 throw TypeError("Illegal value: "+value+" (not a number)");
1286 if (typeof offset !== 'number' || offset % 1 !== 0)
1287 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1288 offset >>>= 0;
1289 if (offset < 0 || offset + 0 > this.buffer.length)
1290 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1291 }
1292 offset += 4;
1293 var capacity8 = this.buffer.length;
1294 if (offset > capacity8)
1295 this.resize((capacity8 *= 2) > offset ? capacity8 : offset);
1296 offset -= 4;
1297 this.littleEndian
1298 ? this.buffer.writeFloatLE(value, offset, true)
1299 : this.buffer.writeFloatBE(value, offset, true);
1300 if (relative) this.offset += 4;
1301 return this;
1302 };
1304 /**
1305 * Writes a 32bit float. This is an alias of {@link ByteBuffer#writeFloat32}.
1306 * @function
1307 * @param {number} value Value to write
1308 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
1309 * @returns {!ByteBuffer} this
1310 * @expose
1311 */
1312 ByteBufferPrototype.writeFloat = ByteBufferPrototype.writeFloat32;
1314 /**
1315 * Reads a 32bit float.
1316 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
1317 * @returns {number}
1318 * @expose
1319 */
1320 ByteBufferPrototype.readFloat32 = function(offset) {
1321 var relative = typeof offset === 'undefined';
1322 if (relative) offset = this.offset;
1323 if (!this.noAssert) {
1324 if (typeof offset !== 'number' || offset % 1 !== 0)
1325 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1326 offset >>>= 0;
1327 if (offset < 0 || offset + 4 > this.buffer.length)
1328 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
1329 }
1330 var value = this.littleEndian
1331 ? this.buffer.readFloatLE(offset, true)
1332 : this.buffer.readFloatBE(offset, true);
1333 if (relative) this.offset += 4;
1334 return value;
1335 };
1337 /**
1338 * Reads a 32bit float. This is an alias of {@link ByteBuffer#readFloat32}.
1339 * @function
1340 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `4` if omitted.
1341 * @returns {number}
1342 * @expose
1343 */
1344 ByteBufferPrototype.readFloat = ByteBufferPrototype.readFloat32;
1346 // types/floats/float64
1348 /**
1349 * Writes a 64bit float.
1350 * @param {number} value Value to write
1351 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1352 * @returns {!ByteBuffer} this
1353 * @expose
1354 */
1355 ByteBufferPrototype.writeFloat64 = function(value, offset) {
1356 var relative = typeof offset === 'undefined';
1357 if (relative) offset = this.offset;
1358 if (!this.noAssert) {
1359 if (typeof value !== 'number')
1360 throw TypeError("Illegal value: "+value+" (not a number)");
1361 if (typeof offset !== 'number' || offset % 1 !== 0)
1362 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1363 offset >>>= 0;
1364 if (offset < 0 || offset + 0 > this.buffer.length)
1365 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1366 }
1367 offset += 8;
1368 var capacity9 = this.buffer.length;
1369 if (offset > capacity9)
1370 this.resize((capacity9 *= 2) > offset ? capacity9 : offset);
1371 offset -= 8;
1372 this.littleEndian
1373 ? this.buffer.writeDoubleLE(value, offset, true)
1374 : this.buffer.writeDoubleBE(value, offset, true);
1375 if (relative) this.offset += 8;
1376 return this;
1377 };
1379 /**
1380 * Writes a 64bit float. This is an alias of {@link ByteBuffer#writeFloat64}.
1381 * @function
1382 * @param {number} value Value to write
1383 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1384 * @returns {!ByteBuffer} this
1385 * @expose
1386 */
1387 ByteBufferPrototype.writeDouble = ByteBufferPrototype.writeFloat64;
1389 /**
1390 * Reads a 64bit float.
1391 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1392 * @returns {number}
1393 * @expose
1394 */
1395 ByteBufferPrototype.readFloat64 = function(offset) {
1396 var relative = typeof offset === 'undefined';
1397 if (relative) offset = this.offset;
1398 if (!this.noAssert) {
1399 if (typeof offset !== 'number' || offset % 1 !== 0)
1400 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1401 offset >>>= 0;
1402 if (offset < 0 || offset + 8 > this.buffer.length)
1403 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+8+") <= "+this.buffer.length);
1404 }
1405 var value = this.littleEndian
1406 ? this.buffer.readDoubleLE(offset, true)
1407 : this.buffer.readDoubleBE(offset, true);
1408 if (relative) this.offset += 8;
1409 return value;
1410 };
1412 /**
1413 * Reads a 64bit float. This is an alias of {@link ByteBuffer#readFloat64}.
1414 * @function
1415 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by `8` if omitted.
1416 * @returns {number}
1417 * @expose
1418 */
1419 ByteBufferPrototype.readDouble = ByteBufferPrototype.readFloat64;
1422 // types/varints/varint32
1424 /**
1425 * Maximum number of bytes required to store a 32bit base 128 variable-length integer.
1426 * @type {number}
1427 * @const
1428 * @expose
1429 */
1430 ByteBuffer.MAX_VARINT32_BYTES = 5;
1432 /**
1433 * Calculates the actual number of bytes required to store a 32bit base 128 variable-length integer.
1434 * @param {number} value Value to encode
1435 * @returns {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT32_BYTES}
1436 * @expose
1437 */
1438 ByteBuffer.calculateVarint32 = function(value) {
1439 // ref: src/google/protobuf/io/coded_stream.cc
1440 value = value >>> 0;
1441 if (value < 1 << 7 ) return 1;
1442 else if (value < 1 << 14) return 2;
1443 else if (value < 1 << 21) return 3;
1444 else if (value < 1 << 28) return 4;
1445 else return 5;
1446 };
1448 /**
1449 * Zigzag encodes a signed 32bit integer so that it can be effectively used with varint encoding.
1450 * @param {number} n Signed 32bit integer
1451 * @returns {number} Unsigned zigzag encoded 32bit integer
1452 * @expose
1453 */
1454 ByteBuffer.zigZagEncode32 = function(n) {
1455 return (((n |= 0) << 1) ^ (n >> 31)) >>> 0; // ref: src/google/protobuf/wire_format_lite.h
1456 };
1458 /**
1459 * Decodes a zigzag encoded signed 32bit integer.
1460 * @param {number} n Unsigned zigzag encoded 32bit integer
1461 * @returns {number} Signed 32bit integer
1462 * @expose
1463 */
1464 ByteBuffer.zigZagDecode32 = function(n) {
1465 return ((n >>> 1) ^ -(n & 1)) | 0; // // ref: src/google/protobuf/wire_format_lite.h
1466 };
1468 /**
1469 * Writes a 32bit base 128 variable-length integer.
1470 * @param {number} value Value to write
1471 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1472 * written if omitted.
1473 * @returns {!ByteBuffer|number} this if `offset` is omitted, else the actual number of bytes written
1474 * @expose
1475 */
1476 ByteBufferPrototype.writeVarint32 = function(value, offset) {
1477 var relative = typeof offset === 'undefined';
1478 if (relative) offset = this.offset;
1479 if (!this.noAssert) {
1480 if (typeof value !== 'number' || value % 1 !== 0)
1481 throw TypeError("Illegal value: "+value+" (not an integer)");
1482 value |= 0;
1483 if (typeof offset !== 'number' || offset % 1 !== 0)
1484 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1485 offset >>>= 0;
1486 if (offset < 0 || offset + 0 > this.buffer.length)
1487 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1488 }
1489 var size = ByteBuffer.calculateVarint32(value),
1490 b;
1491 offset += size;
1492 var capacity10 = this.buffer.length;
1493 if (offset > capacity10)
1494 this.resize((capacity10 *= 2) > offset ? capacity10 : offset);
1495 offset -= size;
1496 value >>>= 0;
1497 while (value >= 0x80) {
1498 b = (value & 0x7f) | 0x80;
1499 this.buffer[offset++] = b;
1500 value >>>= 7;
1501 }
1502 this.buffer[offset++] = value;
1503 if (relative) {
1504 this.offset = offset;
1505 return this;
1506 }
1507 return size;
1508 };
1510 /**
1511 * Writes a zig-zag encoded (signed) 32bit base 128 variable-length integer.
1512 * @param {number} value Value to write
1513 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1514 * written if omitted.
1515 * @returns {!ByteBuffer|number} this if `offset` is omitted, else the actual number of bytes written
1516 * @expose
1517 */
1518 ByteBufferPrototype.writeVarint32ZigZag = function(value, offset) {
1519 return this.writeVarint32(ByteBuffer.zigZagEncode32(value), offset);
1520 };
1522 /**
1523 * Reads a 32bit base 128 variable-length integer.
1524 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1525 * written if omitted.
1526 * @returns {number|!{value: number, length: number}} The value read if offset is omitted, else the value read
1527 * and the actual number of bytes read.
1528 * @throws {Error} If it's not a valid varint. Has a property `truncated = true` if there is not enough data available
1529 * to fully decode the varint.
1530 * @expose
1531 */
1532 ByteBufferPrototype.readVarint32 = function(offset) {
1533 var relative = typeof offset === 'undefined';
1534 if (relative) offset = this.offset;
1535 if (!this.noAssert) {
1536 if (typeof offset !== 'number' || offset % 1 !== 0)
1537 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1538 offset >>>= 0;
1539 if (offset < 0 || offset + 1 > this.buffer.length)
1540 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
1541 }
1542 var c = 0,
1543 value = 0 >>> 0,
1544 b;
1545 do {
1546 if (!this.noAssert && offset > this.limit) {
1547 var err = Error("Truncated");
1548 err['truncated'] = true;
1549 throw err;
1550 }
1551 b = this.buffer[offset++];
1552 if (c < 5)
1553 value |= (b & 0x7f) << (7*c);
1554 ++c;
1555 } while ((b & 0x80) !== 0);
1556 value |= 0;
1557 if (relative) {
1558 this.offset = offset;
1559 return value;
1560 }
1561 return {
1562 "value": value,
1563 "length": c
1564 };
1565 };
1567 /**
1568 * Reads a zig-zag encoded (signed) 32bit base 128 variable-length integer.
1569 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1570 * written if omitted.
1571 * @returns {number|!{value: number, length: number}} The value read if offset is omitted, else the value read
1572 * and the actual number of bytes read.
1573 * @throws {Error} If it's not a valid varint
1574 * @expose
1575 */
1576 ByteBufferPrototype.readVarint32ZigZag = function(offset) {
1577 var val = this.readVarint32(offset);
1578 if (typeof val === 'object')
1579 val["value"] = ByteBuffer.zigZagDecode32(val["value"]);
1580 else
1581 val = ByteBuffer.zigZagDecode32(val);
1582 return val;
1583 };
1585 // types/varints/varint64
1587 if (Long) {
1589 /**
1590 * Maximum number of bytes required to store a 64bit base 128 variable-length integer.
1591 * @type {number}
1592 * @const
1593 * @expose
1594 */
1595 ByteBuffer.MAX_VARINT64_BYTES = 10;
1597 /**
1598 * Calculates the actual number of bytes required to store a 64bit base 128 variable-length integer.
1599 * @param {number|!Long} value Value to encode
1600 * @returns {number} Number of bytes required. Capped to {@link ByteBuffer.MAX_VARINT64_BYTES}
1601 * @expose
1602 */
1603 ByteBuffer.calculateVarint64 = function(value) {
1604 if (typeof value === 'number')
1605 value = Long.fromNumber(value);
1606 else if (typeof value === 'string')
1607 value = Long.fromString(value);
1608 // ref: src/google/protobuf/io/coded_stream.cc
1609 var part0 = value.toInt() >>> 0,
1610 part1 = value.shiftRightUnsigned(28).toInt() >>> 0,
1611 part2 = value.shiftRightUnsigned(56).toInt() >>> 0;
1612 if (part2 == 0) {
1613 if (part1 == 0) {
1614 if (part0 < 1 << 14)
1615 return part0 < 1 << 7 ? 1 : 2;
1616 else
1617 return part0 < 1 << 21 ? 3 : 4;
1618 } else {
1619 if (part1 < 1 << 14)
1620 return part1 < 1 << 7 ? 5 : 6;
1621 else
1622 return part1 < 1 << 21 ? 7 : 8;
1623 }
1624 } else
1625 return part2 < 1 << 7 ? 9 : 10;
1626 };
1628 /**
1629 * Zigzag encodes a signed 64bit integer so that it can be effectively used with varint encoding.
1630 * @param {number|!Long} value Signed long
1631 * @returns {!Long} Unsigned zigzag encoded long
1632 * @expose
1633 */
1634 ByteBuffer.zigZagEncode64 = function(value) {
1635 if (typeof value === 'number')
1636 value = Long.fromNumber(value, false);
1637 else if (typeof value === 'string')
1638 value = Long.fromString(value, false);
1639 else if (value.unsigned !== false) value = value.toSigned();
1640 // ref: src/google/protobuf/wire_format_lite.h
1641 return value.shiftLeft(1).xor(value.shiftRight(63)).toUnsigned();
1642 };
1644 /**
1645 * Decodes a zigzag encoded signed 64bit integer.
1646 * @param {!Long|number} value Unsigned zigzag encoded long or JavaScript number
1647 * @returns {!Long} Signed long
1648 * @expose
1649 */
1650 ByteBuffer.zigZagDecode64 = function(value) {
1651 if (typeof value === 'number')
1652 value = Long.fromNumber(value, false);
1653 else if (typeof value === 'string')
1654 value = Long.fromString(value, false);
1655 else if (value.unsigned !== false) value = value.toSigned();
1656 // ref: src/google/protobuf/wire_format_lite.h
1657 return value.shiftRightUnsigned(1).xor(value.and(Long.ONE).toSigned().negate()).toSigned();
1658 };
1660 /**
1661 * Writes a 64bit base 128 variable-length integer.
1662 * @param {number|Long} value Value to write
1663 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1664 * written if omitted.
1665 * @returns {!ByteBuffer|number} `this` if offset is omitted, else the actual number of bytes written.
1666 * @expose
1667 */
1668 ByteBufferPrototype.writeVarint64 = function(value, offset) {
1669 var relative = typeof offset === 'undefined';
1670 if (relative) offset = this.offset;
1671 if (!this.noAssert) {
1672 if (typeof value === 'number')
1673 value = Long.fromNumber(value);
1674 else if (typeof value === 'string')
1675 value = Long.fromString(value);
1676 else if (!(value && value instanceof Long))
1677 throw TypeError("Illegal value: "+value+" (not an integer or Long)");
1678 if (typeof offset !== 'number' || offset % 1 !== 0)
1679 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1680 offset >>>= 0;
1681 if (offset < 0 || offset + 0 > this.buffer.length)
1682 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1683 }
1684 if (typeof value === 'number')
1685 value = Long.fromNumber(value, false);
1686 else if (typeof value === 'string')
1687 value = Long.fromString(value, false);
1688 else if (value.unsigned !== false) value = value.toSigned();
1689 var size = ByteBuffer.calculateVarint64(value),
1690 part0 = value.toInt() >>> 0,
1691 part1 = value.shiftRightUnsigned(28).toInt() >>> 0,
1692 part2 = value.shiftRightUnsigned(56).toInt() >>> 0;
1693 offset += size;
1694 var capacity11 = this.buffer.length;
1695 if (offset > capacity11)
1696 this.resize((capacity11 *= 2) > offset ? capacity11 : offset);
1697 offset -= size;
1698 switch (size) {
1699 case 10: this.buffer[offset+9] = (part2 >>> 7) & 0x01;
1700 case 9 : this.buffer[offset+8] = size !== 9 ? (part2 ) | 0x80 : (part2 ) & 0x7F;
1701 case 8 : this.buffer[offset+7] = size !== 8 ? (part1 >>> 21) | 0x80 : (part1 >>> 21) & 0x7F;
1702 case 7 : this.buffer[offset+6] = size !== 7 ? (part1 >>> 14) | 0x80 : (part1 >>> 14) & 0x7F;
1703 case 6 : this.buffer[offset+5] = size !== 6 ? (part1 >>> 7) | 0x80 : (part1 >>> 7) & 0x7F;
1704 case 5 : this.buffer[offset+4] = size !== 5 ? (part1 ) | 0x80 : (part1 ) & 0x7F;
1705 case 4 : this.buffer[offset+3] = size !== 4 ? (part0 >>> 21) | 0x80 : (part0 >>> 21) & 0x7F;
1706 case 3 : this.buffer[offset+2] = size !== 3 ? (part0 >>> 14) | 0x80 : (part0 >>> 14) & 0x7F;
1707 case 2 : this.buffer[offset+1] = size !== 2 ? (part0 >>> 7) | 0x80 : (part0 >>> 7) & 0x7F;
1708 case 1 : this.buffer[offset ] = size !== 1 ? (part0 ) | 0x80 : (part0 ) & 0x7F;
1709 }
1710 if (relative) {
1711 this.offset += size;
1712 return this;
1713 } else {
1714 return size;
1715 }
1716 };
1718 /**
1719 * Writes a zig-zag encoded 64bit base 128 variable-length integer.
1720 * @param {number|Long} value Value to write
1721 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1722 * written if omitted.
1723 * @returns {!ByteBuffer|number} `this` if offset is omitted, else the actual number of bytes written.
1724 * @expose
1725 */
1726 ByteBufferPrototype.writeVarint64ZigZag = function(value, offset) {
1727 return this.writeVarint64(ByteBuffer.zigZagEncode64(value), offset);
1728 };
1730 /**
1731 * Reads a 64bit base 128 variable-length integer. Requires Long.js.
1732 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1733 * read if omitted.
1734 * @returns {!Long|!{value: Long, length: number}} The value read if offset is omitted, else the value read and
1735 * the actual number of bytes read.
1736 * @throws {Error} If it's not a valid varint
1737 * @expose
1738 */
1739 ByteBufferPrototype.readVarint64 = function(offset) {
1740 var relative = typeof offset === 'undefined';
1741 if (relative) offset = this.offset;
1742 if (!this.noAssert) {
1743 if (typeof offset !== 'number' || offset % 1 !== 0)
1744 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1745 offset >>>= 0;
1746 if (offset < 0 || offset + 1 > this.buffer.length)
1747 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
1748 }
1749 // ref: src/google/protobuf/io/coded_stream.cc
1750 var start = offset,
1751 part0 = 0,
1752 part1 = 0,
1753 part2 = 0,
1754 b = 0;
1755 b = this.buffer[offset++]; part0 = (b & 0x7F) ; if ( b & 0x80 ) {
1756 b = this.buffer[offset++]; part0 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1757 b = this.buffer[offset++]; part0 |= (b & 0x7F) << 14; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1758 b = this.buffer[offset++]; part0 |= (b & 0x7F) << 21; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1759 b = this.buffer[offset++]; part1 = (b & 0x7F) ; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1760 b = this.buffer[offset++]; part1 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1761 b = this.buffer[offset++]; part1 |= (b & 0x7F) << 14; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1762 b = this.buffer[offset++]; part1 |= (b & 0x7F) << 21; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1763 b = this.buffer[offset++]; part2 = (b & 0x7F) ; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1764 b = this.buffer[offset++]; part2 |= (b & 0x7F) << 7; if ((b & 0x80) || (this.noAssert && typeof b === 'undefined')) {
1765 throw Error("Buffer overrun"); }}}}}}}}}}
1766 var value = Long.fromBits(part0 | (part1 << 28), (part1 >>> 4) | (part2) << 24, false);
1767 if (relative) {
1768 this.offset = offset;
1769 return value;
1770 } else {
1771 return {
1772 'value': value,
1773 'length': offset-start
1774 };
1775 }
1776 };
1778 /**
1779 * Reads a zig-zag encoded 64bit base 128 variable-length integer. Requires Long.js.
1780 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1781 * read if omitted.
1782 * @returns {!Long|!{value: Long, length: number}} The value read if offset is omitted, else the value read and
1783 * the actual number of bytes read.
1784 * @throws {Error} If it's not a valid varint
1785 * @expose
1786 */
1787 ByteBufferPrototype.readVarint64ZigZag = function(offset) {
1788 var val = this.readVarint64(offset);
1789 if (val && val['value'] instanceof Long)
1790 val["value"] = ByteBuffer.zigZagDecode64(val["value"]);
1791 else
1792 val = ByteBuffer.zigZagDecode64(val);
1793 return val;
1794 };
1796 } // Long
1799 // types/strings/cstring
1801 /**
1802 * Writes a NULL-terminated UTF8 encoded string. For this to work the specified string must not contain any NULL
1803 * characters itself.
1804 * @param {string} str String to write
1805 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1806 * contained in `str` + 1 if omitted.
1807 * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written
1808 * @expose
1809 */
1810 ByteBufferPrototype.writeCString = function(str, offset) {
1811 var relative = typeof offset === 'undefined';
1812 if (relative) offset = this.offset;
1813 var i,
1814 k = str.length;
1815 if (!this.noAssert) {
1816 if (typeof str !== 'string')
1817 throw TypeError("Illegal str: Not a string");
1818 for (i=0; i<k; ++i) {
1819 if (str.charCodeAt(i) === 0)
1820 throw RangeError("Illegal str: Contains NULL-characters");
1821 }
1822 if (typeof offset !== 'number' || offset % 1 !== 0)
1823 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1824 offset >>>= 0;
1825 if (offset < 0 || offset + 0 > this.buffer.length)
1826 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1827 }
1828 // UTF8 strings do not contain zero bytes in between except for the zero character, so:
1829 k = Buffer.byteLength(str, "utf8");
1830 offset += k+1;
1831 var capacity12 = this.buffer.length;
1832 if (offset > capacity12)
1833 this.resize((capacity12 *= 2) > offset ? capacity12 : offset);
1834 offset -= k+1;
1835 offset += this.buffer.write(str, offset, k, "utf8");
1836 this.buffer[offset++] = 0;
1837 if (relative) {
1838 this.offset = offset;
1839 return this;
1840 }
1841 return k;
1842 };
1844 /**
1845 * Reads a NULL-terminated UTF8 encoded string. For this to work the string read must not contain any NULL characters
1846 * itself.
1847 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1848 * read if omitted.
1849 * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
1850 * read and the actual number of bytes read.
1851 * @expose
1852 */
1853 ByteBufferPrototype.readCString = function(offset) {
1854 var relative = typeof offset === 'undefined';
1855 if (relative) offset = this.offset;
1856 if (!this.noAssert) {
1857 if (typeof offset !== 'number' || offset % 1 !== 0)
1858 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1859 offset >>>= 0;
1860 if (offset < 0 || offset + 1 > this.buffer.length)
1861 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
1862 }
1863 var start = offset,
1864 temp;
1865 // UTF8 strings do not contain zero bytes in between except for the zero character itself, so:
1866 do {
1867 if (offset >= this.buffer.length)
1868 throw RangeError("Index out of range: "+offset+" <= "+this.buffer.length);
1869 temp = this.buffer[offset++];
1870 } while (temp !== 0);
1871 var str = this.buffer.toString("utf8", start, offset-1);
1872 if (relative) {
1873 this.offset = offset;
1874 return str;
1875 } else {
1876 return {
1877 "string": str,
1878 "length": offset - start
1879 };
1880 }
1881 };
1883 // types/strings/istring
1885 /**
1886 * Writes a length as uint32 prefixed UTF8 encoded string.
1887 * @param {string} str String to write
1888 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1889 * written if omitted.
1890 * @returns {!ByteBuffer|number} `this` if `offset` is omitted, else the actual number of bytes written
1891 * @expose
1892 * @see ByteBuffer#writeVarint32
1893 */
1894 ByteBufferPrototype.writeIString = function(str, offset) {
1895 var relative = typeof offset === 'undefined';
1896 if (relative) offset = this.offset;
1897 if (!this.noAssert) {
1898 if (typeof str !== 'string')
1899 throw TypeError("Illegal str: Not a string");
1900 if (typeof offset !== 'number' || offset % 1 !== 0)
1901 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1902 offset >>>= 0;
1903 if (offset < 0 || offset + 0 > this.buffer.length)
1904 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
1905 }
1906 var start = offset,
1907 k;
1908 k = Buffer.byteLength(str, "utf8");
1909 offset += 4+k;
1910 var capacity13 = this.buffer.length;
1911 if (offset > capacity13)
1912 this.resize((capacity13 *= 2) > offset ? capacity13 : offset);
1913 offset -= 4+k;
1914 if (this.littleEndian) {
1915 this.buffer[offset+3] = (k >>> 24) & 0xFF;
1916 this.buffer[offset+2] = (k >>> 16) & 0xFF;
1917 this.buffer[offset+1] = (k >>> 8) & 0xFF;
1918 this.buffer[offset ] = k & 0xFF;
1919 } else {
1920 this.buffer[offset ] = (k >>> 24) & 0xFF;
1921 this.buffer[offset+1] = (k >>> 16) & 0xFF;
1922 this.buffer[offset+2] = (k >>> 8) & 0xFF;
1923 this.buffer[offset+3] = k & 0xFF;
1924 }
1925 offset += 4;
1926 offset += this.buffer.write(str, offset, k, "utf8");
1927 if (relative) {
1928 this.offset = offset;
1929 return this;
1930 }
1931 return offset - start;
1932 };
1934 /**
1935 * Reads a length as uint32 prefixed UTF8 encoded string.
1936 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
1937 * read if omitted.
1938 * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
1939 * read and the actual number of bytes read.
1940 * @expose
1941 * @see ByteBuffer#readVarint32
1942 */
1943 ByteBufferPrototype.readIString = function(offset) {
1944 var relative = typeof offset === 'undefined';
1945 if (relative) offset = this.offset;
1946 if (!this.noAssert) {
1947 if (typeof offset !== 'number' || offset % 1 !== 0)
1948 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1949 offset >>>= 0;
1950 if (offset < 0 || offset + 4 > this.buffer.length)
1951 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+4+") <= "+this.buffer.length);
1952 }
1953 var start = offset;
1954 var len = this.readUint32(offset);
1955 var str = this.readUTF8String(len, ByteBuffer.METRICS_BYTES, offset += 4);
1956 offset += str['length'];
1957 if (relative) {
1958 this.offset = offset;
1959 return str['string'];
1960 } else {
1961 return {
1962 'string': str['string'],
1963 'length': offset - start
1964 };
1965 }
1966 };
1968 // types/strings/utf8string
1970 /**
1971 * Metrics representing number of UTF8 characters. Evaluates to `c`.
1972 * @type {string}
1973 * @const
1974 * @expose
1975 */
1976 ByteBuffer.METRICS_CHARS = 'c';
1978 /**
1979 * Metrics representing number of bytes. Evaluates to `b`.
1980 * @type {string}
1981 * @const
1982 * @expose
1983 */
1984 ByteBuffer.METRICS_BYTES = 'b';
1986 /**
1987 * Writes an UTF8 encoded string.
1988 * @param {string} str String to write
1989 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted.
1990 * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written.
1991 * @expose
1992 */
1993 ByteBufferPrototype.writeUTF8String = function(str, offset) {
1994 var relative = typeof offset === 'undefined';
1995 if (relative) offset = this.offset;
1996 if (!this.noAssert) {
1997 if (typeof offset !== 'number' || offset % 1 !== 0)
1998 throw TypeError("Illegal offset: "+offset+" (not an integer)");
1999 offset >>>= 0;
2000 if (offset < 0 || offset + 0 > this.buffer.length)
2001 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
2002 }
2003 var k;
2004 k = Buffer.byteLength(str, "utf8");
2005 offset += k;
2006 var capacity14 = this.buffer.length;
2007 if (offset > capacity14)
2008 this.resize((capacity14 *= 2) > offset ? capacity14 : offset);
2009 offset -= k;
2010 offset += this.buffer.write(str, offset, k, "utf8");
2011 if (relative) {
2012 this.offset = offset;
2013 return this;
2014 }
2015 return k;
2016 };
2018 /**
2019 * Writes an UTF8 encoded string. This is an alias of {@link ByteBuffer#writeUTF8String}.
2020 * @function
2021 * @param {string} str String to write
2022 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} if omitted.
2023 * @returns {!ByteBuffer|number} this if offset is omitted, else the actual number of bytes written.
2024 * @expose
2025 */
2026 ByteBufferPrototype.writeString = ByteBufferPrototype.writeUTF8String;
2028 /**
2029 * Calculates the number of UTF8 characters of a string. JavaScript itself uses UTF-16, so that a string's
2030 * `length` property does not reflect its actual UTF8 size if it contains code points larger than 0xFFFF.
2031 * @param {string} str String to calculate
2032 * @returns {number} Number of UTF8 characters
2033 * @expose
2034 */
2035 ByteBuffer.calculateUTF8Chars = function(str) {
2036 return utfx.calculateUTF16asUTF8(stringSource(str))[0];
2037 };
2039 /**
2040 * Calculates the number of UTF8 bytes of a string.
2041 * @param {string} str String to calculate
2042 * @returns {number} Number of UTF8 bytes
2043 * @expose
2044 */
2045 ByteBuffer.calculateUTF8Bytes = function(str) {
2046 if (typeof str !== 'string')
2047 throw TypeError("Illegal argument: "+(typeof str));
2048 return Buffer.byteLength(str, "utf8");
2049 };
2051 /**
2052 * Calculates the number of UTF8 bytes of a string. This is an alias of {@link ByteBuffer.calculateUTF8Bytes}.
2053 * @function
2054 * @param {string} str String to calculate
2055 * @returns {number} Number of UTF8 bytes
2056 * @expose
2057 */
2058 ByteBuffer.calculateString = ByteBuffer.calculateUTF8Bytes;
2060 /**
2061 * Reads an UTF8 encoded string.
2062 * @param {number} length Number of characters or bytes to read.
2063 * @param {string=} metrics Metrics specifying what `length` is meant to count. Defaults to
2064 * {@link ByteBuffer.METRICS_CHARS}.
2065 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2066 * read if omitted.
2067 * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
2068 * read and the actual number of bytes read.
2069 * @expose
2070 */
2071 ByteBufferPrototype.readUTF8String = function(length, metrics, offset) {
2072 if (typeof metrics === 'number') {
2073 offset = metrics;
2074 metrics = undefined;
2075 }
2076 var relative = typeof offset === 'undefined';
2077 if (relative) offset = this.offset;
2078 if (typeof metrics === 'undefined') metrics = ByteBuffer.METRICS_CHARS;
2079 if (!this.noAssert) {
2080 if (typeof length !== 'number' || length % 1 !== 0)
2081 throw TypeError("Illegal length: "+length+" (not an integer)");
2082 length |= 0;
2083 if (typeof offset !== 'number' || offset % 1 !== 0)
2084 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2085 offset >>>= 0;
2086 if (offset < 0 || offset + 0 > this.buffer.length)
2087 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
2088 }
2089 var i = 0,
2090 start = offset,
2091 temp,
2092 sd;
2093 if (metrics === ByteBuffer.METRICS_CHARS) { // The same for node and the browser
2094 sd = stringDestination();
2095 utfx.decodeUTF8(function() {
2096 return i < length && offset < this.limit ? this.buffer[offset++] : null;
2097 }.bind(this), function(cp) {
2098 ++i; utfx.UTF8toUTF16(cp, sd);
2099 });
2100 if (i !== length)
2101 throw RangeError("Illegal range: Truncated data, "+i+" == "+length);
2102 if (relative) {
2103 this.offset = offset;
2104 return sd();
2105 } else {
2106 return {
2107 "string": sd(),
2108 "length": offset - start
2109 };
2110 }
2111 } else if (metrics === ByteBuffer.METRICS_BYTES) {
2112 if (!this.noAssert) {
2113 if (typeof offset !== 'number' || offset % 1 !== 0)
2114 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2115 offset >>>= 0;
2116 if (offset < 0 || offset + length > this.buffer.length)
2117 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+length+") <= "+this.buffer.length);
2118 }
2119 temp = this.buffer.toString("utf8", offset, offset+length);
2120 if (relative) {
2121 this.offset += length;
2122 return temp;
2123 } else {
2124 return {
2125 'string': temp,
2126 'length': length
2127 };
2128 }
2129 } else
2130 throw TypeError("Unsupported metrics: "+metrics);
2131 };
2133 /**
2134 * Reads an UTF8 encoded string. This is an alias of {@link ByteBuffer#readUTF8String}.
2135 * @function
2136 * @param {number} length Number of characters or bytes to read
2137 * @param {number=} metrics Metrics specifying what `n` is meant to count. Defaults to
2138 * {@link ByteBuffer.METRICS_CHARS}.
2139 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2140 * read if omitted.
2141 * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
2142 * read and the actual number of bytes read.
2143 * @expose
2144 */
2145 ByteBufferPrototype.readString = ByteBufferPrototype.readUTF8String;
2147 // types/strings/vstring
2149 /**
2150 * Writes a length as varint32 prefixed UTF8 encoded string.
2151 * @param {string} str String to write
2152 * @param {number=} offset Offset to write to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2153 * written if omitted.
2154 * @returns {!ByteBuffer|number} `this` if `offset` is omitted, else the actual number of bytes written
2155 * @expose
2156 * @see ByteBuffer#writeVarint32
2157 */
2158 ByteBufferPrototype.writeVString = function(str, offset) {
2159 var relative = typeof offset === 'undefined';
2160 if (relative) offset = this.offset;
2161 if (!this.noAssert) {
2162 if (typeof str !== 'string')
2163 throw TypeError("Illegal str: Not a string");
2164 if (typeof offset !== 'number' || offset % 1 !== 0)
2165 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2166 offset >>>= 0;
2167 if (offset < 0 || offset + 0 > this.buffer.length)
2168 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
2169 }
2170 var start = offset,
2171 k, l;
2172 k = Buffer.byteLength(str, "utf8");
2173 l = ByteBuffer.calculateVarint32(k);
2174 offset += l+k;
2175 var capacity15 = this.buffer.length;
2176 if (offset > capacity15)
2177 this.resize((capacity15 *= 2) > offset ? capacity15 : offset);
2178 offset -= l+k;
2179 offset += this.writeVarint32(k, offset);
2180 offset += this.buffer.write(str, offset, k, "utf8");
2181 if (relative) {
2182 this.offset = offset;
2183 return this;
2184 }
2185 return offset - start;
2186 };
2188 /**
2189 * Reads a length as varint32 prefixed UTF8 encoded string.
2190 * @param {number=} offset Offset to read from. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2191 * read if omitted.
2192 * @returns {string|!{string: string, length: number}} The string read if offset is omitted, else the string
2193 * read and the actual number of bytes read.
2194 * @expose
2195 * @see ByteBuffer#readVarint32
2196 */
2197 ByteBufferPrototype.readVString = function(offset) {
2198 var relative = typeof offset === 'undefined';
2199 if (relative) offset = this.offset;
2200 if (!this.noAssert) {
2201 if (typeof offset !== 'number' || offset % 1 !== 0)
2202 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2203 offset >>>= 0;
2204 if (offset < 0 || offset + 1 > this.buffer.length)
2205 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+1+") <= "+this.buffer.length);
2206 }
2207 var start = offset;
2208 var len = this.readVarint32(offset);
2209 var str = this.readUTF8String(len['value'], ByteBuffer.METRICS_BYTES, offset += len['length']);
2210 offset += str['length'];
2211 if (relative) {
2212 this.offset = offset;
2213 return str['string'];
2214 } else {
2215 return {
2216 'string': str['string'],
2217 'length': offset - start
2218 };
2219 }
2220 };
2223 /**
2224 * Appends some data to this ByteBuffer. This will overwrite any contents behind the specified offset up to the appended
2225 * data's length.
2226 * @param {!ByteBuffer|!Buffer|!ArrayBuffer|!Uint8Array|string} source Data to append. If `source` is a ByteBuffer, its
2227 * offsets will be modified according to the performed read operation.
2228 * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8")
2229 * @param {number=} offset Offset to append at. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2230 * written if omitted.
2231 * @returns {!ByteBuffer} this
2232 * @expose
2233 * @example A relative `<01 02>03.append(<04 05>)` will result in `<01 02 04 05>, 04 05|`
2234 * @example An absolute `<01 02>03.append(04 05>, 1)` will result in `<01 04>05, 04 05|`
2235 */
2236 ByteBufferPrototype.append = function(source, encoding, offset) {
2237 if (typeof encoding === 'number' || typeof encoding !== 'string') {
2238 offset = encoding;
2239 encoding = undefined;
2240 }
2241 var relative = typeof offset === 'undefined';
2242 if (relative) offset = this.offset;
2243 if (!this.noAssert) {
2244 if (typeof offset !== 'number' || offset % 1 !== 0)
2245 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2246 offset >>>= 0;
2247 if (offset < 0 || offset + 0 > this.buffer.length)
2248 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
2249 }
2250 if (!(source instanceof ByteBuffer))
2251 source = ByteBuffer.wrap(source, encoding);
2252 var length = source.limit - source.offset;
2253 if (length <= 0) return this; // Nothing to append
2254 offset += length;
2255 var capacity16 = this.buffer.length;
2256 if (offset > capacity16)
2257 this.resize((capacity16 *= 2) > offset ? capacity16 : offset);
2258 offset -= length;
2259 source.buffer.copy(this.buffer, offset, source.offset, source.limit);
2260 source.offset += length;
2261 if (relative) this.offset += length;
2262 return this;
2263 };
2265 /**
2266 * Appends this ByteBuffer's contents to another ByteBuffer. This will overwrite any contents at and after the
2267 specified offset up to the length of this ByteBuffer's data.
2268 * @param {!ByteBuffer} target Target ByteBuffer
2269 * @param {number=} offset Offset to append to. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2270 * read if omitted.
2271 * @returns {!ByteBuffer} this
2272 * @expose
2273 * @see ByteBuffer#append
2274 */
2275 ByteBufferPrototype.appendTo = function(target, offset) {
2276 target.append(this, offset);
2277 return this;
2278 };
2280 /**
2281 * Enables or disables assertions of argument types and offsets. Assertions are enabled by default but you can opt to
2282 * disable them if your code already makes sure that everything is valid.
2283 * @param {boolean} assert `true` to enable assertions, otherwise `false`
2284 * @returns {!ByteBuffer} this
2285 * @expose
2286 */
2287 ByteBufferPrototype.assert = function(assert) {
2288 this.noAssert = !assert;
2289 return this;
2290 };
2292 /**
2293 * Gets the capacity of this ByteBuffer's backing buffer.
2294 * @returns {number} Capacity of the backing buffer
2295 * @expose
2296 */
2297 ByteBufferPrototype.capacity = function() {
2298 return this.buffer.length;
2299 };
2300 /**
2301 * Clears this ByteBuffer's offsets by setting {@link ByteBuffer#offset} to `0` and {@link ByteBuffer#limit} to the
2302 * backing buffer's capacity. Discards {@link ByteBuffer#markedOffset}.
2303 * @returns {!ByteBuffer} this
2304 * @expose
2305 */
2306 ByteBufferPrototype.clear = function() {
2307 this.offset = 0;
2308 this.limit = this.buffer.length;
2309 this.markedOffset = -1;
2310 return this;
2311 };
2313 /**
2314 * Creates a cloned instance of this ByteBuffer, preset with this ByteBuffer's values for {@link ByteBuffer#offset},
2315 * {@link ByteBuffer#markedOffset} and {@link ByteBuffer#limit}.
2316 * @param {boolean=} copy Whether to copy the backing buffer or to return another view on the same, defaults to `false`
2317 * @returns {!ByteBuffer} Cloned instance
2318 * @expose
2319 */
2320 ByteBufferPrototype.clone = function(copy) {
2321 var bb = new ByteBuffer(0, this.littleEndian, this.noAssert);
2322 if (copy) {
2323 var buffer = new Buffer(this.buffer.length);
2324 this.buffer.copy(buffer);
2325 bb.buffer = buffer;
2326 } else {
2327 bb.buffer = this.buffer;
2328 }
2329 bb.offset = this.offset;
2330 bb.markedOffset = this.markedOffset;
2331 bb.limit = this.limit;
2332 return bb;
2333 };
2335 /**
2336 * Compacts this ByteBuffer to be backed by a {@link ByteBuffer#buffer} of its contents' length. Contents are the bytes
2337 * between {@link ByteBuffer#offset} and {@link ByteBuffer#limit}. Will set `offset = 0` and `limit = capacity` and
2338 * adapt {@link ByteBuffer#markedOffset} to the same relative position if set.
2339 * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset}
2340 * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}
2341 * @returns {!ByteBuffer} this
2342 * @expose
2343 */
2344 ByteBufferPrototype.compact = function(begin, end) {
2345 if (typeof begin === 'undefined') begin = this.offset;
2346 if (typeof end === 'undefined') end = this.limit;
2347 if (!this.noAssert) {
2348 if (typeof begin !== 'number' || begin % 1 !== 0)
2349 throw TypeError("Illegal begin: Not an integer");
2350 begin >>>= 0;
2351 if (typeof end !== 'number' || end % 1 !== 0)
2352 throw TypeError("Illegal end: Not an integer");
2353 end >>>= 0;
2354 if (begin < 0 || begin > end || end > this.buffer.length)
2355 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
2356 }
2357 if (begin === 0 && end === this.buffer.length)
2358 return this; // Already compacted
2359 var len = end - begin;
2360 if (len === 0) {
2361 this.buffer = EMPTY_BUFFER;
2362 if (this.markedOffset >= 0) this.markedOffset -= begin;
2363 this.offset = 0;
2364 this.limit = 0;
2365 return this;
2366 }
2367 var buffer = new Buffer(len);
2368 this.buffer.copy(buffer, 0, begin, end);
2369 this.buffer = buffer;
2370 if (this.markedOffset >= 0) this.markedOffset -= begin;
2371 this.offset = 0;
2372 this.limit = len;
2373 return this;
2374 };
2376 /**
2377 * Creates a copy of this ByteBuffer's contents. Contents are the bytes between {@link ByteBuffer#offset} and
2378 * {@link ByteBuffer#limit}.
2379 * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}.
2380 * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}.
2381 * @returns {!ByteBuffer} Copy
2382 * @expose
2383 */
2384 ByteBufferPrototype.copy = function(begin, end) {
2385 if (typeof begin === 'undefined') begin = this.offset;
2386 if (typeof end === 'undefined') end = this.limit;
2387 if (!this.noAssert) {
2388 if (typeof begin !== 'number' || begin % 1 !== 0)
2389 throw TypeError("Illegal begin: Not an integer");
2390 begin >>>= 0;
2391 if (typeof end !== 'number' || end % 1 !== 0)
2392 throw TypeError("Illegal end: Not an integer");
2393 end >>>= 0;
2394 if (begin < 0 || begin > end || end > this.buffer.length)
2395 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
2396 }
2397 if (begin === end)
2398 return new ByteBuffer(0, this.littleEndian, this.noAssert);
2399 var capacity = end - begin,
2400 bb = new ByteBuffer(capacity, this.littleEndian, this.noAssert);
2401 bb.offset = 0;
2402 bb.limit = capacity;
2403 if (bb.markedOffset >= 0) bb.markedOffset -= begin;
2404 this.copyTo(bb, 0, begin, end);
2405 return bb;
2406 };
2408 /**
2409 * Copies this ByteBuffer's contents to another ByteBuffer. Contents are the bytes between {@link ByteBuffer#offset} and
2410 * {@link ByteBuffer#limit}.
2411 * @param {!ByteBuffer} target Target ByteBuffer
2412 * @param {number=} targetOffset Offset to copy to. Will use and increase the target's {@link ByteBuffer#offset}
2413 * by the number of bytes copied if omitted.
2414 * @param {number=} sourceOffset Offset to start copying from. Will use and increase {@link ByteBuffer#offset} by the
2415 * number of bytes copied if omitted.
2416 * @param {number=} sourceLimit Offset to end copying from, defaults to {@link ByteBuffer#limit}
2417 * @returns {!ByteBuffer} this
2418 * @expose
2419 */
2420 ByteBufferPrototype.copyTo = function(target, targetOffset, sourceOffset, sourceLimit) {
2421 var relative,
2422 targetRelative;
2423 if (!this.noAssert) {
2424 if (!ByteBuffer.isByteBuffer(target))
2425 throw TypeError("Illegal target: Not a ByteBuffer");
2426 }
2427 targetOffset = (targetRelative = typeof targetOffset === 'undefined') ? target.offset : targetOffset | 0;
2428 sourceOffset = (relative = typeof sourceOffset === 'undefined') ? this.offset : sourceOffset | 0;
2429 sourceLimit = typeof sourceLimit === 'undefined' ? this.limit : sourceLimit | 0;
2431 if (targetOffset < 0 || targetOffset > target.buffer.length)
2432 throw RangeError("Illegal target range: 0 <= "+targetOffset+" <= "+target.buffer.length);
2433 if (sourceOffset < 0 || sourceLimit > this.buffer.length)
2434 throw RangeError("Illegal source range: 0 <= "+sourceOffset+" <= "+this.buffer.length);
2436 var len = sourceLimit - sourceOffset;
2437 if (len === 0)
2438 return target; // Nothing to copy
2440 target.ensureCapacity(targetOffset + len);
2442 this.buffer.copy(target.buffer, targetOffset, sourceOffset, sourceLimit);
2444 if (relative) this.offset += len;
2445 if (targetRelative) target.offset += len;
2447 return this;
2448 };
2450 /**
2451 * Makes sure that this ByteBuffer is backed by a {@link ByteBuffer#buffer} of at least the specified capacity. If the
2452 * current capacity is exceeded, it will be doubled. If double the current capacity is less than the required capacity,
2453 * the required capacity will be used instead.
2454 * @param {number} capacity Required capacity
2455 * @returns {!ByteBuffer} this
2456 * @expose
2457 */
2458 ByteBufferPrototype.ensureCapacity = function(capacity) {
2459 var current = this.buffer.length;
2460 if (current < capacity)
2461 return this.resize((current *= 2) > capacity ? current : capacity);
2462 return this;
2463 };
2465 /**
2466 * Overwrites this ByteBuffer's contents with the specified value. Contents are the bytes between
2467 * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}.
2468 * @param {number|string} value Byte value to fill with. If given as a string, the first character is used.
2469 * @param {number=} begin Begin offset. Will use and increase {@link ByteBuffer#offset} by the number of bytes
2470 * written if omitted. defaults to {@link ByteBuffer#offset}.
2471 * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}.
2472 * @returns {!ByteBuffer} this
2473 * @expose
2474 * @example `someByteBuffer.clear().fill(0)` fills the entire backing buffer with zeroes
2475 */
2476 ByteBufferPrototype.fill = function(value, begin, end) {
2477 var relative = typeof begin === 'undefined';
2478 if (relative) begin = this.offset;
2479 if (typeof value === 'string' && value.length > 0)
2480 value = value.charCodeAt(0);
2481 if (typeof begin === 'undefined') begin = this.offset;
2482 if (typeof end === 'undefined') end = this.limit;
2483 if (!this.noAssert) {
2484 if (typeof value !== 'number' || value % 1 !== 0)
2485 throw TypeError("Illegal value: "+value+" (not an integer)");
2486 value |= 0;
2487 if (typeof begin !== 'number' || begin % 1 !== 0)
2488 throw TypeError("Illegal begin: Not an integer");
2489 begin >>>= 0;
2490 if (typeof end !== 'number' || end % 1 !== 0)
2491 throw TypeError("Illegal end: Not an integer");
2492 end >>>= 0;
2493 if (begin < 0 || begin > end || end > this.buffer.length)
2494 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
2495 }
2496 if (begin >= end)
2497 return this; // Nothing to fill
2498 this.buffer.fill(value, begin, end);
2499 begin = end;
2500 if (relative) this.offset = begin;
2501 return this;
2502 };
2504 /**
2505 * Makes this ByteBuffer ready for a new sequence of write or relative read operations. Sets `limit = offset` and
2506 * `offset = 0`. Make sure always to flip a ByteBuffer when all relative read or write operations are complete.
2507 * @returns {!ByteBuffer} this
2508 * @expose
2509 */
2510 ByteBufferPrototype.flip = function() {
2511 this.limit = this.offset;
2512 this.offset = 0;
2513 return this;
2514 };
2515 /**
2516 * Marks an offset on this ByteBuffer to be used later.
2517 * @param {number=} offset Offset to mark. Defaults to {@link ByteBuffer#offset}.
2518 * @returns {!ByteBuffer} this
2519 * @throws {TypeError} If `offset` is not a valid number
2520 * @throws {RangeError} If `offset` is out of bounds
2521 * @see ByteBuffer#reset
2522 * @expose
2523 */
2524 ByteBufferPrototype.mark = function(offset) {
2525 offset = typeof offset === 'undefined' ? this.offset : offset;
2526 if (!this.noAssert) {
2527 if (typeof offset !== 'number' || offset % 1 !== 0)
2528 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2529 offset >>>= 0;
2530 if (offset < 0 || offset + 0 > this.buffer.length)
2531 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
2532 }
2533 this.markedOffset = offset;
2534 return this;
2535 };
2536 /**
2537 * Sets the byte order.
2538 * @param {boolean} littleEndian `true` for little endian byte order, `false` for big endian
2539 * @returns {!ByteBuffer} this
2540 * @expose
2541 */
2542 ByteBufferPrototype.order = function(littleEndian) {
2543 if (!this.noAssert) {
2544 if (typeof littleEndian !== 'boolean')
2545 throw TypeError("Illegal littleEndian: Not a boolean");
2546 }
2547 this.littleEndian = !!littleEndian;
2548 return this;
2549 };
2551 /**
2552 * Switches (to) little endian byte order.
2553 * @param {boolean=} littleEndian Defaults to `true`, otherwise uses big endian
2554 * @returns {!ByteBuffer} this
2555 * @expose
2556 */
2557 ByteBufferPrototype.LE = function(littleEndian) {
2558 this.littleEndian = typeof littleEndian !== 'undefined' ? !!littleEndian : true;
2559 return this;
2560 };
2562 /**
2563 * Switches (to) big endian byte order.
2564 * @param {boolean=} bigEndian Defaults to `true`, otherwise uses little endian
2565 * @returns {!ByteBuffer} this
2566 * @expose
2567 */
2568 ByteBufferPrototype.BE = function(bigEndian) {
2569 this.littleEndian = typeof bigEndian !== 'undefined' ? !bigEndian : false;
2570 return this;
2571 };
2572 /**
2573 * Prepends some data to this ByteBuffer. This will overwrite any contents before the specified offset up to the
2574 * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer
2575 * will be resized and its contents moved accordingly.
2576 * @param {!ByteBuffer|string||!Buffer} source Data to prepend. If `source` is a ByteBuffer, its offset will be modified
2577 * according to the performed read operation.
2578 * @param {(string|number)=} encoding Encoding if `data` is a string ("base64", "hex", "binary", defaults to "utf8")
2579 * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes
2580 * prepended if omitted.
2581 * @returns {!ByteBuffer} this
2582 * @expose
2583 * @example A relative `00<01 02 03>.prepend(<04 05>)` results in `<04 05 01 02 03>, 04 05|`
2584 * @example An absolute `00<01 02 03>.prepend(<04 05>, 2)` results in `04<05 02 03>, 04 05|`
2585 */
2586 ByteBufferPrototype.prepend = function(source, encoding, offset) {
2587 if (typeof encoding === 'number' || typeof encoding !== 'string') {
2588 offset = encoding;
2589 encoding = undefined;
2590 }
2591 var relative = typeof offset === 'undefined';
2592 if (relative) offset = this.offset;
2593 if (!this.noAssert) {
2594 if (typeof offset !== 'number' || offset % 1 !== 0)
2595 throw TypeError("Illegal offset: "+offset+" (not an integer)");
2596 offset >>>= 0;
2597 if (offset < 0 || offset + 0 > this.buffer.length)
2598 throw RangeError("Illegal offset: 0 <= "+offset+" (+"+0+") <= "+this.buffer.length);
2599 }
2600 if (!(source instanceof ByteBuffer))
2601 source = ByteBuffer.wrap(source, encoding);
2602 var len = source.limit - source.offset;
2603 if (len <= 0) return this; // Nothing to prepend
2604 var diff = len - offset;
2605 if (diff > 0) { // Not enough space before offset, so resize + move
2606 var buffer = new Buffer(this.buffer.length + diff);
2607 this.buffer.copy(buffer, len, offset, this.buffer.length);
2608 this.buffer = buffer;
2609 this.offset += diff;
2610 if (this.markedOffset >= 0) this.markedOffset += diff;
2611 this.limit += diff;
2612 offset += diff;
2613 } source.buffer.copy(this.buffer, offset - len, source.offset, source.limit);
2615 source.offset = source.limit;
2616 if (relative)
2617 this.offset -= len;
2618 return this;
2619 };
2621 /**
2622 * Prepends this ByteBuffer to another ByteBuffer. This will overwrite any contents before the specified offset up to the
2623 * prepended data's length. If there is not enough space available before the specified `offset`, the backing buffer
2624 * will be resized and its contents moved accordingly.
2625 * @param {!ByteBuffer} target Target ByteBuffer
2626 * @param {number=} offset Offset to prepend at. Will use and decrease {@link ByteBuffer#offset} by the number of bytes
2627 * prepended if omitted.
2628 * @returns {!ByteBuffer} this
2629 * @expose
2630 * @see ByteBuffer#prepend
2631 */
2632 ByteBufferPrototype.prependTo = function(target, offset) {
2633 target.prepend(this, offset);
2634 return this;
2635 };
2636 /**
2637 * Prints debug information about this ByteBuffer's contents.
2638 * @param {function(string)=} out Output function to call, defaults to console.log
2639 * @expose
2640 */
2641 ByteBufferPrototype.printDebug = function(out) {
2642 if (typeof out !== 'function') out = console.log.bind(console);
2643 out(
2644 this.toString()+"\n"+
2645 "-------------------------------------------------------------------\n"+
2646 this.toDebug(/* columns */ true)
2647 );
2648 };
2650 /**
2651 * Gets the number of remaining readable bytes. Contents are the bytes between {@link ByteBuffer#offset} and
2652 * {@link ByteBuffer#limit}, so this returns `limit - offset`.
2653 * @returns {number} Remaining readable bytes. May be negative if `offset > limit`.
2654 * @expose
2655 */
2656 ByteBufferPrototype.remaining = function() {
2657 return this.limit - this.offset;
2658 };
2659 /**
2660 * Resets this ByteBuffer's {@link ByteBuffer#offset}. If an offset has been marked through {@link ByteBuffer#mark}
2661 * before, `offset` will be set to {@link ByteBuffer#markedOffset}, which will then be discarded. If no offset has been
2662 * marked, sets `offset = 0`.
2663 * @returns {!ByteBuffer} this
2664 * @see ByteBuffer#mark
2665 * @expose
2666 */
2667 ByteBufferPrototype.reset = function() {
2668 if (this.markedOffset >= 0) {
2669 this.offset = this.markedOffset;
2670 this.markedOffset = -1;
2671 } else {
2672 this.offset = 0;
2673 }
2674 return this;
2675 };
2676 /**
2677 * Resizes this ByteBuffer to be backed by a buffer of at least the given capacity. Will do nothing if already that
2678 * large or larger.
2679 * @param {number} capacity Capacity required
2680 * @returns {!ByteBuffer} this
2681 * @throws {TypeError} If `capacity` is not a number
2682 * @throws {RangeError} If `capacity < 0`
2683 * @expose
2684 */
2685 ByteBufferPrototype.resize = function(capacity) {
2686 if (!this.noAssert) {
2687 if (typeof capacity !== 'number' || capacity % 1 !== 0)
2688 throw TypeError("Illegal capacity: "+capacity+" (not an integer)");
2689 capacity |= 0;
2690 if (capacity < 0)
2691 throw RangeError("Illegal capacity: 0 <= "+capacity);
2692 }
2693 if (this.buffer.length < capacity) {
2694 var buffer = new Buffer(capacity);
2695 this.buffer.copy(buffer);
2696 this.buffer = buffer;
2697 }
2698 return this;
2699 };
2700 /**
2701 * Reverses this ByteBuffer's contents.
2702 * @param {number=} begin Offset to start at, defaults to {@link ByteBuffer#offset}
2703 * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}
2704 * @returns {!ByteBuffer} this
2705 * @expose
2706 */
2707 ByteBufferPrototype.reverse = function(begin, end) {
2708 if (typeof begin === 'undefined') begin = this.offset;
2709 if (typeof end === 'undefined') end = this.limit;
2710 if (!this.noAssert) {
2711 if (typeof begin !== 'number' || begin % 1 !== 0)
2712 throw TypeError("Illegal begin: Not an integer");
2713 begin >>>= 0;
2714 if (typeof end !== 'number' || end % 1 !== 0)
2715 throw TypeError("Illegal end: Not an integer");
2716 end >>>= 0;
2717 if (begin < 0 || begin > end || end > this.buffer.length)
2718 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
2719 }
2720 if (begin === end)
2721 return this; // Nothing to reverse
2722 Array.prototype.reverse.call(this.buffer.slice(begin, end));
2723 return this;
2724 };
2725 /**
2726 * Skips the next `length` bytes. This will just advance
2727 * @param {number} length Number of bytes to skip. May also be negative to move the offset back.
2728 * @returns {!ByteBuffer} this
2729 * @expose
2730 */
2731 ByteBufferPrototype.skip = function(length) {
2732 if (!this.noAssert) {
2733 if (typeof length !== 'number' || length % 1 !== 0)
2734 throw TypeError("Illegal length: "+length+" (not an integer)");
2735 length |= 0;
2736 }
2737 var offset = this.offset + length;
2738 if (!this.noAssert) {
2739 if (offset < 0 || offset > this.buffer.length)
2740 throw RangeError("Illegal length: 0 <= "+this.offset+" + "+length+" <= "+this.buffer.length);
2741 }
2742 this.offset = offset;
2743 return this;
2744 };
2746 /**
2747 * Slices this ByteBuffer by creating a cloned instance with `offset = begin` and `limit = end`.
2748 * @param {number=} begin Begin offset, defaults to {@link ByteBuffer#offset}.
2749 * @param {number=} end End offset, defaults to {@link ByteBuffer#limit}.
2750 * @returns {!ByteBuffer} Clone of this ByteBuffer with slicing applied, backed by the same {@link ByteBuffer#buffer}
2751 * @expose
2752 */
2753 ByteBufferPrototype.slice = function(begin, end) {
2754 if (typeof begin === 'undefined') begin = this.offset;
2755 if (typeof end === 'undefined') end = this.limit;
2756 if (!this.noAssert) {
2757 if (typeof begin !== 'number' || begin % 1 !== 0)
2758 throw TypeError("Illegal begin: Not an integer");
2759 begin >>>= 0;
2760 if (typeof end !== 'number' || end % 1 !== 0)
2761 throw TypeError("Illegal end: Not an integer");
2762 end >>>= 0;
2763 if (begin < 0 || begin > end || end > this.buffer.length)
2764 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
2765 }
2766 var bb = this.clone();
2767 bb.offset = begin;
2768 bb.limit = end;
2769 return bb;
2770 };
2771 /**
2772 * Returns a copy of the backing buffer that contains this ByteBuffer's contents. Contents are the bytes between
2773 * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}.
2774 * @param {boolean=} forceCopy If `true` returns a copy, otherwise returns a view referencing the same memory if
2775 * possible. Defaults to `false`
2776 * @returns {!Buffer} Contents as a Buffer
2777 * @expose
2778 */
2779 ByteBufferPrototype.toBuffer = function(forceCopy) {
2780 var offset = this.offset,
2781 limit = this.limit;
2782 if (!this.noAssert) {
2783 if (typeof offset !== 'number' || offset % 1 !== 0)
2784 throw TypeError("Illegal offset: Not an integer");
2785 offset >>>= 0;
2786 if (typeof limit !== 'number' || limit % 1 !== 0)
2787 throw TypeError("Illegal limit: Not an integer");
2788 limit >>>= 0;
2789 if (offset < 0 || offset > limit || limit > this.buffer.length)
2790 throw RangeError("Illegal range: 0 <= "+offset+" <= "+limit+" <= "+this.buffer.length);
2791 }
2792 if (forceCopy) {
2793 var buffer = new Buffer(limit - offset);
2794 this.buffer.copy(buffer, 0, offset, limit);
2795 return buffer;
2796 } else {
2797 if (offset === 0 && limit === this.buffer.length)
2798 return this.buffer;
2799 else
2800 return this.buffer.slice(offset, limit);
2801 }
2802 };
2804 /**
2805 * Returns a copy of the backing buffer compacted to contain this ByteBuffer's contents. Contents are the bytes between
2806 * {@link ByteBuffer#offset} and {@link ByteBuffer#limit}.
2807 * @returns {!ArrayBuffer} Contents as an ArrayBuffer
2808 */
2809 ByteBufferPrototype.toArrayBuffer = function() {
2810 var offset = this.offset,
2811 limit = this.limit;
2812 if (!this.noAssert) {
2813 if (typeof offset !== 'number' || offset % 1 !== 0)
2814 throw TypeError("Illegal offset: Not an integer");
2815 offset >>>= 0;
2816 if (typeof limit !== 'number' || limit % 1 !== 0)
2817 throw TypeError("Illegal limit: Not an integer");
2818 limit >>>= 0;
2819 if (offset < 0 || offset > limit || limit > this.buffer.length)
2820 throw RangeError("Illegal range: 0 <= "+offset+" <= "+limit+" <= "+this.buffer.length);
2821 }
2822 var ab = new ArrayBuffer(limit - offset);
2823 if (memcpy) { // Fast
2824 memcpy(ab, 0, this.buffer, offset, limit);
2825 } else { // Slow
2826 var dst = new Uint8Array(ab);
2827 for (var i=offset; i<limit; ++i)
2828 dst[i-offset] = this.buffer[i];
2829 }
2830 return ab;
2831 };
2833 /**
2834 * Converts the ByteBuffer's contents to a string.
2835 * @param {string=} encoding Output encoding. Returns an informative string representation if omitted but also allows
2836 * direct conversion to "utf8", "hex", "base64" and "binary" encoding. "debug" returns a hex representation with
2837 * highlighted offsets.
2838 * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}
2839 * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}
2840 * @returns {string} String representation
2841 * @throws {Error} If `encoding` is invalid
2842 * @expose
2843 */
2844 ByteBufferPrototype.toString = function(encoding, begin, end) {
2845 if (typeof encoding === 'undefined')
2846 return "ByteBufferNB(offset="+this.offset+",markedOffset="+this.markedOffset+",limit="+this.limit+",capacity="+this.capacity()+")";
2847 if (typeof encoding === 'number')
2848 encoding = "utf8",
2849 begin = encoding,
2850 end = begin;
2851 switch (encoding) {
2852 case "utf8":
2853 return this.toUTF8(begin, end);
2854 case "base64":
2855 return this.toBase64(begin, end);
2856 case "hex":
2857 return this.toHex(begin, end);
2858 case "binary":
2859 return this.toBinary(begin, end);
2860 case "debug":
2861 return this.toDebug();
2862 case "columns":
2863 return this.toColumns();
2864 default:
2865 throw Error("Unsupported encoding: "+encoding);
2866 }
2867 };
2869 // encodings/base64
2871 /**
2872 * Encodes this ByteBuffer's contents to a base64 encoded string.
2873 * @param {number=} begin Offset to begin at, defaults to {@link ByteBuffer#offset}.
2874 * @param {number=} end Offset to end at, defaults to {@link ByteBuffer#limit}.
2875 * @returns {string} Base64 encoded string
2876 * @throws {RangeError} If `begin` or `end` is out of bounds
2877 * @expose
2878 */
2879 ByteBufferPrototype.toBase64 = function(begin, end) {
2880 if (typeof begin === 'undefined')
2881 begin = this.offset;
2882 if (typeof end === 'undefined')
2883 end = this.limit;
2884 begin = begin | 0; end = end | 0;
2885 if (begin < 0 || end > this.capacity || begin > end)
2886 throw RangeError("begin, end");
2887 return this.buffer.toString("base64", begin, end);
2888 };
2890 /**
2891 * Decodes a base64 encoded string to a ByteBuffer.
2892 * @param {string} str String to decode
2893 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
2894 * {@link ByteBuffer.DEFAULT_ENDIAN}.
2895 * @returns {!ByteBuffer} ByteBuffer
2896 * @expose
2897 */
2898 ByteBuffer.fromBase64 = function(str, littleEndian) {
2899 return ByteBuffer.wrap(new Buffer(str, "base64"), littleEndian);
2900 return bb;
2901 };
2903 /**
2904 * Encodes a binary string to base64 like `window.btoa` does.
2905 * @param {string} str Binary string
2906 * @returns {string} Base64 encoded string
2907 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.btoa
2908 * @expose
2909 */
2910 ByteBuffer.btoa = function(str) {
2911 return ByteBuffer.fromBinary(str).toBase64();
2912 };
2914 /**
2915 * Decodes a base64 encoded string to binary like `window.atob` does.
2916 * @param {string} b64 Base64 encoded string
2917 * @returns {string} Binary string
2918 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.atob
2919 * @expose
2920 */
2921 ByteBuffer.atob = function(b64) {
2922 return ByteBuffer.fromBase64(b64).toBinary();
2923 };
2925 // encodings/binary
2927 /**
2928 * Encodes this ByteBuffer to a binary encoded string, that is using only characters 0x00-0xFF as bytes.
2929 * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}.
2930 * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}.
2931 * @returns {string} Binary encoded string
2932 * @throws {RangeError} If `offset > limit`
2933 * @expose
2934 */
2935 ByteBufferPrototype.toBinary = function(begin, end) {
2936 if (typeof begin === 'undefined')
2937 begin = this.offset;
2938 if (typeof end === 'undefined')
2939 end = this.limit;
2940 begin |= 0; end |= 0;
2941 if (begin < 0 || end > this.capacity() || begin > end)
2942 throw RangeError("begin, end");
2943 return this.buffer.toString("binary", begin, end);
2944 };
2946 /**
2947 * Decodes a binary encoded string, that is using only characters 0x00-0xFF as bytes, to a ByteBuffer.
2948 * @param {string} str String to decode
2949 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
2950 * {@link ByteBuffer.DEFAULT_ENDIAN}.
2951 * @returns {!ByteBuffer} ByteBuffer
2952 * @expose
2953 */
2954 ByteBuffer.fromBinary = function(str, littleEndian) {
2955 return ByteBuffer.wrap(new Buffer(str, "binary"), littleEndian);
2956 return bb;
2957 };
2959 // encodings/debug
2961 /**
2962 * Encodes this ByteBuffer to a hex encoded string with marked offsets. Offset symbols are:
2963 * * `<` : offset,
2964 * * `'` : markedOffset,
2965 * * `>` : limit,
2966 * * `|` : offset and limit,
2967 * * `[` : offset and markedOffset,
2968 * * `]` : markedOffset and limit,
2969 * * `!` : offset, markedOffset and limit
2970 * @param {boolean=} columns If `true` returns two columns hex + ascii, defaults to `false`
2971 * @returns {string|!Array.<string>} Debug string or array of lines if `asArray = true`
2972 * @expose
2973 * @example `>00'01 02<03` contains four bytes with `limit=0, markedOffset=1, offset=3`
2974 * @example `00[01 02 03>` contains four bytes with `offset=markedOffset=1, limit=4`
2975 * @example `00|01 02 03` contains four bytes with `offset=limit=1, markedOffset=-1`
2976 * @example `|` contains zero bytes with `offset=limit=0, markedOffset=-1`
2977 */
2978 ByteBufferPrototype.toDebug = function(columns) {
2979 var i = -1,
2980 k = this.buffer.length,
2981 b,
2982 hex = "",
2983 asc = "",
2984 out = "";
2985 while (i<k) {
2986 if (i !== -1) {
2987 b = this.buffer[i];
2988 if (b < 0x10) hex += "0"+b.toString(16).toUpperCase();
2989 else hex += b.toString(16).toUpperCase();
2990 if (columns)
2991 asc += b > 32 && b < 127 ? String.fromCharCode(b) : '.';
2992 }
2993 ++i;
2994 if (columns) {
2995 if (i > 0 && i % 16 === 0 && i !== k) {
2996 while (hex.length < 3*16+3) hex += " ";
2997 out += hex+asc+"\n";
2998 hex = asc = "";
2999 }
3000 }
3001 if (i === this.offset && i === this.limit)
3002 hex += i === this.markedOffset ? "!" : "|";
3003 else if (i === this.offset)
3004 hex += i === this.markedOffset ? "[" : "<";
3005 else if (i === this.limit)
3006 hex += i === this.markedOffset ? "]" : ">";
3007 else
3008 hex += i === this.markedOffset ? "'" : (columns || (i !== 0 && i !== k) ? " " : "");
3009 }
3010 if (columns && hex !== " ") {
3011 while (hex.length < 3*16+3)
3012 hex += " ";
3013 out += hex + asc + "\n";
3014 }
3015 return columns ? out : hex;
3016 };
3018 /**
3019 * Decodes a hex encoded string with marked offsets to a ByteBuffer.
3020 * @param {string} str Debug string to decode (not be generated with `columns = true`)
3021 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
3022 * {@link ByteBuffer.DEFAULT_ENDIAN}.
3023 * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
3024 * {@link ByteBuffer.DEFAULT_NOASSERT}.
3025 * @returns {!ByteBuffer} ByteBuffer
3026 * @expose
3027 * @see ByteBuffer#toDebug
3028 */
3029 ByteBuffer.fromDebug = function(str, littleEndian, noAssert) {
3030 var k = str.length,
3031 bb = new ByteBuffer(((k+1)/3)|0, littleEndian, noAssert);
3032 var i = 0, j = 0, ch, b,
3033 rs = false, // Require symbol next
3034 ho = false, hm = false, hl = false, // Already has offset (ho), markedOffset (hm), limit (hl)?
3035 fail = false;
3036 while (i<k) {
3037 switch (ch = str.charAt(i++)) {
3038 case '!':
3039 if (!noAssert) {
3040 if (ho || hm || hl) {
3041 fail = true;
3042 break;
3043 }
3044 ho = hm = hl = true;
3045 }
3046 bb.offset = bb.markedOffset = bb.limit = j;
3047 rs = false;
3048 break;
3049 case '|':
3050 if (!noAssert) {
3051 if (ho || hl) {
3052 fail = true;
3053 break;
3054 }
3055 ho = hl = true;
3056 }
3057 bb.offset = bb.limit = j;
3058 rs = false;
3059 break;
3060 case '[':
3061 if (!noAssert) {
3062 if (ho || hm) {
3063 fail = true;
3064 break;
3065 }
3066 ho = hm = true;
3067 }
3068 bb.offset = bb.markedOffset = j;
3069 rs = false;
3070 break;
3071 case '<':
3072 if (!noAssert) {
3073 if (ho) {
3074 fail = true;
3075 break;
3076 }
3077 ho = true;
3078 }
3079 bb.offset = j;
3080 rs = false;
3081 break;
3082 case ']':
3083 if (!noAssert) {
3084 if (hl || hm) {
3085 fail = true;
3086 break;
3087 }
3088 hl = hm = true;
3089 }
3090 bb.limit = bb.markedOffset = j;
3091 rs = false;
3092 break;
3093 case '>':
3094 if (!noAssert) {
3095 if (hl) {
3096 fail = true;
3097 break;
3098 }
3099 hl = true;
3100 }
3101 bb.limit = j;
3102 rs = false;
3103 break;
3104 case "'":
3105 if (!noAssert) {
3106 if (hm) {
3107 fail = true;
3108 break;
3109 }
3110 hm = true;
3111 }
3112 bb.markedOffset = j;
3113 rs = false;
3114 break;
3115 case ' ':
3116 rs = false;
3117 break;
3118 default:
3119 if (!noAssert) {
3120 if (rs) {
3121 fail = true;
3122 break;
3123 }
3124 }
3125 b = parseInt(ch+str.charAt(i++), 16);
3126 if (!noAssert) {
3127 if (isNaN(b) || b < 0 || b > 255)
3128 throw TypeError("Illegal str: Not a debug encoded string");
3129 }
3130 bb.buffer[j++] = b;
3131 rs = true;
3132 }
3133 if (fail)
3134 throw TypeError("Illegal str: Invalid symbol at "+i);
3135 }
3136 if (!noAssert) {
3137 if (!ho || !hl)
3138 throw TypeError("Illegal str: Missing offset or limit");
3139 if (j<bb.buffer.length)
3140 throw TypeError("Illegal str: Not a debug encoded string (is it hex?) "+j+" < "+k);
3141 }
3142 return bb;
3143 };
3145 // encodings/hex
3147 /**
3148 * Encodes this ByteBuffer's contents to a hex encoded string.
3149 * @param {number=} begin Offset to begin at. Defaults to {@link ByteBuffer#offset}.
3150 * @param {number=} end Offset to end at. Defaults to {@link ByteBuffer#limit}.
3151 * @returns {string} Hex encoded string
3152 * @expose
3153 */
3154 ByteBufferPrototype.toHex = function(begin, end) {
3155 begin = typeof begin === 'undefined' ? this.offset : begin;
3156 end = typeof end === 'undefined' ? this.limit : end;
3157 if (!this.noAssert) {
3158 if (typeof begin !== 'number' || begin % 1 !== 0)
3159 throw TypeError("Illegal begin: Not an integer");
3160 begin >>>= 0;
3161 if (typeof end !== 'number' || end % 1 !== 0)
3162 throw TypeError("Illegal end: Not an integer");
3163 end >>>= 0;
3164 if (begin < 0 || begin > end || end > this.buffer.length)
3165 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
3166 }
3167 return this.buffer.toString("hex", begin, end);
3168 };
3170 /**
3171 * Decodes a hex encoded string to a ByteBuffer.
3172 * @param {string} str String to decode
3173 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
3174 * {@link ByteBuffer.DEFAULT_ENDIAN}.
3175 * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
3176 * {@link ByteBuffer.DEFAULT_NOASSERT}.
3177 * @returns {!ByteBuffer} ByteBuffer
3178 * @expose
3179 */
3180 ByteBuffer.fromHex = function(str, littleEndian, noAssert) {
3181 if (!noAssert) {
3182 if (typeof str !== 'string')
3183 throw TypeError("Illegal str: Not a string");
3184 if (str.length % 2 !== 0)
3185 throw TypeError("Illegal str: Length not a multiple of 2");
3186 }
3187 var bb = new ByteBuffer(0, littleEndian, true);
3188 bb.buffer = new Buffer(str, "hex");
3189 bb.limit = bb.buffer.length;
3190 return bb;
3191 };
3193 // utfx-embeddable
3195 /**
3196 * utfx-embeddable (c) 2014 Daniel Wirtz <dcode@dcode.io>
3197 * Released under the Apache License, Version 2.0
3198 * see: https://github.com/dcodeIO/utfx for details
3199 */
3200 var utfx = function() {
3201 "use strict";
3203 /**
3204 * utfx namespace.
3205 * @inner
3206 * @type {!Object.<string,*>}
3207 */
3208 var utfx = {};
3210 /**
3211 * Maximum valid code point.
3212 * @type {number}
3213 * @const
3214 */
3215 utfx.MAX_CODEPOINT = 0x10FFFF;
3217 /**
3218 * Encodes UTF8 code points to UTF8 bytes.
3219 * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
3220 * respectively `null` if there are no more code points left or a single numeric code point.
3221 * @param {!function(number)} dst Bytes destination as a function successively called with the next byte
3222 */
3223 utfx.encodeUTF8 = function(src, dst) {
3224 var cp = null;
3225 if (typeof src === 'number')
3226 cp = src,
3227 src = function() { return null; };
3228 while (cp !== null || (cp = src()) !== null) {
3229 if (cp < 0x80)
3230 dst(cp&0x7F);
3231 else if (cp < 0x800)
3232 dst(((cp>>6)&0x1F)|0xC0),
3233 dst((cp&0x3F)|0x80);
3234 else if (cp < 0x10000)
3235 dst(((cp>>12)&0x0F)|0xE0),
3236 dst(((cp>>6)&0x3F)|0x80),
3237 dst((cp&0x3F)|0x80);
3238 else
3239 dst(((cp>>18)&0x07)|0xF0),
3240 dst(((cp>>12)&0x3F)|0x80),
3241 dst(((cp>>6)&0x3F)|0x80),
3242 dst((cp&0x3F)|0x80);
3243 cp = null;
3244 }
3245 };
3247 /**
3248 * Decodes UTF8 bytes to UTF8 code points.
3249 * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
3250 * are no more bytes left.
3251 * @param {!function(number)} dst Code points destination as a function successively called with each decoded code point.
3252 * @throws {RangeError} If a starting byte is invalid in UTF8
3253 * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the
3254 * remaining bytes.
3255 */
3256 utfx.decodeUTF8 = function(src, dst) {
3257 var a, b, c, d, fail = function(b) {
3258 b = b.slice(0, b.indexOf(null));
3259 var err = Error(b.toString());
3260 err.name = "TruncatedError";
3261 err['bytes'] = b;
3262 throw err;
3263 };
3264 while ((a = src()) !== null) {
3265 if ((a&0x80) === 0)
3266 dst(a);
3267 else if ((a&0xE0) === 0xC0)
3268 ((b = src()) === null) && fail([a, b]),
3269 dst(((a&0x1F)<<6) | (b&0x3F));
3270 else if ((a&0xF0) === 0xE0)
3271 ((b=src()) === null || (c=src()) === null) && fail([a, b, c]),
3272 dst(((a&0x0F)<<12) | ((b&0x3F)<<6) | (c&0x3F));
3273 else if ((a&0xF8) === 0xF0)
3274 ((b=src()) === null || (c=src()) === null || (d=src()) === null) && fail([a, b, c ,d]),
3275 dst(((a&0x07)<<18) | ((b&0x3F)<<12) | ((c&0x3F)<<6) | (d&0x3F));
3276 else throw RangeError("Illegal starting byte: "+a);
3277 }
3278 };
3280 /**
3281 * Converts UTF16 characters to UTF8 code points.
3282 * @param {!function():number|null} src Characters source as a function returning the next char code respectively
3283 * `null` if there are no more characters left.
3284 * @param {!function(number)} dst Code points destination as a function successively called with each converted code
3285 * point.
3286 */
3287 utfx.UTF16toUTF8 = function(src, dst) {
3288 var c1, c2 = null;
3289 while (true) {
3290 if ((c1 = c2 !== null ? c2 : src()) === null)
3291 break;
3292 if (c1 >= 0xD800 && c1 <= 0xDFFF) {
3293 if ((c2 = src()) !== null) {
3294 if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
3295 dst((c1-0xD800)*0x400+c2-0xDC00+0x10000);
3296 c2 = null; continue;
3297 }
3298 }
3299 }
3300 dst(c1);
3301 }
3302 if (c2 !== null) dst(c2);
3303 };
3305 /**
3306 * Converts UTF8 code points to UTF16 characters.
3307 * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
3308 * respectively `null` if there are no more code points left or a single numeric code point.
3309 * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
3310 * @throws {RangeError} If a code point is out of range
3311 */
3312 utfx.UTF8toUTF16 = function(src, dst) {
3313 var cp = null;
3314 if (typeof src === 'number')
3315 cp = src, src = function() { return null; };
3316 while (cp !== null || (cp = src()) !== null) {
3317 if (cp <= 0xFFFF)
3318 dst(cp);
3319 else
3320 cp -= 0x10000,
3321 dst((cp>>10)+0xD800),
3322 dst((cp%0x400)+0xDC00);
3323 cp = null;
3324 }
3325 };
3327 /**
3328 * Converts and encodes UTF16 characters to UTF8 bytes.
3329 * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null`
3330 * if there are no more characters left.
3331 * @param {!function(number)} dst Bytes destination as a function successively called with the next byte.
3332 */
3333 utfx.encodeUTF16toUTF8 = function(src, dst) {
3334 utfx.UTF16toUTF8(src, function(cp) {
3335 utfx.encodeUTF8(cp, dst);
3336 });
3337 };
3339 /**
3340 * Decodes and converts UTF8 bytes to UTF16 characters.
3341 * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
3342 * are no more bytes left.
3343 * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
3344 * @throws {RangeError} If a starting byte is invalid in UTF8
3345 * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes.
3346 */
3347 utfx.decodeUTF8toUTF16 = function(src, dst) {
3348 utfx.decodeUTF8(src, function(cp) {
3349 utfx.UTF8toUTF16(cp, dst);
3350 });
3351 };
3353 /**
3354 * Calculates the byte length of an UTF8 code point.
3355 * @param {number} cp UTF8 code point
3356 * @returns {number} Byte length
3357 */
3358 utfx.calculateCodePoint = function(cp) {
3359 return (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
3360 };
3362 /**
3363 * Calculates the number of UTF8 bytes required to store UTF8 code points.
3364 * @param {(!function():number|null)} src Code points source as a function returning the next code point respectively
3365 * `null` if there are no more code points left.
3366 * @returns {number} The number of UTF8 bytes required
3367 */
3368 utfx.calculateUTF8 = function(src) {
3369 var cp, l=0;
3370 while ((cp = src()) !== null)
3371 l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
3372 return l;
3373 };
3375 /**
3376 * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes.
3377 * @param {(!function():number|null)} src Characters source as a function returning the next char code respectively
3378 * `null` if there are no more characters left.
3379 * @returns {!Array.<number>} The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1.
3380 */
3381 utfx.calculateUTF16asUTF8 = function(src) {
3382 var n=0, l=0;
3383 utfx.UTF16toUTF8(src, function(cp) {
3384 ++n; l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
3385 });
3386 return [n,l];
3387 };
3389 return utfx;
3390 }();
3392 // encodings/utf8
3394 /**
3395 * Encodes this ByteBuffer's contents between {@link ByteBuffer#offset} and {@link ByteBuffer#limit} to an UTF8 encoded
3396 * string.
3397 * @returns {string} Hex encoded string
3398 * @throws {RangeError} If `offset > limit`
3399 * @expose
3400 */
3401 ByteBufferPrototype.toUTF8 = function(begin, end) {
3402 if (typeof begin === 'undefined') begin = this.offset;
3403 if (typeof end === 'undefined') end = this.limit;
3404 if (!this.noAssert) {
3405 if (typeof begin !== 'number' || begin % 1 !== 0)
3406 throw TypeError("Illegal begin: Not an integer");
3407 begin >>>= 0;
3408 if (typeof end !== 'number' || end % 1 !== 0)
3409 throw TypeError("Illegal end: Not an integer");
3410 end >>>= 0;
3411 if (begin < 0 || begin > end || end > this.buffer.length)
3412 throw RangeError("Illegal range: 0 <= "+begin+" <= "+end+" <= "+this.buffer.length);
3413 }
3414 return this.buffer.toString("utf8", begin, end);
3415 };
3417 /**
3418 * Decodes an UTF8 encoded string to a ByteBuffer.
3419 * @param {string} str String to decode
3420 * @param {boolean=} littleEndian Whether to use little or big endian byte order. Defaults to
3421 * {@link ByteBuffer.DEFAULT_ENDIAN}.
3422 * @param {boolean=} noAssert Whether to skip assertions of offsets and values. Defaults to
3423 * {@link ByteBuffer.DEFAULT_NOASSERT}.
3424 * @returns {!ByteBuffer} ByteBuffer
3425 * @expose
3426 */
3427 ByteBuffer.fromUTF8 = function(str, littleEndian, noAssert) {
3428 if (!noAssert)
3429 if (typeof str !== 'string')
3430 throw TypeError("Illegal str: Not a string");
3431 var bb = new ByteBuffer(0, littleEndian, noAssert);
3432 bb.buffer = new Buffer(str, "utf8");
3433 bb.limit = bb.buffer.length;
3434 return bb;
3435 };
3438 /**
3439 * node-memcpy. This is an optional binding dependency and may not be present.
3440 * @function
3441 * @param {!(Buffer|ArrayBuffer|Uint8Array)} target Destination
3442 * @param {number|!(Buffer|ArrayBuffer)} targetStart Destination start, defaults to 0.
3443 * @param {(!(Buffer|ArrayBuffer|Uint8Array)|number)=} source Source
3444 * @param {number=} sourceStart Source start, defaults to 0.
3445 * @param {number=} sourceEnd Source end, defaults to capacity.
3446 * @returns {number} Number of bytes copied
3447 * @throws {Error} If any index is out of bounds
3448 * @expose
3449 */
3450 ByteBuffer.memcpy = memcpy;
3452 return ByteBuffer;
3454 })();