WriteBlock() 공개 메소드

public WriteBlock ( Stream stream ) : void
stream Stream
리턴 void
예제 #1
0
        private bool WriteLocalFileHeader(bool isEmptyFile)
        {
            uint            num;
            uint            num1;
            ushort          num2;
            ushort          totalSize;
            ushort          num3;
            object          obj;
            BinaryWriter    binaryWriter = new BinaryWriter(this._archive.ArchiveStream);
            Zip64ExtraField nullable     = new Zip64ExtraField();
            bool            flag         = false;

            if (isEmptyFile)
            {
                this.CompressionMethod = ZipArchiveEntry.CompressionMethodValues.Stored;
                num  = 0;
                num1 = 0;
            }
            else if (this._archive.Mode == ZipArchiveMode.Create && !this._archive.ArchiveStream.CanSeek && !isEmptyFile)
            {
                this._generalPurposeBitFlag |= ZipArchiveEntry.BitFlagValues.DataDescriptor;
                flag = false;
                num  = 0;
                num1 = 0;
            }
            else if (!this.SizesTooLarge())
            {
                flag = false;
                num  = (uint)this._compressedSize;
                num1 = (uint)this._uncompressedSize;
            }
            else
            {
                flag = true;
                num  = -1;
                num1 = -1;
                nullable.CompressedSize   = new long?(this._compressedSize);
                nullable.UncompressedSize = new long?(this._uncompressedSize);
                this.VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
            }
            this._offsetOfLocalHeader = binaryWriter.BaseStream.Position;
            if (flag)
            {
                totalSize = nullable.TotalSize;
            }
            else
            {
                totalSize = 0;
            }
            if (this._lhUnknownExtraFields != null)
            {
                num3 = (ushort)ZipGenericExtraField.TotalSize(this._lhUnknownExtraFields);
            }
            else
            {
                num3 = 0;
            }
            int num4 = totalSize + num3;

            if (num4 <= 65535)
            {
                num2 = (ushort)num4;
            }
            else
            {
                if (flag)
                {
                    obj = nullable.TotalSize;
                }
                else
                {
                    obj = null;
                }
                num2 = (ushort)obj;
                this._lhUnknownExtraFields = null;
            }
            binaryWriter.Write((uint)67324752);
            binaryWriter.Write((ushort)this._versionToExtract);
            binaryWriter.Write((ushort)this._generalPurposeBitFlag);
            binaryWriter.Write((ushort)this.CompressionMethod);
            binaryWriter.Write(ZipHelper.DateTimeToDosTime(this._lastModified.DateTime));
            binaryWriter.Write(this._crc32);
            binaryWriter.Write(num);
            binaryWriter.Write(num1);
            binaryWriter.Write((ushort)((int)this._storedEntryNameBytes.Length));
            binaryWriter.Write(num2);
            binaryWriter.Write(this._storedEntryNameBytes);
            if (flag)
            {
                nullable.WriteBlock(this._archive.ArchiveStream);
            }
            if (this._lhUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(this._lhUnknownExtraFields, this._archive.ArchiveStream);
            }
            return(flag);
        }
