ClassiCube/Launcher2/Patcher/ZipWriter.cs
2016-06-11 15:29:45 +10:00

123 lines
4.2 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.TexturePack;
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;
}
}
}