1/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ 2/* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 5/* jshint esnext: true, moz: true */ 6 7"use strict"; 8 9var EXPORTED_SYMBOLS = ["DataReader"]; 10 11class DataReader { 12 // `data` is `Uint8Array` 13 constructor(data, startByte = 0) { 14 this._data = data; 15 this._cursor = startByte; 16 } 17 18 get buffer() { 19 return this._data.buffer; 20 } 21 22 get data() { 23 return this._data; 24 } 25 26 get eof() { 27 return this._cursor >= this._data.length; 28 } 29 30 getBytes(length = 1) { 31 if (!length) { 32 return new Uint8Array(); 33 } 34 35 let end = this._cursor + length; 36 if (end > this._data.length) { 37 return new Uint8Array(); 38 } 39 40 let uint8Array = new Uint8Array(this.buffer.slice(this._cursor, end)); 41 this._cursor += length; 42 43 return uint8Array; 44 } 45 46 getString(length) { 47 let uint8Array = this.getBytes(length); 48 return _uint8ArrayToString(uint8Array); 49 } 50 51 getValue(length) { 52 let uint8Array = this.getBytes(length); 53 return _uint8ArrayToValue(uint8Array); 54 } 55 56 getLabel(decompressData) { 57 let parts = []; 58 let partLength; 59 60 while ((partLength = this.getValue(1))) { 61 // If a length has been specified instead of a pointer, 62 // read the string of the specified length. 63 if (partLength !== 0xc0) { 64 parts.push(this.getString(partLength)); 65 continue; 66 } 67 68 // TODO: Handle case where we have a pointer to the label 69 parts.push(String.fromCharCode(0xc0) + this.getString(1)); 70 break; 71 } 72 73 let label = parts.join("."); 74 75 return _decompressLabel(label, decompressData || this._data); 76 } 77} 78 79/** 80 * @private 81 */ 82function _uint8ArrayToValue(uint8Array) { 83 let length = uint8Array.length; 84 if (length === 0) { 85 return null; 86 } 87 88 let value = 0; 89 for (let i = 0; i < length; i++) { 90 value = value << 8; 91 value += uint8Array[i]; 92 } 93 94 return value; 95} 96 97/** 98 * @private 99 */ 100function _uint8ArrayToString(uint8Array) { 101 let length = uint8Array.length; 102 if (length === 0) { 103 return ""; 104 } 105 106 let results = []; 107 for (let i = 0; i < length; i += 1024) { 108 results.push( 109 String.fromCharCode.apply(null, uint8Array.subarray(i, i + 1024)) 110 ); 111 } 112 113 return results.join(""); 114} 115 116/** 117 * @private 118 */ 119function _decompressLabel(label, decompressData) { 120 let result = ""; 121 122 for (let i = 0, length = label.length; i < length; i++) { 123 if (label.charCodeAt(i) !== 0xc0) { 124 result += label.charAt(i); 125 continue; 126 } 127 128 i++; 129 130 let reader = new DataReader(decompressData, label.charCodeAt(i)); 131 result += _decompressLabel(reader.getLabel(), decompressData); 132 } 133 134 return result; 135} 136