123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901 |
- using System;
- using System.IO;
- using System.Collections;
- using CommonMPQ.SharpZipLib.Checksums;
- using CommonMPQ.SharpZipLib.Zip.Compression;
- using CommonMPQ.SharpZipLib.Zip.Compression.Streams;
- namespace CommonMPQ.SharpZipLib.Zip
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class ZipOutputStream : DeflaterOutputStream
- {
- #region Constructors
-
-
-
-
-
-
- public ZipOutputStream(Stream baseOutputStream)
- : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true))
- {
- }
-
-
-
-
-
- public ZipOutputStream( Stream baseOutputStream, int bufferSize )
- : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, true), bufferSize)
- {
- }
- #endregion
-
-
-
-
-
- public bool IsFinished
- {
- get {
- return entries == null;
- }
- }
-
-
-
-
-
-
-
-
-
- public void SetComment(string comment)
- {
-
- byte[] commentBytes = ZipConstants.ConvertToArray(comment);
- if (commentBytes.Length > 0xffff) {
- throw new ArgumentOutOfRangeException("comment");
- }
- zipComment = commentBytes;
- }
-
-
-
-
-
-
-
-
-
-
- public void SetLevel(int level)
- {
- deflater_.SetLevel(level);
- defaultCompressionLevel = level;
- }
-
-
-
-
-
- public int GetLevel()
- {
- return deflater_.GetLevel();
- }
-
-
-
-
-
-
-
- public UseZip64 UseZip64
- {
- get { return useZip64_; }
- set { useZip64_ = value; }
- }
-
-
-
-
- private void WriteLeShort(int value)
- {
- unchecked {
- baseOutputStream_.WriteByte((byte)(value & 0xff));
- baseOutputStream_.WriteByte((byte)((value >> 8) & 0xff));
- }
- }
-
-
-
-
- private void WriteLeInt(int value)
- {
- unchecked {
- WriteLeShort(value);
- WriteLeShort(value >> 16);
- }
- }
-
-
-
-
- private void WriteLeLong(long value)
- {
- unchecked {
- WriteLeInt((int)value);
- WriteLeInt((int)(value >> 32));
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public void PutNextEntry(ZipEntry entry)
- {
- if ( entry == null ) {
- throw new ArgumentNullException("entry");
- }
- if (entries == null) {
- throw new InvalidOperationException("ZipOutputStream was finished");
- }
-
- if (curEntry != null) {
- CloseEntry();
- }
- if (entries.Count == int.MaxValue) {
- throw new ZipException("Too many entries for Zip file");
- }
-
- CompressionMethod method = entry.CompressionMethod;
- int compressionLevel = defaultCompressionLevel;
-
-
- entry.Flags &= (int)GeneralBitFlags.UnicodeText;
- patchEntryHeader = false;
- bool headerInfoAvailable;
-
- if (entry.Size == 0)
- {
- entry.CompressedSize = entry.Size;
- entry.Crc = 0;
- method = CompressionMethod.Stored;
- headerInfoAvailable = true;
- }
- else
- {
- headerInfoAvailable = (entry.Size >= 0) && entry.HasCrc && entry.CompressedSize >= 0;
-
- if (method == CompressionMethod.Stored)
- {
- if (!headerInfoAvailable)
- {
- if (!CanPatchEntries)
- {
-
- method = CompressionMethod.Deflated;
- compressionLevel = 0;
- }
- }
- else
- {
- entry.CompressedSize = entry.Size;
- headerInfoAvailable = entry.HasCrc;
- }
- }
- }
- if (headerInfoAvailable == false) {
- if (CanPatchEntries == false) {
-
-
-
- entry.Flags |= 8;
- } else {
- patchEntryHeader = true;
- }
- }
-
- if (Password != null) {
- entry.IsCrypted = true;
- if (entry.Crc < 0) {
-
-
-
- entry.Flags |= 8;
- }
- }
- entry.Offset = offset;
- entry.CompressionMethod = (CompressionMethod)method;
-
- curMethod = method;
- sizePatchPos = -1;
-
- if ( (useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)) ) {
- entry.ForceZip64();
- }
-
- WriteLeInt(ZipConstants.LocalHeaderSignature);
-
- WriteLeShort(entry.Version);
- WriteLeShort(entry.Flags);
- WriteLeShort((byte)entry.CompressionMethodForHeader);
- WriteLeInt((int)entry.DosTime);
-
- if (headerInfoAvailable) {
- WriteLeInt((int)entry.Crc);
- if ( entry.LocalHeaderRequiresZip64 ) {
- WriteLeInt(-1);
- WriteLeInt(-1);
- }
- else {
- WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
- WriteLeInt((int)entry.Size);
- }
- } else {
- if (patchEntryHeader) {
- crcPatchPos = baseOutputStream_.Position;
- }
- WriteLeInt(0);
-
- if ( patchEntryHeader ) {
- sizePatchPos = baseOutputStream_.Position;
- }
-
- if ( entry.LocalHeaderRequiresZip64 || patchEntryHeader ) {
- WriteLeInt(-1);
- WriteLeInt(-1);
- }
- else {
- WriteLeInt(0);
- WriteLeInt(0);
- }
- }
- byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
-
- if (name.Length > 0xFFFF) {
- throw new ZipException("Entry name too long.");
- }
- ZipExtraData ed = new ZipExtraData(entry.ExtraData);
- if (entry.LocalHeaderRequiresZip64) {
- ed.StartNewEntry();
- if (headerInfoAvailable) {
- ed.AddLeLong(entry.Size);
- ed.AddLeLong(entry.CompressedSize);
- }
- else {
- ed.AddLeLong(-1);
- ed.AddLeLong(-1);
- }
- ed.AddNewEntry(1);
- if ( !ed.Find(1) ) {
- throw new ZipException("Internal error cant find extra data");
- }
-
- if ( patchEntryHeader ) {
- sizePatchPos = ed.CurrentReadIndex;
- }
- }
- else {
- ed.Delete(1);
- }
- #if !NET_1_1 && !NETCF_2_0
- if (entry.AESKeySize > 0) {
- AddExtraDataAES(entry, ed);
- }
- #endif
- byte[] extra = ed.GetEntryData();
- WriteLeShort(name.Length);
- WriteLeShort(extra.Length);
- if ( name.Length > 0 ) {
- baseOutputStream_.Write(name, 0, name.Length);
- }
-
- if ( entry.LocalHeaderRequiresZip64 && patchEntryHeader ) {
- sizePatchPos += baseOutputStream_.Position;
- }
- if ( extra.Length > 0 ) {
- baseOutputStream_.Write(extra, 0, extra.Length);
- }
-
- offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;
-
- if (entry.AESKeySize > 0)
- offset += entry.AESOverheadSize;
-
-
- curEntry = entry;
- crc.Reset();
- if (method == CompressionMethod.Deflated) {
- deflater_.Reset();
- deflater_.SetLevel(compressionLevel);
- }
- size = 0;
- if (entry.IsCrypted) {
- #if !NET_1_1 && !NETCF_2_0
- if (entry.AESKeySize > 0) {
- WriteAESHeader(entry);
- } else
- #endif
- {
- if (entry.Crc < 0) {
- WriteEncryptionHeader(entry.DosTime << 16);
- } else {
- WriteEncryptionHeader(entry.Crc);
- }
- }
- }
- }
-
-
-
-
-
-
-
-
-
-
- public void CloseEntry()
- {
- if (curEntry == null) {
- throw new InvalidOperationException("No open entry");
- }
- long csize = size;
-
-
- if (curMethod == CompressionMethod.Deflated) {
- if (size >= 0) {
- base.Finish();
- csize = deflater_.TotalOut;
- }
- else {
- deflater_.Reset();
- }
- }
-
- if (curEntry.AESKeySize > 0) {
- baseOutputStream_.Write(AESAuthCode, 0, 10);
- }
- if (curEntry.Size < 0) {
- curEntry.Size = size;
- } else if (curEntry.Size != size) {
- throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
- }
-
- if (curEntry.CompressedSize < 0) {
- curEntry.CompressedSize = csize;
- } else if (curEntry.CompressedSize != csize) {
- throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
- }
-
- if (curEntry.Crc < 0) {
- curEntry.Crc = crc.Value;
- } else if (curEntry.Crc != crc.Value) {
- throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc);
- }
-
- offset += csize;
- if (curEntry.IsCrypted) {
- if (curEntry.AESKeySize > 0) {
- curEntry.CompressedSize += curEntry.AESOverheadSize;
-
- } else {
- curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;
- }
- }
-
-
- if (patchEntryHeader) {
- patchEntryHeader = false;
- long curPos = baseOutputStream_.Position;
- baseOutputStream_.Seek(crcPatchPos, SeekOrigin.Begin);
- WriteLeInt((int)curEntry.Crc);
-
- if ( curEntry.LocalHeaderRequiresZip64 ) {
-
- if ( sizePatchPos == -1 ) {
- throw new ZipException("Entry requires zip64 but this has been turned off");
- }
-
- baseOutputStream_.Seek(sizePatchPos, SeekOrigin.Begin);
- WriteLeLong(curEntry.Size);
- WriteLeLong(curEntry.CompressedSize);
- }
- else {
- WriteLeInt((int)curEntry.CompressedSize);
- WriteLeInt((int)curEntry.Size);
- }
- baseOutputStream_.Seek(curPos, SeekOrigin.Begin);
- }
-
- if ((curEntry.Flags & 8) != 0) {
- WriteLeInt(ZipConstants.DataDescriptorSignature);
- WriteLeInt(unchecked((int)curEntry.Crc));
-
- if ( curEntry.LocalHeaderRequiresZip64 ) {
- WriteLeLong(curEntry.CompressedSize);
- WriteLeLong(curEntry.Size);
- offset += ZipConstants.Zip64DataDescriptorSize;
- }
- else {
- WriteLeInt((int)curEntry.CompressedSize);
- WriteLeInt((int)curEntry.Size);
- offset += ZipConstants.DataDescriptorSize;
- }
- }
-
- entries.Add(curEntry);
- curEntry = null;
- }
-
- void WriteEncryptionHeader(long crcValue)
- {
- offset += ZipConstants.CryptoHeaderSize;
-
- InitializePassword(Password);
-
- byte[] cryptBuffer = new byte[ZipConstants.CryptoHeaderSize];
- Random rnd = new Random();
- rnd.NextBytes(cryptBuffer);
- cryptBuffer[11] = (byte)(crcValue >> 24);
-
- EncryptBlock(cryptBuffer, 0, cryptBuffer.Length);
- baseOutputStream_.Write(cryptBuffer, 0, cryptBuffer.Length);
- }
- #if !NET_1_1 && !NETCF_2_0
- private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData) {
-
- const int VENDOR_VERSION = 2;
-
- const int VENDOR_ID = 0x4541;
- extraData.StartNewEntry();
-
-
- extraData.AddLeShort(VENDOR_VERSION);
- extraData.AddLeShort(VENDOR_ID);
- extraData.AddData(entry.AESEncryptionStrength);
- extraData.AddLeShort((int)entry.CompressionMethod);
- extraData.AddNewEntry(0x9901);
- }
-
-
- private void WriteAESHeader(ZipEntry entry) {
- byte[] salt;
- byte[] pwdVerifier;
- InitializeAESPassword(entry, Password, out salt, out pwdVerifier);
-
-
-
-
-
-
-
-
-
-
-
- baseOutputStream_.Write(salt, 0, salt.Length);
- baseOutputStream_.Write(pwdVerifier, 0, pwdVerifier.Length);
- }
- #endif
-
-
-
-
-
-
-
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (curEntry == null) {
- throw new InvalidOperationException("No open entry.");
- }
-
- if ( buffer == null ) {
- throw new ArgumentNullException("buffer");
- }
-
- if ( offset < 0 ) {
- #if NETCF_1_0
- throw new ArgumentOutOfRangeException("offset");
- #else
- throw new ArgumentOutOfRangeException("offset", "Cannot be negative");
- #endif
- }
- if ( count < 0 ) {
- #if NETCF_1_0
- throw new ArgumentOutOfRangeException("count");
- #else
- throw new ArgumentOutOfRangeException("count", "Cannot be negative");
- #endif
- }
- if ( (buffer.Length - offset) < count ) {
- throw new ArgumentException("Invalid offset/count combination");
- }
-
- crc.Update(buffer, offset, count);
- size += count;
-
- switch (curMethod) {
- case CompressionMethod.Deflated:
- base.Write(buffer, offset, count);
- break;
-
- case CompressionMethod.Stored:
- if (Password != null) {
- CopyAndEncrypt(buffer, offset, count);
- } else {
- baseOutputStream_.Write(buffer, offset, count);
- }
- break;
- }
- }
-
- void CopyAndEncrypt(byte[] buffer, int offset, int count)
- {
- const int CopyBufferSize = 4096;
- byte[] localBuffer = new byte[CopyBufferSize];
- while ( count > 0 ) {
- int bufferCount = (count < CopyBufferSize) ? count : CopyBufferSize;
-
- Array.Copy(buffer, offset, localBuffer, 0, bufferCount);
- EncryptBlock(localBuffer, 0, bufferCount);
- baseOutputStream_.Write(localBuffer, 0, bufferCount);
- count -= bufferCount;
- offset += bufferCount;
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public override void Finish()
- {
- if (entries == null) {
- return;
- }
-
- if (curEntry != null) {
- CloseEntry();
- }
-
- long numEntries = entries.Count;
- long sizeEntries = 0;
-
- foreach (ZipEntry entry in entries) {
- WriteLeInt(ZipConstants.CentralHeaderSignature);
- WriteLeShort(ZipConstants.VersionMadeBy);
- WriteLeShort(entry.Version);
- WriteLeShort(entry.Flags);
- WriteLeShort((short)entry.CompressionMethodForHeader);
- WriteLeInt((int)entry.DosTime);
- WriteLeInt((int)entry.Crc);
- if ( entry.IsZip64Forced() ||
- (entry.CompressedSize >= uint.MaxValue) )
- {
- WriteLeInt(-1);
- }
- else {
- WriteLeInt((int)entry.CompressedSize);
- }
- if ( entry.IsZip64Forced() ||
- (entry.Size >= uint.MaxValue) )
- {
- WriteLeInt(-1);
- }
- else {
- WriteLeInt((int)entry.Size);
- }
- byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
-
- if (name.Length > 0xffff) {
- throw new ZipException("Name too long.");
- }
-
- ZipExtraData ed = new ZipExtraData(entry.ExtraData);
- if ( entry.CentralHeaderRequiresZip64 ) {
- ed.StartNewEntry();
- if ( entry.IsZip64Forced() ||
- (entry.Size >= 0xffffffff) )
- {
- ed.AddLeLong(entry.Size);
- }
- if ( entry.IsZip64Forced() ||
- (entry.CompressedSize >= 0xffffffff) )
- {
- ed.AddLeLong(entry.CompressedSize);
- }
- if ( entry.Offset >= 0xffffffff )
- {
- ed.AddLeLong(entry.Offset);
- }
- ed.AddNewEntry(1);
- }
- else {
- ed.Delete(1);
- }
- #if !NET_1_1 && !NETCF_2_0
- if (entry.AESKeySize > 0) {
- AddExtraDataAES(entry, ed);
- }
- #endif
- byte[] extra = ed.GetEntryData();
-
- byte[] entryComment =
- (entry.Comment != null) ?
- ZipConstants.ConvertToArray(entry.Flags, entry.Comment) :
- new byte[0];
- if (entryComment.Length > 0xffff) {
- throw new ZipException("Comment too long.");
- }
-
- WriteLeShort(name.Length);
- WriteLeShort(extra.Length);
- WriteLeShort(entryComment.Length);
- WriteLeShort(0);
- WriteLeShort(0);
-
- if (entry.ExternalFileAttributes != -1) {
- WriteLeInt(entry.ExternalFileAttributes);
- } else {
- if (entry.IsDirectory) {
- WriteLeInt(16);
- } else {
- WriteLeInt(0);
- }
- }
- if ( entry.Offset >= uint.MaxValue ) {
- WriteLeInt(-1);
- }
- else {
- WriteLeInt((int)entry.Offset);
- }
-
- if ( name.Length > 0 ) {
- baseOutputStream_.Write(name, 0, name.Length);
- }
- if ( extra.Length > 0 ) {
- baseOutputStream_.Write(extra, 0, extra.Length);
- }
- if ( entryComment.Length > 0 ) {
- baseOutputStream_.Write(entryComment, 0, entryComment.Length);
- }
- sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
- }
-
- using ( ZipHelperStream zhs = new ZipHelperStream(baseOutputStream_) ) {
- zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
- }
- entries = null;
- }
-
- #region Instance Fields
-
-
-
- ArrayList entries = new ArrayList();
-
-
-
-
- Crc32 crc = new Crc32();
-
-
-
-
- ZipEntry curEntry;
-
- int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION;
-
- CompressionMethod curMethod = CompressionMethod.Deflated;
-
-
-
- long size;
-
-
-
-
- long offset;
-
-
-
-
- byte[] zipComment = new byte[0];
-
-
-
-
- bool patchEntryHeader;
-
-
-
-
- long crcPatchPos = -1;
-
-
-
-
- long sizePatchPos = -1;
-
-
-
-
- UseZip64 useZip64_ = UseZip64.Dynamic;
- #endregion
- }
- }
|