15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict';
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {ArrayBuffer} arrayBuffer  // TODO(JSDOC).
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_offset  // TODO(JSDOC).
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_length  // TODO(JSDOC).
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function ByteReader(arrayBuffer, opt_offset, opt_length) {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  opt_offset = opt_offset || 0;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  opt_length = opt_length || (arrayBuffer.byteLength - opt_offset);
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.view_ = new DataView(arrayBuffer, opt_offset, opt_length);
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ = 0;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.seekStack_ = [];
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.setByteOrder(ByteReader.BIG_ENDIAN);
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static constants and methods.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Intel, 0x1234 is [0x34, 0x12]
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {number}
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ByteReader.LITTLE_ENDIAN = 0;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Motorola, 0x1234 is [0x12, 0x34]
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {number}
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ByteReader.BIG_ENDIAN = 1;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Seek relative to the beginning of the buffer.
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {number}
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ByteReader.SEEK_BEG = 0;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Seek relative to the current position.
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {number}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ByteReader.SEEK_CUR = 1;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Seek relative to the end of the buffer.
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {number}
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ByteReader.SEEK_END = 2;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Throw an error if (0 > pos >= end) or if (pos + size > end).
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Static utility function.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} end  // TODO(JSDOC).
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.validateRead = function(pos, size, end) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos < 0 || pos >= end)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    throw new Error('Invalid read position');
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos + size > end)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    throw new Error('Read past end of buffer');
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of characters, returning them as a single string.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is a static utility function.  There is a member function with the
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * same name which side-effects the current read position.
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {DataView} dataView  // TODO(JSDOC).
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.readString = function(dataView, pos, size, opt_end) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var codes = [];
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var i = 0; i < size; ++i)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    codes.push(dataView.getUint8(pos + i));
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return String.fromCharCode.apply(null, codes);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of characters, returning them as a single string.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is a static utility function.  There is a member function with the
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * same name which side-effects the current read position.
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {DataView} dataView  // TODO(JSDOC).
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.readNullTerminatedString = function(dataView, pos, size, opt_end) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var codes = [];
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var i = 0; i < size; ++i) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var code = dataView.getUint8(pos + i);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (code == 0) break;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    codes.push(code);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return String.fromCharCode.apply(null, codes);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of UTF16 characters, returning them as a single string.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is a static utility function.  There is a member function with the
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * same name which side-effects the current read position.
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {DataView} dataView  // TODO(JSDOC).
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean} bom  // TODO(JSDOC).
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.readNullTerminatedStringUTF16 = function(
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dataView, pos, bom, size, opt_end) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var littleEndian = false;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var start = 0;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bom) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    littleEndian = (dataView.getUint8(pos) == 0xFF);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start = 2;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var codes = [];
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var i = start; i < size; i += 2) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var code = dataView.getUint16(pos + i, littleEndian);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (code == 0) break;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    codes.push(code);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return String.fromCharCode.apply(null, codes);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @const
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @type {Array.<string>}
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.base64Alphabet_ =
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/').
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    split('');
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of bytes, returning them as a single base64 encoded
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * string.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is a static utility function.  There is a member function with the
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * same name which side-effects the current read position.
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {DataView} dataView  // TODO(JSDOC).
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.readBase64 = function(dataView, pos, size, opt_end) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteReader.validateRead(pos, size, opt_end || dataView.byteLength);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = [];
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var chars = [];
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var padding = 0;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var i = 0; i < size; /* incremented inside */) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var bits = dataView.getUint8(pos + (i++)) << 16;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i < size) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bits |= dataView.getUint8(pos + (i++)) << 8;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (i < size) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bits |= dataView.getUint8(pos + (i++));
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        padding = 1;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      padding = 2;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chars[3] = ByteReader.base64Alphabet_[bits & 63];
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chars[2] = ByteReader.base64Alphabet_[(bits >> 6) & 63];
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chars[1] = ByteReader.base64Alphabet_[(bits >> 12) & 63];
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chars[0] = ByteReader.base64Alphabet_[(bits >> 18) & 63];
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv.push.apply(rv, chars);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (padding > 0)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv[rv.length - 1] = '=';
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (padding > 1)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv[rv.length - 2] = '=';
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv.join('');
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as an image encoded in a data url.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is a static utility function.  There is a member function with the
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * same name which side-effects the current read position.
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {DataView} dataView  // TODO(JSDOC).
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.readImage = function(dataView, pos, size, opt_end) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  opt_end = opt_end || dataView.byteLength;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteReader.validateRead(pos, size, opt_end);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Two bytes is enough to identify the mime type.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var prefixToMime = {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     '\x89P' : 'png',
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     '\xFF\xD8' : 'jpeg',
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     'BM' : 'bmp',
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     'GI' : 'gif'
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var prefix = ByteReader.readString(dataView, pos, 2, opt_end);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var mime = prefixToMime[prefix] ||
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dataView.getUint16(pos, false).toString(16);  // For debugging.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var b64 = ByteReader.readBase64(dataView, pos, size, opt_end);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 'data:image/' + mime + ';base64,' + b64;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Instance methods.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return true if the requested number of bytes can be read from the buffer.
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean}  // TODO(JSDOC).
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.canRead = function(size) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   return this.pos_ + size <= this.view_.byteLength;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return true if the current position is past the end of the buffer.
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean}  // TODO(JSDOC).
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.eof = function() {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.pos_ >= this.view_.byteLength;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return true if the current position is before the beginning of the buffer.
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean}  // TODO(JSDOC).
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.bof = function() {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.pos_ < 0;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return true if the current position is outside the buffer.
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean}  // TODO(JSDOC).
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.beof = function() {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.pos_ >= this.view_.byteLength || this.pos_ < 0;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Set the expected byte ordering for future reads.
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} order  // TODO(JSDOC).
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.setByteOrder = function(order) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.littleEndian_ = order == ByteReader.LITTLE_ENDIAN;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Throw an error if the reader is at an invalid position, or if a read a read
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of |size| would put it in one.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may optionally pass opt_end to override what is considered to be the
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * end of the buffer.
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.validateRead = function(size, opt_end) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (typeof opt_end == 'undefined')
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    opt_end = this.view_.byteLength;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ByteReader.validateRead(this.view_, this.pos_, size, opt_end);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} width  // TODO(JSDOC).
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean=} opt_signed  // TODO(JSDOC).
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readScalar = function(width, opt_signed, opt_end) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var method = opt_signed ? 'getInt' : 'getUint';
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (width) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 1:
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method += '8';
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 2:
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method += '16';
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 4:
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method += '32';
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 8:
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method += '64';
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      throw new Error('Invalid width: ' + width);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.validateRead(width, opt_end);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = this.view_[method](this.pos_, this.littleEndian_);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += width;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of characters, returning them as a single string.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Adjusts the current position on success.  Throws an exception if the
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read would go past the end of the buffer.
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readString = function(size, opt_end) {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = ByteReader.readString(this.view_, this.pos_, size, opt_end);
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += size;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of characters, returning them as a single string.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Adjusts the current position on success.  Throws an exception if the
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read would go past the end of the buffer.
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readNullTerminatedString = function(size, opt_end) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = ByteReader.readNullTerminatedString(this.view_,
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               this.pos_,
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               size,
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               opt_end);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += rv.length;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv.length < size) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we've stopped reading because we found '0' but didn't hit size limit
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // then we should skip additional '0' character
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.pos_++;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of UTF16 characters, returning them as a single string.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Adjusts the current position on success.  Throws an exception if the
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read would go past the end of the buffer.
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean} bom  // TODO(JSDOC).
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readNullTerminatedStringUTF16 =
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function(bom, size, opt_end) {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = ByteReader.readNullTerminatedStringUTF16(
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.view_, this.pos_, bom, size, opt_end);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bom) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the BOM word was present advance the position.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.pos_ += 2;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += rv.length;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv.length < size) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we've stopped reading because we found '0' but didn't hit size limit
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // then we should skip additional '0' character
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.pos_ += 2;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as an array of numbers.
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Adjusts the current position on success.  Throws an exception if the
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read would go past the end of the buffer.
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function(new:Array.<*>)=} opt_arrayConstructor  // TODO(JSDOC).
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Array.<*>}  // TODO(JSDOC).
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readSlice = function(size, opt_end,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          opt_arrayConstructor) {
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.validateRead(size, opt_end);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var arrayConstructor = opt_arrayConstructor || Uint8Array;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var slice = new arrayConstructor(
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.view_.buffer, this.view_.byteOffset + this.pos, size);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += size;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return slice;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read as a sequence of bytes, returning them as a single base64 encoded
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * string.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Adjusts the current position on success.  Throws an exception if the
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read would go past the end of the buffer.
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readBase64 = function(size, opt_end) {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = ByteReader.readBase64(this.view_, this.pos_, size, opt_end);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += size;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Read an image returning it as a data url.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Adjusts the current position on success.  Throws an exception if the
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read would go past the end of the buffer.
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} size  // TODO(JSDOC).
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string}  // TODO(JSDOC).
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.readImage = function(size, opt_end) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var rv = ByteReader.readImage(this.view_, this.pos_, size, opt_end);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ += size;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Seek to a give position relative to opt_seekStart.
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_seekStart  // TODO(JSDOC).
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_end  // TODO(JSDOC).
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.seek = function(pos, opt_seekStart, opt_end) {
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  opt_end = opt_end || this.view_.byteLength;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var newPos;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (opt_seekStart == ByteReader.SEEK_CUR) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    newPos = this.pos_ + pos;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (opt_seekStart == ByteReader.SEEK_END) {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    newPos = opt_end + pos;
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    newPos = pos;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (newPos < 0 || newPos > this.view_.byteLength)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    throw new Error('Seek outside of buffer: ' + (newPos - opt_end));
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.pos_ = newPos;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Seek to a given position relative to opt_seekStart, saving the current
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * position.
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Recover the current position with a call to seekPop.
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} pos  // TODO(JSDOC).
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_seekStart  // TODO(JSDOC).
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.pushSeek = function(pos, opt_seekStart) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var oldPos = this.pos_;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.seek(pos, opt_seekStart);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Alter the seekStack_ after the call to seek(), in case it throws.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.seekStack_.push(oldPos);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Undo a previous seekPush.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.popSeek = function() {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.seek(this.seekStack_.pop());
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return the current read position.
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {number}  // TODO(JSDOC).
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.tell = function() {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.pos_;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
536