//Initializes, attaches it to archive internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd) { _archive = archive; _originallyInArchive = true; _diskNumberStart = cd.DiskNumberStart; _versionToExtract = (ZipVersionNeededValues)cd.VersionNeededToExtract; _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag; CompressionMethod = (CompressionMethodValues)cd.CompressionMethod; _lastModified = new DateTimeOffset(ZipHelper.DosTimeToDateTime(cd.LastModified)); _compressedSize = cd.CompressedSize; _uncompressedSize = cd.UncompressedSize; _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader; /* we don't know this yet: should be _offsetOfLocalHeader + 30 + _storedEntryNameBytes.Length + extrafieldlength * but entryname/extra length could be different in LH */ _storedOffsetOfCompressedData = null; _crc32 = cd.Crc32; _compressedBytes = null; _storedUncompressedData = null; _currentlyOpenForWrite = false; _everOpenedForWrite = false; _outstandingWriteStream = null; FullName = DecodeEntryName(cd.Filename); _lhUnknownExtraFields = null; //the cd should have these as null if we aren't in Update mode _cdUnknownExtraFields = cd.ExtraFields; _fileComment = cd.FileComment; _compressionLevel = null; }
// Initializes, attaches it to archive internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd) { Archive = archive; _diskNumberStart = cd.DiskNumberStart; _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag; _compressionMethod = (CompressionMethodValues)cd.CompressionMethod; // Leave this as a uint and let the caller convert it if it wants (perf optimization) LastWriteTime = cd.LastModified; CompressedLength = cd.CompressedSize; Length = cd.UncompressedSize; ExternalAttributes = (int)cd.ExternalFileAttributes; _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader; // we don't know this yet: should be _offsetOfLocalHeader + 30 + _storedEntryNameBytes.Length + extrafieldlength // but entryname/extra length could be different in LH _storedOffsetOfCompressedData = null; Crc32 = cd.Crc32; // Sacrifice a slight amount of time for safety. Zips entry names are emphatically NOT supposed to // have backslashes according to the spec, but they might anyway, so normalize them all to forward slashes. FullName = DecodeEntryName(cd.Filename)?.Replace('\\', '/') ?? throw new ArgumentNullException(nameof(FullName)); Name = ParseFileName(FullName, (ZipVersionMadeByPlatform)cd.VersionMadeByCompatibility); }
// Initializes, attaches it to archive internal ZipArchiveEntry(ZipArchiveFast archive, ZipCentralDirectoryFileHeader cd) { Archive = archive; _diskNumberStart = cd.DiskNumberStart; _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag; _compressionMethod = (CompressionMethodValues)cd.CompressionMethod; // Leave this as a uint and let the caller convert it if it wants (perf optimization) LastWriteTime = cd.LastModified; CompressedLength = cd.CompressedSize; Length = cd.UncompressedSize; _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader; // we don't know this yet: should be _offsetOfLocalHeader + 30 + _storedEntryNameBytes.Length + extrafieldlength // but entryname/extra length could be different in LH _storedOffsetOfCompressedData = null; // Sacrifice a slight amount of time for safety. Zips entry names are emphatically NOT supposed to // have backslashes according to the spec, but they might anyway, so normalize them all to forward slashes. FullName = DecodeEntryName(cd.Filename).Replace('\\', '/'); // Lazy-load Name so we don't preemptively do a ton of Substring() calls when we don't need to. _versionMadeByCompatibility = (ZipVersionMadeByPlatform)cd.VersionMadeByCompatibility; }
internal ZipArchiveEntry(ZipArchive archive, string entryName) { _archive = archive; _originallyInArchive = false; _diskNumberStart = 0; _versionToExtract = ZipVersionNeededValues.Default; _generalPurposeBitFlag = 0; CompressionMethod = CompressionMethodValues.Deflate; _lastModified = DateTimeOffset.Now; _compressedSize = 0L; _uncompressedSize = 0L; _offsetOfLocalHeader = 0L; _storedOffsetOfCompressedData = null; _crc32 = 0; _compressedBytes = null; _storedUncompressedData = null; _currentlyOpenForWrite = false; _everOpenedForWrite = false; _outstandingWriteStream = null; FullName = entryName; _cdUnknownExtraFields = null; _lhUnknownExtraFields = null; _fileComment = null; _compressionLevel = null; if (_storedEntryNameBytes.Length > 0xffff) { throw new ArgumentException(Messages.EntryNamesTooLong); } if (_archive.Mode == ZipArchiveMode.Create) { _archive.AcquireArchiveStream(this); } }
internal ZipArchiveEntry(ZipArchive archive, ZipCentralDirectoryFileHeader cd) { _archive = archive; _originallyInArchive = true; _diskNumberStart = cd.DiskNumberStart; _versionToExtract = (ZipVersionNeededValues)cd.VersionNeededToExtract; _generalPurposeBitFlag = (BitFlagValues)cd.GeneralPurposeBitFlag; CompressionMethod = (CompressionMethodValues)cd.CompressionMethod; _lastModified = new DateTimeOffset(ZipHelper.DosTimeToDateTime(cd.LastModified)); _compressedSize = cd.CompressedSize; _uncompressedSize = cd.UncompressedSize; _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader; _storedOffsetOfCompressedData = null; _crc32 = cd.Crc32; _compressedBytes = null; _storedUncompressedData = null; _currentlyOpenForWrite = false; _everOpenedForWrite = false; _outstandingWriteStream = null; FullName = DecodeEntryName(cd.Filename); _lhUnknownExtraFields = null; _cdUnknownExtraFields = cd.ExtraFields; _fileComment = cd.FileComment; _compressionLevel = null; }
// Initializes new entry internal ZipArchiveEntry(ZipArchive archive, string entryName) { _archive = archive; _originallyInArchive = false; _diskNumberStart = 0; _versionMadeByPlatform = CurrentZipPlatform; _versionMadeBySpecification = ZipVersionNeededValues.Default; _versionToExtract = ZipVersionNeededValues.Default; // this must happen before following two assignment _generalPurposeBitFlag = 0; CompressionMethod = CompressionMethodValues.Deflate; _lastModified = DateTimeOffset.Now; _compressedSize = 0; // we don't know these yet _uncompressedSize = 0; _externalFileAttr = 0; _offsetOfLocalHeader = 0; _storedOffsetOfCompressedData = null; _crc32 = 0; _compressedBytes = null; _storedUncompressedData = null; _currentlyOpenForWrite = false; _everOpenedForWrite = false; _outstandingWriteStream = null; FullName = entryName; _cdUnknownExtraFields = null; _lhUnknownExtraFields = null; _fileComment = null; _compressionLevel = null; if (_storedEntryNameBytes.Length > ushort.MaxValue) { throw new ArgumentException(); } // grab the stream if we're in create mode if (_archive.Mode == ZipArchiveMode.Create) { _archive.AcquireArchiveStream(this); } }
private void WriteCrcAndSizesInLocalHeader(bool zip64HeaderUsed) { long position = _archive.ArchiveStream.Position; BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream); bool flag1 = SizesTooLarge(); bool flag = flag1 && !zip64HeaderUsed; uint num2 = flag1 ? uint.MaxValue : ((uint)_compressedSize); uint num3 = flag1 ? uint.MaxValue : ((uint)_uncompressedSize); if (flag) { _generalPurposeBitFlag |= BitFlagValues.DataDescriptor; _archive.ArchiveStream.Seek(_offsetOfLocalHeader + 6L, SeekOrigin.Begin); writer.Write((ushort)_generalPurposeBitFlag); } _archive.ArchiveStream.Seek(_offsetOfLocalHeader + 14L, SeekOrigin.Begin); if (!flag) { writer.Write(_crc32); writer.Write(num2); writer.Write(num3); } else { writer.Write((uint)0); writer.Write((uint)0); writer.Write((uint)0); } if (zip64HeaderUsed) { _archive.ArchiveStream.Seek(((_offsetOfLocalHeader + 30L) + _storedEntryNameBytes.Length) + 4L, SeekOrigin.Begin); writer.Write(_uncompressedSize); writer.Write(_compressedSize); _archive.ArchiveStream.Seek(position, SeekOrigin.Begin); } _archive.ArchiveStream.Seek(position, SeekOrigin.Begin); if (flag) { writer.Write(_crc32); writer.Write(_compressedSize); writer.Write(_uncompressedSize); } }
// Initializes, attaches it to archive internal ReadOnlyZipArchiveEntry(ReadOnlyZipArchive archive, ZipCentralDirectoryFileHeader cd) { _archive = archive; _originallyInArchive = true; _diskNumberStart = cd.DiskNumberStart; _versionMadeByPlatform = ( ZipVersionMadeByPlatform )cd.VersionMadeByCompatibility; _versionMadeBySpecification = ( ZipVersionNeededValues )cd.VersionMadeBySpecification; _versionToExtract = ( ZipVersionNeededValues )cd.VersionNeededToExtract; _generalPurposeBitFlag = ( BitFlagValues )cd.GeneralPurposeBitFlag; CompressionMethod = ( CompressionMethodValues )cd.CompressionMethod; _lastModified = new DateTimeOffset(ZipHelper.DosTimeToDateTime(cd.LastModified)); _compressedSize = cd.CompressedSize; _uncompressedSize = cd.UncompressedSize; _externalFileAttr = cd.ExternalFileAttributes; _offsetOfLocalHeader = cd.RelativeOffsetOfLocalHeader; // we don't know this yet: should be _offsetOfLocalHeader + 30 + _storedEntryNameBytes.Length + extrafieldlength // but entryname/extra length could be different in LH _storedOffsetOfCompressedData = null; _crc32 = cd.Crc32; _compressedBytes = null; _storedUncompressedData = null; _currentlyOpenForWrite = false; _everOpenedForWrite = false; _outstandingWriteStream = null; FullName = DecodeEntryName(cd.Filename); _lhUnknownExtraFields = null; // the cd should have these as null if we aren't in Update mode _cdUnknownExtraFields = cd.ExtraFields; _fileComment = cd.FileComment; _compressionLevel = null; }
/* Using _offsetOfLocalHeader, seeks back to where CRC and sizes should be in the header, * writes them, then seeks back to where you started * Assumes that the stream is currently at the end of the data */ private void WriteCrcAndSizesInLocalHeader(Boolean zip64HeaderUsed) { Int64 finalPosition = _archive.ArchiveStream.Position; BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream); Boolean zip64Needed = SizesTooLarge() #if DEBUG_FORCE_ZIP64 || _archive._forceZip64 #endif ; Boolean pretendStreaming = zip64Needed && !zip64HeaderUsed; UInt32 compressedSizeTruncated = zip64Needed ? ZipHelper.Mask32Bit : (UInt32)_compressedSize; UInt32 uncompressedSizeTruncated = zip64Needed ? ZipHelper.Mask32Bit : (UInt32)_uncompressedSize; /* first step is, if we need zip64, but didn't allocate it, pretend we did a stream write, because * we can't go back and give ourselves the space that the extra field needs. * we do this by setting the correct property in the bit flag */ if (pretendStreaming) { _generalPurposeBitFlag |= BitFlagValues.DataDescriptor; _archive.ArchiveStream.Seek(_offsetOfLocalHeader + ZipLocalFileHeader.OffsetToBitFlagFromHeaderStart, SeekOrigin.Begin); writer.Write((UInt16)_generalPurposeBitFlag); } /* next step is fill out the 32-bit size values in the normal header. we can't assume that * they are correct. we also write the CRC */ _archive.ArchiveStream.Seek(_offsetOfLocalHeader + ZipLocalFileHeader.OffsetToCrcFromHeaderStart, SeekOrigin.Begin); if (!pretendStreaming) { writer.Write(_crc32); writer.Write(compressedSizeTruncated); writer.Write(uncompressedSizeTruncated); } else //but if we are pretending to stream, we want to fill in with zeroes { writer.Write((UInt32)0); writer.Write((UInt32)0); writer.Write((UInt32)0); } /* next step: if we wrote the 64 bit header initially, a different implementation might * try to read it, even if the 32-bit size values aren't masked. thus, we should always put the * correct size information in there. note that order of uncomp/comp is switched, and these are * 64-bit values * also, note that in order for this to be correct, we have to insure that the zip64 extra field * is always the first extra field that is written */ if (zip64HeaderUsed) { _archive.ArchiveStream.Seek(_offsetOfLocalHeader + ZipLocalFileHeader.SizeOfLocalHeader + _storedEntryNameBytes.Length + Zip64ExtraField.OffsetToFirstField, SeekOrigin.Begin); writer.Write(_uncompressedSize); writer.Write(_compressedSize); _archive.ArchiveStream.Seek(finalPosition, SeekOrigin.Begin); } // now go to the where we were. assume that this is the end of the data _archive.ArchiveStream.Seek(finalPosition, SeekOrigin.Begin); /* if we are pretending we did a stream write, we want to write the data descriptor out * the data descriptor can have 32-bit sizes or 64-bit sizes. In this case, we always use * 64-bit sizes */ if (pretendStreaming) { writer.Write(_crc32); writer.Write(_compressedSize); writer.Write(_uncompressedSize); } }
//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; }
//Initializes new entry internal ZipArchiveEntry(ZipArchive archive, String entryName) { _archive = archive; _originallyInArchive = false; _diskNumberStart = 0; _versionMadeByPlatform = CurrentZipPlatform; _versionMadeBySpecification = ZipVersionNeededValues.Default; _versionToExtract = ZipVersionNeededValues.Default; //this must happen before following two assignment _generalPurposeBitFlag = 0; CompressionMethod = CompressionMethodValues.Deflate; _lastModified = DateTimeOffset.Now; _compressedSize = 0; //we don't know these yet _uncompressedSize = 0; _offsetOfLocalHeader = 0; _storedOffsetOfCompressedData = null; _crc32 = 0; _compressedBytes = null; _storedUncompressedData = null; _currentlyOpenForWrite = false; _everOpenedForWrite = false; _outstandingWriteStream = null; FullName = entryName; _cdUnknownExtraFields = null; _lhUnknownExtraFields = null; _fileComment = null; _compressionLevel = null; if (_storedEntryNameBytes.Length > UInt16.MaxValue) throw new ArgumentException(SR.EntryNamesTooLong); //grab the stream if we're in create mode if (_archive.Mode == ZipArchiveMode.Create) { _archive.AcquireArchiveStream(this); } }
/// <summary> /// Helper function used to set and reset bits in the publicOptions bit-field. /// </summary> private void SetOptionField(BitFlagValues mask, bool value) { EnumBits = value ? EnumBits |= mask : EnumBits &= ~mask; }
/// <summary> /// /// </summary> /// <param name="index"></param> /// <returns></returns> public bool this[BitFlagValues index] { get { return((EnumBits & index) != 0); } set { EnumBits = value ? EnumBits |= index : EnumBits &= ~index; } }
// Using _offsetOfLocalHeader, seeks back to where CRC and sizes should be in the header, // writes them, then seeks back to where you started // Assumes that the stream is currently at the end of the data private void WriteCrcAndSizesInLocalHeader(bool zip64HeaderUsed) { long finalPosition = _archive.ArchiveStream.Position; BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream); bool zip64Needed = SizesTooLarge() #if DEBUG_FORCE_ZIP64 || _archive._forceZip64 #endif ; bool pretendStreaming = zip64Needed && !zip64HeaderUsed; uint compressedSizeTruncated = zip64Needed ? ZipHelper.Mask32Bit : (uint)_compressedSize; uint uncompressedSizeTruncated = zip64Needed ? ZipHelper.Mask32Bit : (uint)_uncompressedSize; // first step is, if we need zip64, but didn't allocate it, pretend we did a stream write, because // we can't go back and give ourselves the space that the extra field needs. // we do this by setting the correct property in the bit flag if (pretendStreaming) { _generalPurposeBitFlag |= BitFlagValues.DataDescriptor; _archive.ArchiveStream.Seek(_offsetOfLocalHeader + ZipLocalFileHeader.OffsetToBitFlagFromHeaderStart, SeekOrigin.Begin); writer.Write((ushort)_generalPurposeBitFlag); } // next step is fill out the 32-bit size values in the normal header. we can't assume that // they are correct. we also write the CRC _archive.ArchiveStream.Seek(_offsetOfLocalHeader + ZipLocalFileHeader.OffsetToCrcFromHeaderStart, SeekOrigin.Begin); if (!pretendStreaming) { writer.Write(_crc32); writer.Write(compressedSizeTruncated); writer.Write(uncompressedSizeTruncated); } else // but if we are pretending to stream, we want to fill in with zeroes { writer.Write((uint)0); writer.Write((uint)0); writer.Write((uint)0); } // next step: if we wrote the 64 bit header initially, a different implementation might // try to read it, even if the 32-bit size values aren't masked. thus, we should always put the // correct size information in there. note that order of uncomp/comp is switched, and these are // 64-bit values // also, note that in order for this to be correct, we have to insure that the zip64 extra field // is always the first extra field that is written if (zip64HeaderUsed) { _archive.ArchiveStream.Seek(_offsetOfLocalHeader + ZipLocalFileHeader.SizeOfLocalHeader + _storedEntryNameBytes.Length + Zip64ExtraField.OffsetToFirstField, SeekOrigin.Begin); writer.Write(_uncompressedSize); writer.Write(_compressedSize); _archive.ArchiveStream.Seek(finalPosition, SeekOrigin.Begin); } // now go to the where we were. assume that this is the end of the data _archive.ArchiveStream.Seek(finalPosition, SeekOrigin.Begin); // if we are pretending we did a stream write, we want to write the data descriptor out // the data descriptor can have 32-bit sizes or 64-bit sizes. In this case, we always use // 64-bit sizes if (pretendStreaming) { writer.Write(_crc32); writer.Write(_compressedSize); writer.Write(_uncompressedSize); } }
// 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); }
private bool WriteLocalFileHeader(bool isEmptyFile) { uint maxValue; uint num2; ushort num4; BinaryWriter writer = new BinaryWriter(_archive.ArchiveStream); Zip64ExtraField field = new Zip64ExtraField(); bool flag = false; if (isEmptyFile) { CompressionMethod = CompressionMethodValues.Stored; maxValue = 0; num2 = 0; } else if (((_archive.Mode == ZipArchiveMode.Create) && !_archive.ArchiveStream.CanSeek) && !isEmptyFile) { _generalPurposeBitFlag |= BitFlagValues.DataDescriptor; flag = false; maxValue = 0; num2 = 0; } else if (SizesTooLarge()) { flag = true; maxValue = uint.MaxValue; num2 = uint.MaxValue; field.CompressedSize = new long?(_compressedSize); field.UncompressedSize = new long?(_uncompressedSize); VersionToExtractAtLeast(ZipVersionNeededValues.Zip64); } else { flag = false; maxValue = (uint)_compressedSize; num2 = (uint)_uncompressedSize; } _offsetOfLocalHeader = writer.BaseStream.Position; int num3 = (flag ? field.TotalSize : 0) + ((_lhUnknownExtraFields != null) ? ZipGenericExtraField.TotalSize(_lhUnknownExtraFields) : 0); if (num3 > 0xffff) { num4 = flag ? field.TotalSize : ((ushort)0); _lhUnknownExtraFields = null; } else { num4 = (ushort)num3; } writer.Write((uint)0x4034b50); writer.Write((ushort)_versionToExtract); writer.Write((ushort)_generalPurposeBitFlag); writer.Write((ushort)CompressionMethod); writer.Write(ZipHelper.DateTimeToDosTime(_lastModified.DateTime)); writer.Write(_crc32); writer.Write(maxValue); writer.Write(num2); writer.Write((ushort)_storedEntryNameBytes.Length); writer.Write(num4); writer.Write(_storedEntryNameBytes); if (flag) { field.WriteBlock(_archive.ArchiveStream); } if (_lhUnknownExtraFields != null) { ZipGenericExtraField.WriteAllBlocks(_lhUnknownExtraFields, _archive.ArchiveStream); } return(flag); }