예제 #2
0
        internal void WriteCentralDirectoryFileHeader()
        {
            uint            num;
            uint            num1;
            uint            num2;
            ushort          num3;
            ushort          totalSize;
            ushort          num4;
            ushort          length;
            object          obj;
            BinaryWriter    binaryWriter = new BinaryWriter(this._archive.ArchiveStream);
            Zip64ExtraField nullable     = new Zip64ExtraField();
            bool            flag         = false;

            if (!this.SizesTooLarge())
            {
                num  = (uint)this._compressedSize;
                num1 = (uint)this._uncompressedSize;
            }
            else
            {
                flag = true;
                num  = -1;
                num1 = -1;
                nullable.CompressedSize   = new long?(this._compressedSize);
                nullable.UncompressedSize = new long?(this._uncompressedSize);
            }
            if (this._offsetOfLocalHeader <= (ulong)-1)
            {
                num2 = (uint)this._offsetOfLocalHeader;
            }
            else
            {
                flag = true;
                num2 = -1;
                nullable.LocalHeaderOffset = new long?(this._offsetOfLocalHeader);
            }
            if (flag)
            {
                this.VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
            }
            if (flag)
            {
                totalSize = nullable.TotalSize;
            }
            else
            {
                totalSize = 0;
            }
            if (this._cdUnknownExtraFields != null)
            {
                num4 = (ushort)ZipGenericExtraField.TotalSize(this._cdUnknownExtraFields);
            }
            else
            {
                num4 = 0;
            }
            int num5 = totalSize + num4;

            if (num5 <= 65535)
            {
                num3 = (ushort)num5;
            }
            else
            {
                if (flag)
                {
                    obj = nullable.TotalSize;
                }
                else
                {
                    obj = null;
                }
                num3 = (ushort)obj;
                this._cdUnknownExtraFields = null;
            }
            binaryWriter.Write((uint)33639248);
            binaryWriter.Write((ushort)this._versionToExtract);
            binaryWriter.Write((ushort)this._versionToExtract);
            binaryWriter.Write((ushort)this._generalPurposeBitFlag);
            binaryWriter.Write((ushort)this.CompressionMethod);
            binaryWriter.Write(ZipHelper.DateTimeToDosTime(this._lastModified.DateTime));
            binaryWriter.Write(this._crc32);
            binaryWriter.Write(num);
            binaryWriter.Write(num1);
            binaryWriter.Write((ushort)((int)this._storedEntryNameBytes.Length));
            binaryWriter.Write(num3);
            BinaryWriter binaryWriter1 = binaryWriter;

            if (this._fileComment != null)
            {
                length = (ushort)((int)this._fileComment.Length);
            }
            else
            {
                length = 0;
            }
            binaryWriter1.Write(length);
            binaryWriter.Write((ushort)0);
            binaryWriter.Write((ushort)0);
            binaryWriter.Write(this._externalFileAttr);
            binaryWriter.Write(num2);
            binaryWriter.Write(this._storedEntryNameBytes);
            if (flag)
            {
                nullable.WriteBlock(this._archive.ArchiveStream);
            }
            if (this._cdUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(this._cdUnknownExtraFields, this._archive.ArchiveStream);
            }
            if (this._fileComment != null)
            {
                binaryWriter.Write(this._fileComment);
            }
        }
예제 #3
0
        //return value is true if we allocated an extra field for 64 bit headers, un/compressed size
        private Boolean WriteLocalFileHeader(Boolean isEmptyFile)
        {
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            //_entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            //reading in should not be able to produce a entryname longer than UInt16.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= UInt16.MaxValue);

            //decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            Boolean zip64Used = false;
            UInt32 compressedSizeTruncated, uncompressedSizeTruncated;

            //if we already know that we have an empty file don't worry about anything, just do a straight shot of the header
            if (isEmptyFile)
            {
                CompressionMethod = CompressionMethodValues.Stored;
                compressedSizeTruncated = 0;
                uncompressedSizeTruncated = 0;
                Debug.Assert(_compressedSize == 0);
                Debug.Assert(_uncompressedSize == 0);
                Debug.Assert(_crc32 == 0);
            }
            else
            {
                //if we have a non-seekable stream, don't worry about sizes at all, and just set the right bit
                //if we are using the data descriptor, then sizes and crc should be set to 0 in the header
                if (_archive.Mode == ZipArchiveMode.Create && _archive.ArchiveStream.CanSeek == false && !isEmptyFile)
                {
                    _generalPurposeBitFlag |= BitFlagValues.DataDescriptor;
                    zip64Used = false;
                    compressedSizeTruncated = 0;
                    uncompressedSizeTruncated = 0;
                    //the crc should not have been set if we are in create mode, but clear it just to be sure
                    Debug.Assert(_crc32 == 0);
                }
                else //if we are not in streaming mode, we have to decide if we want to write zip64 headers
                {
                    if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
 || (_archive._forceZip64 && _archive.Mode == ZipArchiveMode.Update)
#endif
)
                    {
                        zip64Used = true;
                        compressedSizeTruncated = ZipHelper.Mask32Bit;
                        uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                        //prepare Zip64 extra field object. If we have one of the sizes, the other must go in there
                        zip64ExtraField.CompressedSize = _compressedSize;
                        zip64ExtraField.UncompressedSize = _uncompressedSize;

                        VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
                    }
                    else
                    {
                        zip64Used = false;
                        compressedSizeTruncated = (UInt32)_compressedSize;
                        uncompressedSizeTruncated = (UInt32)_uncompressedSize;
                    }
                }
            }

            //save offset
            _offsetOfLocalHeader = writer.BaseStream.Position;

            //calculate extra field. if zip64 stuff + original extraField aren't going to fit, dump the original extraField, because this is more important
            Int32 bigExtraFieldLength = (zip64Used ? zip64ExtraField.TotalSize : 0)
                                      + (_lhUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_lhUnknownExtraFields) : 0);
            UInt16 extraFieldLength;
            if (bigExtraFieldLength > UInt16.MaxValue)
            {
                extraFieldLength = (UInt16)(zip64Used ? zip64ExtraField.TotalSize : 0);
                _lhUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (UInt16)bigExtraFieldLength;
            }

            //write header
            writer.Write(ZipLocalFileHeader.SignatureConstant);
            writer.Write((UInt16)_versionToExtract);
            writer.Write((UInt16)_generalPurposeBitFlag);
            writer.Write((UInt16)CompressionMethod);
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime)); //UInt32
            writer.Write(_crc32);               //UInt32
            writer.Write(compressedSizeTruncated);  //UInt32
            writer.Write(uncompressedSizeTruncated); //UInt32
            writer.Write((UInt16)_storedEntryNameBytes.Length);
            writer.Write(extraFieldLength);    //UInt16

            writer.Write(_storedEntryNameBytes);

            if (zip64Used)
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            if (_lhUnknownExtraFields != null)
                ZipGenericExtraField.WriteAllBlocks(_lhUnknownExtraFields, _archive.ArchiveStream);

            return zip64Used;
        }
