-
Notifications
You must be signed in to change notification settings - Fork 350
/
Copy pathdeflate.js
168 lines (147 loc) · 4.16 KB
/
deflate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**
* @fileoverview Deflate (RFC1951) 実装.
* Deflateアルゴリズム本体は Zlib.RawDeflate で実装されている.
*/
goog.provide('Zlib.Deflate');
goog.require('USE_TYPEDARRAY');
goog.require('Zlib');
goog.require('Zlib.Adler32');
goog.require('Zlib.RawDeflate');
goog.scope(function() {
/**
* Zlib Deflate
* @constructor
* @param {!(Array|Uint8Array)} input 符号化する対象の byte array.
* @param {Object=} opt_params option parameters.
*/
Zlib.Deflate = function(input, opt_params) {
/** @type {!(Array|Uint8Array)} */
this.input = input;
/** @type {!(Array|Uint8Array)} */
this.output =
new (USE_TYPEDARRAY ? Uint8Array : Array)(Zlib.Deflate.DefaultBufferSize);
/** @type {Zlib.Deflate.CompressionType} */
this.compressionType = Zlib.Deflate.CompressionType.DYNAMIC;
/** @type {Zlib.RawDeflate} */
this.rawDeflate;
/** @type {Object} */
var rawDeflateOption = {};
/** @type {string} */
var prop;
// option parameters
if (opt_params || !(opt_params = {})) {
if (typeof opt_params['compressionType'] === 'number') {
this.compressionType = opt_params['compressionType'];
}
}
// copy options
for (prop in opt_params) {
rawDeflateOption[prop] = opt_params[prop];
}
// set raw-deflate output buffer
rawDeflateOption['outputBuffer'] = this.output;
this.rawDeflate = new Zlib.RawDeflate(this.input, rawDeflateOption);
};
/**
* @const
* @type {number} デフォルトバッファサイズ.
*/
Zlib.Deflate.DefaultBufferSize = 0x8000;
/**
* @enum {number}
*/
Zlib.Deflate.CompressionType = Zlib.RawDeflate.CompressionType;
/**
* 直接圧縮に掛ける.
* @param {!(Array|Uint8Array)} input target buffer.
* @param {Object=} opt_params option parameters.
* @return {!(Array|Uint8Array)} compressed data byte array.
*/
Zlib.Deflate.compress = function(input, opt_params) {
return (new Zlib.Deflate(input, opt_params)).compress();
};
/**
* Deflate Compression.
* @return {!(Array|Uint8Array)} compressed data byte array.
*/
Zlib.Deflate.prototype.compress = function() {
/** @type {Zlib.CompressionMethod} */
var cm;
/** @type {number} */
var cinfo;
/** @type {number} */
var cmf;
/** @type {number} */
var flg;
/** @type {number} */
var fcheck;
/** @type {number} */
var fdict;
/** @type {number} */
var flevel;
/** @type {number} */
var clevel;
/** @type {number} */
var adler;
/** @type {boolean} */
var error = false;
/** @type {!(Array|Uint8Array)} */
var output;
/** @type {number} */
var pos = 0;
output = this.output;
// Compression Method and Flags
cm = Zlib.CompressionMethod.DEFLATE;
switch (cm) {
case Zlib.CompressionMethod.DEFLATE:
cinfo = Math.LOG2E * Math.log(Zlib.RawDeflate.WindowSize) - 8;
break;
default:
throw new Error('invalid compression method');
}
cmf = (cinfo << 4) | cm;
output[pos++] = cmf;
// Flags
fdict = 0;
switch (cm) {
case Zlib.CompressionMethod.DEFLATE:
switch (this.compressionType) {
case Zlib.Deflate.CompressionType.NONE: flevel = 0; break;
case Zlib.Deflate.CompressionType.FIXED: flevel = 1; break;
case Zlib.Deflate.CompressionType.DYNAMIC: flevel = 2; break;
default: throw new Error('unsupported compression type');
}
break;
default:
throw new Error('invalid compression method');
}
flg = (flevel << 6) | (fdict << 5);
fcheck = 31 - (cmf * 256 + flg) % 31;
flg |= fcheck;
output[pos++] = flg;
// Adler-32 checksum
adler = Zlib.Adler32(this.input);
this.rawDeflate.op = pos;
output = this.rawDeflate.compress();
pos = output.length;
if (USE_TYPEDARRAY) {
// subarray 分を元にもどす
output = new Uint8Array(output.buffer);
// expand buffer
if (output.length <= pos + 4) {
this.output = new Uint8Array(output.length + 4);
this.output.set(output);
output = this.output;
}
output = output.subarray(0, pos + 4);
}
// adler32
output[pos++] = (adler >> 24) & 0xff;
output[pos++] = (adler >> 16) & 0xff;
output[pos++] = (adler >> 8) & 0xff;
output[pos++] = (adler ) & 0xff;
return output;
};
// end of scope
});
/* vim:set expandtab ts=2 sw=2 tw=80: */