novnc-rails 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
};
|