private static void BackupAndPlaceFiles(Language language) { ReadOnlyCollection <SWFile> swFiles = SWFileManager.GetFiles(); ILookup <Type, SWFile> swFileTypeLookup = swFiles.ToLookup(f => f.GetType()); IEnumerable <string> archives = swFileTypeLookup[typeof(ArchivedSWFile)].Select(f => f.Path).Union(swFileTypeLookup[typeof(PatchedSWFile)].Select(f => f.Path)); IEnumerable <string> otherSWFiles = swFileTypeLookup[typeof(SWFile)].Select(f => f.Path + Path.GetFileName(f.PathD)); IEnumerable <string> translationFiles = archives.Distinct().Union(otherSWFiles); foreach (string path in translationFiles) { string originalFilePath = Path.Combine(UserSettings.GamePath, path); string translationFilePath = Path.Combine(language.Path, path); string backupFilePath = Path.Combine(language.BackupPath, path); BackupAndPlaceFile(originalFilePath, translationFilePath, backupFilePath); } }
private static bool IsTranslationOutdatedOrMissing(Language language) { if (Methods.IsTranslationOutdated(language)) { return(true); } ReadOnlyCollection <SWFile> swFiles = SWFileManager.GetFiles(); ILookup <Type, SWFile> things = swFiles.ToLookup(f => f.GetType()); IEnumerable <string> archivesPaths = things[typeof(ArchivedSWFile)].Select(f => f.Path).Union(things[typeof(PatchedSWFile)].Select(f => f.Path)); IEnumerable <string> otherSWFilesPaths = things[typeof(SWFile)].Select(f => f.Path + Path.GetFileName(f.PathD)); IEnumerable <string> translationFilePaths = archivesPaths.Distinct().Union(otherSWFilesPaths).Select(f => Path.Combine(language.Path, f)); foreach (string path in translationFilePaths) { if (!File.Exists(path)) { return(true); } } return(false); }
private void Worker_DoWork(object sender, DoWorkEventArgs e) { Logger.Debug(Methods.MethodFullName("Patcher", Thread.CurrentThread.ManagedThreadId.ToString(), this.Language.ToString())); this.CurrentState = State.Load; IEnumerable <ArchivedSWFile> archivedSWFiles = SWFileManager.GetFiles().OfType <ArchivedSWFile>(); string regionFldr = this.Language.ApplyingRegionFolder == "jpc" ? "jp" : this.Language.ApplyingRegionFolder; string datasArchivesPath = Urls.TranslationGitHubHome + regionFldr + '/' + Strings.IniName.DatasArchives; Logger.Debug(Methods.MethodFullName(System.Reflection.MethodBase.GetCurrentMethod(), datasArchivesPath)); Dictionary <string, string> passwordDictionary = LoadPasswords(datasArchivesPath); int archivedSWFilesCount = archivedSWFiles.Count(); var archives = archivedSWFiles.Select(f => f.Path).Distinct().ToDictionary(p => p, p => { string archivePath = Path.Combine(UserSettings.GamePath, p); Logger.Info($"Loading archive=[{archivePath}]"); byte[] fileBytes = File.ReadAllBytes(archivePath); var xms = new XorMemoryStream(fileBytes, SecretByte); return(ZipFile.Read(xms)); }); this.CurrentState = State.Patch; int count = 1; foreach (ArchivedSWFile archivedSWFile in archivedSWFiles) { if (this.Worker.CancellationPending) { e.Cancel = true; return; } this.Worker.ReportProgress(count++ == archivedSWFilesCount ? int.MaxValue : Convert.ToInt32(((double)count / archivedSWFilesCount) * int.MaxValue)); string archiveFileNameWithoutExtension = Path.GetFileNameWithoutExtension(archivedSWFile.Path); string archivePassword = null; if (passwordDictionary.ContainsKey(archiveFileNameWithoutExtension)) { archivePassword = passwordDictionary[archiveFileNameWithoutExtension]; } Logger.Info($"Patching file=[{archivedSWFile.PathA}] archive=[{archivedSWFile.Path}]"); if (archivedSWFile is PatchedSWFile patchedSWFile) { MemoryStream ms = Methods.GetZippedFileStream(archives[patchedSWFile.Path], patchedSWFile.PathA, archivePassword); MemoryStream msDest = new MemoryStream(); string[] fullFormatArray = patchedSWFile.Format.Split(' '); int idIndex = Convert.ToInt32(fullFormatArray[0]); string countFormat = fullFormatArray[1]; string[] formatArray = fullFormatArray.Skip(2).ToArray(); // skip idIndex and countFormat #region Patching the File ulong dataCount = 0; ulong dataSum = 0; ushort hashLength = 32; byte[] hash = new byte[hashLength]; int lineCount = 0; for (int i = 0; i < formatArray.Length; i++) { if (formatArray[i] == "len") { lineCount++; i++; } } Dictionary <ulong, string[]> inputTable = this.ReadInputFile(patchedSWFile.Data, lineCount, idIndex); using (var br = new BinaryReader(ms)) using (var bw = new BinaryWriter(msDest, new UTF8Encoding(false, true), true)) { switch (countFormat) { case "1": dataCount = br.ReadByte(); bw.Write(Convert.ToByte(dataCount)); break; case "2": dataCount = br.ReadUInt16(); bw.Write(Convert.ToUInt16(dataCount)); break; case "4": dataCount = br.ReadUInt32(); bw.Write(Convert.ToUInt32(dataCount)); break; case "8": dataCount = br.ReadUInt64(); bw.Write(Convert.ToUInt64(dataCount)); break; } ulong value = 0; for (ulong i = 0; i < dataCount; i++) { if (this.Worker.CancellationPending) { e.Cancel = true; break; } #region Object Reading object[] current = new object[formatArray.Length]; for (int j = 0; j < formatArray.Length; j++) { if (this.Worker.CancellationPending) { e.Cancel = true; break; } switch (formatArray[j]) { case "1": current[j] = Convert.ToByte(br.ReadByte()); break; case "2": current[j] = Convert.ToUInt16(br.ReadUInt16()); break; case "4": current[j] = Convert.ToUInt32(br.ReadUInt32()); break; case "8": current[j] = Convert.ToUInt64(br.ReadUInt64()); break; case "len": switch (formatArray[++j]) { case "1": value = br.ReadByte(); current[j] = Convert.ToByte(br.ReadByte()); break; case "2": value = br.ReadUInt16(); current[j] = Convert.ToUInt16(value); break; case "4": value = br.ReadUInt32(); current[j] = Convert.ToUInt32(value); break; case "8": value = br.ReadUInt64(); current[j] = Convert.ToUInt64(value); break; } ulong strBytesLength = value * 2; byte[] strBytes = new byte[strBytesLength]; current[j] = strBytes; for (ulong k = 0; k < strBytesLength; k++) { strBytes[k] = br.ReadByte(); } break; } } #endregion Object Reading #region Object Writing int lenPosition = 0; for (int j = 0; j < formatArray.Length; j++) { if (this.Worker.CancellationPending) { e.Cancel = true; break; } switch (formatArray[j]) { case "1": value = Convert.ToByte(current[j]); bw.Write(Convert.ToByte(value)); break; case "2": value = Convert.ToUInt16(current[j]); bw.Write(Convert.ToUInt16(value)); break; case "4": value = Convert.ToUInt32(current[j]); bw.Write(Convert.ToUInt32(value)); break; case "8": value = Convert.ToUInt64(current[j]); bw.Write(Convert.ToUInt64(value)); break; case "len": byte[] strBytes = null; j++; ulong id = Convert.ToUInt64(current[idIndex]); if (inputTable.ContainsKey(id)) { strBytes = Encoding.Unicode.GetBytes(inputTable[id][lenPosition++]); } else { strBytes = current[j] as byte[]; } value = Convert.ToUInt64(strBytes.Length / 2); switch (formatArray[j]) { case "1": bw.Write(Convert.ToByte(value)); break; case "2": bw.Write(Convert.ToUInt16(value)); break; case "4": bw.Write(Convert.ToUInt32(value)); break; case "8": bw.Write(Convert.ToUInt64(value)); break; } foreach (byte b in strBytes) { dataSum += b; bw.Write(b); } break; } dataSum += value; } #endregion Object Writing } bw.Write(hashLength); string hashString = GetMD5(Convert.ToString(dataSum)); for (int i = 0; i < hashLength; i++) { hash[i] = Convert.ToByte(hashString[i]); } bw.Write(hash); } #endregion Patching the File Methods.ZipFileStream(archives[patchedSWFile.Path], patchedSWFile.PathA, msDest, archivePassword); } else { var ms = new MemoryStream(archivedSWFile.Data); if (Path.GetExtension(archivedSWFile.PathD) == ".zip") { Methods.AddZipToZip(archives[archivedSWFile.Path], archivedSWFile.PathA, ms, archivePassword); } else { Methods.ZipFileStream(archives[archivedSWFile.Path], archivedSWFile.PathA, ms, archivePassword); } } } this.CurrentState = State.Save; foreach (KeyValuePair <string, ZipFile> archive in archives) { if (this.Worker.CancellationPending) { e.Cancel = true; return; } string zipFileName = archive.Key; ZipFile zipFile = archive.Value; string archivePath = Path.Combine(this.Language.Path, zipFileName); string archivePathDirectory = Path.GetDirectoryName(archivePath); Directory.CreateDirectory(archivePathDirectory); //Dirty af but will prevent "Not a valid Win32 FileTime" error foreach (ZipEntry ze in zipFile.Entries) { ze.ModifiedTime = DateTime.Now; } using (var fs = new MemoryStream()) { zipFile.Save(fs); byte[] buffer = fs.ToArray(); zipFile.Dispose(); // TODO: using () { } for (int i = 0; i < buffer.Length; i++) { buffer[i] ^= SecretByte; } File.WriteAllBytes(archivePath, buffer); } } /* * Disabled for now since it's useless * * if (UserSettings.WantToPatchExe) * { * this.CurrentState = State.ExePatch; * * string regionId = this.Language.ApplyingRegionId == "jpc" ? "jp" : this.Language.ApplyingRegionId; * string regionFolder = this.Language.ApplyingRegionFolder == "jpc" ? "jp" : this.Language.ApplyingRegionFolder; * string gameExePath = Path.Combine(UserSettings.GamePath, Methods.GetGameExeName(regionId)); * byte[] gameExeBytes = File.ReadAllBytes(gameExePath); * string gameExePatchedPath = Path.Combine(UserSettings.PatcherPath, regionFolder, Methods.GetGameExeName(regionId)); * * Methods.PatchExeFile(gameExeBytes, gameExePatchedPath, Urls.TranslationGitHubHome + regionFolder + '/' + Strings.IniName.BytesToPatch); * } */ }