protected override void DoTaskForFile(string pPath, IVgmtWorkerStruct pExtractStruct, DoWorkEventArgs e) { ExtractCriAcbAwbStruct extractStruct = (ExtractCriAcbAwbStruct)pExtractStruct; byte[] magicBytes; long awbOffset = 0; using (FileStream fs = File.Open(pPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { magicBytes = ParseFile.ParseSimpleOffset(fs, 0, 4); this.progressStruct.Clear(); // ACB if (ParseFile.CompareSegment(magicBytes, 0, CriAcbFile.SIGNATURE_BYTES)) { this.progressStruct.GenericMessage = String.Format("Processing ACB file: '{0}'.{1}", Path.GetFileName(pPath), Environment.NewLine); ReportProgress(Constants.ProgressMessageOnly, this.progressStruct); CriAcbFile acb = new CriAcbFile(fs, 0, extractStruct.IncludeCueIdInFileName); acb.ExtractAll(); } else if (ParseFile.CompareSegment(magicBytes, 0, CriAfs2Archive.SIGNATURE)) { this.progressStruct.GenericMessage = String.Format("Processing AWB file: '{0}'.{1}", Path.GetFileName(pPath), Environment.NewLine); ReportProgress(Constants.ProgressMessageOnly, this.progressStruct); CriAfs2Archive afs2 = new CriAfs2Archive(fs, 0); afs2.ExtractAll(); } else { this.progressStruct.GenericMessage = String.Format("ACB/AWB signature not found at offset 0...scanning for AWB signature: '{0}'.{1}", Path.GetFileName(pPath), Environment.NewLine); ReportProgress(Constants.ProgressMessageOnly, this.progressStruct); awbOffset = ParseFile.GetNextOffset(fs, 0, CriAfs2Archive.SIGNATURE); if (awbOffset > 0) { CriAfs2Archive afs2 = new CriAfs2Archive(fs, awbOffset); afs2.ExtractAll(); } else { this.progressStruct.GenericMessage = String.Format("File is not an ACB or AWB...skipping: '{0}'.{1}", Path.GetFileName(pPath), Environment.NewLine); ReportProgress(Constants.ProgressMessageOnly, this.progressStruct); } } } }
static void Main(string[] args) { Application.EnableVisualStyles(); if (args.Length < 1) { MessageBox.Show("This program can inject audio files into ACB files without the need of repacking their AWBs.\n\nTo start, drag and drop an ACB file to the executable.", "ACB Injector", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } try { string sourceFileName = null; string sourceAudioFileName = null; int waveformId = -1; string destinationFileName = null; foreach (var arg in args) { if (int.TryParse(arg, out int ret) && waveformId < 0) { waveformId = ret; } else if (sourceFileName == null) { sourceFileName = arg; } else if (sourceAudioFileName == null) { sourceAudioFileName = arg; } else if (destinationFileName == null) { destinationFileName = arg; } } CriTable acbFile = new CriTable(); acbFile.Load(sourceFileName); CriTable waveformTable = new CriTable(); waveformTable.Load(acbFile.Rows[0].GetValue <byte[]>("WaveformTable")); var waveforms = waveformTable.Rows.Where(x => x.GetValue <byte>("Streaming") == 0).ToList(); var streamedWaveforms = waveformTable.Rows.Except(waveforms).ToList(); if (streamedWaveforms.Count < 1) { throw new InvalidDataException("This ACB file has no streamed waveforms, aka an AWB file."); } if (waveformId < 0) { while (true) { using (TxtBxDialog textBoxDialog = new TxtBxDialog( streamedWaveforms.Select(x => x.GetValue <ushort>("Id")).OrderBy(x => x).Select(x => x.ToString()).ToArray())) { if (textBoxDialog.ShowDialog() == DialogResult.OK) { if (!int.TryParse(textBoxDialog.Result, out waveformId) || !streamedWaveforms.Any(x => x.GetValue <ushort>("Id") == waveformId)) { MessageBox.Show("Invalid waveform id.", "ACB Injector", MessageBoxButtons.OK); } else { break; } } else { return; } } } } CriRow waveformToInject = streamedWaveforms.FirstOrDefault( x => x.GetValue <ushort>("Id") == waveformId); int newWaveformId = (waveforms.Count > 0 ? waveforms.Max(x => x.GetValue <ushort>("Id")) : -1) + 1; waveformToInject["Id"] = (ushort)newWaveformId; waveformToInject["Streaming"] = (byte)0; if (string.IsNullOrEmpty(sourceAudioFileName)) { using (OpenFileDialog openFileDialog = new OpenFileDialog { Title = "Select the audio file that you are going to inject", InitialDirectory = Path.GetDirectoryName(sourceFileName), Filter = "All Files|*.*", }) { if (openFileDialog.ShowDialog() == DialogResult.OK) { sourceAudioFileName = openFileDialog.FileName; } else { return; } } } CriAfs2Archive archive = new CriAfs2Archive(); if (acbFile.Rows[0]["AwbFile"] is byte[] archiveData && archiveData.Length > 0) { archive.Load(archiveData); // Proof that SonicAudioLib needs a rewrite. // I hate this... foreach (var entry in archive) { var filePath = new FileInfo( Path.GetTempFileName()); File.WriteAllBytes(filePath.FullName, archiveData.Skip((int)entry.Position).Take((int)entry.Length).ToArray()); entry.FilePath = filePath; Junk.Add(entry.FilePath); } } archive.Add(new CriAfs2Entry { Id = (uint)newWaveformId, FilePath = new FileInfo(sourceAudioFileName) }); acbFile.Rows[0]["AwbFile"] = archive.Save(); acbFile.WriterSettings = waveformTable.WriterSettings = CriTableWriterSettings.Adx2Settings; acbFile.Rows[0]["WaveformTable"] = waveformTable.Save(); if (string.IsNullOrEmpty(destinationFileName)) { if (args.Length < 2) { using (SaveFileDialog saveFileDialog = new SaveFileDialog { Title = "Save ACB file", InitialDirectory = Path.GetDirectoryName(sourceFileName), FileName = Path.GetFileName(sourceFileName), Filter = "ACB Files|*.acb", }) { if (saveFileDialog.ShowDialog() == DialogResult.OK) { destinationFileName = saveFileDialog.FileName; } else { return; } } } else { destinationFileName = sourceFileName; } } acbFile.Save(destinationFileName); } catch (Exception ex) { MessageBox.Show(ex.Message, "ACB Injector", MessageBoxButtons.OK, MessageBoxIcon.Error); } foreach (var junk in Junk) { junk.Delete(); } }
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 }