Пример #1
0
        public void Parse(FixHdrOptions op)
        {
            if (op.OutputPath == null)
            {
                op.OutputPath = op.InputPath;
            }

            var ark = ArkFile.FromFile(op.InputPath);

            ark.Encrypted = ark.Encrypted || op.ForceEncryption; // Force encryption
            ark.WriteHeader(op.OutputPath);
        }
Пример #2
0
        public void Parse(ArkCompareOptions op)
        {
            var ark1 = ArkFile.FromFile(op.ArkPath1);
            var ark2 = ArkFile.FromFile(op.ArkPath2);

            var ark1Entries = ark1.Entries
                              .Select(x => x as OffsetArkEntry)
                              .Select(x => new
            {
                Name = x.FullPath,
                x.Size,
                Hash = Crypt.SHA1Hash(ark1.GetArkEntryFileStream(x))
            })
                              .ToList();

            var ark2Entries = ark2.Entries
                              .Select(x => x as OffsetArkEntry)
                              .Select(x => new
            {
                Name = x.FullPath,
                x.Size,
                Hash = Crypt.SHA1Hash(ark2.GetArkEntryFileStream(x))
            })
                              .ToList();

            var sharedEntries = ark1Entries
                                .Intersect(ark2Entries)
                                .ToList();

            var ark1UniqueEntries = ark1Entries
                                    .Except(sharedEntries)
                                    .ToList();

            var ark2UniqueEntries = ark2Entries
                                    .Except(sharedEntries)
                                    .ToList();

            var newFiles = string.Join('\n', ark1UniqueEntries
                                       .Select(x => x.Name));

            // TODO: Create formatted console output
        }
Пример #3
0
        public void Parse(PatchCreatorOptions op)
        {
            var ark         = ArkFile.FromFile(op.InputPath);
            var inplaceEdit = string.IsNullOrWhiteSpace(op.OutputPath);

            var platformExt = GuessPlatform(op.InputPath);

            if (!inplaceEdit)
            {
                if ((int)ark.Version <= 3)
                {
                    // If ark version doesn't support multiple parts then copy entire ark to new directory
                    ark         = ark.CopyToDirectory(Path.Combine(op.OutputPath, "gen"));
                    inplaceEdit = true;
                }
                else
                {
                    // Add additional ark park
                    var patchPartName = $"{Path.GetFileNameWithoutExtension(op.InputPath)}_{ark.PartCount()}.ark";
                    var fullPartPath  = ((int)ark.Version < 9)
                        ? Path.Combine(op.OutputPath, "gen", patchPartName)
                        : Path.Combine(op.OutputPath, patchPartName);

                    ark.AddAdditionalPart(fullPartPath);
                }
            }

            var files = Directory.GetFiles(op.ArkFilesPath, "*", SearchOption.AllDirectories);

            // Open hashes
            var entryInfo = (string.IsNullOrWhiteSpace(op.HashesPath)
                ? new List <ArkEntryInfo>()
                : ArkEntryInfo.ReadFromCSV(op.HashesPath))
                            .ToDictionary(x => x.Path, y => y);

            var updatedHashes = new List <ArkEntryInfo>();

            var dtaRegex         = new Regex("(?i).dta$");
            var genPathedFile    = new Regex(@"(?i)gen[\/][^\/]+$");
            var dotRegex         = new Regex(@"\([.]+\)/");
            var forgeScriptRegex = new Regex("(?i).((dta)|(fusion)|(moggsong)|(script))$");

            // Create temp path
            var tempDir = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));

            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }

            foreach (var file in files)
            {
                var internalPath = FileHelper.GetRelativePath(file, op.ArkFilesPath)
                                   .Replace("\\", "/");

                string inputFilePath = file;

                if ((int)ark.Version < 7 && dtaRegex.IsMatch(internalPath))
                {
                    // Updates path
                    internalPath = $"{internalPath.Substring(0, internalPath.Length - 1)}b";

                    if (!genPathedFile.IsMatch(internalPath))
                    {
                        internalPath = internalPath.Insert(internalPath.LastIndexOf('/'), "/gen");
                    }

                    // Creates temp dtb file
                    inputFilePath = ScriptHelper.ConvertDtaToDtb(file, tempDir, ark.Encrypted, (int)ark.Version);
                }
                else if ((int)ark.Version >= 7 && forgeScriptRegex.IsMatch(internalPath))
                {
                    // Updates path
                    internalPath = $"{internalPath}_dta_{platformExt}";

                    // Creates temp dtb file
                    inputFilePath = ScriptHelper.ConvertDtaToDtb(file, tempDir, ark.Encrypted, (int)ark.Version);
                }

                if (dotRegex.IsMatch(internalPath))
                {
                    internalPath = dotRegex.Replace(internalPath, x => $"{x.Value.Substring(1, x.Length - 3)}/");
                }

                var fileName = Path.GetFileName(internalPath);
                var dirPath  = Path.GetDirectoryName(internalPath).Replace("\\", "/");

                var pendingEntry = new PendingArkEntry(fileName, dirPath)
                {
                    LocalFilePath = inputFilePath
                };

                ark.AddPendingEntry(pendingEntry);
                Console.WriteLine($"Added {pendingEntry.FullPath}");

                if (!entryInfo.TryGetValue(internalPath, out var hashInfo))
                {
                    continue;
                }

                // Update hash
                using var fs  = File.OpenRead(inputFilePath);
                hashInfo.Hash = Crypt.SHA1Hash(fs);
                updatedHashes.Add(hashInfo);
            }

            ark.CommitChanges(inplaceEdit);

            // Clean up temp files
            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }

            if (!inplaceEdit)
            {
                // Writes header
                var hdrPath = ((int)ark.Version < 9)
                    ? Path.Combine(op.OutputPath, "gen", Path.GetFileName(op.InputPath))
                    : Path.Combine(op.OutputPath, Path.GetFileName(op.InputPath));
                ark.WriteHeader(hdrPath);
            }
            else
            {
                // TODO: Also look at possibly still patching exe
                return;
            }

            // Copy exe
            var exePath = Path.Combine(op.OutputPath, Path.GetFileName(op.ExePath));

            File.Copy(op.ExePath, exePath, true);

            if (updatedHashes.Count <= 0)
            {
                return;
            }

            // Patch exe
            using var exeStream = File.OpenWrite(exePath);
            foreach (var hashInfo in updatedHashes)
            {
                var hashBytes = FileHelper.GetBytes(hashInfo.Hash);

                exeStream.Seek(hashInfo.Offset, SeekOrigin.Begin);
                exeStream.Write(hashBytes, 0, hashBytes.Length);

                Console.WriteLine($"Updated hash for {hashInfo.Path}");
            }
        }
