mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-23 09:34:35 -05:00
123 lines
4.1 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|