static void Extract(ExtractOptions options) { var datFile = File.ReadAllBytes(options.File); var jsonFile = JsonDatFile.FromFile(options.JsonPath); Directory.CreateDirectory(options.OutputFolder); var datSpan = datFile.AsSpan(); foreach (var entry in jsonFile.Files) { var filePath = Path.Combine(options.OutputFolder, entry.Name); // Check if first and last byte are within file size. if (entry.Offset > datFile.Length || entry.Offset + entry.SizeBytes > datFile.Length) { Console.WriteLine($"Warning: Skipping file {filePath} because the start or end of file is outside of the archive."); continue; } // Write file using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write); fileStream.Write(datSpan.Slice(entry.Offset, entry.SizeBytes)); Console.WriteLine($"Written File {filePath}."); } }
static void Pack(PackOptions options) { var data = new List <byte>(150 * 1000 * 1000); var files = Directory.GetFiles(options.SourceFolder).ToDictionary(Path.GetFileName, StringComparer.OrdinalIgnoreCase); var originalJsonFile = JsonDatFile.FromFile(options.SourceJson); var jsonFile = new JsonDatFile(); Directory.CreateDirectory(Path.GetDirectoryName(options.JsonPath)); Directory.CreateDirectory(Path.GetDirectoryName(options.DatPath)); foreach (var origFile in originalJsonFile.Files) { if (files.TryGetValue(origFile.Name, out var file)) { var fileBytes = File.ReadAllBytes(file); int currentOffset = data.Count; var fileEntry = new JsonFileEntry(Path.GetFileName(file), fileBytes.Length, currentOffset); data.AddRange(fileBytes); jsonFile.Files.Add(fileEntry); data.AddPadding(2048); } } // Save (Note: Using FileStream to avoid copying large array) File.WriteAllText(options.JsonPath, jsonFile.ToFile()); using var fileStream = new FileStream(options.DatPath, FileMode.Create); fileStream.Write(CollectionsMarshal.AsSpan(data)); Console.WriteLine($"JSON file for injection written to: {options.JsonPath}"); Console.WriteLine($"New DAT file written to: {options.DatPath}"); }
static unsafe void Inject(InjectOptions options) { var elf = File.ReadAllBytes(options.File); var scanner = new DatScanner(elf); var files = scanner.FindFiles(options.Dat); var jsonFile = JsonDatFile.FromFile(options.JsonPath); using var memoryStream = new MemoryStream(elf, true); using var streamReader = new BufferedStreamReader(memoryStream, 2048); using var extendedMemoryStream = new ExtendedMemoryStream(elf, true); // Patch all table entries. foreach (var offset in files.Keys) { Console.WriteLine($"Patching table at: {offset:X}, RAM: {scanner.RawToMemoryAddress(offset):X}"); // Go to 2nd entry and get initial file name write pointer. streamReader.Seek(offset, SeekOrigin.Begin); streamReader.Read(out DatFileEntry firstEntry); // Get file name write pointer. streamReader.Peek(out DatFileEntry secondEntry); int fileNameWritePointer = scanner.MemoryToRawAddress(secondEntry.NamePtr); // Write archive entry var newFirstEntry = new DatFileEntry(firstEntry.NamePtr, jsonFile.Files[0].Offset / DatFileEntry.SECTOR_SIZE_BYTES, jsonFile.Files[0].SizeBytes); extendedMemoryStream.Seek(offset, SeekOrigin.Begin); extendedMemoryStream.Write(newFirstEntry); // Now write each file in order, while keeping track of the pointer. foreach (var entry in jsonFile.Files) { // Make entry for the file. var datEntry = new DatFileEntry(scanner.RawToMemoryAddress(fileNameWritePointer), entry.Offset / DatFileEntry.SECTOR_SIZE_BYTES, entry.SizeBytes); extendedMemoryStream.Write(datEntry); // Get bytes attached to the name (w/ Null Terminator). var alignedTextLength = Utilities.Utilities.RoundUp(entry.Name.Length + 1, 8); // Alignment of 8 var nameBytes = new byte[alignedTextLength]; Encoding.ASCII.GetBytes(entry.Name, nameBytes); // Write bytes to pointer. Array.Copy(nameBytes, 0, elf, fileNameWritePointer, nameBytes.Length); // Align text to next predetermined value like in original ELF. fileNameWritePointer += alignedTextLength; } } // Write new executable to file. memoryStream.Dispose(); streamReader.Dispose(); extendedMemoryStream.Dispose(); Console.WriteLine($"Writing patched file to: {options.File}"); File.WriteAllBytes(options.File, elf); }
private static void Verify(VerifyOptions options) { var jsonFile = JsonDatFile.FromFile(options.JsonPath); var sourceFiles = Directory.GetFiles(options.SourceFolder).ToDictionary(Path.GetFileName, StringComparer.OrdinalIgnoreCase); foreach (var file in jsonFile.Files) { if (sourceFiles.TryGetValue(file.Name, out _)) { continue; } Console.WriteLine($"Missing File: {file.Name}"); } Console.WriteLine($"Verify Complete"); }