Пример #4
0
        public void Parse(Ark2DirOptions op)
        {
            var scriptRegex      = new Regex("(?i).((dtb)|(dta)|(([A-Z]+)(_dta_)([A-Z0-9]+)))$");
            var scriptForgeRegex = new Regex("(?i)(_dta_)([A-Z0-9]+)$");
            var csvRegex         = new Regex("(?i).csv_([A-Z0-9]+)$");

            var dtaRegex  = new Regex("(?i).dta$");
            var miloRegex = new Regex("(?i).milo(_[A-Z0-9]+)?$");

            var genPathedFile    = new Regex(@"(?i)(([^\/\\]+[\/\\])*)(gen[\/\\])([^\/\\]+)$");
            var platformExtRegex = new Regex(@"(?i)_([A-Z0-9]+)$");

            Archive ark;
            int     arkVersion;
            bool    arkEncrypted;

            if (Directory.Exists(op.InputPath))
            {
                // Open as directory
                ark = ArkFileSystem.FromDirectory(op.InputPath);

                // TODO: Get from args probably
                arkVersion   = 10;
                arkEncrypted = true;
            }
            else
            {
                // Open as ark
                var arkFile = ArkFile.FromFile(op.InputPath);
                arkVersion   = (int)arkFile.Version;
                arkEncrypted = arkFile.Encrypted;

                ark = arkFile;
            }

            var scriptsToConvert = ark.Entries
                                   .Where(x => op.ConvertScripts &&
                                          scriptRegex.IsMatch(x.FullPath))
                                   .ToList();

            var csvsToConvert = ark.Entries
                                .Where(x => op.ConvertScripts &&
                                       csvRegex.IsMatch(x.FullPath))
                                .ToList();

            var milosToInflate = ark.Entries
                                 .Where(x => op.InflateMilos &&
                                        miloRegex.IsMatch(x.FullPath))
                                 .ToList();

            var entriesToExtract = ark.Entries
                                   .Where(x => op.ExtractAll)
                                   .Except(scriptsToConvert)
                                   .Except(milosToInflate)
                                   .ToList();

            foreach (var arkEntry in entriesToExtract)
            {
                var filePath = ExtractEntry(ark, arkEntry, CombinePath(op.OutputPath, arkEntry.FullPath));
                Console.WriteLine($"Wrote \"{filePath}\"");
            }

            // Create temp path
            var tempDir = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));

            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }

            foreach (var miloEntry in milosToInflate)
            {
                var filePath = ExtractEntry(ark, miloEntry, CombinePath(op.OutputPath, miloEntry.FullPath));

                // Inflate milo
                var milo = MiloFile.ReadFromFile(filePath);
                milo.Structure = BlockStructure.MILO_A;
                milo.WriteToFile(filePath);

                Console.WriteLine($"Wrote \"{filePath}\"");
            }

            foreach (var csvEntry in csvsToConvert)
            {
                var csvStream = ark.GetArkEntryFileStream(csvEntry);
                var csv       = CSVFile.FromForgeCSVStream(csvStream);

                // Write to file
                var csvPath = CombinePath(op.OutputPath, csvEntry.FullPath);
                csvPath = platformExtRegex.Replace(csvPath, "");

                csv.SaveToFileAsCSV(csvPath);
                Console.WriteLine($"Wrote \"{csvPath}\"");
            }

            var successDtas = 0;

            foreach (var scriptEntry in scriptsToConvert)
            {
                // Just extract file if dta script
                if (dtaRegex.IsMatch(scriptEntry.FullPath))
                {
                    var filePath = ExtractEntry(ark, scriptEntry, CombinePath(op.OutputPath, scriptEntry.FullPath));
                    Console.WriteLine($"Wrote \"{filePath}\"");
                    continue;
                }

                // Creates output path
                var dtaPath = CombinePath(op.OutputPath, scriptEntry.FullPath);
                dtaPath = !scriptForgeRegex.IsMatch(dtaPath)
                    ? $"{dtaPath.Substring(0, dtaPath.Length - 1)}a" // Simply change b -> a
                    : scriptForgeRegex.Replace(dtaPath, "");

                // Removes gen sub directory
                if (genPathedFile.IsMatch(dtaPath))
                {
                    var match = genPathedFile.Match(dtaPath);
                    dtaPath = $"{match.Groups[1]}{match.Groups[4]}";
                }

                var tempDtbPath = ExtractEntry(ark, scriptEntry, Path.Combine(tempDir, Path.GetRandomFileName()));

                try
                {
                    ScriptHelper.ConvertDtbToDta(tempDtbPath, tempDir, arkEncrypted, arkVersion, dtaPath);
                    Console.WriteLine($"Wrote \"{dtaPath}\"");
                    successDtas++;
                }
                catch (DTBParseException ex)
                {
                    Console.WriteLine($"Unable to convert to script, skipping \'{scriptEntry.FullPath}\'");
                    if (File.Exists(dtaPath))
                    {
                        File.Delete(dtaPath);
                    }
                }
                catch (Exception ex)
                {
                }
            }

            if (scriptsToConvert.Count > 0)
            {
                Console.WriteLine($"Converted {successDtas} of {scriptsToConvert.Count} scripts");
            }

            // Clean up temp files
            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }
        }
