public static CriTableReader Open(Stream source, long position, string expectedSignature) { source.Seek(position, SeekOrigin.Begin); if (DataStream.ReadCString(source, 4) != expectedSignature) { throw new InvalidDataException($"'{expectedSignature}' signature could not be found."); } uint flag = DataStream.ReadUInt32(source); uint tableLength = DataStream.ReadUInt32(source); uint unknown = DataStream.ReadUInt32(source); return(CriTableReader.Create(new SubStream(source, source.Position, tableLength))); }
public static ArrayList Deserialize(Stream source, Type type) { ArrayList arrayList = new ArrayList(); using (CriTableReader tableReader = CriTableReader.Create(source, true)) { IEnumerable <PropertyInfo> propertyInfos = type.GetProperties().Where(property => { if (property.GetCustomAttribute <CriIgnoreAttribute>() == null) { string fieldName = property.Name; if (property.GetCustomAttribute <CriFieldAttribute>() != null) { fieldName = property.GetCustomAttribute <CriFieldAttribute>().FieldName; } return(tableReader.ContainsField(fieldName)); } return(false); }); while (tableReader.Read()) { object obj = Activator.CreateInstance(type); // I hope this is faster than the old method lol foreach (PropertyInfo propertyInfo in propertyInfos) { string fieldName = propertyInfo.Name; if (propertyInfo.GetCustomAttribute <CriFieldAttribute>() != null) { fieldName = propertyInfo.GetCustomAttribute <CriFieldAttribute>().FieldName; } object value = tableReader.GetValue(fieldName); if (value is SubStream substream) { value = substream.ToArray(); } else if (value is byte boolean && propertyInfo.PropertyType == typeof(bool)) { value = boolean == 1; }
public override void Read(Stream source) { using (CriTableReader reader = CriTableReader.Create(source)) { switch (reader.TableName) { // ADX wrapper case "AAX": Mode = CriAaxArchiveMode.Adx; break; // DSP wrapper case "ADPCM_WII": Mode = CriAaxArchiveMode.Dsp; break; // WAV wrapper case "SWLPCM": Mode = CriAaxArchiveMode.Wav; break; // Unknown default: throw new InvalidDataException($"Unknown AAX type '{reader.TableName}'. Please report the error with the file(s)."); } if (Mode == CriAaxArchiveMode.Dsp) { // TODO throw new NotImplementedException("DSP files aren't supported yet."); } else { while (reader.Read()) { CriAaxEntry entry = new CriAaxEntry(); entry.Flag = (CriAaxEntryFlag)reader.GetByte("lpflg"); entry.Position = reader.GetPosition("data"); entry.Length = reader.GetLength("data"); entries.Add(entry); } } } }
public static void Main(string[] args) { var awbsByHeaderHash = new Dictionary <string, string>(); var acbsByAwbHeaderHash = new Dictionary <string, string>(); var lines = new List <string>(); string DirectoryForWork = ""; string outputDirectory = ""; if (args.Count() < 1) { DirectoryForWork = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); outputDirectory = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "output"); } else { DirectoryForWork = args[0]; outputDirectory = Path.Combine(args[0], "output"); } StreamWriter LogFile = new StreamWriter(Path.Combine(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "ACB_FinderLog.txt"))); Directory.CreateDirectory(outputDirectory); var md5 = MD5.Create(); var buffer = new byte[4]; var di = Directory.GetFiles(DirectoryForWork, "*", SearchOption.AllDirectories); Console.WriteLine("=== ACB Finder (" + DateTime.Now + ") ==="); LogFile.WriteLine("=== ACB Finder (" + DateTime.Now + ") ==="); Console.WriteLine("Found " + di.Length + " files in " + DirectoryForWork + "..."); LogFile.WriteLine("Found " + di.Length + " files in " + DirectoryForWork + "..."); int AWBsFound = 0; foreach (var filePath in di) { if (filePath.Contains("ACBFinder.exe") || filePath.Contains("SonicAudioLib.dll") || filePath.Contains("ACB_FinderLog.txt")) { continue; } using (var stream = File.OpenRead(filePath)) { stream.Read(buffer, 0, 4); var signature = Encoding.ASCII.GetString(buffer); if (signature == "AFS2") { Console.WriteLine("Found an AWB file: " + filePath.Replace(DirectoryForWork, "").Replace("\\", "")); LogFile.WriteLine("Found an AWB file: " + filePath.Replace(DirectoryForWork, "").Replace("\\", "")); AWBsFound++; stream.Read(buffer, 0, 4); int entryCount = DataStream.ReadInt32(stream); stream.Seek(4 + (entryCount * buffer[2]), SeekOrigin.Current); int length = (buffer[1] == 2 ? DataStream.ReadInt16(stream) : DataStream.ReadInt32(stream)) + 2; stream.Seek(0, SeekOrigin.Begin); var header = new byte[length]; stream.Read(header, 0, length); string hash = Convert.ToBase64String(md5.ComputeHash(header)); awbsByHeaderHash[hash] = filePath; } else if (signature == "@UTF") { stream.Seek(0, SeekOrigin.Begin); try { using (var reader = CriTableReader.Create(stream)) { reader.Read(); string name = (((FileStream)reader.SourceStream).Name).Replace(DirectoryForWork, "").Replace("\\", ""); //Properly get the filename using the stream and remove the directory from it name = name.Remove(name.Length - 4, 4); //Remove the extension too, just in case? File.Copy(filePath, Path.Combine(outputDirectory, name + ".acb"), true); Console.WriteLine("Found and copied ACB: {0}", name); LogFile.WriteLine("Found and copied ACB: {0}", name); lines.Add($"{Path.GetFileName(filePath)}={name}.acb"); if (reader.GetLength("StreamAwbAfs2Header") != 0) { //using ( var reader2 = reader.GetTableReader( "StreamAwbAfs2Header" ) ) //{ // reader2.Read(); var header = reader.GetData("StreamAwbAfs2Header"); var hash = Convert.ToBase64String(md5.ComputeHash(header)); acbsByAwbHeaderHash[hash] = name; //} } } } catch { Console.WriteLine("File could not be read correctly as an ACB: " + filePath.Replace(DirectoryForWork, "").Replace("\\", "")); LogFile.WriteLine("File could not be read correctly as an ACB: " + filePath.Replace(DirectoryForWork, "").Replace("\\", "")); continue; } } } } foreach (var pair in awbsByHeaderHash) { if (!acbsByAwbHeaderHash.TryGetValue(pair.Key, out string name)) { Console.WriteLine("AWB (" + pair.Key + ") with no ACB found."); LogFile.WriteLine("AWB (" + pair.Key + ") with no ACB found."); continue; } lines.Add($"{Path.GetFileName(pair.Value)}={name}.awb"); File.Copy(pair.Value, Path.Combine(outputDirectory, name + ".awb"), true); Console.WriteLine("Copied awb {0}", name); LogFile.WriteLine("Copied awb {0}", name); } foreach (var pair in acbsByAwbHeaderHash.Where(x => !awbsByHeaderHash.ContainsKey(x.Key))) { File.AppendAllText(Path.Combine(outputDirectory, "missing_awb.txt"), string.Format("{0}\n", pair.Value)); } File.WriteAllLines(Path.Combine(outputDirectory, "file_list.txt"), lines); Console.WriteLine("Process completed - Found " + AWBsFound + " AWB file(s). Press any key to exit."); LogFile.WriteLine("== Process completed (" + DateTime.Now + ") - Found " + AWBsFound + " AWB file(s). Press any key to exit. ==="); LogFile.Close(); Console.ReadKey(); }
static void Main(string[] args) { Settings.Default.Save(); if (args.Length < 1) { Console.WriteLine(Resources.Description); Console.ReadLine(); return; } #if !DEBUG try { #endif if (args[0].EndsWith(".csb", StringComparison.OrdinalIgnoreCase)) { var extractor = new DataExtractor(); extractor.ProgressChanged += OnProgressChanged; extractor.BufferSize = Settings.Default.BufferSize; extractor.EnableThreading = Settings.Default.EnableThreading; extractor.MaxThreads = Settings.Default.MaxThreads; string baseDirectory = Path.GetDirectoryName(args[0]); string outputDirectoryName = Path.Combine(baseDirectory, Path.GetFileNameWithoutExtension(args[0])); CriCpkArchive cpkArchive = null; string cpkPath = outputDirectoryName + ".cpk"; bool found = File.Exists(cpkPath); //This should fix "File not found" error in case-sensitive file systems. //Add new extensions when necessary. foreach (string extension in new string[] { "cpk", "CPK" }) { if (found) { break; } cpkPath = outputDirectoryName + "." + extension; found = File.Exists(cpkPath); } using (CriTableReader reader = CriTableReader.Create(args[0])) { while (reader.Read()) { if (reader.GetString("name") == "SOUND_ELEMENT") { long tablePosition = reader.GetPosition("utf"); using (CriTableReader sdlReader = CriTableReader.Create(reader.GetSubStream("utf"))) { while (sdlReader.Read()) { if (sdlReader.GetByte("fmt") != 0) { throw new Exception("The given CSB file contains an audio file which is not an ADX. Only CSB files with ADXs are supported."); } bool streaming = sdlReader.GetBoolean("stmflg"); if (streaming && !found) { throw new Exception("Cannot find the external .CPK file for this .CSB file. Please ensure that the external .CPK file is stored in the directory where the .CPK file is."); } else if (streaming && found && cpkArchive == null) { cpkArchive = new CriCpkArchive(); cpkArchive.Load(cpkPath, Settings.Default.BufferSize); } string sdlName = sdlReader.GetString("name"); DirectoryInfo destinationPath = new DirectoryInfo(Path.Combine(outputDirectoryName, sdlName)); destinationPath.Create(); CriAaxArchive aaxArchive = new CriAaxArchive(); if (streaming) { CriCpkEntry cpkEntry = cpkArchive.GetByPath(sdlName); if (cpkEntry != null) { using (Stream cpkSource = File.OpenRead(cpkPath)) using (Stream aaxSource = cpkEntry.Open(cpkSource)) { aaxArchive.Read(aaxSource); foreach (CriAaxEntry entry in aaxArchive) { extractor.Add(cpkPath, Path.Combine(destinationPath.FullName, entry.Flag == CriAaxEntryFlag.Intro ? "Intro.adx" : "Loop.adx"), cpkEntry.Position + entry.Position, entry.Length); } } } } else { long aaxPosition = sdlReader.GetPosition("data"); using (Stream aaxSource = sdlReader.GetSubStream("data")) { aaxArchive.Read(aaxSource); foreach (CriAaxEntry entry in aaxArchive) { extractor.Add(args[0], Path.Combine(destinationPath.FullName, entry.Flag == CriAaxEntryFlag.Intro ? "Intro.adx" : "Loop.adx"), tablePosition + aaxPosition + entry.Position, entry.Length); } } } } } break; } } } extractor.Run(); } else if (File.GetAttributes(args[0]).HasFlag(FileAttributes.Directory)) { string baseDirectory = Path.GetDirectoryName(args[0]); string csbPath = args[0] + ".csb"; foreach (string extension in new string[] { "csb", "CSB" }) { if (File.Exists(csbPath)) { break; } csbPath = args[0] + "." + extension; } if (!File.Exists(csbPath)) { throw new Exception("Cannot find the .CSB file for this directory. Please ensure that the .CSB file is stored in the directory where this directory is."); } CriCpkArchive cpkArchive = new CriCpkArchive(); cpkArchive.ProgressChanged += OnProgressChanged; CriTable csbFile = new CriTable(); csbFile.Load(csbPath, Settings.Default.BufferSize); CriRow soundElementRow = csbFile.Rows.First(row => (string)row["name"] == "SOUND_ELEMENT"); CriTable soundElementTable = new CriTable(); soundElementTable.Load((byte[])soundElementRow["utf"]); List <FileInfo> junks = new List <FileInfo>(); foreach (CriRow sdlRow in soundElementTable.Rows) { string sdlName = (string)sdlRow["name"]; DirectoryInfo sdlDirectory = new DirectoryInfo(Path.Combine(args[0], sdlName)); if (!sdlDirectory.Exists) { throw new Exception($"Cannot find sound element directory for replacement.\nPath attempt: {sdlDirectory.FullName}"); } bool streaming = (byte)sdlRow["stmflg"] != 0; uint sampleRate = (uint)sdlRow["sfreq"]; byte numberChannels = (byte)sdlRow["nch"]; CriAaxArchive aaxArchive = new CriAaxArchive(); foreach (FileInfo file in sdlDirectory.GetFiles("*.adx")) { CriAaxEntry entry = new CriAaxEntry(); if (file.Name.ToLower(CultureInfo.GetCultureInfo("en-US")) == "intro.adx") { entry.Flag = CriAaxEntryFlag.Intro; entry.FilePath = file; aaxArchive.Add(entry); ReadAdx(file, out sampleRate, out numberChannels); } else if (file.Name.ToLower(CultureInfo.GetCultureInfo("en-US")) == "loop.adx") { entry.Flag = CriAaxEntryFlag.Loop; entry.FilePath = file; aaxArchive.Add(entry); ReadAdx(file, out sampleRate, out numberChannels); } } if (streaming) { CriCpkEntry entry = new CriCpkEntry(); entry.Name = Path.GetFileName(sdlName); entry.DirectoryName = Path.GetDirectoryName(sdlName); entry.Id = (uint)cpkArchive.Count; entry.FilePath = new FileInfo(Path.GetTempFileName()); junks.Add(entry.FilePath); cpkArchive.Add(entry); aaxArchive.Save(entry.FilePath.FullName, Settings.Default.BufferSize); } else { sdlRow["data"] = aaxArchive.Save(); } sdlRow["sfreq"] = sampleRate; sdlRow["nch"] = numberChannels; } soundElementTable.WriterSettings = CriTableWriterSettings.AdxSettings; soundElementRow["utf"] = soundElementTable.Save(); csbFile.WriterSettings = CriTableWriterSettings.AdxSettings; csbFile.Save(csbPath, Settings.Default.BufferSize); if (cpkArchive.Count > 0) { string cpkPath = args[0] + ".cpk"; foreach (string extension in new string[] { "cpk", "CPK" }) { if (File.Exists(args[0] + "." + extension)) { cpkPath = args[0] + "." + extension; break; } } cpkArchive.Save(cpkPath, Settings.Default.BufferSize); } foreach (FileInfo junk in junks) { junk.Delete(); } } #if !DEBUG } catch (Exception exception) { MessageBox.Show($"{exception.Message}", "CSB Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); } #endif }
// All taken from the code for CsbEditor: https://github.com/blueskythlikesclouds/SonicAudioTools/blob/master/Source/CsbEditor/Program.cs public static async Task CSBUnpack(string csbFile) { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); DataExtractor?extractor = new() { EnableThreading = false }; string baseDirectory = Path.GetDirectoryName(csbFile); string outputDirectoryName = Path.Combine(baseDirectory, Path.GetFileNameWithoutExtension(csbFile)); CriCpkArchive cpkArchive = null; string cpkPath = outputDirectoryName + ".cpk"; bool found = File.Exists(cpkPath); //This should fix "File not found" error in case-sensitive file systems. //Add new extensions when necessary. foreach (string extension in new string[] { "cpk", "CPK" }) { if (found) { break; } cpkPath = outputDirectoryName + "." + extension; found = File.Exists(cpkPath); } using (CriTableReader reader = CriTableReader.Create(csbFile)) { while (reader.Read()) { if (reader.GetString("name") == "SOUND_ELEMENT") { long tablePosition = reader.GetPosition("utf"); using (CriTableReader sdlReader = CriTableReader.Create(reader.GetSubStream("utf"))) { while (sdlReader.Read()) { if (sdlReader.GetByte("fmt") != 0) { throw new Exception("The given CSB file contains an audio file which is not an ADX. Only CSB files with ADXs are supported."); } bool streaming = sdlReader.GetBoolean("stmflg"); if (streaming && !found) { throw new Exception("Cannot find the external .CPK file for this .CSB file. Please ensure that the external .CPK file is stored in the directory where the .CPK file is."); } else if (streaming && found && cpkArchive == null) { cpkArchive = new CriCpkArchive(); cpkArchive.Load(cpkPath, 4096); } string sdlName = sdlReader.GetString("name"); DirectoryInfo destinationPath = new DirectoryInfo(Path.Combine(outputDirectoryName, sdlName)); destinationPath.Create(); CriAaxArchive aaxArchive = new CriAaxArchive(); if (streaming) { CriCpkEntry cpkEntry = cpkArchive.GetByPath(sdlName); if (cpkEntry != null) { using (Stream cpkSource = File.OpenRead(cpkPath)) using (Stream aaxSource = cpkEntry.Open(cpkSource)) { aaxArchive.Read(aaxSource); foreach (CriAaxEntry entry in aaxArchive) { extractor.Add(cpkPath, Path.Combine(destinationPath.FullName, entry.Flag == CriAaxEntryFlag.Intro ? "Intro.adx" : "Loop.adx"), cpkEntry.Position + entry.Position, entry.Length); } } } } else { long aaxPosition = sdlReader.GetPosition("data"); using (Stream aaxSource = sdlReader.GetSubStream("data")) { aaxArchive.Read(aaxSource); foreach (CriAaxEntry entry in aaxArchive) { extractor.Add(csbFile, Path.Combine(destinationPath.FullName, entry.Flag == CriAaxEntryFlag.Intro ? "Intro.adx" : "Loop.adx"), tablePosition + aaxPosition + entry.Position, entry.Length); } } } } } break; } } } extractor.Run(); }
static void Main(string[] args) { if (!File.Exists(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)) { Settings.Default.Reset(); Settings.Default.Save(); } if (args.Length < 1) { Console.WriteLine(Resources.Description); Console.ReadLine(); return; } #if !DEBUG try { #endif if (args[0].EndsWith(".acb", StringComparison.OrdinalIgnoreCase)) { var extractor = new DataExtractor(); extractor.ProgressChanged += OnProgressChanged; extractor.BufferSize = Settings.Default.BufferSize; extractor.EnableThreading = Settings.Default.EnableThreading; extractor.MaxThreads = Settings.Default.MaxThreads; string baseDirectory = Path.GetDirectoryName(args[0]); string outputDirectoryPath = Path.ChangeExtension(args[0], null); string extAfs2ArchivePath = string.Empty; Directory.CreateDirectory(outputDirectoryPath); using (CriTableReader acbReader = CriTableReader.Create(args[0])) { acbReader.Read(); CriAfs2Archive afs2Archive = new CriAfs2Archive(); CriAfs2Archive extAfs2Archive = new CriAfs2Archive(); CriCpkArchive cpkArchive = new CriCpkArchive(); CriCpkArchive extCpkArchive = null; extAfs2ArchivePath = outputDirectoryPath + ".awb"; bool found = File.Exists(extAfs2ArchivePath); if (!found) { extAfs2ArchivePath = outputDirectoryPath + "_streamfiles.awb"; found = File.Exists(extAfs2ArchivePath); } if (!found) { extAfs2ArchivePath = outputDirectoryPath + "_STR.awb"; found = File.Exists(extAfs2ArchivePath); } bool cpkMode = true; long awbPosition = acbReader.GetPosition("AwbFile"); if (acbReader.GetLength("AwbFile") > 0) { using (SubStream afs2Stream = acbReader.GetSubStream("AwbFile")) { cpkMode = !CheckIfAfs2(afs2Stream); if (cpkMode) { cpkArchive.Read(afs2Stream); } else { afs2Archive.Read(afs2Stream); } } } if (acbReader.GetLength("StreamAwbAfs2Header") > 0) { cpkMode = false; using (SubStream extAfs2Stream = acbReader.GetSubStream("StreamAwbAfs2Header")) { bool utfMode = DataStream.ReadCString(extAfs2Stream, 4) == "@UTF"; extAfs2Stream.Seek(0, SeekOrigin.Begin); if (utfMode) { using (CriTableReader utfAfs2HeaderReader = CriTableReader.Create(extAfs2Stream)) { utfAfs2HeaderReader.Read(); using (SubStream extAfs2HeaderStream = utfAfs2HeaderReader.GetSubStream("Header")) { extAfs2Archive.Read(extAfs2HeaderStream); } } } else { extAfs2Archive.Read(extAfs2Stream); } } if (!found) { throw new FileNotFoundException("Cannot find the external .AWB file for this .ACB file. Please ensure that the external .AWB file is stored in the directory where the .ACB file is."); } } using (SubStream waveformTableStream = acbReader.GetSubStream("WaveformTable")) using (CriTableReader waveformReader = CriTableReader.Create(waveformTableStream)) { while (waveformReader.Read()) { byte encodeType = waveformReader.GetByte("EncodeType"); bool streaming = waveformReader.GetBoolean("Streaming"); ushort id = waveformReader.ContainsField("MemoryAwbId") ? streaming ? waveformReader.GetUInt16("StreamAwbId") : waveformReader.GetUInt16("MemoryAwbId") : waveformReader.GetUInt16("Id"); string outputName = id.ToString("D5"); if (streaming) { outputName += "_streaming"; } outputName += GetExtension(encodeType); outputName = Path.Combine(outputDirectoryPath, outputName); if (streaming) { if (!found) { throw new Exception("Cannot find the external .AWB file for this .ACB file. Please ensure that the external .AWB file is stored in the directory where the .ACB file is."); } else if (extCpkArchive == null && cpkMode) { extCpkArchive = new CriCpkArchive(); extCpkArchive.Load(extAfs2ArchivePath, Settings.Default.BufferSize); } EntryBase afs2Entry = null; if (cpkMode) { afs2Entry = extCpkArchive.GetById(id); } else { afs2Entry = extAfs2Archive.GetById(id); } extractor.Add(extAfs2ArchivePath, outputName, afs2Entry.Position, afs2Entry.Length); } else { EntryBase afs2Entry = null; if (cpkMode) { afs2Entry = cpkArchive.GetById(id); } else { afs2Entry = afs2Archive.GetById(id); } extractor.Add(args[0], outputName, awbPosition + afs2Entry.Position, afs2Entry.Length); } } } } extractor.Run(); } else if (File.GetAttributes(args[0]).HasFlag(FileAttributes.Directory)) { string baseDirectory = Path.GetDirectoryName(args[0]); string acbPath = args[0] + ".acb"; string awbPath = args[0] + "_streamfiles.awb"; bool found = File.Exists(awbPath); if (!found) { awbPath = args[0] + "_STR.awb"; found = File.Exists(awbPath); } if (!found) { awbPath = args[0] + ".awb"; } if (!File.Exists(acbPath)) { throw new FileNotFoundException("Cannot find the .ACB file for this directory. Please ensure that the .ACB file is stored in the directory where this directory is."); } CriTable acbFile = new CriTable(); acbFile.Load(acbPath, Settings.Default.BufferSize); CriAfs2Archive afs2Archive = new CriAfs2Archive(); CriAfs2Archive extAfs2Archive = new CriAfs2Archive(); CriCpkArchive cpkArchive = new CriCpkArchive(); CriCpkArchive extCpkArchive = new CriCpkArchive(); cpkArchive.Mode = extCpkArchive.Mode = CriCpkMode.Id; afs2Archive.ProgressChanged += OnProgressChanged; extAfs2Archive.ProgressChanged += OnProgressChanged; cpkArchive.ProgressChanged += OnProgressChanged; extCpkArchive.ProgressChanged += OnProgressChanged; bool cpkMode = true; byte[] awbFile = (byte[])acbFile.Rows[0]["AwbFile"]; byte[] streamAwbAfs2Header = (byte[])acbFile.Rows[0]["StreamAwbAfs2Header"]; cpkMode = !(awbFile != null && awbFile.Length >= 4 && Encoding.ASCII.GetString(awbFile, 0, 4) == "AFS2") && (streamAwbAfs2Header == null || streamAwbAfs2Header.Length == 0); using (CriTableReader reader = CriTableReader.Create((byte[])acbFile.Rows[0]["WaveformTable"])) { while (reader.Read()) { byte encodeType = reader.GetByte("EncodeType"); bool streaming = reader.GetBoolean("Streaming"); ushort id = reader.ContainsField("MemoryAwbId") ? streaming ? reader.GetUInt16("StreamAwbId") : reader.GetUInt16("MemoryAwbId") : reader.GetUInt16("Id"); string inputName = id.ToString("D5"); if (streaming) { inputName += "_streaming"; } inputName += GetExtension(encodeType); inputName = Path.Combine(args[0], inputName); if (!File.Exists(inputName)) { throw new FileNotFoundException($"Cannot find audio file with id {id} for replacement.\nPath attempt: {inputName}"); } if (cpkMode) { CriCpkEntry entry = new CriCpkEntry(); entry.FilePath = new FileInfo(inputName); entry.Id = id; if (streaming) { extCpkArchive.Add(entry); } else { cpkArchive.Add(entry); } } else { CriAfs2Entry entry = new CriAfs2Entry(); entry.FilePath = new FileInfo(inputName); entry.Id = id; if (streaming) { extAfs2Archive.Add(entry); } else { afs2Archive.Add(entry); } } } } acbFile.Rows[0]["AwbFile"] = null; acbFile.Rows[0]["StreamAwbAfs2Header"] = null; if (afs2Archive.Count > 0 || cpkArchive.Count > 0) { Console.WriteLine("Saving internal AWB..."); acbFile.Rows[0]["AwbFile"] = cpkMode ? cpkArchive.Save() : afs2Archive.Save(); Console.WriteLine(); } if (extAfs2Archive.Count > 0 || extCpkArchive.Count > 0) { Console.WriteLine("Saving external AWB..."); if (cpkMode) { extCpkArchive.Save(awbPath, Settings.Default.BufferSize); } else { extAfs2Archive.Save(awbPath, Settings.Default.BufferSize); if (Encoding.UTF8.GetString(streamAwbAfs2Header, 0, 4) == "@UTF") { CriTable headerTable = new CriTable(); headerTable.Load(streamAwbAfs2Header); headerTable.Rows[0]["Header"] = extAfs2Archive.Header; headerTable.WriterSettings = CriTableWriterSettings.Adx2Settings; acbFile.Rows[0]["StreamAwbAfs2Header"] = headerTable.Save(); } else { acbFile.Rows[0]["StreamAwbAfs2Header"] = extAfs2Archive.Header; } } } acbFile.WriterSettings = CriTableWriterSettings.Adx2Settings; acbFile.Save(acbPath, Settings.Default.BufferSize); } #if !DEBUG } catch (Exception exception) { MessageBox.Show($"{exception.Message}", "ACB Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); } #endif }
public override void Read(Stream source) { using (CriTableReader reader = CriCpkSection.Open(source, source.Position, "CPK ")) { reader.Read(); bool isLatestVersion = reader.ContainsField("CpkMode"); if (isLatestVersion) { mode = (CriCpkMode)reader.GetUInt32("CpkMode"); } else { bool tocEnabled = reader.GetUInt64("TocOffset") > 0; bool itocEnabled = reader.GetUInt64("ItocOffset") > 0; if (tocEnabled && !itocEnabled) { mode = CriCpkMode.FileName; } else if (!tocEnabled && itocEnabled) { mode = CriCpkMode.Id; } else if (tocEnabled && itocEnabled) { mode = CriCpkMode.FileNameAndId; } else { mode = CriCpkMode.None; } } // No need to waste time, stop right there. if (mode == CriCpkMode.None) { return; } long tocPosition = (long)reader.GetUInt64("TocOffset"); long itocPosition = (long)reader.GetUInt64("ItocOffset"); long etocPosition = (long)reader.GetUInt64("EtocOffset"); long contentPosition = (long)reader.GetUInt64("ContentOffset"); align = reader.GetUInt16("Align"); if (mode == CriCpkMode.FileName || mode == CriCpkMode.FileNameAndId) { using (CriTableReader tocReader = CriCpkSection.Open(source, tocPosition, "TOC ")) using (CriTableReader etocReader = CriCpkSection.Open(source, etocPosition, "ETOC")) { while (tocReader.Read()) { CriCpkEntry entry = new CriCpkEntry(); entry.DirectoryName = tocReader.GetString("DirName"); entry.Name = tocReader.GetString("FileName"); entry.Length = tocReader.GetUInt32("FileSize"); entry.Position = (long)tocReader.GetUInt64("FileOffset"); entry.Id = isLatestVersion ? tocReader.GetUInt32("ID") : tocReader.GetUInt32("Info"); entry.Comment = tocReader.GetString("UserString"); entry.UncompressedLength = tocReader.GetUInt32("ExtractSize"); entry.IsCompressed = entry.Length != entry.UncompressedLength; if (contentPosition < tocPosition) { entry.Position += contentPosition; } else { entry.Position += tocPosition; } entry.Position = Helpers.Align(entry.Position, align); etocReader.MoveToRow(tocReader.CurrentRow); entry.UpdateDateTime = DateTimeFromCpkDateTime(etocReader.GetUInt64("UpdateDateTime")); entries.Add(entry); } } if (mode == CriCpkMode.FileNameAndId && isLatestVersion) { using (CriTableReader itocReader = CriCpkSection.Open(source, itocPosition, "ITOC")) { while (itocReader.Read()) { entries[itocReader.GetInt32("TocIndex")].Id = (uint)itocReader.GetInt32("ID"); } } } } else if (mode == CriCpkMode.Id) { using (CriTableReader itocReader = CriCpkSection.Open(source, itocPosition, "ITOC")) { while (itocReader.Read()) { if (itocReader.GetUInt32("FilesL") > 0) { using (CriTableReader dataReader = itocReader.GetTableReader("DataL")) { while (dataReader.Read()) { CriCpkEntry entry = new CriCpkEntry(); entry.Id = dataReader.GetUInt16("ID"); entry.Length = dataReader.GetUInt16("FileSize"); entry.UncompressedLength = dataReader.GetUInt16("ExtractSize"); entry.IsCompressed = entry.Length != entry.UncompressedLength; entries.Add(entry); } } } if (itocReader.GetUInt32("FilesH") > 0) { using (CriTableReader dataReader = itocReader.GetTableReader("DataH")) { while (dataReader.Read()) { CriCpkEntry entry = new CriCpkEntry(); entry.Id = dataReader.GetUInt16("ID"); entry.Length = dataReader.GetUInt32("FileSize"); entry.UncompressedLength = dataReader.GetUInt32("ExtractSize"); entry.IsCompressed = entry.Length != entry.UncompressedLength; entries.Add(entry); } } } } } long entryPosition = contentPosition; foreach (CriCpkEntry entry in entries.OrderBy(entry => entry.Id)) { entryPosition = Helpers.Align(entryPosition, align); entry.Position = entryPosition; entryPosition += entry.Length; } } else { throw new NotImplementedException($"Unimplemented CPK mode ({mode})"); } Comment = reader.GetString("Comment"); } }