int WriteCentralDirectoryHeader( BlubbZipEntry entry ) { if( entry.CompressedSize < 0 ) { throw new BlubbZipException( "Attempt to write central directory entry with unknown csize" ); } if( entry.Size < 0 ) { throw new BlubbZipException( "Attempt to write central directory entry with unknown size" ); } if( entry.Crc < 0 ) { throw new BlubbZipException( "Attempt to write central directory entry with unknown crc" ); } // Write the central file header WriteLEInt( BlubbZipConstants.CentralHeaderSignature ); // Version made by WriteLEShort( BlubbZipConstants.VersionMadeBy ); // Version required to extract WriteLEShort( entry.Version ); WriteLEShort( entry.Flags ); unchecked { WriteLEShort( (byte)entry.CompressionMethod ); WriteLEInt( (int)entry.DosTime ); WriteLEInt( (int)entry.Crc ); } if( ( entry.IsBlubb64Forced() ) || ( entry.CompressedSize >= 0xffffffff ) ) { WriteLEInt( -1 ); } else { WriteLEInt( (int)( entry.CompressedSize & 0xffffffff ) ); } if( ( entry.IsBlubb64Forced() ) || ( entry.Size >= 0xffffffff ) ) { WriteLEInt( -1 ); } else { WriteLEInt( (int)entry.Size ); } byte[] name = BlubbZipConstants.ConvertToArray( entry.Flags, entry.Name ); if( name.Length > 0xFFFF ) { throw new BlubbZipException( "Entry name is too long." ); } WriteLEShort( name.Length ); // Central header extra data is different to local header version so regenerate. BlubbZipExtraData ed = new BlubbZipExtraData( entry.ExtraData ); if( entry.CentralHeaderRequiresBlubb64 ) { ed.StartNewEntry(); if( ( entry.Size >= 0xffffffff ) || ( useBlubb64_ == UseBlubb64.On ) ) { ed.AddLeLong( entry.Size ); } if( ( entry.CompressedSize >= 0xffffffff ) || ( useBlubb64_ == UseBlubb64.On ) ) { ed.AddLeLong( entry.CompressedSize ); } if( entry.Offset >= 0xffffffff ) { ed.AddLeLong( entry.Offset ); } // Number of disk on which this file starts isnt supported and is never written here. ed.AddNewEntry( 1 ); } else { // Should have already be done when local header was added. ed.Delete( 1 ); } byte[] centralExtraData = ed.GetEntryData(); WriteLEShort( centralExtraData.Length ); WriteLEShort( entry.Comment != null ? entry.Comment.Length : 0 ); WriteLEShort( 0 ); // disk number WriteLEShort( 0 ); // internal file attributes // External file attributes... if( entry.ExternalFileAttributes != -1 ) { WriteLEInt( entry.ExternalFileAttributes ); } else { if( entry.IsDirectory ) { WriteLEUint( 16 ); } else { WriteLEUint( 0 ); } } if( entry.Offset >= 0xffffffff ) { WriteLEUint( 0xffffffff ); } else { WriteLEUint( (uint)(int)entry.Offset ); } if( name.Length > 0 ) { baseStream_.Write( name, 0, name.Length ); } if( centralExtraData.Length > 0 ) { baseStream_.Write( centralExtraData, 0, centralExtraData.Length ); } byte[] rawComment = ( entry.Comment != null ) ? Encoding.ASCII.GetBytes( entry.Comment ) : new byte[ 0 ]; if( rawComment.Length > 0 ) { baseStream_.Write( rawComment, 0, rawComment.Length ); } return BlubbZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length; }
/// <summary> /// Finishes the stream. This will write the central directory at the /// end of the blubb file and flush the stream. /// </summary> /// <remarks> /// This is automatically called when the stream is closed. /// </remarks> /// <exception cref="System.IO.IOException"> /// An I/O error occurs. /// </exception> /// <exception cref="BlubbException"> /// Comment exceeds the maximum length<br/> /// Entry name exceeds the maximum length /// </exception> public override void Finish() { if (entries == null) { return; } if (curEntry != null) { CloseEntry(); } long numEntries = entries.Count; long sizeEntries = 0; foreach (BlubbZipEntry entry in entries) { WriteLeInt(BlubbZipConstants.CentralHeaderSignature); WriteLeShort(BlubbZipConstants.VersionMadeBy); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((short)entry.CompressionMethod); WriteLeInt((int)entry.DosTime); WriteLeInt((int)entry.Crc); if (entry.IsBlubb64Forced() || (entry.CompressedSize >= uint.MaxValue)) { WriteLeInt(-1); } else { WriteLeInt((int)entry.CompressedSize); } if (entry.IsBlubb64Forced() || (entry.Size >= uint.MaxValue)) { WriteLeInt(-1); } else { WriteLeInt((int)entry.Size); } byte[] name = BlubbZipConstants.ConvertToArray(entry.Flags, entry.Name); if (name.Length > 0xffff) { throw new BlubbZipException("Name too long."); } BlubbZipExtraData ed = new BlubbZipExtraData(entry.ExtraData); if (entry.CentralHeaderRequiresBlubb64) { ed.StartNewEntry(); if (entry.IsBlubb64Forced() || (entry.Size >= 0xffffffff)) { ed.AddLeLong(entry.Size); } if (entry.IsBlubb64Forced() || (entry.CompressedSize >= 0xffffffff)) { ed.AddLeLong(entry.CompressedSize); } if (entry.Offset >= 0xffffffff) { ed.AddLeLong(entry.Offset); } ed.AddNewEntry(1); } else { ed.Delete(1); } byte[] extra = ed.GetEntryData(); byte[] entryComment = (entry.Comment != null) ? BlubbZipConstants.ConvertToArray(entry.Flags, entry.Comment) : new byte[0]; if (entryComment.Length > 0xffff) { throw new BlubbZipException("Comment too long."); } WriteLeShort(name.Length); WriteLeShort(extra.Length); WriteLeShort(entryComment.Length); WriteLeShort(0); // disk number WriteLeShort(0); // internal file attributes // external file attributes if (entry.ExternalFileAttributes != -1) { WriteLeInt(entry.ExternalFileAttributes); } else { if (entry.IsDirectory) { WriteLeInt(16); } else { WriteLeInt(0); } } if (entry.Offset >= uint.MaxValue) { WriteLeInt(-1); } else { WriteLeInt((int)entry.Offset); } if (name.Length > 0) { baseOutputStream_.Write(name, 0, name.Length); } if (extra.Length > 0) { baseOutputStream_.Write(extra, 0, extra.Length); } if (entryComment.Length > 0) { baseOutputStream_.Write(entryComment, 0, entryComment.Length); } sizeEntries += BlubbZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length; } using (BlubbZipHelperStream zhs = new BlubbZipHelperStream(baseOutputStream_)) { zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, blubbComment); } entries = null; }
void WriteLocalEntryHeader( BlubbUpdate update ) { BlubbZipEntry entry = update.OutEntry; // TODO: Local offset will require adjusting for multi-disk blubb files. entry.Offset = baseStream_.Position; // TODO: Need to clear any entry flags that dont make sense or throw an exception here. if( update.Command != UpdateCommand.Copy ) { if( entry.CompressionMethod == CompressionMethod.Deflated ) { if( entry.Size == 0 ) { // No need to compress - no data. entry.CompressedSize = entry.Size; entry.Crc = 0; entry.CompressionMethod = CompressionMethod.Stored; } } else if( entry.CompressionMethod == CompressionMethod.Stored ) { entry.Flags &= ~(int)GeneralBitFlags.Descriptor; } if( HaveKeys ) { entry.IsCrypted = true; if( entry.Crc < 0 ) { entry.Flags |= (int)GeneralBitFlags.Descriptor; } } else { entry.IsCrypted = false; } switch( useBlubb64_ ) { case UseBlubb64.Dynamic: if( entry.Size < 0 ) { entry.ForceBlubb64(); } break; case UseBlubb64.On: entry.ForceBlubb64(); break; case UseBlubb64.Off: // Do nothing. The entry itself may be using Blubb64 independantly. break; } } // Write the local file header WriteLEInt( BlubbZipConstants.LocalHeaderSignature ); WriteLEShort( entry.Version ); WriteLEShort( entry.Flags ); WriteLEShort( (byte)entry.CompressionMethod ); WriteLEInt( (int)entry.DosTime ); if( !entry.HasCrc ) { // Note patch address for updating CRC later. update.CrcPatchOffset = baseStream_.Position; WriteLEInt( (int)0 ); } else { WriteLEInt( unchecked( (int)entry.Crc ) ); } if( entry.LocalHeaderRequiresBlubb64 ) { WriteLEInt( -1 ); WriteLEInt( -1 ); } else { if( ( entry.CompressedSize < 0 ) || ( entry.Size < 0 ) ) { update.SizePatchOffset = baseStream_.Position; } WriteLEInt( (int)entry.CompressedSize ); WriteLEInt( (int)entry.Size ); } byte[] name = BlubbZipConstants.ConvertToArray( entry.Flags, entry.Name ); if( name.Length > 0xFFFF ) { throw new BlubbZipException( "Entry name too long." ); } BlubbZipExtraData ed = new BlubbZipExtraData( entry.ExtraData ); if( entry.LocalHeaderRequiresBlubb64 ) { ed.StartNewEntry(); // Local entry header always includes size and compressed size. // NOTE the order of these fields is reversed when compared to the normal headers! ed.AddLeLong( entry.Size ); ed.AddLeLong( entry.CompressedSize ); ed.AddNewEntry( 1 ); } else { ed.Delete( 1 ); } entry.ExtraData = ed.GetEntryData(); WriteLEShort( name.Length ); WriteLEShort( entry.ExtraData.Length ); if( name.Length > 0 ) { baseStream_.Write( name, 0, name.Length ); } if( entry.LocalHeaderRequiresBlubb64 ) { if( !ed.Find( 1 ) ) { throw new BlubbZipException( "Internal error cannot find extra data" ); } update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex; } if( entry.ExtraData.Length > 0 ) { baseStream_.Write( entry.ExtraData, 0, entry.ExtraData.Length ); } }
/// <summary> /// Starts a new Blubb entry. It automatically closes the previous /// entry if present. /// All entry elements bar name are optional, but must be correct if present. /// If the compression method is stored and the output is not patchable /// the compression for that entry is automatically changed to deflate level 0 /// </summary> /// <param name="entry"> /// the entry. /// </param> /// <exception cref="System.ArgumentNullException"> /// if entry passed is null. /// </exception> /// <exception cref="System.IO.IOException"> /// if an I/O error occured. /// </exception> /// <exception cref="System.InvalidOperationException"> /// if stream was finished /// </exception> /// <exception cref="BlubbException"> /// Too many entries in the Blubb file<br/> /// Entry name is too long<br/> /// Finish has already been called<br/> /// </exception> public void PutNextEntry(BlubbZipEntry entry) { if (entry == null) { throw new ArgumentNullException("entry"); } if (entries == null) { throw new InvalidOperationException("BlubbOutputStream was finished"); } if (curEntry != null) { CloseEntry(); } if (entries.Count == int.MaxValue) { throw new BlubbZipException("Too many entries for Blubb file"); } CompressionMethod method = entry.CompressionMethod; int compressionLevel = defaultCompressionLevel; // Clear flags that the library manages internally entry.Flags &= (int)GeneralBitFlags.UnicodeText; patchEntryHeader = false; bool headerInfoAvailable; // No need to compress - definitely no data. if (entry.Size == 0) { entry.CompressedSize = entry.Size; entry.Crc = 0; method = CompressionMethod.Stored; headerInfoAvailable = true; } else { headerInfoAvailable = (entry.Size >= 0) && entry.HasCrc; // Switch to deflation if storing isnt possible. if (method == CompressionMethod.Stored) { if (!headerInfoAvailable) { if (!CanPatchEntries) { // Can't patch entries so storing is not possible. method = CompressionMethod.Deflated; compressionLevel = 0; } } else { // entry.size must be > 0 entry.CompressedSize = entry.Size; headerInfoAvailable = entry.HasCrc; } } } if (headerInfoAvailable == false) { if (CanPatchEntries == false) { // Only way to record size and compressed size is to append a data descriptor // after compressed data. // Stored entries of this form have already been converted to deflating. entry.Flags |= 8; } else { patchEntryHeader = true; } } if (Password != null) { entry.IsCrypted = true; if (entry.Crc < 0) { // Need to append a data descriptor as the crc isnt available for use // with encryption, the date is used instead. Setting the flag // indicates this to the decompressor. entry.Flags |= 8; } } entry.Offset = offset; entry.CompressionMethod = (CompressionMethod)method; curMethod = method; sizePatchPos = -1; if (useBlubb64_ == UseBlubb64.On || (entry.Size < 0 && useBlubb64_ == UseBlubb64.Dynamic)) { entry.ForceBlubb64(); } // Write the local file header WriteLeInt(BlubbZipConstants.LocalHeaderSignature); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((byte)method); WriteLeInt((int)entry.DosTime); // TODO: Refactor header writing. Its done in several places. if (headerInfoAvailable == true) { WriteLeInt((int)entry.Crc); if (entry.LocalHeaderRequiresBlubb64) { WriteLeInt(-1); WriteLeInt(-1); } else { WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + BlubbZipConstants.CryptoHeaderSize : (int)entry.CompressedSize); WriteLeInt((int)entry.Size); } } else { if (patchEntryHeader == true) { crcPatchPos = baseOutputStream_.Position; } WriteLeInt(0); // Crc if (patchEntryHeader) { sizePatchPos = baseOutputStream_.Position; } // For local header both sizes appear in Blubb64 Extended Information if (entry.LocalHeaderRequiresBlubb64 || patchEntryHeader) { WriteLeInt(-1); WriteLeInt(-1); } else { WriteLeInt(0); // Compressed size WriteLeInt(0); // Uncompressed size } } byte[] name = BlubbZipConstants.ConvertToArray(entry.Flags, entry.Name); if (name.Length > 0xFFFF) { throw new BlubbZipException("Entry name too long."); } BlubbZipExtraData ed = new BlubbZipExtraData(entry.ExtraData); if (entry.LocalHeaderRequiresBlubb64) { ed.StartNewEntry(); if (headerInfoAvailable) { ed.AddLeLong(entry.Size); ed.AddLeLong(entry.CompressedSize); } else { ed.AddLeLong(-1); ed.AddLeLong(-1); } ed.AddNewEntry(1); if (!ed.Find(1)) { throw new BlubbZipException("Internal error cant find extra data"); } if (patchEntryHeader) { sizePatchPos = ed.CurrentReadIndex; } } else { ed.Delete(1); } byte[] extra = ed.GetEntryData(); WriteLeShort(name.Length); WriteLeShort(extra.Length); if (name.Length > 0) { baseOutputStream_.Write(name, 0, name.Length); } if (entry.LocalHeaderRequiresBlubb64 && patchEntryHeader) { sizePatchPos += baseOutputStream_.Position; } if (extra.Length > 0) { baseOutputStream_.Write(extra, 0, extra.Length); } offset += BlubbZipConstants.LocalHeaderBaseSize + name.Length + extra.Length; // Activate the entry. curEntry = entry; crc.Reset(); if (method == CompressionMethod.Deflated) { deflater_.Reset(); deflater_.SetLevel(compressionLevel); } size = 0; if (entry.IsCrypted == true) { if (entry.Crc < 0) // so testing Blubb will says its ok { WriteEncryptionHeader(entry.DosTime << 16); } else { WriteEncryptionHeader(entry.Crc); } } }
// Write the local file header // TODO: BlubbHelperStream.WriteLocalHeader is not yet used and needs checking for BlubbFile and BlubbOuptutStream usage void WriteLocalHeader( BlubbZipEntry entry, EntryPatchData patchData ) { CompressionMethod method = entry.CompressionMethod; bool headerInfoAvailable = true; // How to get this? bool patchEntryHeader = false; WriteLEInt( BlubbZipConstants.LocalHeaderSignature ); WriteLEShort( entry.Version ); WriteLEShort( entry.Flags ); WriteLEShort( (byte)method ); WriteLEInt( (int)entry.DosTime ); if( headerInfoAvailable == true ) { WriteLEInt( (int)entry.Crc ); if( entry.LocalHeaderRequiresBlubb64 ) { WriteLEInt( -1 ); WriteLEInt( -1 ); } else { WriteLEInt( entry.IsCrypted ? (int)entry.CompressedSize + BlubbZipConstants.CryptoHeaderSize : (int)entry.CompressedSize ); WriteLEInt( (int)entry.Size ); } } else { if( patchData != null ) { patchData.CrcPatchOffset = stream_.Position; } WriteLEInt( 0 ); // Crc if( patchData != null ) { patchData.SizePatchOffset = stream_.Position; } // For local header both sizes appear in Blubb64 Extended Information if( entry.LocalHeaderRequiresBlubb64 && patchEntryHeader ) { WriteLEInt( -1 ); WriteLEInt( -1 ); } else { WriteLEInt( 0 ); // Compressed size WriteLEInt( 0 ); // Uncompressed size } } byte[] name = BlubbZipConstants.ConvertToArray( entry.Flags, entry.Name ); if( name.Length > 0xFFFF ) { throw new BlubbZipException( "Entry name too long." ); } BlubbZipExtraData ed = new BlubbZipExtraData( entry.ExtraData ); if( entry.LocalHeaderRequiresBlubb64 && ( headerInfoAvailable || patchEntryHeader ) ) { ed.StartNewEntry(); if( headerInfoAvailable ) { ed.AddLeLong( entry.Size ); ed.AddLeLong( entry.CompressedSize ); } else { ed.AddLeLong( -1 ); ed.AddLeLong( -1 ); } ed.AddNewEntry( 1 ); if( !ed.Find( 1 ) ) { throw new BlubbZipException( "Internal error cant find extra data" ); } if( patchData != null ) { patchData.SizePatchOffset = ed.CurrentReadIndex; } } else { ed.Delete( 1 ); } byte[] extra = ed.GetEntryData(); WriteLEShort( name.Length ); WriteLEShort( extra.Length ); if( name.Length > 0 ) { stream_.Write( name, 0, name.Length ); } if( entry.LocalHeaderRequiresBlubb64 && patchEntryHeader ) { patchData.SizePatchOffset += stream_.Position; } if( extra.Length > 0 ) { stream_.Write( extra, 0, extra.Length ); } }
/// <summary> /// Finishes the stream. This will write the central directory at the /// end of the blubb file and flush the stream. /// </summary> /// <remarks> /// This is automatically called when the stream is closed. /// </remarks> /// <exception cref="System.IO.IOException"> /// An I/O error occurs. /// </exception> /// <exception cref="BlubbException"> /// Comment exceeds the maximum length<br/> /// Entry name exceeds the maximum length /// </exception> public override void Finish() { if( entries == null ) { return; } if( curEntry != null ) { CloseEntry(); } long numEntries = entries.Count; long sizeEntries = 0; foreach( BlubbZipEntry entry in entries ) { WriteLeInt( BlubbZipConstants.CentralHeaderSignature ); WriteLeShort( BlubbZipConstants.VersionMadeBy ); WriteLeShort( entry.Version ); WriteLeShort( entry.Flags ); WriteLeShort( (short)entry.CompressionMethod ); WriteLeInt( (int)entry.DosTime ); WriteLeInt( (int)entry.Crc ); if( entry.IsBlubb64Forced() || ( entry.CompressedSize >= uint.MaxValue ) ) { WriteLeInt( -1 ); } else { WriteLeInt( (int)entry.CompressedSize ); } if( entry.IsBlubb64Forced() || ( entry.Size >= uint.MaxValue ) ) { WriteLeInt( -1 ); } else { WriteLeInt( (int)entry.Size ); } byte[] name = BlubbZipConstants.ConvertToArray( entry.Flags, entry.Name ); if( name.Length > 0xffff ) { throw new BlubbZipException( "Name too long." ); } BlubbZipExtraData ed = new BlubbZipExtraData( entry.ExtraData ); if( entry.CentralHeaderRequiresBlubb64 ) { ed.StartNewEntry(); if( entry.IsBlubb64Forced() || ( entry.Size >= 0xffffffff ) ) { ed.AddLeLong( entry.Size ); } if( entry.IsBlubb64Forced() || ( entry.CompressedSize >= 0xffffffff ) ) { ed.AddLeLong( entry.CompressedSize ); } if( entry.Offset >= 0xffffffff ) { ed.AddLeLong( entry.Offset ); } ed.AddNewEntry( 1 ); } else { ed.Delete( 1 ); } byte[] extra = ed.GetEntryData(); byte[] entryComment = ( entry.Comment != null ) ? BlubbZipConstants.ConvertToArray( entry.Flags, entry.Comment ) : new byte[ 0 ]; if( entryComment.Length > 0xffff ) { throw new BlubbZipException( "Comment too long." ); } WriteLeShort( name.Length ); WriteLeShort( extra.Length ); WriteLeShort( entryComment.Length ); WriteLeShort( 0 ); // disk number WriteLeShort( 0 ); // internal file attributes // external file attributes if( entry.ExternalFileAttributes != -1 ) { WriteLeInt( entry.ExternalFileAttributes ); } else { if( entry.IsDirectory ) { WriteLeInt( 16 ); } else { WriteLeInt( 0 ); } } if( entry.Offset >= uint.MaxValue ) { WriteLeInt( -1 ); } else { WriteLeInt( (int)entry.Offset ); } if( name.Length > 0 ) { baseOutputStream_.Write( name, 0, name.Length ); } if( extra.Length > 0 ) { baseOutputStream_.Write( extra, 0, extra.Length ); } if( entryComment.Length > 0 ) { baseOutputStream_.Write( entryComment, 0, entryComment.Length ); } sizeEntries += BlubbZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length; } using( BlubbZipHelperStream zhs = new BlubbZipHelperStream( baseOutputStream_ ) ) { zhs.WriteEndOfCentralDirectory( numEntries, sizeEntries, offset, blubbComment ); } entries = null; }
/// <summary> /// Starts a new Blubb entry. It automatically closes the previous /// entry if present. /// All entry elements bar name are optional, but must be correct if present. /// If the compression method is stored and the output is not patchable /// the compression for that entry is automatically changed to deflate level 0 /// </summary> /// <param name="entry"> /// the entry. /// </param> /// <exception cref="System.ArgumentNullException"> /// if entry passed is null. /// </exception> /// <exception cref="System.IO.IOException"> /// if an I/O error occured. /// </exception> /// <exception cref="System.InvalidOperationException"> /// if stream was finished /// </exception> /// <exception cref="BlubbException"> /// Too many entries in the Blubb file<br/> /// Entry name is too long<br/> /// Finish has already been called<br/> /// </exception> public void PutNextEntry( BlubbZipEntry entry ) { if( entry == null ) throw new ArgumentNullException( "entry" ); if( entries == null ) throw new InvalidOperationException( "BlubbOutputStream was finished" ); if( curEntry != null ) CloseEntry(); if( entries.Count == int.MaxValue ) throw new BlubbZipException( "Too many entries for Blubb file" ); CompressionMethod method = entry.CompressionMethod; int compressionLevel = defaultCompressionLevel; // Clear flags that the library manages internally entry.Flags &= (int)GeneralBitFlags.UnicodeText; patchEntryHeader = false; bool headerInfoAvailable; // No need to compress - definitely no data. if( entry.Size == 0 ) { entry.CompressedSize = entry.Size; entry.Crc = 0; method = CompressionMethod.Stored; headerInfoAvailable = true; } else { headerInfoAvailable = ( entry.Size >= 0 ) && entry.HasCrc; // Switch to deflation if storing isnt possible. if( method == CompressionMethod.Stored ) { if( !headerInfoAvailable ) { if( !CanPatchEntries ) { // Can't patch entries so storing is not possible. method = CompressionMethod.Deflated; compressionLevel = 0; } } else { // entry.size must be > 0 entry.CompressedSize = entry.Size; headerInfoAvailable = entry.HasCrc; } } } if( headerInfoAvailable == false ) { if( CanPatchEntries == false ) { // Only way to record size and compressed size is to append a data descriptor // after compressed data. // Stored entries of this form have already been converted to deflating. entry.Flags |= 8; } else { patchEntryHeader = true; } } if( Password != null ) { entry.IsCrypted = true; if( entry.Crc < 0 ) { // Need to append a data descriptor as the crc isnt available for use // with encryption, the date is used instead. Setting the flag // indicates this to the decompressor. entry.Flags |= 8; } } entry.Offset = offset; entry.CompressionMethod = (CompressionMethod)method; curMethod = method; sizePatchPos = -1; if( useBlubb64_ == UseBlubb64.On || ( entry.Size < 0 && useBlubb64_ == UseBlubb64.Dynamic ) ) entry.ForceBlubb64(); // Write the local file header WriteLeInt( BlubbZipConstants.LocalHeaderSignature ); WriteLeShort( entry.Version ); WriteLeShort( entry.Flags ); WriteLeShort( (byte)method ); WriteLeInt( (int)entry.DosTime ); // TODO: Refactor header writing. Its done in several places. if( headerInfoAvailable == true ) { WriteLeInt( (int)entry.Crc ); if( entry.LocalHeaderRequiresBlubb64 ) { WriteLeInt( -1 ); WriteLeInt( -1 ); } else { WriteLeInt( entry.IsCrypted ? (int)entry.CompressedSize + BlubbZipConstants.CryptoHeaderSize : (int)entry.CompressedSize ); WriteLeInt( (int)entry.Size ); } } else { if( patchEntryHeader == true ) { crcPatchPos = baseOutputStream_.Position; } WriteLeInt( 0 ); // Crc if( patchEntryHeader ) { sizePatchPos = baseOutputStream_.Position; } // For local header both sizes appear in Blubb64 Extended Information if( entry.LocalHeaderRequiresBlubb64 || patchEntryHeader ) { WriteLeInt( -1 ); WriteLeInt( -1 ); } else { WriteLeInt( 0 ); // Compressed size WriteLeInt( 0 ); // Uncompressed size } } byte[] name = BlubbZipConstants.ConvertToArray( entry.Flags, entry.Name ); if( name.Length > 0xFFFF ) throw new BlubbZipException( "Entry name too long." ); BlubbZipExtraData ed = new BlubbZipExtraData( entry.ExtraData ); if( entry.LocalHeaderRequiresBlubb64 ) { ed.StartNewEntry(); if( headerInfoAvailable ) { ed.AddLeLong( entry.Size ); ed.AddLeLong( entry.CompressedSize ); } else { ed.AddLeLong( -1 ); ed.AddLeLong( -1 ); } ed.AddNewEntry( 1 ); if( !ed.Find( 1 ) ) { throw new BlubbZipException( "Internal error cant find extra data" ); } if( patchEntryHeader ) { sizePatchPos = ed.CurrentReadIndex; } } else { ed.Delete( 1 ); } byte[] extra = ed.GetEntryData(); WriteLeShort( name.Length ); WriteLeShort( extra.Length ); if( name.Length > 0 ) { baseOutputStream_.Write( name, 0, name.Length ); } if( entry.LocalHeaderRequiresBlubb64 && patchEntryHeader ) { sizePatchPos += baseOutputStream_.Position; } if( extra.Length > 0 ) { baseOutputStream_.Write( extra, 0, extra.Length ); } offset += BlubbZipConstants.LocalHeaderBaseSize + name.Length + extra.Length; // Activate the entry. curEntry = entry; crc.Reset(); if( method == CompressionMethod.Deflated ) { deflater_.Reset(); deflater_.SetLevel( compressionLevel ); } size = 0; if( entry.IsCrypted == true ) { if( entry.Crc < 0 ) { // so testing Blubb will says its ok WriteEncryptionHeader( entry.DosTime << 16 ); } else { WriteEncryptionHeader( entry.Crc ); } } }
// Write the local file header // TODO: BlubbHelperStream.WriteLocalHeader is not yet used and needs checking for BlubbFile and BlubbOuptutStream usage void WriteLocalHeader(BlubbZipEntry entry, EntryPatchData patchData) { CompressionMethod method = entry.CompressionMethod; bool headerInfoAvailable = true; // How to get this? bool patchEntryHeader = false; WriteLEInt(BlubbZipConstants.LocalHeaderSignature); WriteLEShort(entry.Version); WriteLEShort(entry.Flags); WriteLEShort((byte)method); WriteLEInt((int)entry.DosTime); if (headerInfoAvailable == true) { WriteLEInt((int)entry.Crc); if (entry.LocalHeaderRequiresBlubb64) { WriteLEInt(-1); WriteLEInt(-1); } else { WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + BlubbZipConstants.CryptoHeaderSize : (int)entry.CompressedSize); WriteLEInt((int)entry.Size); } } else { if (patchData != null) { patchData.CrcPatchOffset = stream_.Position; } WriteLEInt(0); // Crc if (patchData != null) { patchData.SizePatchOffset = stream_.Position; } // For local header both sizes appear in Blubb64 Extended Information if (entry.LocalHeaderRequiresBlubb64 && patchEntryHeader) { WriteLEInt(-1); WriteLEInt(-1); } else { WriteLEInt(0); // Compressed size WriteLEInt(0); // Uncompressed size } } byte[] name = BlubbZipConstants.ConvertToArray(entry.Flags, entry.Name); if (name.Length > 0xFFFF) { throw new BlubbZipException("Entry name too long."); } BlubbZipExtraData ed = new BlubbZipExtraData(entry.ExtraData); if (entry.LocalHeaderRequiresBlubb64 && (headerInfoAvailable || patchEntryHeader)) { ed.StartNewEntry(); if (headerInfoAvailable) { ed.AddLeLong(entry.Size); ed.AddLeLong(entry.CompressedSize); } else { ed.AddLeLong(-1); ed.AddLeLong(-1); } ed.AddNewEntry(1); if (!ed.Find(1)) { throw new BlubbZipException("Internal error cant find extra data"); } if (patchData != null) { patchData.SizePatchOffset = ed.CurrentReadIndex; } } else { ed.Delete(1); } byte[] extra = ed.GetEntryData(); WriteLEShort(name.Length); WriteLEShort(extra.Length); if (name.Length > 0) { stream_.Write(name, 0, name.Length); } if (entry.LocalHeaderRequiresBlubb64 && patchEntryHeader) { patchData.SizePatchOffset += stream_.Position; } if (extra.Length > 0) { stream_.Write(extra, 0, extra.Length); } }