Пример #5
0
        public void Parse(HashFinderOptions op)
        {
            var watch = Stopwatch.StartNew();

            var ark  = ArkFile.FromFile(op.InputPath);
            var exts = new[] { "dtb", "elf", "mid" };

            var arkEntries = ark
                             .Entries
                             .Where(x => exts.Contains(x.Extension))
                             .ToList();

            var entryInfo = arkEntries
                            .Select(x => new ArkEntryInfo()
            {
                Path   = x.FullPath,
                Hash   = "",
                Offset = -1
            })
                            .ToList();

            var i = 0;

            foreach (var dtb in arkEntries)
            {
                using (var dtbStream = ark.GetArkEntryFileStream(dtb))
                {
                    entryInfo[i].Hash = Crypt.SHA1Hash(dtbStream);
                    i++;
                }
            }

            var exeBytes = File.ReadAllBytes(op.ExePath);

            Parallel.ForEach(entryInfo, (info) =>
            {
                using (var ar = new AwesomeReader(new MemoryStream(exeBytes)))
                {
                    var hashBytes = FileHelper.GetBytes(info.Hash);
                    ar.BaseStream.Seek(0, SeekOrigin.Begin);

                    var offset = ar.FindNext(hashBytes);
                    if (offset != -1)
                    {
                        info.Offset = offset;
                    }
                }
            });

            watch.Stop();

            var protectedInfo = entryInfo
                                .Where(x => x.Offset != -1)
                                .OrderBy(x => x.Path)
                                .ToList();

            ArkEntryInfo.WriteToCSV(protectedInfo, op.HashesPath);
            var hashCount = protectedInfo.Count();

            Console.WriteLine($"Found offsets for {hashCount} entries of out {entryInfo.Count}");
            Console.WriteLine($"Scan took {watch.Elapsed} ({watch.ElapsedMilliseconds}ms)");
        }
