/// <summary> /// Reads the file indexes of the PSX executable /// </summary> /// <param name="executablePath">Path of the PSX executable</param> /// <param name="offset">Offset in the PSX executable where the file listing starts in bytes</param> /// <param name="length">Length of the file listing in bytes</param> public void LoadExecutable(string executablePath) { RippedExecutablePath = executablePath; FileDictionary.Offset = DictionaryOffset; FileDictionary.Length = DictionaryLength; byte[] listing = new byte[DictionaryLength]; using (BinaryReader reader = new BinaryReader(new FileStream(RippedExecutablePath, FileMode.Open))) { reader.BaseStream.Seek(DictionaryOffset, SeekOrigin.Begin); reader.Read(listing, 0, DictionaryLength); } for (int i = 0; i < DictionaryLength; i += 0x24) { byte[] entryData = new byte[0x24]; Array.Copy(listing, i, entryData, 0, 0x24); FileDictionary.Files.Add(new FileDictionaryFile(entryData)); } FileDictionary.SortFiles(); }
/// <summary> /// Saves the PSX executable with modified indexes to match the current game files /// </summary> public void SaveExecutable() { if (FileDictionary == null) { return; } uint counter = 24; string lastFolder = "BG"; foreach (FileDictionaryFile file in FileDictionary.Files) { if (lastFolder != file.Folder) { counter++; } lastFolder = file.Folder; if (file.IsInsidePkn) { string fileName = RippedDirectory + "\\" + file.Folder + "\\" + file.FullPath; FileInfo fileInfo = new FileInfo(fileName); file.Offset = counter; file.Length = (uint)fileInfo.Length / 2048; uint modLength = (uint)fileInfo.Length % 2048; if (modLength != 0) { file.Length++; } if (!IgnoreMemoryOptimization) { file.SectorOverhead = DisableMemoryOptimization ? 0 : modLength / 4; } counter += file.Length; } else { string fileName = RippedDirectory + file.FullPath; FileInfo fileInfo = new FileInfo(fileName); if (fileInfo.Length % 2336 != 0) { if (MessageBox.Show(String.Format("The file \"{0}\" does not have the correct size.\n Do you want to add zero padding?", fileInfo.FullName), "Incorrect Size!", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { long rest = 2336 - fileInfo.Length % 2336; using (BinaryWriter writer = new BinaryWriter(new FileStream(fileName, FileMode.Append, FileAccess.Write))) { for (int i = 0; i < rest; i++) { writer.Write('\0'); } } fileInfo = new FileInfo(fileName); } else { MessageBox.Show("The build process was cancelled!", "Build process cancelled!"); return; } //MessageBox.Show(String.Format("The file \"{0}\" does not have the correct size.", fileInfo.FullName)); //return; } file.Offset = counter; file.Length = (uint)fileInfo.Length / 2336; counter += file.Length; } } FileDictionary.SortFiles(); using (BinaryWriter writer = new BinaryWriter(new FileStream(RippedExecutablePath, FileMode.Open))) { writer.BaseStream.Seek(FileDictionary.Offset, SeekOrigin.Begin); foreach (FileDictionaryFile file in FileDictionary.Files) { writer.Write(file.GetBytes()); } int CodeCaveSegment = 585512; //Apply Assembler patches (write as single hex because of endianess) //Patch 01 - Allow sjis 2+1 more char in GMAP "school" string writer.BaseStream.Seek(0x03D5CB, SeekOrigin.Begin); writer.Write((byte)0x24); writer.Write((byte)0x03); writer.BaseStream.Seek(0x03D5D0, SeekOrigin.Begin); writer.Write((byte)0xA8); writer.Write((byte)0x03); //Patch 02 - Mod save string to way longer (Speichern) //Move pointer a code cave ("old seq data" printf strings 1/2) writer.BaseStream.Seek(0x0375F8, SeekOrigin.Begin); writer.Write(new byte[] { 0x01, 0x80, 0x04, 0x3C, 0xC4, 0x69, 0x84, 0x24 }); //nop out the lib printf part writer.BaseStream.Seek(0x6BCB4, SeekOrigin.Begin); writer.Write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //Patch 03 - Move pointer (gmap wohnheim) to a code cave ("old seq data" printf string 2/2) writer.BaseStream.Seek(0x03D630, SeekOrigin.Begin); writer.Write(new byte[] { 0x01, 0x80, 0x04, 0x3C, 0xD0, 0x69, 0x84, 0x24 }); //Patch 03.1 writer.BaseStream.Seek(685204, SeekOrigin.Begin); writer.Write(new byte[] { 0x44, 0x45, 0x52, 0x50, 0x4c, 0x41, 0x59, 0x45, 0x52, 0x20, 0x57, 0x41, 0x53, 0x20, 0x48, 0x45, 0x52, 0x45 }); //Patch 04 - Resize the GMAP Draw area for text (0x70 is the hardware limit for width) //We increase the draw rectangle with for one more char writer.BaseStream.Seek(0xF944, SeekOrigin.Begin); writer.Write((byte)0x30); //0x40->0x30 //We overwrite (8001F288 move $a3, $zero) to change the width register back for the other rectangles //Should not crash or cause the game to be unstable, but never say never (should be tested on real hardware later) //alternative for this is the usage of the t2 register (but value is over 0x70, so not tested) writer.BaseStream.Seek(0xF988, SeekOrigin.Begin); writer.Write(new byte[] { 0x40, 0x00, 0x14, 0x24 }); //0x30->0x40 //Patch 05 - Increase the chars in buffer for GMAP draw area (CPU) writer.BaseStream.Seek(0x03D638, SeekOrigin.Begin); writer.Write((byte)0x05); //0x03->0x05 byte libsegptr = 0x28; //dehnen - 584152 - orginal hex: A4 6C 0B 80 //wasser - 584156 - orginal hex: C4 3F 01 80 //stein - 584188 - orginal hex: 3C 3F 01 80 //aufricht - 584208 - orginal hex: 9C 6C 0B 80 //binden - 584212 - orginal hex: 94 6C 0B 80 //Patch 06.1 - Move minigame label pointer (dehnen) to a code cave (sony lib header text) writer.BaseStream.Seek(584152, SeekOrigin.Begin); writer.Write(new byte[] { libsegptr, 0xE7, 0x09, 0x80 }); libsegptr += 12; //Patch 06.2 - Move minigame label pointer (wasser) to a code cave (sony lib header text) writer.BaseStream.Seek(584156, SeekOrigin.Begin); writer.Write(new byte[] { libsegptr, 0xE7, 0x09, 0x80 }); libsegptr += 22; //Patch 06.3 - Move minigame label pointer (stein) to a code cave (sony lib header text) writer.BaseStream.Seek(584188, SeekOrigin.Begin); writer.Write(new byte[] { libsegptr, 0xE7, 0x09, 0x80 }); libsegptr += 22; //Patch 06.4 - Move minigame label pointer (aufricht) to a code cave (sony lib header text) writer.BaseStream.Seek(584208, SeekOrigin.Begin); writer.Write(new byte[] { libsegptr, 0xE7, 0x09, 0x80 }); libsegptr += 12; //Patch 06.5 - Move minigame label pointer (aufricht) to a code cave (sony lib header text) writer.BaseStream.Seek(584212, SeekOrigin.Begin); writer.Write(new byte[] { libsegptr, 0xE7, 0x09, 0x80 }); libsegptr += 16; //---------- //Patch 0x - dialog color for minigame 3 (totally useless ;) //writer.BaseStream.Seek(0x057AFC, SeekOrigin.Begin); //writer.Write((byte)0xA); //Blue 0x02, Red 0x04, Yellow 0x06 } }