Skip to content

Commit 39257fb

Browse files
committed
Added compression flavor/level selection and improved extration speed
New options for compression with addition of flavor/level and store uncompressed. Extration code has been updated.
1 parent d5b5b07 commit 39257fb

File tree

10 files changed

+263
-265
lines changed

10 files changed

+263
-265
lines changed

HPIZ Archiver/MainForm.Designer.cs

Lines changed: 6 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

HPIZ Archiver/MainForm.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ public MainForm()
1818
}
1919
private void MainForm_Load(object sender, EventArgs e)
2020
{
21-
// Disable, Not Implemented yet
22-
compressionLevelComboBox.SelectedIndex = 1;
23-
compressionLevelComboBox.Enabled = false;
21+
compressionLevelComboBox.ComboBox.DataSource = Enum.GetValues(typeof(CompressionFlavor));
22+
compressionLevelComboBox.ComboBox.BindingContext = this.BindingContext;
23+
compressionLevelComboBox.SelectedIndex = 4;
2424
}
2525

26-
27-
2826
private void PopulateList(List<ListViewItem> collection)
2927
{
3028
listViewFiles.Items.Clear();
@@ -262,6 +260,10 @@ private async void compressCheckedFilesToolStripMenuItem_Click(object sender, Ev
262260
int size = Int32.Parse(item.SubItems[1].Text, NumberStyles.AllowThousands);
263261
chunkTotal += (size / 65536) + (size % 65536 == 0 ? 0 : 1);
264262
}
263+
264+
CompressionFlavor flavor;
265+
Enum.TryParse(compressionLevelComboBox.Text, out flavor);
266+
265267
progressBar.Maximum = chunkTotal + 1;
266268
progressBar.Value = 0;
267269
progressBar.Visible = true;
@@ -278,16 +280,18 @@ private async void compressCheckedFilesToolStripMenuItem_Click(object sender, Ev
278280
var timer = new Stopwatch();
279281
timer.Start();
280282

281-
await Task.Run(() => HpiFile.CreateFromFileList(fileList, toolStripPathTextBox.Text, dialogSaveHpi.FileName, progress));
283+
await Task.Run(() => HpiFile.CreateFromFileList(fileList, toolStripPathTextBox.Text, dialogSaveHpi.FileName, progress, flavor));
282284

283285
timer.Stop();
284286

285287
firstStatusLabel.Text = String.Format("Done! Elapsed time: {0}h {1}m {2}s {3}ms", timer.Elapsed.Hours, timer.Elapsed.Minutes,
286288
timer.Elapsed.Seconds, timer.Elapsed.Milliseconds);
287289
secondStatusLabel.Text = dialogSaveHpi.FileName;
288290
toolStrip.Enabled = true;
291+
toolStripCompressButton.Enabled = false;
289292
}
290293
}
294+
291295
}
292296

293297
}

HPIZ/Chunk.cs

Lines changed: 82 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,114 @@
11
using CompressSharper.Zopfli;
2-
using HPIZ.Compression;
32
using System;
43
using System.IO;
54
using System.IO.Compression;
6-
using System.Linq;
7-
using System.Windows.Forms;
85

96
namespace HPIZ
107
{
11-
public class Chunk
8+
internal static class Chunk
129
{
1310
private const int Header = 0x48535153; //SQSH (SQUASH)
1411
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;
3015

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+
}
3420

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");
3825

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");
4128

42-
int checksum = hr.ReadInt32();
29+
MemoryStream output = new MemoryStream(bytesToCompress.Length);
30+
BinaryWriter writer = new BinaryWriter(output);
4331

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);
4636

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
4741

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
4961

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();
5368
}
5469

55-
public Chunk(byte[] data, bool toREMOVE)
70+
internal static byte[] Decompress(MemoryStream bytesToDecompress)
5671
{
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");
6375

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");
7178

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");
8382

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();
8687

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);
9489

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");
10891

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];
11297
if (FlagCompression == CompressionMethod.LZ77)
113-
{
114-
LZ77.Decompress(Data, outputBuffer);
115-
Data = outputBuffer;
116-
}
98+
LZ77.Decompress(compressedData, outputBuffer);
99+
117100
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;
123112
}
124113

125114
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace HPIZ
6+
{
7+
public enum CompressionFlavor
8+
{
9+
StoreUncompressed = 0,
10+
ZLibDeflate = 1,
11+
i5ZopfliDeflate = 5,
12+
i10ZopfliDeflate = 10,
13+
i15ZopfliDeflate = 15
14+
15+
}
16+
}

HPIZ/Compression/LZ77.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using System.IO;
44
using System.Text;
55

6-
namespace HPIZ.Compression
6+
namespace HPIZ
77
{
88
public static class LZ77
99
{

HPIZ/FileEntry.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ public class FileEntry
1010
public CompressionMethod FlagCompression;
1111
public int[] ChunkSizes;
1212

13-
1413
public FileEntry(BinaryReader reader)
1514
{
1615
OffsetOfCompressedData = reader.ReadInt32();
@@ -22,10 +21,19 @@ public FileEntry()
2221
{
2322
}
2423

24+
public FileEntry(int uncompressedSize, CompressionMethod flagCompression, int[] chunkSizes)
25+
{
26+
UncompressedSize = uncompressedSize;
27+
FlagCompression = flagCompression;
28+
ChunkSizes = chunkSizes;
29+
}
2530

2631
public int CompressedSizeCount()
2732
{
28-
return ChunkSizes.Sum();
33+
if (FlagCompression == CompressionMethod.None)
34+
return UncompressedSize;
35+
else
36+
return ChunkSizes.Sum() + ChunkSizes.Length * 4 + Chunk.MinSize;
2937
}
3038

3139
public float Ratio()

HPIZ/HPIZ.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<Compile Include="$(MSBuildThisFileDirectory)Chunk.cs" />
13+
<Compile Include="$(MSBuildThisFileDirectory)Compression\CompressionFlavor.cs" />
1314
<Compile Include="$(MSBuildThisFileDirectory)Compression\CompressionMethod.cs" />
1415
<Compile Include="$(MSBuildThisFileDirectory)Compression\ZLibDeflater.cs" />
1516
<Compile Include="$(MSBuildThisFileDirectory)Compression\LZ77.cs" />

0 commit comments

Comments
 (0)