예제 #1
0
        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();
            }
        }
예제 #2
0
        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
        }
        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();
            }
        }