예제 #4
0
        //should only throw an exception in extremely exceptional cases because it is called from dispose
        internal void WriteCentralDirectoryFileHeader()
        {
            //This part is simple, because we should definitely know the sizes by this time
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            //_entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            //reading in should not be able to produce a entryname longer than UInt16.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= UInt16.MaxValue);

            //decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            UInt32 compressedSizeTruncated, uncompressedSizeTruncated, offsetOfLocalHeaderTruncated;

            Boolean zip64Needed = false;

            if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
 || _archive._forceZip64
#endif
)
            {
                zip64Needed = true;
                compressedSizeTruncated = ZipHelper.Mask32Bit;
                uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                //If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.CompressedSize = _compressedSize;
                zip64ExtraField.UncompressedSize = _uncompressedSize;
            }
            else
            {
                compressedSizeTruncated = (UInt32)_compressedSize;
                uncompressedSizeTruncated = (UInt32)_uncompressedSize;
            }


            if (_offsetOfLocalHeader > UInt32.MaxValue
#if DEBUG_FORCE_ZIP64
 || _archive._forceZip64
#endif
)
            {
                zip64Needed = true;
                offsetOfLocalHeaderTruncated = ZipHelper.Mask32Bit;

                //If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.LocalHeaderOffset = _offsetOfLocalHeader;
            }
            else
            {
                offsetOfLocalHeaderTruncated = (UInt32)_offsetOfLocalHeader;
            }

            if (zip64Needed)
                VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);

            //determine if we can fit zip64 extra field and original extra fields all in
            Int32 bigExtraFieldLength = (zip64Needed ? zip64ExtraField.TotalSize : 0)
                                      + (_cdUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_cdUnknownExtraFields) : 0);
            UInt16 extraFieldLength;
            if (bigExtraFieldLength > UInt16.MaxValue)
            {
                extraFieldLength = (UInt16)(zip64Needed ? zip64ExtraField.TotalSize : 0);
                _cdUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (UInt16)bigExtraFieldLength;
            }

            writer.Write(ZipCentralDirectoryFileHeader.SignatureConstant);      // Central directory file header signature  (4 bytes)
            writer.Write((byte)_versionMadeBySpecification);                    // Version made by Specification (version)  (1 byte)
            writer.Write((byte)CurrentZipPlatform);                             // Version made by Compatibility (type)     (1 byte)
            writer.Write((UInt16)_versionToExtract);                            // Minimum version needed to extract        (2 bytes)
            writer.Write((UInt16)_generalPurposeBitFlag);                       // General Purpose bit flag                 (2 bytes)
            writer.Write((UInt16)CompressionMethod);                            // The Compression method                   (2 bytes)
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime));  // File last modification time and date     (4 bytes)
            writer.Write(_crc32);                                               // CRC-32                                   (4 bytes)
            writer.Write(compressedSizeTruncated);                              // Compressed Size                          (4 bytes)
            writer.Write(uncompressedSizeTruncated);                            // Uncompressed Size                        (4 bytes)
            writer.Write((UInt16)_storedEntryNameBytes.Length);                 // File Name Length                         (2 bytes)
            writer.Write(extraFieldLength);                                     // Extra Field Length                       (2 bytes)

            // This should hold because of how we read it originally in ZipCentralDirectoryFileHeader:
            Debug.Assert((_fileComment == null) || (_fileComment.Length <= UInt16.MaxValue));

            writer.Write(_fileComment != null ? (UInt16)_fileComment.Length : (UInt16)0);    //file comment length
            writer.Write((UInt16)0);    //disk number start
            writer.Write((UInt16)0);    //internal file attributes
            writer.Write((UInt32)0);    //external file attributes
            writer.Write(offsetOfLocalHeaderTruncated); //offset of local header

            writer.Write(_storedEntryNameBytes);

            //write extra fields
            if (zip64Needed)
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            if (_cdUnknownExtraFields != null)
                ZipGenericExtraField.WriteAllBlocks(_cdUnknownExtraFields, _archive.ArchiveStream);

            if (_fileComment != null)
                writer.Write(_fileComment);
        }