Пример #6
0
        public void Parse(Dir2ArkOptions op)
        {
            var dtaRegex         = new Regex("(?i).dta$");
            var genPathedFile    = new Regex(@"(?i)gen[\/][^\/]+$");
            var dotRegex         = new Regex(@"\([.]+\)/");
            var forgeScriptRegex = new Regex("(?i).((dta)|(fusion)|(moggsong)|(script))$");
            var arkPartSizeLimit = (op.PartSizeLimit > 0)
                ? op.PartSizeLimit
                : uint.MaxValue;

            var arkDir = Path.GetFullPath(op.OutputPath);

            // Set encrypted data
            if (op.Encrypt && !op.EncryptKey.HasValue)
            {
                op.EncryptKey = 0x5A_4C_4F_4C;
            }
            else if (op.EncryptKey.HasValue)
            {
                // Don't encrypt unless explicitly stated
                op.EncryptKey = default;
            }

            // Create directory if it doesn't exist
            if (!Directory.Exists(arkDir))
            {
                Directory.CreateDirectory(arkDir);
            }

            // Create ark
            var hdrPath = Path.Combine(arkDir, $"{op.ArkName}.hdr");
            var ark     = ArkFile.Create(hdrPath, (ArkVersion)op.ArkVersion, (int?)op.EncryptKey);

            var files = Directory.GetFiles(op.InputPath, "*", SearchOption.AllDirectories);

            // Create temp path and guess platform
            var tempDir     = CreateTemporaryDirectory();
            var platformExt = GuessPlatform(op.InputPath);

            var currentPartSize = 0u;

            foreach (var file in files)
            {
                var internalPath = FileHelper.GetRelativePath(file, op.InputPath)
                                   .Replace("\\", "/");

                string inputFilePath = file;

                if ((int)ark.Version < 7 && dtaRegex.IsMatch(internalPath))
                {
                    // Updates path
                    internalPath = $"{internalPath.Substring(0, internalPath.Length - 1)}b";

                    if (!genPathedFile.IsMatch(internalPath))
                    {
                        internalPath = internalPath.Insert(internalPath.LastIndexOf('/'), "/gen");
                    }

                    // Creates temp dtb file
                    inputFilePath = ScriptHelper.ConvertDtaToDtb(file, tempDir, ark.Encrypted, (int)ark.Version);
                }
                else if ((int)ark.Version >= 7 && forgeScriptRegex.IsMatch(internalPath))
                {
                    // Updates path
                    internalPath = $"{internalPath}_dta_{platformExt}";

                    // Creates temp dtb file
                    inputFilePath = ScriptHelper.ConvertDtaToDtb(file, tempDir, ark.Encrypted, (int)ark.Version);
                }

                if (dotRegex.IsMatch(internalPath))
                {
                    internalPath = dotRegex.Replace(internalPath, x => $"{x.Value.Substring(1, x.Length - 3)}/");
                }

                // Check part limit
                var fileSizeLong      = new FileInfo(inputFilePath).Length;
                var fileSize          = (uint)fileSizeLong;
                var potentialPartSize = currentPartSize + fileSize;

                if (fileSizeLong > (long)uint.MaxValue)
                {
                    throw new NotSupportedException($"File size above 4GB is unsupported for \"{file}\"");
                }
                else if (potentialPartSize >= arkPartSizeLimit)
                {
                    // Kind of hacky but multiple part writing isn't implemented in commit changes yet
                    ark.CommitChanges(true);
                    ark.AddAdditionalPart();

                    currentPartSize = 0;
                }

                var fileName = Path.GetFileName(internalPath);
                var dirPath  = Path.GetDirectoryName(internalPath).Replace("\\", "/");

                var pendingEntry = new PendingArkEntry(fileName, dirPath)
                {
                    LocalFilePath = inputFilePath
                };

                ark.AddPendingEntry(pendingEntry);
                Console.WriteLine($"Added {pendingEntry.FullPath}");

                currentPartSize += fileSize;
            }

            ark.CommitChanges(true);
            Console.WriteLine($"Wrote hdr to \"{hdrPath}\"");
        }
