/// <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);
        }
Example #2
0
        // !!! 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
        }