Commit c94da429 authored by Spencer Alves's avatar Spencer Alves

Better error handling (fix #2), export and use chunk order (fix #3), some code cleanup

parent 115cff0d
......@@ -112,8 +112,23 @@ namespace Altar
internal set;
}
public FunctionLocalsInfo[] FunctionLocals;
public uint[] VariableExtra;
public FunctionLocalsInfo[] FunctionLocals
{
get;
internal set;
}
public uint[] VariableExtra
{
get;
internal set;
}
public SectionHeaders[] ChunkOrder
{
get;
internal set;
}
internal GMFile()
{
......@@ -147,6 +162,10 @@ namespace Altar
Textures = new TextureInfo [0];
Audio = new AudioInfo [0];
AudioGroups = new string [0];
FunctionLocals = new FunctionLocalsInfo[0];
VariableExtra = new uint [0];
ChunkOrder = new SectionHeaders [0];
}
static T[] TryReadMany<T>(SectionCountOffsets* hdr, Func<uint, T> readOne)
{
......@@ -178,6 +197,15 @@ namespace Altar
{
Content = f;
var orderList = new List<SectionHeaders>(f.HeaderOffsets.Length);
foreach (long headerOffset in f.HeaderOffsets)
{
SectionHeaders tag = ((SectionHeader*)((byte*)f.Form + headerOffset))->Identity;
if (tag != SectionHeaders.Form)
orderList.Add(tag);
}
ChunkOrder = orderList.ToArray();
General = SectionReader.GetGeneralInfo(f);
//Console.Error.WriteLine(General.BytecodeVersion);
Options = SectionReader.GetOptionInfo (f);
......@@ -249,7 +277,7 @@ namespace Altar
}
catch (Exception e)
{
Console.Error.WriteLine("Can't figure out RefDef pairs.");
Console.Error.WriteLine("Warning: Can't figure out RefDef pairs. Exception:");
Console.Error.WriteLine(e);
}
}
......@@ -293,99 +321,63 @@ namespace Altar
switch (hdr->Identity)
{
case SectionHeaders.General:
ret.General = (SectionGeneral*)hdr;
ret.General = (SectionGeneral*)hdr;
break;
case SectionHeaders.Options:
ret.Options = (SectionOptions*)hdr;
break;
case SectionHeaders.Extensions:
ret.Extensions = (SectionUnknown*)hdr;
if (!ret.Extensions->IsEmpty())
Console.Error.WriteLine("Warning: EXTN chunk is not empty, its content will not be exported!");
ret.Options = (SectionOptions*)hdr;
break;
case SectionHeaders.Sounds:
ret.Sounds = (SectionCountOffsets*)hdr;
ret.Sounds = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Sprites:
ret.Sprites = (SectionCountOffsets*)hdr;
ret.Sprites = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Backgrounds:
ret.Backgrounds = (SectionCountOffsets*)hdr;
ret.Backgrounds = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Paths:
ret.Paths = (SectionCountOffsets*)hdr;
ret.Paths = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Scripts:
ret.Scripts = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Shaders:
ret.Shaders = (SectionUnknown*)hdr;
if (!ret.Shaders->IsEmpty())
Console.Error.WriteLine("Warning: SHDR chunk is not empty, its content will not be exported!");
ret.Scripts = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Fonts:
ret.Fonts = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Timelines:
ret.Timelines = (SectionUnknown*)hdr;
if (!ret.Timelines->IsEmpty())
Console.Error.WriteLine("Warning: TMLN chunk is not empty, its content will not be exported!");
ret.Fonts = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Objects:
ret.Objects = (SectionCountOffsets*)hdr;
ret.Objects = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Rooms:
ret.Rooms = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.DataFiles:
ret.DataFiles = (SectionUnknown*)hdr;
if (!ret.DataFiles->IsEmpty())
Console.Error.WriteLine("Warning: DAFL chunk is not empty, its content will not be exported!");
ret.Rooms = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.TexturePage:
ret.TexturePages = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Code:
ret.Code = (SectionCountOffsets*)hdr;
ret.Code = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Variables:
ret.Variables = (SectionRefDefs*)hdr;
ret.Variables = (SectionRefDefs*)hdr;
break;
case SectionHeaders.Functions:
ret.Functions = (SectionRefDefs*)hdr;
ret.Functions = (SectionRefDefs*)hdr;
break;
case SectionHeaders.Strings:
ret.Strings = (SectionCountOffsets*)hdr;
ret.Strings = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Textures:
ret.Textures = (SectionCountOffsets*)hdr;
ret.Textures = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Audio:
ret.Audio = (SectionCountOffsets*)hdr;
ret.Audio = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.AudioGroup:
ret.AudioGroup = (SectionCountOffsets*)hdr;
break;
case SectionHeaders.Language:
ret.Language = (SectionUnknown*)hdr;
if (!ret.Language->IsEmpty())
Console.Error.WriteLine("Warning: LANG chunk is not empty, its content will not be exported!");
break;
case SectionHeaders.GLOB_Unk:
ret.GLOB_Unk = (SectionUnknown*)hdr;
if (!ret.GLOB_Unk->IsEmpty())
Console.Error.WriteLine("Warning: GLOB chunk is not empty, its content will not be exported!");
ret.AudioGroup = (SectionCountOffsets*)hdr;
break;
default:
var unk = (SectionUnknown*)hdr;
if (!unk->IsEmpty())
Console.Error.WriteLine($"Warning: unknown chunk {hdr->Identity.ToChunkName()}, chunk is not empty, its content will not be exported!");
Console.Error.WriteLine($"Warning: unknown chunk {hdr->Identity.ToChunkName()} is not empty, its content will not be exported!");
ret.UnknownChunks.Add(hdr->Identity, (IntPtr)unk);
break;
......
......@@ -10,6 +10,7 @@ namespace Altar
Form = 0x4D524F46, // FORM
General = 0x384E4547, // GEN8
Options = 0x4E54504F, // OPTN
Language = 0x474E414C, // LANG
Extensions = 0x4E545845, // EXTN
Sounds = 0x444E4F53, // SOND
AudioGroup = 0x50524741, // AGRP
......@@ -17,6 +18,7 @@ namespace Altar
Backgrounds = 0x444E4742, // BGND
Paths = 0x48544150, // PATH
Scripts = 0x54504353, // SCPT
GLOB_Unk = 0x424F4C47, // GLOB
Shaders = 0x52444853, // SHDR
Fonts = 0x544E4F46, // FONT
Timelines = 0x4E4C4D54, // TMLN
......@@ -30,8 +32,6 @@ namespace Altar
Strings = 0x47525453, // STRG
Textures = 0x52545854, // TXTR
Audio = 0x4F445541, // AUDO
Language = 0x474E414C, // LANG
GLOB_Unk = 0x424F4C47, // GLOB
Count = 24
}
......@@ -121,13 +121,6 @@ namespace Altar
public SectionGeneral* General;
public SectionOptions* Options;
public SectionUnknown* Extensions; // empty
public SectionUnknown* Shaders ; // empty
public SectionUnknown* Timelines ; // empty
public SectionUnknown* DataFiles ; // empty
public SectionUnknown* Language ; // empty
public SectionUnknown* GLOB_Unk; // empty?
public SectionCountOffsets* Sounds ;
public SectionCountOffsets* Sprites ;
public SectionCountOffsets* Backgrounds ;
......@@ -173,19 +166,6 @@ namespace Altar
case SectionHeaders.Options:
return (SectionHeader*)Options;
case SectionHeaders.Extensions:
return (SectionHeader*)Extensions;
case SectionHeaders.Shaders:
return (SectionHeader*)Shaders;
case SectionHeaders.Timelines:
return (SectionHeader*)Timelines;
case SectionHeaders.DataFiles:
return (SectionHeader*)DataFiles;
case SectionHeaders.Language:
return (SectionHeader*)Language;
case SectionHeaders.GLOB_Unk:
return (SectionHeader*)GLOB_Unk;
case SectionHeaders.Sounds:
return (SectionHeader*)Sounds;
case SectionHeaders.Sprites:
......
......@@ -3,7 +3,7 @@ using CommandLine.Text;
namespace Altar
{
class ExportOptions
public class ExportOptions
{
// free short flags: lvxyz
......
This diff is collapsed.
......@@ -353,7 +353,7 @@ namespace Altar.Recomp
}
else
{
Console.Error.WriteLine("Can't use label " + gotoinst.Label);
Console.Error.WriteLine($"Error in {name}: Can't use label {gotoinst.Label}");
break;
}
var relTarget = (int)absTarget - (int)size;
......@@ -371,7 +371,7 @@ namespace Altar.Recomp
};
break;
default:
Console.Error.WriteLine("Unknown instruction type " + type + "!");
Console.Error.WriteLine($"Error in {name}: Unknown instruction type {type}!");
continue;
}
binaryInstructions.Add(bininst);
......@@ -552,20 +552,27 @@ namespace Altar.Recomp
IList<ReferenceDef> variableStartOffsetsAndCounts;
ResolveReferenceOffsets(data, variableReferences, stringIndices, true, out variableStartOffsetsAndCounts);
// I tried my best at guessing what these should be, but it wasn't enough.
// I suspect it may have to do with variable type, since getting
// one wrong resulted in "tried to index something that isn't an
// array" (or something to that effect).
for (int i = 0; i < variableStartOffsetsAndCounts.Count; i++)
if (f.RefData.Variables == null || f.RefData.Variables.Length == 0)
{
var v = variableStartOffsetsAndCounts[i];
if (i < f.RefData.Variables.Length &&
v.Name == f.RefData.Variables[i].Name)// &&
//(v.InstanceType == f.RefData.Variables[i].InstanceType || v.InstanceType >= InstanceType.StackTopOrGlobal))
Console.Error.WriteLine("Warning: Variable definitions not pre-loaded. Linking may be inaccurate or lose information.");
}
else
{
// I tried my best at guessing what these should be, but it wasn't enough.
// I suspect it may have to do with variable type, since getting
// one wrong resulted in "tried to index something that isn't an
// array" (or something to that effect).
for (int i = 0; i < variableStartOffsetsAndCounts.Count; i++)
{
v.unknown2 = f.RefData.Variables[i].unknown2;
v.InstanceType = f.RefData.Variables[i].InstanceType;
variableStartOffsetsAndCounts[i] = v;
var v = variableStartOffsetsAndCounts[i];
if (i < f.RefData.Variables.Length &&
v.Name == f.RefData.Variables[i].Name)// &&
//(v.InstanceType == f.RefData.Variables[i].InstanceType || v.InstanceType >= InstanceType.StackTopOrGlobal))
{
v.unknown2 = f.RefData.Variables[i].unknown2;
v.InstanceType = f.RefData.Variables[i].InstanceType;
variableStartOffsetsAndCounts[i] = v;
}
}
}
......
This diff is collapsed.
......@@ -113,7 +113,7 @@ namespace Altar.Repack
var allOffs = data.OffsetOffsets.ToList();
var offAcc = bb.Position + datas.Length * sizeof(int); // after all offsets
int[] offsets = new int[datas.Length];
var offsets = new List<int>(datas.Length);
for (int i = 0; i < datas.Length; i++)
{
if (datas[i] == null)
......@@ -124,7 +124,7 @@ namespace Altar.Repack
{
allOffs.Add(bb.Position);
bb.Write(offAcc);
offsets[i] = offAcc;
offsets.Add(offAcc);
offAcc += datas[i].Buffer.Size;
}
......@@ -140,7 +140,7 @@ namespace Altar.Repack
}
data.OffsetOffsets = allOffs.ToArray();
return offsets;
return offsets.ToArray();
}
public static int[] WriteList<T>(BBData data, T[] things,
......@@ -199,7 +199,7 @@ namespace Altar.Repack
{
var bb = data.Buffer;
bb.Write(s);
bb.Write((byte)0);
bb.WriteByte(0);
}
public static IDictionary<string, int> WriteStrings(BBData data, String[] strings)
......@@ -297,7 +297,7 @@ namespace Altar.Repack
for (int i = 0; i < ret.NumberCount; i++)
data.Buffer.Write(ge.WeirdNumbers[i]);
// TODO: some lengthy checksum/hash at the end?
// TODO for 2.0: some lengthy checksum/hash at the end?
// exits after launch if GEN8 is modified at all,
// doesn't launch if the extra stuff is missing
//for (int i = 0; i < 16; i++)
......@@ -367,7 +367,7 @@ namespace Altar.Repack
for (int i = 0; i < textures.Length; i++)
{
BBData texturedata = new BBData(new BinBuffer(), new int[0]);
//texturedata.Buffer.Write(1); // TextureEntry._pad
//texturedata.Buffer.Write(1); // TextureEntry._pad for 2.0
texturedata.Buffer.Write(0); // TextureEntry._pad
texturedata.Buffer.Write(0); // TextureEntry.Offset
datas[i] = texturedata;
......@@ -380,7 +380,7 @@ namespace Altar.Repack
{
Pad(data, 0x80, 8);
var p = data.Buffer.Position;
data.Buffer.Position = offsets[i] + 4; // 8
data.Buffer.Position = offsets[i] + 4; // 8 on 2.0
secondaryOffsets[i] = data.Buffer.Position;
data.Buffer.Write(p);
data.Buffer.Position = p;
......@@ -959,6 +959,7 @@ namespace Altar.Repack
WriteList(data, ri.ObjInst, WriteRoomObjInst, stringOffsets);
}
// Unknown stuff for 2.0
//for (int i = 0; i < 8; i++)
// data.Buffer.Write(0x3F3F3F3F);
}
......
......@@ -149,17 +149,21 @@ namespace Altar.Unpack
static RoomObjInst ReadRoomObjInst(GMFileContent content, IntPtr p)
{
var entry = (RoomObjInstEntry*)p;
var oi = new RoomObjInst();
oi.Index = entry->Index;
oi.Name = StringFromOffset(content, entry->Name);
oi.Unk1 = entry->Unk1;
oi.Unk2 = entry->Unk2;
oi.Unk3 = entry->Unk3;
oi.Instances = new uint[entry->InstCount];
for (uint i = 0; i < oi.Instances.Length; i++)
{
oi.Instances[i] = (&entry->Instances)[i];
}
return oi;
}
......@@ -746,7 +750,7 @@ namespace Altar.Unpack
return ret;
});
}
//TODO: unused stuff might contain info about local vars?
public static ReferenceDef[] GetRefDefsWithLength(GMFileContent content, SectionRefDefs* section)
{
return GetRefDefsInternal(content, section, 1, section->Entries.NameOffset /* actually length, because reasons */, 12, p =>
......
......@@ -510,26 +510,34 @@ namespace Altar.Unpack
return r;
}
public unsafe static JsonData SerializeProject(GMFile f, List<IntPtr> chunks = null)
public unsafe static JsonData SerializeProject(GMFile f, ExportOptions eo, List<IntPtr> chunks = null)
{
var r = CreateObj();
r["general"] = "general.json";
r["options"] = "options.json";
r["chunkorder"] = SerializeArray(f.ChunkOrder, sh => sh.ToChunkName());
r["strings" ] = "strings.json";
r["variables"] = "variables.json";
r["functions"] = "functions.json";
if (eo.General) r["general"] = "general.json";
if (eo.Options) r["options"] = "options.json";
if (eo.String ) r["strings" ] = "strings.json";
if (eo.Variables) r["variables"] = "variables.json";
if (eo.Functions) r["functions"] = "functions.json";
// ---
r["textures"] = CreateArr();
for (int i = 0; i < f.Textures.Length; i++)
r["textures"].Add(SR.DIR_TEX + i.ToString(CultureInfo.InvariantCulture) + SR.EXT_PNG);
if (eo.Texture)
{
r["textures"] = CreateArr();
for (int i = 0; i < f.Textures.Length; i++)
r["textures"].Add(SR.DIR_TEX + i.ToString(CultureInfo.InvariantCulture) + SR.EXT_PNG);
}
r["tpags"] = CreateArr();
for (int i = 0; i < f.TexturePages.Length; i++)
r["tpags"].Add(SR.DIR_TXP + i.ToString(CultureInfo.InvariantCulture) + SR.EXT_JSON);
if (eo.TPag)
{
r["tpags"] = CreateArr();
for (int i = 0; i < f.TexturePages.Length; i++)
r["tpags"].Add(SR.DIR_TXP + i.ToString(CultureInfo.InvariantCulture) + SR.EXT_JSON);
}
// ---
......@@ -539,36 +547,47 @@ namespace Altar.Unpack
if ((s.IsEmbedded || s.IsCompressed) && s.AudioID != -1)
infoTable[s.AudioID] = s;
r["audio"] = CreateArr();
for (int i = 0; i < f.Audio.Length; i++)
r["audio"].Add(SR.DIR_WAV + infoTable[i].Name + SR.EXT_WAV);
if (eo.Audio)
{
r["audio"] = CreateArr();
for (int i = 0; i < f.Audio.Length; i++)
r["audio"].Add(SR.DIR_WAV + infoTable[i].Name + SR.EXT_WAV);
}
r["code"] = CreateArr();
for (int i = 0; i < f.Code.Length; i++)
r["code"].Add(SR.DIR_CODE + f.Code[i].Name + /*SR.EXT_GML_LSP*/SR.EXT_GML_ASM);
if (eo.Disassemble || eo.Decompile)
{
r["code"] = CreateArr();
for (int i = 0; i < f.Code.Length; i++)
{
if (eo.Disassemble)
r["code"].Add(SR.DIR_CODE + f.Code[i].Name + SR.EXT_GML_ASM);
if (eo.Decompile)
r["code"].Add(SR.DIR_CODE + f.Code[i].Name + SR.EXT_GML_LSP);
}
}
// ---
if (f.Sound != null) r["sounds" ] = SerializeArray(f.Sound , s => SR.DIR_SND + s.Name + SR.EXT_JSON);
if (f.Sprites != null) r["sprites"] = SerializeArray(f.Sprites , s => SR.DIR_SPR + s.Name + SR.EXT_JSON);
if (f.Backgrounds != null) r["bg" ] = SerializeArray(f.Backgrounds, s => SR.DIR_BG + s.Name + SR.EXT_JSON);
if (f.Paths != null) r["paths" ] = SerializeArray(f.Paths , s => SR.DIR_PATH + s.Name + SR.EXT_JSON);
if (f.Scripts != null) r["scripts"] = SerializeArray(f.Scripts , s => SR.DIR_SCR + s.Name + SR.EXT_JSON);
if (f.Fonts != null) r["fonts" ] = SerializeArray(f.Fonts , s => SR.DIR_FNT + s.CodeName + SR.EXT_JSON);
if (f.Objects != null) r["objs" ] = SerializeArray(f.Objects , s => SR.DIR_OBJ + s.Name + SR.EXT_JSON);
if (f.Rooms != null) r["rooms" ] = SerializeArray(f.Rooms , s => SR.DIR_ROOM + s.Name + SR.EXT_JSON);
if (f.Sound != null && eo.Sound ) r["sounds" ] = SerializeArray(f.Sound , s => SR.DIR_SND + s.Name + SR.EXT_JSON);
if (f.Sprites != null && eo.Sprite ) r["sprites"] = SerializeArray(f.Sprites , s => SR.DIR_SPR + s.Name + SR.EXT_JSON);
if (f.Backgrounds != null && eo.Background) r["bg" ] = SerializeArray(f.Backgrounds, s => SR.DIR_BG + s.Name + SR.EXT_JSON);
if (f.Paths != null && eo.Path ) r["paths" ] = SerializeArray(f.Paths , s => SR.DIR_PATH + s.Name + SR.EXT_JSON);
if (f.Scripts != null && eo.Script ) r["scripts"] = SerializeArray(f.Scripts , s => SR.DIR_SCR + s.Name + SR.EXT_JSON);
if (f.Fonts != null && eo.Font ) r["fonts" ] = SerializeArray(f.Fonts , s => SR.DIR_FNT + s.CodeName + SR.EXT_JSON);
if (f.Objects != null && eo.Object ) r["objs" ] = SerializeArray(f.Objects , s => SR.DIR_OBJ + s.Name + SR.EXT_JSON);
if (f.Rooms != null && eo.Room ) r["rooms" ] = SerializeArray(f.Rooms , s => SR.DIR_ROOM + s.Name + SR.EXT_JSON);
if (f.AudioGroups != null && f.AudioGroups.Length > 0) r["audiogroups"] = "audiogroups.json";
if (f.AudioGroups != null && eo.AudioGroups) r["audiogroups"] = "audiogroups.json";
if (chunks != null && chunks.Count > 0)
if (chunks != null)
{
r["chunks"] = CreateArr();
for (int i = 0; i < chunks.Count; i++)
{
var hdr = (SectionHeader*)chunks[i];
r["chunks"].Add(hdr->MagicString() + SR.EXT_BIN);
if (hdr != null && (!hdr->IsEmpty() || eo.DumpEmptyChunks))
r["chunks"].Add(hdr->MagicString() + SR.EXT_BIN);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment