Beispiel #1
0
        public bool InitializePartition(string partition)
        {
            Files.Clear();
            LSEntry resource = null;

            if ((resource = LS.TryGetValue(partition)) == null)
            {
                return(false);
            }

            File.WriteAllBytes(partition,
                               GetFile(resource.DTOffset, resource.Size, resource.DTIndex));

            RF = new RFFile(partition);
            if (partition.Contains("("))
            {
                RF.Locale = partition.Substring(partition.IndexOf("("));
            }
            RegionCode = RF.RegionCode;

            LSEntry     lsentry = null;
            IndexedPath path    = new IndexedPath($"data{RF.Locale}/");

            foreach (ResourceEntry rsobj in RF.ResourceEntries)
            {
                if (rsobj == null)
                {
                    continue;
                }

                path[rsobj.FolderDepth] = rsobj.EntryString;

                if (rsobj.Packed)
                {
                    lsentry = LS.TryGetValue(path.ToString() + "packed");
                }

                if (lsentry != null)
                {
                    var tpl = new Tuple <LSEntry, ResourceEntry>(lsentry, rsobj);
                    if (rsobj.Packed)
                    {
                        Files.Add(path.ToString() + "packed", tpl);
                    }
                    else
                    {
                        Files.Add(path.ToString(), tpl);
                    }
                }
            }
            return(true);
        }
Beispiel #2
0
        public bool InitializePartition(string partition)
        {
            LSEntry resource = null;

            if ((resource = LS.TryGetValue(partition)) == null)
            {
                return(false);
            }

            File.WriteAllBytes(partition,
                               GetFile(resource.DTOffset, resource.Size, resource.DTIndex));

            var rf = new RFFile(partition);

            if (partition.Contains("("))
            {
                rf.Locale = partition.Substring(partition.IndexOf("("));
            }

            return(InitializePartition(rf, partition));
        }
Beispiel #3
0
        public bool InitializePartition(RFFile rf, string partition)
        {
            Files.Clear();
            RegionCode = rf.RegionCode;
            LSEntry     lsentry = null;
            IndexedPath path    = new IndexedPath($"data{RF.Locale}/");

            foreach (ResourceEntry rsobj in RF.ResourceEntries)
            {
                if (rsobj == null)
                {
                    continue;
                }

                path[rsobj.FolderDepth] = rsobj.EntryString;

                if (rsobj.Packed)
                {
                    lsentry = LS.TryGetValue(path.ToString() + "packed");
                }

                if (lsentry != null)
                {
                    var tpl = new Tuple <LSEntry, ResourceEntry>(lsentry, rsobj);
                    if (rsobj.Packed)
                    {
                        Files.Add(path.ToString() + "packed", tpl);
                    }
                    else
                    {
                        Files.Add(path.ToString(), tpl);
                    }
                }
            }
            return(true);
        }
