private static void Pack2014(string sourcePath, string saveFileName, Platform platform, bool updateSng, bool updateManifest, bool fixShowlights = true) { using (var psarc = new PSARC.PSARC()) using (var psarcStream = new MemoryStreamExtension()) { if (updateSng) { UpdateSng2014(sourcePath, platform, fixShowlights: fixShowlights); } if (updateManifest) { UpdateManifest2014(sourcePath, platform); } WalkThroughDirectory("", sourcePath, (a, b) => { var fileStream = File.OpenRead(b); psarc.AddEntry(a, fileStream); }); psarc.Write(psarcStream, !platform.IsConsole); if (Path.GetExtension(saveFileName) != ".psarc") { saveFileName += ".psarc"; } using (var outputFileStream = File.Create(saveFileName)) psarcStream.CopyTo(outputFileStream); } }
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(); }
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(); }
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(); }