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