Пример #7
0
        public IActionResult ExtractFilesFromArk([FromBody] ScanRequest request, bool extractMilos, bool extractDTAs, bool convertTextures)
        {
            Archive ark;

            if (!System.IO.File.Exists(request.InputPath))
            {
                // Open as directory if available
                if (Directory.Exists(request.InputPath))
                {
                    ark = ArkFileSystem.FromDirectory(request.InputPath);
                }
                else
                {
                    return(BadRequest($"File \"{request.InputPath}\" does not exist!"));
                }
            }
            else
            {
                // Open as archive
                ark = ArkFile.FromFile(request.InputPath);
            }


            if (request.OutputPath == null)
            {
                return(BadRequest($"Output directory cannot be null!"));
            }

            string CombinePath(string basePath, string path)
            {
                // Consistent slash
                basePath = (request.OutputPath ?? "").Replace("/", "\\");
                path     = (path ?? "").Replace("/", "\\");

                Regex dotRegex = new Regex(@"[.]+[\\]");

                if (dotRegex.IsMatch(path))
                {
                    // Replaces dotdot path
                    path = dotRegex.Replace(path, x => $"({x.Value.Substring(0, x.Value.Length - 1)})\\");
                }

                return(Path.Combine(basePath, path));
            }

            string GetNonGenPath(string path)
            {
                // Consistent slash
                path = (path ?? "").Replace("/", "\\");

                Regex genRegex      = new Regex(@"gen\\[^\\]+$", RegexOptions.IgnoreCase);
                Regex platformRegex = new Regex(@"_[^_]+$", RegexOptions.IgnoreCase); // TODO: Revisit for Forge extensions

                if (genRegex.IsMatch(path))
                {
                    var splitPath = path.Split('\\');
                    var dir       = string.Join("\\", splitPath.SkipLast(2));
                    var file      = platformRegex.Replace(splitPath.Last(), "");

                    path = $"{dir}\\{file}";
                }

                return(path);
            }

            void SaveAsFile(MiloObjectBytes miloEntry, string basePath)
            {
                var fileName = SanitizeFileName(miloEntry.Name);
                var filePath = basePath = Path.Combine(basePath, miloEntry.Type, fileName);

                if (!Directory.Exists(Path.GetDirectoryName(filePath)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(filePath));
                }

                System.IO.File.WriteAllBytes(filePath, miloEntry.Data);
                Console.WriteLine($"Wrote \"{filePath}\"");
            }

            // Extract everything
            if (!extractDTAs && !extractMilos && !convertTextures)
            {
                foreach (var arkEntry in ark.Entries)
                {
                    var filePath = CombinePath(request.OutputPath, arkEntry.FullPath);

                    if (!Directory.Exists(Path.GetDirectoryName(filePath)))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(filePath));
                    }

                    using (var fs = System.IO.File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
                    {
                        using (var stream = ark.GetArkEntryFileStream(arkEntry))
                        {
                            stream.CopyTo(fs);
                        }
                    }

                    Console.WriteLine($"Wrote \"{filePath}\"");
                }

                return(Ok());
            }

            string SanitizeFileName(string fileName)
            {
                // Sanitize file name
                var invalidChars = new Regex($"[{new string(Path.GetInvalidFileNameChars())}]", RegexOptions.IgnoreCase);

                return(invalidChars.Replace(fileName, ""));
            }

            void ProcessMiloArkEntry(ArkEntry miloArkEntry)
            {
                var filePath = CombinePath(request.OutputPath, GetNonGenPath(miloArkEntry.FullPath));

                using (var stream = ark.GetArkEntryFileStream(miloArkEntry))
                {
                    var milo           = MiloFile.ReadFromStream(stream);
                    var miloSerializer = new MiloSerializer(new SystemInfo()
                    {
                        Version   = milo.Version,
                        BigEndian = milo.BigEndian,
                        Platform  = Enum.Parse <Platform>(request.Platform)
                    });

                    var miloDir = new MiloObjectDir();
                    using (var ms = new MemoryStream(milo.Data))
                    {
                        miloSerializer.ReadFromStream(ms, miloDir);
                    }

                    if (convertTextures)
                    {
                        var textureEntries = miloDir.Entries
                                             .Where(x => x.Type == "Tex")
                                             .Select(x => x is Tex ? x as Tex : miloSerializer.ReadFromMiloObjectBytes <Tex>(x as MiloObjectBytes))
                                             .Where(x => x.Bitmap != null && x.Bitmap.RawData?.Length > 0)
                                             .ToList();

                        if (textureEntries.Count <= 0)
                        {
                            return;
                        }

                        foreach (var texEntry in textureEntries)
                        {
                            var entryName = Path.GetFileNameWithoutExtension(SanitizeFileName(texEntry.Name));

                            var pngName = $"{entryName}.png";
                            var pngPath = Path.Combine(filePath, texEntry.Type, pngName);
                            texEntry.Bitmap.SaveAs(miloSerializer.Info, pngPath);

                            Console.WriteLine($"Wrote \"{pngPath}\"");

                            // Write DTA script to file
                            var scriptName = texEntry?.ScriptName ?? "";
                            if (texEntry.Script != null)
                            {
                                var dtaName = (string.IsNullOrEmpty(scriptName))
                                    ? $"{entryName}.dta"
                                    : $"{entryName}_{scriptName}.dta";

                                var dtaPath = Path.Combine(filePath, texEntry.Type, dtaName);

                                var parent = new ParentItem(ParentType.Default);
                                foreach (var item in texEntry.Script.Items)
                                {
                                    parent.Add(item);
                                }

                                texEntry.Script.Items.Clear();
                                texEntry.Script.Items.Add(parent);

                                System.IO.File.WriteAllText(dtaPath, texEntry.Script.ToString());
                                Console.WriteLine($"Wrote \"{dtaPath}\"");
                            }
                        }
                    }

                    if (extractMilos)
                    {
                        if (miloDir.Entries.Count <= 0)
                        {
                            return;
                        }

                        if (!Directory.Exists(Path.GetDirectoryName(filePath)))
                        {
                            Directory.CreateDirectory(Path.GetDirectoryName(filePath));
                        }

                        // Saves milo entries
                        miloDir.Entries.ForEach(x =>
                        {
                            SaveAsFile(x as MiloObjectBytes, filePath);
                            Console.WriteLine($"Wrote \"{filePath}\"");
                        });

                        if (miloDir.Extras.ContainsKey("DirectoryEntry"))
                        {
                            SaveAsFile(miloDir.Extras["DirectoryEntry"] as MiloObjectBytes, filePath);
                            Console.WriteLine($"Wrote \"{filePath}\"");
                        }
                    }
                }
            }

            void ProcessBitmapArkEntry(ArkEntry bitmapArkEntry)
            {
                var arkPath  = GetNonGenPath(bitmapArkEntry.FullPath);
                var filePath = CombinePath(request.OutputPath, $"{Path.GetDirectoryName(arkPath)}\\{Path.GetFileNameWithoutExtension(bitmapArkEntry.FileName)}.png");

                using (var stream = ark.GetArkEntryFileStream(bitmapArkEntry))
                {
                    var miloSerializer = new MiloSerializer(new SystemInfo()
                    {
                        Version   = 25,    // 10 = gh1, 24 = gh2
                        BigEndian = false, // Even on PPC it's LE
                        Platform  = Enum.Parse <Platform>(request.Platform)
                    });

                    var bitmap = miloSerializer.ReadFromStream <HMXBitmap>(stream);
                    bitmap.SaveAs(miloSerializer.Info, filePath);
                    Console.WriteLine($"Wrote \"{filePath}\"");
                }
            }

            // Extract milos
            if (extractMilos || convertTextures)
            {
                var miloEntries = ark.Entries.Where(x => _miloRegex.IsMatch(x.FullPath));

                Parallel.ForEach(miloEntries, (entry) =>
                {
                    ProcessMiloArkEntry(entry);
                });

                //foreach (var entry in miloEntries) ProcessMiloArkEntry(entry);
            }

            // Convert textures
            if (convertTextures)
            {
                var bitmapArkEntries = ark.Entries.Where(x => _bitmapRegex.IsMatch(x.FullPath));

                Parallel.ForEach(bitmapArkEntries, (entry) =>
                {
                    ProcessBitmapArkEntry(entry);
                });

                //foreach (var entry in bitmapArkEntries) ProcessBitmapArkEntry(entry);
            }

            return(Ok());
        }
