public void UpdateSize(Subrecord sr) { sr.size = 0; foreach (var sre in sr.Elements) { sr.size += sre.size; } }
internal void MergeRecord(Subrecord baseRecord, Subrecord updateRecord) { if (baseRecord == null) { return; } if (updateRecord.desc == updateRecord.name && !string.IsNullOrEmpty(baseRecord.desc)) { updateRecord.desc = baseRecord.desc; } var baseItr = baseRecord.Elements.GetEnumerator(); var updateItr = updateRecord.Elements.GetEnumerator(); bool baseOk = baseItr.MoveNext(); bool updateOk = updateItr.MoveNext(); while (baseOk && updateOk) { var bse = baseItr.Current; var use = updateItr.Current; if (bse == null && use == null) { break; } if (use.name.StartsWith("Unknown", StringComparison.InvariantCultureIgnoreCase)) { use.name = bse.name; if (bse.type == use.type) { use.notininfo = bse.notininfo; use.options = bse.options; use.flags = bse.flags; use.hexview = bse.hexview; use.multiline = bse.multiline; } if (bse.type == "string" && use.type == "int") { // likely an lstring use.type = "lstring"; use.notininfo = bse.notininfo; use.options = bse.options; use.flags = bse.flags; use.hexview = bse.hexview; use.multiline = bse.multiline; } } baseOk = baseItr.MoveNext(); updateOk = updateItr.MoveNext(); } }
protected SubrecordBase(Subrecord node) { if (node.name.StartsWith("&#x")) { string[] val = node.name.Split(new[] {';'}, 2, StringSplitOptions.None); var c = (char) int.Parse(val[0].Substring(3), NumberStyles.HexNumber, null); name = c + val[1]; } else name = node.name; repeat = node.repeat; optional = node.optional; desc = node.desc; }
public SubrecordStructure(Subrecord node) : base(node) { notininfo = node.notininfo; size = node.size; Condition = (!string.IsNullOrEmpty(node.condition)) ? (CondType) Enum.Parse(typeof (CondType), node.condition, true) : CondType.None; CondID = node.condid; CondOperand = node.condvalue; UseHexEditor = node.usehexeditor; //if (optional && repeat) //{ // throw new RecordXmlException("repeat and optional must both have the same value if they are non zero"); //} var elements = new List<ElementStructure>(); foreach (var elem in node.Elements) elements.Add(new ElementStructure(elem)); this.elements = elements.ToArray(); ContainsConditionals = this.elements.Count(x => x.CondID != 0) > 0; }
private bool CreateSubrecords(RecordsRecord rr, Record r) { //int srIdx = 0; var groups = from psr in r.SubRecords group psr by psr.Name into g select new { Name = g.Key, Records = g.ToArray() }; int lastIndex = 0; var dict = new Dictionary <string, Subrecord>(); foreach (var kvp in groups) { if (IsCanceled) { return(false); } //if (kvp.Name.Count(a => !Char.IsLetterOrDigit(a)) > 0) continue; int n = kvp.Records.Length; Subrecord sr = rr.Subrecords.FirstOrDefault(x => x.name == kvp.Name); if (sr == null) { sr = new Subrecord(); sr.name = sr.desc = kvp.Name; sr.optional = 1; if (lastIndex + 1 <= rr.Items.Count) { rr.Items.Insert(++lastIndex, sr); } else { rr.Items.Add(sr); } } else { lastIndex = rr.Items.IndexOf(sr, (lastIndex < 0) ? lastIndex : 0); if (lastIndex < 0) // out of order { lastIndex = rr.Items.IndexOf(sr); } } // Group Detection if (n > 0) { int idx1 = r.SubRecords.IndexOf(kvp.Records[0]); int idx2 = idx1; for (int i = 1; i < n; ++i, idx1 = idx2) { idx2 = r.SubRecords.IndexOf(kvp.Records[i]); int diff = r.SubRecords.Skip(idx1).Take(idx2 - idx1).Select((a) => a.Name).Distinct().Count(); if (diff > sr.repeat) { sr.optional = sr.repeat = diff; } } if (sr.repeat == 0 && n > 1) { sr.optional = sr.repeat = 1; } } } return(true); }
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()); } } }