namespace com.hitrust.util.Zip.Compression { using com.hitrust.util; using System; public class DeflaterHuffman { private static byte[] bit4Reverse = new byte[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; private static int BITLEN_NUM = 0x13; private static int[] BL_ORDER = new int[] { 0x10, 0x11, 0x12, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; private Tree blTree; private static int BUFSIZE = 0x4000; private short[] d_buf; private static int DIST_NUM = 30; private Tree distTree; private static int EOF_SYMBOL = 0x100; private int extra_bits; private byte[] l_buf; private int last_lit; private static int LITERAL_NUM = 0x11e; private Tree literalTree; public DeflaterPending pending; private static int REP_11_138 = 0x12; private static int REP_3_10 = 0x11; private static int REP_3_6 = 0x10; private static short[] staticDCodes; private static byte[] staticDLength; private static short[] staticLCodes = new short[LITERAL_NUM]; private static byte[] staticLLength = new byte[LITERAL_NUM]; static DeflaterHuffman() { int index = 0; while (index < 0x90) { staticLCodes[index] = BitReverse((0x30 + index) << 8); staticLLength[index++] = 8; } while (index < 0x100) { staticLCodes[index] = BitReverse((0x100 + index) << 7); staticLLength[index++] = 9; } while (index < 280) { staticLCodes[index] = BitReverse((-256 + index) << 9); staticLLength[index++] = 7; } while (index < LITERAL_NUM) { staticLCodes[index] = BitReverse((-88 + index) << 8); staticLLength[index++] = 8; } staticDCodes = new short[DIST_NUM]; staticDLength = new byte[DIST_NUM]; for (index = 0; index < DIST_NUM; index++) { staticDCodes[index] = BitReverse(index << 11); staticDLength[index] = 5; } } public DeflaterHuffman(DeflaterPending pending) { this.pending = pending; this.literalTree = new Tree(this, LITERAL_NUM, 0x101, 15); this.distTree = new Tree(this, DIST_NUM, 1, 15); this.blTree = new Tree(this, BITLEN_NUM, 4, 7); this.d_buf = new short[BUFSIZE]; this.l_buf = new byte[BUFSIZE]; } public static short BitReverse(int toReverse) { return (short) ((((bit4Reverse[toReverse & 15] << 12) | (bit4Reverse[(toReverse >> 4) & 15] << 8)) | (bit4Reverse[(toReverse >> 8) & 15] << 4)) | bit4Reverse[toReverse >> 12]); } public void CompressBlock() { for (int i = 0; i < this.last_lit; i++) { int len = this.l_buf[i] & 0xff; int distance = this.d_buf[i]; if (distance-- != 0) { int code = this.Lcode(len); this.literalTree.WriteSymbol(code); int count = (code - 0x105) / 4; if ((count > 0) && (count <= 5)) { this.pending.WriteBits(len & ((((int) 1) << count) - 1), count); } int num6 = this.Dcode(distance); this.distTree.WriteSymbol(num6); count = (num6 / 2) - 1; if (count > 0) { this.pending.WriteBits(distance & ((((int) 1) << count) - 1), count); } } else { this.literalTree.WriteSymbol(len); } } this.literalTree.WriteSymbol(EOF_SYMBOL); } private int Dcode(int distance) { int num = 0; while (distance >= 4) { num += 2; distance = distance >> 1; } return (num + distance); } public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) { short[] numArray; IntPtr ptr; (numArray = this.literalTree.freqs)[(int) (ptr = (IntPtr) EOF_SYMBOL)] = (short) (numArray[(int) ptr] + 1); this.literalTree.BuildTree(); this.distTree.BuildTree(); this.literalTree.CalcBLFreq(this.blTree); this.distTree.CalcBLFreq(this.blTree); this.blTree.BuildTree(); int blTreeCodes = 4; for (int i = 0x12; i > blTreeCodes; i--) { if (this.blTree.length[BL_ORDER[i]] > 0) { blTreeCodes = i + 1; } } int num3 = ((((14 + (blTreeCodes * 3)) + this.blTree.GetEncodedLength()) + this.literalTree.GetEncodedLength()) + this.distTree.GetEncodedLength()) + this.extra_bits; int num4 = this.extra_bits; for (int j = 0; j < LITERAL_NUM; j++) { num4 += this.literalTree.freqs[j] * staticLLength[j]; } for (int k = 0; k < DIST_NUM; k++) { num4 += this.distTree.freqs[k] * staticDLength[k]; } if (num3 >= num4) { num3 = num4; } if ((storedOffset >= 0) && ((storedLength + 4) < (num3 >> 3))) { this.FlushStoredBlock(stored, storedOffset, storedLength, lastBlock); } else if (num3 == num4) { this.pending.WriteBits(2 + (lastBlock ? 1 : 0), 3); this.literalTree.SetStaticCodes(staticLCodes, staticLLength); this.distTree.SetStaticCodes(staticDCodes, staticDLength); this.CompressBlock(); this.Reset(); } else { this.pending.WriteBits(4 + (lastBlock ? 1 : 0), 3); this.SendAllTrees(blTreeCodes); this.CompressBlock(); this.Reset(); } } public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) { this.pending.WriteBits(lastBlock ? 1 : 0, 3); this.pending.AlignToByte(); this.pending.WriteShort(storedLength); this.pending.WriteShort(~storedLength); this.pending.WriteBlock(stored, storedOffset, storedLength); this.Reset(); } public bool IsFull() { return (this.last_lit >= BUFSIZE); } private int Lcode(int len) { if (len == 0xff) { return 0x11d; } int num = 0x101; while (len >= 8) { num += 4; len = len >> 1; } return (num + len); } public void Reset() { this.last_lit = 0; this.extra_bits = 0; this.literalTree.Reset(); this.distTree.Reset(); this.blTree.Reset(); } public void SendAllTrees(int blTreeCodes) { this.blTree.BuildCodes(); this.literalTree.BuildCodes(); this.distTree.BuildCodes(); this.pending.WriteBits(this.literalTree.numCodes - 0x101, 5); this.pending.WriteBits(this.distTree.numCodes - 1, 5); this.pending.WriteBits(blTreeCodes - 4, 4); for (int i = 0; i < blTreeCodes; i++) { this.pending.WriteBits(this.blTree.length[BL_ORDER[i]], 3); } this.literalTree.WriteTree(this.blTree); this.distTree.WriteTree(this.blTree); } public bool TallyDist(int dist, int len) { short[] numArray; IntPtr ptr; this.d_buf[this.last_lit] = (short) dist; this.l_buf[this.last_lit++] = (byte) (len - 3); int num = this.Lcode(len - 3); (numArray = this.literalTree.freqs)[(int) (ptr = (IntPtr) num)] = (short) (numArray[(int) ptr] + 1); if ((num >= 0x109) && (num < 0x11d)) { this.extra_bits += (num - 0x105) / 4; } int num2 = this.Dcode(dist - 1); (numArray = this.distTree.freqs)[(int) (ptr = (IntPtr) num2)] = (short) (numArray[(int) ptr] + 1); if (num2 >= 4) { this.extra_bits += (num2 / 2) - 1; } return this.IsFull(); } public bool TallyLit(int lit) { short[] numArray; IntPtr ptr; this.d_buf[this.last_lit] = 0; this.l_buf[this.last_lit++] = (byte) lit; (numArray = this.literalTree.freqs)[(int) (ptr = (IntPtr) lit)] = (short) (numArray[(int) ptr] + 1); return this.IsFull(); } public class Tree { private int[] bl_counts; private short[] codes; private DeflaterHuffman dh; public short[] freqs; public byte[] length; private int maxLength; public int minNumCodes; public int numCodes; public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) { this.dh = dh; this.minNumCodes = minCodes; this.maxLength = maxLength; this.freqs = new short[elems]; this.bl_counts = new int[maxLength]; } public void BuildCodes() { int length = this.freqs.Length; int[] numArray = new int[this.maxLength]; int num = 0; this.codes = new short[this.freqs.Length]; for (int i = 0; i < this.maxLength; i++) { numArray[i] = num; num += this.bl_counts[i] << (15 - i); } for (int j = 0; j < this.numCodes; j++) { int num4 = this.length[j]; if (num4 > 0) { int[] numArray2; IntPtr ptr; this.codes[j] = DeflaterHuffman.BitReverse(numArray[num4 - 1]); (numArray2 = numArray)[(int) (ptr = (IntPtr) (num4 - 1))] = numArray2[(int) ptr] + (((int) 1) << (0x10 - num4)); } } } private void BuildLength(int[] childs) { IntPtr ptr; this.length = new byte[this.freqs.Length]; int num = childs.Length / 2; int num2 = (num + 1) / 2; int num3 = 0; for (int i = 0; i < this.maxLength; i++) { this.bl_counts[i] = 0; } int[] numArray = new int[num]; numArray[num - 1] = 0; for (int j = num - 1; j >= 0; j--) { if (childs[(2 * j) + 1] != -1) { int maxLength = numArray[j] + 1; if (maxLength > this.maxLength) { maxLength = this.maxLength; num3++; } numArray[childs[2 * j]] = numArray[childs[(2 * j) + 1]] = maxLength; } else { int num7 = numArray[j]; this.bl_counts[(int) (ptr = (IntPtr) (num7 - 1))] = this.bl_counts[(int) ptr] + 1; this.length[childs[2 * j]] = (byte) numArray[j]; } } if (num3 != 0) { int num8 = this.maxLength - 1; do { while (this.bl_counts[--num8] == 0) { } do { this.bl_counts[(int) (ptr = (IntPtr) num8)] = this.bl_counts[(int) ptr] - 1; this.bl_counts[(int) (ptr = (IntPtr) (++num8))] = this.bl_counts[(int) ptr] + 1; num3 -= ((int) 1) << ((this.maxLength - 1) - num8); } while ((num3 > 0) && (num8 < (this.maxLength - 1))); } while (num3 > 0); this.bl_counts[(int) (ptr = (IntPtr) (this.maxLength - 1))] = this.bl_counts[(int) ptr] + num3; this.bl_counts[(int) (ptr = (IntPtr) (this.maxLength - 2))] = this.bl_counts[(int) ptr] - num3; int num9 = 2 * num2; for (int k = this.maxLength; k != 0; k--) { int num11 = this.bl_counts[k - 1]; while (num11 > 0) { int index = 2 * childs[num9++]; if (childs[index + 1] == -1) { this.length[childs[index]] = (byte) k; num11--; } } } } } public void BuildTree() { int length = this.freqs.Length; int[] numArray = new int[length]; int num2 = 0; int num3 = 0; for (int i = 0; i < length; i++) { int num5 = this.freqs[i]; if (num5 != 0) { int num7; int index = num2++; while ((index > 0) && (this.freqs[numArray[num7 = (index - 1) / 2]] > num5)) { numArray[index] = numArray[num7]; index = num7; } numArray[index] = i; num3 = i; } } while (num2 < 2) { int num8 = (num3 < 2) ? ++num3 : 0; numArray[num2++] = num8; } this.numCodes = Math.Max(num3 + 1, this.minNumCodes); int num9 = num2; int[] childs = new int[(4 * num2) - 2]; int[] numArray3 = new int[(2 * num2) - 1]; int num10 = num9; for (int j = 0; j < num2; j++) { int num12 = numArray[j]; childs[2 * j] = num12; childs[(2 * j) + 1] = -1; numArray3[j] = this.freqs[num12] << 8; numArray[j] = j; } do { int num13 = numArray[0]; int num14 = numArray[--num2]; int num15 = 0; int num16 = 1; while (num16 < num2) { if (((num16 + 1) < num2) && (numArray3[numArray[num16]] > numArray3[numArray[num16 + 1]])) { num16++; } numArray[num15] = numArray[num16]; num15 = num16; num16 = (num16 * 2) + 1; } int num17 = numArray3[num14]; while (((num16 = num15) > 0) && (numArray3[numArray[num15 = (num16 - 1) / 2]] > num17)) { numArray[num16] = numArray[num15]; } numArray[num16] = num14; int num18 = numArray[0]; num14 = num10++; childs[2 * num14] = num13; childs[(2 * num14) + 1] = num18; int num19 = Math.Min((int) (numArray3[num13] & 0xff), (int) (numArray3[num18] & 0xff)); numArray3[num14] = num17 = ((numArray3[num13] + numArray3[num18]) - num19) + 1; num15 = 0; num16 = 1; while (num16 < num2) { if (((num16 + 1) < num2) && (numArray3[numArray[num16]] > numArray3[numArray[num16 + 1]])) { num16++; } numArray[num15] = numArray[num16]; num15 = num16; num16 = (num15 * 2) + 1; } while (((num16 = num15) > 0) && (numArray3[numArray[num15 = (num16 - 1) / 2]] > num17)) { numArray[num16] = numArray[num15]; } numArray[num16] = num14; } while (num2 > 1); if (numArray[0] != ((childs.Length / 2) - 1)) { throw new SharpZipBaseException("Heap invariant violated"); } this.BuildLength(childs); } public void CalcBLFreq(DeflaterHuffman.Tree blTree) { int num4 = -1; int index = 0; while (index < this.numCodes) { int num; int num2; short[] numArray; IntPtr ptr; int num3 = 1; int num6 = this.length[index]; if (num6 == 0) { num = 0x8a; num2 = 3; } else { num = 6; num2 = 3; if (num4 != num6) { (numArray = blTree.freqs)[(int) (ptr = (IntPtr) num6)] = (short) (numArray[(int) ptr] + 1); num3 = 0; } } num4 = num6; index++; while ((index < this.numCodes) && (num4 == this.length[index])) { index++; if (++num3 >= num) { break; } } if (num3 < num2) { (numArray = blTree.freqs)[(int) (ptr = (IntPtr) num4)] = (short) (numArray[(int) ptr] + ((short) num3)); } else { if (num4 != 0) { (numArray = blTree.freqs)[(int) (ptr = (IntPtr) DeflaterHuffman.REP_3_6)] = (short) (numArray[(int) ptr] + 1); continue; } if (num3 <= 10) { (numArray = blTree.freqs)[(int) (ptr = (IntPtr) DeflaterHuffman.REP_3_10)] = (short) (numArray[(int) ptr] + 1); continue; } (numArray = blTree.freqs)[(int) (ptr = (IntPtr) DeflaterHuffman.REP_11_138)] = (short) (numArray[(int) ptr] + 1); } } } public void CheckEmpty() { bool flag = true; for (int i = 0; i < this.freqs.Length; i++) { if (this.freqs[i] != 0) { flag = false; } } if (!flag) { throw new SharpZipBaseException("!Empty"); } } public int GetEncodedLength() { int num = 0; for (int i = 0; i < this.freqs.Length; i++) { num += this.freqs[i] * this.length[i]; } return num; } public void Reset() { for (int i = 0; i < this.freqs.Length; i++) { this.freqs[i] = 0; } this.codes = null; this.length = null; } public void SetStaticCodes(short[] stCodes, byte[] stLength) { this.codes = stCodes; this.length = stLength; } public void WriteSymbol(int code) { this.dh.pending.WriteBits(this.codes[code] & 0xffff, this.length[code]); } public void WriteTree(DeflaterHuffman.Tree blTree) { int code = -1; int index = 0; while (index < this.numCodes) { int num; int num2; int num3 = 1; int num6 = this.length[index]; if (num6 == 0) { num = 0x8a; num2 = 3; } else { num = 6; num2 = 3; if (code != num6) { blTree.WriteSymbol(num6); num3 = 0; } } code = num6; index++; while ((index < this.numCodes) && (code == this.length[index])) { index++; if (++num3 >= num) { break; } } if (num3 < num2) { while (num3-- > 0) { blTree.WriteSymbol(code); } } else if (code != 0) { blTree.WriteSymbol(DeflaterHuffman.REP_3_6); this.dh.pending.WriteBits(num3 - 3, 2); } else { if (num3 <= 10) { blTree.WriteSymbol(DeflaterHuffman.REP_3_10); this.dh.pending.WriteBits(num3 - 3, 3); continue; } blTree.WriteSymbol(DeflaterHuffman.REP_11_138); this.dh.pending.WriteBits(num3 - 11, 7); } } } } } }