public void Write(Stream inputStream, bool encrypt = false, bool seek = true)
        {
            _header.ArchiveFlags = encrypt ? 4U : 0U;
            _header.TOCEntrySize = 30U;
            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);
            //Write Table of contents
            foreach (Entry current in _toc)
            {
                current.UpdateNameMD5();
                _writer.Write(current.MD5);
                _writer.Write(current.zIndexBegin);
                _writer.WriteUInt40((ulong)current.Data.Length);//current.Length
                _writer.WriteUInt40(current.Offset);
            }
            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;

            // Write zData
            var ndx = 0; // for debugging
            var step = Math.Round(1D / (this.TOC.Count + 2) * 100, 3);
            double progress = 0;
            GlobalExtension.ShowProgress("Writing Zipped Data ...");

            foreach (Entry current in _toc)
            {
                _writer.Write(zStreams[current]);
                progress += step;
                GlobalExtension.UpdateProgress.Value = (int)progress;
                Debug.WriteLine("Zipped: " + ndx++);
                current.Data.Close();
            }
            zStreams = null;

            if (encrypt) // Encrypt TOC
            {
                using (var outputStream = new MemoryStreamExtension())
                {
                    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; //sainty check ofc
                    inputStream.Flush();

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

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

                    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;
                        Debug.WriteLine("Encrypted: " + ndx++);
                    }

                    inputStream.Position = 0;
                    encStream.Position = 0;
                    encStream.CopyTo(inputStream, (int)_header.BlockSizeAlloc);
                }
            }
            if (seek) // May be redundant
            {
                inputStream.Flush();
                inputStream.Position = 0;
            }
            GlobalExtension.HideProgress();
        }
        public void Write(Stream inputStream, bool encrypt = false, bool seek = true)
        {
            _header.ArchiveFlags = encrypt ? 4U : 0U;
            _header.TOCEntrySize = 30U;
            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);
            //Write Table of contents
            foreach (Entry current in _toc)
            {
                current.UpdateNameMD5();
                _writer.Write(current.MD5);
                _writer.Write(current.zIndexBegin);
                _writer.WriteUInt40((ulong)current.Data.Length);//current.Length
                _writer.WriteUInt40(current.Offset);
            }
            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;

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

            GlobalExtension.ShowProgress("Writing Zipped Data ...");

            foreach (Entry current in _toc)
            {
                _writer.Write(zStreams[current]);
                progress += step;
                GlobalExtension.UpdateProgress.Value = (int)progress;
                Console.WriteLine("Zipped: " + ndx++);
                current.Data.Close();
            }
            zStreams = null;

            if (encrypt) // Encrypt TOC
            {
                using (var outputStream = new MemoryStreamExtension())
                {
                    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

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

                    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("Encrypted: " + ndx++);
                    }

                    inputStream.Position = 0;
                    encStream.Position   = 0;
                    encStream.CopyTo(inputStream, (int)_header.BlockSizeAlloc);
                }
            }
            if (seek) // May be redundant
            {
                inputStream.Flush();
                inputStream.Position = 0;
            }
            //GlobalExtension.HideProgress();
        }
