public CPKData(string filePath) { FilePath = filePath; CPK = new CPK(new Tools()); CPK.ReadCPK(filePath, Encoding); Tables = new List <CPKTable>(); BinaryReader binaryReader = new BinaryReader(File.OpenRead(filePath)); List <FileEntry> list = CPK.FileTable.OrderBy((FileEntry x) => x.FileOffset).ToList(); int i = 0; bool flag = Tools.CheckListRedundant(list); for (; i < list.Count; i++) { if (list[i].FileType != null) { Nums++; CPKTable cPKTable = new CPKTable(); if (list[i].ID == null) { cPKTable.id = -1; } else { cPKTable.id = Convert.ToInt32(list[i].ID); } if (cPKTable.id >= 0 && flag) { cPKTable.FileName = ((list[i].DirName != null) ? string.Concat(list[i].DirName, "/") : "") + $"[{cPKTable.id.ToString()}]" + list[i].FileName; } else { cPKTable.FileName = ((list[i].DirName != null) ? string.Concat(list[i].DirName, "/") : "") + list[i].FileName; } cPKTable.LocalName = list[i].FileName.ToString(); cPKTable.FileOffset = Convert.ToUInt64(list[i].FileOffset); cPKTable.FileSize = Convert.ToInt32(list[i].FileSize); cPKTable.ExtractSize = Convert.ToInt32(list[i].ExtractSize); cPKTable.FileType = list[i].FileType; if (list[i].FileType == "FILE") { cPKTable.Pt = (float)Math.Round((float)cPKTable.FileSize / (float)cPKTable.ExtractSize, 2) * 100f; } else { cPKTable.Pt = 100f; } Tables.Add(cPKTable); } } binaryReader.Close(); }
// Taken from CriPakTools - see adknowledgements private void ReplaceCPKFiles(string sourceCPK, string targetCPK, Dictionary <string, string> batchFileList) { CPK cpk = new CPK(new Tools()); cpk.ReadCPK(sourceCPK, ActiveEncodings.currentEncoding); BinaryReader oldFile = new BinaryReader(File.OpenRead(sourceCPK)); bool bUseCompress = false; // this could cause problems later if access to compressed files is needed FileInfo fi = new FileInfo(sourceCPK); string outputName = targetCPK; BinaryWriter newCPK = new BinaryWriter(File.OpenWrite(outputName)); List <FileEntry> entries = cpk.FileTable.OrderBy(x => x.FileOffset).ToList(); Tools tool = new Tools(); for (int i = 0; i < entries.Count; i++) { if (entries[i].FileType != "CONTENT") { if (entries[i].FileType == "FILE") { // I'm too lazy to figure out how to update the ContextOffset position so this works :) if ((ulong)newCPK.BaseStream.Position < cpk.ContentOffset) { ulong padLength = cpk.ContentOffset - (ulong)newCPK.BaseStream.Position; for (ulong z = 0; z < padLength; z++) { newCPK.Write((byte)0); } } } string currentName = ((entries[i].DirName != null) ? entries[i].DirName + "/" : "") + entries[i].FileName; if (!currentName.Contains("/")) { currentName = "/" + currentName; } if (!batchFileList.Keys.Contains(currentName.ToString())) //如果不在表中,复制原始数据 { oldFile.BaseStream.Seek((long)entries[i].FileOffset, SeekOrigin.Begin); entries[i].FileOffset = (ulong)newCPK.BaseStream.Position; if (entries[i].FileName.ToString() == "ETOC_HDR") { cpk.EtocOffset = entries[i].FileOffset; Console.WriteLine("Fix ETOC_OFFSET to {0:x8}", cpk.EtocOffset); } cpk.UpdateFileEntry(entries[i]); byte[] chunk = oldFile.ReadBytes(Int32.Parse(entries[i].FileSize.ToString())); newCPK.Write(chunk); if ((newCPK.BaseStream.Position % 0x800) > 0 && i < entries.Count - 1) { long cur_pos = newCPK.BaseStream.Position; for (int j = 0; j < (0x800 - (cur_pos % 0x800)); j++) { newCPK.Write((byte)0); } } } else { string replace_with = batchFileList[currentName.ToString()]; //Got patch file name Console.WriteLine("Patching: {0}", currentName.ToString()); byte[] newbie = File.ReadAllBytes(replace_with); entries[i].FileOffset = (ulong)newCPK.BaseStream.Position; int o_ext_size = Int32.Parse((entries[i].ExtractSize).ToString()); int o_com_size = Int32.Parse((entries[i].FileSize).ToString()); if ((o_com_size < o_ext_size) && entries[i].FileType == "FILE" && bUseCompress == true) { // is compressed Console.Write("Compressing data:{0:x8}", newbie.Length); byte[] dest_comp = cpk.CompressCRILAYLA(newbie); entries[i].FileSize = Convert.ChangeType(dest_comp.Length, entries[i].FileSizeType); entries[i].ExtractSize = Convert.ChangeType(newbie.Length, entries[i].FileSizeType); cpk.UpdateFileEntry(entries[i]); newCPK.Write(dest_comp); Console.Write(">> {0:x8}\r\n", dest_comp.Length); } else { Console.Write("Storing data:{0:x8}\r\n", newbie.Length); entries[i].FileSize = Convert.ChangeType(newbie.Length, entries[i].FileSizeType); entries[i].ExtractSize = Convert.ChangeType(newbie.Length, entries[i].FileSizeType); cpk.UpdateFileEntry(entries[i]); newCPK.Write(newbie); } if ((newCPK.BaseStream.Position % 0x800) > 0 && i < entries.Count - 1) { long cur_pos = newCPK.BaseStream.Position; for (int j = 0; j < (0x800 - (cur_pos % 0x800)); j++) { newCPK.Write((byte)0); } } } } else { // Content is special.... just update the position cpk.UpdateFileEntry(entries[i]); } } cpk.WriteCPK(newCPK); cpk.WriteITOC(newCPK); cpk.WriteTOC(newCPK); cpk.WriteETOC(newCPK, cpk.EtocOffset); cpk.WriteGTOC(newCPK); newCPK.Close(); oldFile.Close(); }
private CPKBuildObject FilterCPKFile(FileLocationMeta file, string sourceDirectoryPath, string targetDirectoryPath) { var cpkFile = new CPK(new Tools()); // this function gets a bit confusings since file, cpkFile and embeddedFile are all thrown around - i will need to fix that var filePath = Path.Combine(sourceDirectoryPath, file.subPath, file.fileName); if (!cpkFile.ReadCPK(filePath, ActiveEncodings.currentEncoding)) { string errorMessage = string.Format("Unknown error while attempting to open {0}.", filePath); MessageBox.Show(errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); // this could be replaced with a custom form that allows the user to skip all errors or a simple "errors while opening X files" after the files are done being read. though, the later option would require a small restructuring of the code. Environment.Exit(1); } int realFileCount = 0; foreach (var embeddedFile in cpkFile.FileTable) { if (embeddedFile.FileType.ToString() == "FILE") { realFileCount += 1; } } if (realFileCount == 0) { string errorMessage = string.Format("CPK file {0} was empty.", filePath); // i am not sure this should be a fatal error - i will attempt to come back to it once i have a more complete picture of how the build system works and thus have a better idea of how to handle such an eventuality MessageBox.Show(errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(1); } CPKBuildObject cpkBuildInstructions = new CPKBuildObject(); string originalFileLocation = Path.Combine(ProjectFolder.extractedISODir, file.subPath, file.fileName); cpkBuildInstructions.SetOriginalFileLocation(originalFileLocation); string targetFileLocation = Path.Combine(ProjectFolder.repackedGameFilesDir, file.subPath, file.fileName); cpkBuildInstructions.SetTargetFileLocation(targetFileLocation); if (realFileCount > 1) // if there is more than one file in the CPK we move the files within it to their own directory { string newSubDir = Path.GetFileNameWithoutExtension(file.fileName); string newSubPath = Path.Combine(file.subPath, newSubDir); file.subPath = newSubPath; } foreach (var embeddedFile in cpkFile.FileTable) { var cpkMeta = new CPKEmbeddedFileMeta(); if (embeddedFile.FileType != "FILE") { continue; // skip headers etc. } if (FileParser.IsParseable(embeddedFile.FileName.ToString())) // use this to determine whether to unpack or not, not save location { file.switchPath = editableDirectory; } else { file.switchPath = rawDirectory; } string targetFileAbsolutePath = Path.Combine(targetDirectoryPath, ProjectFolder.unpackedGameFilesDir, file.subPath, embeddedFile.FileName.ToString()); DirectoryGuard.CheckDirectory(targetFileAbsolutePath); byte[] fileAsBytes = GrabCPKData(filePath, embeddedFile); if (DebugSettings.ATTEMPT_DECOMPRESSION) { if (fileAsBytes.Length >= 8) // 8 = length of "CRILAYLA" { byte[] crilaylaCheck = new byte[8]; Array.Copy(fileAsBytes, 0, crilaylaCheck, 0, 8); string crilaylaString = Encoding.ASCII.GetString(crilaylaCheck); if (crilaylaString == "CRILAYLA") { byte[] decompressedBytes = cpkFile.DecompressCRILAYLA(fileAsBytes, fileAsBytes.Length); fileAsBytes = decompressedBytes; } } } if (DebugSettings.ALLOW_FILE_WRITES) { FileStream fs = new FileStream(targetFileAbsolutePath, FileMode.Create); BinaryWriter bw = new BinaryWriter(fs); bw.Write(fileAsBytes); bw.Close(); fs.Close(); } if (DebugSettings.COPY_UNPACKED_FILES) { string secondTargetPath = Path.Combine(targetDirectoryPath, ProjectFolder.reassembledGameFilesDir, file.subPath, embeddedFile.FileName.ToString()); DirectoryGuard.CheckDirectory(secondTargetPath); FileStream fs = new FileStream(secondTargetPath, FileMode.Create); BinaryWriter bw = new BinaryWriter(fs); bw.Write(fileAsBytes); bw.Close(); fs.Close(); } string relativeFilePath = Path.Combine(file.subPath, embeddedFile.FileName.ToString()); uint fileID = (uint)embeddedFile.ID; cpkMeta.filePath = Path.Combine(ProjectFolder.reassembledGameFilesDir, relativeFilePath); cpkMeta.fileName = embeddedFile.FileName.ToString(); cpkMeta.checksumType = Checksum.MD5; cpkMeta.checksumValue = Checksums.GetMD5(fileAsBytes); cpkMeta.ID = fileID; cpkBuildInstructions.AddFile(fileID, cpkMeta); } cpkBuildInstructions.SerializeToDisk(Path.Combine(targetDirectoryPath, ProjectFolder.buildScriptsDir)); return(cpkBuildInstructions); }