Beispiel #4
0
        public void BuildPartitions(string folder)
        {
            if (DTFiles == null)
            {
                return;
            }

            FileStream dtstrm   = File.Create("dt_rebuild");
            string     tmpfile  = Path.GetTempFileName();
            FileStream packstrm = File.Create(tmpfile);

            foreach (string str in Directory.EnumerateDirectories(folder))
            {
                if (!str.Contains("data"))
                {
                    return;
                }

                string partition = "resource";
                if (str.Contains("("))
                {
                    partition += str.Substring(str.IndexOf("("));
                }

                var rf = new RFFile();

                LSEntry curPacked = null;
                int     pad       = 0;
                string  packKey   = "";
                foreach (string key in Files.Keys)
                {
                    Console.WriteLine(key);
                    var tpl = Files[key];
                    if (tpl.Item2.Packed)
                    {
                        if (curPacked != null)
                        {
                            int aligned = (int)packstrm.Position.RoundUp(0x10) + 0x60;
                            while (packstrm.Position < aligned)
                            {
                                packstrm.WriteByte(0xBB);
                            }
                            curPacked.Size = (int)packstrm.Length;
                            LS.TrySetValue(packKey, curPacked);

                            packstrm.WriteTo(dtstrm);
                            packstrm.Close();
                            packstrm = File.Open(tmpfile, FileMode.Truncate);
                        }
                        curPacked          = tpl.Item1;
                        packKey            = key;
                        curPacked.DTOffset = (uint)dtstrm.Position;
                        var data = File.ReadAllBytes($"{folder}/{key}");
                        for (pad = 0; pad < data.Length && data[pad] == 0xCC; pad++)
                        {
                            packstrm.WriteByte(0xCC);
                        }
                    }
                    else if (!tpl.Item2.EntryString.EndsWith("/"))
                    {
                        var           filedata = File.ReadAllBytes($"{folder}/{key}");
                        var           cmp      = Util.Compress(filedata);
                        ResourceEntry rsobj    = tpl.Item2;
                        int           rIndex   = RF.ResourceEntries.IndexOf(rsobj);

                        rsobj.OffInPack = (uint)packstrm.Position;
                        rsobj.CmpSize   = cmp.Length;
                        rsobj.DecSize   = filedata.Length;
                        RF[rIndex]      = rsobj;
                        packstrm.Write(cmp, 0, cmp.Length);

                        int aligned = (int)packstrm.Position.RoundUp(0x10) + 0x20;
                        while (packstrm.Position % 0x10 > 0)
                        {
                            packstrm.WriteByte(0xCC);
                        }
                    }
                }
                if (curPacked != null)
                {
                    curPacked.Size = (int)packstrm.Length;
                    LS.TrySetValue(packKey, curPacked);
                    packstrm.WriteTo(dtstrm);
                }
                RF.UpdateEntries();


                byte[] full     = RF.GetBytes();
                var    resource = LS.TryGetValue(partition);
                resource.DTOffset = (uint)dtstrm.Position;
                dtstrm.Write(full, 0, full.Length);
                resource.Size = full.Length;
                LS.TrySetValue(partition, resource);
                LS.UpdateEntries();
                dtstrm.Close();
                packstrm.Close();
            }
        }
Beispiel #5
0
        private static void Unpack_update(string resFile)
        {
            Console.WriteLine("Parsing resource file..");
            RFFile rfFile = new RFFile(resFile);
            var pathParts = new string[20];
            DataSource _curPacked = new DataSource();
            string mainfolder = "";
            string region = "";

            if (resFile.Contains("("))
                region = resFile.Substring(resFile.IndexOf("(", StringComparison.Ordinal), 7);

            foreach (ResourceEntryObject rsobj in rfFile.ResourceEntries)
            {
                if (rsobj == null)
                    continue;

                pathParts[rsobj.FolderDepth - 1] = rsobj.EntryString;
                Array.Clear(pathParts, rsobj.FolderDepth, pathParts.Length - (rsobj.FolderDepth + 1));
                var path = $"data{region}/{string.Join("", pathParts)}";

                if (rsobj.HasPack)
                {
                    path += (rsobj.Compressed ? "packed" : "");
                    if (File.Exists(path))
                    {
                        _curPacked = new DataSource(FileMap.FromFile(path));
                        mainfolder = path.Remove(path.Length - 6);
                    }
                    continue;
                }

                if (!(rsobj.inPatch && path.Contains(mainfolder) && !string.IsNullOrEmpty(mainfolder)))
                    continue;

                if (path.EndsWith("/"))
                {
                    if (!Directory.Exists(path))
                        Directory.CreateDirectory(path);
                }
                else
                {

                    var fileData = new byte[0];

                    if (rsobj.CmpSize > 0)
                    {
                        byte[] tmp = _curPacked.Slice((int)rsobj.OffInPack, 4);

                        if (tmp[0] == 0x78 && tmp[1] == 0x9c)
                            fileData = Util.DeCompress(_curPacked.Slice((int)rsobj.OffInPack, (int)rsobj.CmpSize));
                        else
                            fileData = _curPacked.Slice((int)rsobj.OffInPack, (int)rsobj.DecSize);
                    }

                    Console.WriteLine(path);
                    Logstream.WriteLine($"{path} : size: {rsobj.DecSize:X8}");

                    if (fileData.Length != rsobj.DecSize)
                    {
                        Console.WriteLine("Error: File length doesn't match specified decompressed length, quiting");
                        Logstream.WriteLine("Error: File length doesn't match specified decompressed length, quiting");
                        return;
                    }

                    File.WriteAllBytes(path, fileData);
                }
            }
            Logstream.Close();
            Console.WriteLine("Extraction finished.");

            if (File.Exists($"resource{region}.dec"))
                File.Delete($"resource{region}.dec");
        }
