Skip to content

Commit

Permalink
[hca] Fixed DataBits index access error caused by some malformed HCA …
Browse files Browse the repository at this point in the history
…files (hozuki/libcgss#7)
  • Loading branch information
hozuki committed Feb 21, 2019
1 parent 18ee3cc commit e104bc6
Show file tree
Hide file tree
Showing 14 changed files with 508 additions and 314 deletions.
7 changes: 6 additions & 1 deletion Apps/Acb2Wavs/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ private static void ProcessAllBinaries(uint acbFormatVersion, DecodeParams baseD
File.Delete(extractFilePath);
}

Console.WriteLine(ex.Message);
Console.WriteLine(ex.ToString());

if (ex.InnerException != null) {
Console.WriteLine("Details:");
Console.WriteLine(ex.InnerException.ToString());
}
}
} else {
Console.WriteLine("skipped (not HCA)");
Expand Down
7 changes: 5 additions & 2 deletions Exchange/DereTore.Exchange.Audio.HCA/Ath.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using DereTore.Common;
using DereTore.Common;

namespace DereTore.Exchange.Audio.HCA {
internal sealed class Ath {

static Ath() {
}

public bool Initialize(uint type, uint key) {
switch (type) {
case 0:
Expand Down Expand Up @@ -38,7 +41,7 @@ private void Init1(uint key) {

private readonly byte[] _table = new byte[0x80];

private static readonly byte[] AthInitList = new byte[] {
private static readonly byte[] AthInitList = {
0x78, 0x5f, 0x56, 0x51, 0x4e, 0x4c, 0x4b, 0x49, 0x48, 0x48, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45,
0x44, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x40,
Expand Down
288 changes: 14 additions & 274 deletions Exchange/DereTore.Exchange.Audio.HCA/Channel.cs
Original file line number Diff line number Diff line change
@@ -1,294 +1,34 @@
using System;
using System;
using System.Runtime.InteropServices;
using DereTore.Common;

namespace DereTore.Exchange.Audio.HCA {
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct Channel {

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)]
public float[] Block;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)]
public float[] Base;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 0x80)]
public byte[] Value;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 0x80)]
public byte[] Scale;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 8)]
public byte[] Value2;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 0x80)]
public sbyte[] Value;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 0x80)]
public sbyte[] Scale;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 8)]
public sbyte[] Value2;
[MarshalAs(UnmanagedType.I4)]
public int Type;
// Original type: public char *
public IntPtr Value3;
[MarshalAs(UnmanagedType.U4)]
public uint Value3;
public uint Count;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)]
public float[] Wav1;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)]
public float[] Wav2;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 0x80)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 0x80)]
public float[] Wav3;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R8, SizeConst = 8 * 0x80)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 8 * 0x80)]
public float[] Wave;

public static Channel CreateDefault() {
var v = default(Channel);
v.Block = new float[0x80];
v.Base = new float[0x80];
v.Value = new byte[0x80];
v.Scale = new byte[0x80];
v.Value2 = new byte[8];
v.Type = 0;
v.Value3 = 0;
v.Count = 0;
v.Wav1 = new float[0x80];
v.Wav2 = new float[0x80];
v.Wav3 = new float[0x80];
v.Wave = new float[8 * 0x80];
return v;
}

public void Decode1(DataBits data, uint a, int b, byte[] ath) {
int v = data.GetBit(3);
if (v >= 6) {
for (uint i = 0; i < Count; ++i) {
Value[i] = (byte)data.GetBit(6);
}
} else if (v != 0) {
int v1 = data.GetBit(6);
int v2 = (1 << v) - 1;
int v3 = v2 >> 1;
Value[0] = (byte)v1;
for (uint i = 1; i < Count; ++i) {
int v4 = data.GetBit(v);
if (v4 != v2) {
v1 += v4 - v3;
} else {
v1 = data.GetBit(6);
}
Value[i] = (byte)v1;
}
} else {
Value.ZeroMem();
}
if (Type == 2) {
v = data.CheckBit(4);
Value2[0] = (byte)v;
if (v < 15) {
for (var i = 0; i < 8; ++i) {
Value2[i] = (byte)data.GetBit(4);
}
}
} else {
for (uint i = 0; i < a; ++i) {
//Value3[i] = (byte)data.GetBit(6);
SetValue3(i, (byte)data.GetBit(6));
}
}
for (uint i = 0; i < Count; ++i) {
v = Value[i];
if (v != 0) {
v = (int)(ath[i] + ((b + i) >> 8) - ((v * 5) >> 1) + 1);
if (v < 0) {
v = 15;
} else if (v >= 0x39) {
v = 1;
} else {
v = ChannelTables.Decode1ScaleList[v];
}
}
Scale[i] = (byte)v;
}
for (var i = Count; i < Scale.Length; ++i) {
Scale[i] = 0;
}
for (uint i = 0; i < Count; ++i) {
Base[i] = ChannelTables.Decode1ValueSingle[Value[i]] * ChannelTables.Decode1ScaleSingle[Scale[i]];
}
}

public void Decode2(DataBits data) {
for (uint i = 0; i < Count; ++i) {
float f;
int s = Scale[i];
int bitSize = ChannelTables.Decode2List1[s];
int v = data.GetBit(bitSize);
if (s < 8) {
v += s << 4;
data.AddBit(ChannelTables.Decode2List2[v] - bitSize);
f = ChannelTables.Decode2List3[v];
} else {
v = (1 - ((v & 1) << 1)) * (v >> 1);
if (v == 0) {
data.AddBit(-1);
}
f = v;
}
Block[i] = Base[i] * f;
}
for (var i = Count; i < Block.Length; ++i) {
Block[i] = 0;
}
}

