/// <summary> /// Computes a table that speeds up calculation of the CRC. /// </summary> private static uint[] MakeCrcTable() { uint[] crcTable = new uint[256]; for (uint n = 0; n < 256; n++) { uint c = ZipCrc.Reflect(n, 8); c = c << 24; for (uint k = 0; k < 8; k++) { c = (c << 1) ^ ((c & 0x80000000u) != 0 ? ZipCrc.Poly : 0); } crcTable[n] = ZipCrc.Reflect(c, 32); } return(crcTable); }
public void AddFile(Stream stream, string packageUri, string mimeType, CompressionLevel level) { string partName = this.DeterminePartName(packageUri); ContentType contentType = this.DetermineContentType(partName, mimeType); ZipFileHeader localFileHeader = new ZipFileHeader(false); localFileHeader.localHeaderOffset = (uint)this.BaseStream.Position; localFileHeader.zip64 = stream.Length > 0xFFFFFFFF; localFileHeader.versionMadeBy = 0; localFileHeader.versionNeeded = localFileHeader.zip64 ? (ushort)45 : (ushort)20; localFileHeader.fileName = partName; localFileHeader.compressionMethod = (level == CompressionLevel.NoCompression) ? ZipCompressionMethod.Store : ZipCompressionMethod.Deflate; localFileHeader.flags = this.BaseStream.CanSeek ? ZipFileFlags.None : ZipFileFlags.DataDescriptor; localFileHeader.Write(this.BaseStream); BlockMapFile blockMapFile = new BlockMapFile(partName) { Size = stream.Length, ZipLocalFileHeaderSize = localFileHeader.GetSize() }; this.blockMapFiles.Add(blockMapFile); ZipCrc crc = new ZipCrc(); BlockDeflateStream deflate = (level == CompressionLevel.NoCompression) ? null : new BlockDeflateStream(this.BaseStream, (BlockDeflateCompressionLevel)level); long outputStart = this.BaseStream.Position; int read = 0; byte[] buffer = new byte[64 * 1024]; while (0 < (read = stream.Read(buffer, 0, buffer.Length))) { crc.UpdateCrc(buffer, 0, read); string hash; using (SHA256 sha256 = SHA256.Create()) { byte[] hashedBytes = sha256.ComputeHash(buffer, 0, read); hash = Convert.ToBase64String(hashedBytes); } long compressedBlockSize = 0; if (deflate != null) { compressedBlockSize = deflate.Deflate(buffer, 0, read); } else { this.BaseStream.Write(buffer, 0, read); compressedBlockSize = -1; } BlockMapFileBlock block = new BlockMapFileBlock() { Hash = hash, CompressedSize = compressedBlockSize }; blockMapFile.Blocks.Add(block); } if (deflate != null) { deflate.Flush(); } else { this.BaseStream.Flush(); } // Update the local file header with data discovered while processing file data. localFileHeader.crc32 = crc.Crc; localFileHeader.compressedSize = (uint)(this.BaseStream.Position - outputStart); // (uint)compressedSize; localFileHeader.uncompressedSize = (uint)stream.Length; // If we're using the data descriptor (because we can't see), append the updated information to the file data. if ((localFileHeader.flags & ZipFileFlags.DataDescriptor) == ZipFileFlags.DataDescriptor) { localFileHeader.WriteDataDescriptor(this.BaseStream); } else // go back to re-write the updated local file header in place, then seek back to our current location. { long position = this.BaseStream.Position; this.BaseStream.Seek(localFileHeader.localHeaderOffset, SeekOrigin.Begin); localFileHeader.Write(this.BaseStream); this.BaseStream.Seek(position, SeekOrigin.Begin); } // If we have a 64-bit local header then the central directory must be // ZIP64 as well. if (localFileHeader.zip64) { this.eocd.zip64 = true; this.eocd.versionMadeBy = 45; this.eocd.versionNeeded = 45; } ZipFileHeader centralFileHeader = new ZipFileHeader(localFileHeader); this.eocd.CentralDirectory.Add(centralFileHeader); }