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); }
public FileListItem(DatFileEntry entry) { Entry = entry; UseItemStyleForSubItems = false; nameItem = SubItems.Add(new ListViewSubItem()); typeItem = SubItems.Add(new ListViewSubItem()); sizeItem = SubItems.Add(new ListViewSubItem()); sizeItem.Font = new System.Drawing.Font("Consolas", 10); switch (entry.Type) { case DatFileEntry.DataType.Image: BackColor = Color.FromArgb(255, 220, 255, 220); break; case DatFileEntry.DataType.Map: BackColor = Color.FromArgb(255, 220, 220, 255); break; case DatFileEntry.DataType.Music: BackColor = Color.FromArgb(255, 255, 255, 220); break; case DatFileEntry.DataType.SoundFX: BackColor = Color.FromArgb(255, 255, 255, 180); break; case DatFileEntry.DataType.SpeakerSound: BackColor = Color.FromArgb(255, 255, 255, 140); break; case DatFileEntry.DataType.Sprite: BackColor = Color.FromArgb(255, 180, 255, 180); break; case DatFileEntry.DataType.Text: BackColor = Color.FromArgb(255, 220, 220, 220); break; case DatFileEntry.DataType.Unknown: default: BackColor = Color.FromArgb(255, 255, 0, 0); break; } updateCaptions(); }
public EditForm(Game game, DatFileEntry entry) { InitializeComponent(); Entry = entry; this.game = game; hexBox = new HexBox(); hexBox.Width = hexPanel.Width; hexBox.Height = hexPanel.Height; hexBox.ByteProvider = new DynamicByteProvider(entry.Data); hexBox.GroupSize = 4; hexBox.Dock = DockStyle.Fill; hexBox.GroupSeparatorVisible = true; hexBox.VScrollBarVisible = true; hexBox.LineInfoVisible = true; hexPanel.Controls.Add(hexBox); }
/// <summary> /// Creates a new Json entry given a DAT file entry. /// </summary> public JsonFileEntry(DatFileEntry entry, BufferedStreamReader stream, Func <int, int> memoryToRawAddress) { Name = entry.GetName(stream, memoryToRawAddress); SizeBytes = entry.SizeBytes; Offset = entry.Sector * DatFileEntry.SECTOR_SIZE_BYTES; }
private void showFileDetails(DatFileEntry entry) { selectionLabel.Text = ""; detailsStatusLabel.Text = ""; cursorStatusLabel.Text = ""; currentBitmap = null; currentSprite = null; currentMap = null; canvasPanel.Visible = false; detailsTextBox.Visible = false; pngButton.Visible = false; mapButtonsPanel.Visible = false; frameSelectionPanel.Visible = false; cmfPlayerPanel.Visible = false; stopMusicPlayback(); vocPlayerPanel.Visible = false; currentSpriteFrame = 0; if (entry == null) return; selectionLabel.Text = "[" + entry.TypeString.ToUpper() + "] " + Path.GetFileName(Game.ArchiveFile) + " / " + entry.Filename; switch(entry.Type) { case DatFileEntry.DataType.Sprite: currentSprite = entry.GetSprite(game.MainPalette); if (currentSprite == null) { MessageBox.Show("Failed to load sprite"); return; } currentBitmap = currentSprite.Frames[0]; detailsStatusLabel.Text = $"Frame size: {currentBitmap.Width}x{currentBitmap.Height}"; if (currentSprite.Frames.Length > 1) { frameSelectionPanel.Visible = true; frameLabel.Text = "1/" + currentSprite.Frames.Length; currentSpriteFrame = 0; } pngButton.Visible = true; canvasPanel.Visible = true; break; case DatFileEntry.DataType.Image: try { PcxFile pcx = entry.GetPicture(); currentBitmap = pcx.Bitmap; detailsStatusLabel.Text = $"Image size: {currentBitmap.Width}x{currentBitmap.Height}"; pngButton.Visible = true; canvasPanel.Visible = true; } catch (Exception e) { MessageBox.Show("Failed to convert from PCX to bitmap: " + e.Message, "Conversion failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } break; case DatFileEntry.DataType.Map: currentMap = entry.GetMap(); if (currentMap == null) { MessageBox.Show("Failed to load map"); return; } Game.MapInfo info = Game.InfoByFilename(currentMap.Entry.Filename); selectionLabel.Text += $" - \"{info.Title}\""; detailsStatusLabel.Text = $"Size: {currentMap.Width}x{currentMap.Height}, Password: \"{info.Password}\", Music: {info.Music}"; mapButtonsPanel.Visible = true; canvasPanel.Visible = true; break; case DatFileEntry.DataType.Music: try { startMusicPlayback(entry.Data); } catch (Exception e) { MessageBox.Show("Failed to load CMF music: " + e.Message, "Audio failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } break; case DatFileEntry.DataType.SoundFX: currentVoc = new VocFile(entry.Data); int sec = (int)Math.Ceiling(currentVoc.SecDuration); vocTimeLabel.Text = (sec / 60).ToString("D2") + ":" + (sec % 60).ToString("D2") + " @ " + currentVoc.samplerate + " Hz (" + currentVoc.format + ")"; vocPlayerPanel.Visible = true; break; case DatFileEntry.DataType.Text: detailsTextBox.Text = entry.GetText(); detailsTextBox.Visible = true; break; } draw(); }