Пример #8
0
        public IActionResult ScanArkPost([FromBody] ScanRequest request)
        {
            _miloContext.Database.EnsureCreated();
            var sw = Stopwatch.StartNew();

            // Updates games (arks)
            var game = _miloContext.Arks.FirstOrDefault(x => x.Title == request.GameTitle &&
                                                        x.Platform == request.Platform &&
                                                        x.Region == request.Region);

            if (game == null)
            {
                // Create game
                game = new Data.MiloEntities.Ark()
                {
                    Title    = request.GameTitle,
                    Platform = request.Platform,
                    Region   = request.Region
                };

                _miloContext.Arks.Add(game);
                _miloContext.SaveChanges();
            }

            var ark = ArkFile.FromFile(request.InputPath);

            game.ArkVersion = (int)ark.Version;
            var miloEntries      = new List <Data.MiloEntities.ArkEntry>();
            var totalMiloEntries = 0;

            // Updates ark entries
            foreach (var arkEntry in ark.Entries)
            {
                var entry = arkEntry as OffsetArkEntry;

                var contextEntry = _miloContext.ArkEntries.FirstOrDefault(x => x.Ark == game && x.Path == entry.FullPath);
                if (contextEntry == null)
                {
                    contextEntry = new Data.MiloEntities.ArkEntry()
                    {
                        Ark  = game,
                        Path = entry.FullPath
                    };

                    _miloContext.ArkEntries.Add(contextEntry);
                    _miloContext.SaveChanges();
                }

                contextEntry.Part         = entry.Part;
                contextEntry.Offset       = entry.Offset;
                contextEntry.Size         = (int)entry.Size;
                contextEntry.InflatedSize = (int)entry.InflatedSize;

                if (_miloRegex.IsMatch(contextEntry.Path))
                {
                    miloEntries.Add(contextEntry);
                }

                _miloContext.Update(contextEntry);
            }

            // Updates milos
            foreach (var miloEntry in miloEntries)
            {
                var arkEntry   = ark.Entries.First(x => x.FullPath == miloEntry.Path);
                var mf         = MiloFile.ReadFromStream(ark.GetArkEntryFileStream(arkEntry));
                var serializer = new MiloSerializer(new SystemInfo()
                {
                    BigEndian = mf.BigEndian, Version = mf.Version
                });
                MiloObjectDir milo;


                using (var ms = new MemoryStream(mf.Data))
                {
                    milo = serializer.ReadFromStream <MiloObjectDir>(ms);
                }

                totalMiloEntries += milo.Entries.Count;

                var contextEntry = _miloContext.Milos.FirstOrDefault(x => x.ArkEntry == miloEntry);
                if (contextEntry == null)
                {
                    contextEntry = new Data.MiloEntities.Milo()
                    {
                        ArkEntry = miloEntry
                    };

                    _miloContext.Milos.Add(contextEntry);
                    _miloContext.SaveChanges();
                }

                contextEntry.Version   = mf.Version;
                contextEntry.TotalSize = mf.Data.Length;

                contextEntry.Name = milo.Name ?? "";
                contextEntry.Type = milo.Type ?? "";

                var dirEntry = milo.Entries
                               .Where(x => ((string)x.Type).EndsWith("Dir") && x is MiloObjectBytes)
                               .Select(x => x as MiloObjectBytes)
                               .FirstOrDefault();

                if (dirEntry != null)
                {
                    contextEntry.Size  = dirEntry.Data.Length;
                    contextEntry.Magic = dirEntry.GetMagic();
                }
                else
                {
                    contextEntry.Size  = -1;
                    contextEntry.Magic = -1;
                }

                // Updates milo entries
                foreach (var mEntry in milo.Entries.Where(x => x is MiloObjectBytes && x != dirEntry).Select(y => y as MiloObjectBytes))
                {
                    var contextMEntry = _miloContext.MiloEntries.FirstOrDefault(x => x.Milo == contextEntry && x.Name == mEntry.Name && x.Type == mEntry.Type);
                    if (contextMEntry == null)
                    {
                        contextMEntry = new Data.MiloEntities.MiloEntry()
                        {
                            Milo = contextEntry
                        };

                        _miloContext.MiloEntries.Add(contextMEntry);
                        _miloContext.SaveChanges();
                    }

                    contextMEntry.Name  = mEntry.Name ?? "";
                    contextMEntry.Type  = mEntry.Type ?? "";
                    contextMEntry.Size  = mEntry.Data.Length;
                    contextMEntry.Magic = mEntry.GetMagic();

                    _miloContext.Update(contextMEntry);
                }

                _miloContext.Update(contextEntry);
            }

            _miloContext.SaveChanges();
            sw.Stop();

            return(Ok(new ScanResult()
            {
                TotalArkEntries = ark.Entries.Count,
                TotalMilos = miloEntries.Count,
                TotalMiloEntries = totalMiloEntries,
                TimeElapsed = sw.ElapsedMilliseconds
            }));
        }
