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