/// <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);
                }
            }
        }
		/// <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 );
				}
			}
		}