Skip to content

Commit

Permalink
MLTD bgm_system.acb format fix. (tracks: vgmtoolbox r1040)
Browse files Browse the repository at this point in the history
  • Loading branch information
hozuki committed Aug 31, 2017
1 parent dfc45d0 commit b3ac9f5
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 52 deletions.
8 changes: 4 additions & 4 deletions Apps/AcbUnzip/DereTore.Apps.AcbUnzip.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>4</LangVersion>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
Expand All @@ -29,7 +29,7 @@
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>4</LangVersion>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
Expand All @@ -39,7 +39,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>4</LangVersion>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
Expand All @@ -49,7 +49,7 @@
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>4</LangVersion>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
Expand Down
33 changes: 26 additions & 7 deletions Apps/AcbUnzip/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using DereTore.Exchange.Archive.ACB;

Expand All @@ -13,18 +13,37 @@ internal static class Program {
var fileName = args[0];
var fileInfo = new FileInfo(fileName);

var fullDirPath = Path.Combine(fileInfo.DirectoryName ?? string.Empty, string.Format(DirTemplate, fileInfo.Name));
var fullDirPath = Path.Combine(fileInfo.DirectoryName, string.Format(DirTemplate, fileInfo.Name));
if (!Directory.Exists(fullDirPath)) {
Directory.CreateDirectory(fullDirPath);
}

using (var acb = AcbFile.FromFile(fileName)) {
var fileNames = acb.GetFileNames();
foreach (var s in fileNames) {
var archivedEntryNames = acb.GetFileNames();
for (var i = 0; i < archivedEntryNames.Length; ++i) {
var isCueNonEmpty = archivedEntryNames[i] != null;
var s = archivedEntryNames[i] ?? AcbFile.GetSymbolicFileNameFromCueId((uint)i);
var extractName = Path.Combine(fullDirPath, s);
using (var fs = new FileStream(extractName, FileMode.Create, FileAccess.Write)) {
using (var source = acb.OpenDataStream(s)) {
WriteFile(source, fs);
try {
using (var source = isCueNonEmpty ? acb.OpenDataStream(s) : acb.OpenDataStream((uint)i)) {
using (var fs = new FileStream(extractName, FileMode.Create, FileAccess.Write)) {
WriteFile(source, fs);
}
}
} catch (Exception ex) {
var origForeground = ConsoleColor.Gray;
try {
origForeground = Console.ForegroundColor;
} catch {
}
try {
Console.ForegroundColor = ConsoleColor.Red;
} catch {
}
Console.WriteLine(ex.Message);
try {
Console.ForegroundColor = origForeground;
} catch {
}
}
Console.WriteLine(s);
Expand Down
18 changes: 18 additions & 0 deletions Exchange/DereTore.Exchange.Archive.ACB/AcbException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace DereTore.Exchange.Archive.ACB {
public class AcbException : ApplicationException {

public AcbException() {
}

public AcbException(string message)
: base(message) {
}

public AcbException(string message, Exception innerException)
: base(message, innerException) {
}

}
}
15 changes: 15 additions & 0 deletions Exchange/DereTore.Exchange.Archive.ACB/AcbFieldMissingException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace DereTore.Exchange.Archive.ACB {
public class AcbFieldMissingException : AcbException {

public AcbFieldMissingException(string fieldName)
: base($"Missing {fieldName} field.") {
}

public AcbFieldMissingException(string fieldName, Exception innerException)
: base($"Missing {fieldName} field.", innerException) {
}

}
}
95 changes: 81 additions & 14 deletions Exchange/DereTore.Exchange.Archive.ACB/AcbFile.Internal.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using DereTore.Common;
Expand Down Expand Up @@ -59,8 +59,16 @@ private AcbFile(Stream stream, long offset, long size, string acbFileName, bool
case 3:
case 8:
if (i == 0) {
refItemOffset = synthTable.GetFieldOffset(0, "ReferenceItems").Value;
refItemSize = synthTable.GetFieldSize(0, "ReferenceItems").Value;
var refItemOffsetNullable = synthTable.GetFieldOffset(0, "ReferenceItems");
if (refItemOffsetNullable == null) {
throw new AcbFieldMissingException("ReferenceItems");
}
refItemOffset = refItemOffsetNullable.Value;
var refItemSizeNullable = synthTable.GetFieldSize(0, "ReferenceItems");
if (refItemSizeNullable == null) {
throw new AcbFieldMissingException("ReferenceItems");
}
refItemSize = refItemSizeNullable.Value;
refCorrection = refItemSize - 2;
} else {
refCorrection += 4;
Expand All @@ -70,18 +78,38 @@ private AcbFile(Stream stream, long offset, long size, string acbFileName, bool
throw new FormatException($"Unexpected ReferenceType '{cues[i].ReferenceType}' for CueIndex: '{i}.'");
}

if (refItemSize > 0) {
if (refItemSize != 0) {
cue.WaveformIndex = stream.PeekUInt16BE(refItemOffset + refCorrection);
var waveformId = waveformTable.GetFieldValueAsNumber<ushort>(cue.WaveformIndex, "Id");
if (!waveformId.HasValue) {
// MemoryAwbId is for ADX2LE encoder.
waveformId = waveformTable.GetFieldValueAsNumber<ushort>(cue.WaveformIndex, "MemoryAwbId");
var isStreamingNullable = waveformTable.GetFieldValueAsNumber<byte>(cue.WaveformIndex, "Streaming");
if (isStreamingNullable != null) {
cue.IsStreaming = isStreamingNullable.Value != 0;

var waveformIdNullable = waveformTable.GetFieldValueAsNumber<ushort>(cue.WaveformIndex, "Id");
if (waveformIdNullable != null) {
cue.WaveformId = waveformIdNullable.Value;
} else if (cue.IsStreaming) {
waveformIdNullable = waveformTable.GetFieldValueAsNumber<ushort>(cue.WaveformIndex, "StreamAwbId");
if (waveformIdNullable == null) {
throw new AcbFieldMissingException("StreamAwbId");
}
cue.WaveformId = waveformIdNullable.Value;
} else {
// MemoryAwbId is for ADX2LE encoder.
waveformIdNullable = waveformTable.GetFieldValueAsNumber<ushort>(cue.WaveformIndex, "MemoryAwbId");
if (waveformIdNullable == null) {
throw new AcbFieldMissingException("MemoryAwbId");
}
cue.WaveformId = waveformIdNullable.Value;
}

var encTypeNullable = waveformTable.GetFieldValueAsNumber<byte>(cue.WaveformIndex, "EncodeType");
if (encTypeNullable == null) {
throw new AcbFieldMissingException("EncodeType");
}
cue.EncodeType = encTypeNullable.Value;

cue.IsWaveformIdentified = true;
}
cue.WaveformId = waveformId.GetValueOrDefault();
cue.EncodeType = waveformTable.GetFieldValueAsNumber<byte>(cue.WaveformIndex, "EncodeType").Value;
var isStreaming = waveformTable.GetFieldValueAsNumber<byte>(cue.WaveformIndex, "Streaming").Value;
cue.IsStreaming = isStreaming != 0;
cue.IsWaveformIdentified = true;
}
}
}
Expand All @@ -94,10 +122,17 @@ private AcbFile(Stream stream, long offset, long size, string acbFileName, bool
_cueNameToWaveform = cueNameToWaveform;

for (var i = 0; i < cueNameTable.Rows.Length; ++i) {
var cueIndex = cueNameTable.GetFieldValueAsNumber<ushort>(i, "CueIndex").Value;
var cueIndexNullable = cueNameTable.GetFieldValueAsNumber<ushort>(i, "CueIndex");
if (cueIndexNullable == null) {
throw new AcbFieldMissingException("CueIndex");
}
var cueIndex = cueIndexNullable.Value;
var cue = cues[cueIndex];
if (cue.IsWaveformIdentified) {
var cueName = cueNameTable.GetFieldValueAsString(i, "CueName");
if (cueName == null) {
throw new AcbFieldMissingException("CueName");
}
cueName += GetExtensionForEncodeType(cue.EncodeType);
if (includeCueIdInFileName) {
cueName = cue.CueId.ToString("D5") + "_" + cueName;
Expand All @@ -119,8 +154,40 @@ private AcbFile(Stream stream, long offset, long size, string acbFileName, bool
}
}

private Stream GetDataStreamFromCueInfo(AcbCueRecord cue, string fileNameForErrorInfo) {
if (!cue.IsWaveformIdentified) {
throw new InvalidOperationException($"File '{fileNameForErrorInfo}' is not identified.");
}
if (cue.IsStreaming) {
var externalAwb = ExternalAwb;
if (externalAwb == null) {
throw new InvalidOperationException($"External AWB does not exist for streaming file '{fileNameForErrorInfo}'.");
}
if (!externalAwb.Files.ContainsKey(cue.WaveformId)) {
throw new InvalidOperationException($"Waveform ID {cue.WaveformId} is not found in AWB file {externalAwb.FileName}.");
}
var targetExternalFile = externalAwb.Files[cue.WaveformId];
using (var fs = File.Open(externalAwb.FileName, FileMode.Open, FileAccess.Read)) {
return AcbHelper.ExtractToNewStream(fs, targetExternalFile.FileOffsetAligned, (int)targetExternalFile.FileLength);
}
} else {
var internalAwb = InternalAwb;
if (internalAwb == null) {
throw new InvalidOperationException($"Internal AWB is not found for memory file '{fileNameForErrorInfo}' in '{AcbFileName}'.");
}
if (!internalAwb.Files.ContainsKey(cue.WaveformId)) {
throw new InvalidOperationException($"Waveform ID {cue.WaveformId} is not found in internal AWB in {AcbFileName}.");
}
var targetInternalFile = internalAwb.Files[cue.WaveformId];
return AcbHelper.ExtractToNewStream(Stream, targetInternalFile.FileOffsetAligned, (int)targetInternalFile.FileLength);
}
}

private Afs2Archive GetInternalAwbArchive() {
var internalAwbOffset = GetFieldOffset(0, "AwbFile");
if (internalAwbOffset == null) {
throw new AcbFieldMissingException("AwbFile");
}
var internalAwb = new Afs2Archive(Stream, internalAwbOffset.Value, AcbFileName, false);
internalAwb.Initialize();
return internalAwb;
Expand Down
42 changes: 16 additions & 26 deletions Exchange/DereTore.Exchange.Archive.ACB/AcbFile.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -83,32 +83,22 @@ public sealed partial class AcbFile : UtfTable {
} catch (InvalidOperationException ex) {
throw new InvalidOperationException($"File '{fileName}' is not found or it has multiple entries.", ex);
}
if (!cue.IsWaveformIdentified) {
throw new InvalidOperationException($"File '{fileName}' is not identified.");
}
if (cue.IsStreaming) {
var externalAwb = ExternalAwb;
if (externalAwb == null) {
throw new InvalidOperationException($"External AWB does not exist for streaming file '{fileName}'.");
}
if (!externalAwb.Files.ContainsKey(cue.WaveformId)) {
throw new InvalidOperationException($"Waveform ID {cue.WaveformId} is not found in AWB file {externalAwb.FileName}.");
}
var targetExternalFile = externalAwb.Files[cue.WaveformId];
using (var fs = File.Open(externalAwb.FileName, FileMode.Open, FileAccess.Read)) {
return AcbHelper.ExtractToNewStream(fs, targetExternalFile.FileOffsetAligned, (int)targetExternalFile.FileLength);
}
} else {
var internalAwb = InternalAwb;
if (internalAwb == null) {
throw new InvalidOperationException($"Internal AWB is not found for memory file '{fileName}' in '{AcbFileName}'.");
}
if (!internalAwb.Files.ContainsKey(cue.WaveformId)) {
throw new InvalidOperationException($"Waveform ID {cue.WaveformId} is not found in internal AWB in {AcbFileName}.");
}
var targetInternalFile = internalAwb.Files[cue.WaveformId];
return AcbHelper.ExtractToNewStream(Stream, targetInternalFile.FileOffsetAligned, (int)targetInternalFile.FileLength);
return GetDataStreamFromCueInfo(cue, fileName);
}

public Stream OpenDataStream(uint cueId) {
AcbCueRecord cue;
var tempFileName = $"cue #{cueId}";
try {
cue = Cues.Single(c => c.CueId == cueId);
} catch (InvalidOperationException ex) {
throw new InvalidOperationException($"File '{tempFileName}' is not found or it has multiple entries.", ex);
}
return GetDataStreamFromCueInfo(cue, tempFileName);
}

public static string GetSymbolicFileNameFromCueId(uint cueId) {
return $"dat_{cueId:000000}.bin";
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="AcbException.cs" />
<Compile Include="AcbFieldMissingException.cs" />
<Compile Include="AcbFile.cs" />
<Compile Include="AcbFile.Internal.cs" />
<Compile Include="AcbHelper.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using DereTore.Common;
Expand Down

0 comments on commit b3ac9f5

Please sign in to comment.