Пример #9
0
        public void Parse(Ark2DirOptions op)
        {
            var scriptRegex      = new Regex("(?i).((dtb)|(dta)|(([A-Z]+)(_dta_)([A-Z0-9]+)))$");
            var scriptForgeRegex = new Regex("(?i)(_dta_)([A-Z0-9]+)$");
            var csvRegex         = new Regex("(?i).csv_([A-Z0-9]+)$");

            var dtaRegex     = new Regex("(?i).dta$");
            var textureRegex = new Regex("(?i).((bmp)|(png))(_[A-Z0-9]+)$");
            var miloRegex    = new Regex("(?i).((gh)|(milo)|(rnd))(_[A-Z0-9]+)?$");

            var genPathedFile    = new Regex(@"(?i)(([^\/\\]+[\/\\])*)(gen[\/\\])([^\/\\]+)$");
            var platformExtRegex = new Regex(@"(?i)_([A-Z0-9]+)$");

            Archive ark;
            int     arkVersion;
            bool    arkEncrypted;

            if (Directory.Exists(op.InputPath))
            {
                // Open as directory
                ark = ArkFileSystem.FromDirectory(op.InputPath);

                // TODO: Get from args probably
                arkVersion   = 10;
                arkEncrypted = true;
            }
            else
            {
                // Open as ark
                var arkFile = ArkFile.FromFile(op.InputPath);
                arkVersion   = (int)arkFile.Version;
                arkEncrypted = arkFile.Encrypted;

                ark = arkFile;
            }

            var scriptsToConvert = ark.Entries
                                   .Where(x => op.ConvertScripts &&
                                          arkVersion >= 3 && // Amp dtbs not supported right now
                                          scriptRegex.IsMatch(x.FullPath))
                                   .ToList();

            var csvsToConvert = ark.Entries
                                .Where(x => op.ConvertScripts &&
                                       csvRegex.IsMatch(x.FullPath))
                                .ToList();

            var texturesToConvert = ark.Entries
                                    .Where(x => op.ConvertTextures &&
                                           textureRegex.IsMatch(x.FullPath))
                                    .ToList();

            var milosToInflate = ark.Entries
                                 .Where(x => op.InflateMilos &&
                                        !op.ExtractMilos &&
                                        miloRegex.IsMatch(x.FullPath))
                                 .ToList();

            var milosToExtract = ark.Entries
                                 .Where(x => op.ExtractMilos &&
                                        miloRegex.IsMatch(x.FullPath))
                                 .ToList();

            var entriesToExtract = ark.Entries
                                   .Where(x => op.ExtractAll)
                                   .Except(scriptsToConvert)
                                   .Except(texturesToConvert)
                                   .Except(milosToInflate)
                                   .ToList();

            foreach (var arkEntry in entriesToExtract)
            {
                var filePath = ExtractEntry(ark, arkEntry, CombinePath(op.OutputPath, arkEntry.FullPath));
                Console.WriteLine($"Wrote \"{filePath}\"");
            }

            // Create temp path
            var tempDir = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));

            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }

            foreach (var textureEntry in texturesToConvert)
            {
                using var arkEntryStream = ark.GetArkEntryFileStream(textureEntry);

                var filePath = CombinePath(op.OutputPath, textureEntry.FullPath);
                var pngPath  = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(filePath)), Path.GetFileNameWithoutExtension(filePath) + ".png");

                // Removes gen sub directory
                if (genPathedFile.IsMatch(pngPath))
                {
                    var match = genPathedFile.Match(pngPath);
                    pngPath = $"{match.Groups[1]}{match.Groups[4]}";
                }

                var info = new SystemInfo()
                {
                    Version   = 10,
                    Platform  = Platform.PS2,
                    BigEndian = false
                };

                var serializer = new MiloSerializer(info);
                var bitmap     = serializer.ReadFromStream <HMXBitmap>(arkEntryStream);

                bitmap.SaveAs(info, pngPath);
                Console.WriteLine($"Wrote \"{pngPath}\"");
            }

            foreach (var miloEntry in milosToInflate)
            {
                var filePath = ExtractEntry(ark, miloEntry, CombinePath(op.OutputPath, miloEntry.FullPath));

                // Inflate milo
                var milo = MiloFile.ReadFromFile(filePath);
                milo.Structure = BlockStructure.MILO_A;
                milo.WriteToFile(filePath);

                Console.WriteLine($"Wrote \"{filePath}\"");
            }

            foreach (var miloEntry in milosToExtract)
            {
                var filePath = ExtractEntry(ark, miloEntry, CombinePath(op.OutputPath, miloEntry.FullPath));
                var dirPath  = Path.GetDirectoryName(filePath);

                var tempPath = filePath + "_temp";
                File.Move(filePath, tempPath, true);

                var extPath = Path.Combine(
                    Path.GetDirectoryName(filePath),
                    Path.GetFileName(filePath));

                var state = new AppState(dirPath);
                state.ExtractMiloContents(
                    Path.GetFileName(tempPath),
                    extPath,
                    op.ConvertTextures);

                // TODO: Refactor IDirectory and remove temp file write/delete
                File.Delete(tempPath);

                Console.WriteLine($"Wrote \"{extPath}\"");
            }

            foreach (var csvEntry in csvsToConvert)
            {
                var csvStream = ark.GetArkEntryFileStream(csvEntry);
                var csv       = CSVFile.FromForgeCSVStream(csvStream);

                // Write to file
                var csvPath = CombinePath(op.OutputPath, csvEntry.FullPath);
                csvPath = platformExtRegex.Replace(csvPath, "");

                csv.SaveToFileAsCSV(csvPath);
                Console.WriteLine($"Wrote \"{csvPath}\"");
            }

            var successDtas = 0;

            foreach (var scriptEntry in scriptsToConvert)
            {
                // Just extract file if dta script
                if (dtaRegex.IsMatch(scriptEntry.FullPath))
                {
                    var filePath = ExtractEntry(ark, scriptEntry, CombinePath(op.OutputPath, scriptEntry.FullPath));
                    Console.WriteLine($"Wrote \"{filePath}\"");
                    continue;
                }

                // Creates output path
                var dtaPath = CombinePath(op.OutputPath, scriptEntry.FullPath);
                dtaPath = !scriptForgeRegex.IsMatch(dtaPath)
                    ? $"{dtaPath.Substring(0, dtaPath.Length - 1)}a" // Simply change b -> a
                    : scriptForgeRegex.Replace(dtaPath, "");

                // Removes gen sub directory
                if (genPathedFile.IsMatch(dtaPath))
                {
                    var match = genPathedFile.Match(dtaPath);
                    dtaPath = $"{match.Groups[1]}{match.Groups[4]}";
                }

                var tempDtbPath = ExtractEntry(ark, scriptEntry, Path.Combine(tempDir, Path.GetRandomFileName()));

                try
                {
                    ScriptHelper.ConvertDtbToDta(tempDtbPath, tempDir, arkEncrypted, arkVersion, dtaPath, op.IndentSize);
                    Console.WriteLine($"Wrote \"{dtaPath}\"");
                    successDtas++;
                }
                catch (DTBParseException ex)
                {
                    Console.WriteLine($"Unable to convert to script, skipping \'{scriptEntry.FullPath}\'");
                    if (File.Exists(dtaPath))
                    {
                        File.Delete(dtaPath);
                    }
                }
                catch (Exception ex)
                {
                }
            }

            if (scriptsToConvert.Count > 0)
            {
                Console.WriteLine($"Converted {successDtas} of {scriptsToConvert.Count} scripts");
            }

            // Clean up temp files
            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }
        }