static private string GetProgramForBinaryFile(string file) { using (var input = File.OpenRead(file)) { var guess = new byte[32]; var read = input.Read(guess, 0, (int)Math.Min(guess.Length, input.Length)); string extension = FileDetection.Detect(guess, read); if (_ExtensionLookup.ContainsKey(extension)) { return(_ExtensionLookup[extension]); } } return(null); }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; string filterPattern = null; bool overwriteFiles = false; bool verbose = false; string currentProject = null; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null }, { "f|filter=", "only extract files using pattern", v => filterPattern = v }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, { "p|project=", "override current project", v => currentProject = v }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_tab [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string tabPath = Path.GetFullPath(extras[0]); string outputPath = extras.Count > 1 ? Path.GetFullPath(extras[1]) : Path.ChangeExtension(tabPath, null) + "_unpack"; Regex filter = null; if (string.IsNullOrEmpty(filterPattern) == false) { filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } var manager = ProjectData.Manager.Load(currentProject); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadFileLists(null); var tab = new ArchiveTableFile(); using (var input = File.OpenRead(tabPath)) { tab.Deserialize(input); } var arcPath = Path.ChangeExtension(tabPath, ".arc"); using (var input = File.OpenRead(arcPath)) { long current = 0; long total = tab.Entries.Count; var padding = total.ToString(CultureInfo.InvariantCulture).Length; foreach (var entry in tab.Entries) { current++; string name = hashes[entry.NameHash]; if (name == null) { if (extractUnknowns == false) { continue; } var guess = new byte[32]; input.Seek(entry.Offset, SeekOrigin.Begin); var read = input.Read(guess, 0, (int)Math.Min(guess.Length, entry.Size)); var extension = FileDetection.Detect(guess, read); name = entry.NameHash.ToString("X8"); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine("__UNKNOWN", extension, name); } else { if (name.StartsWith("/") == true) { name = name.Substring(1); } name = name.Replace('/', Path.DirectorySeparatorChar); } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine( "[{0}/{1}] {2}", current.ToString(CultureInfo.InvariantCulture).PadLeft(padding), total, name); } var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory != null) { Directory.CreateDirectory(entryDirectory); } using (var output = File.Create(entryPath)) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.Size); } } } }
public static void Main(string[] args) { bool verbose = false; bool showHelp = false; var options = new OptionSet() { { "v|verbose", "be verbose (list files)", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extra; try { extra = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extra.Count < 1 || extra.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_pack [output_directory]", GetExecutableName()); Console.WriteLine("Unpack specified archive."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extra[0]; string outputBasePath = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, null) + "_unpacked"; Directory.CreateDirectory(outputBasePath); using (var input = File.OpenRead(inputPath)) { var header = new PackFile(); header.Deserialize(input); var entryCount = header.Entries.Count; for (int i = 0; i < entryCount; i++) { var outputPath = Path.Combine(outputBasePath, $"{i}"); uint entryOffset = header.Entries[i].Offset; uint nextEntryOffset = i + 1 >= entryCount ? header.TotalSize : header.Entries[i + 1].Offset; uint entrySize = nextEntryOffset - entryOffset; input.Position = entryOffset; var extension = FileDetection.Guess(input, (int)entrySize, entrySize); outputPath = Path.ChangeExtension(outputPath, extension); if (verbose == true) { Console.WriteLine(outputPath); } input.Position = entryOffset; using (var output = File.Create(outputPath)) { output.WriteFromStream(input, entrySize); } } } }
private static bool GetEntryName(Stream input, BigFile fat, Big.Entry entry, ProjectData.HashList <uint> hashes, bool extractUnknowns, bool onlyUnknowns, out string entryName) { entryName = hashes[entry.NameHash]; if (entryName == null) { if (extractUnknowns == false) { return(false); } string type; string extension; { var guess = new byte[64]; int read = 0; if (entry.CompressionScheme == Big.CompressionScheme.None) { if (entry.CompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); read = input.Read(guess, 0, (int)Math.Min(entry.CompressedSize, guess.Length)); } } else { using (var temp = new MemoryStream()) { EntryDecompression.Decompress(entry, input, temp); temp.Position = 0; read = temp.Read(guess, 0, (int)Math.Min(temp.Length, guess.Length)); } } var tuple = FileDetection.Detect(guess, Math.Min(guess.Length, read)); type = tuple != null ? tuple.Item1 : "unknown"; extension = tuple != null ? tuple.Item2 : null; } entryName = entry.NameHash.ToString("X8"); if (string.IsNullOrEmpty(extension) == false) { entryName = Path.ChangeExtension(entryName, "." + extension); } if (string.IsNullOrEmpty(type) == false) { entryName = Path.Combine(type, entryName); } entryName = Path.Combine("__UNKNOWN", entryName); } else { if (onlyUnknowns == true) { return(false); } entryName = FilterEntryName(entryName); } return(true); }
public static void Main(string[] args) { bool unpackNestedPacks = true; bool verbose = false; bool showHelp = false; var options = new OptionSet() { { "d|dont-unpack-nested-packs", "don't unpack nested .pack files", v => unpackNestedPacks = v == null }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extra; try { extra = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extra.Count < 1 || extra.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_FILETABLE [output_directory]", GetExecutableName()); Console.WriteLine("Unpack specified archive."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extra[0]; string outputBasePath = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, null) + "_unpacked"; FileTableFile table; using (var input = File.OpenRead(inputPath)) { table = new FileTableFile(); table.Deserialize(input); } var inputBasePath = Path.GetDirectoryName(inputPath); // TODO(gibbed): // - generate file index for successful repacking // - better name lookup for name hashes (FNV32) // (don't hardcode the list) var names = new string[] { "MENU_COMMON_PACK", "MENU_TEXTURE_MISC_PACK", "MN_AT_ORGANIZE", "MN_BIRTHDAY", "MN_BT_MAIN", "MN_BT_RESULT", "MN_COMMON", "MN_COMMONWIN", "MN_EVENT", "MN_INPUT", "MN_ITEMICON", "MN_KEY_LAYOUT", "MN_MOVIE", "MN_NETWORK", "MN_OPTION", "MN_ORGANIZE", "MN_SHOP2", "MN_STAFFROLL", "MN_STATUS", "MN_TITLE", "MN_WARRENREPORT", "MN_WORLD", }; var nameHashLookup = names.ToDictionary(v => v.HashFNV32(), v => v); var tableManifestPath = Path.Combine(outputBasePath, "@manifest.json"); var tableManifest = new FileTableManifest() { Endian = table.Endian, TitleId1 = table.TitleId1, TitleId2 = table.TitleId2, Unknown32 = table.Unknown32, ParentalLevel = table.ParentalLevel, InstallDataCryptoKey = table.InstallDataCryptoKey, }; foreach (var directory in table.Directories) { var tableDirectory = new TableDirectory() { Id = directory.Id, BasePath = Path.Combine(outputBasePath, $"{directory.Id}"), }; var fileContainers = new List <IFileContainer>() { tableDirectory, }; var binPath = Path.Combine(inputBasePath, $"{directory.Id:X4}.BIN"); using (var input = File.OpenRead(binPath)) { var fileQueue = new Queue <QueuedFile>(); foreach (var file in directory.Files) { long dataOffset; dataOffset = directory.DataBaseOffset; dataOffset += (file.DataBlockOffset << directory.DataBlockSize) * FileTableFile.BaseDataBlockSize; fileQueue.Enqueue(new QueuedFile() { Id = file.Id, Parent = tableDirectory, NameHash = file.NameHash, DataOffset = dataOffset, DataSize = file.DataSize, }); } while (fileQueue.Count > 0) { var file = fileQueue.Dequeue(); var parent = file.Parent; var nameBuilder = new StringBuilder(); nameBuilder.Append($"{file.Id}"); string name = null; if (file.NameHash != null) { if (nameHashLookup.TryGetValue(file.NameHash.Value, out name) == true) { nameBuilder.Append($"_{name}"); } else { nameBuilder.Append($"_HASH[{file.NameHash.Value:X8}]"); } } if (parent.IdCounts != null) { var idCounts = parent.IdCounts; int idCount; idCounts.TryGetValue(file.Id, out idCount); idCount++; idCounts[file.Id] = idCount; if (idCount > 1) { nameBuilder.Append($"_DUP_{idCount}"); } } if (unpackNestedPacks == true && file.DataSize >= 8) { input.Position = file.DataOffset; var fileMagic = input.ReadValueU32(Endian.Little); if (fileMagic == PackFile.Signature || fileMagic.Swap() == PackFile.Signature) { input.Position = file.DataOffset; var nestedPack = HandleNestedPack(input, fileQueue, file.Id, nameBuilder.ToString(), parent); fileContainers.Add(nestedPack); parent.FileManifests.Add(new FileTableManifest.File() { Id = file.Id, NameHash = file.NameHash, Name = name, IsPack = true, PackId = PackId.Create(file.PackRawId), Path = CleanPathForManifest(PathHelper.GetRelativePath(parent.BasePath, nestedPack.ManifestPath)), }); continue; } } var outputPath = Path.Combine(parent.BasePath, nameBuilder.ToString()); var outputParentPath = Path.GetDirectoryName(outputPath); if (string.IsNullOrEmpty(outputParentPath) == false) { Directory.CreateDirectory(outputParentPath); } input.Position = file.DataOffset; var extension = FileDetection.Guess(input, (int)file.DataSize, file.DataSize); outputPath = Path.ChangeExtension(outputPath, extension); if (verbose == true) { Console.WriteLine(outputPath); } input.Position = file.DataOffset; using (var output = File.Create(outputPath)) { output.WriteFromStream(input, file.DataSize); } parent.FileManifests.Add(new FileTableManifest.File() { Id = file.Id, NameHash = file.NameHash, Name = name, PackId = PackId.Create(file.PackRawId), Path = CleanPathForManifest(PathHelper.GetRelativePath(parent.BasePath, outputPath)), }); } } foreach (var fileContainer in fileContainers) { WriteManifest(fileContainer.ManifestPath, fileContainer); } tableManifest.Directories.Add(new FileTableManifest.Directory() { Id = directory.Id, DataBlockSize = directory.DataBlockSize, IsInInstallData = directory.IsInInstallData, FileManifest = CleanPathForManifest( PathHelper.GetRelativePath(outputBasePath, tableDirectory.ManifestPath)), }); } WriteManifest(tableManifestPath, tableManifest); }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; string filterPattern = null; bool overwriteFiles = false; bool paranoia = false; bool verbose = false; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null }, { "f|filter=", "only extract files using pattern", v => filterPattern = v }, { "p|paranoid", "be paranoid (validate hash when uncompressing files)", v => paranoia = v != null }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_bix [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string bixPath = Path.GetFullPath(extras[0]); string outputPath = extras.Count > 1 ? Path.GetFullPath(extras[1]) : Path.ChangeExtension(bixPath, null) + "_unpack"; Regex filter = null; if (string.IsNullOrEmpty(filterPattern) == false) { filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } var manager = ProjectData.Manager.Load(); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadListsBigNames(); var bix = new BigFileInventory(); using (var input = File.OpenRead(bixPath)) { bix.Deserialize(input, Endian.Little); } var basePath = Path.GetDirectoryName(bixPath); if (string.IsNullOrEmpty(basePath) == true) { throw new InvalidOperationException(); } var bigPath = Path.Combine(basePath, bix.BigFileName + ".big"); using (var input = File.OpenRead(bigPath)) { long current = 0; long total = bix.Entries.Count; foreach (var entry in bix.Entries) { current++; string name = hashes[entry.Id]; if (name == null) { if (extractUnknowns == false) { continue; } KeyValuePair <string, string> extension; // detect type { var guess = new byte[64]; int read = 0; var offset = (entry.Offset << 2) + (entry.Size.LoadOffset & 0xFFF); if (entry.Size.CompressedSize == 0) { if (entry.Size.UncompressedSize > 0) { input.Seek(offset, SeekOrigin.Begin); read = input.Read(guess, 0, (int)Math.Min(entry.Size.UncompressedSize, guess.Length)); } } else { input.Seek(offset, SeekOrigin.Begin); // todo: don't uncompress everything var uncompressedData = QuickCompression.Decompress(input); read = Math.Min(guess.Length, uncompressedData.Length); Array.Copy(uncompressedData, 0, guess, 0, read); } extension = FileDetection.Detect(guess, Math.Min(guess.Length, read)); } name = entry.Id.ToString("X8"); name = Path.ChangeExtension(name, "." + extension.Value); name = Path.Combine(extension.Key, name); name = Path.Combine("__UNKNOWN", name); } else { name = name.Replace(@"/", @"\"); if (name.StartsWith(@"\") == true) { name = name.Substring(1); } } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } var entryParentPath = Path.GetDirectoryName(entryPath); if (string.IsNullOrEmpty(entryParentPath) == true) { throw new InvalidOperationException(); } Directory.CreateDirectory(entryParentPath); if (verbose == true) { Console.WriteLine("[{0}/{1}] {2}", current, total, name); } using (var output = File.Create(entryPath)) { if (entry.Size.CompressedSize == 0) { if (entry.Size.LoadOffset != 0 || entry.Size.CompressedExtra != 0) { throw new InvalidOperationException(); } if (entry.Size.UncompressedSize > 0) { input.Seek(entry.Offset << 2, SeekOrigin.Begin); output.WriteFromStream(input, entry.Size.UncompressedSize); } } else { var uncompressedSize = entry.Size.CompressedSize + entry.Size.LoadOffset - entry.Size.CompressedExtra; if (uncompressedSize != entry.Size.UncompressedSize) { } if (entry.Size.UncompressedSize > 0) { input.Seek((entry.Offset << 2) + (entry.Size.LoadOffset & 0xFFF), SeekOrigin.Begin); QuickCompression.Decompress(input, output); } } } } } }
public static void Main(string[] args) { bool verbose = false; bool showHelp = false; var options = new OptionSet() { { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extra; try { extra = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extra.Count < 1 || extra.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_blob [output_directory]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extra[0]; string baseOutputPath = extra.Count > 1 ? extra[1] : Path.ChangeExtension(inputPath, null) + "_unpacked"; using (var input = File.OpenRead(inputPath)) { const Endian endian = Endian.Little; var count = input.ReadValueU32(endian); var ids = new uint[count]; var sizes = new uint[count]; for (uint i = 0; i < count; i++) { ids[i] = input.ReadValueU32(endian); sizes[i] = input.ReadValueU32(endian); } var end = (uint)input.Length; for (uint i = 0; i < count; i++) { uint id = ids[i]; uint size = sizes[i]; long currentPosition = input.Position; var extension = FileDetection.Guess(input, (int)size, size); input.Position = currentPosition; var name = string.Format( "{0}_{1:X4}_{2:X2}_{3:X2}", i, (id & 0x0000FFFF) >> 0, (id & 0x00FF0000) >> 16, (id & 0xFF000000) >> 24); var outputPath = Path.Combine(baseOutputPath, Path.ChangeExtension(name, extension)); if (verbose == true) { Console.WriteLine(outputPath); } var outputParentPath = Path.GetDirectoryName(outputPath); if (string.IsNullOrEmpty(outputParentPath) == false) { Directory.CreateDirectory(outputParentPath); } using (var output = File.Create(outputPath)) { output.WriteFromStream(input, size); } } } }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; string filterPattern = null; bool overwriteFiles = false; bool verbose = false; string currentProject = null; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = v == null }, { "f|filter=", "only extract files using pattern", v => filterPattern = v }, { "v|verbose", "be verbose", v => verbose = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, { "p|project=", "override current project", v => currentProject = v }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_tab [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string tabPath = Path.GetFullPath(extras[0]); string outputPath = extras.Count > 1 ? Path.GetFullPath(extras[1]) : Path.ChangeExtension(tabPath, null) + "_unpack"; Regex filter = null; if (string.IsNullOrEmpty(filterPattern) == false) { filter = new Regex(filterPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); } var manager = ProjectData.Manager.Load(currentProject); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadFileLists(); var tab = new ArchiveTableFile(); using (var input = File.OpenRead(tabPath)) { tab.Deserialize(input); } var arcPath = Path.ChangeExtension(tabPath, ".arc"); var compressedBlockBytes = new byte[tab.MaxCompressedBlockSize]; var uncompressedBlockBytes = new byte[tab.UncompressedBlockSize]; var singleCompressedBlock = new List <ArchiveTableFile.CompressedBlockInfo>(); singleCompressedBlock.Add(new ArchiveTableFile.CompressedBlockInfo()); using (var input = File.OpenRead(arcPath)) { long current = 0; long total = tab.Entries.Count; var padding = total.ToString(CultureInfo.InvariantCulture).Length; foreach (var entry in tab.Entries) { current++; string name = hashes[entry.NameHash]; if (name == null) { if (extractUnknowns == false) { continue; } var guess = new byte[32]; input.Position = entry.Offset; int read; if (entry.CompressionType == CompressionType.None || entry.CompressedSize == entry.UncompressedSize) { read = input.Read(guess, 0, (int)Math.Min(guess.Length, entry.CompressedSize)); } else { var decompress = GetDecompress(entry.CompressionType); ArchiveTableFile.CompressedBlockInfo compressedBlock; if (entry.CompressedBlockIndex == 0) { compressedBlock = new ArchiveTableFile.CompressedBlockInfo( entry.CompressedSize, entry.UncompressedSize); } else { compressedBlock = tab.CompressedBlocks[entry.CompressedBlockIndex]; } read = input.Read(compressedBlockBytes, 0, (int)compressedBlock.CompressedSize); if (read != compressedBlock.CompressedSize) { throw new EndOfStreamException(); } read = decompress( compressedBlockBytes, 0, (int)compressedBlock.CompressedSize, uncompressedBlockBytes, 0, (int)compressedBlock.UncompressedSize); if (read != compressedBlock.UncompressedSize) { throw new InvalidOperationException(); } var guessSize = Math.Min(32, (int)compressedBlock.UncompressedSize); Array.Copy(uncompressedBlockBytes, 0, guess, 0, guessSize); } var extension = FileDetection.Detect(guess, read); name = entry.NameHash.ToString("X8"); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine("__UNKNOWN", extension, name); } else { if (name.StartsWith("/") == true) { name = name.Substring(1); } name = name.Replace('/', Path.DirectorySeparatorChar); } if (filter != null && filter.IsMatch(name) == false) { continue; } var entryPath = Path.Combine(outputPath, name); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine( "[{0}/{1}] {2}", current.ToString(CultureInfo.InvariantCulture).PadLeft(padding), total, name); } var entryDirectory = Path.GetDirectoryName(entryPath); if (entryDirectory != null) { Directory.CreateDirectory(entryDirectory); } input.Position = entry.Offset; using (var output = File.Create(entryPath)) { if (entry.CompressionType == CompressionType.None || entry.CompressedSize == entry.UncompressedSize) { if (entry.CompressedSize != entry.UncompressedSize) { throw new InvalidOperationException(); } output.WriteFromStream(input, entry.CompressedSize); } else { var decompress = GetDecompress(entry.CompressionType); List <ArchiveTableFile.CompressedBlockInfo> compressedBlocks; ushort compressedBlockCount; ushort compressedBlockIndex = entry.CompressedBlockIndex; if (compressedBlockIndex == 0) { compressedBlocks = singleCompressedBlock; compressedBlocks[0] = new ArchiveTableFile.CompressedBlockInfo( entry.CompressedSize, entry.UncompressedSize); compressedBlockCount = 1; } else { compressedBlocks = tab.CompressedBlocks; long uncompressedSize = 0; compressedBlockCount = 0; for (int i = compressedBlockIndex; uncompressedSize < entry.UncompressedSize; i++) { uncompressedSize += compressedBlocks[i].UncompressedSize; compressedBlockCount++; } } long remaining = entry.UncompressedSize; for (int i = 0; i < compressedBlockCount; i++) { var compressedBlock = compressedBlocks[compressedBlockIndex]; var read = input.Read(compressedBlockBytes, 0, (int)compressedBlock.CompressedSize); if (read != compressedBlock.CompressedSize) { throw new EndOfStreamException(); } var result = decompress( compressedBlockBytes, 0, (int)compressedBlock.CompressedSize, uncompressedBlockBytes, 0, (int)compressedBlock.UncompressedSize); if (result != compressedBlock.UncompressedSize) { throw new InvalidOperationException(); } output.Write(uncompressedBlockBytes, 0, (int)compressedBlock.UncompressedSize); remaining -= compressedBlock.UncompressedSize; compressedBlockIndex++; } if (remaining != 0) { throw new InvalidOperationException(); } } } } } }