public static void Build(CsbProject project, string outputFileName) { CriCpkArchive cpkArchive = new CriCpkArchive(); DirectoryInfo outputDirectory = new DirectoryInfo(Path.GetDirectoryName(outputFileName)); List <SerializationCueSheetTable> cueSheetTables = new List <SerializationCueSheetTable>(); SerializationVersionInfoTable versionInfoTable = new SerializationVersionInfoTable(); cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(new List <SerializationVersionInfoTable>() { versionInfoTable }, CriTableWriterSettings.AdxSettings), Name = "INFO", TableType = 7, }); // Serialize cues. List <SerializationCueTable> cueTables = new List <SerializationCueTable>(); foreach (BuilderCueNode cueNode in project.CueNodes) { cueTables.Add(new SerializationCueTable { Name = cueNode.Name, Id = cueNode.Identifier, UserData = cueNode.UserComment, Flags = cueNode.Flags, SynthPath = cueNode.SynthReference, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(cueTables, CriTableWriterSettings.AdxSettings), Name = "CUE", TableType = 1, }); // Serialize synth tables. List <SerializationSynthTable> synthTables = new List <SerializationSynthTable>(); foreach (BuilderSynthNode synthNode in project.SynthNodes) { SerializationSynthTable synthTable = new SerializationSynthTable { SynthName = synthNode.Name, SynthType = (byte)synthNode.Type, ComplexType = (byte)synthNode.PlaybackType, Volume = synthNode.Volume, Pitch = synthNode.Pitch, DelayTime = synthNode.DelayTime, SControl = synthNode.SControl, EgDelay = synthNode.EgDelay, EgAttack = synthNode.EgAttack, EgHold = synthNode.EgHold, EgDecay = synthNode.EgDecay, EgRelease = synthNode.EgRelease, EgSustain = synthNode.EgSustain, FType = synthNode.FilterType, FCof1 = synthNode.FilterCutoff1, FCof2 = synthNode.FilterCutoff2, FReso = synthNode.FilterReso, FReleaseOffset = synthNode.FilterReleaseOffset, DryOName = synthNode.DryOName, Mtxrtr = synthNode.Mtxrtr, Dry0 = synthNode.Dry0, Dry1 = synthNode.Dry1, Dry2 = synthNode.Dry2, Dry3 = synthNode.Dry3, Dry4 = synthNode.Dry4, Dry5 = synthNode.Dry5, Dry6 = synthNode.Dry6, Dry7 = synthNode.Dry7, WetOName = synthNode.WetOName, Wet0 = synthNode.Wet0, Wet1 = synthNode.Wet1, Wet2 = synthNode.Wet2, Wet3 = synthNode.Wet3, Wet4 = synthNode.Wet4, Wet5 = synthNode.Wet5, Wet6 = synthNode.Wet6, Wet7 = synthNode.Wet7, Wcnct0 = synthNode.Wcnct0, Wcnct1 = synthNode.Wcnct1, Wcnct2 = synthNode.Wcnct2, Wcnct3 = synthNode.Wcnct3, Wcnct4 = synthNode.Wcnct4, Wcnct5 = synthNode.Wcnct5, Wcnct6 = synthNode.Wcnct6, Wcnct7 = synthNode.Wcnct7, VoiceLimitGroupName = synthNode.VoiceLimitGroupReference, VoiceLimitType = synthNode.VoiceLimitType, VoiceLimitPriority = synthNode.VoiceLimitPriority, VoiceLimitPhTime = synthNode.VoiceLimitProhibitionTime, VoiceLimitPcdlt = synthNode.VoiceLimitPcdlt, Pan3dVolumeOffset = synthNode.Pan3dVolumeOffset, Pan3dVolumeGain = synthNode.Pan3dVolumeGain, Pan3dAngleOffset = synthNode.Pan3dAngleOffset, Pan3dAngleGain = synthNode.Pan3dAngleGain, Pan3dDistanceOffset = synthNode.Pan3dDistanceOffset, Pan3dDistanceGain = synthNode.Pan3dDistanceGain, Dry0g = synthNode.Dry0g, Dry1g = synthNode.Dry1g, Dry2g = synthNode.Dry2g, Dry3g = synthNode.Dry3g, Dry4g = synthNode.Dry4g, Dry5g = synthNode.Dry5g, Dry6g = synthNode.Dry6g, Dry7g = synthNode.Dry7g, Wet0g = synthNode.Wet0g, Wet1g = synthNode.Wet1g, Wet2g = synthNode.Wet2g, Wet3g = synthNode.Wet3g, Wet4g = synthNode.Wet4g, Wet5g = synthNode.Wet5g, Wet6g = synthNode.Wet6g, Wet7g = synthNode.Wet7g, F1Type = synthNode.Filter1Type, F1CofOffset = synthNode.Filter1CutoffOffset, F1CofGain = synthNode.Filter1CutoffGain, F1ResoOffset = synthNode.Filter1ResoOffset, F1ResoGain = synthNode.Filter1ResoGain, F2Type = synthNode.Filter2Type, F2CofLowOffset = synthNode.Filter2CutoffLowerOffset, F2CofLowGain = synthNode.Filter2CutoffLowerGain, F2CofHighOffset = synthNode.Filter2CutoffHigherOffset, F2CofHighGain = synthNode.Filter2CutoffHigherGain, Probability = synthNode.PlaybackProbability, NumberLmtChildren = synthNode.NLmtChildren, Repeat = synthNode.Repeat, ComboTime = synthNode.ComboTime, ComboLoopBack = synthNode.ComboLoopBack, }; if (synthNode.Type == BuilderSynthType.Single) { synthTable.LinkName = synthNode.SoundElementReference; } else if (synthNode.Type == BuilderSynthType.WithChildren) { foreach (string trackReference in synthNode.Children) { synthTable.LinkName += trackReference + (char)0x0A; } } if (!string.IsNullOrEmpty(synthNode.AisacReference)) { BuilderAisacNode aisacNode = project.AisacNodes.First(aisac => aisac.Name == synthNode.AisacReference); synthTable.AisacSetName = aisacNode.AisacName + "::" + aisacNode.Name + (char)0x0A; } synthTables.Add(synthTable); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(synthTables, CriTableWriterSettings.AdxSettings), Name = "SYNTH", TableType = 2, }); List <FileInfo> junks = new List <FileInfo>(); // Serialize the sound elements. List <SerializationSoundElementTable> soundElementTables = new List <SerializationSoundElementTable>(); foreach (BuilderSoundElementNode soundElementNode in project.SoundElementNodes) { CriAaxArchive aaxArchive = new CriAaxArchive(); if (!string.IsNullOrEmpty(soundElementNode.Intro)) { aaxArchive.Add(new CriAaxEntry { Flag = CriAaxEntryFlag.Intro, FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Intro)), }); aaxArchive.SetModeFromExtension(soundElementNode.Intro); } if (!string.IsNullOrEmpty(soundElementNode.Loop)) { aaxArchive.Add(new CriAaxEntry { Flag = CriAaxEntryFlag.Loop, FilePath = new FileInfo(Path.Combine(project.AudioDirectory.FullName, soundElementNode.Loop)), }); aaxArchive.SetModeFromExtension(soundElementNode.Loop); } byte[] data = new byte[0]; if (soundElementNode.Streaming) { CriCpkEntry entry = new CriCpkEntry(); entry.Name = Path.GetFileName(soundElementNode.Name); entry.DirectoryName = Path.GetDirectoryName(soundElementNode.Name); entry.Id = (uint)cpkArchive.Count; entry.UpdateDateTime = DateTime.Now; entry.FilePath = new FileInfo(Path.GetTempFileName()); cpkArchive.Add(entry); aaxArchive.Save(entry.FilePath.FullName); junks.Add(entry.FilePath); } else { data = aaxArchive.Save(); } soundElementTables.Add(new SerializationSoundElementTable { Name = soundElementNode.Name, Data = data, FormatType = (byte)aaxArchive.Mode, SoundFrequency = soundElementNode.SampleRate, NumberChannels = soundElementNode.ChannelCount, Streaming = soundElementNode.Streaming, NumberSamples = soundElementNode.SampleCount, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(soundElementTables, CriTableWriterSettings.AdxSettings), Name = "SOUND_ELEMENT", TableType = 4, }); // Serialize the aisacs. List <SerializationAisacTable> aisacTables = new List <SerializationAisacTable>(); foreach (BuilderAisacNode aisacNode in project.AisacNodes) { List <SerializationAisacGraphTable> graphTables = new List <SerializationAisacGraphTable>(); foreach (BuilderAisacGraphNode graphNode in aisacNode.Graphs) { List <SerializationAisacPointTable> pointTables = new List <SerializationAisacPointTable>(); foreach (BuilderAisacPointNode pointNode in graphNode.Points) { pointTables.Add(new SerializationAisacPointTable { In = pointNode.X, Out = pointNode.Y, }); } graphTables.Add(new SerializationAisacGraphTable { Points = CriTableSerializer.Serialize(pointTables, CriTableWriterSettings.AdxSettings), Type = graphNode.Type, InMax = graphNode.MaximumX, InMin = graphNode.MinimumX, OutMax = graphNode.MaximumY, OutMin = graphNode.MinimumY, }); } aisacTables.Add(new SerializationAisacTable { Graph = CriTableSerializer.Serialize(graphTables, CriTableWriterSettings.AdxSettings), Name = aisacNode.AisacName, PathName = aisacNode.Name, Type = aisacNode.Type, RandomRange = aisacNode.RandomRange, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(aisacTables, CriTableWriterSettings.AdxSettings), Name = "ISAAC", TableType = 5, }); // Serialize the voice limit groups. List <SerializationVoiceLimitGroupTable> voiceLimitGroupTables = new List <SerializationVoiceLimitGroupTable>(); foreach (BuilderVoiceLimitGroupNode voiceLimitGroupNode in project.VoiceLimitGroupNodes) { voiceLimitGroupTables.Add(new SerializationVoiceLimitGroupTable { VoiceLimitGroupName = voiceLimitGroupNode.Name, VoiceLimitGroupNum = voiceLimitGroupNode.MaxAmountOfInstances, }); } cueSheetTables.Add(new SerializationCueSheetTable { TableData = CriTableSerializer.Serialize(voiceLimitGroupTables, CriTableWriterSettings.AdxSettings), Name = "VOICE_LIMIT_GROUP", TableType = 6, }); // Finally, serialize the CSB file. CriTableSerializer.Serialize(outputFileName, cueSheetTables, CriTableWriterSettings.AdxSettings, MainForm.Settings.BufferSize); if (cpkArchive.Count > 0) { cpkArchive.Save(Path.ChangeExtension(outputFileName, "cpk"), MainForm.Settings.BufferSize); } foreach (FileInfo junk in junks) { junk.Delete(); } }
public static async Task CSBRepack(string csbDirectory) { string baseDirectory = Path.GetDirectoryName(csbDirectory); string csbPath = csbDirectory + ".csb"; foreach (string extension in new string[] { "csb", "CSB" }) { if (File.Exists(csbPath)) { break; } csbPath = csbDirectory + "." + 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(); CriTable csbFile = new CriTable(); csbFile.Load(csbPath, 4096); 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(csbDirectory, 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, 4096); } 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, 4096); if (cpkArchive.Count > 0) { string cpkPath = csbDirectory + ".cpk"; foreach (string extension in new string[] { "cpk", "CPK" }) { if (File.Exists(csbDirectory + "." + extension)) { cpkPath = csbDirectory + "." + extension; break; } } cpkArchive.Save(cpkPath, 4096); } foreach (FileInfo junk in junks) { junk.Delete(); } }
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 }
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 }