5
0
mirror of synced 2024-11-13 18:10:54 +01:00

Add format metadata to --no-split

This commit is contained in:
windyfairy 2019-10-09 10:03:59 +09:00
parent 7c395d9f8f
commit 99ab3a04b0

View File

@ -46,6 +46,22 @@ namespace gitadora_texbintool
}
}
public class FormatInfo
{
public string Filename;
public byte FormatType;
}
public class FormatMetadata
{
public List<FormatInfo> FormatInfo;
public FormatMetadata()
{
FormatInfo = new List<FormatInfo>();
}
}
class Program
{
static int ReadInt32(BinaryReader reader)
@ -53,8 +69,8 @@ namespace gitadora_texbintool
var data = reader.ReadBytes(4);
Array.Reverse(data);
return BitConverter.ToInt32(data, 0);
}
}
static void WriteInt32(MemoryStream writer, int value)
{
var data = BitConverter.GetBytes(value);
@ -153,134 +169,134 @@ namespace gitadora_texbintool
}
return outputData;
}
public static byte[] Compress(byte[] Data)
{
// Based on: https://github.com/gdkchan/LegaiaText/blob/bbec0465428a9ff1858e4177588599629ca43302/LegaiaText/Legaia/Compression/LZSS.cs
using (MemoryStream Output = new MemoryStream())
{
ulong[] LookUp = new ulong[0x10000];
byte[] Dict = new byte[0x1000];
int DictAddr = 4078;
int SrcAddr = 0;
int BitsAddr = 0;
ushort Mask = 0x80;
byte Header = 0;
Output.Write(BitConverter.GetBytes(0), 0, 4);
Output.Write(BitConverter.GetBytes(0), 0, 4);
while (SrcAddr < Data.Length)
{
if ((Mask <<= 1) == 0x100)
{
int OldAddr = BitsAddr;
BitsAddr = (int)Output.Position;
Output.Seek(OldAddr, SeekOrigin.Begin);
Output.WriteByte(Header);
Output.Seek(BitsAddr, SeekOrigin.Begin);
Output.WriteByte(0);
Header = 0;
Mask = 1;
}
int Length = 2;
int DictPos = 0;
if (SrcAddr + 2 < Data.Length)
{
int Value;
Value = Data[SrcAddr + 0] << 8;
Value |= Data[SrcAddr + 1] << 0;
for (int i = 0; i < 5; i++)
{
int Index = (int)((LookUp[Value] >> (i * 12)) & 0xfff);
//First byte doesn't match, so the others won't match too
if (Data[SrcAddr] != Dict[Index]) break;
//Temporary dictionary used on comparisons
byte[] CmpDict = new byte[0x1000];
Array.Copy(Dict, CmpDict, Dict.Length);
int CmpAddr = DictAddr;
int MatchLen = 0;
for (int j = 0; j < 18 && SrcAddr + j < Data.Length; j++)
{
if (CmpDict[(Index + j) & 0xfff] == Data[SrcAddr + j])
MatchLen++;
else
break;
CmpDict[CmpAddr] = Data[SrcAddr + j];
CmpAddr = (CmpAddr + 1) & 0xfff;
}
if (MatchLen > Length && MatchLen < Output.Length)
{
Length = MatchLen;
DictPos = Index;
}
}
}
if (Length > 2)
{
Output.WriteByte((byte)DictPos);
int NibLo = (Length - 3) & 0xf;
int NibHi = (DictPos >> 4) & 0xf0;
Output.WriteByte((byte)(NibLo | NibHi));
}
else
{
Header |= (byte)Mask;
Output.WriteByte(Data[SrcAddr]);
Length = 1;
}
for (int i = 0; i < Length; i++)
{
if (SrcAddr + 1 < Data.Length)
{
int Value;
Value = Data[SrcAddr + 0] << 8;
Value |= Data[SrcAddr + 1] << 0;
LookUp[Value] <<= 12;
LookUp[Value] |= (uint)DictAddr;
}
Dict[DictAddr] = Data[SrcAddr++];
DictAddr = (DictAddr + 1) & 0xfff;
}
}
Output.Seek(BitsAddr, SeekOrigin.Begin);
Output.WriteByte(Header);
Output.Seek(0, SeekOrigin.Begin);
WriteInt32(Output, Data.Length);
WriteInt32(Output, (int)Output.Length - 8);
return Output.ToArray();
}
}
public static byte[] Compress(byte[] Data)
{
// Based on: https://github.com/gdkchan/LegaiaText/blob/bbec0465428a9ff1858e4177588599629ca43302/LegaiaText/Legaia/Compression/LZSS.cs
using (MemoryStream Output = new MemoryStream())
{
ulong[] LookUp = new ulong[0x10000];
byte[] Dict = new byte[0x1000];
int DictAddr = 4078;
int SrcAddr = 0;
int BitsAddr = 0;
ushort Mask = 0x80;
byte Header = 0;
Output.Write(BitConverter.GetBytes(0), 0, 4);
Output.Write(BitConverter.GetBytes(0), 0, 4);
while (SrcAddr < Data.Length)
{
if ((Mask <<= 1) == 0x100)
{
int OldAddr = BitsAddr;
BitsAddr = (int)Output.Position;
Output.Seek(OldAddr, SeekOrigin.Begin);
Output.WriteByte(Header);
Output.Seek(BitsAddr, SeekOrigin.Begin);
Output.WriteByte(0);
Header = 0;
Mask = 1;
}
int Length = 2;
int DictPos = 0;
if (SrcAddr + 2 < Data.Length)
{
int Value;
Value = Data[SrcAddr + 0] << 8;
Value |= Data[SrcAddr + 1] << 0;
for (int i = 0; i < 5; i++)
{
int Index = (int)((LookUp[Value] >> (i * 12)) & 0xfff);
//First byte doesn't match, so the others won't match too
if (Data[SrcAddr] != Dict[Index]) break;
//Temporary dictionary used on comparisons
byte[] CmpDict = new byte[0x1000];
Array.Copy(Dict, CmpDict, Dict.Length);
int CmpAddr = DictAddr;
int MatchLen = 0;
for (int j = 0; j < 18 && SrcAddr + j < Data.Length; j++)
{
if (CmpDict[(Index + j) & 0xfff] == Data[SrcAddr + j])
MatchLen++;
else
break;
CmpDict[CmpAddr] = Data[SrcAddr + j];
CmpAddr = (CmpAddr + 1) & 0xfff;
}
if (MatchLen > Length && MatchLen < Output.Length)
{
Length = MatchLen;
DictPos = Index;
}
}
}
if (Length > 2)
{
Output.WriteByte((byte)DictPos);
int NibLo = (Length - 3) & 0xf;
int NibHi = (DictPos >> 4) & 0xf0;
Output.WriteByte((byte)(NibLo | NibHi));
}
else
{
Header |= (byte)Mask;
Output.WriteByte(Data[SrcAddr]);
Length = 1;
}
for (int i = 0; i < Length; i++)
{
if (SrcAddr + 1 < Data.Length)
{
int Value;
Value = Data[SrcAddr + 0] << 8;
Value |= Data[SrcAddr + 1] << 0;
LookUp[Value] <<= 12;
LookUp[Value] |= (uint)DictAddr;
}
Dict[DictAddr] = Data[SrcAddr++];
DictAddr = (DictAddr + 1) & 0xfff;
}
}
Output.Seek(BitsAddr, SeekOrigin.Begin);
Output.WriteByte(Header);
Output.Seek(0, SeekOrigin.Begin);
WriteInt32(Output, Data.Length);
WriteInt32(Output, (int)Output.Length - 8);
return Output.ToArray();
}
}
static int CalculateHash(string input)
@ -375,7 +391,7 @@ namespace gitadora_texbintool
var stringMetadata = ReadNameSection(reader, offset + namOffset);
reader.BaseStream.Seek(offset + rectOffset, SeekOrigin.Begin);
var rectInfoMetadata = new List<RectMetadata>();
for (int i = 0; i < layerCount; i++)
{
@ -457,6 +473,26 @@ namespace gitadora_texbintool
return texInfoList;
}
public static FormatMetadata DeserializeFormatMetadata(string filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(FormatMetadata));
StreamReader reader = new StreamReader(filename);
var formatMetdataList = (FormatMetadata)serializer.Deserialize(reader);
reader.Close();
for (var index = 0; index < formatMetdataList.FormatInfo.Count; index++)
{
formatMetdataList.FormatInfo[index] = new FormatInfo
{
Filename = formatMetdataList.FormatInfo[index].Filename,
FormatType = formatMetdataList.FormatInfo[index].FormatType,
};
}
return formatMetdataList;
}
static void ParseTexbinFile(string filename, bool splitImages = true)
{
var outputPath = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename));
@ -518,6 +554,7 @@ namespace gitadora_texbintool
}
}
var formatMetadata = new FormatMetadata();
foreach (var entry in entries)
{
reader.BaseStream.Seek(entry.DataOffset, SeekOrigin.Begin);
@ -550,6 +587,11 @@ namespace gitadora_texbintool
rectInfoList.Add(rectInfo);
}
formatMetadata.FormatInfo.Add(new FormatInfo{
Filename = entry.Filename,
FormatType = data[0x2c]
});
foreach (var rectInfo in rectInfoList)
{
try
@ -578,10 +620,11 @@ namespace gitadora_texbintool
var outputFilename = Path.Combine(outputPath, rectInfo.Filename);
outputFilename += ext;
Console.WriteLine("Saving {0}...", outputFilename);
File.WriteAllBytes(outputFilename, extractedData);
// File.WriteAllBytes(outputFilename.Replace(ext, ".bin"), data);
}
}
}
@ -593,6 +636,11 @@ namespace gitadora_texbintool
}
}
}
if (!splitImages)
{
Serialize<FormatMetadata>(formatMetadata, Path.Combine(outputPath, "_metadata-format.xml"));
}
}
}
@ -627,7 +675,7 @@ namespace gitadora_texbintool
for (int i = 0; i < filelist_sorted.Length; i++)
{
var filelist_idx = filelist_unique.IndexOf(filelist_sorted[i]);
nameSection.AddRange(BitConverter.GetBytes(CalculateHash(filelist_sorted[i])));
nameSection.AddRange(BitConverter.GetBytes(filelist_idx));
@ -656,8 +704,8 @@ namespace gitadora_texbintool
static void CreateTexbinFile(string pathname, bool generateRectSection = true, bool compressedData = true)
{
var filelist = Directory.GetFiles(pathname).Where(x => !x.ToLower().EndsWith("_metadata.xml")).ToArray();
var filelist_unique = filelist.Select(Path.GetFileNameWithoutExtension).Distinct().Where(x => !x.ToLower().EndsWith("_metadata.xml")).ToList();
var filelist = Directory.GetFiles(pathname).Where(x => !x.ToLower().EndsWith(".xml")).ToArray();
var filelist_unique = filelist.Select(Path.GetFileNameWithoutExtension).Distinct().Where(x => !x.ToLower().EndsWith(".xml")).ToList();
filelist_unique = filelist_unique.Select(x => x.ToUpper()).ToList();
if (filelist_unique.Count != filelist.Length)
@ -666,6 +714,24 @@ namespace gitadora_texbintool
Environment.Exit(1);
}
var formatMetadata = new FormatMetadata();
if (File.Exists(Path.Combine(pathname, "_metadata-format.xml")))
{
formatMetadata = DeserializeFormatMetadata(Path.Combine(pathname, "_metadata-format.xml"));
}
else
{
foreach (var filename in filelist_unique)
{
var data = new FormatInfo
{
Filename = filename,
FormatType = 0,
};
formatMetadata.FormatInfo.Add(data);
}
}
var nameSection = CreateNameSection(filelist_unique);
var dataSection = new List<byte>();
@ -682,22 +748,28 @@ namespace gitadora_texbintool
{
data = gitadora_textool.Program.CreateImageCore(data, true);
}
var formatTypeList = formatMetadata.FormatInfo.Where(x =>
String.CompareOrdinal(Path.GetFileNameWithoutExtension(filelist_unique[i]),
x.Filename) == 0).ToList();
data[0x2c] = formatTypeList.Count > 0 ? formatTypeList[0].FormatType : data[0x2c];
fileinfoSection.AddRange(BitConverter.GetBytes(0));
fileinfoSection.AddRange(BitConverter.GetBytes(data.Length + 0x08));
fileinfoSection.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + (filelist_unique.Count * 0x0c) + dataSection.Count));
if (compressedData)
{
dataSection.AddRange(Compress(data));
}
else
{
dataSection.AddRange(BitConverter.GetBytes(data.Length).Reverse());
dataSection.AddRange(BitConverter.GetBytes(0));
dataSection.AddRange(data);
}
if (compressedData)
{
dataSection.AddRange(Compress(data));
}
else
{
dataSection.AddRange(BitConverter.GetBytes(data.Length).Reverse());
dataSection.AddRange(BitConverter.GetBytes(0));
dataSection.AddRange(data);
}
imageRectInfo[filelist_unique[i]] = new Tuple<ushort, ushort>((ushort)((data[0x11] << 8) | data[0x10]), (ushort)((data[0x13] << 8) | data[0x12]));
}
@ -739,8 +811,8 @@ namespace gitadora_texbintool
var rectNameFilelist = rectInfo.RectInfo.Select(x => x.Filename)
.Select(Path.GetFileNameWithoutExtension).Distinct()
.Where(x => !x.ToLower().EndsWith("_metadata.xml")).ToList();
.Where(x => !x.ToLower().EndsWith(".xml")).ToList();
var rectinfoSection = new List<byte>();
var rectNameSection = CreateNameSection(rectNameFilelist);
foreach (var data in rectInfo.RectInfo)
@ -800,12 +872,12 @@ namespace gitadora_texbintool
var splitImage = true;
var generateRectSection = true;
var compressedData = true;
var compressedData = true;
var filenames = new List<string>();
for (var index = 0; index < args.Length; index++)
{
if (String.CompareOrdinal(args[index].ToLower(), "--no-rect") == 0
if (String.CompareOrdinal(args[index].ToLower(), "--no-rect") == 0
|| String.CompareOrdinal(args[index].ToLower(), "--nr") == 0
|| String.CompareOrdinal(args[index].ToLower(), "-nr") == 0)
{