novnc-rails 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/COPYING +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +0 -0
- data/lib/novnc-rails.rb +8 -0
- data/lib/novnc-rails/version.rb +5 -0
- data/vendor/assets/javascripts/noVNC/Orbitron700.ttf +0 -0
- data/vendor/assets/javascripts/noVNC/Orbitron700.woff +0 -0
- data/vendor/assets/javascripts/noVNC/base.css +512 -0
- data/vendor/assets/javascripts/noVNC/base64.js +113 -0
- data/vendor/assets/javascripts/noVNC/black.css +71 -0
- data/vendor/assets/javascripts/noVNC/blue.css +64 -0
- data/vendor/assets/javascripts/noVNC/des.js +276 -0
- data/vendor/assets/javascripts/noVNC/display.js +751 -0
- data/vendor/assets/javascripts/noVNC/input.js +388 -0
- data/vendor/assets/javascripts/noVNC/jsunzip.js +676 -0
- data/vendor/assets/javascripts/noVNC/keyboard.js +543 -0
- data/vendor/assets/javascripts/noVNC/keysym.js +378 -0
- data/vendor/assets/javascripts/noVNC/keysymdef.js +15 -0
- data/vendor/assets/javascripts/noVNC/logo.js +1 -0
- data/vendor/assets/javascripts/noVNC/playback.js +102 -0
- data/vendor/assets/javascripts/noVNC/rfb.js +1889 -0
- data/vendor/assets/javascripts/noVNC/ui.js +979 -0
- data/vendor/assets/javascripts/noVNC/util.js +656 -0
- data/vendor/assets/javascripts/noVNC/web-socket-js/README.txt +109 -0
- data/vendor/assets/javascripts/noVNC/web-socket-js/WebSocketMain.swf +0 -0
- data/vendor/assets/javascripts/noVNC/web-socket-js/swfobject.js +4 -0
- data/vendor/assets/javascripts/noVNC/web-socket-js/web_socket.js +391 -0
- data/vendor/assets/javascripts/noVNC/websock.js +388 -0
- data/vendor/assets/javascripts/noVNC/webutil.js +239 -0
- metadata +86 -0
@@ -0,0 +1,388 @@
|
|
1
|
+
/*
|
2
|
+
* noVNC: HTML5 VNC client
|
3
|
+
* Copyright (C) 2012 Joel Martin
|
4
|
+
* Copyright (C) 2013 Samuel Mannehed for Cendio AB
|
5
|
+
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
6
|
+
*/
|
7
|
+
|
8
|
+
/*jslint browser: true, white: false */
|
9
|
+
/*global window, Util */
|
10
|
+
|
11
|
+
var Keyboard, Mouse;
|
12
|
+
|
13
|
+
(function () {
|
14
|
+
"use strict";
|
15
|
+
|
16
|
+
//
|
17
|
+
// Keyboard event handler
|
18
|
+
//
|
19
|
+
|
20
|
+
Keyboard = function (defaults) {
|
21
|
+
this._keyDownList = []; // List of depressed keys
|
22
|
+
// (even if they are happy)
|
23
|
+
|
24
|
+
Util.set_defaults(this, defaults, {
|
25
|
+
'target': document,
|
26
|
+
'focused': true
|
27
|
+
});
|
28
|
+
|
29
|
+
// create the keyboard handler
|
30
|
+
this._handler = new KeyEventDecoder(kbdUtil.ModifierSync(),
|
31
|
+
VerifyCharModifier( /* jshint newcap: false */
|
32
|
+
TrackKeyState(
|
33
|
+
EscapeModifiers(this._handleRfbEvent.bind(this))
|
34
|
+
)
|
35
|
+
)
|
36
|
+
); /* jshint newcap: true */
|
37
|
+
|
38
|
+
// keep these here so we can refer to them later
|
39
|
+
this._eventHandlers = {
|
40
|
+
'keyup': this._handleKeyUp.bind(this),
|
41
|
+
'keydown': this._handleKeyDown.bind(this),
|
42
|
+
'keypress': this._handleKeyPress.bind(this),
|
43
|
+
'blur': this._allKeysUp.bind(this)
|
44
|
+
};
|
45
|
+
};
|
46
|
+
|
47
|
+
Keyboard.prototype = {
|
48
|
+
// private methods
|
49
|
+
|
50
|
+
_handleRfbEvent: function (e) {
|
51
|
+
if (this._onKeyPress) {
|
52
|
+
Util.Debug("onKeyPress " + (e.type == 'keydown' ? "down" : "up") +
|
53
|
+
", keysym: " + e.keysym.keysym + "(" + e.keysym.keyname + ")");
|
54
|
+
this._onKeyPress(e.keysym.keysym, e.type == 'keydown');
|
55
|
+
}
|
56
|
+
},
|
57
|
+
|
58
|
+
_handleKeyDown: function (e) {
|
59
|
+
if (!this._focused) { return true; }
|
60
|
+
|
61
|
+
if (this._handler.keydown(e)) {
|
62
|
+
// Suppress bubbling/default actions
|
63
|
+
Util.stopEvent(e);
|
64
|
+
return false;
|
65
|
+
} else {
|
66
|
+
// Allow the event to bubble and become a keyPress event which
|
67
|
+
// will have the character code translated
|
68
|
+
return true;
|
69
|
+
}
|
70
|
+
},
|
71
|
+
|
72
|
+
_handleKeyPress: function (e) {
|
73
|
+
if (!this._focused) { return true; }
|
74
|
+
|
75
|
+
if (this._handler.keypress(e)) {
|
76
|
+
// Suppress bubbling/default actions
|
77
|
+
Util.stopEvent(e);
|
78
|
+
return false;
|
79
|
+
} else {
|
80
|
+
// Allow the event to bubble and become a keyPress event which
|
81
|
+
// will have the character code translated
|
82
|
+
return true;
|
83
|
+
}
|
84
|
+
},
|
85
|
+
|
86
|
+
_handleKeyUp: function (e) {
|
87
|
+
if (!this._focused) { return true; }
|
88
|
+
|
89
|
+
if (this._handler.keyup(e)) {
|
90
|
+
// Suppress bubbling/default actions
|
91
|
+
Util.stopEvent(e);
|
92
|
+
return false;
|
93
|
+
} else {
|
94
|
+
// Allow the event to bubble and become a keyPress event which
|
95
|
+
// will have the character code translated
|
96
|
+
return true;
|
97
|
+
}
|
98
|
+
},
|
99
|
+
|
100
|
+
_allKeysUp: function () {
|
101
|
+
Util.Debug(">> Keyboard.allKeysUp");
|
102
|
+
this._handler.releaseAll();
|
103
|
+
Util.Debug("<< Keyboard.allKeysUp");
|
104
|
+
},
|
105
|
+
|
106
|
+
// Public methods
|
107
|
+
|
108
|
+
grab: function () {
|
109
|
+
//Util.Debug(">> Keyboard.grab");
|
110
|
+
var c = this._target;
|
111
|
+
|
112
|
+
Util.addEvent(c, 'keydown', this._eventHandlers.keydown);
|
113
|
+
Util.addEvent(c, 'keyup', this._eventHandlers.keyup);
|
114
|
+
Util.addEvent(c, 'keypress', this._eventHandlers.keypress);
|
115
|
+
|
116
|
+
// Release (key up) if window loses focus
|
117
|
+
Util.addEvent(window, 'blur', this._eventHandlers.blur);
|
118
|
+
|
119
|
+
//Util.Debug("<< Keyboard.grab");
|
120
|
+
},
|
121
|
+
|
122
|
+
ungrab: function () {
|
123
|
+
//Util.Debug(">> Keyboard.ungrab");
|
124
|
+
var c = this._target;
|
125
|
+
|
126
|
+
Util.removeEvent(c, 'keydown', this._eventHandlers.keydown);
|
127
|
+
Util.removeEvent(c, 'keyup', this._eventHandlers.keyup);
|
128
|
+
Util.removeEvent(c, 'keypress', this._eventHandlers.keypress);
|
129
|
+
Util.removeEvent(window, 'blur', this._eventHandlers.blur);
|
130
|
+
|
131
|
+
// Release (key up) all keys that are in a down state
|
132
|
+
this._allKeysUp();
|
133
|
+
|
134
|
+
//Util.Debug(">> Keyboard.ungrab");
|
135
|
+
},
|
136
|
+
|
137
|
+
sync: function (e) {
|
138
|
+
this._handler.syncModifiers(e);
|
139
|
+
}
|
140
|
+
};
|
141
|
+
|
142
|
+
Util.make_properties(Keyboard, [
|
143
|
+
['target', 'wo', 'dom'], // DOM element that captures keyboard input
|
144
|
+
['focused', 'rw', 'bool'], // Capture and send key events
|
145
|
+
|
146
|
+
['onKeyPress', 'rw', 'func'] // Handler for key press/release
|
147
|
+
]);
|
148
|
+
|
149
|
+
//
|
150
|
+
// Mouse event handler
|
151
|
+
//
|
152
|
+
|
153
|
+
Mouse = function (defaults) {
|
154
|
+
this._mouseCaptured = false;
|
155
|
+
|
156
|
+
this._doubleClickTimer = null;
|
157
|
+
this._lastTouchPos = null;
|
158
|
+
|
159
|
+
// Configuration attributes
|
160
|
+
Util.set_defaults(this, defaults, {
|
161
|
+
'target': document,
|
162
|
+
'focused': true,
|
163
|
+
'scale': 1.0,
|
164
|
+
'touchButton': 1
|
165
|
+
});
|
166
|
+
|
167
|
+
this._eventHandlers = {
|
168
|
+
'mousedown': this._handleMouseDown.bind(this),
|
169
|
+
'mouseup': this._handleMouseUp.bind(this),
|
170
|
+
'mousemove': this._handleMouseMove.bind(this),
|
171
|
+
'mousewheel': this._handleMouseWheel.bind(this),
|
172
|
+
'mousedisable': this._handleMouseDisable.bind(this)
|
173
|
+
};
|
174
|
+
};
|
175
|
+
|
176
|
+
Mouse.prototype = {
|
177
|
+
// private methods
|
178
|
+
_captureMouse: function () {
|
179
|
+
// capturing the mouse ensures we get the mouseup event
|
180
|
+
if (this._target.setCapture) {
|
181
|
+
this._target.setCapture();
|
182
|
+
}
|
183
|
+
|
184
|
+
// some browsers give us mouseup events regardless,
|
185
|
+
// so if we never captured the mouse, we can disregard the event
|
186
|
+
this._mouseCaptured = true;
|
187
|
+
},
|
188
|
+
|
189
|
+
_releaseMouse: function () {
|
190
|
+
if (this._target.releaseCapture) {
|
191
|
+
this._target.releaseCapture();
|
192
|
+
}
|
193
|
+
this._mouseCaptured = false;
|
194
|
+
},
|
195
|
+
|
196
|
+
_resetDoubleClickTimer: function () {
|
197
|
+
this._doubleClickTimer = null;
|
198
|
+
},
|
199
|
+
|
200
|
+
_handleMouseButton: function (e, down) {
|
201
|
+
if (!this._focused) { return true; }
|
202
|
+
|
203
|
+
if (this._notify) {
|
204
|
+
this._notify(e);
|
205
|
+
}
|
206
|
+
|
207
|
+
var evt = (e ? e : window.event);
|
208
|
+
var pos = Util.getEventPosition(e, this._target, this._scale);
|
209
|
+
|
210
|
+
var bmask;
|
211
|
+
if (e.touches || e.changedTouches) {
|
212
|
+
// Touch device
|
213
|
+
|
214
|
+
// When two touches occur within 500 ms of each other and are
|
215
|
+
// closer than 20 pixels together a double click is triggered.
|
216
|
+
if (down == 1) {
|
217
|
+
if (this._doubleClickTimer === null) {
|
218
|
+
this._lastTouchPos = pos;
|
219
|
+
} else {
|
220
|
+
clearTimeout(this._doubleClickTimer);
|
221
|
+
|
222
|
+
// When the distance between the two touches is small enough
|
223
|
+
// force the position of the latter touch to the position of
|
224
|
+
// the first.
|
225
|
+
|
226
|
+
var xs = this._lastTouchPos.x - pos.x;
|
227
|
+
var ys = this._lastTouchPos.y - pos.y;
|
228
|
+
var d = Math.sqrt((xs * xs) + (ys * ys));
|
229
|
+
|
230
|
+
// The goal is to trigger on a certain physical width, the
|
231
|
+
// devicePixelRatio brings us a bit closer but is not optimal.
|
232
|
+
if (d < 20 * window.devicePixelRatio) {
|
233
|
+
pos = this._lastTouchPos;
|
234
|
+
}
|
235
|
+
}
|
236
|
+
this._doubleClickTimer = setTimeout(this._resetDoubleClickTimer.bind(this), 500);
|
237
|
+
}
|
238
|
+
bmask = this._touchButton;
|
239
|
+
// If bmask is set
|
240
|
+
} else if (evt.which) {
|
241
|
+
/* everything except IE */
|
242
|
+
bmask = 1 << evt.button;
|
243
|
+
} else {
|
244
|
+
/* IE including 9 */
|
245
|
+
bmask = (evt.button & 0x1) + // Left
|
246
|
+
(evt.button & 0x2) * 2 + // Right
|
247
|
+
(evt.button & 0x4) / 2; // Middle
|
248
|
+
}
|
249
|
+
|
250
|
+
if (this._onMouseButton) {
|
251
|
+
Util.Debug("onMouseButton " + (down ? "down" : "up") +
|
252
|
+
", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
|
253
|
+
this._onMouseButton(pos.x, pos.y, down, bmask);
|
254
|
+
}
|
255
|
+
Util.stopEvent(e);
|
256
|
+
return false;
|
257
|
+
},
|
258
|
+
|
259
|
+
_handleMouseDown: function (e) {
|
260
|
+
this._captureMouse();
|
261
|
+
this._handleMouseButton(e, 1);
|
262
|
+
},
|
263
|
+
|
264
|
+
_handleMouseUp: function (e) {
|
265
|
+
if (!this._mouseCaptured) { return; }
|
266
|
+
|
267
|
+
this._handleMouseButton(e, 0);
|
268
|
+
this._releaseMouse();
|
269
|
+
},
|
270
|
+
|
271
|
+
_handleMouseWheel: function (e) {
|
272
|
+
if (!this._focused) { return true; }
|
273
|
+
|
274
|
+
if (this._notify) {
|
275
|
+
this._notify(e);
|
276
|
+
}
|
277
|
+
|
278
|
+
var evt = (e ? e : window.event);
|
279
|
+
var pos = Util.getEventPosition(e, this._target, this._scale);
|
280
|
+
var wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
|
281
|
+
var bmask;
|
282
|
+
if (wheelData > 0) {
|
283
|
+
bmask = 1 << 3;
|
284
|
+
} else {
|
285
|
+
bmask = 1 << 4;
|
286
|
+
}
|
287
|
+
|
288
|
+
if (this._onMouseButton) {
|
289
|
+
this._onMouseButton(pos.x, pos.y, 1, bmask);
|
290
|
+
this._onMouseButton(pos.x, pos.y, 0, bmask);
|
291
|
+
}
|
292
|
+
Util.stopEvent(e);
|
293
|
+
return false;
|
294
|
+
},
|
295
|
+
|
296
|
+
_handleMouseMove: function (e) {
|
297
|
+
if (! this._focused) { return true; }
|
298
|
+
|
299
|
+
if (this._notify) {
|
300
|
+
this._notify(e);
|
301
|
+
}
|
302
|
+
|
303
|
+
var evt = (e ? e : window.event);
|
304
|
+
var pos = Util.getEventPosition(e, this._target, this._scale);
|
305
|
+
if (this._onMouseMove) {
|
306
|
+
this._onMouseMove(pos.x, pos.y);
|
307
|
+
}
|
308
|
+
Util.stopEvent(e);
|
309
|
+
return false;
|
310
|
+
},
|
311
|
+
|
312
|
+
_handleMouseDisable: function (e) {
|
313
|
+
if (!this._focused) { return true; }
|
314
|
+
|
315
|
+
var evt = (e ? e : window.event);
|
316
|
+
var pos = Util.getEventPosition(e, this._target, this._scale);
|
317
|
+
|
318
|
+
/* Stop propagation if inside canvas area */
|
319
|
+
if ((pos.realx >= 0) && (pos.realy >= 0) &&
|
320
|
+
(pos.realx < this._target.offsetWidth) &&
|
321
|
+
(pos.realy < this._target.offsetHeight)) {
|
322
|
+
//Util.Debug("mouse event disabled");
|
323
|
+
Util.stopEvent(e);
|
324
|
+
return false;
|
325
|
+
}
|
326
|
+
|
327
|
+
return true;
|
328
|
+
},
|
329
|
+
|
330
|
+
|
331
|
+
// Public methods
|
332
|
+
grab: function () {
|
333
|
+
var c = this._target;
|
334
|
+
|
335
|
+
if ('ontouchstart' in document.documentElement) {
|
336
|
+
Util.addEvent(c, 'touchstart', this._eventHandlers.mousedown);
|
337
|
+
Util.addEvent(window, 'touchend', this._eventHandlers.mouseup);
|
338
|
+
Util.addEvent(c, 'touchend', this._eventHandlers.mouseup);
|
339
|
+
Util.addEvent(c, 'touchmove', this._eventHandlers.mousemove);
|
340
|
+
} else {
|
341
|
+
Util.addEvent(c, 'mousedown', this._eventHandlers.mousedown);
|
342
|
+
Util.addEvent(window, 'mouseup', this._eventHandlers.mouseup);
|
343
|
+
Util.addEvent(c, 'mouseup', this._eventHandlers.mouseup);
|
344
|
+
Util.addEvent(c, 'mousemove', this._eventHandlers.mousemove);
|
345
|
+
Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
|
346
|
+
this._eventHandlers.mousewheel);
|
347
|
+
}
|
348
|
+
|
349
|
+
/* Work around right and middle click browser behaviors */
|
350
|
+
Util.addEvent(document, 'click', this._eventHandlers.mousedisable);
|
351
|
+
Util.addEvent(document.body, 'contextmenu', this._eventHandlers.mousedisable);
|
352
|
+
},
|
353
|
+
|
354
|
+
ungrab: function () {
|
355
|
+
var c = this._target;
|
356
|
+
|
357
|
+
if ('ontouchstart' in document.documentElement) {
|
358
|
+
Util.removeEvent(c, 'touchstart', this._eventHandlers.mousedown);
|
359
|
+
Util.removeEvent(window, 'touchend', this._eventHandlers.mouseup);
|
360
|
+
Util.removeEvent(c, 'touchend', this._eventHandlers.mouseup);
|
361
|
+
Util.removeEvent(c, 'touchmove', this._eventHandlers.mousemove);
|
362
|
+
} else {
|
363
|
+
Util.removeEvent(c, 'mousedown', this._eventHandlers.mousedown);
|
364
|
+
Util.removeEvent(window, 'mouseup', this._eventHandlers.mouseup);
|
365
|
+
Util.removeEvent(c, 'mouseup', this._eventHandlers.mouseup);
|
366
|
+
Util.removeEvent(c, 'mousemove', this._eventHandlers.mousemove);
|
367
|
+
Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
|
368
|
+
this._eventHandlers.mousewheel);
|
369
|
+
}
|
370
|
+
|
371
|
+
/* Work around right and middle click browser behaviors */
|
372
|
+
Util.removeEvent(document, 'click', this._eventHandlers.mousedisable);
|
373
|
+
Util.removeEvent(document.body, 'contextmenu', this._eventHandlers.mousedisable);
|
374
|
+
|
375
|
+
}
|
376
|
+
};
|
377
|
+
|
378
|
+
Util.make_properties(Mouse, [
|
379
|
+
['target', 'ro', 'dom'], // DOM element that captures mouse input
|
380
|
+
['notify', 'ro', 'func'], // Function to call to notify whenever a mouse event is received
|
381
|
+
['focused', 'rw', 'bool'], // Capture and send mouse clicks/movement
|
382
|
+
['scale', 'rw', 'float'], // Viewport scale factor 0.0 - 1.0
|
383
|
+
|
384
|
+
['onMouseButton', 'rw', 'func'], // Handler for mouse button click/release
|
385
|
+
['onMouseMove', 'rw', 'func'], // Handler for mouse movement
|
386
|
+
['touchButton', 'rw', 'int'] // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
387
|
+
]);
|
388
|
+
})();
|
@@ -0,0 +1,676 @@
|
|
1
|
+
/*
|
2
|
+
* JSUnzip
|
3
|
+
*
|
4
|
+
* Copyright (c) 2011 by Erik Moller
|
5
|
+
* All Rights Reserved
|
6
|
+
*
|
7
|
+
* This software is provided 'as-is', without any express
|
8
|
+
* or implied warranty. In no event will the authors be
|
9
|
+
* held liable for any damages arising from the use of
|
10
|
+
* this software.
|
11
|
+
*
|
12
|
+
* Permission is granted to anyone to use this software
|
13
|
+
* for any purpose, including commercial applications,
|
14
|
+
* and to alter it and redistribute it freely, subject to
|
15
|
+
* the following restrictions:
|
16
|
+
*
|
17
|
+
* 1. The origin of this software must not be
|
18
|
+
* misrepresented; you must not claim that you
|
19
|
+
* wrote the original software. If you use this
|
20
|
+
* software in a product, an acknowledgment in
|
21
|
+
* the product documentation would be appreciated
|
22
|
+
* but is not required.
|
23
|
+
*
|
24
|
+
* 2. Altered source versions must be plainly marked
|
25
|
+
* as such, and must not be misrepresented as
|
26
|
+
* being the original software.
|
27
|
+
*
|
28
|
+
* 3. This notice may not be removed or altered from
|
29
|
+
* any source distribution.
|
30
|
+
*/
|
31
|
+
|
32
|
+
var tinf;
|
33
|
+
|
34
|
+
function JSUnzip() {
|
35
|
+
|
36
|
+
this.getInt = function(offset, size) {
|
37
|
+
switch (size) {
|
38
|
+
case 4:
|
39
|
+
return (this.data.charCodeAt(offset + 3) & 0xff) << 24 |
|
40
|
+
(this.data.charCodeAt(offset + 2) & 0xff) << 16 |
|
41
|
+
(this.data.charCodeAt(offset + 1) & 0xff) << 8 |
|
42
|
+
(this.data.charCodeAt(offset + 0) & 0xff);
|
43
|
+
break;
|
44
|
+
case 2:
|
45
|
+
return (this.data.charCodeAt(offset + 1) & 0xff) << 8 |
|
46
|
+
(this.data.charCodeAt(offset + 0) & 0xff);
|
47
|
+
break;
|
48
|
+
default:
|
49
|
+
return this.data.charCodeAt(offset) & 0xff;
|
50
|
+
break;
|
51
|
+
}
|
52
|
+
};
|
53
|
+
|
54
|
+
this.getDOSDate = function(dosdate, dostime) {
|
55
|
+
var day = dosdate & 0x1f;
|
56
|
+
var month = ((dosdate >> 5) & 0xf) - 1;
|
57
|
+
var year = 1980 + ((dosdate >> 9) & 0x7f)
|
58
|
+
var second = (dostime & 0x1f) * 2;
|
59
|
+
var minute = (dostime >> 5) & 0x3f;
|
60
|
+
hour = (dostime >> 11) & 0x1f;
|
61
|
+
return new Date(year, month, day, hour, minute, second);
|
62
|
+
}
|
63
|
+
|
64
|
+
this.open = function(data) {
|
65
|
+
this.data = data;
|
66
|
+
this.files = [];
|
67
|
+
|
68
|
+
if (this.data.length < 22)
|
69
|
+
return { 'status' : false, 'error' : 'Invalid data' };
|
70
|
+
var endOfCentralDirectory = this.data.length - 22;
|
71
|
+
while (endOfCentralDirectory >= 0 && this.getInt(endOfCentralDirectory, 4) != 0x06054b50)
|
72
|
+
--endOfCentralDirectory;
|
73
|
+
if (endOfCentralDirectory < 0)
|
74
|
+
return { 'status' : false, 'error' : 'Invalid data' };
|
75
|
+
if (this.getInt(endOfCentralDirectory + 4, 2) != 0 || this.getInt(endOfCentralDirectory + 6, 2) != 0)
|
76
|
+
return { 'status' : false, 'error' : 'No multidisk support' };
|
77
|
+
|
78
|
+
var entriesInThisDisk = this.getInt(endOfCentralDirectory + 8, 2);
|
79
|
+
var centralDirectoryOffset = this.getInt(endOfCentralDirectory + 16, 4);
|
80
|
+
var globalCommentLength = this.getInt(endOfCentralDirectory + 20, 2);
|
81
|
+
this.comment = this.data.slice(endOfCentralDirectory + 22, endOfCentralDirectory + 22 + globalCommentLength);
|
82
|
+
|
83
|
+
var fileOffset = centralDirectoryOffset;
|
84
|
+
|
85
|
+
for (var i = 0; i < entriesInThisDisk; ++i) {
|
86
|
+
if (this.getInt(fileOffset + 0, 4) != 0x02014b50)
|
87
|
+
return { 'status' : false, 'error' : 'Invalid data' };
|
88
|
+
if (this.getInt(fileOffset + 6, 2) > 20)
|
89
|
+
return { 'status' : false, 'error' : 'Unsupported version' };
|
90
|
+
if (this.getInt(fileOffset + 8, 2) & 1)
|
91
|
+
return { 'status' : false, 'error' : 'Encryption not implemented' };
|
92
|
+
|
93
|
+
var compressionMethod = this.getInt(fileOffset + 10, 2);
|
94
|
+
if (compressionMethod != 0 && compressionMethod != 8)
|
95
|
+
return { 'status' : false, 'error' : 'Unsupported compression method' };
|
96
|
+
|
97
|
+
var lastModFileTime = this.getInt(fileOffset + 12, 2);
|
98
|
+
var lastModFileDate = this.getInt(fileOffset + 14, 2);
|
99
|
+
var lastModifiedDate = this.getDOSDate(lastModFileDate, lastModFileTime);
|
100
|
+
|
101
|
+
var crc = this.getInt(fileOffset + 16, 4);
|
102
|
+
// TODO: crc
|
103
|
+
|
104
|
+
var compressedSize = this.getInt(fileOffset + 20, 4);
|
105
|
+
var uncompressedSize = this.getInt(fileOffset + 24, 4);
|
106
|
+
|
107
|
+
var fileNameLength = this.getInt(fileOffset + 28, 2);
|
108
|
+
var extraFieldLength = this.getInt(fileOffset + 30, 2);
|
109
|
+
var fileCommentLength = this.getInt(fileOffset + 32, 2);
|
110
|
+
|
111
|
+
var relativeOffsetOfLocalHeader = this.getInt(fileOffset + 42, 4);
|
112
|
+
|
113
|
+
var fileName = this.data.slice(fileOffset + 46, fileOffset + 46 + fileNameLength);
|
114
|
+
var fileComment = this.data.slice(fileOffset + 46 + fileNameLength + extraFieldLength, fileOffset + 46 + fileNameLength + extraFieldLength + fileCommentLength);
|
115
|
+
|
116
|
+
if (this.getInt(relativeOffsetOfLocalHeader + 0, 4) != 0x04034b50)
|
117
|
+
return { 'status' : false, 'error' : 'Invalid data' };
|
118
|
+
var localFileNameLength = this.getInt(relativeOffsetOfLocalHeader + 26, 2);
|
119
|
+
var localExtraFieldLength = this.getInt(relativeOffsetOfLocalHeader + 28, 2);
|
120
|
+
var localFileContent = relativeOffsetOfLocalHeader + 30 + localFileNameLength + localExtraFieldLength;
|
121
|
+
|
122
|
+
this.files[fileName] =
|
123
|
+
{
|
124
|
+
'fileComment' : fileComment,
|
125
|
+
'compressionMethod' : compressionMethod,
|
126
|
+
'compressedSize' : compressedSize,
|
127
|
+
'uncompressedSize' : uncompressedSize,
|
128
|
+
'localFileContent' : localFileContent,
|
129
|
+
'lastModifiedDate' : lastModifiedDate
|
130
|
+
};
|
131
|
+
|
132
|
+
fileOffset += 46 + fileNameLength + extraFieldLength + fileCommentLength;
|
133
|
+
}
|
134
|
+
return { 'status' : true }
|
135
|
+
};
|
136
|
+
|
137
|
+
|
138
|
+
this.read = function(fileName) {
|
139
|
+
var fileInfo = this.files[fileName];
|
140
|
+
if (fileInfo) {
|
141
|
+
if (fileInfo.compressionMethod == 8) {
|
142
|
+
if (!tinf) {
|
143
|
+
tinf = new TINF();
|
144
|
+
tinf.init();
|
145
|
+
}
|
146
|
+
var result = tinf.uncompress(this.data, fileInfo.localFileContent);
|
147
|
+
if (result.status == tinf.OK)
|
148
|
+
return { 'status' : true, 'data' : result.data };
|
149
|
+
else
|
150
|
+
return { 'status' : false, 'error' : result.error };
|
151
|
+
} else {
|
152
|
+
return { 'status' : true, 'data' : this.data.slice(fileInfo.localFileContent, fileInfo.localFileContent + fileInfo.uncompressedSize) };
|
153
|
+
}
|
154
|
+
}
|
155
|
+
return { 'status' : false, 'error' : "File '" + fileName + "' doesn't exist in zip" };
|
156
|
+
};
|
157
|
+
|
158
|
+
};
|
159
|
+
|
160
|
+
|
161
|
+
|
162
|
+
/*
|
163
|
+
* tinflate - tiny inflate
|
164
|
+
*
|
165
|
+
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
166
|
+
* All Rights Reserved
|
167
|
+
*
|
168
|
+
* http://www.ibsensoftware.com/
|
169
|
+
*
|
170
|
+
* This software is provided 'as-is', without any express
|
171
|
+
* or implied warranty. In no event will the authors be
|
172
|
+
* held liable for any damages arising from the use of
|
173
|
+
* this software.
|
174
|
+
*
|
175
|
+
* Permission is granted to anyone to use this software
|
176
|
+
* for any purpose, including commercial applications,
|
177
|
+
* and to alter it and redistribute it freely, subject to
|
178
|
+
* the following restrictions:
|
179
|
+
*
|
180
|
+
* 1. The origin of this software must not be
|
181
|
+
* misrepresented; you must not claim that you
|
182
|
+
* wrote the original software. If you use this
|
183
|
+
* software in a product, an acknowledgment in
|
184
|
+
* the product documentation would be appreciated
|
185
|
+
* but is not required.
|
186
|
+
*
|
187
|
+
* 2. Altered source versions must be plainly marked
|
188
|
+
* as such, and must not be misrepresented as
|
189
|
+
* being the original software.
|
190
|
+
*
|
191
|
+
* 3. This notice may not be removed or altered from
|
192
|
+
* any source distribution.
|
193
|
+
*/
|
194
|
+
|
195
|
+
/*
|
196
|
+
* tinflate javascript port by Erik Moller in May 2011.
|
197
|
+
* emoller@opera.com
|
198
|
+
*
|
199
|
+
* read_bits() patched by mike@imidio.com to allow
|
200
|
+
* reading more then 8 bits (needed in some zlib streams)
|
201
|
+
*/
|
202
|
+
|
203
|
+
"use strict";
|
204
|
+
|
205
|
+
function TINF() {
|
206
|
+
|
207
|
+
this.OK = 0;
|
208
|
+
this.DATA_ERROR = (-3);
|
209
|
+
this.WINDOW_SIZE = 32768;
|
210
|
+
|
211
|
+
/* ------------------------------ *
|
212
|
+
* -- internal data structures -- *
|
213
|
+
* ------------------------------ */
|
214
|
+
|
215
|
+
this.TREE = function() {
|
216
|
+
this.table = new Array(16); /* table of code length counts */
|
217
|
+
this.trans = new Array(288); /* code -> symbol translation table */
|
218
|
+
};
|
219
|
+
|
220
|
+
this.DATA = function(that) {
|
221
|
+
this.source = '';
|
222
|
+
this.sourceIndex = 0;
|
223
|
+
this.tag = 0;
|
224
|
+
this.bitcount = 0;
|
225
|
+
|
226
|
+
this.dest = [];
|
227
|
+
|
228
|
+
this.history = [];
|
229
|
+
|
230
|
+
this.ltree = new that.TREE(); /* dynamic length/symbol tree */
|
231
|
+
this.dtree = new that.TREE(); /* dynamic distance tree */
|
232
|
+
};
|
233
|
+
|
234
|
+
/* --------------------------------------------------- *
|
235
|
+
* -- uninitialized global data (static structures) -- *
|
236
|
+
* --------------------------------------------------- */
|
237
|
+
|
238
|
+
this.sltree = new this.TREE(); /* fixed length/symbol tree */
|
239
|
+
this.sdtree = new this.TREE(); /* fixed distance tree */
|
240
|
+
|
241
|
+
/* extra bits and base tables for length codes */
|
242
|
+
this.length_bits = new Array(30);
|
243
|
+
this.length_base = new Array(30);
|
244
|
+
|
245
|
+
/* extra bits and base tables for distance codes */
|
246
|
+
this.dist_bits = new Array(30);
|
247
|
+
this.dist_base = new Array(30);
|
248
|
+
|
249
|
+
/* special ordering of code length codes */
|
250
|
+
this.clcidx = [
|
251
|
+
16, 17, 18, 0, 8, 7, 9, 6,
|
252
|
+
10, 5, 11, 4, 12, 3, 13, 2,
|
253
|
+
14, 1, 15
|
254
|
+
];
|
255
|
+
|
256
|
+
/* ----------------------- *
|
257
|
+
* -- utility functions -- *
|
258
|
+
* ----------------------- */
|
259
|
+
|
260
|
+
/* build extra bits and base tables */
|
261
|
+
this.build_bits_base = function(bits, base, delta, first)
|
262
|
+
{
|
263
|
+
var i, sum;
|
264
|
+
|
265
|
+
/* build bits table */
|
266
|
+
for (i = 0; i < delta; ++i) bits[i] = 0;
|
267
|
+
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = Math.floor(i / delta);
|
268
|
+
|
269
|
+
/* build base table */
|
270
|
+
for (sum = first, i = 0; i < 30; ++i)
|
271
|
+
{
|
272
|
+
base[i] = sum;
|
273
|
+
sum += 1 << bits[i];
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
/* build the fixed huffman trees */
|
278
|
+
this.build_fixed_trees = function(lt, dt)
|
279
|
+
{
|
280
|
+
var i;
|
281
|
+
|
282
|
+
/* build fixed length tree */
|
283
|
+
for (i = 0; i < 7; ++i) lt.table[i] = 0;
|
284
|
+
|
285
|
+
lt.table[7] = 24;
|
286
|
+
lt.table[8] = 152;
|
287
|
+
lt.table[9] = 112;
|
288
|
+
|
289
|
+
for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;
|
290
|
+
for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;
|
291
|
+
for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;
|
292
|
+
for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;
|
293
|
+
|
294
|
+
/* build fixed distance tree */
|
295
|
+
for (i = 0; i < 5; ++i) dt.table[i] = 0;
|
296
|
+
|
297
|
+
dt.table[5] = 32;
|
298
|
+
|
299
|
+
for (i = 0; i < 32; ++i) dt.trans[i] = i;
|
300
|
+
}
|
301
|
+
|
302
|
+
/* given an array of code lengths, build a tree */
|
303
|
+
this.build_tree = function(t, lengths, loffset, num)
|
304
|
+
{
|
305
|
+
var offs = new Array(16);
|
306
|
+
var i, sum;
|
307
|
+
|
308
|
+
/* clear code length count table */
|
309
|
+
for (i = 0; i < 16; ++i) t.table[i] = 0;
|
310
|
+
|
311
|
+
/* scan symbol lengths, and sum code length counts */
|
312
|
+
for (i = 0; i < num; ++i) t.table[lengths[loffset + i]]++;
|
313
|
+
|
314
|
+
t.table[0] = 0;
|
315
|
+
|
316
|
+
/* compute offset table for distribution sort */
|
317
|
+
for (sum = 0, i = 0; i < 16; ++i)
|
318
|
+
{
|
319
|
+
offs[i] = sum;
|
320
|
+
sum += t.table[i];
|
321
|
+
}
|
322
|
+
|
323
|
+
/* create code->symbol translation table (symbols sorted by code) */
|
324
|
+
for (i = 0; i < num; ++i)
|
325
|
+
{
|
326
|
+
if (lengths[loffset + i]) t.trans[offs[lengths[loffset + i]]++] = i;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
330
|
+
/* ---------------------- *
|
331
|
+
* -- decode functions -- *
|
332
|
+
* ---------------------- */
|
333
|
+
|
334
|
+
/* get one bit from source stream */
|
335
|
+
this.getbit = function(d)
|
336
|
+
{
|
337
|
+
var bit;
|
338
|
+
|
339
|
+
/* check if tag is empty */
|
340
|
+
if (!d.bitcount--)
|
341
|
+
{
|
342
|
+
/* load next tag */
|
343
|
+
d.tag = d.source[d.sourceIndex++] & 0xff;
|
344
|
+
d.bitcount = 7;
|
345
|
+
}
|
346
|
+
|
347
|
+
/* shift bit out of tag */
|
348
|
+
bit = d.tag & 0x01;
|
349
|
+
d.tag >>= 1;
|
350
|
+
|
351
|
+
return bit;
|
352
|
+
}
|
353
|
+
|
354
|
+
/* read a num bit value from a stream and add base */
|
355
|
+
function read_bits_direct(source, bitcount, tag, idx, num)
|
356
|
+
{
|
357
|
+
var val = 0;
|
358
|
+
while (bitcount < 24) {
|
359
|
+
tag = tag | (source[idx++] & 0xff) << bitcount;
|
360
|
+
bitcount += 8;
|
361
|
+
}
|
362
|
+
val = tag & (0xffff >> (16 - num));
|
363
|
+
tag >>= num;
|
364
|
+
bitcount -= num;
|
365
|
+
return [bitcount, tag, idx, val];
|
366
|
+
}
|
367
|
+
this.read_bits = function(d, num, base)
|
368
|
+
{
|
369
|
+
if (!num)
|
370
|
+
return base;
|
371
|
+
|
372
|
+
var ret = read_bits_direct(d.source, d.bitcount, d.tag, d.sourceIndex, num);
|
373
|
+
d.bitcount = ret[0];
|
374
|
+
d.tag = ret[1];
|
375
|
+
d.sourceIndex = ret[2];
|
376
|
+
return ret[3] + base;
|
377
|
+
}
|
378
|
+
|
379
|
+
/* given a data stream and a tree, decode a symbol */
|
380
|
+
this.decode_symbol = function(d, t)
|
381
|
+
{
|
382
|
+
while (d.bitcount < 16) {
|
383
|
+
d.tag = d.tag | (d.source[d.sourceIndex++] & 0xff) << d.bitcount;
|
384
|
+
d.bitcount += 8;
|
385
|
+
}
|
386
|
+
|
387
|
+
var sum = 0, cur = 0, len = 0;
|
388
|
+
do {
|
389
|
+
cur = 2 * cur + ((d.tag & (1 << len)) >> len);
|
390
|
+
|
391
|
+
++len;
|
392
|
+
|
393
|
+
sum += t.table[len];
|
394
|
+
cur -= t.table[len];
|
395
|
+
|
396
|
+
} while (cur >= 0);
|
397
|
+
|
398
|
+
d.tag >>= len;
|
399
|
+
d.bitcount -= len;
|
400
|
+
|
401
|
+
return t.trans[sum + cur];
|
402
|
+
}
|
403
|
+
|
404
|
+
/* given a data stream, decode dynamic trees from it */
|
405
|
+
this.decode_trees = function(d, lt, dt)
|
406
|
+
{
|
407
|
+
var code_tree = new this.TREE();
|
408
|
+
var lengths = new Array(288+32);
|
409
|
+
var hlit, hdist, hclen;
|
410
|
+
var i, num, length;
|
411
|
+
|
412
|
+
/* get 5 bits HLIT (257-286) */
|
413
|
+
hlit = this.read_bits(d, 5, 257);
|
414
|
+
|
415
|
+
/* get 5 bits HDIST (1-32) */
|
416
|
+
hdist = this.read_bits(d, 5, 1);
|
417
|
+
|
418
|
+
/* get 4 bits HCLEN (4-19) */
|
419
|
+
hclen = this.read_bits(d, 4, 4);
|
420
|
+
|
421
|
+
for (i = 0; i < 19; ++i) lengths[i] = 0;
|
422
|
+
|
423
|
+
/* read code lengths for code length alphabet */
|
424
|
+
for (i = 0; i < hclen; ++i)
|
425
|
+
{
|
426
|
+
/* get 3 bits code length (0-7) */
|
427
|
+
var clen = this.read_bits(d, 3, 0);
|
428
|
+
|
429
|
+
lengths[this.clcidx[i]] = clen;
|
430
|
+
}
|
431
|
+
|
432
|
+
/* build code length tree */
|
433
|
+
this.build_tree(code_tree, lengths, 0, 19);
|
434
|
+
|
435
|
+
/* decode code lengths for the dynamic trees */
|
436
|
+
for (num = 0; num < hlit + hdist; )
|
437
|
+
{
|
438
|
+
var sym = this.decode_symbol(d, code_tree);
|
439
|
+
|
440
|
+
switch (sym)
|
441
|
+
{
|
442
|
+
case 16:
|
443
|
+
/* copy previous code length 3-6 times (read 2 bits) */
|
444
|
+
{
|
445
|
+
var prev = lengths[num - 1];
|
446
|
+
for (length = this.read_bits(d, 2, 3); length; --length)
|
447
|
+
{
|
448
|
+
lengths[num++] = prev;
|
449
|
+
}
|
450
|
+
}
|
451
|
+
break;
|
452
|
+
case 17:
|
453
|
+
/* repeat code length 0 for 3-10 times (read 3 bits) */
|
454
|
+
for (length = this.read_bits(d, 3, 3); length; --length)
|
455
|
+
{
|
456
|
+
lengths[num++] = 0;
|
457
|
+
}
|
458
|
+
break;
|
459
|
+
case 18:
|
460
|
+
/* repeat code length 0 for 11-138 times (read 7 bits) */
|
461
|
+
for (length = this.read_bits(d, 7, 11); length; --length)
|
462
|
+
{
|
463
|
+
lengths[num++] = 0;
|
464
|
+
}
|
465
|
+
break;
|
466
|
+
default:
|
467
|
+
/* values 0-15 represent the actual code lengths */
|
468
|
+
lengths[num++] = sym;
|
469
|
+
break;
|
470
|
+
}
|
471
|
+
}
|
472
|
+
|
473
|
+
/* build dynamic trees */
|
474
|
+
this.build_tree(lt, lengths, 0, hlit);
|
475
|
+
this.build_tree(dt, lengths, hlit, hdist);
|
476
|
+
}
|
477
|
+
|
478
|
+
/* ----------------------------- *
|
479
|
+
* -- block inflate functions -- *
|
480
|
+
* ----------------------------- */
|
481
|
+
|
482
|
+
/* given a stream and two trees, inflate a block of data */
|
483
|
+
this.inflate_block_data = function(d, lt, dt)
|
484
|
+
{
|
485
|
+
// js optimization.
|
486
|
+
var ddest = d.dest;
|
487
|
+
var ddestlength = ddest.length;
|
488
|
+
|
489
|
+
while (1)
|
490
|
+
{
|
491
|
+
var sym = this.decode_symbol(d, lt);
|
492
|
+
|
493
|
+
/* check for end of block */
|
494
|
+
if (sym == 256)
|
495
|
+
{
|
496
|
+
return this.OK;
|
497
|
+
}
|
498
|
+
|
499
|
+
if (sym < 256)
|
500
|
+
{
|
501
|
+
ddest[ddestlength++] = sym; // ? String.fromCharCode(sym);
|
502
|
+
d.history.push(sym);
|
503
|
+
} else {
|
504
|
+
|
505
|
+
var length, dist, offs;
|
506
|
+
var i;
|
507
|
+
|
508
|
+
sym -= 257;
|
509
|
+
|
510
|
+
/* possibly get more bits from length code */
|
511
|
+
length = this.read_bits(d, this.length_bits[sym], this.length_base[sym]);
|
512
|
+
|
513
|
+
dist = this.decode_symbol(d, dt);
|
514
|
+
|
515
|
+
/* possibly get more bits from distance code */
|
516
|
+
offs = d.history.length - this.read_bits(d, this.dist_bits[dist], this.dist_base[dist]);
|
517
|
+
|
518
|
+
if (offs < 0)
|
519
|
+
throw ("Invalid zlib offset " + offs);
|
520
|
+
|
521
|
+
/* copy match */
|
522
|
+
for (i = offs; i < offs + length; ++i) {
|
523
|
+
//ddest[ddestlength++] = ddest[i];
|
524
|
+
ddest[ddestlength++] = d.history[i];
|
525
|
+
d.history.push(d.history[i]);
|
526
|
+
}
|
527
|
+
}
|
528
|
+
}
|
529
|
+
}
|
530
|
+
|
531
|
+
/* inflate an uncompressed block of data */
|
532
|
+
this.inflate_uncompressed_block = function(d)
|
533
|
+
{
|
534
|
+
var length, invlength;
|
535
|
+
var i;
|
536
|
+
|
537
|
+
if (d.bitcount > 7) {
|
538
|
+
var overflow = Math.floor(d.bitcount / 8);
|
539
|
+
d.sourceIndex -= overflow;
|
540
|
+
d.bitcount = 0;
|
541
|
+
d.tag = 0;
|
542
|
+
}
|
543
|
+
|
544
|
+
/* get length */
|
545
|
+
length = d.source[d.sourceIndex+1];
|
546
|
+
length = 256*length + d.source[d.sourceIndex];
|
547
|
+
|
548
|
+
/* get one's complement of length */
|
549
|
+
invlength = d.source[d.sourceIndex+3];
|
550
|
+
invlength = 256*invlength + d.source[d.sourceIndex+2];
|
551
|
+
|
552
|
+
/* check length */
|
553
|
+
if (length != (~invlength & 0x0000ffff)) return this.DATA_ERROR;
|
554
|
+
|
555
|
+
d.sourceIndex += 4;
|
556
|
+
|
557
|
+
/* copy block */
|
558
|
+
for (i = length; i; --i) {
|
559
|
+
d.history.push(d.source[d.sourceIndex]);
|
560
|
+
d.dest[d.dest.length] = d.source[d.sourceIndex++];
|
561
|
+
}
|
562
|
+
|
563
|
+
/* make sure we start next block on a byte boundary */
|
564
|
+
d.bitcount = 0;
|
565
|
+
|
566
|
+
return this.OK;
|
567
|
+
}
|
568
|
+
|
569
|
+
/* inflate a block of data compressed with fixed huffman trees */
|
570
|
+
this.inflate_fixed_block = function(d)
|
571
|
+
{
|
572
|
+
/* decode block using fixed trees */
|
573
|
+
return this.inflate_block_data(d, this.sltree, this.sdtree);
|
574
|
+
}
|
575
|
+
|
576
|
+
/* inflate a block of data compressed with dynamic huffman trees */
|
577
|
+
this.inflate_dynamic_block = function(d)
|
578
|
+
{
|
579
|
+
/* decode trees from stream */
|
580
|
+
this.decode_trees(d, d.ltree, d.dtree);
|
581
|
+
|
582
|
+
/* decode block using decoded trees */
|
583
|
+
return this.inflate_block_data(d, d.ltree, d.dtree);
|
584
|
+
}
|
585
|
+
|
586
|
+
/* ---------------------- *
|
587
|
+
* -- public functions -- *
|
588
|
+
* ---------------------- */
|
589
|
+
|
590
|
+
/* initialize global (static) data */
|
591
|
+
this.init = function()
|
592
|
+
{
|
593
|
+
/* build fixed huffman trees */
|
594
|
+
this.build_fixed_trees(this.sltree, this.sdtree);
|
595
|
+
|
596
|
+
/* build extra bits and base tables */
|
597
|
+
this.build_bits_base(this.length_bits, this.length_base, 4, 3);
|
598
|
+
this.build_bits_base(this.dist_bits, this.dist_base, 2, 1);
|
599
|
+
|
600
|
+
/* fix a special case */
|
601
|
+
this.length_bits[28] = 0;
|
602
|
+
this.length_base[28] = 258;
|
603
|
+
|
604
|
+
this.reset();
|
605
|
+
}
|
606
|
+
|
607
|
+
this.reset = function()
|
608
|
+
{
|
609
|
+
this.d = new this.DATA(this);
|
610
|
+
delete this.header;
|
611
|
+
}
|
612
|
+
|
613
|
+
/* inflate stream from source to dest */
|
614
|
+
this.uncompress = function(source, offset)
|
615
|
+
{
|
616
|
+
|
617
|
+
var d = this.d;
|
618
|
+
var bfinal;
|
619
|
+
|
620
|
+
/* initialise data */
|
621
|
+
d.source = source;
|
622
|
+
d.sourceIndex = offset;
|
623
|
+
d.bitcount = 0;
|
624
|
+
|
625
|
+
d.dest = [];
|
626
|
+
|
627
|
+
// Skip zlib header at start of stream
|
628
|
+
if (typeof this.header == 'undefined') {
|
629
|
+
this.header = this.read_bits(d, 16, 0);
|
630
|
+
/* byte 0: 0x78, 7 = 32k window size, 8 = deflate */
|
631
|
+
/* byte 1: check bits for header and other flags */
|
632
|
+
}
|
633
|
+
|
634
|
+
var blocks = 0;
|
635
|
+
|
636
|
+
do {
|
637
|
+
|
638
|
+
var btype;
|
639
|
+
var res;
|
640
|
+
|
641
|
+
/* read final block flag */
|
642
|
+
bfinal = this.getbit(d);
|
643
|
+
|
644
|
+
/* read block type (2 bits) */
|
645
|
+
btype = this.read_bits(d, 2, 0);
|
646
|
+
|
647
|
+
/* decompress block */
|
648
|
+
switch (btype)
|
649
|
+
{
|
650
|
+
case 0:
|
651
|
+
/* decompress uncompressed block */
|
652
|
+
res = this.inflate_uncompressed_block(d);
|
653
|
+
break;
|
654
|
+
case 1:
|
655
|
+
/* decompress block with fixed huffman trees */
|
656
|
+
res = this.inflate_fixed_block(d);
|
657
|
+
break;
|
658
|
+
case 2:
|
659
|
+
/* decompress block with dynamic huffman trees */
|
660
|
+
res = this.inflate_dynamic_block(d);
|
661
|
+
break;
|
662
|
+
default:
|
663
|
+
return { 'status' : this.DATA_ERROR };
|
664
|
+
}
|
665
|
+
|
666
|
+
if (res != this.OK) return { 'status' : this.DATA_ERROR };
|
667
|
+
blocks++;
|
668
|
+
|
669
|
+
} while (!bfinal && d.sourceIndex < d.source.length);
|
670
|
+
|
671
|
+
d.history = d.history.slice(-this.WINDOW_SIZE);
|
672
|
+
|
673
|
+
return { 'status' : this.OK, 'data' : d.dest };
|
674
|
+
}
|
675
|
+
|
676
|
+
};
|