예제 #5
0
        // return value is true if we allocated an extra field for 64 bit headers, un/compressed size
        private bool WriteLocalFileHeader(bool isEmptyFile)
        {
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            // _entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            // reading in should not be able to produce an entryname longer than ushort.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= ushort.MaxValue);

            // decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            bool            zip64Used = false;
            uint            compressedSizeTruncated, uncompressedSizeTruncated;

            // if we already know that we have an empty file don't worry about anything, just do a straight shot of the header
            if (isEmptyFile)
            {
                CompressionMethod         = CompressionMethodValues.Stored;
                compressedSizeTruncated   = 0;
                uncompressedSizeTruncated = 0;
                Debug.Assert(_compressedSize == 0);
                Debug.Assert(_uncompressedSize == 0);
                Debug.Assert(_crc32 == 0);
            }
            else
            {
                // if we have a non-seekable stream, don't worry about sizes at all, and just set the right bit
                // if we are using the data descriptor, then sizes and crc should be set to 0 in the header
                if (_archive.Mode == ZipArchiveMode.Create && _archive.ArchiveStream.CanSeek == false && !isEmptyFile)
                {
                    _generalPurposeBitFlag |= BitFlagValues.DataDescriptor;
                    zip64Used = false;
                    compressedSizeTruncated   = 0;
                    uncompressedSizeTruncated = 0;
                    // the crc should not have been set if we are in create mode, but clear it just to be sure
                    Debug.Assert(_crc32 == 0);
                }
                else // if we are not in streaming mode, we have to decide if we want to write zip64 headers
                {
                    if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
                        || (_archive._forceZip64 && _archive.Mode == ZipArchiveMode.Update)
#endif
                        )
                    {
                        zip64Used = true;
                        compressedSizeTruncated   = ZipHelper.Mask32Bit;
                        uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                        // prepare Zip64 extra field object. If we have one of the sizes, the other must go in there
                        zip64ExtraField.CompressedSize   = _compressedSize;
                        zip64ExtraField.UncompressedSize = _uncompressedSize;

                        VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
                    }
                    else
                    {
                        zip64Used = false;
                        compressedSizeTruncated   = (uint)_compressedSize;
                        uncompressedSizeTruncated = (uint)_uncompressedSize;
                    }
                }
            }

            // save offset
            _offsetOfLocalHeader = writer.BaseStream.Position;

            // calculate extra field. if zip64 stuff + original extraField aren't going to fit, dump the original extraField, because this is more important
            int bigExtraFieldLength = (zip64Used ? zip64ExtraField.TotalSize : 0)
                                      + (_lhUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_lhUnknownExtraFields) : 0);
            ushort extraFieldLength;
            if (bigExtraFieldLength > ushort.MaxValue)
            {
                extraFieldLength      = (ushort)(zip64Used ? zip64ExtraField.TotalSize : 0);
                _lhUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (ushort)bigExtraFieldLength;
            }

            // write header
            writer.Write(ZipLocalFileHeader.SignatureConstant);
            writer.Write((ushort)_versionToExtract);
            writer.Write((ushort)_generalPurposeBitFlag);
            writer.Write((ushort)CompressionMethod);
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime)); // uint
            writer.Write(_crc32);                                              // uint
            writer.Write(compressedSizeTruncated);                             // uint
            writer.Write(uncompressedSizeTruncated);                           // uint
            writer.Write((ushort)_storedEntryNameBytes.Length);
            writer.Write(extraFieldLength);                                    // ushort

            writer.Write(_storedEntryNameBytes);

            if (zip64Used)
            {
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            }
            if (_lhUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(_lhUnknownExtraFields, _archive.ArchiveStream);
            }

            return(zip64Used);
        }
