Projekt

Obecné

Profil

Stáhnout (10.8 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
'use strict'
2
/* eslint camelcase: "off" */
3
4
var assert = require('assert')
5
6
var Zstream = require('pako/lib/zlib/zstream')
7
var zlib_deflate = require('pako/lib/zlib/deflate.js')
8
var zlib_inflate = require('pako/lib/zlib/inflate.js')
9
var constants = require('pako/lib/zlib/constants')
10
11
for (var key in constants) {
12
  exports[key] = constants[key]
13
}
14
15
// zlib modes
16
exports.NONE = 0
17
exports.DEFLATE = 1
18
exports.INFLATE = 2
19
exports.GZIP = 3
20
exports.GUNZIP = 4
21
exports.DEFLATERAW = 5
22
exports.INFLATERAW = 6
23
exports.UNZIP = 7
24
25
var GZIP_HEADER_ID1 = 0x1f
26
var GZIP_HEADER_ID2 = 0x8b
27
28
/**
29
 * Emulate Node's zlib C++ layer for use by the JS layer in index.js
30
 */
31
function Zlib (mode) {
32
  if (typeof mode !== 'number' || mode < exports.DEFLATE || mode > exports.UNZIP) {
33
    throw new TypeError('Bad argument')
34
  }
35
36
  this.dictionary = null
37
  this.err = 0
38
  this.flush = 0
39
  this.init_done = false
40
  this.level = 0
41
  this.memLevel = 0
42
  this.mode = mode
43
  this.strategy = 0
44
  this.windowBits = 0
45
  this.write_in_progress = false
46
  this.pending_close = false
47
  this.gzip_id_bytes_read = 0
48
}
49
50
Zlib.prototype.close = function () {
51
  if (this.write_in_progress) {
52
    this.pending_close = true
53
    return
54
  }
55
56
  this.pending_close = false
57
58
  assert(this.init_done, 'close before init')
59
  assert(this.mode <= exports.UNZIP)
60
61
  if (this.mode === exports.DEFLATE || this.mode === exports.GZIP || this.mode === exports.DEFLATERAW) {
62
    zlib_deflate.deflateEnd(this.strm)
63
  } else if (this.mode === exports.INFLATE || this.mode === exports.GUNZIP ||
64
      this.mode === exports.INFLATERAW || this.mode === exports.UNZIP) {
65
    zlib_inflate.inflateEnd(this.strm)
66
  }
67
68
  this.mode = exports.NONE
69
70
  this.dictionary = null
71
}
72
73
Zlib.prototype.write = function (flush, input, in_off, in_len, out, out_off, out_len) {
74
  return this._write(true, flush, input, in_off, in_len, out, out_off, out_len)
75
}
76
77
Zlib.prototype.writeSync = function (flush, input, in_off, in_len, out, out_off, out_len) {
78
  return this._write(false, flush, input, in_off, in_len, out, out_off, out_len)
79
}
80
81
Zlib.prototype._write = function (async, flush, input, in_off, in_len, out, out_off, out_len) {
82
  assert.equal(arguments.length, 8)
83
84
  assert(this.init_done, 'write before init')
85
  assert(this.mode !== exports.NONE, 'already finalized')
86
  assert.equal(false, this.write_in_progress, 'write already in progress')
87
  assert.equal(false, this.pending_close, 'close is pending')
88
89
  this.write_in_progress = true
90
91
  assert.equal(false, flush === undefined, 'must provide flush value')
92
93
  this.write_in_progress = true
94
95
  if (flush !== exports.Z_NO_FLUSH &&
96
    flush !== exports.Z_PARTIAL_FLUSH &&
97
    flush !== exports.Z_SYNC_FLUSH &&
98
    flush !== exports.Z_FULL_FLUSH &&
99
    flush !== exports.Z_FINISH &&
100
    flush !== exports.Z_BLOCK) {
101
    throw new Error('Invalid flush value')
102
  }
103
104
  if (input == null) {
105
    input = Buffer.alloc(0)
106
    in_len = 0
107
    in_off = 0
108
  }
109
110
  this.strm.avail_in = in_len
111
  this.strm.input = input
112
  this.strm.next_in = in_off
113
  this.strm.avail_out = out_len
114
  this.strm.output = out
115
  this.strm.next_out = out_off
116
  this.flush = flush
117
118
  if (!async) {
119
    // sync version
120
    this._process()
121
122
    if (this._checkError()) {
123
      return this._afterSync()
124
    }
125
    return
126
  }
127
128
  // async version
129
  var self = this
130
  process.nextTick(function () {
131
    self._process()
132
    self._after()
133
  })
134
135
  return this
136
}
137
138
Zlib.prototype._afterSync = function () {
139
  var avail_out = this.strm.avail_out
140
  var avail_in = this.strm.avail_in
141
142
  this.write_in_progress = false
143
144
  return [avail_in, avail_out]
145
}
146
147
Zlib.prototype._process = function () {
148
  var next_expected_header_byte = null
149
150
  // If the avail_out is left at 0, then it means that it ran out
151
  // of room.  If there was avail_out left over, then it means
152
  // that all of the input was consumed.
153
  switch (this.mode) {
154
    case exports.DEFLATE:
155
    case exports.GZIP:
156
    case exports.DEFLATERAW:
157
      this.err = zlib_deflate.deflate(this.strm, this.flush)
158
      break
159
    case exports.UNZIP:
160
      if (this.strm.avail_in > 0) {
161
        next_expected_header_byte = this.strm.next_in
162
      }
163
164
      switch (this.gzip_id_bytes_read) {
165
        case 0:
166
          if (next_expected_header_byte === null) {
167
            break
168
          }
169
170
          if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID1) {
171
            this.gzip_id_bytes_read = 1
172
            next_expected_header_byte++
173
174
            if (this.strm.avail_in === 1) {
175
              // The only available byte was already read.
176
              break
177
            }
178
          } else {
179
            this.mode = exports.INFLATE
180
            break
181
          }
182
183
          // fallthrough
184
        case 1:
185
          if (next_expected_header_byte === null) {
186
            break
187
          }
188
189
          if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID2) {
190
            this.gzip_id_bytes_read = 2
191
            this.mode = exports.GUNZIP
192
          } else {
193
            // There is no actual difference between INFLATE and INFLATERAW
194
            // (after initialization).
195
            this.mode = exports.INFLATE
196
          }
197
198
          break
199
        default:
200
          throw new Error('invalid number of gzip magic number bytes read')
201
      }
202
203
      // fallthrough
204
    case exports.INFLATE:
205
    case exports.GUNZIP:
206
    case exports.INFLATERAW:
207
      this.err = zlib_inflate.inflate(this.strm, this.flush)
208
209
      // If data was encoded with dictionary
210
      if (this.err === exports.Z_NEED_DICT && this.dictionary) {
211
        // Load it
212
        this.err = zlib_inflate.inflateSetDictionary(this.strm, this.dictionary)
213
        if (this.err === exports.Z_OK) {
214
          // And try to decode again
215
          this.err = zlib_inflate.inflate(this.strm, this.flush)
216
        } else if (this.err === exports.Z_DATA_ERROR) {
217
          // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
218
          // Make it possible for After() to tell a bad dictionary from bad
219
          // input.
220
          this.err = exports.Z_NEED_DICT
221
        }
222
      }
223
      while (this.strm.avail_in > 0 &&
224
             this.mode === exports.GUNZIP &&
225
             this.err === exports.Z_STREAM_END &&
226
             this.strm.next_in[0] !== 0x00) {
227
        // Bytes remain in input buffer. Perhaps this is another compressed
228
        // member in the same archive, or just trailing garbage.
229
        // Trailing zero bytes are okay, though, since they are frequently
230
        // used for padding.
231
232
        this.reset()
233
        this.err = zlib_inflate.inflate(this.strm, this.flush)
234
      }
235
      break
236
    default:
237
      throw new Error('Unknown mode ' + this.mode)
238
  }