Beispiel #6
0
        /// <summary>
        /// Unpacks data from the game archive using the default resource file.
        /// </summary>
        /// <param name="resourceStr">The resource file (embedded or otherwise) to use in extraction</param>
        private static void Unpack_default(string resourceStr)
        {
            string region = "";
            if (resourceStr.Contains("("))
                region = resourceStr.Substring(resourceStr.IndexOf("(", StringComparison.Ordinal), 7);

            LSEntryObject _resource = lsFile.Entries[Util.calc_crc(resourceStr)];

            File.WriteAllBytes(resourceStr,
                GetFileDataDecompressed(_resource.DTOffset + (uint)_resource.PaddingLength, _resource.Size,
                    _resource.DTIndex));

            Console.WriteLine($"Parsing {resourceStr} file..");
            RFFile rfFile = new RFFile(resourceStr);

            var pathParts = new string[20];
            var offsetParts = new LSEntryObject[20];
            foreach (ResourceEntryObject rsobj in rfFile.ResourceEntries)
            {
                if (rsobj == null)
                    continue;

                pathParts[rsobj.FolderDepth - 1] = rsobj.EntryString;
                Array.Clear(pathParts, rsobj.FolderDepth, pathParts.Length - (rsobj.FolderDepth + 1));
                var path = string.Join("", pathParts);

                LSEntryObject fileEntry;
                if (rsobj.HasPack)
                {
                    var crcPath = $"data/{path.TrimEnd('/') + (rsobj.Compressed ? "/packed" : "")}";
                    var crc = Util.calc_crc(crcPath);
                    lsFile.Entries.TryGetValue(crc, out fileEntry);
                }
                else
                    fileEntry = null;

                offsetParts[rsobj.FolderDepth - 1] = fileEntry;
                Array.Clear(offsetParts, rsobj.FolderDepth, offsetParts.Length - (rsobj.FolderDepth + 1));

                var outfn = $"data{region}/{path}";
                if (path.EndsWith("/"))
                {
                    if (!Directory.Exists(outfn))
                        Directory.CreateDirectory(outfn);
                }
                else
                {
                    LSEntryObject lsentry = offsetParts.Last(x => x != null);

                    var fileData = new byte[0];

                    if (rsobj.CmpSize > 0)
                        fileData = GetFileDataDecompressed(lsentry.DTOffset + rsobj.OffInPack, (uint)rsobj.CmpSize,
                            lsentry.DTIndex);

                    Console.WriteLine(outfn);
                    Logstream.WriteLine($"{outfn} : size: {rsobj.DecSize:X8}");

                    if (fileData.Length != rsobj.DecSize)
                    {
                        Console.WriteLine("Error: File length doesn't match specified decompressed length, skipping");
                        Logstream.WriteLine("Error: File length doesn't match specified decompressed length, skipping");
                    }

                    File.WriteAllBytes(outfn, fileData);
                }
            }
            // clean up
            Logstream.Close();

            Console.WriteLine("Extraction finished");

            if (File.Exists("resource.dec"))
                File.Delete("resource.dec");
            if (File.Exists("resource"))
                File.Delete("resource");
        }
