|
1 | 1 | using CompressSharper.Zopfli; |
2 | | -using HPIZ.Compression; |
3 | 2 | using System; |
4 | 3 | using System.IO; |
5 | 4 | using System.IO.Compression; |
6 | | -using System.Linq; |
7 | | -using System.Windows.Forms; |
8 | 5 |
|
9 | 6 | namespace HPIZ |
10 | 7 | { |
11 | | - public class Chunk |
| 8 | + internal static class Chunk |
12 | 9 | { |
13 | 10 | private const int Header = 0x48535153; //SQSH (SQUASH) |
14 | 11 | private const byte DefaultVersion = 2; //Always 2? |
15 | | - public const int SizeOfChunk = 19; |
16 | | - |
17 | | - public CompressionMethod FlagCompression; |
18 | | - public bool IsObfuscated; |
19 | | - public int CompressedSize; // the length of the compressed data |
20 | | - public int DecompressedSize; // the length of the decompressed data |
21 | | - public byte[] Data; |
22 | | - public Chunk(byte[] chunkData) |
23 | | - { |
24 | | - BinaryReader hr = new BinaryReader(new MemoryStream(chunkData)); |
25 | | - int headerMark = hr.ReadInt32(); |
26 | | - if (headerMark != Chunk.Header) throw new InvalidDataException("Invalid Chunk Header"); |
27 | | - |
28 | | - int version = hr.ReadByte(); |
29 | | - if (version != DefaultVersion) throw new NotImplementedException("Unsuported Chunk Version"); |
| 12 | + public const int MinSize = 19; |
| 13 | + public const int MaxSize = 65536; |
| 14 | + private const byte NoObfuscation = 0; |
30 | 15 |
|
31 | | - FlagCompression = (CompressionMethod)hr.ReadByte(); |
32 | | - if (FlagCompression != CompressionMethod.LZ77 && FlagCompression != CompressionMethod.ZLib) |
33 | | - throw new Exception("Unknown compression method in Chunk header"); |
| 16 | + public static int ObtainDecompressedSize(byte[] chunk) |
| 17 | + { |
| 18 | + return BitConverter.ToInt32(chunk, 11); |
| 19 | + } |
34 | 20 |
|
35 | | - IsObfuscated = hr.ReadBoolean(); |
36 | | - CompressedSize = hr.ReadInt32(); |
37 | | - DecompressedSize = hr.ReadInt32(); |
| 21 | + internal static byte[] Compress(byte[] bytesToCompress, CompressionFlavor flavor) |
| 22 | + { |
| 23 | + if (bytesToCompress == null) |
| 24 | + throw new InvalidDataException("Cannot compress null array"); |
38 | 25 |
|
39 | | - if (FlagCompression == CompressionMethod.None && CompressedSize != DecompressedSize) |
40 | | - throw new Exception("Chunk size inconsistent with decompressed and compressed sizes"); |
| 26 | + if (flavor == CompressionFlavor.StoreUncompressed) |
| 27 | + throw new InvalidOperationException("Chunk format cannot be used for uncompressed data"); |
41 | 28 |
|
42 | | - int checksum = hr.ReadInt32(); |
| 29 | + MemoryStream output = new MemoryStream(bytesToCompress.Length); |
| 30 | + BinaryWriter writer = new BinaryWriter(output); |
43 | 31 |
|
44 | | - Data = new byte[CompressedSize]; |
45 | | - hr.Read(Data, 0, CompressedSize); |
| 32 | + writer.Write(Chunk.Header); |
| 33 | + writer.Write(Chunk.DefaultVersion); |
| 34 | + writer.Write((byte)CompressionMethod.ZLib); |
| 35 | + writer.Write(NoObfuscation); |
46 | 36 |
|
| 37 | + using (MemoryStream compressedStream = new MemoryStream(bytesToCompress.Length)) |
| 38 | + { |
| 39 | + compressedStream.WriteByte(0x78); //ZLib header first byte |
| 40 | + compressedStream.WriteByte(0xDA); //ZLib header second byte |
47 | 41 |
|
48 | | - if (ComputeChecksum() != checksum) throw new InvalidDataException("Bad Chunk Checksum"); |
| 42 | + switch (flavor) |
| 43 | + { |
| 44 | + case CompressionFlavor.ZLibDeflate: |
| 45 | + using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Compress, true)) |
| 46 | + deflateStream.Write(bytesToCompress, 0, bytesToCompress.Length); |
| 47 | + break; |
| 48 | + case CompressionFlavor.i5ZopfliDeflate: |
| 49 | + case CompressionFlavor.i10ZopfliDeflate: |
| 50 | + case CompressionFlavor.i15ZopfliDeflate: |
| 51 | + ZopfliDeflater zstream = new ZopfliDeflater(compressedStream); |
| 52 | + zstream.NumberOfIterations = (int)flavor; |
| 53 | + zstream.MasterBlockSize = 0; |
| 54 | + zstream.Deflate(bytesToCompress, true); |
| 55 | + break; |
| 56 | + default: |
| 57 | + throw new InvalidOperationException("Unknow compression flavor"); |
| 58 | + } |
| 59 | + var compressedDataArray = compressedStream.ToArray(); //Change to stream |
| 60 | + int checksum = ComputeChecksum(compressedDataArray); //Change to stream |
49 | 61 |
|
50 | | - if (IsObfuscated) |
51 | | - for (int j = 0; j < CompressedSize; ++j) |
52 | | - Data[j] = (byte)((Data[j] - j) ^ j); |
| 62 | + writer.Write(compressedDataArray.Length); |
| 63 | + writer.Write(bytesToCompress.Length); |
| 64 | + writer.Write(checksum); |
| 65 | + writer.Write(compressedDataArray); |
| 66 | + } |
| 67 | + return output.ToArray(); |
53 | 68 | } |
54 | 69 |
|
55 | | - public Chunk(byte[] data, bool toREMOVE) |
| 70 | + internal static byte[] Decompress(MemoryStream bytesToDecompress) |
56 | 71 | { |
57 | | - Data = data; |
58 | | - FlagCompression = CompressionMethod.None; |
59 | | - IsObfuscated = false; |
60 | | - CompressedSize = data.Length; |
61 | | - DecompressedSize = data.Length; |
62 | | - } |
| 72 | + BinaryReader reader = new BinaryReader(bytesToDecompress); |
| 73 | + int headerMark = reader.ReadInt32(); |
| 74 | + if (headerMark != Chunk.Header) throw new InvalidDataException("Invalid Chunk Header"); |
63 | 75 |
|
64 | | - private int ComputeChecksum() |
65 | | - { |
66 | | - int sum = 0; |
67 | | - for (int i = 0; i < Data.Length; ++i) |
68 | | - sum += Data[i]; |
69 | | - return sum; |
70 | | - } |
| 76 | + int version = reader.ReadByte(); |
| 77 | + if (version != DefaultVersion) throw new NotImplementedException("Unsuported Chunk Version"); |
71 | 78 |
|
72 | | - public void WriteBytes(BinaryWriter writer) |
73 | | - { |
74 | | - writer.Write(Chunk.Header); |
75 | | - writer.Write(Chunk.DefaultVersion); |
76 | | - writer.Write((byte)FlagCompression); |
77 | | - writer.Write(IsObfuscated); |
78 | | - writer.Write(CompressedSize); |
79 | | - writer.Write(DecompressedSize); |
80 | | - writer.Write(ComputeChecksum()); |
81 | | - writer.Write(Data); |
82 | | - } |
| 79 | + CompressionMethod FlagCompression = (CompressionMethod)reader.ReadByte(); |
| 80 | + if (FlagCompression != CompressionMethod.LZ77 && FlagCompression != CompressionMethod.ZLib) |
| 81 | + throw new InvalidOperationException("Unknown compression method in Chunk header"); |
83 | 82 |
|
84 | | - public void Compress(bool useZopfli) |
85 | | - { |
| 83 | + bool IsObfuscated = reader.ReadBoolean(); |
| 84 | + int CompressedSize = reader.ReadInt32(); |
| 85 | + int DecompressedSize = reader.ReadInt32(); |
| 86 | + int checksum = reader.ReadInt32(); |
86 | 87 |
|
87 | | - using (MemoryStream ms = new MemoryStream(Data.Length)) |
88 | | - { |
89 | | - ms.WriteByte(0x78); //ZLib header first byte |
90 | | - ms.WriteByte(0xDA); //ZLib header second byte |
91 | | - if (useZopfli) |
92 | | - { |
93 | | - ZopfliDeflater zstream = new ZopfliDeflater(ms); |
| 88 | + byte[] compressedData = reader.ReadBytes(CompressedSize); |
94 | 89 |
|
95 | | - zstream.NumberOfIterations = 10; |
96 | | - zstream.MasterBlockSize = 0; |
97 | | - zstream.Deflate(Data, true); |
98 | | - } |
99 | | - else |
100 | | - using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Compress, true)) |
101 | | - deflateStream.Write(Data, 0, Data.Length); |
102 | | - |
103 | | - Data = ms.ToArray(); |
104 | | - CompressedSize = Data.Length; |
105 | | - FlagCompression = CompressionMethod.ZLib; |
106 | | - } |
107 | | - } |
| 90 | + if (ComputeChecksum(compressedData) != checksum) throw new InvalidDataException("Bad Chunk Checksum"); |
108 | 91 |
|
109 | | - public void Decompress() |
110 | | - { |
111 | | - var outputBuffer = new byte[DecompressedSize]; |
| 92 | + if (IsObfuscated) |
| 93 | + for (int j = 0; j < CompressedSize; ++j) |
| 94 | + compressedData[j] = (byte)((compressedData[j] - j) ^ j); |
| 95 | + |
| 96 | + byte[] outputBuffer = new byte[DecompressedSize]; |
112 | 97 | if (FlagCompression == CompressionMethod.LZ77) |
113 | | - { |
114 | | - LZ77.Decompress(Data, outputBuffer); |
115 | | - Data = outputBuffer; |
116 | | - } |
| 98 | + LZ77.Decompress(compressedData, outputBuffer); |
| 99 | + |
117 | 100 | if (FlagCompression == CompressionMethod.ZLib) |
118 | | - { |
119 | | - ZLibDeflater.Decompress(Data, outputBuffer); |
120 | | - Data = outputBuffer; |
121 | | - } |
122 | | - FlagCompression = CompressionMethod.None; |
| 101 | + ZLibDeflater.Decompress(compressedData, outputBuffer); |
| 102 | + |
| 103 | + return outputBuffer; |
| 104 | + } |
| 105 | + |
| 106 | + private static int ComputeChecksum(byte[] data) |
| 107 | + { |
| 108 | + int sum = 0; |
| 109 | + for (int i = 0; i < data.Length; ++i) |
| 110 | + sum += data[i]; |
| 111 | + return sum; |
123 | 112 | } |
124 | 113 |
|
125 | 114 | } |
|
0 commit comments