Beispiel #3
0
        public void Write(Stream psarc, bool encrypt)
        {
            this.header.archiveFlags = encrypt ? 4U : 0U;
            this.header.TOCEntrySize = 30;
            this.WriteManifest();
            //Pack entries
            Dictionary <Entry, byte[]> zStreams; List <uint> zLengths;

            DeflateEntries(out zStreams, out zLengths);
            //Build zLengths
            _writer = new BigEndianBinaryWriter(psarc);
            this.header.TotalTOCSize = (uint)(32 + this.TOC.Count * this.header.TOCEntrySize + zLengths.Count * bNum);
            this.TOC[0].Offset       = (ulong)this.header.TotalTOCSize;
            for (int i = 1; i < this.TOC.Count; i++)
            {
                this.TOC[i].Offset = this.TOC[i - 1].Offset + (ulong)(zStreams[this.TOC[i - 1]].Length);
            }
            //Write Header
            _writer.Write(this.header.MagicNumber);
            _writer.Write(this.header.VersionNumber);
            _writer.Write(this.header.CompressionMethod);
            _writer.Write(this.header.TotalTOCSize);
            _writer.Write(this.header.TOCEntrySize);
            _writer.Write(this.TOC.Count);
            _writer.Write(this.header.blockSizeAlloc);
            _writer.Write(this.header.archiveFlags);
            //Write Table of contents
            foreach (Entry current in this.TOC)
            {
                current.UpdateNameMD5();
                _writer.Write((current.Id == 0) ? new byte[16] : current.MD5);
                _writer.Write(current.zIndexBegin);
                _writer.WriteUInt40((ulong)current.Data.Length);
                _writer.WriteUInt40(current.Offset);
            }
            foreach (uint zLen in zLengths)
            {
                switch (bNum)
                {
                case 2:
                    _writer.Write((ushort)zLen);
                    break;

                case 3:
                    _writer.WriteUInt24(zLen);
                    break;

                case 4:
                    _writer.Write(zLen);
                    break;
                }
            }
            //Write zData
            foreach (Entry current in this.TOC)
            {
                _writer.Write(zStreams[current]);
                current.Data.Close();
            }
            if (encrypt)
            {// Encrypt TOC
                var encStream = new MemoryStreamExtension();
                using (var outputStream = new MemoryStreamExtension())
                {
                    int bytesRead;
                    int decSize = 0;
                    var buffer  = new byte[30000];
                    int tocSize = (int)this.header.TotalTOCSize - 32;

                    psarc.Seek(32, SeekOrigin.Begin);
                    RijndaelEncryptor.EncryptPSARC(psarc, outputStream, this.header.TotalTOCSize);

                    psarc.Seek(0, SeekOrigin.Begin);
                    while ((bytesRead = psarc.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        encStream.Write(buffer, 0, bytesRead);
                    }

                    outputStream.Seek(0, SeekOrigin.Begin);
                    encStream.Seek(32, SeekOrigin.Begin);
                    while ((bytesRead = outputStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        decSize += bytesRead;
                        if (decSize > tocSize)
                        {
                            bytesRead = tocSize - (decSize - bytesRead);
                        }
                        encStream.Write(buffer, 0, bytesRead);
                    }
                }

                psarc.Seek(0, SeekOrigin.Begin);
                encStream.Seek(0, SeekOrigin.Begin);
                encStream.CopyTo(psarc, (int)this.header.blockSizeAlloc);
            }
            psarc.Flush();
        }
Beispiel #4
0
        public void Write(Stream str, bool encrypt)
        {
            if (encrypt)
            {
                this.header.archiveFlags = 4;
            }
            this.header.TOCEntrySize = 30;
            this.UpdateManifest();
            Dictionary <Entry, byte[]> dictionary;
            List <uint> list;

            this.deflateEntries(out dictionary, out list, this.header.blockSize);
            byte b   = 1;
            uint num = 256;

            do
            {
                num *= 256;
                b   += 1;
            }while (num < this.header.blockSize);
            BigEndianBinaryWriter bigEndianBinaryWriter = new BigEndianBinaryWriter(str);

            this.header.TotalTOCSize = (uint)(32 + this.header.TOCEntrySize * (this.Entries.Count) + ((int)b * list.Count));
            this.Entries[0].Offset   = (ulong)this.header.TotalTOCSize;
            for (int i = 1; i < this.Entries.Count; i++)
            {
                this.Entries[i].Offset = this.Entries[i - 1].Offset + (ulong)(dictionary[this.Entries[i - 1]].Length);
            }
            bigEndianBinaryWriter.Write(this.header.MagicNumber);
            bigEndianBinaryWriter.Write(this.header.VersionNumber);
            bigEndianBinaryWriter.Write(this.header.CompressionMethod);
            bigEndianBinaryWriter.Write(this.header.TotalTOCSize);
            bigEndianBinaryWriter.Write(this.header.TOCEntrySize);
            bigEndianBinaryWriter.Write(this.Entries.Count);
            bigEndianBinaryWriter.Write(this.header.blockSize);
            bigEndianBinaryWriter.Write(this.header.archiveFlags);
            foreach (Entry current in this.Entries)
            {
                current.UpdateNameMD5();
                bigEndianBinaryWriter.Write((current.id == 0) ? new byte[16] : current.MD5);
                bigEndianBinaryWriter.Write(current.zIndex);
                bigEndianBinaryWriter.WriteUInt40((ulong)current.Data.Length);
                bigEndianBinaryWriter.WriteUInt40(current.Offset);
            }
            foreach (uint current2 in list)
            {
                switch (b)
                {
                case 2:
                    bigEndianBinaryWriter.Write((ushort)current2);
                    break;

                case 3:
                    bigEndianBinaryWriter.WriteUInt24(current2);
                    break;

                case 4:
                    bigEndianBinaryWriter.Write(current2);
                    break;
                }
            }
            foreach (Entry current in this.Entries)
            {
                bigEndianBinaryWriter.Write(dictionary[current]);
            }

            if (encrypt)
            {
                var encStream = new MemoryStreamExtension();
                using (var outputStream = new MemoryStreamExtension())
                {
                    str.Seek(32, SeekOrigin.Begin);
                    RijndaelEncryptor.EncryptPSARC(str, outputStream, this.header.TotalTOCSize);

                    int    bytesRead;
                    byte[] buffer = new byte[30000];

                    str.Seek(0, SeekOrigin.Begin);
                    while ((bytesRead = str.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        encStream.Write(buffer, 0, bytesRead);
                    }
                    int decMax  = (int)this.header.TotalTOCSize - 32;
                    int decSize = 0;
                    outputStream.Seek(0, SeekOrigin.Begin);
                    encStream.Seek(32, SeekOrigin.Begin);
                    while ((bytesRead = outputStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        decSize += bytesRead;
                        if (decSize > decMax)
                        {
                            bytesRead = decMax - (decSize - bytesRead);
                        }
                        encStream.Write(buffer, 0, bytesRead);
                    }
                }

                str.Seek(0, SeekOrigin.Begin);
                encStream.Seek(0, SeekOrigin.Begin);
                encStream.CopyTo(str);
            }

            str.Flush();
        }
        public void Write(Stream str, bool encrypt)
        {
            if (encrypt)
                this.header.archiveFlags = 4;
            this.header.TOCEntrySize = 30;
            this.UpdateManifest();
            Dictionary<Entry, byte[]> dictionary;
            List<uint> list;
            this.deflateEntries(out dictionary, out list, this.header.blockSize);
            byte b = 1;
            uint num = 256;
            do
            {
                num *= 256;
                b += 1;
            }
            while (num < this.header.blockSize);
            BigEndianBinaryWriter bigEndianBinaryWriter = new BigEndianBinaryWriter(str);
            this.header.TotalTOCSize = (uint)(32 + this.header.TOCEntrySize * (this.Entries.Count) + ((int)b * list.Count));
            this.Entries[0].Offset = (ulong)this.header.TotalTOCSize;
            for (int i = 1; i < this.Entries.Count; i++)
            {
                this.Entries[i].Offset = this.Entries[i - 1].Offset + (ulong)(dictionary[this.Entries[i - 1]].Length);
            }
            bigEndianBinaryWriter.Write(this.header.MagicNumber);
            bigEndianBinaryWriter.Write(this.header.VersionNumber);
            bigEndianBinaryWriter.Write(this.header.CompressionMethod);
            bigEndianBinaryWriter.Write(this.header.TotalTOCSize);
            bigEndianBinaryWriter.Write(this.header.TOCEntrySize);
            bigEndianBinaryWriter.Write(this.Entries.Count);
            bigEndianBinaryWriter.Write(this.header.blockSize);
            bigEndianBinaryWriter.Write(this.header.archiveFlags);
            foreach (Entry current in this.Entries)
            {
                current.UpdateNameMD5();
                bigEndianBinaryWriter.Write((current.id == 0) ? new byte[16] : current.MD5);
                bigEndianBinaryWriter.Write(current.zIndex);
                bigEndianBinaryWriter.WriteUInt40((ulong)current.Data.Length);
                bigEndianBinaryWriter.WriteUInt40(current.Offset);
            }
            foreach (uint current2 in list)
            {
                switch (b)
                {
                    case 2:
                        bigEndianBinaryWriter.Write((ushort)current2);
                        break;
                    case 3:
                        bigEndianBinaryWriter.WriteUInt24(current2);
                        break;
                    case 4:
                        bigEndianBinaryWriter.Write(current2);
                        break;
                }
            }
            foreach (Entry current in this.Entries)
            {
                bigEndianBinaryWriter.Write(dictionary[current]);
            }

            if (encrypt)
            {
                var encStream = new MemoryStreamExtension();
                using (var outputStream = new MemoryStreamExtension())
                {
                    str.Seek(32, SeekOrigin.Begin);
                    RijndaelEncryptor.EncryptPSARC(str, outputStream, this.header.TotalTOCSize);

                    int bytesRead;
                    byte[] buffer = new byte[30000];

                    str.Seek(0, SeekOrigin.Begin);
                    while ((bytesRead = str.Read(buffer, 0, buffer.Length)) > 0)
                        encStream.Write(buffer, 0, bytesRead);
                    int decMax = (int)this.header.TotalTOCSize - 32;
                    int decSize = 0;
                    outputStream.Seek(0, SeekOrigin.Begin);
                    encStream.Seek(32, SeekOrigin.Begin);
                    while ((bytesRead = outputStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        decSize += bytesRead;
                        if (decSize > decMax) bytesRead = decMax - (decSize - bytesRead);
                        encStream.Write(buffer, 0, bytesRead);
                    }
                }

                str.Seek(0, SeekOrigin.Begin);
                encStream.Seek(0, SeekOrigin.Begin);
                encStream.CopyTo(str);
            }

            str.Flush();
        }
        /// <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();
        }
        public void Write(Stream inputStream, bool encrypt)
        {
            // TODO: This produces perfect results for song archives (original vs repacked)
            // there are slight differences in the binary of large archives (original vs repacked).  WHY?
            //
            this.header.archiveFlags = encrypt ? 4U : 0U;
            this.header.TOCEntrySize = 30;
            this.WriteManifest();
            //Pack entries
            Dictionary <Entry, byte[]> zStreams; List <uint> zLengths;

            DeflateEntries(out zStreams, out zLengths);
            //Build zLengths
            _writer = new BigEndianBinaryWriter(inputStream);
            this.header.TotalTOCSize = (uint)(32 + this.TOC.Count * this.header.TOCEntrySize + zLengths.Count * bNum);
            this.TOC[0].Offset       = (ulong)this.header.TotalTOCSize;
            for (int i = 1; i < this.TOC.Count; i++)
            {
                this.TOC[i].Offset = this.TOC[i - 1].Offset + (ulong)(zStreams[this.TOC[i - 1]].Length);
            }
            //Write Header
            _writer.Write(this.header.MagicNumber);
            _writer.Write(this.header.VersionNumber);
            _writer.Write(this.header.CompressionMethod);
            _writer.Write(this.header.TotalTOCSize);
            _writer.Write(this.header.TOCEntrySize);
            _writer.Write(this.TOC.Count);
            _writer.Write(this.header.blockSizeAlloc);
            _writer.Write(this.header.archiveFlags);
            //Write Table of contents
            foreach (Entry current in this.TOC)
            {
                current.UpdateNameMD5();
                _writer.Write((current.Id == 0) ? new byte[16] : current.MD5);
                _writer.Write(current.zIndexBegin);
                _writer.WriteUInt40((ulong)current.Data.Length);
                _writer.WriteUInt40(current.Offset);
            }
            foreach (uint zLen in zLengths)
            {
                switch (bNum)
                {
                case 2:
                    _writer.Write((ushort)zLen);
                    break;

                case 3:
                    _writer.WriteUInt24(zLen);
                    break;

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

            // Write zData
            var    ndx      = 0; // for debugging
            var    step     = Math.Round(1.0 / (this.TOC.Count + 2) * 100, 3);
            double progress = 0;

            GlobalExtension.ShowProgress("Writing Zipped Data ...");

            foreach (Entry current in this.TOC)
            {
                _writer.Write(zStreams[current]);
                progress += step;
                GlobalExtension.UpdateProgress.Value = (int)progress;
                Debug.WriteLine("Zipped: " + ndx++);
                current.Data.Close();
            }

            if (encrypt) // Encrypt TOC
            {
                using (var outputStream = new MemoryStreamExtension())
                {
                    var encStream = new MemoryStreamExtension();
                    inputStream.Seek(32, SeekOrigin.Begin);
                    RijndaelEncryptor.EncryptPSARC(inputStream, outputStream, this.header.TotalTOCSize);
                    inputStream.Seek(0, SeekOrigin.Begin);

                    int bytesRead;
                    var buffer = new byte[32];
                    bytesRead = inputStream.Read(buffer, 0, buffer.Length);
                    inputStream.Flush();
                    // quick copy header from input stream
                    encStream.Write(buffer, 0, bytesRead);
                    encStream.Seek(32, SeekOrigin.Begin);

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

                    ndx      = 0;                 // for debuging
                    step     = Math.Round(1.0 / ((tocSize / buffer.Length) + 2) * 100, 3);
                    progress = 0;
                    GlobalExtension.ShowProgress("Writing Encrypted Data ...");

                    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;
                        Debug.WriteLine("Encrypted: " + ndx++);
                    }

                    inputStream.Seek(0, SeekOrigin.Begin);
                    encStream.Seek(0, SeekOrigin.Begin);
                    encStream.CopyTo(inputStream, (int)this.header.blockSizeAlloc);
                }
            }

            inputStream.Flush();
            GlobalExtension.HideProgress();
        }