예제 #6
0
        // should only throw an exception in extremely exceptional cases because it is called from dispose
        internal void WriteCentralDirectoryFileHeader()
        {
            // This part is simple, because we should definitely know the sizes by this time
            BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream);

            // _entryname only gets set when we read in or call moveTo. MoveTo does a check, and
            // reading in should not be able to produce an entryname longer than ushort.MaxValue
            Debug.Assert(_storedEntryNameBytes.Length <= ushort.MaxValue);

            // decide if we need the Zip64 extra field:
            Zip64ExtraField zip64ExtraField = new Zip64ExtraField();
            uint            compressedSizeTruncated, uncompressedSizeTruncated, offsetOfLocalHeaderTruncated;

            bool zip64Needed = false;

            if (SizesTooLarge()
#if DEBUG_FORCE_ZIP64
                || _archive._forceZip64
#endif
                )
            {
                zip64Needed               = true;
                compressedSizeTruncated   = ZipHelper.Mask32Bit;
                uncompressedSizeTruncated = ZipHelper.Mask32Bit;

                // If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.CompressedSize   = _compressedSize;
                zip64ExtraField.UncompressedSize = _uncompressedSize;
            }
            else
            {
                compressedSizeTruncated   = (uint)_compressedSize;
                uncompressedSizeTruncated = (uint)_uncompressedSize;
            }


            if (_offsetOfLocalHeader > uint.MaxValue
#if DEBUG_FORCE_ZIP64
                || _archive._forceZip64
#endif
                )
            {
                zip64Needed = true;
                offsetOfLocalHeaderTruncated = ZipHelper.Mask32Bit;

                // If we have one of the sizes, the other must go in there as speced for LH, but not necessarily for CH, but we do it anyways
                zip64ExtraField.LocalHeaderOffset = _offsetOfLocalHeader;
            }
            else
            {
                offsetOfLocalHeaderTruncated = (uint)_offsetOfLocalHeader;
            }

            if (zip64Needed)
            {
                VersionToExtractAtLeast(ZipVersionNeededValues.Zip64);
            }

            // determine if we can fit zip64 extra field and original extra fields all in
            int bigExtraFieldLength = (zip64Needed ? zip64ExtraField.TotalSize : 0)
                                      + (_cdUnknownExtraFields != null ? ZipGenericExtraField.TotalSize(_cdUnknownExtraFields) : 0);
            ushort extraFieldLength;
            if (bigExtraFieldLength > ushort.MaxValue)
            {
                extraFieldLength      = (ushort)(zip64Needed ? zip64ExtraField.TotalSize : 0);
                _cdUnknownExtraFields = null;
            }
            else
            {
                extraFieldLength = (ushort)bigExtraFieldLength;
            }

            writer.Write(ZipCentralDirectoryFileHeader.SignatureConstant);      // Central directory file header signature  (4 bytes)
            writer.Write((byte)_versionMadeBySpecification);                    // Version made by Specification (version)  (1 byte)
            writer.Write((byte)CurrentZipPlatform);                             // Version made by Compatibility (type)     (1 byte)
            writer.Write((ushort)_versionToExtract);                            // Minimum version needed to extract        (2 bytes)
            writer.Write((ushort)_generalPurposeBitFlag);                       // General Purpose bit flag                 (2 bytes)
            writer.Write((ushort)CompressionMethod);                            // The Compression method                   (2 bytes)
            writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime));  // File last modification time and date     (4 bytes)
            writer.Write(_crc32);                                               // CRC-32                                   (4 bytes)
            writer.Write(compressedSizeTruncated);                              // Compressed Size                          (4 bytes)
            writer.Write(uncompressedSizeTruncated);                            // Uncompressed Size                        (4 bytes)
            writer.Write((ushort)_storedEntryNameBytes.Length);                 // File Name Length                         (2 bytes)
            writer.Write(extraFieldLength);                                     // Extra Field Length                       (2 bytes)

            // This should hold because of how we read it originally in ZipCentralDirectoryFileHeader:
            Debug.Assert((_fileComment == null) || (_fileComment.Length <= ushort.MaxValue));

            writer.Write(_fileComment != null ? (ushort)_fileComment.Length : (ushort)0); // file comment length
            writer.Write((ushort)0);                                                      // disk number start
            writer.Write((ushort)0);                                                      // internal file attributes
            writer.Write(_externalFileAttr);                                              // external file attributes
            writer.Write(offsetOfLocalHeaderTruncated);                                   // offset of local header

            writer.Write(_storedEntryNameBytes);

            // write extra fields
            if (zip64Needed)
            {
                zip64ExtraField.WriteBlock(_archive.ArchiveStream);
            }
            if (_cdUnknownExtraFields != null)
            {
                ZipGenericExtraField.WriteAllBlocks(_cdUnknownExtraFields, _archive.ArchiveStream);
            }

            if (_fileComment != null)
            {
                writer.Write(_fileComment);
            }
        }