/// <summary> /// Adds the entry. /// </summary> /// <param name="entryName">Name of the entry.</param> /// <param name="stream">The stream.</param> public void AddEntry([NotNull] string entryName, [NotNull] Stream stream) { if (!stream.CanRead) { throw new ArgumentException("Stream should be readable"); } // To do: assert whether entry name is unique and valid var entryInfo = new ZipEntryInfo(); entryInfo.EntryName = entryName; entryInfo.LastModifiedDate = DateTime.Now - new TimeSpan(1, 0, 0); Archive(stream, _outputStream, _tempFileStream, entryInfo, _encoding); _entriesCount++; }
private static void Archive(Stream input, Stream output, Stream headerOutput, ZipEntryInfo additionalInfo, Encoding encoding) { var bytes = new byte[4096]; long i = 0; // signature Write4Bytes(bytes, ref i, ZipConstants.ZipEntrySignature); // version needed short FixedVersionNeeded = 0x14; // from examining existing zip files Write2Bytes(bytes, ref i, FixedVersionNeeded); // bitfield short BitField = 0x00; // from examining existing zip files Write2Bytes(bytes, ref i, BitField); // compression method var offsetOfCompression = output.Position + i; short CompressionMethod = 0x08; // 0x08 = Deflate, 0x00 == No Compression Write2Bytes(bytes, ref i, CompressionMethod); // LastMod var _LastModDateTime = additionalInfo.LastModifiedDateInt; Write4Bytes(bytes, ref i, _LastModDateTime); // Writing zeros for Crc32, CompressedSize and UncompressedSize. Total length is 12 bytes // This fields will be filled later, after compression var offsetOfCrcAndSizesInHeader = i; var offsetOfCrcAndSizes = output.Position + i; i += 12; // Increasing offset by 12. // filename length (Int16) var data = encoding.GetBytes(additionalInfo.EntryName); var length = (short)data.Length; Write2Bytes(bytes, ref i, length); // extra field length (short) short ExtraFieldLength = 0x00; Write2Bytes(bytes, ref i, ExtraFieldLength); // actual filename Array.Copy(data, 0, bytes, i, data.Length); i += data.Length; // remember the file offset of this header long relativeOffsetOfHeader = (int)output.Position; // finally, write the header to the stream output.Write(bytes, 0, (int)i); var crc32 = new CRC32(); uint crc; var fileDataOffset = output.Position; using (var compressedStream = new DeflateStream(output, CompressionMode.Compress, true)) { crc = crc32.GetCrc32AndCopy(input, compressedStream); } var compressedSize = output.Position - fileDataOffset; long originalSize = crc32.TotalBytesRead; //if(originalSize == 0) //{ // SetNoCompression(output, offsetOfCompression); // compressedSize = 0; // crc = 0; // output.Seek(fileDataOffset, SeekOrigin.Begin); //} // We don't need the input stream, so we close it input.Close(); WriteCrcAndSizes(output, offsetOfCrcAndSizes, crc, originalSize, compressedSize); // Copying crc, originalSize, compressedSize to the bytes. In order to be used in central directory structure var k = offsetOfCrcAndSizesInHeader; Write4Bytes(bytes, ref k, (int)crc); Write4Bytes(bytes, ref k, (int)compressedSize); Write4Bytes(bytes, ref k, (int)originalSize); var header = new byte[i]; Array.Copy(bytes, header, i); WriteCenralDirectoryFileHeader(headerOutput, header, relativeOffsetOfHeader); }