Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80540 views
1
'use strict';
2
3
4
var zlib_deflate = require('./zlib/deflate.js');
5
var utils = require('./utils/common');
6
var strings = require('./utils/strings');
7
var msg = require('./zlib/messages');
8
var zstream = require('./zlib/zstream');
9
10
var toString = Object.prototype.toString;
11
12
/* Public constants ==========================================================*/
13
/* ===========================================================================*/
14
15
var Z_NO_FLUSH = 0;
16
var Z_FINISH = 4;
17
18
var Z_OK = 0;
19
var Z_STREAM_END = 1;
20
21
var Z_DEFAULT_COMPRESSION = -1;
22
23
var Z_DEFAULT_STRATEGY = 0;
24
25
var Z_DEFLATED = 8;
26
27
/* ===========================================================================*/
28
29
30
/**
31
* class Deflate
32
*
33
* Generic JS-style wrapper for zlib calls. If you don't need
34
* streaming behaviour - use more simple functions: [[deflate]],
35
* [[deflateRaw]] and [[gzip]].
36
**/
37
38
/* internal
39
* Deflate.chunks -> Array
40
*
41
* Chunks of output data, if [[Deflate#onData]] not overriden.
42
**/
43
44
/**
45
* Deflate.result -> Uint8Array|Array
46
*
47
* Compressed result, generated by default [[Deflate#onData]]
48
* and [[Deflate#onEnd]] handlers. Filled after you push last chunk
49
* (call [[Deflate#push]] with `Z_FINISH` / `true` param).
50
**/
51
52
/**
53
* Deflate.err -> Number
54
*
55
* Error code after deflate finished. 0 (Z_OK) on success.
56
* You will not need it in real life, because deflate errors
57
* are possible only on wrong options or bad `onData` / `onEnd`
58
* custom handlers.
59
**/
60
61
/**
62
* Deflate.msg -> String
63
*
64
* Error message, if [[Deflate.err]] != 0
65
**/
66
67
68
/**
69
* new Deflate(options)
70
* - options (Object): zlib deflate options.
71
*
72
* Creates new deflator instance with specified params. Throws exception
73
* on bad params. Supported options:
74
*
75
* - `level`
76
* - `windowBits`
77
* - `memLevel`
78
* - `strategy`
79
*
80
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
81
* for more information on these.
82
*
83
* Additional options, for internal needs:
84
*
85
* - `chunkSize` - size of generated data chunks (16K by default)
86
* - `raw` (Boolean) - do raw deflate
87
* - `gzip` (Boolean) - create gzip wrapper
88
* - `to` (String) - if equal to 'string', then result will be "binary string"
89
* (each char code [0..255])
90
* - `header` (Object) - custom header for gzip
91
* - `text` (Boolean) - true if compressed data believed to be text
92
* - `time` (Number) - modification time, unix timestamp
93
* - `os` (Number) - operation system code
94
* - `extra` (Array) - array of bytes with extra data (max 65536)
95
* - `name` (String) - file name (binary string)
96
* - `comment` (String) - comment (binary string)
97
* - `hcrc` (Boolean) - true if header crc should be added
98
*
99
* ##### Example:
100
*
101
* ```javascript
102
* var pako = require('pako')
103
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
104
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
105
*
106
* var deflate = new pako.Deflate({ level: 3});
107
*
108
* deflate.push(chunk1, false);
109
* deflate.push(chunk2, true); // true -> last chunk
110
*
111
* if (deflate.err) { throw new Error(deflate.err); }
112
*
113
* console.log(deflate.result);
114
* ```
115
**/
116
var Deflate = function(options) {
117
118
this.options = utils.assign({
119
level: Z_DEFAULT_COMPRESSION,
120
method: Z_DEFLATED,
121
chunkSize: 16384,
122
windowBits: 15,
123
memLevel: 8,
124
strategy: Z_DEFAULT_STRATEGY,
125
to: ''
126
}, options || {});
127
128
var opt = this.options;
129
130
if (opt.raw && (opt.windowBits > 0)) {
131
opt.windowBits = -opt.windowBits;
132
}
133
134
else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
135
opt.windowBits += 16;
136
}
137
138
this.err = 0; // error code, if happens (0 = Z_OK)
139
this.msg = ''; // error message
140
this.ended = false; // used to avoid multiple onEnd() calls
141
this.chunks = []; // chunks of compressed data
142
143
this.strm = new zstream();
144
this.strm.avail_out = 0;
145
146
var status = zlib_deflate.deflateInit2(
147
this.strm,
148
opt.level,
149
opt.method,
150
opt.windowBits,
151
opt.memLevel,
152
opt.strategy
153
);
154
155
if (status !== Z_OK) {
156
throw new Error(msg[status]);
157
}
158
159
if (opt.header) {
160
zlib_deflate.deflateSetHeader(this.strm, opt.header);
161
}
162
};
163
164
/**
165
* Deflate#push(data[, mode]) -> Boolean
166
* - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
167
* converted to utf8 byte sequence.
168
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
169
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
170
*
171
* Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
172
* new compressed chunks. Returns `true` on success. The last data block must have
173
* mode Z_FINISH (or `true`). That flush internal pending buffers and call
174
* [[Deflate#onEnd]].
175
*
176
* On fail call [[Deflate#onEnd]] with error code and return false.
177
*
178
* We strongly recommend to use `Uint8Array` on input for best speed (output
179
* array format is detected automatically). Also, don't skip last param and always
180
* use the same type in your code (boolean or number). That will improve JS speed.
181
*
182
* For regular `Array`-s make sure all elements are [0..255].
183
*
184
* ##### Example
185
*
186
* ```javascript
187
* push(chunk, false); // push one of data chunks
188
* ...
189
* push(chunk, true); // push last chunk
190
* ```
191
**/
192
Deflate.prototype.push = function(data, mode) {
193
var strm = this.strm;
194
var chunkSize = this.options.chunkSize;
195
var status, _mode;
196
197
if (this.ended) { return false; }
198
199
_mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
200
201
// Convert data if needed
202
if (typeof data === 'string') {
203
// If we need to compress text, change encoding to utf8.
204
strm.input = strings.string2buf(data);
205
} else if (toString.call(data) === '[object ArrayBuffer]') {
206
strm.input = new Uint8Array(data);
207
} else {
208
strm.input = data;
209
}
210
211
strm.next_in = 0;
212
strm.avail_in = strm.input.length;
213
214
do {
215
if (strm.avail_out === 0) {
216
strm.output = new utils.Buf8(chunkSize);
217
strm.next_out = 0;
218
strm.avail_out = chunkSize;
219
}
220
status = zlib_deflate.deflate(strm, _mode); /* no bad return value */
221
222
if (status !== Z_STREAM_END && status !== Z_OK) {
223
this.onEnd(status);
224
this.ended = true;
225
return false;
226
}
227
if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) {
228
if (this.options.to === 'string') {
229
this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
230
} else {
231
this.onData(utils.shrinkBuf(strm.output, strm.next_out));
232
}
233
}
234
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
235
236
// Finalize on the last chunk.
237
if (_mode === Z_FINISH) {
238
status = zlib_deflate.deflateEnd(this.strm);
239
this.onEnd(status);
240
this.ended = true;
241
return status === Z_OK;
242
}
243
244
return true;
245
};
246
247
248
/**
249
* Deflate#onData(chunk) -> Void
250
* - chunk (Uint8Array|Array|String): ouput data. Type of array depends
251
* on js engine support. When string output requested, each chunk
252
* will be string.
253
*
254
* By default, stores data blocks in `chunks[]` property and glue
255
* those in `onEnd`. Override this handler, if you need another behaviour.
256
**/
257
Deflate.prototype.onData = function(chunk) {
258
this.chunks.push(chunk);
259
};
260
261
262
/**
263
* Deflate#onEnd(status) -> Void
264
* - status (Number): deflate status. 0 (Z_OK) on success,
265
* other if not.
266
*
267
* Called once after you tell deflate that input stream complete
268
* or error happenned. By default - join collected chunks,
269
* free memory and fill `results` / `err` properties.
270
**/
271
Deflate.prototype.onEnd = function(status) {
272
// On success - join
273
if (status === Z_OK) {
274
if (this.options.to === 'string') {
275
this.result = this.chunks.join('');
276
} else {
277
this.result = utils.flattenChunks(this.chunks);
278
}
279
}
280
this.chunks = [];
281
this.err = status;
282
this.msg = this.strm.msg;
283
};
284
285
286
/**
287
* deflate(data[, options]) -> Uint8Array|Array|String
288
* - data (Uint8Array|Array|String): input data to compress.
289
* - options (Object): zlib deflate options.
290
*
291
* Compress `data` with deflate alrorythm and `options`.
292
*
293
* Supported options are:
294
*
295
* - level
296
* - windowBits
297
* - memLevel
298
* - strategy
299
*
300
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
301
* for more information on these.
302
*
303
* Sugar (options):
304
*
305
* - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
306
* negative windowBits implicitly.
307
* - `to` (String) - if equal to 'string', then result will be "binary string"
308
* (each char code [0..255])
309
*
310
* ##### Example:
311
*
312
* ```javascript
313
* var pako = require('pako')
314
* , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
315
*
316
* console.log(pako.deflate(data));
317
* ```
318
**/
319
function deflate(input, options) {
320
var deflator = new Deflate(options);
321
322
deflator.push(input, true);
323
324
// That will never happens, if you don't cheat with options :)
325
if (deflator.err) { throw deflator.msg; }
326
327
return deflator.result;
328
}
329
330
331
/**
332
* deflateRaw(data[, options]) -> Uint8Array|Array|String
333
* - data (Uint8Array|Array|String): input data to compress.
334
* - options (Object): zlib deflate options.
335
*
336
* The same as [[deflate]], but creates raw data, without wrapper
337
* (header and adler32 crc).
338
**/
339
function deflateRaw(input, options) {
340
options = options || {};
341
options.raw = true;
342
return deflate(input, options);
343
}
344
345
346
/**
347
* gzip(data[, options]) -> Uint8Array|Array|String
348
* - data (Uint8Array|Array|String): input data to compress.
349
* - options (Object): zlib deflate options.
350
*
351
* The same as [[deflate]], but create gzip wrapper instead of
352
* deflate one.
353
**/
354
function gzip(input, options) {
355
options = options || {};
356
options.gzip = true;
357
return deflate(input, options);
358
}
359
360
361
exports.Deflate = Deflate;
362
exports.deflate = deflate;
363
exports.deflateRaw = deflateRaw;
364
exports.gzip = gzip;
365