private static void WriteAfs2ArchiveToStream(ReadOnlyCollection <byte[]> files, Stream stream, uint alignment) { var fileCount = (uint)files.Count; if (files.Count >= ushort.MaxValue) { throw new IndexOutOfRangeException($"File count {fileCount} exceeds maximum possible value (65535)."); } if (files.Count != 1) { throw new NotSupportedException("Currently DereTore does not support more than one file."); } stream.WriteBytes(Afs2Archive.Afs2Signature); const uint version = 0x00020401; stream.WriteUInt32LE(version); stream.WriteUInt32LE(fileCount); stream.WriteUInt32LE(alignment); const uint offsetFieldSize = (version >> 8) & 0xff; // version[1], always 4? See Afs2Archive.Initialize(). // Prepare the fields. var afs2HeaderSegmentSize = 0x10 + // General data 2 * fileCount + // Cue IDs offsetFieldSize * fileCount + // File offsets sizeof(uint); // Size of last file (U32) // Assuming the music file always has ID 0 in Waveform table and Cue table. var records = new List <Afs2FileRecord>(); var currentFileRawOffset = afs2HeaderSegmentSize; for (ushort i = 0; i < fileCount; ++i) { var record = new Afs2FileRecord { // TODO: Use the Cue table. CueId = i, FileOffsetRaw = currentFileRawOffset, FileOffsetAligned = AcbHelper.RoundUpToAlignment(currentFileRawOffset, alignment) }; records.Add(record); currentFileRawOffset = (uint)(record.FileOffsetAligned + files[i].Length); } var lastFileEndOffset = currentFileRawOffset; for (var i = 0; i < files.Count; ++i) { stream.WriteUInt16LE(records[i].CueId); } for (var i = 0; i < files.Count; ++i) { stream.WriteUInt32LE((uint)records[i].FileOffsetRaw); } // TODO: Dynamically judge it. See Afs2Archive.Initialize(). stream.WriteUInt32LE(lastFileEndOffset); for (var i = 0; i < files.Count; ++i) { stream.SeekAndWriteBytes(files[i], records[i].FileOffsetAligned); } }
// ReSharper disable once IdentifierTypo private static void AfsToWav(Afs2FileRecord afsRecord, Stream awbStream, DecodeParams decodeParams, string output) { using var fileData = AcbHelper.ExtractToNewStream(awbStream, afsRecord.FileOffsetAligned, (int)afsRecord.FileLength); var isHcaStream = DereTore.Exchange.Audio.HCA.HcaReader.IsHcaStream(fileData); if (!isHcaStream) { return; } using var fs = File.OpenWrite(output); try { HcaToWav(fileData, fs, decodeParams); } catch (Exception) { Console.Error.WriteLine($"Failed to convert {output}:"); throw; } }