Beispiel #1
0
        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];
                int uncompressedSize = (int)entry.UncompressedSize;

                var result = MiniLZO.LZO.DecompressSafe(
                    compressedData,
                    0,
                    (int)entry.CompressedSize,
                    uncompressedData,
                    0,
                    ref uncompressedSize);
                if (result != MiniLZO.ErrorCode.Success)
                {
                    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)));
        }
Beispiel #2
0
        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];
                    int uncompressedSize = (int)entry.UncompressedSize;

                    var result = MiniLZO.LZO.DecompressSafe(
                        compressedData,
                        0,
                        (int)entry.CompressedSize,
                        uncompressedData,
                        0,
                        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 void Deserialize(Stream input)
        {
            var magic = input.ReadValueU32(Endian.Little);

            if (magic != 0x46415432)             // FAT2
            {
                throw new FormatException("not a big file");
            }
            var endian = Endian.Little;

            var version = input.ReadValueU32(endian);

            if (version != 5)
            {
                throw new FormatException("unsupported big file version");
            }

            input.ReadValueU32(endian);
            var indexCount = input.ReadValueU32(endian);

            this.Entries.Clear();
            for (int i = 0; i < indexCount; i++)
            {
                var index = new Big.Entry();
                index.Deserialize(input, endian);
                this.Entries.Add(index);
            }

            // There's a dword at the end of the file past the index entries, all observed
            // Far Cry 2 archives all have it as 0, I assume it's another table for something.

            if (input.ReadValueU32(endian) != 0)
            {
                throw new FormatException("unexpected value");
            }
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
        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) + ".fc2map";

            var map = new MapFile();

            map.Info          = new Map.Info();
            map.Snapshot      = new Map.Snapshot();
            map.Data          = new Map.Data();
            map.Data.Unknown2 = new Map.Snapshot();
            map.Archive       = new Map.Archive();

            using (var input = File.OpenRead(Path.Combine(inputPath, "map.xml")))
            {
                var doc = new XPathDocument(input);
                var nav = doc.CreateNavigator();

                var info = nav.SelectSingleNode("/map/info");
                map.Info.Name      = info.SelectSingleNode("name").Value;
                map.Info.Creator   = info.SelectSingleNode("creator").Value;
                map.Info.Author    = info.SelectSingleNode("author").Value;
                map.Info.Size      = (Map.Size)Enum.Parse(typeof(Map.Size), info.SelectSingleNode("size").Value);
                map.Info.Players   = (Map.Players)Enum.Parse(typeof(Map.Players), info.SelectSingleNode("players").Value);
                map.Info.Unknown2  = uint.Parse(info.SelectSingleNode("unknown2").Value, CultureInfo.InvariantCulture);
                map.Info.Unknown3  = uint.Parse(info.SelectSingleNode("unknown3").Value, CultureInfo.InvariantCulture);
                map.Info.Unknown4  = uint.Parse(info.SelectSingleNode("unknown4").Value, CultureInfo.InvariantCulture);
                map.Info.Unknown5  = ulong.Parse(info.SelectSingleNode("unknown5").Value, CultureInfo.InvariantCulture);
                map.Info.Unknown7  = ulong.Parse(info.SelectSingleNode("unknown7").Value, CultureInfo.InvariantCulture);
                map.Info.Unknown10 = ulong.Parse(info.SelectSingleNode("unknown10").Value, CultureInfo.InvariantCulture);

                using (var reader = new XmlTextReader(new StringReader(info.SelectSingleNode("unknown11").OuterXml)))
                {
                    reader.MoveToContent();
                    map.Info.Unknown11 = new byte[0];
                    int read = 0;
                    do
                    {
                        Array.Resize(ref map.Info.Unknown11, map.Info.Unknown11.Length + 4096);
                        read += reader.ReadBinHex(map.Info.Unknown11, read, 4096);
                    }while (reader.EOF == false);
                    Array.Resize(ref map.Info.Unknown11, read);
                }

                using (var reader = new XmlTextReader(new StringReader(info.SelectSingleNode("unknown12").OuterXml)))
                {
                    reader.MoveToContent();
                    map.Info.Unknown12 = new byte[0];
                    int read = 0;
                    do
                    {
                        Array.Resize(ref map.Info.Unknown12, map.Info.Unknown12.Length + 4096);
                        read += reader.ReadBinHex(map.Info.Unknown12, read, 4096);
                    }while (reader.EOF == false);
                    Array.Resize(ref map.Info.Unknown12, read);
                }

                map.Info.Unknown15 = uint.Parse(info.SelectSingleNode("unknown15").Value, CultureInfo.InvariantCulture);

                var snapshot = nav.SelectSingleNode("/map/snapshot");
                map.Snapshot.Width         = uint.Parse(snapshot.SelectSingleNode("width").Value, CultureInfo.InvariantCulture);
                map.Snapshot.Height        = uint.Parse(snapshot.SelectSingleNode("height").Value, CultureInfo.InvariantCulture);
                map.Snapshot.BytesPerPixel = uint.Parse(snapshot.SelectSingleNode("bpp").Value, CultureInfo.InvariantCulture);
                map.Snapshot.Unknown4      = uint.Parse(snapshot.SelectSingleNode("unknown4").Value, CultureInfo.InvariantCulture);

                var data = nav.SelectSingleNode("/map/data");
                map.Data.Unknown1 = data.SelectSingleNode("unknown1").Value;
            }

            using (var input = File.OpenRead(Path.Combine(inputPath, "snapshot.bin")))
            {
                map.Snapshot.Data = new byte[input.Length];
                input.Read(map.Snapshot.Data, 0, map.Snapshot.Data.Length);
            }

            var paths = new SortedDictionary <uint, string>();

            if (verbose == true)
            {
                Console.WriteLine("Finding files...");
            }

            var dataPath = Path.Combine(inputPath, "archive");

            dataPath = Path.GetFullPath(dataPath);

            if (dataPath.EndsWith(Path.DirectorySeparatorChar.ToString()) == true)
            {
                dataPath = dataPath.Substring(0, dataPath.Length - 1);
            }

            foreach (string path in Directory.GetFiles(dataPath, "*", SearchOption.AllDirectories))
            {
                string fullPath = Path.GetFullPath(path);
                string partPath = fullPath.Substring(dataPath.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)
                {
                    continue;
                }

                paths[hash] = fullPath;
            }

            var big = new BigFile();

            using (var output = new MemoryStream())
            {
                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))
                    {
                        entry.CompressionScheme = Big.CompressionScheme.None;
                        entry.UncompressedSize  = 0;
                        entry.CompressedSize    = (uint)input.Length;
                        output.WriteFromStream(input, input.Length);
                    }

                    big.Entries.Add(entry);
                }

                map.Archive.DAT = MakeCompressedData(output);
            }

            using (var output = new MemoryStream())
            {
                big.Serialize(output);
                map.Archive.FAT = MakeCompressedData(output);
            }

            using (var output = new MemoryStream())
            {
                var settings = new XmlWriterSettings();
                settings.Indent             = true;
                settings.OmitXmlDeclaration = true;
                settings.IndentChars        = "\t";
                settings.Encoding           = Encoding.ASCII;

                using (var writer = XmlWriter.Create(output, settings))
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement("FatInfo");

                    foreach (var entry in big.Entries.OrderBy(e => e.NameHash))
                    {
                        writer.WriteStartElement("File");
                        writer.WriteAttributeString("Path", entry.NameHash.ToString(CultureInfo.InvariantCulture));
                        writer.WriteAttributeString("Crc", entry.NameHash.ToString(CultureInfo.InvariantCulture));
                        writer.WriteAttributeString("FileTime", "0");
                        writer.WriteEndElement();
                    }

                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                }

                output.Position = 0;
                map.Archive.XML = MakeCompressedData(output);
            }

            using (var output = File.Create(outputPath))
            {
                map.Serialize(output);
            }
        }