private void loadHeader(MemoryStream stream) { uint tag = stream.ReadUInt32(); if (tag != SfarTag) { throw new Exception("Wrong SFAR tag"); } uint sfarVersion = stream.ReadUInt32(); if (sfarVersion != SfarVersion) { throw new Exception("Wrong SFAR version"); } uint dataOffset = stream.ReadUInt32(); uint entriesOffset = stream.ReadUInt32(); filesCount = stream.ReadUInt32(); uint sizesArrayOffset = stream.ReadUInt32(); maxBlockSize = stream.ReadUInt32(); uint compressionTag = stream.ReadUInt32(); if (compressionTag != LZMATag) { throw new Exception("Not LZMA compression for SFAR file"); } uint numBlockSizes = 0; stream.JumpTo(entriesOffset); filesList = new List <FileEntry>(); for (int i = 0; i < filesCount; i++) { FileEntry file = new FileEntry(); file.filenameHash = stream.ReadToBuffer(16); file.compressedBlockSizesIndex = stream.ReadInt32(); file.uncomprSize = stream.ReadUInt32(); file.uncomprSize |= (long)stream.ReadByte() << 32; file.dataOffset = stream.ReadUInt32(); file.dataOffset |= (long)stream.ReadByte() << 32; file.numBlocks = (uint)((file.uncomprSize + maxBlockSize - 1) / maxBlockSize); filesList.Add(file); numBlockSizes += file.numBlocks; } stream.JumpTo(sizesArrayOffset); blockSizes = new List <ushort>(); for (int i = 0; i < numBlockSizes; i++) { blockSizes.Add(stream.ReadUInt16()); } filenamesIndex = -1; for (int i = 0; i < filesCount; i++) { if (StructuralComparisons.StructuralEqualityComparer.Equals(filesList[i].filenameHash, FileListHash)) { stream.JumpTo(filesList[i].dataOffset); int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex]; byte[] inBuf = stream.ReadToBuffer(compressedBlockSize); byte[] outBuf = new SevenZipHelper.LZMA().Decompress(inBuf, (uint)filesList[i].uncomprSize); if (outBuf.Length == 0) { throw new Exception(); } StreamReader filenamesStream = new StreamReader(new MemoryStream(outBuf)); while (filenamesStream.EndOfStream == false) { string name = filenamesStream.ReadLine(); byte[] hash = MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(name.ToLowerInvariant())); for (int l = 0; l < filesCount; l++) { if (StructuralComparisons.StructuralEqualityComparer.Equals(filesList[l].filenameHash, hash)) { FileEntry f = filesList[l]; f.filenamePath = name; filesList[l] = f; } } } filenamesIndex = i; break; } } if (filenamesIndex == -1) { throw new Exception("filenames entry not found"); } }
public void extract(string SFARfilename, string outPath) { loadHeader(SFARfilename); Directory.CreateDirectory(Path.Combine(outPath, "CookedPCConsole")); using (FileStream outputFile = new FileStream(Path.Combine(outPath, "CookedPCConsole", "Default.sfar"), FileMode.Create, FileAccess.Write)) { outputFile.WriteUInt32(SfarTag); outputFile.WriteUInt32(SfarVersion); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)filesList.Count); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)MaxBlockSize); outputFile.WriteUInt32(LZMATag); } for (int i = 0; i < filesCount; i++) { if (filenamesIndex == i) { continue; } if (filesList[i].filenamePath == null) { throw new Exception("filename missing"); } if (mainWindow != null) { mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + filesList.Count() + " - " + Path.GetFileName(filesList[i].filenamePath)); } int pos = filesList[i].filenamePath.IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase); string filename = filesList[i].filenamePath.Substring(pos + ("\\BIOGame\\DLC\\").Length).Replace('/', '\\'); string dir = Path.GetDirectoryName(outPath); Directory.CreateDirectory(Path.GetDirectoryName(dir + filename)); using (FileStream outputFile = new FileStream(dir + filename, FileMode.Create, FileAccess.Write)) { sfarFile.JumpTo(filesList[i].dataOffset); if (filesList[i].compressedBlockSizesIndex == -1) { outputFile.WriteFromStream(sfarFile, filesList[i].uncomprSize); } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); List <long> blockBytesLeft = new List <long>(); long bytesLeft = filesList[i].uncomprSize; for (int j = 0; j < filesList[i].numBlocks; j++) { blockBytesLeft.Add(bytesLeft); int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + j]; int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize); if (compressedBlockSize == 0) { compressedBlockSize = (int)maxBlockSize; } compressedBlockBuffers.Add(sfarFile.ReadToBuffer(compressedBlockSize)); uncompressedBlockBuffers.Add(null); bytesLeft -= uncompressedBlockSize; } Parallel.For(0, filesList[i].numBlocks, j => { int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + (int)j]; int uncompressedBlockSize = (int)Math.Min(blockBytesLeft[(int)j], maxBlockSize); if (compressedBlockSize == 0 || compressedBlockSize == blockBytesLeft[(int)j]) { uncompressedBlockBuffers[(int)j] = compressedBlockBuffers[(int)j]; } else { uncompressedBlockBuffers[(int)j] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize); if (uncompressedBlockBuffers[(int)j].Length == 0) { throw new Exception(); } } }); for (int j = 0; j < filesList[i].numBlocks; j++) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]); } } } } sfarFile.Close(); sfarFile.Dispose(); sfarFile = null; }
public void extract(string SFARfilename, string outPath, bool ipc, ref int currentProgress, int totalNumber) { if (!File.Exists(SFARfilename)) { throw new Exception("filename missing"); } byte[] buffer = File.ReadAllBytes(SFARfilename); File.Delete(SFARfilename); using (FileStream outputFile = new FileStream(SFARfilename, FileMode.Create, FileAccess.Write)) { outputFile.WriteUInt32(SfarTag); outputFile.WriteUInt32(SfarVersion); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32(0); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)MaxBlockSize); outputFile.WriteUInt32(LZMATag); } using (MemoryStream stream = new MemoryStream(buffer)) { loadHeader(stream); int lastProgress = -1; for (int i = 0; i < filesCount; i++, currentProgress++) { if (filenamesIndex == i) { continue; } if (filesList[i].filenamePath == null) { throw new Exception("filename missing"); } if (ipc) { int newProgress = (100 * currentProgress) / totalNumber; if (lastProgress != newProgress) { Console.WriteLine("[IPC]TASK_PROGRESS " + newProgress); Console.Out.Flush(); lastProgress = newProgress; } } int pos = filesList[i].filenamePath.IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase); string filename = filesList[i].filenamePath.Substring(pos + ("\\BIOGame\\DLC\\").Length).Replace('/', '\\'); string dir = Path.GetDirectoryName(outPath); Directory.CreateDirectory(Path.GetDirectoryName(dir + filename)); using (FileStream outputFile = new FileStream(dir + filename, FileMode.Create, FileAccess.Write)) { stream.JumpTo(filesList[i].dataOffset); if (filesList[i].compressedBlockSizesIndex == -1) { outputFile.WriteFromStream(stream, filesList[i].uncomprSize); } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); List <long> blockBytesLeft = new List <long>(); long bytesLeft = filesList[i].uncomprSize; for (int j = 0; j < filesList[i].numBlocks; j++) { blockBytesLeft.Add(bytesLeft); int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + j]; int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize); if (compressedBlockSize == 0) { compressedBlockSize = (int)maxBlockSize; } compressedBlockBuffers.Add(stream.ReadToBuffer(compressedBlockSize)); uncompressedBlockBuffers.Add(null); bytesLeft -= uncompressedBlockSize; } Parallel.For(0, filesList[i].numBlocks, j => { int compressedBlockSize = blockSizes[filesList[i].compressedBlockSizesIndex + (int)j]; int uncompressedBlockSize = (int)Math.Min(blockBytesLeft[(int)j], maxBlockSize); if (compressedBlockSize == 0 || compressedBlockSize == blockBytesLeft[(int)j]) { uncompressedBlockBuffers[(int)j] = compressedBlockBuffers[(int)j]; } else { uncompressedBlockBuffers[(int)j] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize); if (uncompressedBlockBuffers[(int)j].Length == 0) { throw new Exception(); } } }); for (int j = 0; j < filesList[i].numBlocks; j++) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]); } } } } } }
public byte[] unpackFileEntry(string filename) { if (sfarFile == null) { throw new Exception(); } string name = filename.Replace('\\', '/'); byte[] fileHash = MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(name.ToLowerInvariant())); int index = filesList.FindIndex(s => StructuralComparisons.StructuralEqualityComparer.Equals(s.filenameHash, fileHash)); if (index == -1) { throw new Exception(); } using (MemoryStream outputFile = new MemoryStream()) { sfarFile.JumpTo(filesList[index].dataOffset); if (filesList[index].compressedBlockSizesIndex == -1) { outputFile.WriteFromStream(sfarFile, filesList[index].uncomprSize); } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); List <long> blockBytesLeft = new List <long>(); long bytesLeft = filesList[index].uncomprSize; for (int j = 0; j < filesList[index].numBlocks; j++) { blockBytesLeft.Add(bytesLeft); int compressedBlockSize = blockSizes[filesList[index].compressedBlockSizesIndex + j]; int uncompressedBlockSize = (int)Math.Min(bytesLeft, maxBlockSize); if (compressedBlockSize == 0) { compressedBlockSize = (int)maxBlockSize; } compressedBlockBuffers.Add(sfarFile.ReadToBuffer(compressedBlockSize)); uncompressedBlockBuffers.Add(null); bytesLeft -= uncompressedBlockSize; } Parallel.For(0, filesList[index].numBlocks, j => { int compressedBlockSize = blockSizes[filesList[index].compressedBlockSizesIndex + (int)j]; int uncompressedBlockSize = (int)Math.Min(blockBytesLeft[(int)j], maxBlockSize); if (compressedBlockSize == 0 || compressedBlockSize == blockBytesLeft[(int)j]) { uncompressedBlockBuffers[(int)j] = compressedBlockBuffers[(int)j]; } else { uncompressedBlockBuffers[(int)j] = new SevenZipHelper.LZMA().Decompress(compressedBlockBuffers[(int)j], (uint)uncompressedBlockSize); if (uncompressedBlockBuffers[(int)j].Length == 0) { throw new Exception(); } } }); for (int j = 0; j < filesList[index].numBlocks; j++) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[j]); } } return(outputFile.ToArray()); } }