ClassiCube/Launcher2/Patcher/ZipWriter.cs
2016-11-27 14:50:45 +11:00

123 lines
4.1 KiB
C#

// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using ClassicalSharp.Textures;
namespace Launcher.Patcher {
public sealed class ZipWriter {
BinaryWriter writer;
Stream stream;
public ZipWriter(Stream stream) {
this.stream = stream;
writer = new BinaryWriter(stream);
}
internal ZipEntry[] entries;
internal int entriesCount;
public void WriteZipEntry(ZipEntry entry, byte[] data) {
entry.CompressedDataSize = (int)entry.UncompressedDataSize;
entry.LocalHeaderOffset = (int)stream.Position;
entries[entriesCount++] = entry;
WriteLocalFileEntry(entry, data, data.Length);
}
public void WriteNewImage(Bitmap bmp, string filename) {
MemoryStream data = new MemoryStream();
bmp.Save(data, ImageFormat.Png);
byte[] buffer = data.GetBuffer();
WriteNewEntry(filename, buffer, (int)data.Length);
}
public void WriteNewString(string text, string filename) {
byte[] data = Encoding.ASCII.GetBytes(text);
WriteNewEntry(filename, data, data.Length);
}
public void WriteNewEntry(string filename, byte[] data, int dataLength) {
ZipEntry entry = new ZipEntry();
entry.UncompressedDataSize = dataLength;
entry.Crc32 = CRC32(data, dataLength);
entry.CompressedDataSize = dataLength;
entry.LocalHeaderOffset = (int)stream.Position;
entry.Filename = filename;
entries[entriesCount++] = entry;
WriteLocalFileEntry(entry, data, dataLength);
}
public void WriteCentralDirectoryRecords() {
int dirOffset = (int)stream.Position;
for (int i = 0; i < entriesCount; i++) {
WriteCentralDirectoryHeaderEntry(entries[i]);
}
int dirSize = (int)(stream.Position - dirOffset);
WriteEndOfCentralDirectoryRecord((ushort)entriesCount, dirSize, dirOffset);
}
void WriteLocalFileEntry(ZipEntry entry, byte[] data, int length) {
writer.Write(0x04034b50); // signature
writer.Write((ushort)20); // version needed
writer.Write((ushort)0); // bitflags
writer.Write((ushort)0); // compression method
writer.Write(0); // last modified
writer.Write(entry.Crc32);
writer.Write(entry.CompressedDataSize);
writer.Write(entry.UncompressedDataSize);
writer.Write((ushort)entry.Filename.Length);
writer.Write((ushort)0); // extra field length
for (int i = 0; i < entry.Filename.Length; i++)
writer.Write((byte)entry.Filename[i]);
writer.Write(data, 0, length);
}
void WriteCentralDirectoryHeaderEntry(ZipEntry entry) {
writer.Write(0x02014b50); // signature
writer.Write((ushort)20); // version
writer.Write((ushort)20); // version needed
writer.Write((ushort)0); // bitflags
writer.Write((ushort)0); // compression method
writer.Write(0); // last modified
writer.Write(entry.Crc32);
writer.Write(entry.CompressedDataSize);
writer.Write(entry.UncompressedDataSize);
writer.Write((ushort)entry.Filename.Length);
writer.Write((ushort)0); // extra field length
writer.Write((ushort)0); // file comment length
writer.Write((ushort)0); // disk number
writer.Write((ushort)0); // internal attributes
writer.Write(0); // external attributes
writer.Write(entry.LocalHeaderOffset);
for (int i = 0; i < entry.Filename.Length; i++)
writer.Write((byte)entry.Filename[i]);
}
void WriteEndOfCentralDirectoryRecord(ushort entries, int centralDirSize, int centralDirOffset) {
writer.Write(0x06054b50); // signature
writer.Write((ushort)0); // disk number
writer.Write((ushort)0); // disk number of start
writer.Write(entries); // disk entries
writer.Write(entries); // total entries
writer.Write(centralDirSize);
writer.Write(centralDirOffset);
writer.Write((ushort)0); // comment length
}
static uint CRC32(byte[] data, int length) {
uint crc = 0xffffffffU;
for (int i = 0; i < length; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++)
crc = (crc >> 1) ^ (crc & 1) * 0xEDB88320;
}
return crc ^ 0xffffffffU;
}
}
}