using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Text; using ClassicalSharp.TexturePack; namespace Launcher2 { 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; } } }