/// <summary> /// Create a new LocalFileHeader /// </summary> /// <param name="fileName"></param> /// <param name="encoding"></param> /// <param name="compressionMethod"></param> /// <param name="deflateOption"></param> /// <param name="streaming">true if in streaming mode</param> /// <returns></returns> internal static ZipIOLocalFileHeader CreateNew(string fileName, Encoding encoding, CompressionMethodEnum compressionMethod, DeflateOptionEnum deflateOption, bool streaming) { //this should be ensured by the higher levels Debug.Assert(Enum.IsDefined(typeof(CompressionMethodEnum), compressionMethod)); Debug.Assert(Enum.IsDefined(typeof(DeflateOptionEnum), deflateOption)); byte[] asciiName = encoding.GetBytes(fileName); if (asciiName.Length > ZipIOBlockManager.MaxFileNameSize) { throw new ArgumentOutOfRangeException("fileName"); } ZipIOLocalFileHeader header = new ZipIOLocalFileHeader(); header._signature = ZipIOLocalFileHeader._signatureConstant; header._compressionMethod = (ushort)compressionMethod; if (streaming) { header._versionNeededToExtract = (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat; } else { header._versionNeededToExtract = (UInt16)ZipIOBlockManager.CalcVersionNeededToExtractFromCompression( compressionMethod); } if (compressionMethod != CompressionMethodEnum.Stored) { Debug.Assert(deflateOption != DeflateOptionEnum.None); //this should be ensured by the higher levels header.DeflateOption = deflateOption; } if (streaming) { // set bit 3 header.StreamingCreationFlag = true; } header._lastModFileDateTime = ZipIOBlockManager.ToMsDosDateTime(DateTime.Now); header._fileNameLength = (UInt16)asciiName.Length; header._fileName = asciiName; header._extraField = ZipIOExtraField.CreateNew(!streaming /* creating padding if it is not in streaming creation mode */); header._extraFieldLength = header._extraField.Size; //populate frequently used field with user friendly data representations header._stringFileName = fileName; return(header); }
// !!! ATTENTION !!!! This function is only supposed to be called by // Block Manager.Save which has proper protection to ensure no stack overflow will happen // as a result of Stream.Flush calls which in turn result in BlockManager.Save calls public void UpdateReferences(bool closingFlag) { Invariant.Assert(!_blockManager.Streaming); long uncompressedSize; long compressedSize; CheckDisposed(); if (closingFlag) { CloseExposedStreams(); } else { FlushExposedStreams(); } // At this point we can update Local Headers with the proper CRC Value // We can also update other Local File Header Values (compressed/uncompressed size) // we rely on our DirtyFlag property to properly account for all possbile modifications within streams if (GetDirtyFlag(closingFlag)) { // Remember the size of the header before update long headerSizeBeforeUpdate = _localFileHeader.Size; // now prior to possibly closing streams we need to preserve uncompressed Size // otherwise Length function will fail to give it to us later after closing uncompressedSize = _crcCalculatingStream.Length; // calculate CRC prior to closing _localFileHeader.Crc32 = _crcCalculatingStream.CalculateCrc(); // If we are closing we can do extra things , calculate CRC , close deflate stream // it is particularly important to close the deflate stream as it might hold some extra bytes // even after Flush() if (closingFlag) { // we have got the CRC so we can close the stream _crcCalculatingStream.Close(); // in order to get proper compressed size we have to close the deflate stream if (_deflateStream != null) { _deflateStream.Close(); } } if (_fileItemStream.DataChanged) { _localFileHeader.LastModFileDateTime = ZipIOBlockManager.ToMsDosDateTime(DateTime.Now); } // get compressed size after possible closing Deflated stream // as a result of some ineffeciencies in CRC calculation it might result in Seek in compressed stream // and there fore switching mode and flushing extra compressed bytes compressedSize = _fileItemStream.Length; // this will properly (taking into account ZIP64 scenario) update local file header // Offset is passed in to determine whether ZIP 64 is required for small files that // happened to be located required 32 bit offset in the archive _localFileHeader.UpdateZip64Structures(compressedSize, uncompressedSize, Offset); // Add/remove padding to compensate the header size change // NOTE: Padding needs to be updated only after updating all the header fields // that can affect the header size _localFileHeader.UpdatePadding(_localFileHeader.Size - headerSizeBeforeUpdate); // We always save File Items in Non-streaming mode unless it wasn't touched //in which case we leave them alone _localFileHeader.StreamingCreationFlag = false; _localFileDataDescriptor = null; // in some cases UpdateZip64Structures call might result in creation/removal // of extra field if such thing happened we need to move FileItemStream appropriatel _fileItemStream.Move(checked (Offset + _localFileHeader.Size - _fileItemStream.Offset)); _dirtyFlag = true; } #if FALSE // we would like to take this oppportunity and validate basic asumption // that our GetDirtyFlag method is a reliable way to finding changes // there is no scenario in which change will happened, affecting sizes // and will not be registered by the GetDirtyFlag // ??????????????????????? else { // we even willing to recalculate CRC just in case for verification purposes UInt32 calculatedCRC32 = CalculateCrc32(); if (!_localFileHeader.StreamingCreationFlag) { Debug.Assert(_localFileHeader.Crc32 == calculatedCRC32); Debug.Assert(_localFileHeader.CompressedSize == CompressedSize); Debug.Assert(_localFileHeader.UncompressedSize == UncompressedSize); } else { Debug.Assert(_localFileDataDescriptor.Crc32 == calculatedCRC32); Debug.Assert(_localFileDataDescriptor.CompressedSize == CompressedSize); Debug.Assert(_localFileDataDescriptor.UncompressedSize == UncompressedSize); } /////////////////////////////////////////////////////////////////////// // we do not have an initialized value for the compressed size in this case compressedSize = _fileItemStream.Length; Debug.Assert(CompressedSize == compressedSize); Debug.Assert(UncompressedSize == uncompressedSize); } #endif }