public SubrecordElement CreateType(string name, string type) { var elem = new SubrecordElement(); elem.name = string.IsNullOrEmpty(name) ? "Unknown" : name; elem.type = type; return(elem); }
public ElementStructure(SubrecordElement node) { name = node.name; desc = node.desc; @group = node.group; hexview = node.hexview; notininfo = node.notininfo; optional = node.optional != 0; options = node.options == null ? new string[0] : node.options.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries); flags = node.flags == null ? new string[0] : node.flags.Split(new[] {';'}); repeat = node.repeat; CondID = node.condid; if (optional || repeat > 0) { if (group != 0) throw new RecordXmlException("Elements with a group attribute cant be marked optional or repeat"); } FormIDType = null; multiline = node.multiline; type = (ElementValueType) Enum.Parse(typeof (ElementValueType), node.type, true); switch (type) { case ElementValueType.FormID: FormIDType = node.reftype; break; case ElementValueType.Blob: if (repeat > 0 || optional) throw new RecordXmlException( "blob type elements can't be marked with repeat or optional"); break; } }
private void ProcessSubRecord(Subrecord sr, SubRecord[] srs) { long minSize = srs.Min(a => a.Size); long maxSize = srs.Max(a => a.Size); if (maxSize == 0) // likely a group start { sr.size = -1; return; } int szCount = 0; foreach (var ss in srs) { if (ss.Size == 0) { continue; } byte[] data = ss.GetReadonlyData(); if (IsLikelyString(new ArraySegment <byte>(data, 0, (int)ss.Size))) { if (++szCount > 10) { SubrecordElement elem = CreateType(null, "string"); sr.Elements.Add(elem); break; } } else { break; } } if (sr.Elements.Count > 0) { return; // found string } if (minSize == maxSize && maxSize < 256) { sr.size = (int)maxSize; int index = 0; // Walk through each element guessing the data type for (int offset = 0, elemSize = 4; offset < maxSize; offset += elemSize) { int numZero = 0; int numFloat = 0; int num2Short = 0; int isFormID = 0; int numTotal = 0; int isLString = 0; string reftype = null; if (maxSize - offset < 4) { if (maxSize >= 2) { var elem = CreateType(index++, "short"); elem.size = 2; sr.Elements.Add(elem); elemSize = 2; continue; } else { var elem = CreateType(index++, "byte"); elem.size = 1; sr.Elements.Add(elem); elemSize = 1; continue; } } foreach (var ss in srs) //.Random(srs.Length < 10 ? 0 : srs.Length / 10) { ++numTotal; byte[] data = ss.GetReadonlyData(); uint ui4 = TypeConverter.h2i(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); if (ui4 == 0) { ++numZero; continue; } ushort lhs = TypeConverter.h2s(data[offset], data[offset + 1]); ushort uhs = TypeConverter.h2s(data[offset + 2], data[offset + 3]); float flt = TypeConverter.h2f(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); if (IsLikelyFloat(flt)) { ++numFloat; } if (lhs > 0 && lhs < 255 && uhs > 0 && uhs < 255) { ++num2Short; } if (ui4 > 100) { Record r = FormLookup(ui4); if (r != null) { if (string.IsNullOrEmpty(reftype)) { reftype = r.Name; isFormID++; } else if (reftype == r.Name) { isFormID++; } } if (!string.IsNullOrEmpty(StringLookup(ui4))) { ++isLString; } } } if (numTotal > 0) { float floatPct = (numFloat + numZero) / (float)numTotal; float shortPct = (num2Short + numZero) / (float)numTotal; float formPct = (isFormID + numZero) / (float)numTotal; float lstrPct = (isLString + numZero) / (float)numTotal; if (numFloat > 0 && floatPct > 0.5f) { var elem = CreateType(index++, "float"); elem.size = 4; sr.Elements.Add(elem); } else if (num2Short > 0 && shortPct > 0.5f) { var elem = CreateType(index++, "short"); elem.size = 2; sr.Elements.Add(elem); sr.Elements.Add(elem); UpdateSize(sr); } else if (isFormID > 0 && formPct > 0.5f) { var elem = CreateType(index++, "formid"); elem.reftype = reftype; elem.size = 4; sr.Elements.Add(elem); } else if (isLString > 0 && lstrPct > 0.5f) { var elem = CreateType(index++, "lstring"); elem.size = 4; sr.Elements.Add(elem); } else { var elem = CreateType(index++, "int"); elem.size = 4; sr.Elements.Add(elem); } } } } else // guess dynamically sized object... default to blob { if (sr.Elements.Count == 0) { long modSum = srs.Sum(a => a.Size % 4); // useful if we suspect this is an array of integers if (modSum == 0) { int count = 0; string reftype = null; foreach (var ss in srs) { byte[] data = ss.GetReadonlyData(); int offset = 0; uint ui4 = GetUInt32(data, offset); if (ui4 < 100) { continue; } Record r = FormLookup(ui4); if (r != null) { if (string.IsNullOrEmpty(reftype)) { reftype = r.Name; } else if (reftype == r.Name) { if (++count > 10) { break; } } } else { break; } } if (count > 0) { var elem = CreateType("ID", "formid"); elem.reftype = reftype; elem.size = 4; elem.repeat = 1; elem.optional = 1; sr.Elements.Add(elem); } } } // check if it is a string else make it a blob sr.size = 0; if (sr.Elements.Count == 0) { sr.Elements.Add(CreateBlob()); } } }