private static bool ReadBinaryTemplate(string FileName, System.IO.BinaryReader Reader, int FloatingPointSize, Template Template, bool Inline, ref BinaryCache Cache, out Structure Structure) {
const short TOKEN_NAME = 0x1;
const short TOKEN_STRING = 0x2;
const short TOKEN_INTEGER = 0x3;
const short TOKEN_INTEGER_LIST = 0x6;
const short TOKEN_FLOAT_LIST = 0x7;
const short TOKEN_OBRACE = 0xA;
const short TOKEN_CBRACE = 0xB;
const short TOKEN_COMMA = 0x13;
const short TOKEN_SEMICOLON = 0x14;
Structure = new Structure(Template.Name, new object[] { });
System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
System.Text.ASCIIEncoding Ascii = new System.Text.ASCIIEncoding();
int m; for (m = 0; m < Template.Members.Length; m++) {
if (Template.Members[m] == "[???]") {
// unknown template
int Level = 0;
if (Cache.IntegersRemaining != 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "An integer list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
} else if (Cache.FloatsRemaining != 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "A float list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
}
short Token = Reader.ReadInt16();
switch (Token) {
case TOKEN_NAME:
{
Level++;
int n = Reader.ReadInt32();
if (n < 1) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_NAME at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
Reader.BaseStream.Position += n;
Token = Reader.ReadInt16();
if (Token != TOKEN_OBRACE) {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_OBRACE expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
} break;
case TOKEN_INTEGER:
{
Reader.BaseStream.Position += 4;
} break;
case TOKEN_INTEGER_LIST:
{
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_INTEGER_LIST at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
Reader.BaseStream.Position += 4 * n;
} break;
case TOKEN_FLOAT_LIST:
{
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_FLOAT_LIST at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
Reader.BaseStream.Position += (FloatingPointSize >> 3) * n;
} break;
case TOKEN_STRING:
{
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_STRING at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
Reader.BaseStream.Position += n;
Token = Reader.ReadInt16();
if (Token != TOKEN_COMMA & Token != TOKEN_SEMICOLON) {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_COMMA or TOKEN_SEMICOLON expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
} break;
case TOKEN_OBRACE:
Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected token TOKEN_OBRACE encountered at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
case TOKEN_CBRACE:
if (Level == 0) return true;
Level--;
break;
default:
Interface.AddMessage(Interface.MessageType.Error, false, "Unknown token encountered at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
} m--;
} else if (Template.Members[m] == "[...]") {
// any template
if (Cache.IntegersRemaining != 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "An integer list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
} else if (Cache.FloatsRemaining != 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "A float list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
}
if (Template.Name.Length == 0 && Reader.BaseStream.Position == Reader.BaseStream.Length) {
// end of file
return true;
}
short Token = Reader.ReadInt16();
switch (Token) {
case TOKEN_NAME:
int n = Reader.ReadInt32();
if (n < 1) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_NAME at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
string Name = new string(Ascii.GetChars(Reader.ReadBytes(n)));
Token = Reader.ReadInt16();
if (Token != TOKEN_OBRACE) {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_OBRACE expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
Structure o;
if (!ReadBinaryTemplate(FileName, Reader, FloatingPointSize, GetTemplate(Name), false, ref Cache, out o)) {
return false;
}
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = o;
break;
case TOKEN_CBRACE:
if (Template.Name.Length == 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "Unexpected TOKEN_CBRACE encountered at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
m++;
break;
default:
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_NAME or TOKEN_CBRACE expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
} m--;
} else if (Template.Members[m].EndsWith("]", StringComparison.Ordinal)) {
// inlined array expected
string r = Template.Members[m].Substring(0, Template.Members[m].Length - 1);
int h = r.IndexOf('[');
if (h >= 0) {
string z = r.Substring(h + 1, r.Length - h - 1);
r = r.Substring(0, h);
if (!int.TryParse(z, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out h)) {
Interface.AddMessage(Interface.MessageType.Error, false, "The internal format description for a template array is invalid in template " + Template.Name + " in binary X object file " + FileName);
return false;
}
if (h < 0 || h >= Structure.Data.Length || !(Structure.Data[h] is int)) {
Interface.AddMessage(Interface.MessageType.Error, false, "The internal format description for a template array is invalid in template " + Template.Name + " in binary X object file " + FileName);
return false;
}
h = (int)Structure.Data[h];
} else {
Interface.AddMessage(Interface.MessageType.Error, false, "The internal format description for a template array is invalid in template " + Template.Name + " in binary X object file " + FileName);
return false;
}
if (r == "DWORD") {
// dword array
int[] o = new int[h];
for (int i = 0; i < h; i++) {
if (Cache.IntegersRemaining != 0) {
// use cached integer
int a = Cache.Integers[Cache.IntegersRemaining - 1];
Cache.IntegersRemaining--;
o[i] = a;
} else if (Cache.FloatsRemaining != 0) {
// cannot use cached float
Interface.AddMessage(Interface.MessageType.Error, false, "A float list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
} else {
while (true) {
short Token = Reader.ReadInt16();
if (Token == TOKEN_INTEGER) {
int a = Reader.ReadInt32();
o[i] = a; break;
} else if (Token == TOKEN_INTEGER_LIST) {
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_INTEGER_LIST at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
if (n != 0) {
Cache.Integers = new int[n];
for (int j = 0; j < n; i++) {
Cache.Integers[n - j - 1] = Reader.ReadInt32();
}
Cache.IntegersRemaining = n - 1;
int a = Cache.Integers[Cache.IntegersRemaining];
o[i] = a;
break;
}
} else {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_INTEGER or TOKEN_INTEGER_LIST expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
}
}
}
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = o;
} else if (r == "float") {
// float array
double[] o = new double[h];
for (int i = 0; i < h; i++) {
if (Cache.IntegersRemaining != 0) {
// cannot use cached integer
Interface.AddMessage(Interface.MessageType.Error, false, "An integer list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
} else if (Cache.FloatsRemaining != 0) {
// use cached float
double a = Cache.Floats[Cache.FloatsRemaining - 1];
Cache.FloatsRemaining--;
o[i] = a;
} else {
while (true) {
short Token = Reader.ReadInt16();
if (Token == TOKEN_FLOAT_LIST) {
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_FLOAT_LIST at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
if (n != 0) {
Cache.Floats = new double[n];
for (int j = 0; j < n; i++) {
if (FloatingPointSize == 32) {
Cache.Floats[n - j - 1] = (double)Reader.ReadSingle();
} else if (FloatingPointSize == 64) {
Cache.Floats[n - j - 1] = Reader.ReadDouble();
}
}
Cache.FloatsRemaining = n - 1;
double a = Cache.Floats[Cache.FloatsRemaining];
o[i] = a;
break;
}
} else {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_FLOAT_LIST expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
}
}
}
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = o;
} else {
// template array
Structure[] o = new Structure[h];
for (int i = 0; i < h; i++) {
ReadBinaryTemplate(FileName, Reader, FloatingPointSize, GetTemplate(r), true, ref Cache, out o[i]);
}
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = o;
}
} else {
// inlined template or primitive expected
switch (Template.Members[m]) {
case "DWORD":
// dword expected
if (Cache.IntegersRemaining != 0) {
// use cached integer
int a = Cache.Integers[Cache.IntegersRemaining - 1];
Cache.IntegersRemaining--;
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = a;
} else if (Cache.FloatsRemaining != 0) {
// cannot use cached float
Interface.AddMessage(Interface.MessageType.Error, false, "A float list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
} else {
// read new data
while (true) {
short Token = Reader.ReadInt16();
if (Token == TOKEN_INTEGER) {
int a = Reader.ReadInt32();
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = a;
break;
} else if (Token == TOKEN_INTEGER_LIST) {
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_INTEGER_LIST at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
if (n != 0) {
Cache.Integers = new int[n];
for (int i = 0; i < n; i++) {
Cache.Integers[n - i - 1] = Reader.ReadInt32();
}
Cache.IntegersRemaining = n - 1;
int a = Cache.Integers[Cache.IntegersRemaining];
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = a;
break;
}
} else {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_INTEGER or TOKEN_INTEGER_LIST expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
}
} break;
case "float":
// float expected
if (Cache.IntegersRemaining != 0) {
// cannot use cached integer
Interface.AddMessage(Interface.MessageType.Error, false, "An integer list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
} else if (Cache.FloatsRemaining != 0) {
// use cached float
double a = Cache.Floats[Cache.FloatsRemaining - 1];
Cache.FloatsRemaining--;
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = a;
} else {
// read new data
while (true) {
short Token = Reader.ReadInt16();
if (Token == TOKEN_FLOAT_LIST) {
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_FLOAT_LIST at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
if (n != 0) {
Cache.Floats = new double[n];
for (int i = 0; i < n; i++) {
if (FloatingPointSize == 32) {
Cache.Floats[n - i - 1] = (double)Reader.ReadSingle();
} else if (FloatingPointSize == 64) {
Cache.Floats[n - i - 1] = Reader.ReadDouble();
}
}
Cache.FloatsRemaining = n - 1;
double a = Cache.Floats[Cache.FloatsRemaining];
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = a;
break;
}
} else {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_FLOAT_LIST expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
}
} break;
case "string":
{
// string expected
if (Cache.IntegersRemaining != 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "An integer list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
} else if (Cache.FloatsRemaining != 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "A float list was not depleted at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
}
short Token = Reader.ReadInt16();
if (Token == TOKEN_STRING) {
int n = Reader.ReadInt32();
if (n < 0) {
Interface.AddMessage(Interface.MessageType.Error, false, "count is invalid in TOKEN_STRING at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
string s = new string(Ascii.GetChars(Reader.ReadBytes(n)));
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = s;
Token = Reader.ReadInt16();
if (Token != TOKEN_SEMICOLON) {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_SEMICOLON expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
} else {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_STRING expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
} break;
default:
// inlined template expected
Structure o;
ReadBinaryTemplate(FileName, Reader, FloatingPointSize, GetTemplate(Template.Members[m]), true, ref Cache, out o);
Array.Resize<object>(ref Structure.Data, Structure.Data.Length + 1);
Structure.Data[Structure.Data.Length - 1] = o;
break;
}
}
}
if (Inline) {
return true;
} else {
string s = Template.Members[Template.Members.Length - 1];
if (s != "[???]" & s != "[...]") {
int Token = Reader.ReadInt16();
if (Token != TOKEN_CBRACE) {
Interface.AddMessage(Interface.MessageType.Error, false, "TOKEN_CBRACE expected at position 0x" + Reader.BaseStream.Position.ToString("X", Culture) + " in binary X object file " + FileName);
return false;
}
}
return true;
}
}