/// <summary>
        /// Writes to the inputStream
        /// <para>Default 'seek' is true, flushes and seeks to the end of stream after write is finished</para>
        /// <para>Eliminates the need for coding output.Flush() followed by output.Seek(0, SeekOrigin.Begin)</para>
        /// </summary>
        /// <param name="inputStream"></param>
        /// <param name="encrypt"></param>
        /// <param name="seek"></param>
        public void Write(Stream inputStream, bool encrypt = false, bool seek = true)
        {
            _header.ArchiveFlags = encrypt ? 4U : 0U;
            _header.TOCEntrySize = 30U;

            // track artifacts
            WriteManifest();

            //Pack entries
            List <uint> zLengths;
            Dictionary <Entry, byte[]> zStreams;

            DeflateEntries(out zStreams, out zLengths);

            //Build zLengths
            _writer = new BigEndianBinaryWriter(inputStream);
            _header.TotalTOCSize = (uint)(32 + _toc.Count * _header.TOCEntrySize + zLengths.Count * bNum);
            _toc[0].Offset       = _header.TotalTOCSize;

            for (int i = 1; i < _toc.Count; i++)
            {
                _toc[i].Offset = _toc[i - 1].Offset + (ulong)(zStreams[_toc[i - 1]].Length);
            }

            //Write Header
            _writer.Write(_header.MagicNumber);
            _writer.Write(_header.VersionNumber);
            _writer.Write(_header.CompressionMethod);
            _writer.Write(_header.TotalTOCSize);
            _writer.Write(_header.TOCEntrySize);
            _writer.Write(_toc.Count);
            _writer.Write(_header.BlockSizeAlloc);
            _writer.Write(_header.ArchiveFlags);

            var    step     = Math.Round(1D / (this.TOC.Count + 2) * 100, 3);
            double progress = 0;

            GlobalExtension.ShowProgress("Writing tocData ...");

            //Write Table of contents
            foreach (Entry entry in _toc)
            {
                entry.UpdateNameMD5();
                _writer.Write(entry.MD5);
                _writer.Write(entry.zIndexBegin);
                _writer.WriteUInt40((ulong)entry.Data.Length);
                _writer.WriteUInt40(entry.Offset);

                progress += step;
                GlobalExtension.UpdateProgress.Value = (int)progress;
                Console.WriteLine("Writing tocData: " + entry.Id);
            }

            foreach (uint zLen in zLengths)
            {
                switch (bNum)
                {
                case 2:     //16bit
                    _writer.Write((ushort)zLen);
                    break;

                case 3:     //24bit
                    _writer.WriteUInt24(zLen);
                    break;

                case 4:     //32bit
                    _writer.Write(zLen);
                    break;
                }
            }

            zLengths = null;
            progress = 0;
            GlobalExtension.ShowProgress("Writing zData ...");

            // Write zData
            foreach (Entry entry in _toc)
            {
                // skip NamesBlock.bin
                //if (current.Name == "NamesBlock.bin")
                //    continue;

                //try
                //{
                // use chunk write method to avoid OOM Exceptions
                var z   = zStreams[entry];
                var len = z.Length;
                if (len > _header.BlockSizeAlloc)
                {
                    using (var msInput = new MemoryStreamExtension(z))
                        using (var msExt = new MemoryStreamExtension())
                            using (var _writer2 = new BigEndianBinaryWriter(msExt))
                            {
                                int bytesRead;
                                int totalBytesRead = 0;
                                var buffer         = new byte[_header.BlockSizeAlloc];
                                while ((bytesRead = msInput.Read(buffer, 0, buffer.Length)) > 0)
                                {
                                    totalBytesRead += bytesRead;
                                    if (totalBytesRead > len)
                                    {
                                        bytesRead = len - (totalBytesRead - bytesRead);
                                    }

                                    using (var msOutput = new MemoryStreamExtension())
                                    {
                                        msOutput.Write(buffer, 0, bytesRead);
                                        _writer2.Write(msOutput.ToArray());
                                    }
                                }

                                _writer.Write(msExt.ToArray());
                            }
                }
                else
                {
                    _writer.Write(zStreams[entry]);
                }

                if (entry.Data != null)
                {
                    entry.Data.Close();
                }
                //}
                //catch (Exception ex)
                //{
                //    Console.WriteLine("<ERROR> _writer.Write: " + ex.Message);
                //    _writer.Flush();
                //    _writer.Dispose();
                //    break;
                //}

                progress += step;
                GlobalExtension.UpdateProgress.Value = (int)progress;
                Console.WriteLine("Writing zData: " + entry.Id);
            }

            zStreams = null;

            if (encrypt) // Encrypt TOC
            {
                using (var outputStream = new MemoryStreamExtension())
                    using (var encStream = new MemoryStreamExtension())
                    {
                        inputStream.Position = 32L;
                        RijndaelEncryptor.EncryptPSARC(inputStream, outputStream, _header.TotalTOCSize);
                        inputStream.Position = 0L;

                        // quick copy header from input stream
                        var buffer = new byte[32];
                        encStream.Write(buffer, 0, inputStream.Read(buffer, 0, buffer.Length));
                        encStream.Position = 32; //sanity check ofc
                        inputStream.Flush();

                        int tocSize = (int)_header.TotalTOCSize - 32;
                        int decSize = 0;
                        buffer = new byte[1024 * 16]; // more efficient use of memory

                        var ndx = 0;                  // for debugging
                        step     = Math.Round(1D / (((double)tocSize / buffer.Length) + 2) * 100, 3);
                        progress = 0;
                        GlobalExtension.ShowProgress("Writing encryptedData ...");

                        int bytesRead;
                        while ((bytesRead = outputStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            decSize += bytesRead;
                            if (decSize > tocSize)
                            {
                                bytesRead = tocSize - (decSize - bytesRead);
                            }

                            encStream.Write(buffer, 0, bytesRead);

                            progress += step;
                            GlobalExtension.UpdateProgress.Value = (int)progress;
                            Console.WriteLine("Writing encryptedData: " + ndx++);
                        }

                        inputStream.Position = 0;
                        encStream.Position   = 0;
                        encStream.CopyTo(inputStream, (int)_header.BlockSizeAlloc);
                    }
            }

            if (seek)
            {
                inputStream.Flush();
                inputStream.Seek(0, SeekOrigin.Begin);
            }

            //GlobalExtension.HideProgress();
        }