private static string DetectExtension(Stream input, Big.Entry entry) { 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 if (entry.CompressionScheme == Big.CompressionScheme.LZO1x) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } Array.Copy(uncompressedData, 0, guess, 0, Math.Min(guess.Length, uncompressedData.Length)); read = uncompressedData.Length; } else { throw new NotSupportedException(); } return(FileExtensions.Detect(guess, Math.Min(guess.Length, read))); }
private static void ExtractFile(Stream input, Big.Entry entry, Stream output) { if (entry.CompressionScheme == Big.CompressionScheme.None) { if (entry.CompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.CompressedSize); } } else if (entry.CompressionScheme == Big.CompressionScheme.LZO1x) { if (entry.UncompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } output.Write(uncompressedData, 0, uncompressedData.Length); } } else { throw new NotSupportedException(); } }
public static void Main(string[] args) { bool showHelp = false; bool overwriteFiles = false; bool verbose = 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> 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_fat [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack"; var manager = ProjectData.Manager.Load(); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadLists( "*.filelist", s => s.HashFileNameCRC32(), s => s.ToLowerInvariant()); var map = new MapFile(); using (var input = File.OpenRead(inputPath)) { map.Deserialize(input); } Directory.CreateDirectory(outputPath); using (var output = File.Create(Path.Combine(outputPath, "map.xml"))) { var settings = new XmlWriterSettings(); settings.Indent = true; using (var writer = XmlWriter.Create(output, settings)) { writer.WriteStartDocument(); writer.WriteStartElement("map"); writer.WriteStartElement("info"); writer.WriteElementString("name", map.Info.Name); writer.WriteElementString("creator", map.Info.Creator); writer.WriteElementString("author", map.Info.Author); writer.WriteElementString("size", map.Info.Size.ToString()); writer.WriteElementString("players", map.Info.Players.ToString()); writer.WriteElementString("unknown2", map.Info.Unknown2.ToString()); writer.WriteElementString("unknown3", map.Info.Unknown3.ToString()); writer.WriteElementString("unknown4", map.Info.Unknown4.ToString()); writer.WriteElementString("unknown5", map.Info.Unknown5.ToString()); writer.WriteElementString("unknown7", map.Info.Unknown7.ToString()); writer.WriteElementString("unknown10", map.Info.Unknown10.ToString()); writer.WriteStartElement("unknown11"); writer.WriteBinHex(map.Info.Unknown11, 0, map.Info.Unknown11.Length); writer.WriteEndElement(); writer.WriteStartElement("unknown12"); writer.WriteBinHex(map.Info.Unknown12, 0, map.Info.Unknown12.Length); writer.WriteEndElement(); writer.WriteElementString("unknown15", map.Info.Unknown15.ToString()); writer.WriteEndElement(); writer.WriteStartElement("snapshot"); writer.WriteElementString("width", map.Snapshot.Width.ToString()); writer.WriteElementString("height", map.Snapshot.Height.ToString()); writer.WriteElementString("bpp", map.Snapshot.BytesPerPixel.ToString()); writer.WriteElementString("unknown4", map.Snapshot.Unknown4.ToString()); writer.WriteEndElement(); writer.WriteStartElement("data"); writer.WriteElementString("unknown1", map.Data.Unknown1); writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndDocument(); } } using (var input = map.Archive.XML.Unpack()) { using (var output = File.Create(Path.Combine(outputPath, "archive.xml"))) { output.WriteFromStream(input, input.Length); } } using (var output = File.Create(Path.Combine(outputPath, "snapshot.bin"))) { output.Write(map.Snapshot.Data, 0, map.Snapshot.Data.Length); } var big = new BigFile(); using (var input = map.Archive.FAT.Unpack()) { big.Deserialize(input); } var dataPath = Path.Combine(outputPath, "archive"); Directory.CreateDirectory(dataPath); using (var input = map.Archive.DAT.Unpack()) { long current = 0; long total = big.Entries.Count; foreach (var entry in big.Entries) { current++; string name = hashes[entry.NameHash]; if (name == null) { string extension; // detect type { var guess = new byte[64]; int read = 0; if (entry.CompressionScheme == 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 if (entry.CompressionScheme == CompressionScheme.LZO1x) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } Array.Copy(uncompressedData, 0, guess, 0, Math.Min(guess.Length, uncompressedData.Length)); read = uncompressedData.Length; } else { throw new NotSupportedException(); } extension = FileExtensions.Detect(guess, Math.Min(guess.Length, read)); } name = entry.NameHash.ToString("X8"); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine(extension, name); name = Path.Combine("__UNKNOWN", name); } else { name = name.Replace("/", "\\"); if (name.StartsWith("\\") == true) { name = name.Substring(1); } } var entryPath = Path.Combine(dataPath, name); Directory.CreateDirectory(Path.GetDirectoryName(entryPath)); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine("[{0}/{1}] {2}", current, total, name); } using (var output = File.Create(entryPath)) { if (entry.CompressionScheme == CompressionScheme.None) { if (entry.CompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.CompressedSize); } } else if (entry.CompressionScheme == CompressionScheme.LZO1x) { if (entry.UncompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } output.Write(uncompressedData, 0, uncompressedData.Length); } } else { throw new NotSupportedException(); } } } } }
public static void Main(string[] args) { bool showHelp = false; bool verbose = false; bool compress = false; var options = new OptionSet() { { "v|verbose", "be verbose", v => verbose = v != null }, { "c|compress", "compress data with LZO1x", v => compress = 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 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ output_fat input_directory+", GetExecutableName()); Console.WriteLine("Pack files from input directories into a Encapsulated Resource File."); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } var inputPaths = new List <string>(); string fatPath, datPath; if (extras.Count == 1) { inputPaths.Add(extras[0]); fatPath = Path.ChangeExtension(extras[0], ".fat"); datPath = Path.ChangeExtension(extras[0], ".dat"); } else { fatPath = extras[0]; if (Path.GetExtension(fatPath) != ".fat") { datPath = fatPath; fatPath = Path.ChangeExtension(datPath, ".fat"); } else { datPath = Path.ChangeExtension(fatPath, ".dat"); } inputPaths.AddRange(extras.Skip(1)); } var paths = new SortedDictionary <uint, string>(); if (verbose == true) { Console.WriteLine("Finding files..."); } foreach (var relPath in inputPaths) { string inputPath = Path.GetFullPath(relPath); if (inputPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == true) { inputPath = inputPath.Substring(0, inputPath.Length - 1); } foreach (string path in Directory.GetFiles(inputPath, "*", SearchOption.AllDirectories)) { string fullPath = Path.GetFullPath(path); string partPath = fullPath.Substring(inputPath.Length + 1).ToLowerInvariant(); uint hash = 0xFFFFFFFFu; if (partPath.ToUpper().StartsWith("__UNKNOWN") == true) { string partName; partName = Path.GetFileNameWithoutExtension(partPath); if (partName.Length > 8) { partName = partName.Substring(0, 8); } hash = uint.Parse( partName, System.Globalization.NumberStyles.AllowHexSpecifier); } else { hash = partPath.HashFileNameCRC32(); } if (paths.ContainsKey(hash) == true) { //if (verbose == true) { Console.WriteLine("Ignoring {0} duplicate.", partPath); } continue; } paths[hash] = fullPath; //Console.WriteLine(fullPath); } } var big = new BigFile(); using (var output = File.Create(datPath)) { foreach (var value in paths) { var hash = value.Key; var path = value.Value; if (verbose == true) { Console.WriteLine(path); } var entry = new Big.Entry(); entry.NameHash = hash; entry.Offset = output.Position; using (var input = File.OpenRead(path)) { if (compress == false) { entry.CompressionScheme = Big.CompressionScheme.None; entry.UncompressedSize = 0; entry.CompressedSize = (uint)input.Length; output.WriteFromStream(input, input.Length); } else { var uncompressedData = new byte[input.Length]; var uncompressedSize = (uint)uncompressedData.Length; input.Read(uncompressedData, 0, uncompressedData.Length); var compressedData = new byte[ uncompressedData.Length + (uncompressedData.Length / 16) + 64 + 3]; var compressedSize = (uint)compressedData.Length; var result = LZO1x.Compress( uncompressedData, uncompressedSize, compressedData, ref compressedSize); if (result != 0) { throw new InvalidOperationException("compression error " + result.ToString()); } if (compressedSize < uncompressedSize) { entry.CompressionScheme = Big.CompressionScheme.LZO1x; entry.UncompressedSize = uncompressedSize; entry.CompressedSize = compressedSize; output.Write(compressedData, 0, (int)compressedSize); } else { input.Seek(0, SeekOrigin.Begin); entry.CompressionScheme = Big.CompressionScheme.None; entry.UncompressedSize = 0; entry.CompressedSize = (uint)input.Length; output.WriteFromStream(input, input.Length); } } output.Seek(output.Position.Align(16), SeekOrigin.Begin); } big.Entries.Add(entry); } } using (var output = File.Create(fatPath)) { big.Serialize(output); } }
public static void Main(string[] args) { bool showHelp = false; bool extractUnknowns = true; bool noArt = true; bool overwriteFiles = false; bool verbose = false; var options = new OptionSet() { { "o|overwrite", "overwrite existing files", v => overwriteFiles = v != null }, { "na|no-art", "don't extract art files (textures, models, etc)", v => noArt = v != null }, { "nu|no-unknowns", "don't extract unknown files", v => extractUnknowns = 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_fat [output_dir]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string fatPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(fatPath, null) + "_unpack"; string datPath; if (Path.GetExtension(fatPath) == ".dat") { datPath = fatPath; fatPath = Path.ChangeExtension(fatPath, ".fat"); } else { datPath = Path.ChangeExtension(fatPath, ".dat"); } var manager = ProjectData.Manager.Load(); if (manager.ActiveProject == null) { Console.WriteLine("Warning: no active project loaded."); } var hashes = manager.LoadLists( "*.filelist", s => s.HashFileNameCRC32(), s => s.ToLowerInvariant()); var big = new BigFile(); using (var input = File.OpenRead(fatPath)) { big.Deserialize(input); } using (var input = File.OpenRead(datPath)) { long current = 0; long total = big.Entries.Count; foreach (var entry in big.Entries) { current++; string name = hashes[entry.NameHash]; if (name == null) { if (extractUnknowns == false) { continue; } string extension; // detect type { var guess = new byte[64]; int read = 0; if (entry.CompressionScheme == 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 if (entry.CompressionScheme == CompressionScheme.LZO1x) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } Array.Copy(uncompressedData, 0, guess, 0, Math.Min(guess.Length, uncompressedData.Length)); read = uncompressedData.Length; } else { throw new NotSupportedException(); } extension = FileExtensions.Detect(guess, Math.Min(guess.Length, read)); } name = entry.NameHash.ToString("X8"); name = Path.ChangeExtension(name, "." + extension); name = Path.Combine(extension, name); name = Path.Combine("__UNKNOWN", name); } else { name = name.Replace("/", "\\"); if (name.StartsWith("\\") == true) { name = name.Substring(1); } } if (noArt == true) { var ext = Path.GetExtension(name); if (ext == ".xbt" || ext == ".xbg" || ext == ".xbm" || ext == ".spk" || ext == ".mab" || ext == ".lfe" || ext == ".lfa" || ext == ".rtx" || ext == ".apm") { continue; } } var entryPath = Path.Combine(outputPath, name); Directory.CreateDirectory(Path.GetDirectoryName(entryPath)); if (overwriteFiles == false && File.Exists(entryPath) == true) { continue; } if (verbose == true) { Console.WriteLine("[{0}/{1}] {2}", current, total, name); } using (var output = File.Create(entryPath)) { if (entry.CompressionScheme == CompressionScheme.None) { if (entry.CompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.CompressedSize); } } else if (entry.CompressionScheme == CompressionScheme.LZO1x) { if (entry.UncompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } output.Write(uncompressedData, 0, uncompressedData.Length); } } else { throw new NotSupportedException(); } } } } }
private static bool UnpackFileFromBig(string fatPath, string fileName, string outputPath) { var datPath = Path.ChangeExtension(fatPath, ".dat"); if (File.Exists(fatPath) == false || File.Exists(datPath) == false) { return(false); } var big = new BigFile(); using (var input = File.OpenRead(fatPath)) { big.Deserialize(input); } var entries = big.Entries.Where(e => e.NameHash == fileName.HashFileNameCRC32()); if (entries.Count() == 0) { return(false); } var entry = entries.First(); using (var input = File.OpenRead(datPath)) { using (var output = File.Create(outputPath)) { if (entry.CompressionScheme == Big.CompressionScheme.None) { if (entry.CompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); output.WriteFromStream(input, entry.CompressedSize); } } else if (entry.CompressionScheme == Big.CompressionScheme.LZO1x) { if (entry.UncompressedSize > 0) { input.Seek(entry.Offset, SeekOrigin.Begin); var compressedData = new byte[entry.CompressedSize]; if (input.Read(compressedData, 0, compressedData.Length) != compressedData.Length) { throw new EndOfStreamException(); } var uncompressedData = new byte[entry.UncompressedSize]; uint uncompressedSize = entry.UncompressedSize; var result = LZO1x.Decompress( compressedData, entry.CompressedSize, uncompressedData, ref uncompressedSize); if (result != 0) { throw new InvalidOperationException("decompression error: " + result.ToString()); } else if (uncompressedSize != entry.UncompressedSize) { throw new InvalidOperationException("did not decompress correct amount of data"); } output.Write(uncompressedData, 0, uncompressedData.Length); } } else { throw new NotSupportedException(); } } } return(true); }