public void fullRePack(string inPath, string outPath, string DLCName, MainWindow mainWindow, Installer installer) { if (sfarFile != null) { throw new Exception(); } if (!Directory.Exists(inPath)) { throw new Exception("Directory not found: " + inPath); } List <byte[]> hashList = new List <byte[]>(); List <string> srcFilesList = Directory.GetFiles(inPath, "*.*", SearchOption.AllDirectories).ToList(); srcFilesList.RemoveAll(s => s.ToLowerInvariant().Contains("default.sfar")); using (FileStream outputFile = new FileStream(inPath + @"\TOC", FileMode.Create, FileAccess.Write)) { for (int i = 0; i < srcFilesList.Count(); i++) { int pos = srcFilesList[i].IndexOf("\\BIOGame\\DLC\\", StringComparison.OrdinalIgnoreCase); string filename = srcFilesList[i].Substring(pos).Replace('\\', '/'); hashList.Add(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(filename.ToLowerInvariant()))); outputFile.WriteStringASCII(filename + Environment.NewLine); } } hashList.Add(FileListHash); srcFilesList.Add(inPath + @"\TOC"); Directory.CreateDirectory(Path.GetDirectoryName(outPath)); using (FileStream outputFile = new FileStream(outPath, FileMode.Create, FileAccess.Write)) { long numBlockSizes = 0; int curBlockSizesIndex = 0; long dataOffset = HeaderSize + EntryHeaderSize * (srcFilesList.Count()); long sizesArrayOffset = dataOffset; for (int i = 0; i < srcFilesList.Count(); i++) { if (srcFilesList[i].EndsWith(".bik", StringComparison.OrdinalIgnoreCase) || srcFilesList[i].EndsWith(".afc", StringComparison.OrdinalIgnoreCase)) { continue; } long fileLen = new FileInfo(srcFilesList[i]).Length; long numBlocks = (fileLen + MaxBlockSize - 1) / MaxBlockSize; dataOffset += numBlocks * sizeof(ushort); numBlockSizes += numBlocks; } List <FileEntry> filesList = new List <FileEntry>(); ushort[] blockSizes = new ushort[numBlockSizes]; long curDataOffset = dataOffset; outputFile.JumpTo(dataOffset); for (int i = 0; i < srcFilesList.Count(); i++) { if (mainWindow != null) { mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + srcFilesList.Count() + " - " + Path.GetFileName(srcFilesList[i])); } if (installer != null) { installer.updateStatusPrepare("Compressing DLC... " + (i + 1) + " of " + srcFilesList.Count); } FileEntry file = new FileEntry(); Stream inputFile = new FileStream(srcFilesList[i], FileMode.Open, FileAccess.Read); long fileLen = new FileInfo(srcFilesList[i]).Length; file.dataOffset = curDataOffset; file.uncomprSize = fileLen; file.filenameHash = hashList[i]; if (srcFilesList[i].EndsWith(".bik", StringComparison.OrdinalIgnoreCase) || srcFilesList[i].EndsWith(".afc", StringComparison.OrdinalIgnoreCase)) { outputFile.WriteFromStream(inputFile, fileLen); file.compressedBlockSizesIndex = -1; } else { List <byte[]> uncompressedBlockBuffers = new List <byte[]>(); List <byte[]> compressedBlockBuffers = new List <byte[]>(); file.compressedBlockSizesIndex = curBlockSizesIndex; file.numBlocks = (uint)((file.uncomprSize + MaxBlockSize - 1) / MaxBlockSize); for (int k = 0; k < file.numBlocks; k++) { long uncompressedBlockSize = MaxBlockSize; if (k == (file.numBlocks - 1)) // last block { uncompressedBlockSize = file.uncomprSize - (MaxBlockSize * k); } uncompressedBlockBuffers.Add(inputFile.ReadToBuffer((int)uncompressedBlockSize)); compressedBlockBuffers.Add(null); } Parallel.For(0, file.numBlocks, k => { compressedBlockBuffers[(int)k] = SevenZipHelper.LZMA.Compress(uncompressedBlockBuffers[(int)k], 9); if (compressedBlockBuffers[(int)k].Length == 0) { throw new Exception(); } }); for (int k = 0; k < file.numBlocks; k++, curBlockSizesIndex++) { if (compressedBlockBuffers[k].Length >= (int)MaxBlockSize) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[k]); blockSizes[curBlockSizesIndex] = 0; } else if (compressedBlockBuffers[k].Length >= uncompressedBlockBuffers[k].Length) { outputFile.WriteFromBuffer(uncompressedBlockBuffers[k]); blockSizes[curBlockSizesIndex] = (ushort)uncompressedBlockBuffers[k].Length; } else { outputFile.WriteFromBuffer(compressedBlockBuffers[k]); blockSizes[curBlockSizesIndex] = (ushort)compressedBlockBuffers[k].Length; } } } curDataOffset = outputFile.Position; filesList.Add(file); inputFile.Close(); } if (blockSizes.Count() != curBlockSizesIndex) { throw new Exception(); } outputFile.SeekBegin(); outputFile.WriteUInt32(SfarTag); outputFile.WriteUInt32(SfarVersion); outputFile.WriteUInt32((uint)dataOffset); outputFile.WriteUInt32(HeaderSize); outputFile.WriteUInt32((uint)filesList.Count); outputFile.WriteUInt32((uint)sizesArrayOffset); outputFile.WriteUInt32((uint)MaxBlockSize); outputFile.WriteUInt32(LZMATag); filesList.Sort(new FileArrayComparer()); for (int i = 0; i < filesList.Count; i++) { outputFile.WriteFromBuffer(filesList[i].filenameHash); outputFile.WriteInt32(filesList[i].compressedBlockSizesIndex); outputFile.WriteUInt32((uint)filesList[i].uncomprSize); outputFile.WriteByte((byte)(filesList[i].uncomprSize >> 32)); outputFile.WriteUInt32((uint)filesList[i].dataOffset); outputFile.WriteByte((byte)(filesList[i].dataOffset >> 32)); } if (outputFile.Position != sizesArrayOffset) { throw new Exception(); } for (int i = 0; i < blockSizes.Count(); i++) { outputFile.WriteUInt16(blockSizes[i]); } if (outputFile.Position != dataOffset) { throw new Exception(); } } File.Delete(inPath + @"\TOC"); }
static public void unpackAllDLC(MainWindow mainWindow, Installer installer) { if (!Directory.Exists(GameData.DLCData)) { if (mainWindow != null) { MessageBox.Show("No DLCs need to be extracted."); } return; } List <string> sfarFiles = Directory.GetFiles(GameData.DLCData, "Default.sfar", SearchOption.AllDirectories).ToList(); for (int i = 0; i < sfarFiles.Count; i++) { if (File.Exists(Path.Combine(Path.GetDirectoryName(sfarFiles[i]), "Mount.dlc"))) { sfarFiles.RemoveAt(i--); } } if (sfarFiles.Count() == 0) { if (mainWindow != null) { MessageBox.Show("No DLCs need to be extracted."); } return; } long diskFreeSpace = Misc.getDiskFreeSpace(GameData.GamePath); long diskUsage = 0; for (int i = 0; i < sfarFiles.Count; i++) { diskUsage += new FileInfo(sfarFiles[i]).Length; } diskUsage = (long)(diskUsage * 2.5); if (diskUsage > diskFreeSpace) { if (mainWindow != null) { MessageBox.Show("You have not enough disk space remaining. You need about " + Misc.getBytesFormat(diskUsage) + " free."); } return; } string tmpDlcDir = Path.Combine(GameData.GamePath, "BIOGame", "DLCTemp"); if (Directory.Exists(tmpDlcDir)) { Directory.Delete(tmpDlcDir, true); } Directory.CreateDirectory(tmpDlcDir); string originInstallFiles = Path.Combine(GameData.DLCData, "__metadata"); if (Directory.Exists(originInstallFiles)) { Directory.Move(originInstallFiles, tmpDlcDir + "\\__metadata"); } for (int i = 0; i < sfarFiles.Count; i++) { string DLCname = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(sfarFiles[i]))); string outPath = Path.Combine(tmpDlcDir, DLCname); Directory.CreateDirectory(outPath); ME3DLC dlc = new ME3DLC(mainWindow); if (mainWindow != null) { mainWindow.updateStatusLabel("SFAR extracting - DLC " + (i + 1) + " of " + sfarFiles.Count); } if (installer != null) { installer.updateStatusPrepare("Extracting DLC ... " + (i + 1) + " of " + sfarFiles.Count); } dlc.extract(sfarFiles[i], outPath); } sfarFiles = Directory.GetFiles(GameData.DLCData, "Default.sfar", SearchOption.AllDirectories).ToList(); for (int i = 0; i < sfarFiles.Count; i++) { if (File.Exists(Path.Combine(Path.GetDirectoryName(sfarFiles[i]), "Mount.dlc"))) { string source = Path.GetDirectoryName(Path.GetDirectoryName(sfarFiles[i])); Directory.Move(source, tmpDlcDir + "\\" + Path.GetFileName(source)); } } Directory.Delete(GameData.DLCData, true); Directory.Move(tmpDlcDir, GameData.DLCData); }
public void extract(string SFARfilename, string outPath, bool ipc, ref int currentProgress, int totalNumber) { if (!File.Exists(SFARfilename)) { throw new Exception("filename missing"); } if (mainWindow != null) { mainWindow.updateStatusLabel2("Loading SFAR..."); } 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 (mainWindow != null) { mainWindow.updateStatusLabel2("File " + (i + 1) + " of " + filesList.Count() + " - " + Path.GetFileName(filesList[i].filenamePath)); } if (installer != null) { installer.updateStatusPrepare("Unpacking DLC " + ((currentProgress + 1) * 100 / totalNumber) + "%"); } 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]); } } } } } }