Beispiel #7
0
        private static unsafe void PatchArchive(string resourceString, string patchFolder)
        {
            LSEntryObject _resource = lsFile.Entries[Util.calc_crc(resourceString)];
            byte[] resource = GetFileDataDecompressed(_resource.DTOffset + (uint)_resource.PaddingLength,
                _resource.Size,
                _resource.DTIndex);
            File.WriteAllBytes(resourceString, resource);

            Console.WriteLine($"Patching {resourceString}");
            RFFile rfFile = new RFFile(resourceString);

            var pathParts = new string[20];
            var offsetParts = new LSEntryObject[20];
            foreach (ResourceEntryObject rsobj in rfFile.ResourceEntries)
            {
                if (rsobj == null)
                    continue;

                pathParts[rsobj.FolderDepth - 1] = rsobj.EntryString;
                Array.Clear(pathParts, rsobj.FolderDepth, pathParts.Length - (rsobj.FolderDepth + 1));
                var path = string.Join("", pathParts);

                LSEntryObject fileEntry;
                if (rsobj.HasPack)
                {
                    var crcPath = $"data/{path.TrimEnd('/') + (rsobj.Compressed ? "/packed" : "")}";
                    var crc = Util.calc_crc(crcPath);
                    lsFile.Entries.TryGetValue(crc, out fileEntry);
                }
                else
                    fileEntry = null;

                offsetParts[rsobj.FolderDepth - 1] = fileEntry;
                Array.Clear(offsetParts, rsobj.FolderDepth, offsetParts.Length - (rsobj.FolderDepth + 1));

                if (!path.EndsWith("/"))
                    if (File.Exists($"{patchFolder}/{path}"))
                    {
                        Console.WriteLine($"Patch found: {patchFolder}/{path}");
                        Logstream.WriteLine($"Patch found: {patchFolder}/{path}");

                        LSEntryObject lsentry = offsetParts.Last(x => x != null);
                        byte[] raw = File.ReadAllBytes($"{patchFolder}/{path}");
                        byte[] compressed = Util.Compress(raw);
                        if (compressed.Length > rsobj.CmpSize + 0x10)
                        {
                            Console.WriteLine("Patching files larger than original not yet supported, skipping");
                            continue;
                        }
                        rsobj.CmpSize = (uint)compressed.Length;
                        rsobj.DecSize = (uint)raw.Length;
                        uint difference = 0;
                        DataSource src = GetFileChunk(lsentry.DTOffset, lsentry.Size, lsentry.DTIndex, out difference);
                        VoidPtr addr = src.Address + difference;
                        addr += rsobj.OffInPack;
                        for (int i = 0; i < compressed.Length; i++)
                            *(byte*)(addr + i) = compressed[i];

                        // write 0xCC over unused bytes.
                        addr += compressed.Length;
                        int truncateBytes = (int)rsobj.CmpSize - compressed.Length;
                        for (int i = 0; i < truncateBytes; i++)
                            *(byte*)(addr + i) = 0xCC;

                        src.Close();
                    }
            }
            // Update resource and LS files.
            rfFile.UpdateEntries();
            byte[] dec = rfFile._workingSource.Slice((int)rfFile.Header.HeaderLen1,
                (int)(rfFile._workingSource.Length - rfFile.Header.HeaderLen1));
            byte[] cmp = Util.Compress(dec);
            rfFile.Header.CompressedLen = (uint)cmp.Length;
            rfFile.Header.DecompressedLen = (uint)dec.Length;
            byte[] header = rfFile.Header.ToArray();
            byte[] full = header.Concat(cmp).ToArray();
            lsFile.Entries[Util.calc_crc(resourceString)].Size = (uint)full.Length;
            lsFile.UpdateEntries();

            // Patch the resource data back into the DT file.
            uint diff;
            DataSource rSource = GetFileChunk(_resource.DTOffset, _resource.Size, _resource.DTIndex, out diff);
            VoidPtr curAddr = rSource.Address + diff;
            for (int i = 0; i < full.Length; i++)
            {
                *(byte*)(curAddr + i) = full[i];
            }
            rSource.Close();
            rfFile._workingSource.Close();

            if (File.Exists(resourceString))
                File.Delete(resourceString);
            if (File.Exists(resourceString + ".dec"))
                File.Delete(resourceString + ".dec");
        }