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; }
/// <summary> /// Loop through all properties of a subrecord /// and check if a property is a file path /// then checks if that file exists in the filemap /// </summary> /// <param name="subRecord"></param> /// <param name="map"></param> /// <param name="fileMap"></param> private static void GetPathsInSubRecordRecursive( Subrecord subRecord, List <string> map) { ArgumentNullException.ThrowIfNull(CurrentInstallation); var recordTypeName = subRecord.Name; var properties = subRecord .GetType() .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) .OrderBy(x => x.MetadataToken) .ToList() !; foreach (var property in properties) { var val = subRecord is not null?property.GetValue(subRecord) : null; if (val is string rawstr) { var str = rawstr.TrimEnd('\0').ToLower(); var file = CurrentInstallation.GetSubstitutingDataFile(str); if (file is null) { map.Add(str); } } else { if (val is Subrecord subrecord) { GetPathsInSubRecordRecursive(subrecord, map); } } } }
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(); } }
internal void ReadSubrecord() { var subrecord = new Subrecord(this); if (subrecord.signature == "XXXX") { var nextSize = reader.ReadUInt32(); subrecord = new Subrecord(this) { dataSize = nextSize }; } subrecordEndPos = stream.Position + subrecord.dataSize; _currentSubrecord = subrecord; }
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, ElementBase[] elementTree, ElementStructure[] elements) : base(node) { this.notininfo = node.notininfo; this.size = node.size; this.Condition = (!string.IsNullOrEmpty(node.condition)) ? (CondType)Enum.Parse(typeof(CondType), node.condition, true) : CondType.None; this.CondID = node.condid; this.CondOperand = node.condvalue; this.UseHexEditor = node.usehexeditor; this.elementTree = elementTree; this.elements = elements; this.ContainsConditionals = this.elements.Count(x => x.CondID != 0) > 0; }
public Challenge(SimpleSubrecord <String> EditorID, SimpleSubrecord <String> Name, SimpleSubrecord <String> LargeIcon, SimpleSubrecord <String> SmallIcon, RecordReference Script, SimpleSubrecord <String> Description, ChallengeData Data, Subrecord Value1, Subrecord Value2) { this.EditorID = EditorID; }
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 (this.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 = this.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 = this.CreateType(index++, "short"); elem.size = 2; sr.Elements.Add(elem); elemSize = 2; continue; } else { var elem = this.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 = this.FormLookup(ui4); if (r != null) { if (string.IsNullOrEmpty(reftype)) { reftype = r.Name; isFormID++; } else if (reftype == r.Name) { isFormID++; } } if (!string.IsNullOrEmpty(this.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 = this.CreateType(index++, "float"); elem.size = 4; sr.Elements.Add(elem); } else if (num2Short > 0 && shortPct > 0.5f) { var elem = this.CreateType(index++, "short"); elem.size = 2; sr.Elements.Add(elem); sr.Elements.Add(elem); this.UpdateSize(sr); } else if (isFormID > 0 && formPct > 0.5f) { var elem = this.CreateType(index++, "formid"); elem.reftype = reftype; elem.size = 4; sr.Elements.Add(elem); } else if (isLString > 0 && lstrPct > 0.5f) { var elem = this.CreateType(index++, "lstring"); elem.size = 4; sr.Elements.Add(elem); } else { var elem = this.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 = this.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 = this.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(this.CreateBlob()); } } }
public GameSetting(SimpleSubrecord <String> EditorID, Subrecord Value) { this.EditorID = EditorID; }
public Note(SimpleSubrecord <String> EditorID, ObjectBounds ObjectBounds, SimpleSubrecord <String> Name, Model Model, SimpleSubrecord <String> LargeIcon, SimpleSubrecord <String> SmallIcon, RecordReference PickUpSound, RecordReference DropSound, SimpleSubrecord <NoteType> Type, List <RecordReference> Quests, SimpleSubrecord <String> Image, Subrecord EntryData, RecordReference Audio) { this.EditorID = EditorID; this.ObjectBounds = ObjectBounds; this.Name = Name; }