239
}
240
241
Zlib.prototype._checkError = function () {
242
  // Acceptable error states depend on the type of zlib stream.
243
  switch (this.err) {
244
    case exports.Z_OK:
245
    case exports.Z_BUF_ERROR:
246
      if (this.strm.avail_out !== 0 && this.flush === exports.Z_FINISH) {
247
        this._error('unexpected end of file')
248
        return false
249
      }
250
      break
251
    case exports.Z_STREAM_END:
252
      // normal statuses, not fatal
253
      break
254
    case exports.Z_NEED_DICT:
255
      if (this.dictionary == null) {
256
        this._error('Missing dictionary')
257
      } else {
258
        this._error('Bad dictionary')
259
      }
260
      return false
261
    default:
262
      // something else.
263
      this._error('Zlib error')
264
      return false
265
  }
266
267
  return true
268
}
269
270
Zlib.prototype._after = function () {
271
  if (!this._checkError()) {
272
    return
273
  }
274
275
  var avail_out = this.strm.avail_out
276
  var avail_in = this.strm.avail_in
277
278
  this.write_in_progress = false
279
280
  // call the write() cb
281
  this.callback(avail_in, avail_out)
282
283
  if (this.pending_close) {
284
    this.close()
285
  }
286
}
287
288
Zlib.prototype._error = function (message) {
289
  if (this.strm.msg) {
290
    message = this.strm.msg
291
  }
292
  this.onerror(message, this.err)
293
294
  // no hope of rescue.
295
  this.write_in_progress = false
296
  if (this.pending_close) {
297
    this.close()
298
  }
299
}
300
301
Zlib.prototype.init = function (windowBits, level, memLevel, strategy, dictionary) {
302
  assert(arguments.length === 4 || arguments.length === 5, 'init(windowBits, level, memLevel, strategy, [dictionary])')
303
304
  assert(windowBits >= 8 && windowBits <= 15, 'invalid windowBits')
305
  assert(level >= -1 && level <= 9, 'invalid compression level')
306
307
  assert(memLevel >= 1 && memLevel <= 9, 'invalid memlevel')
308
309
  assert(strategy === exports.Z_FILTERED ||
310
         strategy === exports.Z_HUFFMAN_ONLY ||
311
         strategy === exports.Z_RLE ||
312
         strategy === exports.Z_FIXED ||
313
         strategy === exports.Z_DEFAULT_STRATEGY, 'invalid strategy')
314
315
  this._init(level, windowBits, memLevel, strategy, dictionary)
316
  this._setDictionary()
317
}
318
319
Zlib.prototype.params = function () {
320
  throw new Error('deflateParams Not supported')
321
}
322
323
Zlib.prototype.reset = function () {
324
  this._reset()
325
  this._setDictionary()
326
}
327
328
Zlib.prototype._init = function (level, windowBits, memLevel, strategy, dictionary) {
329
  this.level = level
330
  this.windowBits = windowBits
331
  this.memLevel = memLevel
332
  this.strategy = strategy
333
334
  this.flush = exports.Z_NO_FLUSH
335
336
  this.err = exports.Z_OK
337
338
  if (this.mode === exports.GZIP || this.mode === exports.GUNZIP) {
339
    this.windowBits += 16
340
  }
341
342
  if (this.mode === exports.UNZIP) {
343
    this.windowBits += 32
344
  }
345
346
  if (this.mode === exports.DEFLATERAW || this.mode === exports.INFLATERAW) {
347
    this.windowBits = -1 * this.windowBits
348
  }
349
350
  this.strm = new Zstream()
351
352
  switch (this.mode) {
353
    case exports.DEFLATE:
354
    case exports.GZIP:
355
    case exports.DEFLATERAW:
356
      this.err = zlib_deflate.deflateInit2(
357
        this.strm,
358
        this.level,
359
        exports.Z_DEFLATED,
360
        this.windowBits,
361
        this.memLevel,
362
        this.strategy
363
      )
364
      break
365
    case exports.INFLATE:
366
    case exports.GUNZIP:
367
    case exports.INFLATERAW:
368
    case exports.UNZIP:
369
      this.err = zlib_inflate.inflateInit2(
370
        this.strm,
371
        this.windowBits
372
      )
373
      break
374
    default:
375
      throw new Error('Unknown mode ' + this.mode)
376
  }
377
378
  if (this.err !== exports.Z_OK) {
379
    this._error('Init error')
380
  }
381
382
  this.dictionary = dictionary
383
384
  this.write_in_progress = false
385
  this.init_done = true
386
}
387
388
Zlib.prototype._setDictionary = function () {
389
  if (this.dictionary == null) {
390
    return
391
  }
392
393
  this.err = exports.Z_OK
394
395
  switch (this.mode) {
396
    case exports.DEFLATE:
397
    case exports.DEFLATERAW:
398
      this.err = zlib_deflate.deflateSetDictionary(this.strm, this.dictionary)
399
      break
400
    default:
401
      break
402
  }
403
404
  if (this.err !== exports.Z_OK) {
405
    this._error('Failed to set dictionary')
406
  }
407
}
408
409
Zlib.prototype._reset = function () {
410
  this.err = exports.Z_OK
411
412
  switch (this.mode) {
413
    case exports.DEFLATE:
414
    case exports.DEFLATERAW:
415
    case exports.GZIP:
416
      this.err = zlib_deflate.deflateReset(this.strm)
417
      break
418
    case exports.INFLATE:
419
    case exports.INFLATERAW:
420
    case exports.GUNZIP:
421
      this.err = zlib_inflate.inflateReset(this.strm)
422
      break
423
    default:
424
      break
425
  }
426
427
  if (this.err !== exports.Z_OK) {
428
    this._error('Failed to reset stream')
429
  }
430
}
431
432
exports.Zlib = Zlib