public void Decode3(uint a, uint b, uint c, uint d) {
if (Type != 2 && b != 0) {
float[] listFloat = ChannelTables.Decode3ListSingle;
int offset = ChannelTables.Decode3ListOffset;
for (uint i = 0, k = c, l = c - 1; i < a; ++i) {
for (uint j = 0; j < b && k < d; ++j, --l) {
Block[k++] = listFloat[GetValue3(i) - Value[l] + offset] * Block[l];
}
}
Block[0x80 - 1] = 0;
}
}

public static void Decode4(ref Channel @this, ref Channel next, int index, uint a, uint b, uint c) {
if (@this.Type == 1 && c != 0) {
var f1 = ChannelTables.Decode4ListSingle[next.Value2[index]];
var f2 = f1 - 2f;
float[] s = @this.Block;
float[] d = next.Block;
int sIndex, dIndex;
sIndex = (int)b;
dIndex = (int)b;
for (uint i = 0; i < a; ++i) {
// Don't know why, but it just happened.
// See se_live_flic_perfect.hca
// original:
/*
* (no 'break')
* d[dIndex++] = s[sIndex] * f2;
* s[sIndex++] = s[sIndex] * f1;
*/
if (sIndex >= s.Length || dIndex >= d.Length) {
break;
}
d[dIndex] = s[sIndex] * f2;
dIndex++;
s[sIndex] = s[sIndex] * f1;
sIndex++;
}
}
}

public void Decode5(int index) {
float[] s;
float[] d;
s = Block;
d = Wav1;
int sIndex = 0, dIndex = 0;
int s1Index, s2Index;
for (int i = 0, count1 = 1, count2 = 0x40; i < 7; ++i, count1 <<= 1, count2 >>= 1) {
int dIndex1 = dIndex, dIndex2 = dIndex + count2;
for (int j = 0; j < count1; ++j) {
for (int k = 0; k < count2; ++k) {
float a = s[sIndex++];
float b = s[sIndex++];
d[dIndex1++] = b + a;
d[dIndex2++] = a - b;
}
dIndex1 += count2;
dIndex2 += count2;
}
sIndex -= 0x80;
HcaHelper.Exchange(ref sIndex, ref dIndex);
HcaHelper.Exchange(ref s, ref d);
}
s = Wav1;
d = Block;
sIndex = dIndex = 0;
for (int i = 0, count1 = 0x40, count2 = 1; i < 7; ++i, count1 >>= 1, count2 <<= 1) {
// The original array is a 2-rank array, [7][0x40].
int list1FloatIndex = i * 0x40;
// The original array is a 2-rank array, [7][0x40].
int list2FloatIndex = i * 0x40;
s1Index = sIndex;
s2Index = sIndex + count2;
int dIndex1 = dIndex;
int dIndex2 = dIndex + count2 * 2 - 1;
for (int j = 0; j < count1; ++j) {
for (int k = 0; k < count2; ++k) {
float fa = s[s1Index++];
float fb = s[s2Index++];
float fc = ChannelTables.Decode5List1Single[list1FloatIndex++];
float fd = ChannelTables.Decode5List2Single[list2FloatIndex++];
d[dIndex1++] = fa * fc - fb * fd;
d[dIndex2--] = fa * fd + fb * fc;
}
s1Index += count2;
s2Index += count2;
dIndex1 += count2;
dIndex2 += count2 * 3;
}
HcaHelper.Exchange(ref sIndex, ref dIndex);
HcaHelper.Exchange(ref s, ref d);
}
d = Wav2;
for (int i = 0; i < 0x80; ++i) {
d[i] = s[i];
}
s = ChannelTables.Decode5List3Single;
sIndex = 0;
d = Wave;
// The original array is [8][0x80].
dIndex = index * 0x80;
float[] s1 = Wav2;
s1Index = 0x40;
float[] s2 = Wav3;
s2Index = 0;
for (int i = 0; i < 0x40; ++i) {
d[dIndex++] = s1[s1Index++] * s[sIndex++] + s2[s2Index++];
}
for (int i = 0; i < 0x40; ++i) {
d[dIndex++] = s[sIndex++] * s1[--s1Index] - s2[s2Index++];
}
s1 = Wav2;
s2 = Wav3;
s1Index = 0x40 - 1;
s2Index = 0;
for (int i = 0; i < 0x40; ++i) {
s2[s2Index++] = s1[s1Index--] * s[--sIndex];
}
for (int i = 0; i < 0x40; ++i) {
s2[s2Index++] = s[--sIndex] * s1[++s1Index];
}
}

private byte GetValue3(int refIndex) {
int index = (int)(refIndex + Value3);
if (0 <= index && index < 0x80) {
return Value[index];
} else if (0x80 <= index && index < 0x80 + 0x80) {
return Scale[index - 0x80];
} else {
throw new ArgumentOutOfRangeException(nameof(refIndex));
}
}

private byte GetValue3(uint refIndex) {
var index = refIndex + Value3;
if (index < 0x80) {
return Value[index];
} else if (index < 0x80 + 0x80) {
return Scale[index - 0x80];
} else {
throw new ArgumentOutOfRangeException(nameof(refIndex));
}
}

private void SetValue3(int refIndex, byte value) {
Value[refIndex + Value3] = value;
}

private void SetValue3(uint refIndex, byte value) {
Value[refIndex + Value3] = value;
}

private void SetValue3(byte value) {
Value[Value3] = value;
}

}
}
Loading

0 comments on commit e104bc6

Please sign in to comment.