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
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {ArrayBuffer} arrayBuffer An array of buffers to be read from.
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_offset Offset to read bytes at.
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_length Number of bytes to read.
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) *
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in the file.
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} end Maximum position to read from.
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) *
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {DataView} dataView Data view instance.
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to read from.
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Read string.
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) *
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {DataView} dataView Data view instance.
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to read from.
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Read string.
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) *
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {DataView} dataView Data view instance.
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to read from.
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean} bom True if BOM should be parsed.
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Read string.
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) *
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {DataView} dataView Data view instance.
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to read from.
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Base 64 encoded value.
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) *
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {DataView} dataView Data view instance.
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to read from.
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Image as a data url.
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 = {
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    '\x89P' : 'png',
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    '\xFF\xD8' : 'jpeg',
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    'BM' : 'bmp',
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    '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) *
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {boolean} True if allowed, false otherwise.
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.canRead = function(size) {
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  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.
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {boolean} True if EOF, otherwise false.
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.
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {boolean} True if BOF, otherwise false.
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.
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {boolean} True if outside, false if inside.
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.
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} order Byte order. Either LITTLE_ENDIAN or BIG_ENDIAN.
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) *
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
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)/**
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} width Number of bytes to read.
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean=} opt_signed True if signed, false otherwise.
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Scalar value.
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) *
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} String value.
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) *
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Null-terminated string value.
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) *
3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean} bom True if BOM should be parsed.
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Read string.
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) *
4311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
4321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
4331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {function(new:Array.<*>)=} opt_arrayConstructor Array constructor.
4341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {Array.<*>} Array of bytes.
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) *
4551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Base 64 encoded value.
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) *
4711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} size Number of bytes to read.
4721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to read from.
4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {string} Image as a data url.
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) *
4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to seek to.
4851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_seekStart Relative position in bytes.
4861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_end Maximum position to seek to.
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) *
5121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number} pos Position in bytes to seek to.
5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {number=} opt_seekStart Relative position in bytes.
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.
5311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {number} Current position in bytes.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ByteReader.prototype.tell = function() {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this.pos_;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
536