├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── edit_warning.txt
├── strip_xdelta3_decoder.sh
├── tests
├── debug.js
├── misc.js
├── style.css
├── testA.html
├── testA
│ ├── A.delta
│ ├── A.expectedTarget
│ └── A.source
├── testB.html
├── testB
│ ├── B.delta
│ └── B.expectedTarget
├── testC.html
├── testC
│ ├── C.delta
│ └── C.expectedTarget
├── testD.html
├── testD
│ ├── D.delta
│ ├── D.expectedTarget
│ └── D.source
├── testE.html
└── testE
│ ├── E.delta
│ ├── E.expectedTarget
│ └── E.source
├── xdelta3-decode_with_debug.h
├── xdelta3_decoder.js
├── xdelta3_decoder_with_debug.js
└── xdelta3_with_debug.c
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution,
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult [GitHub Help] for more
22 | information on using pull requests.
23 |
24 | [GitHub Help]: https://help.github.com/articles/about-pull-requests/
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This code is in a very rough state.
2 |
3 | This is a Javascript port of XDelta3 C++ decoder.
4 | See the XDelta3 website for infomation on XDelta3: http://xdelta.org/
5 |
6 | XDelta3 is written in C and can compress, make diffs, and decode (re-expand)
7 | binary as well as text files. As a file compressor XDelta3 deltas are slightly
8 | larger than the same file compressed with gzip. However, depending on the data,
9 | XDelta3 diffs can be dramatically smaller than the compressed files.
10 |
11 | This port to Javascript only implements the decoder. To use this Javacript code
12 | use the XDelta3 C code to diff or compress files and use this Javascript code to
13 | decode the files in the browser.
14 |
15 | This port was done by adding print statements to the C code and then making the
16 | Javascript mirror the C code. When decoding files the outputs of the C and
17 | Javascript code should be identical. Meld is a useful tool for comparing the 2
18 | print outputs. The debug\_save() routine can be used to save the Javascript
19 | print outputs without the console line numbers.
20 |
21 | To make changes to this code:
22 |
23 | 1. compile the XDelta C code using the C files with the print statements
24 | 1. decode a test file using the C code and save the print statements in a file
25 | 1. modify the xdelta3\_decoder\_with\_debug.js
26 | 1. decode the same test file in the browser
27 | 1. copy the dev console log to a file
28 | 1. verify that the C and Javascript print statements are identical
29 |
30 | This Javascript has be tested on smaller (300KB) files.
31 |
32 |
--------------------------------------------------------------------------------
/edit_warning.txt:
--------------------------------------------------------------------------------
1 | /////////////////////////////////////////////////////////////
2 | // //
3 | // DO NOT EDIT THIS FILE! //
4 | // //
5 | // THIS FILE WILL BE OVERWRITTEN DURING THE BUILD PROCESS! //
6 | // //
7 | // EDIT xdelta3_decoder_with_debug.js //
8 | // //
9 | // THIS FILE IS GENERATED FILE BY REMOVING THE DEBUG //
10 | // COMMENTS FROM xdelta3_decoder_with_debug.js //
11 | // //
12 | /////////////////////////////////////////////////////////////
13 |
--------------------------------------------------------------------------------
/strip_xdelta3_decoder.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | cat edit_warning.txt > xdelta3_decoder.js
3 | grep -v '// DEBUG ONLY' xdelta3_decoder_with_debug.js >> xdelta3_decoder.js
4 |
--------------------------------------------------------------------------------
/tests/debug.js:
--------------------------------------------------------------------------------
1 |
2 | var debug_text = '';
3 |
4 | function printf(text) {
5 | var last = text.length - 1;
6 | if (text[last] == '\n') {
7 | //console.log(text.substr(0,last));
8 | console.log(text);
9 | } else {
10 | console.log(text);
11 | }
12 | debug_text += text;
13 | }
14 |
15 | function debug_save(){
16 | var filename = 'debug.log';
17 |
18 | var blob = new Blob([debug_text], {type: 'text/json'}),
19 | e = document.createEvent('MouseEvents'),
20 | a = document.createElement('a')
21 |
22 | a.download = filename
23 | a.href = window.URL.createObjectURL(blob)
24 | a.dataset.downloadurl = ['text/json', a.download, a.href].join(':')
25 | e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
26 | a.dispatchEvent(e)
27 |
28 | debug_text = '';
29 | }
30 |
31 | function dumpBytes(bytes, offset, length) {
32 | printf('++++++++++++++++++++++++++++++++++++++++++\n');
33 | var output = '';
34 | var text = '';
35 | for (var i = 0; i < length; i++) {
36 | var aByte = bytes[offset + i];
37 | var dec = ' ' + aByte;
38 | if (aByte >= 32 && aByte < 127) {
39 | text += String.fromCharCode(aByte);
40 | } else {
41 | text += ' ';
42 | }
43 | output += dec.substr(-3) + ', ';
44 | if (i % 8 == 7) {
45 | output += ' // \'' + text + '\'\n';
46 | text = '';
47 | }
48 | }
49 | i--;
50 | if (i % 8 != 7) {
51 | output += ' // \'' + text + '\'\n';
52 | }
53 | printf(output);
54 | printf('++++++++++++++++++++++++++++++++++++++++++\n');
55 | }
56 |
57 | /**
58 | * @param {!xd3_hinst} inst1
59 | * @param {!xd3_hinst} inst2
60 | */
61 | function printInstructionPair(inst1, inst2) {
62 | printf(
63 | typeToTypeString(inst1.type) + '/' + inst1.size + '/' + typeToMode(inst1.type) + ' : ' +
64 | typeToTypeString(inst2.type) + '/' + inst2.size + '/' + typeToMode(inst2.type) + "\n");
65 | }
66 |
67 | function dumpCodeTableRows(tableRows, startRow, endRow) {
68 | var output = '';
69 | output += '==============================================\n';
70 | output += 'code table:\n';
71 | for (var row = startRow; row < endRow; row++) {
72 | var tableRow = tableRows[row];
73 | output += rightJustify(row, 3) + ': ';
74 | output += typeToTypeString(tableRow.type1) + '(' + tableRow.type1 + '), ';
75 | output += rightJustify(tableRow.size1, 2) + ', ';
76 | output += typeToMode(tableRow.type1) + ', ';
77 | output += typeToTypeString(tableRow.type2) + '(' + tableRow.type2 + '), ';
78 | output += rightJustify(tableRow.size2, 2) + ', ';
79 | output += typeToMode(tableRow.type2);
80 | output += '\n';
81 | }
82 | output += '==============================================\n';
83 | printf(output);
84 | }
85 |
86 | // TODO(bstell): move to a common file
87 | var XD3_NOOP = 0;
88 | var XD3_ADD = 1;
89 | var XD3_RUN = 2;
90 | var XD3_CPY = 3;
91 |
92 | function typeToMode(type) {
93 | if (type == XD3_NOOP) {
94 | return 0;
95 | }
96 | else if (type == XD3_ADD) {
97 | return 0;
98 | }
99 | else if (type == XD3_RUN) {
100 | return 0;
101 | }
102 | else {
103 | return type - XD3_CPY;
104 | }
105 | }
106 |
107 | function typeToTypeString(type) {
108 | var typeString;
109 | if (type == XD3_NOOP) {
110 | typeString = 'XD3_NOOP';
111 | }
112 | else if (type == XD3_ADD) {
113 | typeString = 'XD3_ADD';
114 | }
115 | else if (type == XD3_RUN) {
116 | typeString = 'XD3_RUN';
117 | }
118 | else {
119 | typeString = 'XD3_CPY';
120 | }
121 | return typeString;
122 | }
123 |
124 | function rightJustify(str, len) {
125 | var longStr = ' ' + str;
126 | return longStr.substr(-len);
127 | }
128 |
129 | function toHexStr(val) {
130 | var hex = '0' + val.toString(16);
131 | return '0x' + hex.substr(-2);
132 | }
133 |
134 |
--------------------------------------------------------------------------------
/tests/misc.js:
--------------------------------------------------------------------------------
1 |
2 | function setInnerHtml(id, message) {
3 | var msgEle = document.getElementById(id);
4 | msgEle.innerHTML = message;
5 | console.log(message);
6 | }
7 |
8 | function compareBytes(bytesA, bytesB) {
9 | var msg;
10 | var length = bytesB.byteLength;
11 | for (var i = 0; i < length; i++) {
12 | if (bytesA[i] != bytesB[i]) {
13 | return i +': bytesA('+bytesA[i]+') != bytesB('+bytesB[i]+')';
14 | }
15 | }
16 | return 'matched!';
17 | }
18 |
19 | // Load a file.
20 | function loadFile(url, callback) {
21 | var xhttp = new XMLHttpRequest();
22 | xhttp.onreadystatechange = function() {
23 | if (this.readyState == 4) {
24 | if (this.status == 200) {
25 | callback(new Uint8Array(this.response));
26 | }
27 | }
28 | };
29 | xhttp.open("GET", url, true);
30 | xhttp.responseType = "arraybuffer";
31 | xhttp.send();
32 | }
33 |
34 | function addRow(id, name, path) {
35 | var msgEle = document.getElementById(id);
36 | msgEle.innerHTML += '
' + name + ': ' + path + ' ';
37 | }
38 |
--------------------------------------------------------------------------------
/tests/style.css:
--------------------------------------------------------------------------------
1 | table {
2 | border-collapse: collapse;
3 | }
4 | td, th {
5 | border: 1px solid lightGray;
6 | }
7 |
--------------------------------------------------------------------------------
/tests/testA.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | XDelta3 TestA: text with source
5 |
6 |
7 |
8 |
9 |
50 |
51 |
52 | XDelta3 decode text delta with a source
53 |
54 | status:
55 |
56 |
61 |
62 |
--------------------------------------------------------------------------------
/tests/testA/A.delta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testA/A.delta
--------------------------------------------------------------------------------
/tests/testA/A.expectedTarget:
--------------------------------------------------------------------------------
1 | /**
2 | * Enum for error values.
3 | * @enum {string}
4 | */
5 | tachyfont.Error = {
6 | FILE_ID: 'ETF',
7 | // 02-03 no longer used.
8 | KNOWN_WINDOW_ON_ERROR: '05',
9 | UNKNOWN_WINDOW_ON_ERROR: '06',
10 | NOT_ENOUGH_STORAGE: '07',
11 | STORAGE_INFORMATION_FUNCTION: '08',
12 | GET_STORAGE_INFORMATION: '09',
13 | NO_PRELUDE_REPORTS: '10',
14 | PRELUDE_REPORT_TYPE: '11',
15 | BELOW_GLOBAL_STABLE_TIME: '12',
16 | OPEN_GLOBAL_DATABASE: '13',
17 | NO_INDEXED_DB: '14',
18 | NO_MUTATION_OBSERVER: '15',
19 | NO_FONT_LOADER: '16',
20 | PAGE_LOADED: '17',
21 | GET_COMPACT_FONT: '18',
22 | // 19 no longer used.
23 | DISPLAY_COMPACT_FONT: '20',
24 | NO_UINT8ARRAY_FROM: '21',
25 | END: '00'
26 | };
27 |
28 |
29 | /**
30 | * The error reporter for this file.
31 | * @param {string} errNum The error number (encoded in a string);
32 | * @param {*=} opt_errInfo Optional error object;
33 | * @param {string} opt_fontId Optional identifier for the font.
34 | */
35 | tachyfont.reportError = function(errNum, opt_errInfo, opt_fontId) {
36 | var errInfo = opt_errInfo || '';
37 | var fontId = opt_fontId || '000';
38 | tachyfont.Reporter.reportError(
39 | tachyfont.Error.FILE_ID + errNum, fontId, errInfo);
40 | };
41 |
42 |
43 | if (window.addEventListener) {
44 | /**
45 | * Report any uncaught errors.
46 | * @param {!Event} error The error information.
47 | * @private
48 | */
49 | tachyfont.windowOnError_ = function(error) {
50 | if (!error['filename']) {
51 | // The information is stripped from the report because of CORS issues.
52 | tachyfont.reportError(tachyfont.Error.UNKNOWN_WINDOW_ON_ERROR);
53 | return;
54 | }
55 | var errorObj = {};
56 | errorObj['message'] = error['message'];
57 | errorObj['filename'] = error['filename'];
58 | errorObj['lineno'] = error['lineno'];
59 | errorObj['colno'] = error['colno'];
60 | if (error.error) {
61 | errorObj['stack'] = error['error']['stack'].substring(0, 1000);
62 | }
63 | var errorStr = JSON.stringify(errorObj);
64 | tachyfont.reportError(tachyfont.Error.KNOWN_WINDOW_ON_ERROR, errorStr);
65 | };
66 | window.addEventListener('error', tachyfont.windowOnError_, false);
67 | }
68 |
--------------------------------------------------------------------------------
/tests/testA/A.source:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @license
5 | * Copyright 2015 Google Inc. All rights reserved.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8 | * use this file except in compliance with the License. You may obtain a copy of
9 | * the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 | * License for the specific language governing permissions and limitations under
17 | * the License.
18 | */
19 |
20 | goog.provide('tachyfont');
21 | goog.provide('tachyfont.Error');
22 | goog.provide('tachyfont.TachyFont');
23 |
24 | goog.require('goog.Promise');
25 | goog.require('goog.Uri');
26 | goog.require('goog.asserts');
27 | goog.require('goog.debug.Logger');
28 | goog.require('tachyfont.Define');
29 | /** @suppress {extraRequire} */
30 | goog.require('tachyfont.FontsInfo');
31 | goog.require('tachyfont.IncrementalFont');
32 | goog.require('tachyfont.Persist');
33 | goog.require('tachyfont.Reporter');
34 | goog.require('tachyfont.TachyFontSet');
35 | goog.require('tachyfont.log');
36 | goog.require('tachyfont.utils');
37 |
38 |
39 |
40 | /**
41 | * TachyFont - A namespace.
42 | * @param {!tachyfont.FontInfo} fontInfo The font info.
43 | * @param {boolean} dropData If true then drop the persistent store data.
44 | * @param {!Object=} opt_params Optional parameters.
45 | * @constructor
46 | */
47 | tachyfont.TachyFont = function(fontInfo, dropData, opt_params) {
48 | var params = opt_params || {};
49 |
50 | /**
51 | * The object that handles the binary manipulation of the font data.
52 | * @private {!tachyfont.IncrementalFont.obj}
53 | * TODO(bstell): integrate the manager into this object.
54 | */
55 | this.incrfont_ = tachyfont.IncrementalFont.createManager(fontInfo, dropData,
56 | params);
57 | };
58 |
59 |
60 | /**
61 | * Lazily load the data for these chars.
62 | */
63 | tachyfont.TachyFont.prototype.getIncrfont = function() {
64 | return this.incrfont_;
65 | };
66 |
67 |
68 | /**
69 | * Lazily load the data for these chars.
70 | */
71 | tachyfont.TachyFont.prototype.loadNeededChars = function() {
72 | this.incrfont_.loadChars();
73 | };
74 |
75 |
76 | /**
77 | * The persistence 'stable' time.
78 | * If the data has been in persistent store longer than this then the data is
79 | * considered to be stable; ie: not being automatically cleared. The time is in
80 | * milliseconds.
81 | * @type {number}
82 | */
83 | tachyfont.TachyFont.GLOBAL_STABLE_DATA_TIME = 24 * 60 * 60 * 1000;
84 |
85 |
86 | /**
87 | * Enum for error values.
88 | * @enum {string}
89 | */
90 | tachyfont.Error = {
91 | FILE_ID: 'ETF',
92 | // 02-03 no longer used.
93 | KNOWN_WINDOW_ON_ERROR: '05',
94 | UNKNOWN_WINDOW_ON_ERROR: '06',
95 | NOT_ENOUGH_STORAGE: '07',
96 | STORAGE_INFORMATION_FUNCTION: '08',
97 | GET_STORAGE_INFORMATION: '09',
98 | NO_PRELUDE_REPORTS: '10',
99 | PRELUDE_REPORT_TYPE: '11',
100 | BELOW_GLOBAL_STABLE_TIME: '12',
101 | OPEN_GLOBAL_DATABASE: '13',
102 | NO_INDEXED_DB: '14',
103 | NO_MUTATION_OBSERVER: '15',
104 | NO_FONT_LOADER: '16',
105 | PAGE_LOADED: '17',
106 | GET_COMPACT_FONT: '18',
107 | // 19 no longer used.
108 | DISPLAY_COMPACT_FONT: '20',
109 | NO_UINT8ARRAY_FROM: '21',
110 | END: '00'
111 | };
112 |
--------------------------------------------------------------------------------
/tests/testB.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | XDelta3 TestB: text/no-source
5 |
6 |
7 |
8 |
9 |
45 |
46 |
47 | XDelta3 decode text delta (no source)
48 | status:
49 |
50 |
55 |
56 |
--------------------------------------------------------------------------------
/tests/testB/B.delta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testB/B.delta
--------------------------------------------------------------------------------
/tests/testB/B.expectedTarget:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | goog.provide('tachyfont');
4 | goog.provide('tachyfont.Error');
5 | goog.provide('tachyfont.TachyFont');
6 |
7 | goog.require('goog.Promise');
8 | goog.require('goog.Uri');
9 | goog.require('goog.asserts');
10 | goog.require('goog.debug.Logger');
11 | goog.require('tachyfont.Define');
12 | /** @suppress {extraRequire} */
13 | goog.require('tachyfont.FontsInfo');
14 | goog.require('tachyfont.IncrementalFont');
15 | goog.require('tachyfont.Persist');
16 | goog.require('tachyfont.Reporter');
17 | goog.require('tachyfont.TachyFontSet');
18 | goog.require('tachyfont.log');
19 | goog.require('tachyfont.utils');
20 |
21 |
22 |
23 | /**
24 | * TachyFont - A namespace.
25 | * @param {!tachyfont.FontInfo} fontInfo The font info.
26 | * @param {boolean} dropData If true then drop the persistent store data.
27 | * @param {!Object=} opt_params Optional parameters.
28 | * @constructor
29 | */
30 | tachyfont.TachyFont = function(fontInfo, dropData, opt_params) {
31 | var params = opt_params || {};
32 |
33 | /**
34 | * The object that handles the binary manipulation of the font data.
35 | * @private {!tachyfont.IncrementalFont.obj}
36 | * TODO(bstell): integrate the manager into this object.
37 | */
38 | this.incrfont_ = tachyfont.IncrementalFont.createManager(fontInfo, dropData,
39 | params);
40 | };
41 |
42 |
43 | /**
44 | * Lazily load the data for these chars.
45 | */
46 | tachyfont.TachyFont.prototype.getIncrfont = function() {
47 | return this.incrfont_;
48 | };
49 |
50 |
51 | /**
52 | * Lazily load the data for these chars.
53 | */
54 | tachyfont.TachyFont.prototype.loadNeededChars = function() {
55 | this.incrfont_.loadChars();
56 | };
57 |
58 |
59 | /**
60 | * The persistence 'stable' time.
61 | * If the data has been in persistent store longer than this then the data is
62 | * considered to be stable; ie: not being automatically cleared. The time is in
63 | * milliseconds.
64 | * @type {number}
65 | */
66 | tachyfont.TachyFont.GLOBAL_STABLE_DATA_TIME = 24 * 60 * 60 * 1000;
67 |
68 |
69 | /**
70 | * Enum for error values.
71 | * @enum {string}
72 | */
73 | tachyfont.Error = {
74 | FILE_ID: 'ETF',
75 | // 02-03 no longer used.
76 | KNOWN_WINDOW_ON_ERROR: '05',
77 | UNKNOWN_WINDOW_ON_ERROR: '06',
78 | NOT_ENOUGH_STORAGE: '07',
79 | STORAGE_INFORMATION_FUNCTION: '08',
80 | GET_STORAGE_INFORMATION: '09',
81 | NO_PRELUDE_REPORTS: '10',
82 | PRELUDE_REPORT_TYPE: '11',
83 | BELOW_GLOBAL_STABLE_TIME: '12',
84 | OPEN_GLOBAL_DATABASE: '13',
85 | NO_INDEXED_DB: '14',
86 | NO_MUTATION_OBSERVER: '15',
87 | NO_FONT_LOADER: '16',
88 | PAGE_LOADED: '17',
89 | GET_COMPACT_FONT: '18',
90 | // 19 no longer used.
91 | DISPLAY_COMPACT_FONT: '20',
92 | NO_UINT8ARRAY_FROM: '21',
93 | END: '00'
94 | };
95 |
96 |
97 |
--------------------------------------------------------------------------------
/tests/testC.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | XDelta3 TestC: binary/no-source
5 |
6 |
7 |
8 |
9 |
45 |
46 |
47 | XDelta3 decode binary delta (no source)
48 | status:
49 |
50 |
55 |
56 |
--------------------------------------------------------------------------------
/tests/testC/C.delta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testC/C.delta
--------------------------------------------------------------------------------
/tests/testC/C.expectedTarget:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testC/C.expectedTarget
--------------------------------------------------------------------------------
/tests/testD.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | XDelta3 TestD: big binary with source
5 |
6 |
7 |
8 |
9 |
50 |
51 |
52 | XDelta3 decode big binary delta with a source
53 |
54 | status:
55 |
56 |
61 |
62 |
--------------------------------------------------------------------------------
/tests/testD/D.delta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testD/D.delta
--------------------------------------------------------------------------------
/tests/testD/D.expectedTarget:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testD/D.expectedTarget
--------------------------------------------------------------------------------
/tests/testD/D.source:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testD/D.source
--------------------------------------------------------------------------------
/tests/testE.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | XDelta3 TestE: big binary with source and secondary compressor
5 |
6 |
7 |
8 |
9 |
50 |
51 |
52 | XDelta3 decode big binary delta with a source and secondary compressor
53 |
54 | status:
55 |
56 |
61 |
62 |
--------------------------------------------------------------------------------
/tests/testE/E.delta:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testE/E.delta
--------------------------------------------------------------------------------
/tests/testE/E.expectedTarget:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testE/E.expectedTarget
--------------------------------------------------------------------------------
/tests/testE/E.source:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/xdelta3-decoder-js/065bdca8991bb4610aeb158f126321d471c40631/tests/testE/E.source
--------------------------------------------------------------------------------
/xdelta3-decode_with_debug.h:
--------------------------------------------------------------------------------
1 | /* xdelta3 - delta compression tools and library
2 | Copyright 2016 Joshua MacDonald
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _XDELTA3_DECODE_H_
18 | #define _XDELTA3_DECODE_H_
19 |
20 | #include "xdelta3-internal.h"
21 |
22 | #define SRCORTGT(x) ((((x) & VCD_SRCORTGT) == VCD_SOURCE) ? \
23 | VCD_SOURCE : ((((x) & VCD_SRCORTGT) == \
24 | VCD_TARGET) ? VCD_TARGET : 0))
25 |
26 | static inline int
27 | xd3_decode_byte (xd3_stream *stream, usize_t *val)
28 | {
29 | //printf("xd3_decode_byte: pos = %d, ", stream->total_in);
30 | if (stream->avail_in == 0)
31 | {
32 | printf("no more data\n");
33 | stream->msg = "further input required";
34 | return XD3_INPUT;
35 | }
36 |
37 | //printf("value = %d(0x%x)\n", stream->next_in[0]);
38 | (*val) = stream->next_in[0];
39 |
40 | DECODE_INPUT (1);
41 | return 0;
42 | }
43 |
44 | static inline int
45 | xd3_decode_bytes (xd3_stream *stream, uint8_t *buf, usize_t *pos, usize_t size)
46 | {
47 | usize_t want;
48 | usize_t take;
49 | //printf("xd3_decode_bytes: pos = %d\n", *pos);
50 |
51 | /* Note: The case where (*pos == size) happens when a zero-length
52 | * appheader or code table is transmitted, but there is nothing in
53 | * the standard against that. */
54 | while (*pos < size)
55 | {
56 | if (stream->avail_in == 0)
57 | {
58 | stream->msg = "further input required";
59 | return XD3_INPUT;
60 | }
61 |
62 | want = size - *pos;
63 | take = xd3_min (want, stream->avail_in);
64 |
65 | memcpy (buf + *pos, stream->next_in, (size_t) take);
66 |
67 | DECODE_INPUT (take);
68 | (*pos) += take;
69 | }
70 |
71 | return 0;
72 | }
73 |
74 | /* Initialize the decoder for a new window. The dec_tgtlen value is
75 | * preserved across successive window decodings, and the update to
76 | * dec_winstart is delayed until a new window actually starts. This
77 | * is to avoid throwing an error due to overflow until the last
78 | * possible moment. This makes it possible to encode exactly 4GB
79 | * through a 32-bit encoder. */
80 | static int
81 | xd3_decode_init_window (xd3_stream *stream)
82 | {
83 | stream->dec_cpylen = 0;
84 | stream->dec_cpyoff = 0;
85 | stream->dec_cksumbytes = 0;
86 |
87 | xd3_init_cache (& stream->acache);
88 |
89 | return 0;
90 | }
91 |
92 | /* Allocates buffer space for the target window and possibly the
93 | * VCD_TARGET copy-window. Also sets the base of the two copy
94 | * segments. */
95 | static int
96 | xd3_decode_setup_buffers (xd3_stream *stream)
97 | {
98 | printf("xd3_decode_setup_buffers\n");
99 | /* If VCD_TARGET is set then the previous buffer may be reused. */
100 | if (stream->dec_win_ind & VCD_TARGET)
101 | {
102 | printf("xd3_decode_setup_buffers: VCD_TARGET set\n");
103 | /* Note: this implementation is untested, since Xdelta3 itself
104 | * does not implement an encoder for VCD_TARGET mode. Thus, mark
105 | * unimplemented until needed. */
106 | if (1)
107 | {
108 | stream->msg = "VCD_TARGET not implemented";
109 | return XD3_UNIMPLEMENTED;
110 | }
111 |
112 | /* But this implementation only supports copying from the last
113 | * target window. If the offset is outside that range, it can't
114 | * be done. */
115 | if (stream->dec_cpyoff < stream->dec_laststart)
116 | {
117 | stream->msg = "unsupported VCD_TARGET offset";
118 | return XD3_INVALID_INPUT;
119 | }
120 |
121 | /* See if the two windows are the same. This indicates the
122 | * first time VCD_TARGET is used. This causes a second buffer
123 | * to be allocated, after that the two are swapped in the
124 | * DEC_FINISH case. */
125 | if (stream->dec_lastwin == stream->next_out)
126 | {
127 | stream->next_out = NULL;
128 | stream->space_out = 0;
129 | }
130 |
131 | /* TODO: (See note above, this looks incorrect) */
132 | stream->dec_cpyaddrbase = stream->dec_lastwin +
133 | (usize_t) (stream->dec_cpyoff - stream->dec_laststart);
134 | }
135 |
136 | /* See if the current output window is large enough. */
137 | //printf("stream->space_out = %d\n", stream->space_out);
138 | //printf("stream->dec_tgtlen = %d\n", stream->dec_tgtlen);
139 | if (stream->space_out < stream->dec_tgtlen)
140 | {
141 | xd3_free (stream, stream->dec_buffer);
142 |
143 | stream->space_out =
144 | xd3_round_blksize (stream->dec_tgtlen, XD3_ALLOCSIZE);
145 | //printf("stream->space_out = %d\n", stream->space_out);
146 |
147 | if ((stream->dec_buffer =
148 | (uint8_t*) xd3_alloc (stream, stream->space_out, 1)) == NULL)
149 | {
150 | return ENOMEM;
151 | }
152 |
153 | stream->next_out = stream->dec_buffer;
154 | }
155 |
156 | /* dec_tgtaddrbase refers to an invalid base address, but it is
157 | * always used with a sufficiently large instruction offset (i.e.,
158 | * beyond the copy window). This condition is enforced by
159 | * xd3_decode_output_halfinst. */
160 | stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen;
161 | //printf("stream->next_out = %d\n", stream->next_out);
162 | //printf("stream->dec_cpylen = %d\n", stream->dec_cpylen);
163 | //printf("stream->dec_tgtaddrbase = %d\n", stream->dec_tgtaddrbase);
164 | //printf("stream->dec_tgtaddrbase_delta = %d\n", stream->dec_tgtaddrbase - stream->dec_buffer);
165 |
166 | return 0;
167 | }
168 |
169 | static int
170 | xd3_decode_allocate (xd3_stream *stream,
171 | usize_t size,
172 | uint8_t **buf_ptr,
173 | usize_t *buf_alloc)
174 | {
175 | IF_DEBUG2 (DP(RINT "[xd3_decode_allocate] size %"W"u alloc %"W"u\n",
176 | size, *buf_alloc));
177 |
178 | if (*buf_ptr != NULL && *buf_alloc < size)
179 | {
180 | xd3_free (stream, *buf_ptr);
181 | *buf_ptr = NULL;
182 | }
183 |
184 | if (*buf_ptr == NULL)
185 | {
186 | *buf_alloc = xd3_round_blksize (size, XD3_ALLOCSIZE);
187 |
188 | if ((*buf_ptr = (uint8_t*) xd3_alloc (stream, *buf_alloc, 1)) == NULL)
189 | {
190 | return ENOMEM;
191 | }
192 | }
193 |
194 | return 0;
195 | }
196 |
197 | static int
198 | xd3_decode_section (xd3_stream *stream,
199 | xd3_desect *section,
200 | xd3_decode_state nstate,
201 | int copy)
202 | {
203 | XD3_ASSERT (section->pos <= section->size);
204 | XD3_ASSERT (stream->dec_state != nstate);
205 |
206 | if (section->pos < section->size)
207 | {
208 | usize_t sect_take;
209 |
210 | if (stream->avail_in == 0)
211 | {
212 | return XD3_INPUT;
213 | }
214 |
215 | if ((copy == 0) && (section->pos == 0))
216 | {
217 | /* No allocation/copy needed */
218 | //printf("No allocation/copy needed\n");
219 | section->buf = stream->next_in;
220 | sect_take = section->size;
221 | //printf(": sect_take = %d (%s/%d)\n", sect_take, __FILE__, __LINE__);
222 | //printf("++++++++++++++++++++++\n");
223 | //for (unsigned int i = 0; i < sect_take; i++) {
224 | // printf("0x%02x, ", *(section->buf + i));
225 | // if (i % 8 == 7) {
226 | // printf("\n");
227 | // }
228 | //}
229 | //printf("\n");
230 | //printf("++++++++++++++++++++++\n");
231 | IF_DEBUG1 (DP(RINT "[xd3_decode_section] zerocopy %"W"u @ %"W"u avail %"W"u\n",
232 | sect_take, section->pos, stream->avail_in));
233 | }
234 | else
235 | {
236 | printf("allocation/copy is needed\n");
237 | usize_t sect_need = section->size - section->pos;
238 | printf("sect_needed = %d\n", sect_need);
239 |
240 | /* Allocate and copy */
241 | sect_take = xd3_min (sect_need, stream->avail_in);
242 |
243 | if (section->pos == 0)
244 | {
245 | int ret;
246 |
247 | if ((ret = xd3_decode_allocate (stream,
248 | section->size,
249 | & section->copied1,
250 | & section->alloc1)))
251 | {
252 | return ret;
253 | }
254 |
255 | section->buf = section->copied1;
256 | }
257 |
258 | IF_DEBUG2 (DP(RINT "[xd3_decode_section] take %"W"u @ %"W"u [need %"W"u] avail %"W"u\n",
259 | sect_take, section->pos, sect_need, stream->avail_in));
260 | XD3_ASSERT (section->pos + sect_take <= section->alloc1);
261 |
262 | memcpy (section->copied1 + section->pos,
263 | stream->next_in,
264 | sect_take);
265 | }
266 |
267 | section->pos += sect_take;
268 |
269 | stream->dec_winbytes += sect_take;
270 |
271 | DECODE_INPUT (sect_take);
272 | }
273 |
274 | if (section->pos < section->size)
275 | {
276 | printf(": = (%s/%d)\n", __FILE__, __LINE__);
277 | IF_DEBUG1 (DP(RINT "[xd3_decode_section] further input required %"W"u\n",
278 | section->size - section->pos));
279 | stream->msg = "further input required";
280 | return XD3_INPUT;
281 | }
282 |
283 | XD3_ASSERT (section->pos == section->size);
284 |
285 | //printf(": = (%s/%d)\n", __FILE__, __LINE__);
286 | stream->dec_state = nstate;
287 | section->buf_max = section->buf + section->size;
288 | section->pos = 0;
289 | return 0;
290 | }
291 |
292 | /* Decode the size and address for half of an instruction (i.e., a
293 | * single opcode). This updates the stream->dec_position, which are
294 | * bytes already output prior to processing this instruction. Perform
295 | * bounds checking for sizes and copy addresses, which uses the
296 | * dec_position (which is why these checks are done here). */
297 | static int
298 | xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst)
299 | {
300 | printf("xd3_decode_parse_halfinst\n");
301 | int ret;
302 |
303 | /* If the size from the instruction table is zero then read a size value. */
304 | int needSize = inst->size == 0;
305 | if ((inst->size == 0) &&
306 | (ret = xd3_read_size (stream,
307 | & stream->inst_sect.buf,
308 | stream->inst_sect.buf_max,
309 | & inst->size)))
310 | {
311 | return XD3_INVALID_INPUT;
312 | }
313 | if (needSize) {
314 | printf("read inst size = %d\n", inst->size);
315 | }
316 |
317 | /* For copy instructions, read address. */
318 | if (inst->type >= XD3_CPY)
319 | {
320 | IF_DEBUG2 ({
321 | static int cnt = 0;
322 | XPR(NT "DECODE:%u: COPY at %"Q"u (winoffset %"W"u) "
323 | "size %"W"u winaddr %"W"u\n",
324 | cnt++,
325 | stream->total_out + (stream->dec_position -
326 | stream->dec_cpylen),
327 | (stream->dec_position - stream->dec_cpylen),
328 | inst->size,
329 | inst->addr);
330 | });
331 |
332 | printf("dec_position = %d\n", stream->dec_position);
333 | printf("mode = %d\n", inst->type - XD3_CPY);
334 | if ((ret = xd3_decode_address (stream,
335 | stream->dec_position,
336 | inst->type - XD3_CPY,
337 | & stream->addr_sect.buf,
338 | stream->addr_sect.buf_max,
339 | & inst->addr)))
340 | {
341 | return ret;
342 | }
343 | printf("XD3_CPY address = %d\n", inst->addr);
344 |
345 | /* Cannot copy an address before it is filled-in. */
346 | if (inst->addr >= stream->dec_position)
347 | {
348 | stream->msg = "address too large";
349 | return XD3_INVALID_INPUT;
350 | }
351 |
352 | /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining
353 | * buffer space in its own segment. */
354 | if (inst->addr < stream->dec_cpylen &&
355 | inst->addr + inst->size > stream->dec_cpylen)
356 | {
357 | stream->msg = "size too large";
358 | return XD3_INVALID_INPUT;
359 | }
360 | }
361 | else
362 | {
363 | IF_DEBUG2 ({
364 | if (inst->type == XD3_ADD)
365 | {
366 | static int cnt;
367 | XPR(NT "DECODE:%d: ADD at %"Q"u (winoffset %"W"u) size %"W"u\n",
368 | cnt++,
369 | (stream->total_out + stream->dec_position - stream->dec_cpylen),
370 | stream->dec_position - stream->dec_cpylen,
371 | inst->size);
372 | }
373 | else
374 | {
375 | static int cnt;
376 | XD3_ASSERT (inst->type == XD3_RUN);
377 | XPR(NT "DECODE:%d: RUN at %"Q"u (winoffset %"W"u) size %"W"u\n",
378 | cnt++,
379 | stream->total_out + stream->dec_position - stream->dec_cpylen,
380 | stream->dec_position - stream->dec_cpylen,
381 | inst->size);
382 | }
383 | });
384 | }
385 |
386 | /* Check: The instruction will not overflow the output buffer. */
387 | if (stream->dec_position + inst->size > stream->dec_maxpos)
388 | {
389 | stream->msg = "size too large";
390 | return XD3_INVALID_INPUT;
391 | }
392 |
393 | printf("dec_position = %d\n", stream->dec_position);
394 | printf("inst size = %d\n", inst->size);
395 | stream->dec_position += inst->size;
396 | printf("dec_position = %d\n", stream->dec_position);
397 | return 0;
398 | }
399 |
400 | /* Decode a single opcode and then decode the two half-instructions. */
401 | static int
402 | xd3_decode_instruction (xd3_stream *stream)
403 | {
404 | static int instCount = 0;
405 | printf("xd3_decode_instruction %d\n", instCount++);
406 | int ret;
407 | const xd3_dinst *inst;
408 |
409 | if (stream->inst_sect.buf == stream->inst_sect.buf_max)
410 | {
411 | stream->msg = "instruction underflow";
412 | return XD3_INVALID_INPUT;
413 | }
414 |
415 | printf("instPair = %d\n", *stream->inst_sect.buf);
416 | inst = &stream->code_table[*stream->inst_sect.buf++];
417 |
418 | stream->dec_current1.type = inst->type1;
419 | stream->dec_current2.type = inst->type2;
420 | stream->dec_current1.size = inst->size1;
421 | stream->dec_current2.size = inst->size2;
422 | printf("%s/%d/%d : %s/%d/%d\n",
423 | typeToTypeString(inst->type1), inst->size1, typeToMode(inst->type1),
424 | typeToTypeString(inst->type2), inst->size2, typeToMode(inst->type2));
425 |
426 | /* For each instruction with a real operation, decode the
427 | * corresponding size and addresses if necessary. Assume a
428 | * code-table may have NOOP in either position, although this is
429 | * unlikely. */
430 | if (inst->type1 != XD3_NOOP &&
431 | (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))
432 | {
433 | return ret;
434 | }
435 | if (inst->type2 != XD3_NOOP &&
436 | (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2)))
437 | {
438 | return ret;
439 | }
440 | return 0;
441 | }
442 |
443 | static void
444 | dumpBytes(const uint8_t* p, int len) {
445 | printf("++++++++++++++++++++++++++++++++++++++++++\n");
446 | uint8_t buf[9];
447 | int i;
448 | for (i = 0; i < len; i++) {
449 | //printf("0x%02x, ", p[i]);
450 | printf("%3d, ", p[i]);
451 | if (p[i] >= 32 && p[i] < 127) {
452 | buf[i % 8] = p[i];
453 | } else {
454 | buf[i % 8] = ' ';
455 | }
456 | if (i % 8 == 7) {
457 | buf[8] = '\0';
458 | printf(" // '%s'\n", buf);
459 | }
460 | }
461 | i--;
462 | if (i % 8 != 7) {
463 | buf[(i % 8) + 1] = '\0';
464 | printf(" // '%s'\n", buf);
465 | }
466 | printf("++++++++++++++++++++++++++++++++++++++++++\n");
467 | }
468 |
469 | /* Output the result of a single half-instruction. OPT: This the
470 | decoder hotspot. Modifies "hinst", see below. */
471 | static int
472 | xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
473 | {
474 | printf("xd3_decode_output_halfinst: type=%d, addr=%d, size=%d\n", inst->type, inst->addr, inst->size);
475 | /* This method is reentrant for copy instructions which may return
476 | * XD3_GETSRCBLK to the caller. Each time through a copy takes the
477 | * minimum of inst->size and the available space on whichever block
478 | * supplies the data */
479 | usize_t take = inst->size;
480 | //printf("take = %d (line %d)\n", take, __LINE__);
481 | int start_pos = stream->avail_out;
482 | printf("start_pos = %d\n", start_pos);
483 |
484 | if (USIZE_T_OVERFLOW (stream->avail_out, take) ||
485 | stream->avail_out + take > stream->space_out)
486 | {
487 | stream->msg = "overflow while decoding";
488 | return XD3_INVALID_INPUT;
489 | }
490 |
491 | XD3_ASSERT (inst->type != XD3_NOOP);
492 |
493 | switch (inst->type)
494 | {
495 | case XD3_RUN:
496 | {
497 | /* Only require a single data byte. */
498 | if (stream->data_sect.buf == stream->data_sect.buf_max)
499 | {
500 | stream->msg = "data underflow";
501 | return XD3_INVALID_INPUT;
502 | }
503 |
504 | printf(" >>>> XD3_RUN: memset 0x%02x for %d\n", stream->data_sect.buf[0], take);
505 | memset (stream->next_out + stream->avail_out,
506 | stream->data_sect.buf[0],
507 | take);
508 | dumpBytes(stream->next_out + stream->avail_out, take);
509 |
510 | stream->data_sect.buf += 1;
511 | stream->avail_out += take;
512 | inst->type = XD3_NOOP;
513 | break;
514 | }
515 | case XD3_ADD:
516 | {
517 | /* Require at least TAKE data bytes. */
518 | if (stream->data_sect.buf + take > stream->data_sect.buf_max)
519 | {
520 | stream->msg = "data underflow";
521 | return XD3_INVALID_INPUT;
522 | }
523 |
524 | printf(" >>>> XD3_ADD: memcpy %d from the data_sect\n", take);
525 | memcpy (stream->next_out + stream->avail_out,
526 | stream->data_sect.buf,
527 | take);
528 | dumpBytes(stream->next_out + stream->avail_out, take);
529 |
530 | stream->data_sect.buf += take;
531 | stream->avail_out += take;
532 | inst->type = XD3_NOOP;
533 | break;
534 | }
535 | default:
536 | {
537 | printf(" >>>> XD3_CPY\n");
538 | usize_t i;
539 | const uint8_t *src;
540 | uint8_t *dst;
541 | int overlap;
542 |
543 | /* See if it copies from the VCD_TARGET/VCD_SOURCE window or
544 | * the target window. Out-of-bounds checks for the addresses
545 | * and sizes are performed in xd3_decode_parse_halfinst. This
546 | * if/else must set "overlap", "src", and "dst". */
547 | //printf("inst->addr = %d (line %d)\n", inst->addr, __LINE__);
548 | printf("dec_cpylen = %d\n", stream->dec_cpylen);
549 | if (inst->addr < stream->dec_cpylen)
550 | {
551 | /* In both branches we are copying from outside the
552 | * current decoder window, the first (VCD_TARGET) is
553 | * unimplemented. */
554 | overlap = 0;
555 | printf("overlap = 0\n");
556 |
557 | /* This branch sets "src". As a side-effect, we modify
558 | * "inst" so that if we reenter this method after a
559 | * XD3_GETSRCBLK response the state is correct. So if the
560 | * instruction can be fulfilled by a contiguous block of
561 | * memory then we will set:
562 | *
563 | * inst->type = XD3_NOOP;
564 | * inst->size = 0;
565 | */
566 | if (stream->dec_win_ind & VCD_TARGET)
567 | {
568 | /* TODO: Users have requested long-distance copies of
569 | * similar material within a target (e.g., for dup
570 | * supression in backups). This code path is probably
571 | * dead due to XD3_UNIMPLEMENTED in xd3_decode_setup_buffers */
572 | inst->size = 0;
573 | inst->type = XD3_NOOP;
574 | stream->msg = "VCD_TARGET not implemented";
575 | return XD3_UNIMPLEMENTED;
576 | }
577 | else
578 | {
579 | /* In this case we have to read a source block, which
580 | * could return control to the caller. We need to
581 | * know the first block number needed for this
582 | * copy. */
583 | //printf("read source block(%s/%d)\n", __FILE__, __LINE__);
584 | printf("read source block\n");
585 | xd3_source *source = stream->src;
586 | xoff_t block = source->cpyoff_blocks;
587 | usize_t blkoff = source->cpyoff_blkoff;
588 | const usize_t blksize = source->blksize;
589 | int ret;
590 |
591 | if (block !=0) {
592 | printf("block = %d\n", block);
593 | printf("source->blksize = %d\n", source->blksize);
594 | }
595 | printf("blkoff = %d\n", blkoff);
596 | printf("add inst addr to blkoff\n");
597 | xd3_blksize_add (&block, &blkoff, source, inst->addr);
598 | XD3_ASSERT (blkoff < blksize);
599 | if (block !=0) {
600 | printf("block = %d\n", block);
601 | }
602 | printf("blkoff = %d\n", blkoff);
603 |
604 | if ((ret = xd3_getblk (stream, block)))
605 | {
606 | /* could be a XD3_GETSRCBLK failure. */
607 | if (ret == XD3_TOOFARBACK)
608 | {
609 | stream->msg = "non-seekable source in decode";
610 | ret = XD3_INTERNAL;
611 | }
612 | return ret;
613 | }
614 |
615 | src = source->curblk + blkoff;
616 | //printf("source->curblk=%d, blkoff=%d\n", source->curblk, blkoff);
617 |
618 | /* This block is either full, or a partial block that
619 | * must contain enough bytes. */
620 | if ((source->onblk != blksize) &&
621 | (blkoff + take > source->onblk))
622 | {
623 | IF_DEBUG1 (XPR(NT "[srcfile] short at blkno %"Q"u onblk "
624 | "%"W"u blksize %"W"u blkoff %"W"u take %"W"u\n",
625 | block,
626 | source->onblk,
627 | blksize,
628 | blkoff,
629 | take));
630 | stream->msg = "source file too short";
631 | return XD3_INVALID_INPUT;
632 | }
633 |
634 | XD3_ASSERT (blkoff != blksize);
635 |
636 | /* Check if we have enough data on this block to
637 | * finish the instruction. */
638 | if (blkoff + take <= blksize)
639 | {
640 | inst->type = XD3_NOOP;
641 | inst->size = 0;
642 | }
643 | else
644 | {
645 | take = blksize - blkoff;
646 | inst->size -= take;
647 | inst->addr += take;
648 |
649 | /* because (blkoff + take > blksize), above */
650 | XD3_ASSERT (inst->size != 0);
651 | }
652 | }
653 | }
654 | else
655 | {
656 | /* TODO: the memcpy/overlap optimization, etc. Overlap
657 | * here could be more specific, it's whether (inst->addr -
658 | * srclen) + inst->size > input_pos ? And is the system
659 | * memcpy really any good? */
660 | overlap = 1;
661 | printf("overlap = 1\n");
662 |
663 | /* For a target-window copy, we know the entire range is
664 | * in-memory. The dec_tgtaddrbase is negatively offset by
665 | * dec_cpylen because the addresses start beyond that
666 | * point. */
667 | //printf("stream->dec_tgtaddrbase = %d\n", stream->dec_tgtaddrbase);
668 | //printf("inst->addr = %d\n", inst->addr);
669 | //printf("stream->dec_tgtaddrbase_delta = %d\n", stream->dec_tgtaddrbase - stream->dec_buffer);
670 | int overlap_pos = inst->addr - stream->dec_cpylen;
671 | printf("overlap_pos = %d\n", overlap_pos);
672 | src = stream->dec_tgtaddrbase + inst->addr;
673 | //printf("src = %d (%s/%d)\n", src,__FILE__, __LINE__);
674 | inst->type = XD3_NOOP;
675 | inst->size = 0;
676 | }
677 |
678 | //printf("next_out = %d, avail_out = %d\n", stream->next_out, stream->avail_out);
679 | dst = stream->next_out + stream->avail_out;
680 |
681 | stream->avail_out += take;
682 | //printf("avail_out = %d\n", stream->avail_out);
683 |
684 | if (overlap)
685 | {
686 | printf(" <<<< manually copy %d\n", take);
687 | uint8_t* p = dst;
688 | /* Can't just memcpy here due to possible overlap. */
689 | for (i = take; i != 0; i -= 1)
690 | {
691 | *dst++ = *src++;
692 | }
693 | dumpBytes(p, take);
694 | }
695 | else
696 | {
697 | printf(" <<<< memcopy take=%d\n", take);
698 | memcpy (dst, src, take);
699 | dumpBytes(dst, take);
700 | }
701 | }
702 | }
703 |
704 | return 0;
705 | }
706 |
707 | static int
708 | xd3_decode_finish_window (xd3_stream *stream)
709 | {
710 | printf("xd3_decode_finish_window\n");
711 | stream->dec_winbytes = 0;
712 | stream->dec_state = DEC_FINISH;
713 |
714 | stream->data_sect.pos = 0;
715 | stream->inst_sect.pos = 0;
716 | stream->addr_sect.pos = 0;
717 |
718 | return XD3_OUTPUT;
719 | }
720 |
721 | static int
722 | xd3_decode_secondary_sections (xd3_stream *secondary_stream)
723 | {
724 | #if SECONDARY_ANY
725 | int ret;
726 | printf("xd3_decode_secondary_sections\n");
727 | #define DECODE_SECONDARY_SECTION(UPPER,LOWER) \
728 | ((secondary_stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \
729 | (ret = xd3_decode_secondary (secondary_stream, \
730 | & secondary_stream-> LOWER ## _sect, \
731 | & xd3_sec_ ## LOWER (secondary_stream))))
732 |
733 | if (DECODE_SECONDARY_SECTION (DATA, data) ||
734 | DECODE_SECONDARY_SECTION (INST, inst) ||
735 | DECODE_SECONDARY_SECTION (ADDR, addr))
736 | {
737 | return ret;
738 | }
739 | #undef DECODE_SECONDARY_SECTION
740 | #endif
741 | return 0;
742 | }
743 |
744 | static int
745 | xd3_decode_sections (xd3_stream *stream)
746 | {
747 | printf("xd3_decode_sections\n");
748 | usize_t need, more, take;
749 | int copy, ret;
750 |
751 | if ((stream->flags & XD3_JUST_HDR) != 0)
752 | {
753 | /* Nothing left to do. */
754 | return xd3_decode_finish_window (stream);
755 | }
756 |
757 | /* To avoid extra copying, allocate three sections at once (but
758 | * check for overflow). */
759 | need = stream->inst_sect.size;
760 |
761 | if (USIZE_T_OVERFLOW (need, stream->addr_sect.size))
762 | {
763 | stream->msg = "decoder section size overflow";
764 | return XD3_INTERNAL;
765 | }
766 | need += stream->addr_sect.size;
767 |
768 | if (USIZE_T_OVERFLOW (need, stream->data_sect.size))
769 | {
770 | stream->msg = "decoder section size overflow";
771 | return XD3_INTERNAL;
772 | }
773 | need += stream->data_sect.size;
774 |
775 | /* The window may be entirely processed. */
776 | XD3_ASSERT (stream->dec_winbytes <= need);
777 |
778 | /* Compute how much more input is needed. */
779 | more = (need - stream->dec_winbytes);
780 |
781 | /* How much to consume. */
782 | take = xd3_min (more, stream->avail_in);
783 |
784 | /* See if the input is completely available, to avoid copy. */
785 | copy = (take != more);
786 | //printf("copy = %d\n", copy);
787 |
788 | /* If the window is skipped... */
789 | if ((stream->flags & XD3_SKIP_WINDOW) != 0)
790 | {
791 | printf("skip window\n");
792 | /* Skip the available input. */
793 | DECODE_INPUT (take);
794 |
795 | printf("skip %d bytes\n", take);
796 | stream->dec_winbytes += take;
797 |
798 | if (copy)
799 | {
800 | stream->msg = "further input required";
801 | return XD3_INPUT;
802 | }
803 |
804 | return xd3_decode_finish_window (stream);
805 | }
806 |
807 | /* Process all but the DATA section. */
808 | switch (stream->dec_state)
809 | {
810 | default:
811 | stream->msg = "internal error";
812 | return XD3_INVALID_INPUT;
813 |
814 | case DEC_DATA:
815 | if ((ret = xd3_decode_section (stream, & stream->data_sect,
816 | DEC_INST, copy))) { return ret; }
817 | case DEC_INST:
818 | if ((ret = xd3_decode_section (stream, & stream->inst_sect,
819 | DEC_ADDR, copy))) { return ret; }
820 | case DEC_ADDR:
821 | if ((ret = xd3_decode_section (stream, & stream->addr_sect,
822 | DEC_EMIT, copy))) { return ret; }
823 | }
824 |
825 | XD3_ASSERT (stream->dec_winbytes == need);
826 |
827 | if ((ret = xd3_decode_secondary_sections (stream))) { return ret; }
828 |
829 | if (stream->flags & XD3_SKIP_EMIT)
830 | {
831 | printf("skip emit\n");
832 | return xd3_decode_finish_window (stream);
833 | }
834 |
835 | /* OPT: A possible optimization is to avoid allocating memory in
836 | * decode_setup_buffers and to avoid a large memcpy when the window
837 | * consists of a single VCD_SOURCE copy instruction. */
838 | if ((ret = xd3_decode_setup_buffers (stream))) { return ret; }
839 |
840 | return 0;
841 | }
842 |
843 | static int
844 | xd3_decode_emit (xd3_stream *stream)
845 | {
846 | printf("\n\n");
847 | printf("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@\n");
848 | printf(" xd3_decode_emit:\n");
849 | printf("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@\n");
850 | int ret;
851 |
852 | /* Produce output: originally structured to allow reentrant code
853 | * that fills as much of the output buffer as possible, but VCDIFF
854 | * semantics allows to copy from anywhere from the target window, so
855 | * instead allocate a sufficiently sized buffer after the target
856 | * window length is decoded.
857 | *
858 | * This code still needs to be reentrant to allow XD3_GETSRCBLK to
859 | * return control. This is handled by setting the
860 | * stream->dec_currentN instruction types to XD3_NOOP after they
861 | * have been processed. */
862 | XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT));
863 | XD3_ASSERT (stream->dec_tgtlen <= stream->space_out);
864 |
865 |
866 | //printf("dec_current1.type = %d\n", stream->dec_current1.type);
867 | //printf("dec_current2.type = %d\n", stream->dec_current2.type);
868 | while (stream->inst_sect.buf != stream->inst_sect.buf_max ||
869 | stream->dec_current1.type != XD3_NOOP ||
870 | stream->dec_current2.type != XD3_NOOP)
871 | {
872 | /* Decode next instruction pair. */
873 | printf("\n========== Decode next instruction pair ==========\n");
874 | if ((stream->dec_current1.type == XD3_NOOP) &&
875 | (stream->dec_current2.type == XD3_NOOP) &&
876 | (ret = xd3_decode_instruction (stream))) { return ret; }
877 |
878 | /* Output dec_current1 */
879 | while ((stream->dec_current1.type != XD3_NOOP))
880 | {
881 | printf("output dec_current1 ----------\n");
882 | if ((ret = xd3_decode_output_halfinst (stream, & stream->dec_current1)))
883 | {
884 | return ret;
885 | }
886 | }
887 | /* Output dec_current2 */
888 | while (stream->dec_current2.type != XD3_NOOP)
889 | {
890 | printf("output dec_current2 ----------\n");
891 | if ((ret = xd3_decode_output_halfinst (stream, & stream->dec_current2)))
892 | {
893 | return ret;
894 | }
895 | }
896 | }
897 |
898 | if (stream->avail_out != stream->dec_tgtlen)
899 | {
900 | IF_DEBUG2 (DP(RINT "AVAIL_OUT(%"W"u) != DEC_TGTLEN(%"W"u)\n",
901 | stream->avail_out, stream->dec_tgtlen));
902 | stream->msg = "wrong window length";
903 | return XD3_INVALID_INPUT;
904 | }
905 |
906 | if (stream->data_sect.buf != stream->data_sect.buf_max)
907 | {
908 | stream->msg = "extra data section";
909 | return XD3_INVALID_INPUT;
910 | }
911 |
912 | if (stream->addr_sect.buf != stream->addr_sect.buf_max)
913 | {
914 | stream->msg = "extra address section";
915 | return XD3_INVALID_INPUT;
916 | }
917 |
918 | /* OPT: Should cksum computation be combined with the above loop? */
919 | printf("check checksum is VCD_ADLER32 set\n");
920 | if ((stream->dec_win_ind & VCD_ADLER32) != 0 &&
921 | (stream->flags & XD3_ADLER32_NOVER) == 0)
922 | {
923 | uint32_t a32 = adler32 (1L, stream->next_out, stream->avail_out);
924 | printf("a32 = %d\n", a32);
925 |
926 | if (a32 != stream->dec_adler32)
927 | {
928 | stream->msg = "target window checksum mismatch";
929 | return XD3_INVALID_INPUT;
930 | }
931 | }
932 |
933 | /* Finished with a window. */
934 | return xd3_decode_finish_window (stream);
935 | }
936 |
937 | int
938 | xd3_decode_input (xd3_stream *stream)
939 | {
940 | int ret;
941 | int srcortgt;
942 |
943 | if (stream->enc_state != 0)
944 | {
945 | stream->msg = "encoder/decoder transition";
946 | return XD3_INVALID_INPUT;
947 | }
948 |
949 | #define BYTE_CASE(expr,x,nstate) \
950 | do { \
951 | if ( (expr) && \
952 | ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; } \
953 | stream->dec_state = (nstate); \
954 | } while (0)
955 |
956 | #define OFFSET_CASE(expr,x,nstate) \
957 | do { \
958 | if ( (expr) && \
959 | ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; } \
960 | stream->dec_state = (nstate); \
961 | } while (0)
962 |
963 | #define SIZE_CASE(expr,x,nstate) \
964 | do { \
965 | if ( (expr) && \
966 | ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; } \
967 | stream->dec_state = (nstate); \
968 | } while (0)
969 |
970 | switch (stream->dec_state)
971 | {
972 | case DEC_VCHEAD:
973 | {
974 | printf("==================================\n");
975 | printf(" HEADER pos = %d\n", stream->total_in);
976 | printf("==================================\n");
977 | printf("DEC_VCHEAD: load magic bytes\n");
978 | if ((ret = xd3_decode_bytes (stream, stream->dec_magic,
979 | & stream->dec_magicbytes, 4)))
980 | {
981 | return ret;
982 | }
983 | dumpBytes(stream->dec_magic, 4);
984 |
985 | printf("DEC_VCHEAD: check magic bytes\n");
986 | if (stream->dec_magic[0] != VCDIFF_MAGIC1 ||
987 | stream->dec_magic[1] != VCDIFF_MAGIC2 ||
988 | stream->dec_magic[2] != VCDIFF_MAGIC3)
989 | {
990 | stream->msg = "not a VCDIFF input";
991 | return XD3_INVALID_INPUT;
992 | }
993 |
994 | if (stream->dec_magic[3] != 0)
995 | {
996 | stream->msg = "VCDIFF input version > 0 is not supported";
997 | return XD3_INVALID_INPUT;
998 | }
999 |
1000 | stream->dec_state = DEC_HDRIND;
1001 | }
1002 | case DEC_HDRIND:
1003 | {
1004 | if ((ret = xd3_decode_byte (stream, & stream->dec_hdr_ind)))
1005 | {
1006 | return ret;
1007 | }
1008 | printf("DEC_HDRIND: dec_hdr_ind = 0x%02x\n", stream->dec_hdr_ind);
1009 |
1010 | //printf("DEC_HDRIND: check only lower 3 bits of hdr indicator set\n");
1011 | if ((stream->dec_hdr_ind & VCD_INVHDR) != 0)
1012 | {
1013 | stream->msg = "unrecognized header indicator bits set";
1014 | return XD3_INVALID_INPUT;
1015 | }
1016 |
1017 | stream->dec_state = DEC_SECONDID;
1018 | }
1019 |
1020 | case DEC_SECONDID:
1021 | /* Secondary compressor ID: only if VCD_SECONDARY is set */
1022 | printf("DEC_SECONDID: read byte if VCD_SECONDARY(%d)\n", stream->dec_hdr_ind & VCD_SECONDARY);
1023 | if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0)
1024 | {
1025 | BYTE_CASE (1, stream->dec_secondid, DEC_TABLEN);
1026 | printf("DEC_SECONDID = %d\n", stream->dec_secondid);
1027 |
1028 | switch (stream->dec_secondid)
1029 | {
1030 | case VCD_FGK_ID:
1031 | FGK_CASE (stream);
1032 | case VCD_DJW_ID:
1033 | DJW_CASE (stream);
1034 | case VCD_LZMA_ID:
1035 | LZMA_CASE (stream);
1036 | default:
1037 | stream->msg = "unknown secondary compressor ID";
1038 | return XD3_INVALID_INPUT;
1039 | }
1040 | }
1041 |
1042 | case DEC_TABLEN:
1043 | /* Length of code table data: only if VCD_CODETABLE is set */
1044 | printf("DEC_TABLEN: read size if VCD_CODETABLE(%d)\n", stream->dec_hdr_ind & VCD_CODETABLE);
1045 | SIZE_CASE ((stream->dec_hdr_ind & VCD_CODETABLE) != 0,
1046 | stream->dec_codetblsz, DEC_NEAR);
1047 |
1048 | /* The codetblsz counts the two NEAR/SAME bytes */
1049 | if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) {
1050 | printf("DEC_TABLEN: \n");
1051 | if (stream->dec_codetblsz <= 2) {
1052 | stream->msg = "invalid code table size";
1053 | return ENOMEM;
1054 | }
1055 | stream->dec_codetblsz -= 2;
1056 | }
1057 | case DEC_NEAR:
1058 | /* Near modes: only if VCD_CODETABLE is set */
1059 | printf("DEC_NEAR: read byte if VCD_CODETABLE(%d)\n", stream->dec_hdr_ind & VCD_CODETABLE);
1060 | BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0,
1061 | stream->acache.s_near, DEC_SAME);
1062 | case DEC_SAME:
1063 | /* Same modes: only if VCD_CODETABLE is set */
1064 | printf("DEC_SAME: read byte if VCD_CODETABLE(%d)\n", stream->dec_hdr_ind & VCD_CODETABLE);
1065 | BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0,
1066 | stream->acache.s_same, DEC_TABDAT);
1067 | case DEC_TABDAT:
1068 | /* Compressed code table data */
1069 |
1070 | if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0)
1071 | {
1072 | stream->msg = "VCD_CODETABLE support was removed";
1073 | return XD3_UNIMPLEMENTED;
1074 | }
1075 | else
1076 | {
1077 | printf("use the default table.\n");
1078 | /* Use the default table. */
1079 | printf("use default table near_modes %d\n", __rfc3284_code_table_desc.near_modes);
1080 | stream->acache.s_near = __rfc3284_code_table_desc.near_modes;
1081 | printf("use default table same_modes %d\n", __rfc3284_code_table_desc.same_modes);
1082 | stream->acache.s_same = __rfc3284_code_table_desc.same_modes;
1083 | stream->code_table = xd3_rfc3284_code_table ();
1084 | }
1085 |
1086 | if ((ret = xd3_alloc_cache (stream))) { return ret; }
1087 |
1088 | stream->dec_state = DEC_APPLEN;
1089 |
1090 | case DEC_APPLEN:
1091 | /* Length of application data */
1092 | printf("DEC_APPLEN: read size if VCD_APPHEADER(%d)\n", stream->dec_hdr_ind & VCD_APPHEADER);
1093 | SIZE_CASE((stream->dec_hdr_ind & VCD_APPHEADER) != 0,
1094 | stream->dec_appheadsz, DEC_APPDAT);
1095 | if (stream->dec_hdr_ind & VCD_APPHEADER) {
1096 | printf("dec_appheadsz = %d\n", stream->dec_appheadsz);
1097 | }
1098 |
1099 | case DEC_APPDAT:
1100 | /* Application data */
1101 | if (stream->dec_hdr_ind & VCD_APPHEADER)
1102 | {
1103 | printf("DEC_APPDAT: \n");
1104 | /* Note: we add an additional byte for padding, to allow
1105 | 0-termination. Check for overflow: */
1106 | if (USIZE_T_OVERFLOW(stream->dec_appheadsz, 1))
1107 | {
1108 | stream->msg = "exceptional appheader size";
1109 | return XD3_INVALID_INPUT;
1110 | }
1111 |
1112 | if ((stream->dec_appheader == NULL) &&
1113 | (stream->dec_appheader =
1114 | (uint8_t*) xd3_alloc (stream,
1115 | stream->dec_appheadsz+1, 1)) == NULL)
1116 | {
1117 | return ENOMEM;
1118 | }
1119 |
1120 | stream->dec_appheader[stream->dec_appheadsz] = 0;
1121 |
1122 | if ((ret = xd3_decode_bytes (stream, stream->dec_appheader,
1123 | & stream->dec_appheadbytes,
1124 | stream->dec_appheadsz)))
1125 | {
1126 | return ret;
1127 | }
1128 | dumpBytes(stream->dec_appheader, stream->dec_appheadsz + 1);
1129 | }
1130 |
1131 | /* xoff_t -> usize_t is safe because this is the first block. */
1132 | stream->dec_hdrsize = (usize_t) stream->total_in;
1133 | printf("pos after dec_appheader = %d\n", stream->total_in);
1134 | printf("\n");
1135 | stream->dec_state = DEC_WININD;
1136 |
1137 | case DEC_WININD:
1138 | {
1139 | printf("DEC_WININD\n");
1140 | printf("==================================\n");
1141 | printf(" WINDOW pos = %d\n", stream->total_in);
1142 | printf("==================================\n");
1143 | /* Start of a window: the window indicator */
1144 | if ((ret = xd3_decode_byte (stream, & stream->dec_win_ind)))
1145 | {
1146 | return ret;
1147 | }
1148 | printf("dec_win_ind = %d(0x%02x)\n", stream->dec_win_ind, stream->dec_win_ind);
1149 | printf("dec_tgtlen = %d(0x%02x)\n", stream->dec_tgtlen, stream->dec_tgtlen);
1150 |
1151 | printf("window_count = %d\n", stream->dec_window_count);
1152 | stream->current_window = stream->dec_window_count;
1153 |
1154 | if (XOFF_T_OVERFLOW (stream->dec_winstart, stream->dec_tgtlen))
1155 | {
1156 | stream->msg = "decoder file offset overflow";
1157 | return XD3_INVALID_INPUT;
1158 | }
1159 |
1160 | stream->dec_winstart += stream->dec_tgtlen;
1161 | printf("dec_winstart = %d\n", stream->dec_winstart);
1162 |
1163 | if ((stream->dec_win_ind & VCD_INVWIN) != 0)
1164 | {
1165 | stream->msg = "unrecognized window indicator bits set";
1166 | return XD3_INVALID_INPUT;
1167 | }
1168 |
1169 | printf("xd3_decode_init_window\n");
1170 | if ((ret = xd3_decode_init_window (stream))) { return ret; }
1171 |
1172 | stream->dec_state = DEC_CPYLEN;
1173 |
1174 | IF_DEBUG2 (DP(RINT "--------- TARGET WINDOW %"Q"u -----------\n",
1175 | stream->current_window));
1176 | }
1177 |
1178 | case DEC_CPYLEN:
1179 | srcortgt = SRCORTGT(stream->dec_win_ind);
1180 | printf("srcortgt = %d\n", srcortgt);
1181 | /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */
1182 | printf("DEC_CPYLEN: dec_cpylen = %d\n", stream->dec_cpylen);
1183 | printf("DEC_CPYLEN: get size if SRCORTGT(%d), pos = %d\n", srcortgt, stream->total_in);
1184 | SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen,
1185 | DEC_CPYOFF);
1186 | if (SRCORTGT (stream->dec_win_ind)) {
1187 | printf("dec_cpylen = %d\n", stream->dec_cpylen);
1188 | }
1189 |
1190 | /* Set the initial, logical decoder position (HERE address) in
1191 | * dec_position. This is set to just after the source/copy
1192 | * window, as we are just about to output the first byte of
1193 | * target window. */
1194 | stream->dec_position = stream->dec_cpylen;
1195 |
1196 | case DEC_CPYOFF:
1197 | /* Copy window offset: only if VCD_SOURCE or VCD_TARGET is set */
1198 | printf("DEC_CPYOFF: get size if SRCORTGT(%d), pos = %d\n", srcortgt, stream->total_in);
1199 | OFFSET_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpyoff,
1200 | DEC_ENCLEN);
1201 | if (SRCORTGT (stream->dec_win_ind)) {
1202 | printf("dec_cpyoff = %d\n", stream->dec_cpyoff);
1203 | }
1204 |
1205 | /* Copy offset and copy length may not overflow. */
1206 | if (XOFF_T_OVERFLOW (stream->dec_cpyoff, stream->dec_cpylen))
1207 | {
1208 | stream->msg = "decoder copy window overflows a file offset";
1209 | return XD3_INVALID_INPUT;
1210 | }
1211 |
1212 | /* Check copy window bounds: VCD_TARGET window may not exceed
1213 | current position. */
1214 | if ((stream->dec_win_ind & VCD_TARGET) &&
1215 | (stream->dec_cpyoff + stream->dec_cpylen >
1216 | stream->dec_winstart))
1217 | {
1218 | stream->msg = "VCD_TARGET window out of bounds";
1219 | return XD3_INVALID_INPUT;
1220 | }
1221 |
1222 | case DEC_ENCLEN:
1223 | /* Length of the delta encoding */
1224 | SIZE_CASE(1, stream->dec_enclen, DEC_TGTLEN);
1225 | printf("DEC_ENCLEN: dec_enclen = %d\n", stream->dec_enclen);
1226 | case DEC_TGTLEN:
1227 | /* Length of target window */
1228 | SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND);
1229 | printf("DEC_TGTLEN: dec_tgtlen = %d\n", stream->dec_tgtlen);
1230 | //printf("\n");
1231 | //printf("target window length = %d\n", stream->dec_tgtlen);
1232 | //printf("\n");
1233 |
1234 | /* Set the maximum decoder position, beyond which we should not
1235 | * decode any data. This is the maximum value for dec_position.
1236 | * This may not exceed the size of a usize_t. */
1237 | if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen))
1238 | {
1239 | stream->msg = "decoder target window overflows a usize_t";
1240 | return XD3_INVALID_INPUT;
1241 | }
1242 |
1243 | /* Check for malicious files. */
1244 | if (stream->dec_tgtlen > XD3_HARDMAXWINSIZE)
1245 | {
1246 | stream->msg = "hard window size exceeded";
1247 | return XD3_INVALID_INPUT;
1248 | }
1249 |
1250 | stream->dec_maxpos = stream->dec_cpylen + stream->dec_tgtlen;
1251 |
1252 | case DEC_DELIND:
1253 | /* Delta indicator */
1254 | BYTE_CASE(1, stream->dec_del_ind, DEC_DATALEN);
1255 | printf("DEC_DELIND: dec_del_ind = %d\n", stream->dec_del_ind);
1256 |
1257 | if ((stream->dec_del_ind & VCD_INVDEL) != 0)
1258 | {
1259 | stream->msg = "unrecognized delta indicator bits set";
1260 | return XD3_INVALID_INPUT;
1261 | }
1262 |
1263 | /* Delta indicator is only used with secondary compression. */
1264 | if ((stream->dec_del_ind != 0) && (stream->sec_type == NULL))
1265 | {
1266 | stream->msg = "invalid delta indicator bits set";
1267 | return XD3_INVALID_INPUT;
1268 | }
1269 |
1270 | /* Section lengths */
1271 | case DEC_DATALEN:
1272 | SIZE_CASE(1, stream->data_sect.size, DEC_INSTLEN);
1273 | printf("DEC_DATALEN: data_sect size = %d\n", stream->data_sect.size);
1274 | case DEC_INSTLEN:
1275 | SIZE_CASE(1, stream->inst_sect.size, DEC_ADDRLEN);
1276 | printf("DEC_INSTLEN: inst_sect size = %d\n", stream->inst_sect.size);
1277 | case DEC_ADDRLEN:
1278 | SIZE_CASE(1, stream->addr_sect.size, DEC_CKSUM);
1279 | printf("DEC_ADDRLEN: addr_sect size = %d\n", stream->addr_sect.size);
1280 |
1281 | case DEC_CKSUM:
1282 | printf("DEC_CKSUM: get checksum if VCD_ADLER32 pos = %d\n", stream->total_in);
1283 | /* Window checksum. */
1284 | if ((stream->dec_win_ind & VCD_ADLER32) != 0)
1285 | {
1286 | int i;
1287 |
1288 | if ((ret = xd3_decode_bytes (stream, stream->dec_cksum,
1289 | & stream->dec_cksumbytes, 4)))
1290 | {
1291 | return ret;
1292 | }
1293 | dumpBytes(stream->dec_cksum, 4);
1294 |
1295 | for (i = 0; i < 4; i += 1)
1296 | {
1297 | stream->dec_adler32 =
1298 | (stream->dec_adler32 << 8) | stream->dec_cksum[i];
1299 | }
1300 | printf("stream->dec_adler32 = %d\n", stream->dec_adler32);
1301 | }
1302 |
1303 | //printf("\n");
1304 | stream->dec_state = DEC_DATA;
1305 |
1306 | /* Check dec_enclen for redundency, otherwise it is not really used. */
1307 | {
1308 | usize_t enclen_check =
1309 | (1 + (xd3_sizeof_size (stream->dec_tgtlen) +
1310 | xd3_sizeof_size (stream->data_sect.size) +
1311 | xd3_sizeof_size (stream->inst_sect.size) +
1312 | xd3_sizeof_size (stream->addr_sect.size)) +
1313 | stream->data_sect.size +
1314 | stream->inst_sect.size +
1315 | stream->addr_sect.size +
1316 | ((stream->dec_win_ind & VCD_ADLER32) ? 4 : 0));
1317 |
1318 | if (stream->dec_enclen != enclen_check)
1319 | {
1320 | stream->msg = "incorrect encoding length (redundent)";
1321 | return XD3_INVALID_INPUT;
1322 | }
1323 | }
1324 |
1325 | /* Returning here gives the application a chance to inspect the
1326 | * header, skip the window, etc. */
1327 | if (stream->current_window == 0) { return XD3_GOTHEADER; }
1328 | else { return XD3_WINSTART; }
1329 |
1330 | case DEC_DATA:
1331 | case DEC_INST:
1332 | case DEC_ADDR:
1333 | /* Next read the three sections. */
1334 | if ((ret = xd3_decode_sections (stream))) { return ret; }
1335 | //printf("data_sect.size = %d\n", stream->data_sect.size);
1336 | dumpBytes(stream->data_sect.buf, stream->data_sect.size);
1337 | //printf("inst_sect.size = %d\n", stream->inst_sect.size);
1338 | dumpBytes(stream->inst_sect.buf, stream->inst_sect.size);
1339 | //printf("addr_sect.size = %d\n", stream->addr_sect.size);
1340 | dumpBytes(stream->addr_sect.buf, stream->addr_sect.size);
1341 |
1342 | case DEC_EMIT:
1343 | printf("DEC_EMIT:\n");
1344 |
1345 | /* To speed VCD_SOURCE block-address calculations, the source
1346 | * cpyoff_blocks and cpyoff_blkoff are pre-computed. */
1347 | if (stream->dec_win_ind & VCD_SOURCE)
1348 | {
1349 | xd3_source *src = stream->src;
1350 |
1351 | if (src == NULL)
1352 | {
1353 | stream->msg = "source input required";
1354 | return XD3_INVALID_INPUT;
1355 | }
1356 |
1357 | //printf("++++++++++++++++\n");
1358 | printf("stream->dec_cpyoff = %d\n", stream->dec_cpyoff);
1359 | //printf("src->cpyoff_blkoff = %d\n", src->cpyoff_blkoff);
1360 | xd3_blksize_div(stream->dec_cpyoff, src,
1361 | &src->cpyoff_blocks,
1362 | &src->cpyoff_blkoff);
1363 | //printf("stream->dec_cpyoff = %d\n", stream->dec_cpyoff);
1364 | //printf("src->cpyoff_blocks = %d\n", src->cpyoff_blocks);
1365 | printf("src->cpyoff_blkoff = %d\n", src->cpyoff_blkoff);
1366 | //printf("++++++++++++++++\n");
1367 |
1368 | IF_DEBUG2(DP(RINT
1369 | "[decode_cpyoff] %"Q"u "
1370 | "cpyblkno %"Q"u "
1371 | "cpyblkoff %"W"u "
1372 | "blksize %"W"u\n",
1373 | stream->dec_cpyoff,
1374 | src->cpyoff_blocks,
1375 | src->cpyoff_blkoff,
1376 | src->blksize));
1377 | }
1378 |
1379 | /* xd3_decode_emit returns XD3_OUTPUT on every success. */
1380 | if ((ret = xd3_decode_emit (stream)) == XD3_OUTPUT)
1381 | {
1382 | stream->total_out += stream->avail_out;
1383 | }
1384 |
1385 | return ret;
1386 |
1387 | case DEC_FINISH:
1388 | {
1389 | if (stream->dec_win_ind & VCD_TARGET)
1390 | {
1391 | if (stream->dec_lastwin == NULL)
1392 | {
1393 | stream->dec_lastwin = stream->next_out;
1394 | stream->dec_lastspace = stream->space_out;
1395 | }
1396 | else
1397 | {
1398 | xd3_swap_uint8p (& stream->dec_lastwin,
1399 | & stream->next_out);
1400 | xd3_swap_usize_t (& stream->dec_lastspace,
1401 | & stream->space_out);
1402 | }
1403 | }
1404 |
1405 | stream->dec_lastlen = stream->dec_tgtlen;
1406 | stream->dec_laststart = stream->dec_winstart;
1407 | stream->dec_window_count += 1;
1408 |
1409 | /* Note: the updates to dec_winstart & current_window are
1410 | * deferred until after the next DEC_WININD byte is read. */
1411 | stream->dec_state = DEC_WININD;
1412 | return XD3_WINFINISH;
1413 | }
1414 |
1415 | default:
1416 | stream->msg = "invalid state";
1417 | return XD3_INVALID_INPUT;
1418 | }
1419 | }
1420 |
1421 | #endif // _XDELTA3_DECODE_H_
1422 |
--------------------------------------------------------------------------------
/xdelta3_decoder.js:
--------------------------------------------------------------------------------
1 | /////////////////////////////////////////////////////////////
2 | // //
3 | // DO NOT EDIT THIS FILE! //
4 | // //
5 | // THIS FILE WILL BE OVERWRITTEN DURING THE BUILD PROCESS! //
6 | // //
7 | // EDIT xdelta3_decoder_with_debug.js //
8 | // //
9 | // THIS FILE IS GENERATED FILE BY REMOVING THE DEBUG //
10 | // COMMENTS FROM xdelta3_decoder_with_debug.js //
11 | // //
12 | /////////////////////////////////////////////////////////////
13 | 'use strict';
14 | /**
15 | * xdelta3 - delta compression tools and library
16 | * Copyright 2016 Joshua MacDonald
17 | *
18 | * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
19 | * 2011, 2012, 2013, 2014, 2015 josh.macdonald@gmail.com
20 | *
21 | * Licensed under the Apache License, Version 2.0 (the "License");
22 | * you may not use this file except in compliance with the License.
23 | * You may obtain a copy of the License at
24 | *
25 | * http://www.apache.org/licenses/LICENSE-2.0
26 | *
27 | * Unless required by applicable law or agreed to in writing, software
28 | * distributed under the License is distributed on an "AS IS" BASIS,
29 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30 | * See the License for the specific language governing permissions and
31 | * limitations under the License.
32 | */
33 |
34 | /**
35 | * @fileoverview This file implements XDelta3 decoding.
36 | * Note: the subroutine, method, field, and variable names do not follow
37 | * Javascript style guide but reflect the names in the XDelta3 C++ files. This
38 | * makes is to make it easier to keep this code in synch with the C++ code.
39 | *
40 | * The C++ code is very casual about initializing and accessing data structures.
41 | * This code is a port and follows that code style.
42 | */
43 |
44 | (function() {
45 |
46 | // Check for namespace collision.
47 | if ((typeof window['XDelta3Decoder'] != 'undefined')
48 | || (typeof window.XDelta3Decoder != 'undefined')) {
49 | throw new Error('XDelta3Decoder already defined.');
50 | }
51 |
52 | /**
53 | * The public class.
54 | */
55 | window.XDelta3Decoder = function(debugOutput) { //
56 | };
57 |
58 | var XDelta3Decoder = window.XDelta3Decoder;
59 |
60 | /**
61 | * The public API to decode a delta possibly with a source.
62 | * @param {!Uint8Array} delta The Xdelta delta file.
63 | * @param {Uint8Array=} opt_source The source file (optional).
64 | * @return {!ArrayBuffer}
65 | */
66 | XDelta3Decoder.decode = function(delta, opt_source) {
67 | if (typeof opt_source != 'object') {
68 | opt_source = null;
69 | }
70 | var xdelta3 = new _XDelta3Decoder(delta, opt_source);
71 | var uint8Bytes = xdelta3.xd3_decode_input();
72 | return uint8Bytes.buffer;
73 | }
74 |
75 | /**
76 | * The public API to disable debug printf code.
77 | */
78 |
79 | // Define debug fallback routines if needed.
80 |
81 | /**
82 | * The XDelta3 data commands.
83 | */
84 | /** @type {number} */
85 | var XD3_NOOP = 0;
86 | /** @type {number} */
87 | var XD3_ADD = 1;
88 | /** @type {number} */
89 | var XD3_RUN = 2;
90 | /** @type {number} */
91 | var XD3_CPY = 3;
92 |
93 | /** @type {number} */
94 | var MIN_MATCH = 4;
95 |
96 | /**
97 | * Header indicator bits.
98 | */
99 | /** @type {number} */
100 | var VCD_SECONDARY = 1;
101 | /** @type {number} */
102 | var VCD_CODETABLE = 2;
103 | /** @type {number} */
104 | var VCD_APPHEADER = 4;
105 | /** @type {number} */
106 | var VCD_INVHDR = ~(VCD_SECONDARY | VCD_CODETABLE | VCD_APPHEADER);
107 |
108 | var VCD_SOURCE = 0x01;
109 | var VCD_TARGET = 0x02;
110 | var VCD_ADLER32 = 0x04;
111 |
112 |
113 | /**
114 | * Declares the main decode class.
115 | * @param {!Uint8Array} delta The Xdelta3 delta file.
116 | * @param {Uint8Array=} opt_source The source file (optional).
117 | * @constructor
118 | */
119 | function _XDelta3Decoder(delta, opt_source) {
120 | /** @type {!Uint8Array} */
121 | this.delta = delta;
122 |
123 | var source = opt_source || new Uint8Array(1);
124 | /** @type {!DataObject} */
125 | this.source = new DataObject(source);
126 |
127 | /** @type {!xd3_source} */
128 | this.src = new xd3_source();
129 |
130 | /** @type {number} */
131 | this.position = 0;
132 |
133 | /** @type {number} */
134 | this.dec_window_count = 0;
135 |
136 | /** @type {number} */
137 | this.dec_winstart = 0;
138 |
139 | /**
140 | * The length of the target window.
141 | * @type {number}
142 | */
143 | this.dec_tgtlen = 0;
144 |
145 | /**
146 | * The Alder32 checksum. This is used to verify the decoded bytes checksum
147 | * matches the checksum of the original.
148 | */
149 | this.dec_adler32 = 0;
150 |
151 | /**
152 | * First half instruction.
153 | * @type {!xd3_hinst}
154 | */
155 | this.dec_current1 = new xd3_hinst();
156 |
157 | /**
158 | * Second half instruction.
159 | * @type {!xd3_hinst}
160 | */
161 | this.dec_current2 = new xd3_hinst();
162 |
163 | /** @type {!xd3_desect} */
164 | this.data_sect = new xd3_desect();
165 |
166 | /** @type {!xd3_desect} */
167 | this.inst_sect = new xd3_desect();
168 |
169 | /** @type {!xd3_desect} */
170 | this.addr_sect = new xd3_desect();
171 |
172 | /**
173 | * The address cache.
174 | * @type {!xd3_addr_cache}
175 | */
176 | this.acache = new xd3_addr_cache(
177 | __rfc3284_code_table_desc.near_modes,
178 | __rfc3284_code_table_desc.same_modes);
179 | }
180 |
181 | /**
182 | * Allocates the address caches.
183 | */
184 | _XDelta3Decoder.prototype.xd3_alloc_cache = function() {
185 | this.acache.near_array = null; // not sure this is needed
186 | this.acache.same_array = null; // not sure this is needed
187 | if (this.acache.s_near > 0) {
188 | this.acache.near_array = allocArray(this.acache.s_near, 0);
189 | }
190 | if (this.acache.s_same > 0) {
191 | this.acache.same_array = allocArray(this.acache.s_same * 256, 0);
192 | }
193 | };
194 |
195 | /**
196 | * Parses the delta file data and produces the targetWindow data.
197 | * @return {!Uint8Array}
198 | */
199 | _XDelta3Decoder.prototype.xd3_decode_input = function() {
200 |
201 | if (this.delta[0] != 0xD6 || // 'V' with MSB set
202 | this.delta[1] != 0xC3 || // 'C' with MSB set
203 | this.delta[2] != 0xC4 || // 'D' with MSB set
204 | this.delta[3] != 0) { // unused but be set to zero
205 | throw new Error('XD3_INVALID_INPUT invalid magic');
206 | }
207 | this.position = 4;
208 |
209 | this.dec_hdr_ind = this.delta[this.position++];
210 | if (this.dec_hdr_ind & VCD_INVHDR) {
211 | throw new Error('VCD_INVHDR unrecognized header indicator bits set');
212 | }
213 |
214 | if (this.dec_hdr_ind & VCD_SECONDARY) {
215 | throw new Error('VCD_SECONDARY not implemented');
216 | }
217 |
218 | if (this.dec_hdr_ind & VCD_CODETABLE) {
219 | throw new Error('VCD_CODETABLE support was removed');
220 | } else {
221 | /* Use the default table. */
222 | this.acache.s_near = __rfc3284_code_table_desc.near_modes;
223 | this.acache.s_same = __rfc3284_code_table_desc.same_modes;
224 | this.code_table = xd3_rfc3284_code_table();
225 | }
226 |
227 | this.xd3_alloc_cache();
228 |
229 | if (this.dec_hdr_ind & VCD_APPHEADER) {
230 | this.dec_appheadsz = this.getInteger();
231 | // Note: appHeader does not have a 0-termination.
232 | this.dec_apphead = this.xd3_alloc(this.dec_appheadsz + 1);
233 | this.xd3_decode_bytes(this.dec_apphead, 0, this.dec_appheadsz);
234 | this.dec_apphead[this.dec_appheadsz + 1] = 0;
235 | }
236 |
237 | //var targetLength = 0;
238 | while (true) {
239 | if (this.position >= this.delta.length) {
240 | break;
241 | }
242 | //targetLength +=
243 | this.handleWindow();
244 | }
245 | return this.dec_buffer.bytes;
246 | };
247 |
248 | _XDelta3Decoder.prototype.xd3_decode_init_window = function() {
249 | this.dec_cpylen = 0;
250 | this.dec_cpyoff = 0;
251 | // this.dec_cksumbytes = 0;
252 |
253 | xd3_init_cache(this.acache);
254 | }
255 |
256 | _XDelta3Decoder.prototype.handleWindow = function() {
257 | this.dec_win_ind = this.delta[this.position++]; // DEC_WININD
258 |
259 | if (this.dec_win_ind & ~7) {
260 | throw new Error('VCD_INVWIN unexpected bits set');
261 | }
262 |
263 | this.current_window = this.dec_window_count;
264 |
265 | this.dec_winstart += this.dec_tgtlen;
266 |
267 | this.xd3_decode_init_window();
268 | var SRCORTGT = VCD_SOURCE | VCD_TARGET;
269 | var srcortgt = SRCORTGT & this.dec_win_ind;
270 |
271 | // If using a source or target data segment: read the lenght and position
272 | // integers.
273 | if (srcortgt) {
274 | this.dec_cpylen = this.getInteger(); // DEC_CPYLEN
275 | }
276 | this.dec_position = this.dec_cpylen;
277 | if (srcortgt) {
278 | var sourcePosition = this.getInteger(); // DEC_CPYOFF
279 | this.dec_cpyoff = sourcePosition;
280 | }
281 |
282 | this.dec_enclen = this.getInteger(); // DEC_ENCLEN
283 |
284 | // Calculate the position if the delta was actually read.
285 | // var positionAfterDelta = this.position + this.dec_enclen;
286 |
287 | // Get the target window length.
288 | this.dec_tgtlen = this.getInteger(); // DEC_TGTLEN
289 |
290 | this.dec_del_ind = this.getByte(); // DEC_DELIND
291 |
292 | this.data_sect.size = this.getInteger(); // DEC_DATALEN
293 | this.inst_sect.size = this.getInteger(); // DEC_INSTLEN
294 | this.addr_sect.size = this.getInteger(); // DEC_ADDRLEN
295 |
296 | if (this.dec_win_ind & VCD_ADLER32) { // DEC_CKSUM
297 | this.dec_cksum = this.xd3_decode_allocate(4);
298 | for (var i = 0; i < 4; i += 1) {
299 | this.dec_adler32 = (this.dec_adler32 << 8) | this.dec_cksum[i];
300 | }
301 | }
302 |
303 | this.xd3_decode_sections();
304 |
305 | /* In the C++ code:
306 | * To speed VCD_SOURCE block-address calculations, the source
307 | * cpyoff_blocks and cpyoff_blkoff are pre-computed.
308 | * However, in this Javascript code there is no 'blocks'.
309 | */
310 | if (this.dec_win_ind & VCD_SOURCE) {
311 | this.src.cpyoff_blkoff = this.dec_cpyoff;
312 | }
313 | this.xd3_decode_emit();
314 |
315 | return this.dec_tgtlen;
316 | };
317 |
318 | /**
319 | * This function only has code if the preprocessor statement
320 | * "#if SECONDARY_ANY" is set. SECONDARY_ANY does not seem to be set.
321 | */
322 | _XDelta3Decoder.prototype.xd3_decode_secondary_sections = function() { //
323 | };
324 |
325 | /**
326 | * @param {!xd3_desect} sect
327 | */
328 | _XDelta3Decoder.prototype.xd3_decode_section = function(sect) {
329 | // It is possible to just point into the buffer but perhaps that can be done
330 | // later.
331 | sect.bytes = this.xd3_decode_allocate(sect.size);
332 | };
333 |
334 | _XDelta3Decoder.prototype.xd3_decode_sections = function() {
335 | this.xd3_decode_section(this.data_sect);
336 | this.xd3_decode_section(this.inst_sect);
337 | this.xd3_decode_section(this.addr_sect);
338 |
339 | this.xd3_decode_secondary_sections();
340 |
341 | this.xd3_decode_setup_buffers();
342 | };
343 |
344 | _XDelta3Decoder.prototype.xd3_decode_setup_buffers = function() {
345 | this.dec_buffer = new DataObject(new Uint8Array(this.dec_tgtlen));
346 | };
347 |
348 | var VCD_SELF = 0;
349 | var VCD_HERE = 1;
350 |
351 | /**
352 | * xd3_decode_address
353 | * @param {number} here
354 | * @param {number} mode
355 | * @param {!xd3_desect} sect
356 | */
357 | _XDelta3Decoder.prototype.xd3_decode_address = function(here, mode, sect) {
358 | var val;
359 | var same_start = 2 + this.acache.s_near;
360 |
361 | if (mode < same_start) {
362 | val = sect.getInteger();
363 | switch (mode) {
364 | case VCD_SELF:
365 | break;
366 | case VCD_HERE:
367 | // var old_val = val;
368 | val = here - val;
369 | break;
370 | default:
371 | val += this.acache.near_array[mode - 2];
372 | }
373 | } else {
374 | mode -= same_start;
375 | var offset = sect.getByte();
376 | val = this.acache.same_array[mode * 256 + offset];
377 | }
378 |
379 | this.xd3_update_cache(this.acache, val);
380 |
381 | return val;
382 | };
383 |
384 | /**
385 | * @param {!xd3_addr_cache} acache
386 | * @param {number} addr
387 | */
388 | _XDelta3Decoder.prototype.xd3_update_cache = function(acache, addr) {
389 | if (acache.s_near > 0) {
390 | acache.near_array[acache.next_slot] = addr;
391 | acache.next_slot = (acache.next_slot + 1) % acache.s_near;
392 | }
393 |
394 | if (acache.s_same > 0) {
395 | acache.same_array[addr % (acache.s_same * 256)] = addr;
396 | }
397 | };
398 |
399 | /**
400 | * @param {!xd3_hinst} inst
401 | */
402 | _XDelta3Decoder.prototype.xd3_decode_output_halfinst = function(inst) {
403 | var take = inst.size;
404 | var blkoff;
405 |
406 | switch (inst.type) {
407 | case XD3_RUN:
408 | var val = this.data_sect.getByte();
409 | this.dec_buffer.fill(val, take);
410 | break;
411 |
412 | case XD3_ADD:
413 | this.dec_buffer.copySect(this.data_sect, take);
414 | break;
415 |
416 | default:
417 | var overlap;
418 | var overlap_pos;
419 | if (inst.addr < this.dec_cpylen) {
420 | overlap = 0;
421 | if (this.dec_win_ind & VCD_TARGET) {
422 | throw new Error('VCD_TARGET not supported');
423 | } else {
424 | blkoff = this.src.cpyoff_blkoff;
425 | blkoff = this.dec_cpyoff + inst.addr;
426 | }
427 | } else {
428 | overlap = 1;
429 | overlap_pos = inst.addr - this.dec_cpylen;
430 | }
431 | if (overlap) {
432 | this.dec_buffer.copyBytes(this.dec_buffer.bytes, overlap_pos, take);
433 | } else {
434 | this.dec_buffer.copyBytes(this.source.bytes, blkoff, take);
435 | }
436 | }
437 | };
438 |
439 | /**
440 | * xref: xd3_decode_parse_halfinst
441 | * @param {!xd3_hinst} inst
442 | */
443 | _XDelta3Decoder.prototype.xd3_decode_parse_halfinst = function(inst) {
444 | // Get size and address if necessary.
445 | if (inst.size == 0) {
446 | inst.size = this.inst_sect.getInteger();
447 | }
448 |
449 | /* For copy instructions, read address. */
450 | if (inst.type >= XD3_CPY) {
451 | var mode = inst.type - XD3_CPY;
452 | inst.addr =
453 | this.xd3_decode_address(this.dec_position, mode, this.addr_sect);
454 | }
455 |
456 | this.dec_position += inst.size;
457 | };
458 |
459 | /**
460 | * xref: xd3_decode_instruction
461 | */
462 | _XDelta3Decoder.prototype.xd3_decode_instruction = function() {
463 | var code_table = this.code_table;
464 | var instPair = this.inst_sect.getByte();
465 |
466 | this.dec_current1.type = code_table.tableRows[instPair].type1;
467 | this.dec_current1.size = code_table.tableRows[instPair].size1;
468 | // dec_current1.addr keeps it previous value.
469 |
470 | this.dec_current2.type = code_table.tableRows[instPair].type2;
471 | this.dec_current2.size = code_table.tableRows[instPair].size2;
472 | // dec_current2.addr keeps it previous value.
473 |
474 |
475 | /* For each instruction with a real operation, decode the
476 | * corresponding size and addresses if necessary. Assume a
477 | * code-table may have NOOP in either position, although this is
478 | * unlikely. */
479 | if (this.dec_current1.type != XD3_NOOP) {
480 | this.xd3_decode_parse_halfinst(this.dec_current1);
481 | }
482 | if (this.dec_current2.type != XD3_NOOP) {
483 | this.xd3_decode_parse_halfinst(this.dec_current2);
484 | }
485 | };
486 |
487 | _XDelta3Decoder.prototype.xd3_decode_finish_window = function() {
488 | // stream->dec_winbytes = 0;
489 | // stream->dec_state = DEC_FINISH;
490 | this.data_sect.pos = 0;
491 | this.inst_sect.pos = 0;
492 | this.addr_sect.pos = 0;
493 | };
494 |
495 | _XDelta3Decoder.prototype.xd3_decode_emit = function() {
496 |
497 | var instLength = this.inst_sect.bytes.byteLength;
498 | /* Decode next instruction pair. */
499 | while (this.inst_sect.pos < instLength) {
500 | this.xd3_decode_instruction();
501 |
502 | /* Output dec_current1 */
503 | if (this.dec_current1.type != XD3_NOOP) {
504 | this.xd3_decode_output_halfinst(this.dec_current1);
505 | }
506 | /* Output dec_current2 */
507 | if (this.dec_current2.type != XD3_NOOP) {
508 | this.xd3_decode_output_halfinst(this.dec_current2);
509 | }
510 | }
511 | if (this.dec_win_ind & VCD_ADLER32) {
512 | var a32 = adler32(1, this.dec_buffer.bytes, 0, this.dec_tgtlen);
513 | if (a32 != this.dec_adler32) {
514 | throw new Error('target window checksum mismatch');
515 | }
516 | }
517 |
518 | /* Finished with a window. */
519 | this.xd3_decode_finish_window();
520 | };
521 |
522 | _XDelta3Decoder.prototype.xd3_alloc = function(length) {
523 | return new Uint8Array(length);
524 | };
525 |
526 | _XDelta3Decoder.prototype.xd3_decode_bytes = function(bytes, pos, length) {
527 | for (var i = 0; i < length; i++) {
528 | bytes[pos + i] = this.delta[this.position++];
529 | }
530 | };
531 |
532 | _XDelta3Decoder.prototype.xd3_decode_allocate = function(length) {
533 | var bytes =
534 | new Uint8Array(this.delta.slice(this.position, this.position + length));
535 | this.position += length;
536 | return bytes;
537 | };
538 |
539 | _XDelta3Decoder.prototype.getByte = function() {
540 | return this.delta[this.position++];
541 | };
542 |
543 | _XDelta3Decoder.prototype.getInteger = function() {
544 | var maxBytes = Math.min(20, this.delta.length - this.position);
545 | var integer = 0;
546 | for (var i = 0; i < maxBytes; i++) {
547 | var aPart = this.delta[this.position++];
548 | integer += aPart & 0x7F;
549 | if (!(aPart & 0x80)) {
550 | return integer;
551 | }
552 | integer <<= 7;
553 | }
554 | throw new Error('delta integer too long');
555 | };
556 |
557 | /**
558 | * The code table.
559 | * @param {!Array} tableRows
560 | * @constructor
561 | * @struct
562 | */
563 | var xd3_dinst_table = function(tableRows) {
564 | /** @type {!Array} */
565 | this.tableRows = tableRows;
566 | };
567 |
568 | /**
569 | * xd3_hinst
570 | * @constructor
571 | */
572 | function xd3_hinst() {
573 | this.type = XD3_NOOP;
574 | this.size = 0;
575 | this.addr = 0;
576 | }
577 |
578 | /**
579 | * The code-table double instruction.
580 | * @constructor
581 | */
582 | function xd3_dinst() {
583 | /** @type {number} */
584 | this.type1 = XD3_NOOP;
585 | /** @type {number} */
586 | this.size1 = 0;
587 | /** @type {number} */
588 | this.type2 = XD3_NOOP;
589 | /** @type {number} */
590 | this.size2 = 0;
591 | }
592 |
593 | /**
594 | * @param {!xd3_code_table_desc} desc
595 | * @return {!xd3_dinst_table}
596 | */
597 | function xd3_build_code_table(desc) {
598 | var row = 0;
599 | var tableRows = new Array(256);
600 | for (var i = 0; i < 256; i++) {
601 | tableRows[i] = new xd3_dinst();
602 | }
603 | var cpyModes = 2 + desc.near_modes + desc.same_modes;
604 |
605 | // The single RUN command.
606 | tableRows[row++].type1 = XD3_RUN;
607 |
608 | // The ADD only commands.
609 | tableRows[row++].type1 = XD3_ADD;
610 | for (var size1 = 1; size1 <= desc.add_sizes; size1++) {
611 | tableRows[row].type1 = XD3_ADD;
612 | tableRows[row++].size1 = size1;
613 | }
614 |
615 | // The Copy only commands.
616 | for (var mode = 0; mode < cpyModes; mode++) {
617 | tableRows[row++].type1 = XD3_CPY + mode;
618 |
619 | for (var size1 = MIN_MATCH; size1 < MIN_MATCH + desc.cpy_sizes; size1++) {
620 | tableRows[row].type1 = XD3_CPY + mode;
621 | tableRows[row++].size1 = size1;
622 | }
623 | }
624 |
625 | // The Add/Copy commands.
626 | for (var mode = 0; mode < cpyModes; mode++) {
627 | for (var size1 = 1; size1 <= desc.addcopy_add_max; size1++) {
628 | var max = (mode < 2 + desc.near_modes) ? //
629 | desc.addcopy_near_cpy_max :
630 | desc.addcopy_same_cpy_max;
631 | for (var size2 = MIN_MATCH; size2 <= max; size2++) {
632 | tableRows[row].type1 = XD3_ADD;
633 | tableRows[row].size1 = size1;
634 | tableRows[row].type2 = XD3_CPY + mode;
635 | tableRows[row++].size2 = size2;
636 | }
637 | }
638 | }
639 |
640 | // The Copy/Add commands.
641 | for (var mode = 0; mode < cpyModes; mode++) {
642 | var max = (mode < 2 + desc.near_modes) ? //
643 | desc.copyadd_near_cpy_max :
644 | desc.copyadd_same_cpy_max;
645 | for (var size1 = MIN_MATCH; size1 <= max; size1++) {
646 | for (var size2 = 1; size2 <= desc.copyadd_add_max; size2++) {
647 | tableRows[row].type1 = XD3_CPY + mode;
648 | tableRows[row].size1 = size1;
649 | tableRows[row].type2 = XD3_ADD;
650 | tableRows[row++].size2 = size2;
651 | }
652 | }
653 | }
654 |
655 | return new xd3_dinst_table(tableRows);
656 | }
657 |
658 |
659 | /**
660 | * @constructor
661 | */
662 | function xd3_code_table_desc() {
663 | this.add_sizes = 0;
664 | this.near_modes = 0;
665 | this.same_modes = 0;
666 | this.cpy_sizes = 0;
667 |
668 | this.addcopy_add_max = 0;
669 | this.addcopy_near_cpy_max = 0;
670 | this.addcopy_same_cpy_max = 0;
671 |
672 | this.copyadd_add_max = 0;
673 | this.copyadd_near_cpy_max = 0;
674 | this.copyadd_same_cpy_max = 0;
675 | }
676 |
677 |
678 | /**
679 | * This builds the __rfc3284_code_table_desc
680 | * Assumes a single RUN instruction
681 | * Assumes that MIN_MATCH is 4.
682 | * @return {!xd3_code_table_desc}
683 | */
684 | function build_rfc3284_code_table_desc() {
685 | var desc = new xd3_code_table_desc();
686 | desc.add_sizes = 17;
687 | desc.near_modes = 4;
688 | desc.same_modes = 3;
689 | desc.cpy_sizes = 15;
690 |
691 | desc.addcopy_add_max = 4;
692 | desc.addcopy_near_cpy_max = 6;
693 | desc.addcopy_same_cpy_max = 4;
694 |
695 | desc.copyadd_add_max = 1;
696 | desc.copyadd_near_cpy_max = 4;
697 | desc.copyadd_same_cpy_max = 4;
698 |
699 | // xd3_code_table_sizes addcopy_max_sizes[MAX_MODES];
700 | // { {6,163,3},{6,175,3},{6,187,3},{6,199,3},{6,211,3},{6,223,3},
701 | // {4,235,1},{4,239,1},{4,243,1} },
702 |
703 | // xd3_code_table_sizes copyadd_max_sizes[MAX_MODES];
704 | // { {4,247,1},{4,248,1},{4,249,1},{4,250,1},{4,251,1},{4,252,1},
705 | // {4,253,1},{4,254,1},{4,255,1} },
706 |
707 | return desc;
708 | }
709 |
710 | var __rfc3284_code_table_desc = build_rfc3284_code_table_desc();
711 |
712 | var A32_BASE = 65521; /* Largest prime smaller than 2^16 */
713 | var A32_NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2
714 | + (n+1)(BASE-1) <= 2^32-1 */
715 |
716 | // 1140 #define A32_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
717 | // 1141 #define A32_DO2(buf,i) A32_DO1(buf,i); A32_DO1(buf,i+1);
718 | // 1142 #define A32_DO4(buf,i) A32_DO2(buf,i); A32_DO2(buf,i+2);
719 | // 1143 #define A32_DO8(buf,i) A32_DO4(buf,i); A32_DO4(buf,i+4);
720 | // 1144 #define A32_DO16(buf) A32_DO8(buf,0); A32_DO8(buf,8);
721 |
722 |
723 | /**
724 | * Calculated the Adler32 checksum.
725 | * @param {number} adler I'm not sure what this is.
726 | * @param {!Uint8Array} buf
727 | * @param {number} pos
728 | * @param {number} len
729 | * @return {number}
730 | */
731 | function adler32(adler, buf, pos, len) {
732 | var s1 = adler & 0xffff;
733 | var s2 = (adler >> 16) & 0xffff;
734 | var k;
735 |
736 | while (len > 0) {
737 | k = (len < A32_NMAX) ? len : A32_NMAX;
738 | len -= k;
739 |
740 | if (k != 0) {
741 | do {
742 | s1 += buf[pos++];
743 | s2 += s1;
744 | } while (--k);
745 | }
746 |
747 | s1 %= A32_BASE;
748 | s2 %= A32_BASE;
749 | }
750 |
751 | return (s2 << 16) | s1;
752 | }
753 |
754 |
755 | /**
756 | * @constructor
757 | */
758 | function xd3_addr_cache(s_near, s_same) {
759 | this.s_near = s_near;
760 | this.s_same = s_same;
761 | this.next_slot = 0; /* the circular index for near */
762 | this.near_array = null; /* array of size s_near */
763 | this.same_array = null; /* array of size s_same*256 */
764 | }
765 |
766 |
767 | /**
768 | * @param {!xd3_addr_cache} acache
769 | */
770 | function xd3_init_cache(acache) {
771 | if (acache.s_near > 0) {
772 | for (var i = 0; i < acache.near_array.length; i++) {
773 | acache.near_array[i] = 0;
774 | }
775 | acache.next_slot = 0;
776 | }
777 |
778 | if (acache.s_same > 0) {
779 | for (var i = 0; i < acache.same_array.length; i++) {
780 | acache.same_array[i] = 0;
781 | }
782 | }
783 | }
784 |
785 | /**
786 | * Used by the decoder to buffer input in sections.
787 | * XDelta3 C++ struct.
788 | * @constructor
789 | * @struct
790 | */
791 | function xd3_desect() {
792 | /**
793 | * The buffer as a slice of the backingBuffer;
794 | * @type {?Uint8Array}
795 | */
796 | this.bytes = null;
797 |
798 | /** @type {number} */
799 | this.size = 0;
800 |
801 | /** @type {number} */
802 | this.pos = 0;
803 | }
804 |
805 | /**
806 | * Gets a byte from the section.
807 | * @return {number}
808 | */
809 | xd3_desect.prototype.getByte = function() {
810 | if (!this.bytes) {
811 | throw new Error('bytes not set');
812 | }
813 | return this.bytes[this.pos++];
814 | };
815 |
816 | /**
817 | * Gets an integer from the section.
818 | * XDelta3 integers are encodes as a variable number of 7 bit bytes. Bit 8, the
819 | * most significant bit is used to indicate more bytes needed.
820 | * @return {number}
821 | */
822 | xd3_desect.prototype.getInteger = function() {
823 | if (!this.bytes) {
824 | throw new Error('bytes not set');
825 | }
826 | var val = 0;
827 | for (var i = 0; i < 10; i++) {
828 | var aByte = this.bytes[this.pos++];
829 | val += aByte & 0x7F;
830 | if (!(aByte & 0x80)) {
831 | return val;
832 | }
833 | val <<= 7;
834 | }
835 | throw new Error('invalid number');
836 | };
837 |
838 |
839 | /**
840 | * Builds a default code table.
841 | * @return {!xd3_dinst_table}
842 | */
843 | function xd3_rfc3284_code_table() {
844 | return xd3_build_code_table(__rfc3284_code_table_desc);
845 | }
846 |
847 | /**
848 | * Allocates and initializes a Javascript Array.
849 | * @return {!Array}
850 | */
851 | function allocArray(len, val) {
852 | var arr = new Array(len);
853 | for (var i = 0; i < len; i++) {
854 | arr[i] = val;
855 | }
856 | return arr;
857 | }
858 |
859 | /**
860 | * @constructor
861 | */
862 | function xd3_source() {
863 | /** @type {number} */
864 | this.cpyoff_blkoff = -1;
865 | }
866 |
867 | /**
868 | * @param {!Uint8Array} bytes
869 | * @constructor
870 | */
871 | function DataObject(bytes) {
872 | this.pos = 0;
873 | this.bytes = bytes;
874 | };
875 |
876 | DataObject.prototype.getByte = function() {
877 | return this.bytes[this.pos++];
878 | };
879 |
880 | DataObject.prototype.getInteger = function() {
881 | var val = 0;
882 | for (var i = 0; i < 10; i++) {
883 | var aByte = this.bytes[this.pos++];
884 | val += aByte & 0x7F;
885 | if (!(aByte & 0x80)) {
886 | return val;
887 | }
888 | val <<= 7;
889 | }
890 | throw new Error('invalid number');
891 | };
892 |
893 | DataObject.prototype.fill = function(val, length) {
894 | // TODO(bstell): see if there is a function for this.
895 | for (var i = 0; i < length; i++) {
896 | this.bytes[this.pos++] = val;
897 | }
898 | };
899 |
900 | /**
901 | * @param {!xd3_desect} sect
902 | * @param {number} length
903 | */
904 | DataObject.prototype.copySect = function(sect, length) {
905 | // TODO(bstell): see if there is a function for this.
906 | for (var i = 0; i < length; i++) {
907 | this.bytes[this.pos++] = sect.bytes[sect.pos++];
908 | }
909 | };
910 |
911 | DataObject.prototype.copyBytes = function(bytes, offset, length) {
912 | // TODO(bstell): see if there is a function for this.
913 | for (var i = 0; i < length; i++) {
914 | this.bytes[this.pos++] = bytes[offset++];
915 | }
916 | };
917 |
918 | })();
919 |
--------------------------------------------------------------------------------
/xdelta3_decoder_with_debug.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * xdelta3 - delta compression tools and library
4 | * Copyright 2016 Joshua MacDonald
5 | *
6 | * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
7 | * 2011, 2012, 2013, 2014, 2015 josh.macdonald@gmail.com
8 | *
9 | * Licensed under the Apache License, Version 2.0 (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 | /**
23 | * @fileoverview This file implements XDelta3 decoding.
24 | * Note: the subroutine, method, field, and variable names do not follow
25 | * Javascript style guide but reflect the names in the XDelta3 C++ files. This
26 | * makes is to make it easier to keep this code in synch with the C++ code.
27 | *
28 | * The C++ code is very casual about initializing and accessing data structures.
29 | * This code is a port and follows that code style.
30 | */
31 |
32 | (function() {
33 |
34 | // Check for namespace collision.
35 | if ((typeof window['XDelta3Decoder'] != 'undefined')
36 | || (typeof window.XDelta3Decoder != 'undefined')) {
37 | throw new Error('XDelta3Decoder already defined.');
38 | }
39 |
40 | /**
41 | * The public class.
42 | */
43 | window.XDelta3Decoder = function(debugOutput) { //
44 | };
45 |
46 | var XDelta3Decoder = window.XDelta3Decoder;
47 |
48 | /**
49 | * The public API to decode a delta possibly with a source.
50 | * @param {!Uint8Array} delta The Xdelta delta file.
51 | * @param {Uint8Array=} opt_source The source file (optional).
52 | * @return {!ArrayBuffer}
53 | */
54 | XDelta3Decoder.decode = function(delta, opt_source) {
55 | if (typeof opt_source != 'object') {
56 | opt_source = null;
57 | }
58 | var xdelta3 = new _XDelta3Decoder(delta, opt_source);
59 | var uint8Bytes = xdelta3.xd3_decode_input();
60 | return uint8Bytes.buffer;
61 | }
62 |
63 | /**
64 | * The public API to disable debug printf code.
65 | */
66 | XDelta3Decoder.disableDebug = function() { // DEBUG ONLY
67 | for (var i = 0; i < fallbackRoutines.length; i++) { // DEBUG ONLY
68 | var name = fallbackRoutines[i]; // DEBUG ONLY
69 | window[name] = function() {}; // DEBUG ONLY
70 | } // DEBUG ONLY
71 | } // DEBUG ONLY
72 |
73 | // Define debug fallback routines if needed.
74 | var fallbackRoutines = [ // DEBUG ONLY
75 | 'dumpBytes', // DEBUG ONLY
76 | 'dumpCodeTableRows', // DEBUG ONLY
77 | 'printf', // DEBUG ONLY
78 | 'printInstructionPair', // DEBUG ONLY
79 | 'toHexStr' // DEBUG ONLY
80 | ]; // DEBUG ONLY
81 | for (var i = 0; i < fallbackRoutines.length; i++) { // DEBUG ONLY
82 | var name = fallbackRoutines[i]; // DEBUG ONLY
83 | if (typeof window[name] == 'undefined') { // DEBUG ONLY
84 | window[name] = function() {}; // DEBUG ONLY
85 | } // DEBUG ONLY
86 | } // DEBUG ONLY
87 |
88 | /**
89 | * The XDelta3 data commands.
90 | */
91 | /** @type {number} */
92 | var XD3_NOOP = 0;
93 | /** @type {number} */
94 | var XD3_ADD = 1;
95 | /** @type {number} */
96 | var XD3_RUN = 2;
97 | /** @type {number} */
98 | var XD3_CPY = 3;
99 |
100 | /** @type {number} */
101 | var MIN_MATCH = 4;
102 |
103 | /**
104 | * Header indicator bits.
105 | */
106 | /** @type {number} */
107 | var VCD_SECONDARY = 1;
108 | /** @type {number} */
109 | var VCD_CODETABLE = 2;
110 | /** @type {number} */
111 | var VCD_APPHEADER = 4;
112 | /** @type {number} */
113 | var VCD_INVHDR = ~(VCD_SECONDARY | VCD_CODETABLE | VCD_APPHEADER);
114 |
115 | var VCD_SOURCE = 0x01;
116 | var VCD_TARGET = 0x02;
117 | var VCD_ADLER32 = 0x04;
118 |
119 |
120 | /**
121 | * Declares the main decode class.
122 | * @param {!Uint8Array} delta The Xdelta3 delta file.
123 | * @param {Uint8Array=} opt_source The source file (optional).
124 | * @constructor
125 | */
126 | function _XDelta3Decoder(delta, opt_source) {
127 | /** @type {!Uint8Array} */
128 | this.delta = delta;
129 |
130 | var source = opt_source || new Uint8Array(1);
131 | /** @type {!DataObject} */
132 | this.source = new DataObject(source);
133 |
134 | /** @type {!xd3_source} */
135 | this.src = new xd3_source();
136 |
137 | /** @type {number} */
138 | this.position = 0;
139 |
140 | /** @type {number} */
141 | this.dec_window_count = 0;
142 |
143 | /** @type {number} */
144 | this.dec_winstart = 0;
145 |
146 | /**
147 | * The length of the target window.
148 | * @type {number}
149 | */
150 | this.dec_tgtlen = 0;
151 |
152 | /**
153 | * The Alder32 checksum. This is used to verify the decoded bytes checksum
154 | * matches the checksum of the original.
155 | */
156 | this.dec_adler32 = 0;
157 |
158 | /**
159 | * First half instruction.
160 | * @type {!xd3_hinst}
161 | */
162 | this.dec_current1 = new xd3_hinst();
163 |
164 | /**
165 | * Second half instruction.
166 | * @type {!xd3_hinst}
167 | */
168 | this.dec_current2 = new xd3_hinst();
169 |
170 | /** @type {!xd3_desect} */
171 | this.data_sect = new xd3_desect();
172 |
173 | /** @type {!xd3_desect} */
174 | this.inst_sect = new xd3_desect();
175 |
176 | /** @type {!xd3_desect} */
177 | this.addr_sect = new xd3_desect();
178 |
179 | /**
180 | * The address cache.
181 | * @type {!xd3_addr_cache}
182 | */
183 | this.acache = new xd3_addr_cache(
184 | __rfc3284_code_table_desc.near_modes,
185 | __rfc3284_code_table_desc.same_modes);
186 | }
187 |
188 | /**
189 | * Allocates the address caches.
190 | */
191 | _XDelta3Decoder.prototype.xd3_alloc_cache = function() {
192 | printf("xd3_alloc_cache\n"); // DEBUG ONLY
193 | this.acache.near_array = null; // not sure this is needed
194 | this.acache.same_array = null; // not sure this is needed
195 | if (this.acache.s_near > 0) {
196 | this.acache.near_array = allocArray(this.acache.s_near, 0);
197 | }
198 | if (this.acache.s_same > 0) {
199 | this.acache.same_array = allocArray(this.acache.s_same * 256, 0);
200 | }
201 | };
202 |
203 | /**
204 | * Parses the delta file data and produces the targetWindow data.
205 | * @return {!Uint8Array}
206 | */
207 | _XDelta3Decoder.prototype.xd3_decode_input = function() {
208 | printf("==================================\n"); // DEBUG ONLY
209 | printf(" HEADER pos = " + this.position + "\n"); // DEBUG ONLY
210 | printf("==================================\n"); // DEBUG ONLY
211 | printf("DEC_VCHEAD: load magic bytes\n"); // DEBUG ONLY
212 | dumpBytes(this.delta, 0, 4); // DEBUG ONLY
213 |
214 | printf("DEC_VCHEAD: check magic bytes\n"); // DEBUG ONLY
215 | if (this.delta[0] != 0xD6 || // 'V' with MSB set
216 | this.delta[1] != 0xC3 || // 'C' with MSB set
217 | this.delta[2] != 0xC4 || // 'D' with MSB set
218 | this.delta[3] != 0) { // unused but be set to zero
219 | throw new Error('XD3_INVALID_INPUT invalid magic');
220 | }
221 | this.position = 4;
222 |
223 | this.dec_hdr_ind = this.delta[this.position++];
224 | printf("DEC_HDRIND: dec_hdr_ind = " + toHexStr(this.dec_hdr_ind) + "\n"); // DEBUG ONLY
225 | if (this.dec_hdr_ind & VCD_INVHDR) {
226 | throw new Error('VCD_INVHDR unrecognized header indicator bits set');
227 | }
228 |
229 | printf("DEC_SECONDID: read byte if VCD_SECONDARY(" + (this.dec_hdr_ind & VCD_SECONDARY) + ")\n"); // DEBUG ONLY
230 | if (this.dec_hdr_ind & VCD_SECONDARY) {
231 | throw new Error('VCD_SECONDARY not implemented');
232 | }
233 | printf("DEC_TABLEN: read size if VCD_CODETABLE(" + (this.dec_hdr_ind & VCD_CODETABLE) + ")\n"); // DEBUG ONLY
234 | printf("DEC_NEAR: read byte if VCD_CODETABLE(" + (this.dec_hdr_ind & VCD_CODETABLE) + ")\n"); // DEBUG ONLY
235 | printf("DEC_SAME: read byte if VCD_CODETABLE(" + (this.dec_hdr_ind & VCD_CODETABLE) + ")\n"); // DEBUG ONLY
236 |
237 | if (this.dec_hdr_ind & VCD_CODETABLE) {
238 | throw new Error('VCD_CODETABLE support was removed');
239 | } else {
240 | printf("use the default table.\n"); // DEBUG ONLY
241 | /* Use the default table. */
242 | printf("use default table near_modes " + __rfc3284_code_table_desc.near_modes + "\n"); // DEBUG ONLY
243 | this.acache.s_near = __rfc3284_code_table_desc.near_modes;
244 | printf("use default table same_modes " + __rfc3284_code_table_desc.same_modes + "\n"); // DEBUG ONLY
245 | this.acache.s_same = __rfc3284_code_table_desc.same_modes;
246 | this.code_table = xd3_rfc3284_code_table();
247 | }
248 |
249 | this.xd3_alloc_cache();
250 |
251 | printf("DEC_APPLEN: read size if VCD_APPHEADER(" + (this.dec_hdr_ind & VCD_APPHEADER) // DEBUG ONLY
252 | + ")\n"); // DEBUG ONLY
253 | if (this.dec_hdr_ind & VCD_APPHEADER) {
254 | this.dec_appheadsz = this.getInteger();
255 | printf("dec_appheadsz = " + this.dec_appheadsz + "\n"); // DEBUG ONLY
256 | printf("DEC_APPDAT: \n"); // DEBUG ONLY
257 | // Note: appHeader does not have a 0-termination.
258 | this.dec_apphead = this.xd3_alloc(this.dec_appheadsz + 1);
259 | this.xd3_decode_bytes(this.dec_apphead, 0, this.dec_appheadsz);
260 | this.dec_apphead[this.dec_appheadsz + 1] = 0;
261 | dumpBytes(this.dec_apphead, 0, this.dec_appheadsz + 1); // DEBUG ONLY
262 | }
263 | printf("pos after dec_appheader = " + this.position + "\n\n"); // DEBUG ONLY
264 |
265 | //var targetLength = 0;
266 | while (true) {
267 | printf("DEC_WININD\n"); // DEBUG ONLY
268 | printf("==================================\n"); // DEBUG ONLY
269 | printf(" WINDOW pos = "+this.position+"\n"); // DEBUG ONLY
270 | printf("==================================\n"); // DEBUG ONLY
271 | if (this.position >= this.delta.length) {
272 | break;
273 | }
274 | //targetLength +=
275 | this.handleWindow();
276 | }
277 | printf("no more data\n"); // DEBUG ONLY
278 | return this.dec_buffer.bytes;
279 | };
280 |
281 | _XDelta3Decoder.prototype.xd3_decode_init_window = function() {
282 | this.dec_cpylen = 0;
283 | this.dec_cpyoff = 0;
284 | // this.dec_cksumbytes = 0;
285 |
286 | xd3_init_cache(this.acache);
287 | }
288 |
289 | _XDelta3Decoder.prototype.handleWindow = function() {
290 | this.dec_win_ind = this.delta[this.position++]; // DEC_WININD
291 | printf("dec_win_ind = " + this.dec_win_ind + "(" + toHexStr(this.dec_win_ind) + ")\n"); // DEBUG ONLY
292 | printf("dec_tgtlen = " + this.dec_tgtlen + "(" + toHexStr(this.dec_tgtlen) + ")\n"); // DEBUG ONLY
293 |
294 | if (this.dec_win_ind & ~7) {
295 | throw new Error('VCD_INVWIN unexpected bits set');
296 | }
297 |
298 | printf("window_count = " + this.dec_window_count + "\n"); // DEBUG ONLY
299 | this.current_window = this.dec_window_count;
300 |
301 | this.dec_winstart += this.dec_tgtlen;
302 | printf("dec_winstart = " + this.dec_winstart + "\n"); // DEBUG ONLY
303 |
304 | printf('xd3_decode_init_window\n'); // DEBUG ONLY
305 | this.xd3_decode_init_window();
306 | var SRCORTGT = VCD_SOURCE | VCD_TARGET;
307 | var srcortgt = SRCORTGT & this.dec_win_ind;
308 | printf("srcortgt = " + srcortgt + "\n"); // DEBUG ONLY
309 |
310 | // If using a source or target data segment: read the lenght and position
311 | // integers.
312 | printf("DEC_CPYLEN: dec_cpylen = "+this.dec_cpylen+"\n"); // DEBUG ONLY
313 | printf("DEC_CPYLEN: get size if SRCORTGT("+srcortgt+"), pos = "+this.position+"\n"); // DEBUG ONLY
314 | if (srcortgt) {
315 | this.dec_cpylen = this.getInteger(); // DEC_CPYLEN
316 | printf("dec_cpylen = " + this.dec_cpylen + "\n"); // DEBUG ONLY
317 | }
318 | this.dec_position = this.dec_cpylen;
319 | printf("DEC_CPYOFF: get size if SRCORTGT("+srcortgt+"), pos = "+this.position+"\n"); // DEBUG ONLY
320 | if (srcortgt) {
321 | var sourcePosition = this.getInteger(); // DEC_CPYOFF
322 | this.dec_cpyoff = sourcePosition;
323 | printf("dec_cpyoff = " + this.dec_cpyoff + "\n"); // DEBUG ONLY
324 | }
325 |
326 | this.dec_enclen = this.getInteger(); // DEC_ENCLEN
327 | printf("DEC_ENCLEN: dec_enclen = " + this.dec_enclen + "\n") // DEBUG ONLY
328 |
329 | // Calculate the position if the delta was actually read.
330 | // var positionAfterDelta = this.position + this.dec_enclen;
331 |
332 | // Get the target window length.
333 | this.dec_tgtlen = this.getInteger(); // DEC_TGTLEN
334 | printf("DEC_TGTLEN: dec_tgtlen = " + this.dec_tgtlen + "\n"); // DEBUG ONLY
335 |
336 | this.dec_del_ind = this.getByte(); // DEC_DELIND
337 | printf("DEC_DELIND: dec_del_ind = " + this.dec_del_ind + "\n"); // DEBUG ONLY
338 |
339 | this.data_sect.size = this.getInteger(); // DEC_DATALEN
340 | this.inst_sect.size = this.getInteger(); // DEC_INSTLEN
341 | this.addr_sect.size = this.getInteger(); // DEC_ADDRLEN
342 | printf("DEC_DATALEN: data_sect size = " + this.data_sect.size + "\n"); // DEBUG ONLY
343 | printf("DEC_INSTLEN: inst_sect size = " + this.inst_sect.size + "\n"); // DEBUG ONLY
344 | printf("DEC_ADDRLEN: addr_sect size = " + this.addr_sect.size + "\n"); // DEBUG ONLY
345 |
346 | printf("DEC_CKSUM: get checksum if VCD_ADLER32 pos = " + this.position + "\n"); // DEBUG ONLY
347 | if (this.dec_win_ind & VCD_ADLER32) { // DEC_CKSUM
348 | this.dec_cksum = this.xd3_decode_allocate(4);
349 | dumpBytes(this.dec_cksum, 0, 4); // DEBUG ONLY
350 | for (var i = 0; i < 4; i += 1) {
351 | this.dec_adler32 = (this.dec_adler32 << 8) | this.dec_cksum[i];
352 | }
353 | printf("stream->dec_adler32 = "+this.dec_adler32+"\n"); // DEBUG ONLY
354 | }
355 |
356 | this.xd3_decode_sections();
357 | dumpBytes(this.data_sect.bytes, 0, this.data_sect.size); // DEBUG ONLY
358 | dumpBytes(this.inst_sect.bytes, 0, this.inst_sect.size); // DEBUG ONLY
359 | dumpBytes(this.addr_sect.bytes, 0, this.addr_sect.size); // DEBUG ONLY
360 |
361 | printf('DEC_EMIT:\n'); // DEBUG ONLY
362 | /* In the C++ code:
363 | * To speed VCD_SOURCE block-address calculations, the source
364 | * cpyoff_blocks and cpyoff_blkoff are pre-computed.
365 | * However, in this Javascript code there is no 'blocks'.
366 | */
367 | if (this.dec_win_ind & VCD_SOURCE) {
368 | printf("stream->dec_cpyoff = " + this.dec_cpyoff + "\n"); // DEBUG ONLY
369 | this.src.cpyoff_blkoff = this.dec_cpyoff;
370 | printf("src->cpyoff_blkoff = " + this.src.cpyoff_blkoff + "\n"); // DEBUG ONLY
371 | }
372 | this.xd3_decode_emit();
373 |
374 | return this.dec_tgtlen;
375 | };
376 |
377 | /**
378 | * This function only has code if the preprocessor statement
379 | * "#if SECONDARY_ANY" is set. SECONDARY_ANY does not seem to be set.
380 | */
381 | _XDelta3Decoder.prototype.xd3_decode_secondary_sections = function() { //
382 | };
383 |
384 | /**
385 | * @param {!xd3_desect} sect
386 | */
387 | _XDelta3Decoder.prototype.xd3_decode_section = function(sect) {
388 | // It is possible to just point into the buffer but perhaps that can be done
389 | // later.
390 | sect.bytes = this.xd3_decode_allocate(sect.size);
391 | };
392 |
393 | _XDelta3Decoder.prototype.xd3_decode_sections = function() {
394 | printf("xd3_decode_sections\n"); // DEBUG ONLY
395 | this.xd3_decode_section(this.data_sect);
396 | this.xd3_decode_section(this.inst_sect);
397 | this.xd3_decode_section(this.addr_sect);
398 |
399 | this.xd3_decode_secondary_sections();
400 |
401 | this.xd3_decode_setup_buffers();
402 | };
403 |
404 | _XDelta3Decoder.prototype.xd3_decode_setup_buffers = function() {
405 | printf("xd3_decode_setup_buffers\n"); // DEBUG ONLY
406 | this.dec_buffer = new DataObject(new Uint8Array(this.dec_tgtlen));
407 | };
408 |
409 | var VCD_SELF = 0;
410 | var VCD_HERE = 1;
411 |
412 | /**
413 | * xd3_decode_address
414 | * @param {number} here
415 | * @param {number} mode
416 | * @param {!xd3_desect} sect
417 | */
418 | _XDelta3Decoder.prototype.xd3_decode_address = function(here, mode, sect) {
419 | printf("xd3_decode_address\n"); // DEBUG ONLY
420 | var val;
421 | var same_start = 2 + this.acache.s_near;
422 | printf("here = " + here + "\n"); // DEBUG ONLY
423 | printf("mode = " + mode + "\n"); // DEBUG ONLY
424 | printf("acache.s_near = " + this.acache.s_near + "\n"); // DEBUG ONLY
425 | printf("same_start = " + same_start + "\n"); // DEBUG ONLY
426 |
427 | if (mode < same_start) {
428 | val = sect.getInteger();
429 | printf("val = " + val + "\n"); // DEBUG ONLY
430 | switch (mode) {
431 | case VCD_SELF:
432 | printf('use self\n'); // DEBUG ONLY
433 | break;
434 | case VCD_HERE:
435 | printf('subtract from here\n'); // DEBUG ONLY
436 | // var old_val = val;
437 | val = here - val;
438 | printf("val = " + val + "\n"); // DEBUG ONLY
439 | break;
440 | default:
441 | printf('add near_array['+(mode-2)+'] = '+ // DEBUG ONLY
442 | this.acache.near_array[mode - 2]+'\n'); // DEBUG ONLY
443 | val += this.acache.near_array[mode - 2];
444 | printf("val = " + val + "\n"); // DEBUG ONLY
445 | }
446 | } else {
447 | mode -= same_start;
448 | var offset = sect.getByte();
449 | printf("mode = "+mode+", offset = "+offset+"\n"); // DEBUG ONLY
450 | val = this.acache.same_array[mode * 256 + offset];
451 | printf("val = " + val + "\n"); // DEBUG ONLY
452 | }
453 |
454 | this.xd3_update_cache(this.acache, val);
455 |
456 | return val;
457 | };
458 |
459 | /**
460 | * @param {!xd3_addr_cache} acache
461 | * @param {number} addr
462 | */
463 | _XDelta3Decoder.prototype.xd3_update_cache = function(acache, addr) {
464 | printf("acache->s_near = "+acache.s_near+"\n"); // DEBUG ONLY
465 | if (acache.s_near > 0) {
466 | acache.near_array[acache.next_slot] = addr;
467 | printf("acache->near_array["+acache.next_slot+"] = "+addr+"\n"); // DEBUG ONLY
468 | acache.next_slot = (acache.next_slot + 1) % acache.s_near;
469 | printf("acache->next_slot = "+acache.next_slot+"\n"); // DEBUG ONLY
470 | }
471 |
472 | printf("acache->s_same = "+acache.s_same+"\n"); // DEBUG ONLY
473 | if (acache.s_same > 0) {
474 | acache.same_array[addr % (acache.s_same * 256)] = addr;
475 | printf("acache->same_array["+(addr % (acache.s_same*256))+"] = "+addr+"\n"); // DEBUG ONLY
476 | }
477 | };
478 |
479 | /**
480 | * @param {!xd3_hinst} inst
481 | */
482 | _XDelta3Decoder.prototype.xd3_decode_output_halfinst = function(inst) {
483 | printf("xd3_decode_output_halfinst: type=" + inst.type + // DEBUG ONLY
484 | ", addr=" + inst.addr + ", size=" + inst.size + "\n"); // DEBUG ONLY
485 | var take = inst.size;
486 | var blkoff;
487 | var start_pos = this.dec_buffer.pos; // DEBUG ONLY
488 | printf("start_pos = " + start_pos + "\n"); // DEBUG ONLY
489 |
490 | switch (inst.type) {
491 | case XD3_RUN:
492 | var val = this.data_sect.getByte();
493 | printf(" >>>> XD3_RUN: memset "+ toHexStr(val) +" for " + take + "\n"); // DEBUG ONLY
494 | this.dec_buffer.fill(val, take);
495 | dumpBytes(this.dec_buffer.bytes, start_pos, take); // DEBUG ONLY
496 | break;
497 |
498 | case XD3_ADD:
499 | printf(" >>>> XD3_ADD: memcpy "+take+" from the data_sect\n"); // DEBUG ONLY
500 | this.dec_buffer.copySect(this.data_sect, take);
501 | dumpBytes(this.dec_buffer.bytes, start_pos, take); // DEBUG ONLY
502 | break;
503 |
504 | default:
505 | printf(" >>>> XD3_CPY\n"); // DEBUG ONLY
506 | printf("dec_cpylen = " + this.dec_cpylen + "\n"); // DEBUG ONLY
507 | var overlap;
508 | var overlap_pos;
509 | if (inst.addr < this.dec_cpylen) {
510 | overlap = 0;
511 | printf("overlap = 0\n"); // DEBUG ONLY
512 | if (this.dec_win_ind & VCD_TARGET) {
513 | throw new Error('VCD_TARGET not supported');
514 | } else {
515 | printf("read source block\n"); // DEBUG ONLY
516 | blkoff = this.src.cpyoff_blkoff;
517 | printf("blkoff = " + blkoff + "\n"); // DEBUG ONLY
518 | printf("add inst addr to blkoff\n"); // DEBUG ONLY
519 | blkoff = this.dec_cpyoff + inst.addr;
520 | printf("blkoff = " + blkoff + "\n"); // DEBUG ONLY
521 | }
522 | } else {
523 | overlap = 1;
524 | printf("overlap = 1\n"); // DEBUG ONLY
525 | overlap_pos = inst.addr - this.dec_cpylen;
526 | printf("overlap_pos = "+overlap_pos+"\n"); // DEBUG ONLY
527 | }
528 | if (overlap) {
529 | printf(" <<<< manually copy "+take+"\n"); // DEBUG ONLY
530 | this.dec_buffer.copyBytes(this.dec_buffer.bytes, overlap_pos, take);
531 | dumpBytes(this.dec_buffer.bytes, start_pos, take); // DEBUG ONLY
532 | } else {
533 | printf(" <<<< memcopy take=" + take + "\n"); // DEBUG ONLY
534 | this.dec_buffer.copyBytes(this.source.bytes, blkoff, take);
535 | dumpBytes(this.dec_buffer.bytes, start_pos, take); // DEBUG ONLY
536 | }
537 | }
538 | };
539 |
540 | /**
541 | * xref: xd3_decode_parse_halfinst
542 | * @param {!xd3_hinst} inst
543 | */
544 | _XDelta3Decoder.prototype.xd3_decode_parse_halfinst = function(inst) {
545 | printf("xd3_decode_parse_halfinst\n"); // DEBUG ONLY
546 | // Get size and address if necessary.
547 | if (inst.size == 0) {
548 | inst.size = this.inst_sect.getInteger();
549 | printf("read inst size = " + inst.size + "\n"); // DEBUG ONLY
550 | }
551 |
552 | /* For copy instructions, read address. */
553 | if (inst.type >= XD3_CPY) {
554 | printf("dec_position = " + this.dec_position + "\n"); // DEBUG ONLY
555 | var mode = inst.type - XD3_CPY;
556 | printf("mode = " + mode + "\n"); // DEBUG ONLY
557 | inst.addr =
558 | this.xd3_decode_address(this.dec_position, mode, this.addr_sect);
559 | printf("XD3_CPY address = " + inst.addr + "\n"); // DEBUG ONLY
560 | }
561 |
562 | printf('dec_position = ' + this.dec_position + "\n"); // DEBUG ONLY
563 | printf('inst size = ' + inst.size + "\n"); // DEBUG ONLY
564 | this.dec_position += inst.size;
565 | printf('dec_position = ' + this.dec_position + "\n"); // DEBUG ONLY
566 | };
567 |
568 | var instCount = 0; // DEBUG ONLY
569 | /**
570 | * xref: xd3_decode_instruction
571 | */
572 | _XDelta3Decoder.prototype.xd3_decode_instruction = function() {
573 | printf("xd3_decode_instruction "+(instCount++)+"\n"); // DEBUG ONLY
574 | var code_table = this.code_table;
575 | var instPair = this.inst_sect.getByte();
576 | printf('instPair = ' + instPair + "\n"); // DEBUG ONLY
577 |
578 | this.dec_current1.type = code_table.tableRows[instPair].type1;
579 | this.dec_current1.size = code_table.tableRows[instPair].size1;
580 | // dec_current1.addr keeps it previous value.
581 |
582 | this.dec_current2.type = code_table.tableRows[instPair].type2;
583 | this.dec_current2.size = code_table.tableRows[instPair].size2;
584 | // dec_current2.addr keeps it previous value.
585 |
586 | printInstructionPair(this.dec_current1, this.dec_current2); // DEBUG ONLY
587 |
588 | /* For each instruction with a real operation, decode the
589 | * corresponding size and addresses if necessary. Assume a
590 | * code-table may have NOOP in either position, although this is
591 | * unlikely. */
592 | if (this.dec_current1.type != XD3_NOOP) {
593 | this.xd3_decode_parse_halfinst(this.dec_current1);
594 | }
595 | if (this.dec_current2.type != XD3_NOOP) {
596 | this.xd3_decode_parse_halfinst(this.dec_current2);
597 | }
598 | };
599 |
600 | _XDelta3Decoder.prototype.xd3_decode_finish_window = function() {
601 | printf("xd3_decode_finish_window\n"); // DEBUG ONLY
602 | // stream->dec_winbytes = 0;
603 | // stream->dec_state = DEC_FINISH;
604 | this.data_sect.pos = 0;
605 | this.inst_sect.pos = 0;
606 | this.addr_sect.pos = 0;
607 | };
608 |
609 | _XDelta3Decoder.prototype.xd3_decode_emit = function() {
610 | printf("\n\n"); // DEBUG ONLY
611 | printf("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@\n"); // DEBUG ONLY
612 | printf(" xd3_decode_emit:\n"); // DEBUG ONLY
613 | printf("#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@#@\n"); // DEBUG ONLY
614 |
615 | var instLength = this.inst_sect.bytes.byteLength;
616 | /* Decode next instruction pair. */
617 | while (this.inst_sect.pos < instLength) {
618 | printf('\n========== Decode next instruction pair ==========\n'); // DEBUG ONLY
619 | this.xd3_decode_instruction();
620 |
621 | /* Output dec_current1 */
622 | if (this.dec_current1.type != XD3_NOOP) {
623 | printf("output dec_current1 ----------\n"); // DEBUG ONLY
624 | this.xd3_decode_output_halfinst(this.dec_current1);
625 | }
626 | /* Output dec_current2 */
627 | if (this.dec_current2.type != XD3_NOOP) {
628 | printf("output dec_current2 ----------\n"); // DEBUG ONLY
629 | this.xd3_decode_output_halfinst(this.dec_current2);
630 | }
631 | }
632 | printf("check checksum is VCD_ADLER32 set\n"); // DEBUG ONLY
633 | if (this.dec_win_ind & VCD_ADLER32) {
634 | var a32 = adler32(1, this.dec_buffer.bytes, 0, this.dec_tgtlen);
635 | printf("a32 = "+a32+"\n"); // DEBUG ONLY
636 | if (a32 != this.dec_adler32) {
637 | throw new Error('target window checksum mismatch');
638 | }
639 | }
640 |
641 | /* Finished with a window. */
642 | this.xd3_decode_finish_window();
643 | };
644 |
645 | _XDelta3Decoder.prototype.xd3_alloc = function(length) {
646 | return new Uint8Array(length);
647 | };
648 |
649 | _XDelta3Decoder.prototype.xd3_decode_bytes = function(bytes, pos, length) {
650 | for (var i = 0; i < length; i++) {
651 | bytes[pos + i] = this.delta[this.position++];
652 | }
653 | };
654 |
655 | _XDelta3Decoder.prototype.xd3_decode_allocate = function(length) {
656 | var bytes =
657 | new Uint8Array(this.delta.slice(this.position, this.position + length));
658 | this.position += length;
659 | return bytes;
660 | };
661 |
662 | _XDelta3Decoder.prototype.getByte = function() {
663 | return this.delta[this.position++];
664 | };
665 |
666 | _XDelta3Decoder.prototype.getInteger = function() {
667 | var maxBytes = Math.min(20, this.delta.length - this.position);
668 | var integer = 0;
669 | for (var i = 0; i < maxBytes; i++) {
670 | var aPart = this.delta[this.position++];
671 | integer += aPart & 0x7F;
672 | if (!(aPart & 0x80)) {
673 | return integer;
674 | }
675 | integer <<= 7;
676 | }
677 | throw new Error('delta integer too long');
678 | };
679 |
680 | /**
681 | * The code table.
682 | * @param {!Array} tableRows
683 | * @constructor
684 | * @struct
685 | */
686 | var xd3_dinst_table = function(tableRows) {
687 | /** @type {!Array} */
688 | this.tableRows = tableRows;
689 | };
690 |
691 | /**
692 | * xd3_hinst
693 | * @constructor
694 | */
695 | function xd3_hinst() {
696 | this.type = XD3_NOOP;
697 | this.size = 0;
698 | this.addr = 0;
699 | }
700 |
701 | /**
702 | * The code-table double instruction.
703 | * @constructor
704 | */
705 | function xd3_dinst() {
706 | /** @type {number} */
707 | this.type1 = XD3_NOOP;
708 | /** @type {number} */
709 | this.size1 = 0;
710 | /** @type {number} */
711 | this.type2 = XD3_NOOP;
712 | /** @type {number} */
713 | this.size2 = 0;
714 | }
715 |
716 | /**
717 | * @param {!xd3_code_table_desc} desc
718 | * @return {!xd3_dinst_table}
719 | */
720 | function xd3_build_code_table(desc) {
721 | printf("xd3_build_code_table\n"); // DEBUG ONLY
722 | var startRow = 0; // DEBUG ONLY
723 | var row = 0;
724 | var tableRows = new Array(256);
725 | for (var i = 0; i < 256; i++) {
726 | tableRows[i] = new xd3_dinst();
727 | }
728 | var cpyModes = 2 + desc.near_modes + desc.same_modes;
729 |
730 | // The single RUN command.
731 | tableRows[row++].type1 = XD3_RUN;
732 |
733 | // The ADD only commands.
734 | tableRows[row++].type1 = XD3_ADD;
735 | for (var size1 = 1; size1 <= desc.add_sizes; size1++) {
736 | tableRows[row].type1 = XD3_ADD;
737 | tableRows[row++].size1 = size1;
738 | }
739 | dumpCodeTableRows(tableRows, startRow, row); // DEBUG ONLY
740 | startRow = row; // DEBUG ONLY
741 |
742 | // The Copy only commands.
743 | for (var mode = 0; mode < cpyModes; mode++) {
744 | tableRows[row++].type1 = XD3_CPY + mode;
745 |
746 | for (var size1 = MIN_MATCH; size1 < MIN_MATCH + desc.cpy_sizes; size1++) {
747 | tableRows[row].type1 = XD3_CPY + mode;
748 | tableRows[row++].size1 = size1;
749 | }
750 | dumpCodeTableRows(tableRows, startRow, row); // DEBUG ONLY
751 | startRow = row; // DEBUG ONLY
752 | }
753 |
754 | // The Add/Copy commands.
755 | for (var mode = 0; mode < cpyModes; mode++) {
756 | for (var size1 = 1; size1 <= desc.addcopy_add_max; size1++) {
757 | var max = (mode < 2 + desc.near_modes) ? //
758 | desc.addcopy_near_cpy_max :
759 | desc.addcopy_same_cpy_max;
760 | for (var size2 = MIN_MATCH; size2 <= max; size2++) {
761 | tableRows[row].type1 = XD3_ADD;
762 | tableRows[row].size1 = size1;
763 | tableRows[row].type2 = XD3_CPY + mode;
764 | tableRows[row++].size2 = size2;
765 | }
766 | }
767 | dumpCodeTableRows(tableRows, startRow, row); // DEBUG ONLY
768 | startRow = row; // DEBUG ONLY
769 | }
770 |
771 | // The Copy/Add commands.
772 | for (var mode = 0; mode < cpyModes; mode++) {
773 | var max = (mode < 2 + desc.near_modes) ? //
774 | desc.copyadd_near_cpy_max :
775 | desc.copyadd_same_cpy_max;
776 | for (var size1 = MIN_MATCH; size1 <= max; size1++) {
777 | for (var size2 = 1; size2 <= desc.copyadd_add_max; size2++) {
778 | tableRows[row].type1 = XD3_CPY + mode;
779 | tableRows[row].size1 = size1;
780 | tableRows[row].type2 = XD3_ADD;
781 | tableRows[row++].size2 = size2;
782 | }
783 | }
784 | }
785 | dumpCodeTableRows(tableRows, startRow, row); // DEBUG ONLY
786 |
787 | return new xd3_dinst_table(tableRows);
788 | }
789 |
790 |
791 | /**
792 | * @constructor
793 | */
794 | function xd3_code_table_desc() {
795 | this.add_sizes = 0;
796 | this.near_modes = 0;
797 | this.same_modes = 0;
798 | this.cpy_sizes = 0;
799 |
800 | this.addcopy_add_max = 0;
801 | this.addcopy_near_cpy_max = 0;
802 | this.addcopy_same_cpy_max = 0;
803 |
804 | this.copyadd_add_max = 0;
805 | this.copyadd_near_cpy_max = 0;
806 | this.copyadd_same_cpy_max = 0;
807 | }
808 |
809 |
810 | /**
811 | * This builds the __rfc3284_code_table_desc
812 | * Assumes a single RUN instruction
813 | * Assumes that MIN_MATCH is 4.
814 | * @return {!xd3_code_table_desc}
815 | */
816 | function build_rfc3284_code_table_desc() {
817 | var desc = new xd3_code_table_desc();
818 | desc.add_sizes = 17;
819 | desc.near_modes = 4;
820 | desc.same_modes = 3;
821 | desc.cpy_sizes = 15;
822 |
823 | desc.addcopy_add_max = 4;
824 | desc.addcopy_near_cpy_max = 6;
825 | desc.addcopy_same_cpy_max = 4;
826 |
827 | desc.copyadd_add_max = 1;
828 | desc.copyadd_near_cpy_max = 4;
829 | desc.copyadd_same_cpy_max = 4;
830 |
831 | // xd3_code_table_sizes addcopy_max_sizes[MAX_MODES];
832 | // { {6,163,3},{6,175,3},{6,187,3},{6,199,3},{6,211,3},{6,223,3},
833 | // {4,235,1},{4,239,1},{4,243,1} },
834 |
835 | // xd3_code_table_sizes copyadd_max_sizes[MAX_MODES];
836 | // { {4,247,1},{4,248,1},{4,249,1},{4,250,1},{4,251,1},{4,252,1},
837 | // {4,253,1},{4,254,1},{4,255,1} },
838 |
839 | return desc;
840 | }
841 |
842 | var __rfc3284_code_table_desc = build_rfc3284_code_table_desc();
843 |
844 | var A32_BASE = 65521; /* Largest prime smaller than 2^16 */
845 | var A32_NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2
846 | + (n+1)(BASE-1) <= 2^32-1 */
847 |
848 | // 1140 #define A32_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
849 | // 1141 #define A32_DO2(buf,i) A32_DO1(buf,i); A32_DO1(buf,i+1);
850 | // 1142 #define A32_DO4(buf,i) A32_DO2(buf,i); A32_DO2(buf,i+2);
851 | // 1143 #define A32_DO8(buf,i) A32_DO4(buf,i); A32_DO4(buf,i+4);
852 | // 1144 #define A32_DO16(buf) A32_DO8(buf,0); A32_DO8(buf,8);
853 |
854 |
855 | /**
856 | * Calculated the Adler32 checksum.
857 | * @param {number} adler I'm not sure what this is.
858 | * @param {!Uint8Array} buf
859 | * @param {number} pos
860 | * @param {number} len
861 | * @return {number}
862 | */
863 | function adler32(adler, buf, pos, len) {
864 | printf("adler32: adler = "+adler+"\n"); // DEBUG ONLY
865 | printf("adler32: len = "+len+"\n"); // DEBUG ONLY
866 | var s1 = adler & 0xffff;
867 | var s2 = (adler >> 16) & 0xffff;
868 | var k;
869 |
870 | while (len > 0) {
871 | k = (len < A32_NMAX) ? len : A32_NMAX;
872 | len -= k;
873 |
874 | if (k != 0) {
875 | do {
876 | s1 += buf[pos++];
877 | s2 += s1;
878 | } while (--k);
879 | }
880 |
881 | s1 %= A32_BASE;
882 | s2 %= A32_BASE;
883 | }
884 |
885 | return (s2 << 16) | s1;
886 | }
887 |
888 |
889 | /**
890 | * @constructor
891 | */
892 | function xd3_addr_cache(s_near, s_same) {
893 | this.s_near = s_near;
894 | this.s_same = s_same;
895 | this.next_slot = 0; /* the circular index for near */
896 | this.near_array = null; /* array of size s_near */
897 | this.same_array = null; /* array of size s_same*256 */
898 | }
899 |
900 |
901 | /**
902 | * @param {!xd3_addr_cache} acache
903 | */
904 | function xd3_init_cache(acache) {
905 | printf("xd3_init_cache\n"); // DEBUG ONLY
906 | if (acache.s_near > 0) {
907 | for (var i = 0; i < acache.near_array.length; i++) {
908 | acache.near_array[i] = 0;
909 | }
910 | acache.next_slot = 0;
911 | }
912 |
913 | if (acache.s_same > 0) {
914 | for (var i = 0; i < acache.same_array.length; i++) {
915 | acache.same_array[i] = 0;
916 | }
917 | }
918 | }
919 |
920 | /**
921 | * Used by the decoder to buffer input in sections.
922 | * XDelta3 C++ struct.
923 | * @constructor
924 | * @struct
925 | */
926 | function xd3_desect() {
927 | /**
928 | * The buffer as a slice of the backingBuffer;
929 | * @type {?Uint8Array}
930 | */
931 | this.bytes = null;
932 |
933 | /** @type {number} */
934 | this.size = 0;
935 |
936 | /** @type {number} */
937 | this.pos = 0;
938 | }
939 |
940 | /**
941 | * Gets a byte from the section.
942 | * @return {number}
943 | */
944 | xd3_desect.prototype.getByte = function() {
945 | if (!this.bytes) {
946 | throw new Error('bytes not set');
947 | }
948 | return this.bytes[this.pos++];
949 | };
950 |
951 | /**
952 | * Gets an integer from the section.
953 | * XDelta3 integers are encodes as a variable number of 7 bit bytes. Bit 8, the
954 | * most significant bit is used to indicate more bytes needed.
955 | * @return {number}
956 | */
957 | xd3_desect.prototype.getInteger = function() {
958 | if (!this.bytes) {
959 | throw new Error('bytes not set');
960 | }
961 | var val = 0;
962 | for (var i = 0; i < 10; i++) {
963 | var aByte = this.bytes[this.pos++];
964 | val += aByte & 0x7F;
965 | if (!(aByte & 0x80)) {
966 | return val;
967 | }
968 | val <<= 7;
969 | }
970 | throw new Error('invalid number');
971 | };
972 |
973 |
974 | /**
975 | * Builds a default code table.
976 | * @return {!xd3_dinst_table}
977 | */
978 | function xd3_rfc3284_code_table() {
979 | printf("xd3_rfc3284_code_table\n"); // DEBUG ONLY
980 | return xd3_build_code_table(__rfc3284_code_table_desc);
981 | }
982 |
983 | /**
984 | * Allocates and initializes a Javascript Array.
985 | * @return {!Array}
986 | */
987 | function allocArray(len, val) {
988 | var arr = new Array(len);
989 | for (var i = 0; i < len; i++) {
990 | arr[i] = val;
991 | }
992 | return arr;
993 | }
994 |
995 | /**
996 | * @constructor
997 | */
998 | function xd3_source() {
999 | /** @type {number} */
1000 | this.cpyoff_blkoff = -1;
1001 | }
1002 |
1003 | /**
1004 | * @param {!Uint8Array} bytes
1005 | * @constructor
1006 | */
1007 | function DataObject(bytes) {
1008 | this.pos = 0;
1009 | this.bytes = bytes;
1010 | };
1011 |
1012 | DataObject.prototype.getByte = function() {
1013 | return this.bytes[this.pos++];
1014 | };
1015 |
1016 | DataObject.prototype.getInteger = function() {
1017 | var val = 0;
1018 | for (var i = 0; i < 10; i++) {
1019 | var aByte = this.bytes[this.pos++];
1020 | val += aByte & 0x7F;
1021 | if (!(aByte & 0x80)) {
1022 | return val;
1023 | }
1024 | val <<= 7;
1025 | }
1026 | throw new Error('invalid number');
1027 | };
1028 |
1029 | DataObject.prototype.fill = function(val, length) {
1030 | // TODO(bstell): see if there is a function for this.
1031 | for (var i = 0; i < length; i++) {
1032 | this.bytes[this.pos++] = val;
1033 | }
1034 | };
1035 |
1036 | /**
1037 | * @param {!xd3_desect} sect
1038 | * @param {number} length
1039 | */
1040 | DataObject.prototype.copySect = function(sect, length) {
1041 | // TODO(bstell): see if there is a function for this.
1042 | for (var i = 0; i < length; i++) {
1043 | this.bytes[this.pos++] = sect.bytes[sect.pos++];
1044 | }
1045 | };
1046 |
1047 | DataObject.prototype.copyBytes = function(bytes, offset, length) {
1048 | // TODO(bstell): see if there is a function for this.
1049 | for (var i = 0; i < length; i++) {
1050 | this.bytes[this.pos++] = bytes[offset++];
1051 | }
1052 | };
1053 |
1054 | })();
1055 |
--------------------------------------------------------------------------------