Mercurial > repos > SharpZipLib
comparison Zip/Compression/DeflaterHuffman.cs @ 1:94e25b786321
Re #311: can't read ZIP file packed by Linux app Archive Manager/File Roller
Initial commit of clean SharpZipLib 0860 source. Only change is build paths.
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 30 Oct 2010 14:03:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:d16ef17fa7bb | 1:94e25b786321 |
---|---|
1 // DeflaterHuffman.cs | |
2 // | |
3 // Copyright (C) 2001 Mike Krueger | |
4 // Copyright (C) 2004 John Reilly | |
5 // | |
6 // This file was translated from java, it was part of the GNU Classpath | |
7 // Copyright (C) 2001 Free Software Foundation, Inc. | |
8 // | |
9 // This program is free software; you can redistribute it and/or | |
10 // modify it under the terms of the GNU General Public License | |
11 // as published by the Free Software Foundation; either version 2 | |
12 // of the License, or (at your option) any later version. | |
13 // | |
14 // This program is distributed in the hope that it will be useful, | |
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 // GNU General Public License for more details. | |
18 // | |
19 // You should have received a copy of the GNU General Public License | |
20 // along with this program; if not, write to the Free Software | |
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
22 // | |
23 // Linking this library statically or dynamically with other modules is | |
24 // making a combined work based on this library. Thus, the terms and | |
25 // conditions of the GNU General Public License cover the whole | |
26 // combination. | |
27 // | |
28 // As a special exception, the copyright holders of this library give you | |
29 // permission to link this library with independent modules to produce an | |
30 // executable, regardless of the license terms of these independent | |
31 // modules, and to copy and distribute the resulting executable under | |
32 // terms of your choice, provided that you also meet, for each linked | |
33 // independent module, the terms and conditions of the license of that | |
34 // module. An independent module is a module which is not derived from | |
35 // or based on this library. If you modify this library, you may extend | |
36 // this exception to your version of the library, but you are not | |
37 // obligated to do so. If you do not wish to do so, delete this | |
38 // exception statement from your version. | |
39 | |
40 using System; | |
41 | |
42 namespace ICSharpCode.SharpZipLib.Zip.Compression | |
43 { | |
44 | |
45 /// <summary> | |
46 /// This is the DeflaterHuffman class. | |
47 /// | |
48 /// This class is <i>not</i> thread safe. This is inherent in the API, due | |
49 /// to the split of Deflate and SetInput. | |
50 /// | |
51 /// author of the original java version : Jochen Hoenicke | |
52 /// </summary> | |
53 public class DeflaterHuffman | |
54 { | |
55 const int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6); | |
56 const int LITERAL_NUM = 286; | |
57 | |
58 // Number of distance codes | |
59 const int DIST_NUM = 30; | |
60 // Number of codes used to transfer bit lengths | |
61 const int BITLEN_NUM = 19; | |
62 | |
63 // repeat previous bit length 3-6 times (2 bits of repeat count) | |
64 const int REP_3_6 = 16; | |
65 // repeat a zero length 3-10 times (3 bits of repeat count) | |
66 const int REP_3_10 = 17; | |
67 // repeat a zero length 11-138 times (7 bits of repeat count) | |
68 const int REP_11_138 = 18; | |
69 | |
70 const int EOF_SYMBOL = 256; | |
71 | |
72 // The lengths of the bit length codes are sent in order of decreasing | |
73 // probability, to avoid transmitting the lengths for unused bit length codes. | |
74 static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; | |
75 | |
76 static readonly byte[] bit4Reverse = { | |
77 0, | |
78 8, | |
79 4, | |
80 12, | |
81 2, | |
82 10, | |
83 6, | |
84 14, | |
85 1, | |
86 9, | |
87 5, | |
88 13, | |
89 3, | |
90 11, | |
91 7, | |
92 15 | |
93 }; | |
94 | |
95 static short[] staticLCodes; | |
96 static byte[] staticLLength; | |
97 static short[] staticDCodes; | |
98 static byte[] staticDLength; | |
99 | |
100 class Tree | |
101 { | |
102 #region Instance Fields | |
103 public short[] freqs; | |
104 | |
105 public byte[] length; | |
106 | |
107 public int minNumCodes; | |
108 | |
109 public int numCodes; | |
110 | |
111 short[] codes; | |
112 int[] bl_counts; | |
113 int maxLength; | |
114 DeflaterHuffman dh; | |
115 #endregion | |
116 | |
117 #region Constructors | |
118 public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) | |
119 { | |
120 this.dh = dh; | |
121 this.minNumCodes = minCodes; | |
122 this.maxLength = maxLength; | |
123 freqs = new short[elems]; | |
124 bl_counts = new int[maxLength]; | |
125 } | |
126 | |
127 #endregion | |
128 | |
129 /// <summary> | |
130 /// Resets the internal state of the tree | |
131 /// </summary> | |
132 public void Reset() | |
133 { | |
134 for (int i = 0; i < freqs.Length; i++) { | |
135 freqs[i] = 0; | |
136 } | |
137 codes = null; | |
138 length = null; | |
139 } | |
140 | |
141 public void WriteSymbol(int code) | |
142 { | |
143 // if (DeflaterConstants.DEBUGGING) { | |
144 // freqs[code]--; | |
145 // // Console.Write("writeSymbol("+freqs.length+","+code+"): "); | |
146 // } | |
147 dh.pending.WriteBits(codes[code] & 0xffff, length[code]); | |
148 } | |
149 | |
150 /// <summary> | |
151 /// Check that all frequencies are zero | |
152 /// </summary> | |
153 /// <exception cref="SharpZipBaseException"> | |
154 /// At least one frequency is non-zero | |
155 /// </exception> | |
156 public void CheckEmpty() | |
157 { | |
158 bool empty = true; | |
159 for (int i = 0; i < freqs.Length; i++) { | |
160 if (freqs[i] != 0) { | |
161 //Console.WriteLine("freqs[" + i + "] == " + freqs[i]); | |
162 empty = false; | |
163 } | |
164 } | |
165 | |
166 if (!empty) { | |
167 throw new SharpZipBaseException("!Empty"); | |
168 } | |
169 } | |
170 | |
171 /// <summary> | |
172 /// Set static codes and length | |
173 /// </summary> | |
174 /// <param name="staticCodes">new codes</param> | |
175 /// <param name="staticLengths">length for new codes</param> | |
176 public void SetStaticCodes(short[] staticCodes, byte[] staticLengths) | |
177 { | |
178 codes = staticCodes; | |
179 length = staticLengths; | |
180 } | |
181 | |
182 /// <summary> | |
183 /// Build dynamic codes and lengths | |
184 /// </summary> | |
185 public void BuildCodes() | |
186 { | |
187 int numSymbols = freqs.Length; | |
188 int[] nextCode = new int[maxLength]; | |
189 int code = 0; | |
190 | |
191 codes = new short[freqs.Length]; | |
192 | |
193 // if (DeflaterConstants.DEBUGGING) { | |
194 // //Console.WriteLine("buildCodes: "+freqs.Length); | |
195 // } | |
196 | |
197 for (int bits = 0; bits < maxLength; bits++) { | |
198 nextCode[bits] = code; | |
199 code += bl_counts[bits] << (15 - bits); | |
200 | |
201 // if (DeflaterConstants.DEBUGGING) { | |
202 // //Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits] | |
203 // +" nextCode: "+code); | |
204 // } | |
205 } | |
206 | |
207 #if DebugDeflation | |
208 if ( DeflaterConstants.DEBUGGING && (code != 65536) ) | |
209 { | |
210 throw new SharpZipBaseException("Inconsistent bl_counts!"); | |
211 } | |
212 #endif | |
213 for (int i=0; i < numCodes; i++) { | |
214 int bits = length[i]; | |
215 if (bits > 0) { | |
216 | |
217 // if (DeflaterConstants.DEBUGGING) { | |
218 // //Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"), | |
219 // +bits); | |
220 // } | |
221 | |
222 codes[i] = BitReverse(nextCode[bits-1]); | |
223 nextCode[bits-1] += 1 << (16 - bits); | |
224 } | |
225 } | |
226 } | |
227 | |
228 public void BuildTree() | |
229 { | |
230 int numSymbols = freqs.Length; | |
231 | |
232 /* heap is a priority queue, sorted by frequency, least frequent | |
233 * nodes first. The heap is a binary tree, with the property, that | |
234 * the parent node is smaller than both child nodes. This assures | |
235 * that the smallest node is the first parent. | |
236 * | |
237 * The binary tree is encoded in an array: 0 is root node and | |
238 * the nodes 2*n+1, 2*n+2 are the child nodes of node n. | |
239 */ | |
240 int[] heap = new int[numSymbols]; | |
241 int heapLen = 0; | |
242 int maxCode = 0; | |
243 for (int n = 0; n < numSymbols; n++) { | |
244 int freq = freqs[n]; | |
245 if (freq != 0) { | |
246 // Insert n into heap | |
247 int pos = heapLen++; | |
248 int ppos; | |
249 while (pos > 0 && freqs[heap[ppos = (pos - 1) / 2]] > freq) { | |
250 heap[pos] = heap[ppos]; | |
251 pos = ppos; | |
252 } | |
253 heap[pos] = n; | |
254 | |
255 maxCode = n; | |
256 } | |
257 } | |
258 | |
259 /* We could encode a single literal with 0 bits but then we | |
260 * don't see the literals. Therefore we force at least two | |
261 * literals to avoid this case. We don't care about order in | |
262 * this case, both literals get a 1 bit code. | |
263 */ | |
264 while (heapLen < 2) { | |
265 int node = maxCode < 2 ? ++maxCode : 0; | |
266 heap[heapLen++] = node; | |
267 } | |
268 | |
269 numCodes = Math.Max(maxCode + 1, minNumCodes); | |
270 | |
271 int numLeafs = heapLen; | |
272 int[] childs = new int[4 * heapLen - 2]; | |
273 int[] values = new int[2 * heapLen - 1]; | |
274 int numNodes = numLeafs; | |
275 for (int i = 0; i < heapLen; i++) { | |
276 int node = heap[i]; | |
277 childs[2 * i] = node; | |
278 childs[2 * i + 1] = -1; | |
279 values[i] = freqs[node] << 8; | |
280 heap[i] = i; | |
281 } | |
282 | |
283 /* Construct the Huffman tree by repeatedly combining the least two | |
284 * frequent nodes. | |
285 */ | |
286 do { | |
287 int first = heap[0]; | |
288 int last = heap[--heapLen]; | |
289 | |
290 // Propagate the hole to the leafs of the heap | |
291 int ppos = 0; | |
292 int path = 1; | |
293 | |
294 while (path < heapLen) { | |
295 if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) { | |
296 path++; | |
297 } | |
298 | |
299 heap[ppos] = heap[path]; | |
300 ppos = path; | |
301 path = path * 2 + 1; | |
302 } | |
303 | |
304 /* Now propagate the last element down along path. Normally | |
305 * it shouldn't go too deep. | |
306 */ | |
307 int lastVal = values[last]; | |
308 while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) { | |
309 heap[path] = heap[ppos]; | |
310 } | |
311 heap[path] = last; | |
312 | |
313 | |
314 int second = heap[0]; | |
315 | |
316 // Create a new node father of first and second | |
317 last = numNodes++; | |
318 childs[2 * last] = first; | |
319 childs[2 * last + 1] = second; | |
320 int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff); | |
321 values[last] = lastVal = values[first] + values[second] - mindepth + 1; | |
322 | |
323 // Again, propagate the hole to the leafs | |
324 ppos = 0; | |
325 path = 1; | |
326 | |
327 while (path < heapLen) { | |
328 if (path + 1 < heapLen && values[heap[path]] > values[heap[path+1]]) { | |
329 path++; | |
330 } | |
331 | |
332 heap[ppos] = heap[path]; | |
333 ppos = path; | |
334 path = ppos * 2 + 1; | |
335 } | |
336 | |
337 // Now propagate the new element down along path | |
338 while ((path = ppos) > 0 && values[heap[ppos = (path - 1)/2]] > lastVal) { | |
339 heap[path] = heap[ppos]; | |
340 } | |
341 heap[path] = last; | |
342 } while (heapLen > 1); | |
343 | |
344 if (heap[0] != childs.Length / 2 - 1) { | |
345 throw new SharpZipBaseException("Heap invariant violated"); | |
346 } | |
347 | |
348 BuildLength(childs); | |
349 } | |
350 | |
351 /// <summary> | |
352 /// Get encoded length | |
353 /// </summary> | |
354 /// <returns>Encoded length, the sum of frequencies * lengths</returns> | |
355 public int GetEncodedLength() | |
356 { | |
357 int len = 0; | |
358 for (int i = 0; i < freqs.Length; i++) { | |
359 len += freqs[i] * length[i]; | |
360 } | |
361 return len; | |
362 } | |
363 | |
364 /// <summary> | |
365 /// Scan a literal or distance tree to determine the frequencies of the codes | |
366 /// in the bit length tree. | |
367 /// </summary> | |
368 public void CalcBLFreq(Tree blTree) | |
369 { | |
370 int max_count; /* max repeat count */ | |
371 int min_count; /* min repeat count */ | |
372 int count; /* repeat count of the current code */ | |
373 int curlen = -1; /* length of current code */ | |
374 | |
375 int i = 0; | |
376 while (i < numCodes) { | |
377 count = 1; | |
378 int nextlen = length[i]; | |
379 if (nextlen == 0) { | |
380 max_count = 138; | |
381 min_count = 3; | |
382 } else { | |
383 max_count = 6; | |
384 min_count = 3; | |
385 if (curlen != nextlen) { | |
386 blTree.freqs[nextlen]++; | |
387 count = 0; | |
388 } | |
389 } | |
390 curlen = nextlen; | |
391 i++; | |
392 | |
393 while (i < numCodes && curlen == length[i]) { | |
394 i++; | |
395 if (++count >= max_count) { | |
396 break; | |
397 } | |
398 } | |
399 | |
400 if (count < min_count) { | |
401 blTree.freqs[curlen] += (short)count; | |
402 } else if (curlen != 0) { | |
403 blTree.freqs[REP_3_6]++; | |
404 } else if (count <= 10) { | |
405 blTree.freqs[REP_3_10]++; | |
406 } else { | |
407 blTree.freqs[REP_11_138]++; | |
408 } | |
409 } | |
410 } | |
411 | |
412 /// <summary> | |
413 /// Write tree values | |
414 /// </summary> | |
415 /// <param name="blTree">Tree to write</param> | |
416 public void WriteTree(Tree blTree) | |
417 { | |
418 int max_count; // max repeat count | |
419 int min_count; // min repeat count | |
420 int count; // repeat count of the current code | |
421 int curlen = -1; // length of current code | |
422 | |
423 int i = 0; | |
424 while (i < numCodes) { | |
425 count = 1; | |
426 int nextlen = length[i]; | |
427 if (nextlen == 0) { | |
428 max_count = 138; | |
429 min_count = 3; | |
430 } else { | |
431 max_count = 6; | |
432 min_count = 3; | |
433 if (curlen != nextlen) { | |
434 blTree.WriteSymbol(nextlen); | |
435 count = 0; | |
436 } | |
437 } | |
438 curlen = nextlen; | |
439 i++; | |
440 | |
441 while (i < numCodes && curlen == length[i]) { | |
442 i++; | |
443 if (++count >= max_count) { | |
444 break; | |
445 } | |
446 } | |
447 | |
448 if (count < min_count) { | |
449 while (count-- > 0) { | |
450 blTree.WriteSymbol(curlen); | |
451 } | |
452 } else if (curlen != 0) { | |
453 blTree.WriteSymbol(REP_3_6); | |
454 dh.pending.WriteBits(count - 3, 2); | |
455 } else if (count <= 10) { | |
456 blTree.WriteSymbol(REP_3_10); | |
457 dh.pending.WriteBits(count - 3, 3); | |
458 } else { | |
459 blTree.WriteSymbol(REP_11_138); | |
460 dh.pending.WriteBits(count - 11, 7); | |
461 } | |
462 } | |
463 } | |
464 | |
465 void BuildLength(int[] childs) | |
466 { | |
467 this.length = new byte [freqs.Length]; | |
468 int numNodes = childs.Length / 2; | |
469 int numLeafs = (numNodes + 1) / 2; | |
470 int overflow = 0; | |
471 | |
472 for (int i = 0; i < maxLength; i++) { | |
473 bl_counts[i] = 0; | |
474 } | |
475 | |
476 // First calculate optimal bit lengths | |
477 int[] lengths = new int[numNodes]; | |
478 lengths[numNodes-1] = 0; | |
479 | |
480 for (int i = numNodes - 1; i >= 0; i--) { | |
481 if (childs[2 * i + 1] != -1) { | |
482 int bitLength = lengths[i] + 1; | |
483 if (bitLength > maxLength) { | |
484 bitLength = maxLength; | |
485 overflow++; | |
486 } | |
487 lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength; | |
488 } else { | |
489 // A leaf node | |
490 int bitLength = lengths[i]; | |
491 bl_counts[bitLength - 1]++; | |
492 this.length[childs[2*i]] = (byte) lengths[i]; | |
493 } | |
494 } | |
495 | |
496 // if (DeflaterConstants.DEBUGGING) { | |
497 // //Console.WriteLine("Tree "+freqs.Length+" lengths:"); | |
498 // for (int i=0; i < numLeafs; i++) { | |
499 // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] | |
500 // + " len: "+length[childs[2*i]]); | |
501 // } | |
502 // } | |
503 | |
504 if (overflow == 0) { | |
505 return; | |
506 } | |
507 | |
508 int incrBitLen = maxLength - 1; | |
509 do { | |
510 // Find the first bit length which could increase: | |
511 while (bl_counts[--incrBitLen] == 0) | |
512 ; | |
513 | |
514 // Move this node one down and remove a corresponding | |
515 // number of overflow nodes. | |
516 do { | |
517 bl_counts[incrBitLen]--; | |
518 bl_counts[++incrBitLen]++; | |
519 overflow -= 1 << (maxLength - 1 - incrBitLen); | |
520 } while (overflow > 0 && incrBitLen < maxLength - 1); | |
521 } while (overflow > 0); | |
522 | |
523 /* We may have overshot above. Move some nodes from maxLength to | |
524 * maxLength-1 in that case. | |
525 */ | |
526 bl_counts[maxLength-1] += overflow; | |
527 bl_counts[maxLength-2] -= overflow; | |
528 | |
529 /* Now recompute all bit lengths, scanning in increasing | |
530 * frequency. It is simpler to reconstruct all lengths instead of | |
531 * fixing only the wrong ones. This idea is taken from 'ar' | |
532 * written by Haruhiko Okumura. | |
533 * | |
534 * The nodes were inserted with decreasing frequency into the childs | |
535 * array. | |
536 */ | |
537 int nodePtr = 2 * numLeafs; | |
538 for (int bits = maxLength; bits != 0; bits--) { | |
539 int n = bl_counts[bits-1]; | |
540 while (n > 0) { | |
541 int childPtr = 2*childs[nodePtr++]; | |
542 if (childs[childPtr + 1] == -1) { | |
543 // We found another leaf | |
544 length[childs[childPtr]] = (byte) bits; | |
545 n--; | |
546 } | |
547 } | |
548 } | |
549 // if (DeflaterConstants.DEBUGGING) { | |
550 // //Console.WriteLine("*** After overflow elimination. ***"); | |
551 // for (int i=0; i < numLeafs; i++) { | |
552 // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]] | |
553 // + " len: "+length[childs[2*i]]); | |
554 // } | |
555 // } | |
556 } | |
557 | |
558 } | |
559 | |
560 #region Instance Fields | |
561 /// <summary> | |
562 /// Pending buffer to use | |
563 /// </summary> | |
564 public DeflaterPending pending; | |
565 | |
566 Tree literalTree; | |
567 Tree distTree; | |
568 Tree blTree; | |
569 | |
570 // Buffer for distances | |
571 short[] d_buf; | |
572 byte[] l_buf; | |
573 int last_lit; | |
574 int extra_bits; | |
575 #endregion | |
576 | |
577 static DeflaterHuffman() | |
578 { | |
579 // See RFC 1951 3.2.6 | |
580 // Literal codes | |
581 staticLCodes = new short[LITERAL_NUM]; | |
582 staticLLength = new byte[LITERAL_NUM]; | |
583 | |
584 int i = 0; | |
585 while (i < 144) { | |
586 staticLCodes[i] = BitReverse((0x030 + i) << 8); | |
587 staticLLength[i++] = 8; | |
588 } | |
589 | |
590 while (i < 256) { | |
591 staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7); | |
592 staticLLength[i++] = 9; | |
593 } | |
594 | |
595 while (i < 280) { | |
596 staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9); | |
597 staticLLength[i++] = 7; | |
598 } | |
599 | |
600 while (i < LITERAL_NUM) { | |
601 staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8); | |
602 staticLLength[i++] = 8; | |
603 } | |
604 | |
605 // Distance codes | |
606 staticDCodes = new short[DIST_NUM]; | |
607 staticDLength = new byte[DIST_NUM]; | |
608 for (i = 0; i < DIST_NUM; i++) { | |
609 staticDCodes[i] = BitReverse(i << 11); | |
610 staticDLength[i] = 5; | |
611 } | |
612 } | |
613 | |
614 /// <summary> | |
615 /// Construct instance with pending buffer | |
616 /// </summary> | |
617 /// <param name="pending">Pending buffer to use</param> | |
618 public DeflaterHuffman(DeflaterPending pending) | |
619 { | |
620 this.pending = pending; | |
621 | |
622 literalTree = new Tree(this, LITERAL_NUM, 257, 15); | |
623 distTree = new Tree(this, DIST_NUM, 1, 15); | |
624 blTree = new Tree(this, BITLEN_NUM, 4, 7); | |
625 | |
626 d_buf = new short[BUFSIZE]; | |
627 l_buf = new byte [BUFSIZE]; | |
628 } | |
629 | |
630 /// <summary> | |
631 /// Reset internal state | |
632 /// </summary> | |
633 public void Reset() | |
634 { | |
635 last_lit = 0; | |
636 extra_bits = 0; | |
637 literalTree.Reset(); | |
638 distTree.Reset(); | |
639 blTree.Reset(); | |
640 } | |
641 | |
642 /// <summary> | |
643 /// Write all trees to pending buffer | |
644 /// </summary> | |
645 /// <param name="blTreeCodes">The number/rank of treecodes to send.</param> | |
646 public void SendAllTrees(int blTreeCodes) | |
647 { | |
648 blTree.BuildCodes(); | |
649 literalTree.BuildCodes(); | |
650 distTree.BuildCodes(); | |
651 pending.WriteBits(literalTree.numCodes - 257, 5); | |
652 pending.WriteBits(distTree.numCodes - 1, 5); | |
653 pending.WriteBits(blTreeCodes - 4, 4); | |
654 for (int rank = 0; rank < blTreeCodes; rank++) { | |
655 pending.WriteBits(blTree.length[BL_ORDER[rank]], 3); | |
656 } | |
657 literalTree.WriteTree(blTree); | |
658 distTree.WriteTree(blTree); | |
659 | |
660 #if DebugDeflation | |
661 if (DeflaterConstants.DEBUGGING) { | |
662 blTree.CheckEmpty(); | |
663 } | |
664 #endif | |
665 } | |
666 | |
667 /// <summary> | |
668 /// Compress current buffer writing data to pending buffer | |
669 /// </summary> | |
670 public void CompressBlock() | |
671 { | |
672 for (int i = 0; i < last_lit; i++) { | |
673 int litlen = l_buf[i] & 0xff; | |
674 int dist = d_buf[i]; | |
675 if (dist-- != 0) { | |
676 // if (DeflaterConstants.DEBUGGING) { | |
677 // Console.Write("["+(dist+1)+","+(litlen+3)+"]: "); | |
678 // } | |
679 | |
680 int lc = Lcode(litlen); | |
681 literalTree.WriteSymbol(lc); | |
682 | |
683 int bits = (lc - 261) / 4; | |
684 if (bits > 0 && bits <= 5) { | |
685 pending.WriteBits(litlen & ((1 << bits) - 1), bits); | |
686 } | |
687 | |
688 int dc = Dcode(dist); | |
689 distTree.WriteSymbol(dc); | |
690 | |
691 bits = dc / 2 - 1; | |
692 if (bits > 0) { | |
693 pending.WriteBits(dist & ((1 << bits) - 1), bits); | |
694 } | |
695 } else { | |
696 // if (DeflaterConstants.DEBUGGING) { | |
697 // if (litlen > 32 && litlen < 127) { | |
698 // Console.Write("("+(char)litlen+"): "); | |
699 // } else { | |
700 // Console.Write("{"+litlen+"}: "); | |
701 // } | |
702 // } | |
703 literalTree.WriteSymbol(litlen); | |
704 } | |
705 } | |
706 | |
707 #if DebugDeflation | |
708 if (DeflaterConstants.DEBUGGING) { | |
709 Console.Write("EOF: "); | |
710 } | |
711 #endif | |
712 literalTree.WriteSymbol(EOF_SYMBOL); | |
713 | |
714 #if DebugDeflation | |
715 if (DeflaterConstants.DEBUGGING) { | |
716 literalTree.CheckEmpty(); | |
717 distTree.CheckEmpty(); | |
718 } | |
719 #endif | |
720 } | |
721 | |
722 /// <summary> | |
723 /// Flush block to output with no compression | |
724 /// </summary> | |
725 /// <param name="stored">Data to write</param> | |
726 /// <param name="storedOffset">Index of first byte to write</param> | |
727 /// <param name="storedLength">Count of bytes to write</param> | |
728 /// <param name="lastBlock">True if this is the last block</param> | |
729 public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) | |
730 { | |
731 #if DebugDeflation | |
732 // if (DeflaterConstants.DEBUGGING) { | |
733 // //Console.WriteLine("Flushing stored block "+ storedLength); | |
734 // } | |
735 #endif | |
736 pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3); | |
737 pending.AlignToByte(); | |
738 pending.WriteShort(storedLength); | |
739 pending.WriteShort(~storedLength); | |
740 pending.WriteBlock(stored, storedOffset, storedLength); | |
741 Reset(); | |
742 } | |
743 | |
744 /// <summary> | |
745 /// Flush block to output with compression | |
746 /// </summary> | |
747 /// <param name="stored">Data to flush</param> | |
748 /// <param name="storedOffset">Index of first byte to flush</param> | |
749 /// <param name="storedLength">Count of bytes to flush</param> | |
750 /// <param name="lastBlock">True if this is the last block</param> | |
751 public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) | |
752 { | |
753 literalTree.freqs[EOF_SYMBOL]++; | |
754 | |
755 // Build trees | |
756 literalTree.BuildTree(); | |
757 distTree.BuildTree(); | |
758 | |
759 // Calculate bitlen frequency | |
760 literalTree.CalcBLFreq(blTree); | |
761 distTree.CalcBLFreq(blTree); | |
762 | |
763 // Build bitlen tree | |
764 blTree.BuildTree(); | |
765 | |
766 int blTreeCodes = 4; | |
767 for (int i = 18; i > blTreeCodes; i--) { | |
768 if (blTree.length[BL_ORDER[i]] > 0) { | |
769 blTreeCodes = i+1; | |
770 } | |
771 } | |
772 int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() + | |
773 literalTree.GetEncodedLength() + distTree.GetEncodedLength() + | |
774 extra_bits; | |
775 | |
776 int static_len = extra_bits; | |
777 for (int i = 0; i < LITERAL_NUM; i++) { | |
778 static_len += literalTree.freqs[i] * staticLLength[i]; | |
779 } | |
780 for (int i = 0; i < DIST_NUM; i++) { | |
781 static_len += distTree.freqs[i] * staticDLength[i]; | |
782 } | |
783 if (opt_len >= static_len) { | |
784 // Force static trees | |
785 opt_len = static_len; | |
786 } | |
787 | |
788 if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) { | |
789 // Store Block | |
790 | |
791 // if (DeflaterConstants.DEBUGGING) { | |
792 // //Console.WriteLine("Storing, since " + storedLength + " < " + opt_len | |
793 // + " <= " + static_len); | |
794 // } | |
795 FlushStoredBlock(stored, storedOffset, storedLength, lastBlock); | |
796 } else if (opt_len == static_len) { | |
797 // Encode with static tree | |
798 pending.WriteBits((DeflaterConstants.STATIC_TREES << 1) + (lastBlock ? 1 : 0), 3); | |
799 literalTree.SetStaticCodes(staticLCodes, staticLLength); | |
800 distTree.SetStaticCodes(staticDCodes, staticDLength); | |
801 CompressBlock(); | |
802 Reset(); | |
803 } else { | |
804 // Encode with dynamic tree | |
805 pending.WriteBits((DeflaterConstants.DYN_TREES << 1) + (lastBlock ? 1 : 0), 3); | |
806 SendAllTrees(blTreeCodes); | |
807 CompressBlock(); | |
808 Reset(); | |
809 } | |
810 } | |
811 | |
812 /// <summary> | |
813 /// Get value indicating if internal buffer is full | |
814 /// </summary> | |
815 /// <returns>true if buffer is full</returns> | |
816 public bool IsFull() | |
817 { | |
818 return last_lit >= BUFSIZE; | |
819 } | |
820 | |
821 /// <summary> | |
822 /// Add literal to buffer | |
823 /// </summary> | |
824 /// <param name="literal">Literal value to add to buffer.</param> | |
825 /// <returns>Value indicating internal buffer is full</returns> | |
826 public bool TallyLit(int literal) | |
827 { | |
828 // if (DeflaterConstants.DEBUGGING) { | |
829 // if (lit > 32 && lit < 127) { | |
830 // //Console.WriteLine("("+(char)lit+")"); | |
831 // } else { | |
832 // //Console.WriteLine("{"+lit+"}"); | |
833 // } | |
834 // } | |
835 d_buf[last_lit] = 0; | |
836 l_buf[last_lit++] = (byte)literal; | |
837 literalTree.freqs[literal]++; | |
838 return IsFull(); | |
839 } | |
840 | |
841 /// <summary> | |
842 /// Add distance code and length to literal and distance trees | |
843 /// </summary> | |
844 /// <param name="distance">Distance code</param> | |
845 /// <param name="length">Length</param> | |
846 /// <returns>Value indicating if internal buffer is full</returns> | |
847 public bool TallyDist(int distance, int length) | |
848 { | |
849 // if (DeflaterConstants.DEBUGGING) { | |
850 // //Console.WriteLine("[" + distance + "," + length + "]"); | |
851 // } | |
852 | |
853 d_buf[last_lit] = (short)distance; | |
854 l_buf[last_lit++] = (byte)(length - 3); | |
855 | |
856 int lc = Lcode(length - 3); | |
857 literalTree.freqs[lc]++; | |
858 if (lc >= 265 && lc < 285) { | |
859 extra_bits += (lc - 261) / 4; | |
860 } | |
861 | |
862 int dc = Dcode(distance - 1); | |
863 distTree.freqs[dc]++; | |
864 if (dc >= 4) { | |
865 extra_bits += dc / 2 - 1; | |
866 } | |
867 return IsFull(); | |
868 } | |
869 | |
870 | |
871 /// <summary> | |
872 /// Reverse the bits of a 16 bit value. | |
873 /// </summary> | |
874 /// <param name="toReverse">Value to reverse bits</param> | |
875 /// <returns>Value with bits reversed</returns> | |
876 public static short BitReverse(int toReverse) | |
877 { | |
878 return (short) (bit4Reverse[toReverse & 0xF] << 12 | | |
879 bit4Reverse[(toReverse >> 4) & 0xF] << 8 | | |
880 bit4Reverse[(toReverse >> 8) & 0xF] << 4 | | |
881 bit4Reverse[toReverse >> 12]); | |
882 } | |
883 | |
884 static int Lcode(int length) | |
885 { | |
886 if (length == 255) { | |
887 return 285; | |
888 } | |
889 | |
890 int code = 257; | |
891 while (length >= 8) { | |
892 code += 4; | |
893 length >>= 1; | |
894 } | |
895 return code + length; | |
896 } | |
897 | |
898 static int Dcode(int distance) | |
899 { | |
900 int code = 0; | |
901 while (distance >= 4) { | |
902 code += 2; | |
903 distance >>= 1; | |
904 } | |
905 return code + distance; | |
906 } | |
907 } | |
908 } |