public void Dispose() { if (m_should_dispose && !_disposed) { m_file.Dispose(); _disposed = true; } }
public override ArcFile TryOpen(ArcView file) { var name = Path.GetFileName(file.Name); if (!NamePattern.IsMatch(name)) { return(null); } var match = NamePattern.Match(name); int name_id = 1; var num_str = match.Groups["num"].Value; if (!string.IsNullOrEmpty(num_str)) { name_id = Int32.Parse(num_str); } if (name_id < 1) { return(null); } ArcView index = file; try { if (name_id != 1) { string index_name; if (file.Name.HasExtension(".dat")) { index_name = VFS.ChangeFileName(file.Name, "0001.dat"); } else { index_name = VFS.ChangeFileName(file.Name, "data"); } if (!VFS.FileExists(index_name)) { return(null); } index = VFS.OpenView(index_name); } var dir = ReadIndex(index, name_id, file.MaxOffset); if (null == dir || 0 == dir.Count) { return(null); } return(new ArcFile(file, this, dir)); } finally { if (index != file) { index.Dispose(); } } }
protected override void Dispose(bool disposing) { if (!_vff_disposed) { if (disposing && ExtraFile != null) { ExtraFile.Dispose(); } _vff_disposed = true; } base.Dispose(disposing); }
public override ArcFile TryOpen(ArcView file) { var name = Path.GetFileName(file.Name); if (!NamePattern.IsMatch(name)) { return(null); } var match = NamePattern.Match(name); int name_id = Int32.Parse(match.Groups[1].Value); if (name_id < 1) { return(null); } ArcView index = file; try { if (name_id != 1) { var index_name = VFS.ChangeFileName(file.Name, "0001.dat"); if (!VFS.FileExists(index_name)) { return(null); } index = VFS.OpenView(index_name); } var dir = ReadIndex(index, name_id, file.MaxOffset); if (null == dir || 0 == dir.Count) { return(null); } return(new ArcFile(file, this, dir)); } finally { if (index != file) { index.Dispose(); } } }
public override void Create(Stream output, IEnumerable <Entry> list, ResourceOptions options, EntryCallback callback) { ArcFile base_archive = null; var ami_options = GetOptions <AmiOptions> (options); if (null != ami_options && ami_options.UseBaseArchive && !string.IsNullOrEmpty(ami_options.BaseArchive)) { var base_file = new ArcView(ami_options.BaseArchive); try { if (base_file.View.ReadUInt32(0) == Signature) { base_archive = TryOpen(base_file); } if (null == base_archive) { throw new InvalidFormatException(string.Format("{0}: base archive could not be read", Path.GetFileName(ami_options.BaseArchive))); } base_file = null; } finally { if (null != base_file) { base_file.Dispose(); } } } try { var file_table = new SortedDictionary <uint, PackedEntry>(); if (null != base_archive) { foreach (AmiEntry entry in base_archive.Dir) { file_table[entry.Id] = entry; } } int update_count = UpdateFileTable(file_table, list); if (0 == update_count) { throw new InvalidFormatException(arcStrings.AMINoFiles); } uint file_count = (uint)file_table.Count; if (null != callback) { callback((int)file_count + 1, null, null); } int callback_count = 0; long start_offset = output.Position; uint data_offset = file_count * 16 + 16; output.Seek(data_offset, SeekOrigin.Current); foreach (var entry in file_table) { if (null != callback) { callback(callback_count++, entry.Value, arcStrings.MsgAddingFile); } long current_offset = output.Position; if (current_offset > uint.MaxValue) { throw new FileSizeException(); } if (entry.Value is AmiEntry) { CopyAmiEntry(base_archive, entry.Value, output); } else { entry.Value.Size = WriteAmiEntry(entry.Value, output); } entry.Value.Offset = (uint)current_offset; } if (null != callback) { callback(callback_count++, null, arcStrings.MsgWritingIndex); } output.Position = start_offset; using (var header = new BinaryWriter(output, Encoding.ASCII, true)) { header.Write(Signature); header.Write(file_count); header.Write(data_offset); header.Write((uint)0); foreach (var entry in file_table) { header.Write(entry.Key); header.Write((uint)entry.Value.Offset); header.Write((uint)entry.Value.UnpackedSize); header.Write((uint)entry.Value.Size); } } } finally { if (null != base_archive) { base_archive.Dispose(); } } }
public override ArcFile TryOpen(ArcView file) { var match = s_ResNameRe.Match(file.Name); if (!match.Success || file.View.AsciiEqual(0, "AiFS")) { return(null); } var digits = match.Groups[1]; int arc_num = UInt16.Parse(digits.Value); int toc_num = arc_num - 1; int arc_index = 1; // number by which archive is referenced within toc file // look for toc file ArcView toc_file = null; var toc_name_sb = new StringBuilder(file.Name.Length); while (toc_num >= 0) { toc_name_sb.Clear(); toc_name_sb.Append(file.Name); toc_name_sb.Remove(digits.Index, digits.Length); toc_name_sb.Insert(digits.Index, toc_num.ToString("D4")); var toc_name = toc_name_sb.ToString(); if (!VFS.FileExists(toc_name)) { return(null); } toc_file = VFS.OpenView(toc_name); if (toc_file.View.AsciiEqual(0, "AiFS")) { break; } toc_file.Dispose(); toc_file = null; toc_num--; arc_index++; } if (null == toc_file) { return(null); } using (toc_file) { int res_count = toc_file.View.ReadInt32(0xC); if (res_count < arc_index) { return(null); } uint index_offset = 0x10; // find archive reference within toc file bool arc_found = false; for (int i = 0; i < res_count && index_offset < toc_file.MaxOffset; ++i) { int num = toc_file.View.ReadInt32(index_offset); if (0x01000000 == num) { index_offset += 4; num = toc_file.View.ReadInt32(index_offset); } if (num == arc_index) { arc_found = true; break; } uint entries = toc_file.View.ReadUInt32(index_offset + 0xC); index_offset += 0x10 + entries * 8; } if (!arc_found) { return(null); } int count = toc_file.View.ReadInt32(index_offset + 0xC); if (!IsSaneCount(count)) { return(null); } int start_index = toc_file.View.ReadInt32(index_offset + 4); index_offset += 0x10; var dir = new List <Entry> (count); for (int i = 0; i < count; ++i) { uint offset = toc_file.View.ReadUInt32(index_offset); uint size = toc_file.View.ReadUInt32(index_offset + 4); if (size != 0) { var entry = new Entry { Name = string.Format("{0:D5}.ogg", start_index + i), Type = "audio", Offset = offset, Size = size, }; entry.Offset = toc_file.View.ReadUInt32(index_offset); if (!entry.CheckPlacement(file.MaxOffset)) { return(null); } dir.Add(entry); } index_offset += 8; } if (0 == dir.Count) { return(null); } return(new ArcFile(file, this, dir)); } }
public override ArcFile TryOpen(ArcView file) { uint base_offset = 0; ArcView index_file = file; ArcView extra_file = null; try { // possible filesystem structure: // game.dat -- main archive body // game.001 -- [optional] extra part // game.ext -- [optional] separate index (could be included into the main body) uint signature = index_file.View.ReadUInt32(0); if (file.Name.HasExtension(".exe") && (0x5A4D == (signature & 0xFFFF))) // 'MZ' { base_offset = SkipExeData(index_file); signature = index_file.View.ReadUInt32(base_offset); } else if (!file.Name.HasExtension(".dat")) { return(null); } else if (0x666676 != signature) { var ext_filename = Path.ChangeExtension(file.Name, ".ext"); if (!VFS.FileExists(ext_filename)) { return(null); } index_file = VFS.OpenView(ext_filename); signature = index_file.View.ReadUInt32(0); } if (0x666676 != signature) { return(null); } int count = index_file.View.ReadInt32(base_offset + 6); if (!IsSaneCount(count)) { return(null); } var dir = ReadIndex(index_file, base_offset, count); if (null == dir) { return(null); } long max_offset = file.MaxOffset; for (int i = 0; i < dir.Count; ++i) { if (!dir[i].CheckPlacement(max_offset)) { if (extra_file != null) { // remove entries that don't fit into game.dat+game.001 int discard = dir.Count - i; Trace.WriteLine(string.Format("{0} entries didn't fit and were discarded", discard), "[vff]"); dir.RemoveRange(i, discard); break; } var extra_filename = Path.ChangeExtension(file.Name, ".001"); if (!VFS.FileExists(extra_filename)) { return(null); } extra_file = VFS.OpenView(extra_filename); max_offset += extra_file.MaxOffset; if (!dir[i].CheckPlacement(max_offset)) { return(null); } } } if (null == extra_file) { return(new ArcFile(file, this, dir)); } return(new VffArchive(file, this, dir, extra_file)); } catch { if (extra_file != null) { extra_file.Dispose(); } throw; } finally { if (index_file != file) { index_file.Dispose(); } } }
public override void Create(Stream output, IEnumerable<Entry> list, ResourceOptions options, EntryCallback callback) { ArcFile base_archive = null; var ami_options = GetOptions<AmiOptions> (options); if (null != ami_options && ami_options.UseBaseArchive && !string.IsNullOrEmpty (ami_options.BaseArchive)) { var base_file = new ArcView (ami_options.BaseArchive); try { if (base_file.View.ReadUInt32(0) == Signature) base_archive = TryOpen (base_file); if (null == base_archive) throw new InvalidFormatException (string.Format ("{0}: base archive could not be read", Path.GetFileName (ami_options.BaseArchive))); base_file = null; } finally { if (null != base_file) base_file.Dispose(); } } try { var file_table = new SortedDictionary<uint, PackedEntry>(); if (null != base_archive) { foreach (AmiEntry entry in base_archive.Dir) file_table[entry.Id] = entry; } int update_count = UpdateFileTable (file_table, list); if (0 == update_count) throw new InvalidFormatException (arcStrings.AMINoFiles); uint file_count = (uint)file_table.Count; if (null != callback) callback ((int)file_count+1, null, null); int callback_count = 0; long start_offset = output.Position; uint data_offset = file_count * 16 + 16; output.Seek (data_offset, SeekOrigin.Current); foreach (var entry in file_table) { if (null != callback) callback (callback_count++, entry.Value, arcStrings.MsgAddingFile); long current_offset = output.Position; if (current_offset > uint.MaxValue) throw new FileSizeException(); if (entry.Value is AmiEntry) CopyAmiEntry (base_archive, entry.Value, output); else entry.Value.Size = WriteAmiEntry (entry.Value, output); entry.Value.Offset = (uint)current_offset; } if (null != callback) callback (callback_count++, null, arcStrings.MsgWritingIndex); output.Position = start_offset; using (var header = new BinaryWriter (output, Encoding.ASCII, true)) { header.Write (Signature); header.Write (file_count); header.Write (data_offset); header.Write ((uint)0); foreach (var entry in file_table) { header.Write (entry.Key); header.Write ((uint)entry.Value.Offset); header.Write ((uint)entry.Value.UnpackedSize); header.Write ((uint)entry.Value.Size); } } } finally { if (null != base_archive) base_archive.Dispose(); } }
public override ArcFile TryOpen(ArcView file) { uint base_offset = 0; ArcView index_file = file; try { // possible filesystem structure: // game.dat -- main archive body // game.ext -- [optional] separate index (could be included into the main body) // game.001 -- [optional] extra parts // game.002 // ... uint signature = index_file.View.ReadUInt32(0); if (file.Name.HasExtension(".exe") && (0x5A4D == (signature & 0xFFFF))) // 'MZ' { base_offset = SkipExeData(index_file); signature = index_file.View.ReadUInt32(base_offset); } else if (!file.Name.HasExtension(".dat")) { return(null); } else if (0x666676 != signature) { var ext_filename = Path.ChangeExtension(file.Name, ".ext"); if (!VFS.FileExists(ext_filename)) { return(null); } index_file = VFS.OpenView(ext_filename); signature = index_file.View.ReadUInt32(0); } if (0x666676 != signature) { return(null); } int count = index_file.View.ReadInt32(base_offset + 6); if (!IsSaneCount(count)) { return(null); } var dir = ReadIndex(index_file, base_offset, count); if (null == dir) { return(null); } long max_offset = file.MaxOffset; var parts = new List <ArcView>(); try { for (int i = 1; i < 100; ++i) { var ext = string.Format(".{0:D3}", i); var part_filename = Path.ChangeExtension(file.Name, ext); if (!VFS.FileExists(part_filename)) { break; } var arc_file = VFS.OpenView(part_filename); max_offset += arc_file.MaxOffset; parts.Add(arc_file); } } catch { foreach (var part in parts) { part.Dispose(); } throw; } if (0 == parts.Count) { return(new ArcFile(file, this, dir)); } return(new MultiFileArchive(file, this, dir, parts)); } finally { if (index_file != file) { index_file.Dispose(); } } }
static void Main(string[] args) { Console.WriteLine("ONE Eternal Patch v1.0"); Console.WriteLine("developed by Sep7\n"); ////////// //INPUTS ////////// string inputLanguage = ""; do { Console.WriteLine("Enter 1 if you want to patch the Japanese Version."); Console.WriteLine("Enter 2 if you want to patch the English translated Version."); inputLanguage = Console.ReadLine(); if (inputLanguage.Length != 1 || (inputLanguage.Substring(0, 1) != "1" && inputLanguage.Substring(0, 1) != "2")) { Console.WriteLine("Syntax Error.\n"); } } while (inputLanguage.Length != 1 || (inputLanguage.Substring(0, 1) != "1" && inputLanguage.Substring(0, 1) != "2")); string inputBonusCG = ""; do { Console.WriteLine("\nEnter 1 if you want to add the bonus CGs."); Console.WriteLine("Enter 2 if you want to remove them."); inputBonusCG = Console.ReadLine(); if (inputBonusCG.Length != 1 || (inputBonusCG.Substring(0, 1) != "1" && inputBonusCG.Substring(0, 1) != "2")) { Console.WriteLine("Syntax Error."); } } while (inputBonusCG.Length != 1 || (inputBonusCG.Substring(0, 1) != "1" && inputBonusCG.Substring(0, 1) != "2")); ////////////////////////////// //EXTRACTING OF THE PATCH FILES ////////////////////////////// //First, we create a view of the file that'll allow us to work on it, the file is still encrypted. ArcView originalFile = null; ArcView patchFile = null; try { patchFile = new ArcView("./ONE_Patch_Files"); } catch (System.IO.FileNotFoundException e) { Console.WriteLine("\nError: the file \"ONE_Patch_Files\" was not found.\n" + "Make sure to place it in the same directory as the executable.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (System.UnauthorizedAccessException e) { Console.WriteLine("\nError: the file \"ONE_Patch_Files\" can't be accessed.\n" + "Make sure that the file and the current folder are not in read only access.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (Exception e) { Console.WriteLine(e); Console.ReadKey(true); System.Environment.Exit(1); } LstOpener lst = new LstOpener(); List <Entry> resultFilesList = new List <Entry>(); ArcFile arcOriginalFiles = null; ArcFile arcPatchFiles = null; ArchiveFileSystem afsOriginalFiles = null; ArchiveFileSystem afsPatchFiles = null; String suffix = ""; try { //then, we want to get the encrypted file with the LstOpener //the arcfile is composed of the view on the original file, of an instance of LstOpener used to determinate the format //and of a list of all the files/entries with their names, type, offset and size arcPatchFiles = lst.TryOpen(patchFile); } catch (System.UnauthorizedAccessException e) { Console.WriteLine("\nError: the file \"ONE_Patch_Files.lst\" can't be accessed.\n" + "Make sure that the file and the current folder are not in read only access.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (Exception e) { Console.WriteLine(e); Console.ReadKey(true); System.Environment.Exit(1); } try { //create a dictionary of data where the key is equal to the name of the entry and where the content is equal to the current entry afsPatchFiles = arcPatchFiles.CreateFileSystem(); } catch (System.NullReferenceException e) { Console.WriteLine("\nError: the file \"ONE_Patch_Files.lst\" was not found.\n" + "Make sure to place it in the same directory as the executable.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (Exception e) { Console.WriteLine(e); Console.ReadKey(true); System.Environment.Exit(1); } List <Entry> patchFilesList = new List <Entry>(); //Remove the Bonus CGs in the Japanese version if (inputBonusCG.Substring(0, 1) == "2" && inputLanguage.Substring(0, 1) == "1") { suffix = "_JAP"; } //Remove the Bonus CGs in the English version else if (inputBonusCG.Substring(0, 1) == "2" && inputLanguage.Substring(0, 1) == "2") { suffix = "_ENG"; } //Add the Bonus CGs in the Japanese version else if (inputBonusCG.Substring(0, 1) == "1" && inputLanguage.Substring(0, 1) == "1") { suffix = "_JAPBCG"; } //Add the Bonus CGs in the English version else { suffix = "_ENGBCG"; } //Scripts patchFilesList.Add(afsPatchFiles.FindFile("AK26" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEAK" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMO" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMS" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMU" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMZ" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODENN" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("DS01" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("DS05" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("DS07" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("DS09" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("DS10_A" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("DS19" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("MS22" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("MS25" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("MS27" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("MY24" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("NV30" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("RM24" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("SBD25N1" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("SBRM14N1" + suffix + ".SNX")); patchFilesList.Add(afsPatchFiles.FindFile("SBRM17M1" + suffix + ".SNX")); //PNGs if (inputBonusCG.Substring(0, 1) == "1") { patchFilesList.Add(afsPatchFiles.FindFile("BG400.PNG")); } patchFilesList.Add(afsPatchFiles.FindFile("CGMODEAKBK" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEAKCHIP" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMOBK" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMOCHIP" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMSBK" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMSCHIP" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMUBK" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMUCHIP" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMZBK" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODEMZCHIP" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODENNBK" + suffix + ".PNG")); patchFilesList.Add(afsPatchFiles.FindFile("CGMODENNCHIP" + suffix + ".PNG")); if (inputBonusCG.Substring(0, 1) == "1") { patchFilesList.Add(afsPatchFiles.FindFile("FGAK17.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGAK18.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMI17.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMI18.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMI19.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMS18.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMS19.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMY16.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMY17.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMZ17.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGMZ18.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGRM16.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGRM17.PNG")); patchFilesList.Add(afsPatchFiles.FindFile("FGRM18.PNG")); } //This file only exists in the English translated version and is placed at the end of the archive for some reasons. //I'm pretty sure it's a mistake of the TL team but I prefer to update it, just in case. if (inputLanguage.Substring(0, 1) == "2") { patchFilesList.Add(afsPatchFiles.FindFile("CGMODEAKMU" + suffix + ".PNG")); } List <String> filesListToNotUpdate = new List <String> { "BG400.PNG", "FGAK17.PNG", "FGAK18.PNG", "FGMI17.PNG", "FGMI18.PNG", "FGMI19.PNG", "FGMS18.PNG", "FGMS19.PNG", "FGMY16.PNG", "FGMY17.PNG", "FGMZ17.PNG", "FGMZ18.PNG", "FGRM16.PNG", "FGRM17.PNG", "FGRM18.PNG" }; ////////////////////////////// //EXTRACTING OF THE ORIGINAL FILES ////////////////////////////// try { originalFile = new ArcView("./one"); } catch (System.IO.FileNotFoundException e) { Console.WriteLine("\nError: the file \"one\" was not found.\n" + "Make sure to place it in the same directory as the executable.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (System.UnauthorizedAccessException e) { Console.WriteLine("\nError: the file \"one\" can't be accessed.\n" + "Make sure that the file and the current folder are not in read only access.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (Exception e) { Console.WriteLine(e); Console.ReadKey(true); System.Environment.Exit(1); } try { arcOriginalFiles = lst.TryOpen(originalFile); } catch (System.UnauthorizedAccessException e) { Console.WriteLine("\nError: the file \"one.lst\" can't be accessed.\n" + "Make sure that the file and the current folder are not in read only access.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (Exception e) { Console.WriteLine(e); Console.ReadKey(true); System.Environment.Exit(1); } try { afsOriginalFiles = arcOriginalFiles.CreateFileSystem(); } catch (System.NullReferenceException e) { Console.WriteLine("\nError: the file \"one.lst\" was not found.\n" + "Make sure to place it in the same directory as the executable.\n\n" + "Error details: " + e + "\n\nPress any key to continue."); Console.ReadKey(true); System.Environment.Exit(1); } catch (Exception e) { Console.WriteLine(e); Console.ReadKey(true); System.Environment.Exit(1); } List <Entry> originalFilesList = new List <Entry>(); originalFilesList = (List <Entry>)afsOriginalFiles.GetFiles(); int i = 0; foreach (Entry entry in originalFilesList) { String fileName = ""; //Updating the name of the file if (patchFilesList.ToArray().Length > i) { fileName = ((Entry)patchFilesList.ToArray()[i]).Name; //Remove the suffix of the name of the files if (fileName.Contains(suffix)) { fileName = fileName.Replace(suffix, ""); } } //Skip the bonus CGs if the user doesn't want them if (inputBonusCG.Substring(0, 1) == "2" && filesListToNotUpdate.Any(entry.Name.Contains)) { continue; } //Update if (patchFilesList.ToArray().Length > i && entry.Name.Equals(fileName)) { resultFilesList.Add((Entry)patchFilesList.ToArray()[i]); Console.WriteLine(fileName + " will be updated."); i++; } //Insert new file(s) and the current original file else if (patchFilesList.ToArray().Length > i && entry.Type.Equals(((Entry)patchFilesList.ToArray()[i]).Type) && String.Compare(entry.Name, fileName) > 0) { while (patchFilesList.ToArray().Length > i && entry.Type.Equals(((Entry)patchFilesList.ToArray()[i]).Type) && String.Compare(entry.Name, fileName) > 0 && !fileName.Equals("CGMODEAKMU.PNG")) { resultFilesList.Add((Entry)patchFilesList.ToArray()[i]); Console.WriteLine(fileName + " will be inserted."); i++; //Updating the name of the file if (patchFilesList.ToArray().Length > i) { fileName = ((Entry)patchFilesList.ToArray()[i]).Name; //Remove the suffix of the name of the files if (fileName.Contains(suffix)) { fileName = fileName.Replace(suffix, ""); } } } resultFilesList.Add(entry); } //Insert the current original file else { resultFilesList.Add(entry); } } //////////////////// //WRITING PART //////////////////// Console.WriteLine("Writing..."); var cp932 = Encodings.cp932.WithFatalFallback(); //cp932 is the encoding for the Japanese characters var nbFiles = resultFilesList.ToArray().Length; //count the number of files //The file one_TEMP will be written directly into binary BinaryWriter bw = null; bw = new BinaryWriter(File.Create("./one_TEMP.lst")); Boolean headerWritten = false; long offset = 0; //The key is always equal to 01 in hexa (at least for ONE), it's possible to change it without any impact but I don't see the point to do it var key = 0x01; var convertedKey = key; //The first operation takes the key, convert it into binary, move the bits to 8 positions towards the left and make a binary OR with the first key, I've put some examples //This allows the key to be on 32 bits instead of 8 (the program uses a lot of 32 bits functions) convertedKey |= convertedKey << 8; //1 => 257, 0001 => 0000 0001 0000 0001 convertedKey |= convertedKey << 16; //257 => 16 843 009 => 0001 0001 0001 0001 //This key is used to encrypt the SNX files, she's always equal to 02 //We only need the key to be on 8 bits so we don't do a conversion var keySNX = 0x02; //This part is used to initialize the variables used to read the one_TEMP file Stream stream = null; var output = PhysicalFileSystem.CreateFile("./one_TEMP"); //Loop that will treat each file, it's going to insert an entry into the one_TEMP.lst file and then insert it into the one_TEMP file afterwards foreach (Entry entry in resultFilesList) { //We start with the transformation of the data //Remove the suffix of the name of the files String fileName = entry.Name; if (fileName.Contains(suffix)) { fileName = fileName.Replace(suffix, ""); } int pointPosition = fileName.IndexOf("."); String extension = fileName.Substring(pointPosition + 1, fileName.Length - pointPosition - 1); byte[] bufferName = LstOpener.WriteName(fileName.Substring(0, pointPosition), 64, (byte)key, cp932); long fileSize = entry.Size ^ convertedKey; long convertedOffset = offset ^ convertedKey; offset += entry.Size; //Type is the only part that is not encrypted with the key int type = 0; if (extension.Equals("SNX")) { type = 1; } else if (extension.Equals("BMP")) { type = 2; } else if (extension.Equals("PNG")) { type = 3; } else if (extension.Equals("WAV")) { type = 4; } else if (extension.Equals("OGG")) { type = 5; } else { type = -1; } //Byte writing in the lst file //Writing of the header if (!headerWritten) { //The header corresponds to the 4 first bytes of the files, he indicates the number of files and the key (4th bytes) var header = nbFiles ^ convertedKey; bw.Write(header); headerWritten = true; } bw.Write((int)convertedOffset); bw.Write((int)fileSize); bw.Write(bufferName); bw.Write(type); //Creation of the file into the one file //These two conditions are used to determinate if the current file comes from the original files or the patch files if (afsOriginalFiles.FileExists(entry.Name)) { stream = arcOriginalFiles.OpenEntry(entry); } else if (afsPatchFiles.FileExists(entry.Name)) { stream = arcPatchFiles.OpenEntry(entry); } int byteTempo = 0; //The SNX files need to be written byte by byte, indeed, we need to transform them because they're encrypted in the one file with a XOR key 02 to make sure that nobody can read them if (type == 1) { while ((byteTempo = stream.ReadByte()) > -1) { byteTempo = byteTempo ^ keySNX; output.WriteByte((byte)byteTempo); //we directly wrote the bytes into the file without using the stream } } else { stream.CopyTo(output); } stream.Dispose(); } //The original Japanese version ends with 48 bytes corresponding to the end of a PNG file. //It's not the case for the English translation, it doesn't seem to have an impact in the game and it's very probably a mistake since the last file is also a PNG file (the value is duplicated). //However, I prefer to put it in order to have a faithful recreation of the file. if (inputLanguage.Substring(0, 1) == "1") { List <byte> listByteFinFichier = new List <byte> { 0xa4, 0x01, 0xcc, 0x9c, 0x72, 0x05, 0x0c, 0x0c, 0x33, 0x01, 0x47, 0x00, 0x8f, 0x07, 0xef, 0x9f, 0xce, 0xaa, 0x0a, 0x60, 0xb8, 0x6e, 0x5e, 0x0c, 0x7e, 0x0b, 0x30, 0x00, 0xf1, 0x70, 0xc4, 0x43, 0x75, 0x7e, 0x8f, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; foreach (byte b in listByteFinFichier) { output.WriteByte(b); } } bw.Close(); output.Close(); output.Dispose(); originalFile.Dispose(); patchFile.Dispose(); //At the end, we replace the original files with the files that we have created. File.SetAttributes("one", FileAttributes.Normal); File.SetAttributes("one.lst", FileAttributes.Normal); File.Delete("one"); File.Delete("one.lst"); File.Move("one_TEMP", "one"); File.Move("one_TEMP.lst", "one.lst"); Console.WriteLine("\nDone!"); Console.WriteLine("\nPress any key to continue."); Console.ReadKey(true); }