novnc-rails 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +0 -0
  3. data/LICENSE.txt +0 -0
  4. data/README.md +0 -0
  5. data/lib/novnc-rails.rb +8 -0
  6. data/lib/novnc-rails/version.rb +5 -0
  7. data/vendor/assets/javascripts/noVNC/Orbitron700.ttf +0 -0
  8. data/vendor/assets/javascripts/noVNC/Orbitron700.woff +0 -0
  9. data/vendor/assets/javascripts/noVNC/base.css +512 -0
  10. data/vendor/assets/javascripts/noVNC/base64.js +113 -0
  11. data/vendor/assets/javascripts/noVNC/black.css +71 -0
  12. data/vendor/assets/javascripts/noVNC/blue.css +64 -0
  13. data/vendor/assets/javascripts/noVNC/des.js +276 -0
  14. data/vendor/assets/javascripts/noVNC/display.js +751 -0
  15. data/vendor/assets/javascripts/noVNC/input.js +388 -0
  16. data/vendor/assets/javascripts/noVNC/jsunzip.js +676 -0
  17. data/vendor/assets/javascripts/noVNC/keyboard.js +543 -0
  18. data/vendor/assets/javascripts/noVNC/keysym.js +378 -0
  19. data/vendor/assets/javascripts/noVNC/keysymdef.js +15 -0
  20. data/vendor/assets/javascripts/noVNC/logo.js +1 -0
  21. data/vendor/assets/javascripts/noVNC/playback.js +102 -0
  22. data/vendor/assets/javascripts/noVNC/rfb.js +1889 -0
  23. data/vendor/assets/javascripts/noVNC/ui.js +979 -0
  24. data/vendor/assets/javascripts/noVNC/util.js +656 -0
  25. data/vendor/assets/javascripts/noVNC/web-socket-js/README.txt +109 -0
  26. data/vendor/assets/javascripts/noVNC/web-socket-js/WebSocketMain.swf +0 -0
  27. data/vendor/assets/javascripts/noVNC/web-socket-js/swfobject.js +4 -0
  28. data/vendor/assets/javascripts/noVNC/web-socket-js/web_socket.js +391 -0
  29. data/vendor/assets/javascripts/noVNC/websock.js +388 -0
  30. data/vendor/assets/javascripts/noVNC/webutil.js +239 -0
  31. 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
+ };