/// <summary> /// 文件导出 /// </summary> /// <param name="fileInfo"></param> private void ExportFile(FilePosInfo fileInfo) { FileStream fs = null; try { fs = File.Open(fileInfo.File, FileMode.Open); fs.Seek(fileInfo.FilePos, SeekOrigin.Begin); byte[] subFile = new byte[fileInfo.FileSize]; fs.Read(subFile, 0, subFile.Length); File.WriteAllBytes(this.baseFolder + @"\" + fileInfo.SubName, subFile); fs.Close(); fs = null; } catch (Exception ex) { MessageBox.Show(ex.Message + "\n" + ex.StackTrace); } finally { if (fs != null) { fs.Close(); } } }
/// <summary> /// 添加Afs文件 /// </summary> /// <param name="afsFile"></param> private void AddAfsFile(string afsFile) { byte[] byAfs = File.ReadAllBytes(afsFile); int subFileCount = (byAfs[7] << 24) | (byAfs[6] << 16) | (byAfs[5] << 8) | byAfs[4]; int entryPos = 8; int nameEntryPos = entryPos + subFileCount * 8; nameEntryPos = (byAfs[nameEntryPos + 3] << 24) | (byAfs[nameEntryPos + 2] << 16) | (byAfs[nameEntryPos + 1] << 8) | byAfs[nameEntryPos]; for (int i = 0; i < subFileCount; i++) { FilePosInfo fileInfo = new FilePosInfo(afsFile); fileInfo.FilePos = (byAfs[entryPos + i * 8 + 3] << 24) | (byAfs[entryPos + i * 8 + 2] << 16) | (byAfs[entryPos + i * 8 + 1] << 8) | byAfs[entryPos + i * 8]; fileInfo.FileSize = (byAfs[entryPos + i * 8 + 7] << 24) | (byAfs[entryPos + i * 8 + 6] << 16) | (byAfs[entryPos + i * 8 + 5] << 8) | byAfs[entryPos + i * 8 + 4]; fileInfo.SubName = Util.GetFileNameFromStringTable(byAfs, nameEntryPos + i * 0x30); fileInfo.SubIndex = i.ToString(); if (string.IsNullOrEmpty(fileInfo.SubName.Trim())) { fileInfo.SubName = Util.GetShortName(afsFile) + "_" + i.ToString().PadLeft(2, '0'); } this.textFiles.Add(fileInfo); this.lstAsfFiles.Items.Add(fileInfo.SubName.PadRight(40, ' ') + " " + fileInfo.FilePos.ToString("x") + "--" + (fileInfo.FilePos + fileInfo.FileSize).ToString("x")); } }
/// <summary> /// 重新设置带Entry信息的翻译后的数据 /// </summary> /// <param name="currentFileInfo">当前选择的文件</param> /// <param name="byData">当前选择的文件的字节数据</param> /// <param name="cnBytes">翻译后的字节数据</param> /// <returns>带Entry信息的翻译后的数据</returns> protected override byte[] ResetCnDataWithEnrty(FilePosInfo currentFileInfo, byte[] byData, List <byte> cnBytes) { // 带Entry的文本,先保存修改后的各个Entry int entryLen = currentFileInfo.TextEntrys.Count * 2; byte[] byCnData = new byte[entryLen + 2 + cnBytes.Count]; int idx = 0; for (int i = 0; i < currentFileInfo.TextEntrys.Count; i += 2) { int startPos = currentFileInfo.TextEntrys[i] / 2; int lenInfo = currentFileInfo.TextEntrys[i + 1] / 2; byCnData[idx * 4] = (byte)((startPos >> 8) & 0xFF); byCnData[idx * 4 + 1] = (byte)(startPos & 0xFF); byCnData[idx * 4 + 2] = (byte)((lenInfo >> 8) & 0xFF); byCnData[idx * 4 + 3] = (byte)(lenInfo & 0xFF); idx++; } // 再保存文本数据 byCnData[entryLen] = 0x80; byCnData[entryLen + 1] = 0; Array.Copy(cnBytes.ToArray(), 0, byCnData, entryLen + 2, cnBytes.Count); return(byCnData); }
/// <summary> /// 重新设置Entry位置信息 /// </summary> /// <param name="currentFileInfo">当前选择的文件</param> /// <param name="cnTxtLen">当前行中文文本字节长度</param> /// <param name="prevEntryPos">前一个Entry位置信息</param> /// <returns>当前Entry位置信息</returns> protected override int ResetLastEntryPosInfo(FilePosInfo currentFileInfo, int cnTxtLen, int prevEntryPos) { // 保存文本的长度 currentFileInfo.TextEntrys.Add(cnTxtLen); return(prevEntryPos + cnTxtLen); }
/// <summary> /// 初始化文本开始位置 /// </summary> private void InitStartPos(string folder) { this.fileList.Items.Clear(); this.textFiles.Clear(); // 添加sysmes.ald文本 FilePosInfo posInfo = new FilePosInfo(folder + @"\sysmes.ald"); posInfo.TextStart = 0; posInfo.TextEnd = 0xdc4; this.textFiles.Add(posInfo); this.fileList.Items.Add("sysmes.ald" + " 0x0--0xdc4"); posInfo = new FilePosInfo(folder + @"\sysmes.ald"); posInfo.TextStart = 0xdc4; posInfo.SubIndex = "_1"; if (this.isNgc) { posInfo.TextEnd = 0x52f0; } else { posInfo.TextEnd = 0x4ab8; } this.textFiles.Add(posInfo); this.fileList.Items.Add("sysmes.ald" + " 0xdc4--0x" + posInfo.TextEnd.ToString("x")); }
/// <summary> /// 根据配置文件,取得所有需要Copy的文件 /// </summary> /// <param name="ngcFolder"></param> /// <returns></returns> private List <FilePosInfo> GetNeedCopyFiles(string ngcFolder, bool isComBinFile) { List <FilePosInfo> needCopyFiles = new List <FilePosInfo>(); string configFile; if (isComBinFile) { configFile = ngcFolder + @"\BinAddr.txt"; } else { configFile = ngcFolder + @"\TextAddr.txt"; } if (File.Exists(configFile)) { string[] files = File.ReadAllLines(configFile); for (int i = 0; i < files.Length; i += 2) { FilePosInfo fileInfo = new FilePosInfo(files[i], files[i + 1].Split(' ')); needCopyFiles.Add(fileInfo); } } return(needCopyFiles); }
/// <summary> /// 文件变更 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void fileList_SelectedIndexChanged(object sender, EventArgs e) { // 设置文本 FilePosInfo filePosInfo = this.textFiles[this.fileList.SelectedIndex]; this.txtJp.Text = this.ChangeFile(filePosInfo.File, filePosInfo.TextStart, filePosInfo.TextEnd, this.jpFontCharPage); this.txtCn.Text = this.ChangeFile(filePosInfo.File + "_cn", filePosInfo.TextStart, filePosInfo.TextEnd, this.cnFontCharPage); }
/// <summary> /// 对象比较 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> private int PosInfoCompare(FilePosInfo a, FilePosInfo b) { if (a.IsFolder || b.IsFolder) { return(0); } else { return(a.FilePos - b.FilePos); } }
/// <summary> /// 开始解码文本 /// </summary> /// <param name="currentFileInfo">当前选择的文件</param> /// <param name="isCnTxt">是否是中文</param> /// <returns>解码的文本</returns> protected override string DecodeText(FilePosInfo currentFileInfo, bool isCnTxt) { if (isCnTxt) { return(this.DecodeText(File.ReadAllBytes(this.cnFile), currentFileInfo)); } else { return(this.DecodeText(File.ReadAllBytes(currentFileInfo.File), currentFileInfo)); } }
/// <summary> /// 写入Ngc补丁(文件大小、格式可以不固定) /// </summary> /// <param name="jpFiInfosForSort"></param> /// <param name="jpFiInfos"></param> /// <param name="allCnFiles"></param> /// <param name="cnFs"></param> /// <param name="jpFs"></param> /// <returns></returns> private int WriteNgcTypeA(List <FilePosInfo> jpFiInfosForSort, List <FilePosInfo> jpFiInfos, List <FilePosInfo> allCnFiles, BufferedStream cnFs, BufferedStream jpFs) { int copyFile = 0; int copyLen = 0; foreach (FilePosInfo jpFiInfo in jpFiInfosForSort) { // 更新进度条 this.ProcessBarStep(); // 如果是目录,不做任何处理 if (jpFiInfo.IsFolder) { continue; } // 查找原始文件对应的中文文件 FilePosInfo cnFiInfo = allCnFiles.FirstOrDefault <FilePosInfo>(cnFile => cnFile.File.EndsWith(jpFiInfo.File, StringComparison.OrdinalIgnoreCase)); if (cnFiInfo == null) { // 如果没有找到中文文件,写入原始的文件 jpFs.Seek(jpFiInfo.FilePos, SeekOrigin.Begin); cnFs.Seek(jpFiInfo.TextStart, SeekOrigin.Begin); this.FileStreamCopy(cnFs, jpFs, jpFiInfo.FileSize); } else { cnFs.Seek(jpFiInfo.TextStart, SeekOrigin.Begin); copyLen = this.FileStreamCopy(cnFs, cnFiInfo.File); copyFile++; if (copyLen != jpFiInfo.FileSize) { jpFiInfo.TextEnd = copyLen; if (cnFiInfo.File.ToLower().IndexOf("start.dol") >= 0) { throw new Exception("Start.dol是重要系统文件,大小不能变化!"); } // 文件大小变化,改变这个文件以后的所有文件的位置信息 int diffSize = Util.ResetPos(copyLen - jpFiInfo.FileSize, RAW_SIZE); this.ResetAllPos(jpFiInfos, jpFiInfo.FilePos, diffSize); } } } return(copyFile); }
/// <summary> /// 开始解码 /// </summary> /// <param name="byData"></param> /// <param name="startPos"></param> private string DecodeText(byte[] byData, FilePosInfo filePosInfo, string[] fontChar) { StringBuilder sb = new StringBuilder(); int txtStart = filePosInfo.TextStart + 2; for (int j = filePosInfo.EntryPos; j < filePosInfo.TextStart; j += 4) { int startPos = txtStart + Util.GetOffset(byData, j, j + 1) * 2; int endPos = startPos + Util.GetOffset(byData, j + 2, j + 3) * 2; sb.Append(this.DecodeText(byData, fontChar, startPos, endPos)); } return(sb.ToString()); }
/// <summary> /// 开始解码 /// </summary> /// <param name="byData"></param> /// <param name="filePosInfo"></param> private string DecodeText(byte[] byData, FilePosInfo filePosInfo) { if (filePosInfo.File.EndsWith(".dol", StringComparison.OrdinalIgnoreCase)) { Encoding encoding = Encoding.GetEncoding("Shift-jis"); byte[] byTemp = new byte[filePosInfo.TextEnd - filePosInfo.TextStart]; Array.Copy(byData, filePosInfo.TextStart, byTemp, 0, byTemp.Length); return(this.ResetText(Util.EncodeByteArray(byTemp, encoding)) .Replace("^0^^0^^0^^0^", "^0 0 0 0^\n") .Replace("^0^^0^", "^0 0^\n")); } else { return(this.ResetText(this.DecodeSkpText(byData, filePosInfo))); } }
/// <summary> /// 设置文本位置信息 /// </summary> /// <param name="fiInfo"></param> private bool SetTextPosInfo(FilePosInfo fiInfo) { byte[] byData = File.ReadAllBytes(fiInfo.File); //fiInfo.TextEnd = Util.GetOffset(byData, 0x8, 0xB); //for (int i = 0x20; i < byData.Length; i += 2) //{ // //if (byData[i] == 0x20 && byData[i + 1] == 0xF1 && byData[i + 2] == 0x20 && byData[i + 3] == 0xFF) // //{ // // fiInfo.EntryPos = i + 4; // // fiInfo.TextStart = fiInfo.EntryPos + Util.GetOffset(byData, fiInfo.EntryPos, fiInfo.EntryPos + 3); // // return true; // //} // if (byData[i] == 0x20 && byData[i + 1] == 0xFF && byData[i + 2] == 0x0 && byData[i + 3] == 0x0 // && (byData[i + 4] != 0x0 || byData[i + 5] != 0x0)) // { // fiInfo.EntryPos = i + 2; // fiInfo.TextStart = fiInfo.EntryPos + Util.GetOffset(byData, fiInfo.EntryPos, fiInfo.EntryPos + 3); // return true; // } //} int txtStartPos = Util.GetOffset(byData, 0x1C, 0x1F); int txtEndPos = Util.GetOffset(byData, 0x20, 0x23); if (txtStartPos == 0 || txtEndPos == 0 || txtStartPos >= txtEndPos) { return(false); } fiInfo.TextEnd = txtEndPos; for (int i = txtStartPos; i < txtEndPos; i++) { if (byData[i] == 0x20 && (byData[i + 1] == 0xFF || byData[i + 1] == 0x03) && byData[i + 2] == 0x0 && byData[i + 3] == 0x0 && (byData[i + 4] != 0x0 || byData[i + 5] != 0x0) && byData[i + 6] == 0x0 && byData[i + 7] == 0x0) { fiInfo.EntryPos = i + 2; fiInfo.TextStart = fiInfo.EntryPos + Util.GetOffset(byData, fiInfo.EntryPos, fiInfo.EntryPos + 3); return(true); } } return(false); }
/// <summary> /// 导入文件 /// </summary> /// <param name="fileInfo"></param> private void ImportFile(FilePosInfo fileInfo) { FileStream fs = null; try { string impFile = this.baseFolder + @"\" + fileInfo.SubName; if (!File.Exists(impFile)) { throw new Exception("没有找到导入的文件!"); } byte[] subFile = File.ReadAllBytes(impFile); if (subFile.Length > fileInfo.FileSize) { throw new Exception("导入的文件容量大于原始文件!"); } else if (impFile.ToLower().IndexOf(fileInfo.SubName.ToLower()) == -1) { throw new Exception("导入的文件名和原始文件名不一致"); } fs = File.Open(fileInfo.File, FileMode.Open); fs.Seek(fileInfo.FilePos, SeekOrigin.Begin); fs.Write(subFile, 0, subFile.Length); fs.Close(); fs = null; } catch (Exception ex) { MessageBox.Show(ex.Message + "\n" + ex.StackTrace); } finally { if (fs != null) { fs.Close(); } } }
/// <summary> /// 开始解码 /// </summary> /// <param name="byData"></param> /// <param name="filePosInfo"></param> private string DecodeSkpText(byte[] byData, FilePosInfo filePosInfo) { StringBuilder sb = new StringBuilder(); int txtStart = filePosInfo.TextStart; Encoding encoding = Encoding.GetEncoding("Shift-jis"); byte[] byTemp = null; try { for (int j = filePosInfo.EntryPos + 4; j < filePosInfo.TextStart; j += 4) { int startPos = txtStart; int endPos = filePosInfo.EntryPos + Util.GetOffset(byData, j, j + 3); txtStart = endPos; byTemp = new byte[endPos - startPos]; Array.Copy(byData, startPos, byTemp, 0, byTemp.Length); sb.Append(Util.EncodeByteArray(byTemp, encoding)); sb.Append("\n"); } if (filePosInfo.TextEnd > txtStart) { byTemp = new byte[filePosInfo.TextEnd - txtStart]; Array.Copy(byData, txtStart, byTemp, 0, byTemp.Length); sb.Append(Util.EncodeByteArray(byTemp, encoding)); } } catch { return("发生错误:\n" + filePosInfo.EntryPos.ToString("x") + " " + filePosInfo.TextStart.ToString("x")); } return(sb.ToString()); }
/// <summary> /// 导入所有的图片 /// </summary> private void ImportAllImg(params object[] param) { List <FilePosInfo> fileNameInfo = Util.GetAllFiles(this.baseFolder).Where(p => !p.IsFolder && p.File.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ).ToList(); if (fileNameInfo.Count == 0) { MessageBox.Show("没有发现能导入的文件,请重新检查选择的目录,或导入的文件是否是[fileName_XX.png]的格式"); return; } this.currentImgEditor.rotateFlipType = (RotateFlipType)param[0]; // 统计信息 List <string> impFiles = new List <string>(); int impImgCount = 0; // 显示进度条 this.ResetProcessBar(fileNameInfo.Count); for (int i = 0; i < fileNameInfo.Count; i++) { FilePosInfo fileInfo = fileNameInfo[i]; // 取得要导入的文件名 string[] names = Util.GetShortName(fileInfo.File).Replace(".png", string.Empty).Split('_'); string impShortName = names[0]; int impFileIndex = Convert.ToInt16(names[1]); // 查找导入文件的位置 int oldFileIndex = -1; int oldFileSubIndex = 0; string itemText = string.Empty; this.Invoke((MethodInvoker) delegate() { for (int j = 0; j < this.lstImg.Items.Count; j++) { itemText = this.lstImg.Items[j].ToString(); if (itemText.IndexOf(impShortName) >= 0) { if (oldFileSubIndex == impFileIndex) { oldFileIndex = j; break; } else { oldFileSubIndex++; } } } }); if (oldFileIndex != -1) { // 保存当前文件名 impImgCount++; if (!impFiles.Contains(impShortName)) { impFiles.Add(impShortName); } this.Invoke((MethodInvoker) delegate() { this.lstImg.SelectedIndex = oldFileIndex; }); Image[] oldImg = this.currentImgEditor.ImageDecode(this.ImgFiles[oldFileIndex], itemText); if (oldImg.Length == 1) { this.ImgFiles[oldFileIndex] = this.currentImgEditor.ImportImg(fileInfo.File, oldImg[0], this.ImgFiles[oldFileIndex], itemText); } else { int gridImgIndex = Convert.ToInt16(names[2]); this.currentImgEditor.imageIndex = gridImgIndex; this.ImgFiles[oldFileIndex] = this.currentImgEditor.ImportImg(fileInfo.File, oldImg[gridImgIndex], this.ImgFiles[oldFileIndex], itemText); } this.ImgChangeInfo[oldFileIndex] = true; } // 更新进度条 this.ProcessBarStep(); } // 隐藏进度条 this.CloseProcessBar(); StringBuilder sb = new StringBuilder(); sb.Append("所有图片导入完成!\n"); sb.Append("总共:" + fileNameInfo.Count + " 张图片\n"); sb.Append("其中:" + impImgCount + " 张图片,导入到了:" + impFiles.Count + " 个文件中\n"); MessageBox.Show(sb.ToString()); // 切换最新图片 this.Invoke((MethodInvoker) delegate() { this.lstImg_SelectedIndexChanged(this.lstImg, new EventArgs()); }); }
/// <summary> /// 写入Ngc补丁(文件大小、格式固定) /// </summary> /// <param name="jpFiInfosForSort"></param> /// <param name="jpFiInfos"></param> /// <param name="allCnFiles"></param> /// <param name="cnFs"></param> /// <param name="jpFs"></param> /// <returns></returns> private int WriteNgcTypeB(List <FilePosInfo> jpFiInfosForSort, List <FilePosInfo> jpFiInfos, List <FilePosInfo> allCnFiles, BufferedStream cnFs, BufferedStream jpFs) { int copyLen = 0; int copyFile = 0; for (int i = 0; i < jpFiInfosForSort.Count; i++) { FilePosInfo jpFiInfo = jpFiInfosForSort[i]; // 更新进度条 this.ProcessBarStep(); // 调整位置 jpFs.Seek(jpFiInfo.FilePos, SeekOrigin.Begin); cnFs.Seek(jpFiInfo.TextStart, SeekOrigin.Begin); if (i < jpFiInfosForSort.Count - 1) { copyLen = jpFiInfosForSort[i + 1].TextStart - jpFiInfo.TextStart; } else { copyLen = NGC_ISO_LEN - jpFiInfo.TextStart; } // 写入原始的文件 this.FileStreamCopy(cnFs, jpFs, copyLen); // 查找原始文件对应的中文文件 FilePosInfo cnFiInfo = allCnFiles.FirstOrDefault <FilePosInfo>(cnFile => cnFile.File.EndsWith(jpFiInfo.File, StringComparison.OrdinalIgnoreCase)); if (cnFiInfo != null) { cnFs.Seek(jpFiInfo.TextStart, SeekOrigin.Begin); copyLen = this.FileStreamCopy(cnFs, cnFiInfo.File); copyFile++; if (copyLen > jpFiInfo.FileSize) { string errInfo = cnFiInfo.File + "\r\n" + "补丁文件Size超过原来的文件,无法保持一致\r\n" + "请去掉【保持内部文件大小、位置一致】的选项"; throw new Exception(errInfo); } else if (copyLen < jpFiInfo.FileSize) { if (cnFiInfo.File.ToLower().IndexOf("start.dol") >= 0) { throw new Exception("Start.dol是重要系统文件,大小不能变化!"); } // 补丁文件小于原文件,补0 int emptyLen = jpFiInfo.FileSize - copyLen; while (emptyLen-- > 0) { cnFs.WriteByte(0); } } } } return(copyFile); }
/// <summary> /// 开始打包(重新组织每个文件大小,位置) /// </summary> private void PatchNgc(params object[] param) { string jpIsoFile = (string)param[0]; string cnPatchFolder = (string)param[1]; bool isReSize = (bool)param[2]; // 改变标题,按钮状态 string oldTitle = this.Text; this.SetWinStatus(false, this.Text + " 打补丁中,请稍等......"); // 开始打补丁 List <FilePosInfo> jpFiInfos = new List <FilePosInfo>(); List <FilePosInfo> jpFiInfosForSort = new List <FilePosInfo>(); List <KeyValuePair <string, int> > folderInfo = new List <KeyValuePair <string, int> >(); BufferedStream jpFs = null; BufferedStream cnFs = null; FileStream jpReader = null; FileStream cnWriter = null; string cnIsoFile = string.Empty; // 设置第一个文件开始位置(默认最大,挨个比较取最小的) int firstFilePos = NGC_ISO_LEN; // 当前目录 string currentFolder = "root"; try { // 将文件中的数据,读取到byData中 jpReader = File.OpenRead(jpIsoFile); jpFs = new BufferedStream(jpReader, COPY_BLOCK); // 读取Dol位置信息 jpFs.Seek(0x420, SeekOrigin.Begin); byte[] byData = new byte[4]; jpFs.Read(byData, 0, byData.Length); int dolOffset = Util.GetOffset(byData, 0, 3); // 读取FST位置信息 jpFs.Seek(0x424, SeekOrigin.Begin); byData = new byte[4]; jpFs.Read(byData, 0, byData.Length); int fstOffset = Util.GetOffset(byData, 0, 3); jpFs.Seek(0x4, SeekOrigin.Current); jpFs.Read(byData, 0, byData.Length); int fstSize = Util.GetOffset(byData, 0, 3); jpFs.Seek(0x4, SeekOrigin.Current); jpFs.Read(byData, 0, byData.Length); int maxFstSize = Util.GetOffset(byData, 0, 3); jpFs.Seek(0x4, SeekOrigin.Current); jpFs.Read(byData, 0, byData.Length); int userPos = Util.GetOffset(byData, 0, 3); jpFs.Seek(0x4, SeekOrigin.Current); jpFs.Read(byData, 0, byData.Length); int userLen = Util.GetOffset(byData, 0, 3); // 读取FST信息 jpFs.Seek(fstOffset, SeekOrigin.Begin); byte[] fstData = new byte[fstSize]; jpFs.Read(fstData, 0, fstData.Length); // 设置Dol信息 FilePosInfo fileInfo = new FilePosInfo("Start.dol", false, fstOffset - dolOffset); fileInfo.FilePos = dolOffset; fileInfo.FileSize = fstOffset - dolOffset; fileInfo.TextStart = fileInfo.FilePos; fileInfo.TextEnd = fileInfo.FileSize; jpFiInfos.Add(fileInfo); jpFiInfosForSort.Add(fileInfo); // 循环读取文件信息 int fstNum = Util.GetOffset(fstData, 0x8, 0xB); byte[] fileNameTab = new byte[fstSize - fstNum * 0xc]; Array.Copy(fstData, fstNum * 0xc, fileNameTab, 0, fileNameTab.Length); int fileNameOffset = Util.GetOffset(fstData, 0x1, 0x3); String rootName = Util.GetFileNameFromStringTable(fileNameTab, fileNameOffset); FilePosInfo rootFile = new FilePosInfo("root", true, 0); rootFile.FileSize = fstNum; folderInfo.Add(new KeyValuePair <string, int>("root", fstNum)); jpFiInfos.Add(rootFile); // 循环读取文件信息 for (int i = 1; i < fstNum; i++) { int fstTabOffset = i * 0xc; fileNameOffset = Util.GetOffset(fstData, fstTabOffset + 0x1, fstTabOffset + 0x3); String name = Util.GetFileNameFromStringTable(fileNameTab, fileNameOffset); bool isFolder = fstData[fstTabOffset] == 1; int filePos = Util.GetOffset(fstData, fstTabOffset + 0x4, fstTabOffset + 0x7); int fileSize = Util.GetOffset(fstData, fstTabOffset + 0x8, fstTabOffset + 0xB); fileInfo = new FilePosInfo(name, isFolder, fileSize); fileInfo.FilePos = filePos; fileInfo.FileSize = fileSize; fileInfo.TextStart = filePos; fileInfo.TextEnd = fileSize; // 重新设置当前的目录及文件名 if (isFolder) { currentFolder = jpFiInfos[filePos + 1].File + @"\" + name; fileInfo.File = currentFolder; folderInfo.Add(new KeyValuePair <string, int>(currentFolder, fileSize)); } else { fileInfo.File = this.GetCurrentFolder(folderInfo, i) + fileInfo.File; if (filePos < firstFilePos) { firstFilePos = filePos; } jpFiInfosForSort.Add(fileInfo); } jpFiInfos.Add(fileInfo); } // 将地址信息List重新排序 jpFiInfosForSort.Sort(this.PosInfoCompare); // 为了防止文件过大,超过容量,尽量减少firstFilePos if (isReSize) { int startFilePos = Util.ResetPos(userPos + userLen, RAW_SIZE); if (startFilePos < firstFilePos) { int diffSize = Util.ResetPos(startFilePos - firstFilePos, RAW_SIZE); this.ResetAllPos(jpFiInfos, firstFilePos, diffSize); firstFilePos = startFilePos; } } // 重新设置原始文件路径,去掉里面的[root],因为中文补丁文件中,可能没有这个路径 jpFiInfosForSort.ForEach(p => p.File = p.File.Replace(@"root\", "")); // 读取所有补丁文件信息 Util.IsGetAllFile = true; List <FilePosInfo> allCnFiles = Util.GetAllFiles(cnPatchFolder).Where(p => !p.IsFolder).ToList(); Util.IsGetAllFile = false; // 重新生成中文Iso文件 string isoShortName = Util.GetShortNameWithoutType(jpIsoFile); cnIsoFile = jpIsoFile.Replace(isoShortName + ".", isoShortName + "_CN."); if (File.Exists(cnIsoFile)) { File.Delete(cnIsoFile); } cnWriter = File.Open(cnIsoFile, FileMode.CreateNew); cnFs = new BufferedStream(cnWriter, COPY_BLOCK); cnFs.SetLength(NGC_ISO_LEN); // Copy第一个文件之前的数据信息 jpFs.Seek(0, SeekOrigin.Begin); cnFs.Seek(0, SeekOrigin.Begin); this.FileStreamCopy(cnFs, jpFs, firstFilePos); // 显示进度条 this.ResetProcessBar(jpFiInfos.Count); // 循环所有的原始文件,替换成相应中文文件,写入中文Iso int copyFile = 0; if (isReSize) { copyFile = WriteNgcTypeA(jpFiInfosForSort, jpFiInfos, allCnFiles, cnFs, jpFs); } else { copyFile = WriteNgcTypeB(jpFiInfosForSort, jpFiInfos, allCnFiles, cnFs, jpFs); } // 写入文件的位置信息 // 只有在改变了单个文件大小,位置的情况下才写入 if (isReSize) { for (int i = 1; i < fstNum; i++) { int fstTabOffset = i * 0xc; FilePosInfo filePosInfo = jpFiInfos[i + 1]; fstData[fstTabOffset + 0x4] = (byte)((filePosInfo.TextStart >> 24) & 0xFF); fstData[fstTabOffset + 0x5] = (byte)((filePosInfo.TextStart >> 16) & 0xFF); fstData[fstTabOffset + 0x6] = (byte)((filePosInfo.TextStart >> 8) & 0xFF); fstData[fstTabOffset + 0x7] = (byte)(filePosInfo.TextStart & 0xFF); fstData[fstTabOffset + 0x8] = (byte)((filePosInfo.TextEnd >> 24) & 0xFF); fstData[fstTabOffset + 0x9] = (byte)((filePosInfo.TextEnd >> 16) & 0xFF); fstData[fstTabOffset + 0xA] = (byte)((filePosInfo.TextEnd >> 8) & 0xFF); fstData[fstTabOffset + 0xB] = (byte)(filePosInfo.TextEnd & 0xFF); } cnFs.Seek(fstOffset, SeekOrigin.Begin); cnFs.Write(fstData, 0, fstData.Length); } // 隐藏进度条 this.CloseProcessBar(); MessageBox.Show("打汉化补丁完成!\n一共成功导入了:" + copyFile + " 个文件"); } finally { if (jpFs != null) { jpFs.Close(); } if (cnFs != null) { cnFs.Close(); } if (jpReader != null) { jpReader.Close(); } if (cnWriter != null) { cnWriter.Close(); } // 恢复按钮状态 this.SetWinStatus(true, oldTitle); } }
/// <summary> /// 生成新的Afs文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCreateAfs_Click(object sender, EventArgs e) { string afsFiles = @"E:\游戏汉化\NgcBioCv\BioCvNgcCn\A\root\rdx_lnkA"; List <FilePosInfo> fileInfos = Util.GetAllFiles(afsFiles).Where(p => !p.IsFolder && p.File.EndsWith(".rdx@", StringComparison.OrdinalIgnoreCase)).ToList(); string oldAfsFile = @"E:\游戏汉化\NgcBioCv\BioCvNgcJp\A\root\rdx_lnk1.afs"; byte[] byOldAfs = File.ReadAllBytes(oldAfsFile); int subFileCount = (byOldAfs[7] << 24) | (byOldAfs[6] << 16) | (byOldAfs[5] << 8) | byOldAfs[4]; int entryPos = 8; int nameEntryPos = entryPos + subFileCount * 8; nameEntryPos = (byOldAfs[nameEntryPos + 3] << 24) | (byOldAfs[nameEntryPos + 2] << 16) | (byOldAfs[nameEntryPos + 1] << 8) | byOldAfs[nameEntryPos]; List <FilePosInfo> oldFiles = new List <FilePosInfo>(); int firstPos = 0; for (int i = 0; i < subFileCount + 1; i++) { FilePosInfo fileInfo = new FilePosInfo(oldAfsFile); fileInfo.FilePos = (byOldAfs[entryPos + i * 8 + 3] << 24) | (byOldAfs[entryPos + i * 8 + 2] << 16) | (byOldAfs[entryPos + i * 8 + 1] << 8) | byOldAfs[entryPos + i * 8]; fileInfo.FileSize = (byOldAfs[entryPos + i * 8 + 7] << 24) | (byOldAfs[entryPos + i * 8 + 6] << 16) | (byOldAfs[entryPos + i * 8 + 5] << 8) | byOldAfs[entryPos + i * 8 + 4]; oldFiles.Add(fileInfo); if (i == 0) { firstPos = fileInfo.FilePos; } } if ((oldFiles.Count - fileInfos.Count) != 1) { return; } List <byte[]> newFileBy = new List <byte[]>(); for (int i = 0; i < oldFiles.Count - 1; i++) { FilePosInfo oldItem = oldFiles[i]; FilePosInfo newItem = fileInfos[i]; byte[] cnFile = File.ReadAllBytes(newItem.File); newFileBy.Add(cnFile); int newSize = cnFile.Length; int sizeDiff = newSize - oldItem.FileSize; if (sizeDiff != 0) { for (int j = i + 1; j < oldFiles.Count; j++) { FilePosInfo resetItem = oldFiles[j]; resetItem.FilePos += sizeDiff; // 开始位置特殊处理,必须是2048的倍数 int chkDiffLen = resetItem.FilePos % 2048; if (chkDiffLen > 0) { resetItem.FilePos += (2048 - chkDiffLen); } } } oldItem.FileSize = newSize; } FilePosInfo lastItem = oldFiles[oldFiles.Count - 1]; byte[] byNewAfs = new byte[lastItem.FilePos + lastItem.FileSize]; Array.Copy(byOldAfs, 0, byNewAfs, 0, 8); for (int i = 0; i < oldFiles.Count; i++) { FilePosInfo oldItem = oldFiles[i]; byNewAfs[entryPos + i * 8] = (byte)(oldItem.FilePos & 0xFF); byNewAfs[entryPos + i * 8 + 1] = (byte)((oldItem.FilePos >> 8) & 0xFF); byNewAfs[entryPos + i * 8 + 2] = (byte)((oldItem.FilePos >> 16) & 0xFF); byNewAfs[entryPos + i * 8 + 3] = (byte)((oldItem.FilePos >> 24) & 0xFF); byNewAfs[entryPos + i * 8 + 4] = (byte)(oldItem.FileSize & 0xFF); byNewAfs[entryPos + i * 8 + 5] = (byte)((oldItem.FileSize >> 8) & 0xFF); byNewAfs[entryPos + i * 8 + 6] = (byte)((oldItem.FileSize >> 16) & 0xFF); byNewAfs[entryPos + i * 8 + 7] = (byte)((oldItem.FileSize >> 24) & 0xFF); if (i < oldFiles.Count - 1) { FilePosInfo newItem = fileInfos[i]; Array.Copy(newFileBy[i], 0, byNewAfs, oldItem.FilePos, newFileBy[i].Length); } else { Array.Copy(byOldAfs, nameEntryPos, byNewAfs, lastItem.FilePos, lastItem.FileSize); } } File.WriteAllBytes(oldAfsFile.Replace("BioCvNgcJp", "BioCvNgcCn"), byNewAfs); }
/// <summary> /// 导出文本 /// </summary> private void ExoprtText() { Microsoft.Office.Interop.Excel.Application xApp = null; Microsoft.Office.Interop.Excel.Workbook xBook = null; Microsoft.Office.Interop.Excel.Worksheet xSheet = null; // 设定保存的文件名 string fileName = @"E:\My\Hanhua\testFile\bioCv\BioCvTextNgc.xls"; //string fileName = @"D:\game\iso\wii\生化危机维罗妮卡汉化\Bio0Text_" + this.exportName + ".xls"; // 先删除原来的文件 File.Delete(fileName); // 显示进度条 this.ResetProcessBar(this.fileList.Items.Count); try { // 创建Application对象 xApp = new Microsoft.Office.Interop.Excel.ApplicationClass(); //xApp.Visible = true; // 追加一个WorkBook xBook = xApp.Workbooks.Add(Missing.Value); for (int j = 0; j < this.fileList.Items.Count; j++) { // 追加一个Sheet FilePosInfo filePosInfo = this.textFiles[j]; // 更新当前文本 this.fileList.SelectedIndex = j; // 取得日文、中文文本 string jpText = this.txtJp.Text; string cnText = this.txtCn.Text; string sheetName = Util.GetShortFileName(filePosInfo.File); int sameNameCount = 0; for (int i = 0; i < j; i++) { if (Util.GetShortFileName(this.textFiles[i].File).IndexOf(sheetName) >= 0) { sameNameCount++; } } xSheet = (Microsoft.Office.Interop.Excel.Worksheet)xBook.Sheets.Add(Missing.Value, Missing.Value, Missing.Value, Missing.Value); xSheet.Name = sheetName + (sameNameCount > 0 ? "_" + sameNameCount.ToString().PadLeft(2, '0') : string.Empty); // 将每行文本保存到Sheet中 string[] jpTexts = jpText.Split('\n'); string[] cnTexts = cnText.Split('\n'); for (int i = 0; i < jpTexts.Length; i++) { // 写入日文文本 Microsoft.Office.Interop.Excel.Range rngJp = xSheet.get_Range("A" + (i + 1), Missing.Value); rngJp.Value2 = jpTexts[i]; } for (int i = 0; i < cnTexts.Length; i++) { // 写入中文文本 Microsoft.Office.Interop.Excel.Range rngCn = xSheet.get_Range("G" + (i + 1), Missing.Value); rngCn.Value2 = cnTexts[i]; } // 更新进度条 this.ProcessBarStep(); } // 保存 xSheet.SaveAs( fileName, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value); // 隐藏进度条 this.CloseProcessBar(); // 显示保存完成信息 MessageBox.Show("导出完成!"); } catch (Exception me) { MessageBox.Show(this.baseFile + "\n" + me.Message); } finally { // 隐藏进度条 this.CloseProcessBar(); // 清空各种对象 xSheet = null; xBook = null; if (xApp != null) { xApp.Quit(); xApp = null; } } }
/// <summary> /// 开始复制文本 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCopy_Click(object sender, EventArgs e) { if (!this.CheckFath(this.txtJpFolder) || !this.CheckFath(this.txtCnFolder) || !this.CheckFath(this.txtNgcFolder)) { return; } // 根据配置文件,取得所有需要Copy的文件 List <FilePosInfo> needCopyFiles = this.GetNeedCopyFiles(this.txtNgcFolder.Text, false); List <FilePosInfo> needCopyBinFiles = this.GetNeedCopyFiles(this.txtNgcFolder.Text, true); if (needCopyFiles.Count == 0 || needCopyBinFiles.Count == 0) { MessageBox.Show("路径错误,没有找到需要Copy的文件!"); return; } StringBuilder notExistFiles = new StringBuilder(); StringBuilder saveFaileFiles = new StringBuilder(); this.fileCheckInfo.Clear(); // 显示进度条 this.ResetProcessBar(needCopyFiles.Count + needCopyBinFiles.Count); try { // 开始循环所有的日文bin文件 for (int i = 0; i < needCopyBinFiles.Count; i++) { FilePosInfo fileInfo = needCopyBinFiles[i]; // 取得各个文件名 string fileName = @"\" + fileInfo.File.Replace("_1", string.Empty).Replace("_2", string.Empty).Replace("_3", string.Empty).Replace("_4", string.Empty).Replace("_5", string.Empty); string jpFile = this.txtJpFolder.Text + @"\BIN" + fileName + ".bin"; string cnFile = this.txtCnFolder.Text + @"\BIN" + fileName + ".bin"; string ngcFile = this.txtNgcFolder.Text + @"\root\&&systemdata\start_cn.dol"; if (File.Exists(jpFile) && File.Exists(cnFile)) { // 取得文本数据 int startPos = Convert.ToInt32(fileInfo.PosInfo[0], 16); int endPos = Convert.ToInt32(fileInfo.PosInfo[1], 16); byte[] byJpData = new byte[endPos - startPos]; byte[] byCnData = new byte[byJpData.Length]; this.GetTextData(jpFile, cnFile, fileInfo.PosInfo, byJpData, byCnData); // 保存文本数据 this.SaveTextData(ngcFile, byJpData, byCnData, notExistFiles, saveFaileFiles, fileInfo.File); } // 更新进度条 this.ProcessBarStep(); } // 开始循环所有的日文rdt文件 //for (int i = 1; i <= 7; i++) //{ // List<FilePosInfo> copyFiles = needCopyFiles.Where(p => p.File.IndexOf("r" + i) != -1).ToList(); // foreach (FilePosInfo fileInfo in copyFiles) // { // // 取得各个文件名 // string fileName = @"\" + fileInfo.File.Replace("_1", string.Empty).Replace("_2", string.Empty); // string jpFile = this.txtJpFolder.Text + @"\STAGE" + i + fileName + ".ard"; // string cnFile = this.txtCnFolder.Text + @"\STAGE" + i + fileName + ".ard"; // string ngcFile1 = this.txtNgcFolder.Text + @"\root\bio19\data_j\rdt" + fileName + ".rdt"; // string ngcFile2 = this.txtNgcFolder.Text + @"\root\bio19\data_aj\rdt" + fileName + ".rdt"; // if (File.Exists(jpFile) // && File.Exists(cnFile)) // { // // 取得文本数据 // int startPos = Convert.ToInt32(fileInfo.PosInfo[0], 16); // int endPos = Convert.ToInt32(fileInfo.PosInfo[1], 16); // byte[] byJpData = new byte[endPos - startPos]; // byte[] byCnData = new byte[byJpData.Length]; // this.GetTextData(jpFile, cnFile, fileInfo.PosInfo, byJpData, byCnData); // // 保存文本数据 // this.SaveTextData(ngcFile1, byJpData, byCnData, notExistFiles, saveFaileFiles, fileInfo.File); // this.SaveTextData(ngcFile2, byJpData, byCnData, notExistFiles, saveFaileFiles, fileInfo.File); // } // // 更新进度条 // this.ProcessBarStep(); // } //} // 隐藏进度条 this.CloseProcessBar(); } catch (Exception me) { MessageBox.Show(this.baseFile + "\n" + me.Message); } finally { // 隐藏进度条 this.CloseProcessBar(); } // 显示结果 if (notExistFiles.Length == 0 && saveFaileFiles.Length == 0) { MessageBox.Show("完全Copy成功!"); } else { MessageBox.Show("不存在的文件:\n" + notExistFiles.ToString() + "\n" + "错误的文件:\n" + saveFaileFiles.ToString()); } }
/// <summary> /// 选择文件变更 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void lstAsfFiles_SelectedIndexChanged(object sender, EventArgs e) { FilePosInfo fileInfo = this.textFiles[this.lstAsfFiles.SelectedIndex]; this.baseFile = fileInfo.File; }