diff --git a/_cache_service_worker.js b/_cache_service_worker.js
index fce3417..efe9ed6 100644
--- a/_cache_service_worker.js
+++ b/_cache_service_worker.js
@@ -12,7 +12,7 @@ limitations under the License.
mod by marcrobledo, original from: https://github.com/GoogleChrome/samples/blob/gh-pages/service-worker/basic/service-worker.js
*/
-const PRECACHE_ID='v20180830';
+const PRECACHE_ID='v20180918';
const PRECACHE_FILES=[
'index.html','./',
'RomPatcher.css',
diff --git a/index.html b/index.html
index 46bdaf2..86dbd84 100644
--- a/index.html
+++ b/index.html
@@ -16,8 +16,7 @@
-
-
+
@@ -54,7 +53,7 @@
-
+
@@ -104,7 +103,8 @@
diff --git a/xdelta.js b/xdelta.js
new file mode 100644
index 0000000..0c1e7b8
--- /dev/null
+++ b/xdelta.js
@@ -0,0 +1,973 @@
+/* xdelta3 module for RomPatcher.js v20180918 - Marc Robledo 2016-2018 - http://www.marcrobledo.com/license */
+
+var XDELTA_MAGIC=0xd6c3c400;
+
+function XDelta(patchData){
+ this.patchData=patchData;
+}
+XDelta.prototype.toString=function(){
+ return ''
+}
+
+/* code borrowed from https://github.com/google/xdelta3-decoder-js/blob/master/tests/testA.html */
+XDelta.prototype.apply=function(romFile){
+ var target;
+ try{
+ target=XDelta3Decoder.decode(this.patchData, new Uint8Array(romFile.fileReader.result));
+ }catch(e){
+ alert('EXCEPTION: ' + e.message);
+ return false;
+ }
+
+ var tempFile=new MarcBinFile(target.byteLength);
+ var targetUint8Array=new Uint8Array(target);
+ for(var i=0; i
0) {
+ this.acache.near_array = allocArray(this.acache.s_near, 0);
+ }
+ if (this.acache.s_same > 0) {
+ this.acache.same_array = allocArray(this.acache.s_same * 256, 0);
+ }
+ };
+
+ /**
+ * Parses the delta file data and produces the targetWindow data.
+ * @return {!Uint8Array}
+ */
+ _XDelta3Decoder.prototype.xd3_decode_input = function() {
+
+ if (this.delta[0] != 0xD6 || // 'V' with MSB set
+ this.delta[1] != 0xC3 || // 'C' with MSB set
+ this.delta[2] != 0xC4 || // 'D' with MSB set
+ this.delta[3] != 0) { // unused but be set to zero
+ throw new Error('XD3_INVALID_INPUT invalid magic');
+ }
+ this.position = 4;
+
+ this.dec_hdr_ind = this.delta[this.position++];
+ if (this.dec_hdr_ind & VCD_INVHDR) {
+ throw new Error('VCD_INVHDR unrecognized header indicator bits set');
+ }
+
+ if (this.dec_hdr_ind & VCD_SECONDARY) {
+ throw new Error('VCD_SECONDARY not implemented');
+ }
+
+ if (this.dec_hdr_ind & VCD_CODETABLE) {
+ throw new Error('VCD_CODETABLE support was removed');
+ } else {
+ /* Use the default table. */
+ this.acache.s_near = __rfc3284_code_table_desc.near_modes;
+ this.acache.s_same = __rfc3284_code_table_desc.same_modes;
+ this.code_table = xd3_rfc3284_code_table();
+ }
+
+ this.xd3_alloc_cache();
+
+ if (this.dec_hdr_ind & VCD_APPHEADER) {
+ this.dec_appheadsz = this.getInteger();
+ // Note: appHeader does not have a 0-termination.
+ this.dec_apphead = this.xd3_alloc(this.dec_appheadsz + 1);
+ this.xd3_decode_bytes(this.dec_apphead, 0, this.dec_appheadsz);
+ this.dec_apphead[this.dec_appheadsz + 1] = 0;
+ }
+
+ //var targetLength = 0;
+ while (true) {
+ if (this.position >= this.delta.length) {
+ break;
+ }
+ //targetLength +=
+ this.handleWindow();
+ }
+ return this.dec_buffer.bytes;
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_init_window = function() {
+ this.dec_cpylen = 0;
+ this.dec_cpyoff = 0;
+ // this.dec_cksumbytes = 0;
+
+ xd3_init_cache(this.acache);
+ }
+
+ _XDelta3Decoder.prototype.handleWindow = function() {
+ this.dec_win_ind = this.delta[this.position++]; // DEC_WININD
+
+ if (this.dec_win_ind & ~7) {
+ throw new Error('VCD_INVWIN unexpected bits set');
+ }
+
+ this.current_window = this.dec_window_count;
+
+ this.dec_winstart += this.dec_tgtlen;
+
+ this.xd3_decode_init_window();
+ var SRCORTGT = VCD_SOURCE | VCD_TARGET;
+ var srcortgt = SRCORTGT & this.dec_win_ind;
+
+ // If using a source or target data segment: read the lenght and position
+ // integers.
+ if (srcortgt) {
+ this.dec_cpylen = this.getInteger(); // DEC_CPYLEN
+ }
+ this.dec_position = this.dec_cpylen;
+ if (srcortgt) {
+ var sourcePosition = this.getInteger(); // DEC_CPYOFF
+ this.dec_cpyoff = sourcePosition;
+ }
+
+ this.dec_enclen = this.getInteger(); // DEC_ENCLEN
+
+ // Calculate the position if the delta was actually read.
+ // var positionAfterDelta = this.position + this.dec_enclen;
+
+ // Get the target window length.
+ this.dec_tgtlen = this.getInteger(); // DEC_TGTLEN
+
+ this.dec_del_ind = this.getByte(); // DEC_DELIND
+
+ this.data_sect.size = this.getInteger(); // DEC_DATALEN
+ this.inst_sect.size = this.getInteger(); // DEC_INSTLEN
+ this.addr_sect.size = this.getInteger(); // DEC_ADDRLEN
+
+ if (this.dec_win_ind & VCD_ADLER32) { // DEC_CKSUM
+ this.dec_cksum = this.xd3_decode_allocate(4);
+ for (var i = 0; i < 4; i += 1) {
+ this.dec_adler32 = (this.dec_adler32 << 8) | this.dec_cksum[i];
+ }
+ }
+
+ this.xd3_decode_sections();
+
+ /* In the C++ code:
+ * To speed VCD_SOURCE block-address calculations, the source
+ * cpyoff_blocks and cpyoff_blkoff are pre-computed.
+ * However, in this Javascript code there is no 'blocks'.
+ */
+ if (this.dec_win_ind & VCD_SOURCE) {
+ this.src.cpyoff_blkoff = this.dec_cpyoff;
+ }
+ this.xd3_decode_emit();
+
+ return this.dec_tgtlen;
+ };
+
+ /**
+ * This function only has code if the preprocessor statement
+ * "#if SECONDARY_ANY" is set. SECONDARY_ANY does not seem to be set.
+ */
+ _XDelta3Decoder.prototype.xd3_decode_secondary_sections = function() { //
+ };
+
+ /**
+ * @param {!xd3_desect} sect
+ */
+ _XDelta3Decoder.prototype.xd3_decode_section = function(sect) {
+ // It is possible to just point into the buffer but perhaps that can be done
+ // later.
+ sect.bytes = this.xd3_decode_allocate(sect.size);
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_sections = function() {
+ this.xd3_decode_section(this.data_sect);
+ this.xd3_decode_section(this.inst_sect);
+ this.xd3_decode_section(this.addr_sect);
+
+ this.xd3_decode_secondary_sections();
+
+ this.xd3_decode_setup_buffers();
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_setup_buffers = function() {
+ this.dec_buffer = new DataObject(new Uint8Array(this.dec_tgtlen));
+ };
+
+ var VCD_SELF = 0;
+ var VCD_HERE = 1;
+
+ /**
+ * xd3_decode_address
+ * @param {number} here
+ * @param {number} mode
+ * @param {!xd3_desect} sect
+ */
+ _XDelta3Decoder.prototype.xd3_decode_address = function(here, mode, sect) {
+ var val;
+ var same_start = 2 + this.acache.s_near;
+
+ if (mode < same_start) {
+ val = sect.getInteger();
+ switch (mode) {
+ case VCD_SELF:
+ break;
+ case VCD_HERE:
+ // var old_val = val;
+ val = here - val;
+ break;
+ default:
+ val += this.acache.near_array[mode - 2];
+ }
+ } else {
+ mode -= same_start;
+ var offset = sect.getByte();
+ val = this.acache.same_array[mode * 256 + offset];
+ }
+
+ this.xd3_update_cache(this.acache, val);
+
+ return val;
+ };
+
+ /**
+ * @param {!xd3_addr_cache} acache
+ * @param {number} addr
+ */
+ _XDelta3Decoder.prototype.xd3_update_cache = function(acache, addr) {
+ if (acache.s_near > 0) {
+ acache.near_array[acache.next_slot] = addr;
+ acache.next_slot = (acache.next_slot + 1) % acache.s_near;
+ }
+
+ if (acache.s_same > 0) {
+ acache.same_array[addr % (acache.s_same * 256)] = addr;
+ }
+ };
+
+ /**
+ * @param {!xd3_hinst} inst
+ */
+ _XDelta3Decoder.prototype.xd3_decode_output_halfinst = function(inst) {
+ var take = inst.size;
+ var blkoff;
+
+ switch (inst.type) {
+ case XD3_RUN:
+ var val = this.data_sect.getByte();
+ this.dec_buffer.fill(val, take);
+ break;
+
+ case XD3_ADD:
+ this.dec_buffer.copySect(this.data_sect, take);
+ break;
+
+ default:
+ var overlap;
+ var overlap_pos;
+ if (inst.addr < this.dec_cpylen) {
+ overlap = 0;
+ if (this.dec_win_ind & VCD_TARGET) {
+ throw new Error('VCD_TARGET not supported');
+ } else {
+ blkoff = this.src.cpyoff_blkoff;
+ blkoff = this.dec_cpyoff + inst.addr;
+ }
+ } else {
+ overlap = 1;
+ overlap_pos = inst.addr - this.dec_cpylen;
+ }
+ if (overlap) {
+ this.dec_buffer.copyBytes(this.dec_buffer.bytes, overlap_pos, take);
+ } else {
+ this.dec_buffer.copyBytes(this.source.bytes, blkoff, take);
+ }
+ }
+ };
+
+ /**
+ * xref: xd3_decode_parse_halfinst
+ * @param {!xd3_hinst} inst
+ */
+ _XDelta3Decoder.prototype.xd3_decode_parse_halfinst = function(inst) {
+ // Get size and address if necessary.
+ if (inst.size == 0) {
+ inst.size = this.inst_sect.getInteger();
+ }
+
+ /* For copy instructions, read address. */
+ if (inst.type >= XD3_CPY) {
+ var mode = inst.type - XD3_CPY;
+ inst.addr =
+ this.xd3_decode_address(this.dec_position, mode, this.addr_sect);
+ }
+
+ this.dec_position += inst.size;
+ };
+
+ /**
+ * xref: xd3_decode_instruction
+ */
+ _XDelta3Decoder.prototype.xd3_decode_instruction = function() {
+ var code_table = this.code_table;
+ var instPair = this.inst_sect.getByte();
+
+ this.dec_current1.type = code_table.tableRows[instPair].type1;
+ this.dec_current1.size = code_table.tableRows[instPair].size1;
+ // dec_current1.addr keeps it previous value.
+
+ this.dec_current2.type = code_table.tableRows[instPair].type2;
+ this.dec_current2.size = code_table.tableRows[instPair].size2;
+ // dec_current2.addr keeps it previous value.
+
+
+ /* For each instruction with a real operation, decode the
+ * corresponding size and addresses if necessary. Assume a
+ * code-table may have NOOP in either position, although this is
+ * unlikely. */
+ if (this.dec_current1.type != XD3_NOOP) {
+ this.xd3_decode_parse_halfinst(this.dec_current1);
+ }
+ if (this.dec_current2.type != XD3_NOOP) {
+ this.xd3_decode_parse_halfinst(this.dec_current2);
+ }
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_finish_window = function() {
+ // stream->dec_winbytes = 0;
+ // stream->dec_state = DEC_FINISH;
+ this.data_sect.pos = 0;
+ this.inst_sect.pos = 0;
+ this.addr_sect.pos = 0;
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_emit = function() {
+
+ var instLength = this.inst_sect.bytes.byteLength;
+ /* Decode next instruction pair. */
+ while (this.inst_sect.pos < instLength) {
+ this.xd3_decode_instruction();
+
+ /* Output dec_current1 */
+ if (this.dec_current1.type != XD3_NOOP) {
+ this.xd3_decode_output_halfinst(this.dec_current1);
+ }
+ /* Output dec_current2 */
+ if (this.dec_current2.type != XD3_NOOP) {
+ this.xd3_decode_output_halfinst(this.dec_current2);
+ }
+ }
+ if (this.dec_win_ind & VCD_ADLER32) {
+ var a32 = adler32(1, this.dec_buffer.bytes, 0, this.dec_tgtlen);
+ if (a32 != this.dec_adler32) {
+ throw new Error('target window checksum mismatch');
+ }
+ }
+
+ /* Finished with a window. */
+ this.xd3_decode_finish_window();
+ };
+
+ _XDelta3Decoder.prototype.xd3_alloc = function(length) {
+ return new Uint8Array(length);
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_bytes = function(bytes, pos, length) {
+ for (var i = 0; i < length; i++) {
+ bytes[pos + i] = this.delta[this.position++];
+ }
+ };
+
+ _XDelta3Decoder.prototype.xd3_decode_allocate = function(length) {
+ var bytes =
+ new Uint8Array(this.delta.slice(this.position, this.position + length));
+ this.position += length;
+ return bytes;
+ };
+
+ _XDelta3Decoder.prototype.getByte = function() {
+ return this.delta[this.position++];
+ };
+
+ _XDelta3Decoder.prototype.getInteger = function() {
+ var maxBytes = Math.min(20, this.delta.length - this.position);
+ var integer = 0;
+ for (var i = 0; i < maxBytes; i++) {
+ var aPart = this.delta[this.position++];
+ integer += aPart & 0x7F;
+ if (!(aPart & 0x80)) {
+ return integer;
+ }
+ integer <<= 7;
+ }
+ throw new Error('delta integer too long');
+ };
+
+ /**
+ * The code table.
+ * @param {!Array} tableRows
+ * @constructor
+ * @struct
+ */
+ var xd3_dinst_table = function(tableRows) {
+ /** @type {!Array} */
+ this.tableRows = tableRows;
+ };
+
+ /**
+ * xd3_hinst
+ * @constructor
+ */
+ function xd3_hinst() {
+ this.type = XD3_NOOP;
+ this.size = 0;
+ this.addr = 0;
+ }
+
+ /**
+ * The code-table double instruction.
+ * @constructor
+ */
+ function xd3_dinst() {
+ /** @type {number} */
+ this.type1 = XD3_NOOP;
+ /** @type {number} */
+ this.size1 = 0;
+ /** @type {number} */
+ this.type2 = XD3_NOOP;
+ /** @type {number} */
+ this.size2 = 0;
+ }
+
+ /**
+ * @param {!xd3_code_table_desc} desc
+ * @return {!xd3_dinst_table}
+ */
+ function xd3_build_code_table(desc) {
+ var row = 0;
+ var tableRows = new Array(256);
+ for (var i = 0; i < 256; i++) {
+ tableRows[i] = new xd3_dinst();
+ }
+ var cpyModes = 2 + desc.near_modes + desc.same_modes;
+
+ // The single RUN command.
+ tableRows[row++].type1 = XD3_RUN;
+
+ // The ADD only commands.
+ tableRows[row++].type1 = XD3_ADD;
+ for (var size1 = 1; size1 <= desc.add_sizes; size1++) {
+ tableRows[row].type1 = XD3_ADD;
+ tableRows[row++].size1 = size1;
+ }
+
+ // The Copy only commands.
+ for (var mode = 0; mode < cpyModes; mode++) {
+ tableRows[row++].type1 = XD3_CPY + mode;
+
+ for (var size1 = MIN_MATCH; size1 < MIN_MATCH + desc.cpy_sizes; size1++) {
+ tableRows[row].type1 = XD3_CPY + mode;
+ tableRows[row++].size1 = size1;
+ }
+ }
+
+ // The Add/Copy commands.
+ for (var mode = 0; mode < cpyModes; mode++) {
+ for (var size1 = 1; size1 <= desc.addcopy_add_max; size1++) {
+ var max = (mode < 2 + desc.near_modes) ? //
+ desc.addcopy_near_cpy_max :
+ desc.addcopy_same_cpy_max;
+ for (var size2 = MIN_MATCH; size2 <= max; size2++) {
+ tableRows[row].type1 = XD3_ADD;
+ tableRows[row].size1 = size1;
+ tableRows[row].type2 = XD3_CPY + mode;
+ tableRows[row++].size2 = size2;
+ }
+ }
+ }
+
+ // The Copy/Add commands.
+ for (var mode = 0; mode < cpyModes; mode++) {
+ var max = (mode < 2 + desc.near_modes) ? //
+ desc.copyadd_near_cpy_max :
+ desc.copyadd_same_cpy_max;
+ for (var size1 = MIN_MATCH; size1 <= max; size1++) {
+ for (var size2 = 1; size2 <= desc.copyadd_add_max; size2++) {
+ tableRows[row].type1 = XD3_CPY + mode;
+ tableRows[row].size1 = size1;
+ tableRows[row].type2 = XD3_ADD;
+ tableRows[row++].size2 = size2;
+ }
+ }
+ }
+
+ return new xd3_dinst_table(tableRows);
+ }
+
+
+ /**
+ * @constructor
+ */
+ function xd3_code_table_desc() {
+ this.add_sizes = 0;
+ this.near_modes = 0;
+ this.same_modes = 0;
+ this.cpy_sizes = 0;
+
+ this.addcopy_add_max = 0;
+ this.addcopy_near_cpy_max = 0;
+ this.addcopy_same_cpy_max = 0;
+
+ this.copyadd_add_max = 0;
+ this.copyadd_near_cpy_max = 0;
+ this.copyadd_same_cpy_max = 0;
+ }
+
+
+ /**
+ * This builds the __rfc3284_code_table_desc
+ * Assumes a single RUN instruction
+ * Assumes that MIN_MATCH is 4.
+ * @return {!xd3_code_table_desc}
+ */
+ function build_rfc3284_code_table_desc() {
+ var desc = new xd3_code_table_desc();
+ desc.add_sizes = 17;
+ desc.near_modes = 4;
+ desc.same_modes = 3;
+ desc.cpy_sizes = 15;
+
+ desc.addcopy_add_max = 4;
+ desc.addcopy_near_cpy_max = 6;
+ desc.addcopy_same_cpy_max = 4;
+
+ desc.copyadd_add_max = 1;
+ desc.copyadd_near_cpy_max = 4;
+ desc.copyadd_same_cpy_max = 4;
+
+ // xd3_code_table_sizes addcopy_max_sizes[MAX_MODES];
+ // { {6,163,3},{6,175,3},{6,187,3},{6,199,3},{6,211,3},{6,223,3},
+ // {4,235,1},{4,239,1},{4,243,1} },
+
+ // xd3_code_table_sizes copyadd_max_sizes[MAX_MODES];
+ // { {4,247,1},{4,248,1},{4,249,1},{4,250,1},{4,251,1},{4,252,1},
+ // {4,253,1},{4,254,1},{4,255,1} },
+
+ return desc;
+ }
+
+ var __rfc3284_code_table_desc = build_rfc3284_code_table_desc();
+
+ var A32_BASE = 65521; /* Largest prime smaller than 2^16 */
+ var A32_NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2
+ + (n+1)(BASE-1) <= 2^32-1 */
+
+ // 1140 #define A32_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+ // 1141 #define A32_DO2(buf,i) A32_DO1(buf,i); A32_DO1(buf,i+1);
+ // 1142 #define A32_DO4(buf,i) A32_DO2(buf,i); A32_DO2(buf,i+2);
+ // 1143 #define A32_DO8(buf,i) A32_DO4(buf,i); A32_DO4(buf,i+4);
+ // 1144 #define A32_DO16(buf) A32_DO8(buf,0); A32_DO8(buf,8);
+
+
+ /**
+ * Calculated the Adler32 checksum.
+ * @param {number} adler I'm not sure what this is.
+ * @param {!Uint8Array} buf
+ * @param {number} pos
+ * @param {number} len
+ * @return {number}
+ */
+ function adler32(adler, buf, pos, len) {
+ var s1 = adler & 0xffff;
+ var s2 = (adler >> 16) & 0xffff;
+ var k;
+
+ while (len > 0) {
+ k = (len < A32_NMAX) ? len : A32_NMAX;
+ len -= k;
+
+ if (k != 0) {
+ do {
+ s1 += buf[pos++];
+ s2 += s1;
+ } while (--k);
+ }
+
+ s1 %= A32_BASE;
+ s2 %= A32_BASE;
+ }
+
+ return (s2 << 16) | s1;
+ }
+
+
+ /**
+ * @constructor
+ */
+ function xd3_addr_cache(s_near, s_same) {
+ this.s_near = s_near;
+ this.s_same = s_same;
+ this.next_slot = 0; /* the circular index for near */
+ this.near_array = null; /* array of size s_near */
+ this.same_array = null; /* array of size s_same*256 */
+ }
+
+
+ /**
+ * @param {!xd3_addr_cache} acache
+ */
+ function xd3_init_cache(acache) {
+ if (acache.s_near > 0) {
+ for (var i = 0; i < acache.near_array.length; i++) {
+ acache.near_array[i] = 0;
+ }
+ acache.next_slot = 0;
+ }
+
+ if (acache.s_same > 0) {
+ for (var i = 0; i < acache.same_array.length; i++) {
+ acache.same_array[i] = 0;
+ }
+ }
+ }
+
+ /**
+ * Used by the decoder to buffer input in sections.
+ * XDelta3 C++ struct.
+ * @constructor
+ * @struct
+ */
+ function xd3_desect() {
+ /**
+ * The buffer as a slice of the backingBuffer;
+ * @type {?Uint8Array}
+ */
+ this.bytes = null;
+
+ /** @type {number} */
+ this.size = 0;
+
+ /** @type {number} */
+ this.pos = 0;
+ }
+
+ /**
+ * Gets a byte from the section.
+ * @return {number}
+ */
+ xd3_desect.prototype.getByte = function() {
+ if (!this.bytes) {
+ throw new Error('bytes not set');
+ }
+ return this.bytes[this.pos++];
+ };
+
+ /**
+ * Gets an integer from the section.
+ * XDelta3 integers are encodes as a variable number of 7 bit bytes. Bit 8, the
+ * most significant bit is used to indicate more bytes needed.
+ * @return {number}
+ */
+ xd3_desect.prototype.getInteger = function() {
+ if (!this.bytes) {
+ throw new Error('bytes not set');
+ }
+ var val = 0;
+ for (var i = 0; i < 10; i++) {
+ var aByte = this.bytes[this.pos++];
+ val += aByte & 0x7F;
+ if (!(aByte & 0x80)) {
+ return val;
+ }
+ val <<= 7;
+ }
+ throw new Error('invalid number');
+ };
+
+
+ /**
+ * Builds a default code table.
+ * @return {!xd3_dinst_table}
+ */
+ function xd3_rfc3284_code_table() {
+ return xd3_build_code_table(__rfc3284_code_table_desc);
+ }
+
+ /**
+ * Allocates and initializes a Javascript Array.
+ * @return {!Array}
+ */
+ function allocArray(len, val) {
+ var arr = new Array(len);
+ for (var i = 0; i < len; i++) {
+ arr[i] = val;
+ }
+ return arr;
+ }
+
+ /**
+ * @constructor
+ */
+ function xd3_source() {
+ /** @type {number} */
+ this.cpyoff_blkoff = -1;
+ }
+
+ /**
+ * @param {!Uint8Array} bytes
+ * @constructor
+ */
+ function DataObject(bytes) {
+ this.pos = 0;
+ this.bytes = bytes;
+ };
+
+ DataObject.prototype.getByte = function() {
+ return this.bytes[this.pos++];
+ };
+
+ DataObject.prototype.getInteger = function() {
+ var val = 0;
+ for (var i = 0; i < 10; i++) {
+ var aByte = this.bytes[this.pos++];
+ val += aByte & 0x7F;
+ if (!(aByte & 0x80)) {
+ return val;
+ }
+ val <<= 7;
+ }
+ throw new Error('invalid number');
+ };
+
+ DataObject.prototype.fill = function(val, length) {
+ // TODO(bstell): see if there is a function for this.
+ for (var i = 0; i < length; i++) {
+ this.bytes[this.pos++] = val;
+ }
+ };
+
+ /**
+ * @param {!xd3_desect} sect
+ * @param {number} length
+ */
+ DataObject.prototype.copySect = function(sect, length) {
+ // TODO(bstell): see if there is a function for this.
+ for (var i = 0; i < length; i++) {
+ this.bytes[this.pos++] = sect.bytes[sect.pos++];
+ }
+ };
+
+ DataObject.prototype.copyBytes = function(bytes, offset, length) {
+ // TODO(bstell): see if there is a function for this.
+ for (var i = 0; i < length; i++) {
+ this.bytes[this.pos++] = bytes[offset++];
+ }
+ };
+
+})();