public static void ReorderSubrecords(Record rec) { var records = rec.GetStructures(); if (rec == null || records == null) { return; } RecordStructure recStruct; if (!records.TryGetValue(rec.Name, out recStruct)) { return; } SubrecordStructure[] sss = recStruct.subrecords; var subs = new List <SubRecord>(rec.SubRecords); foreach (var sub in subs) { sub.DetachStructure(); } var newsubs = new List <SubRecord>(); for (int ssidx = 0, sslen = 0; ssidx < sss.Length; ssidx += sslen) { SubrecordStructure ss = sss[ssidx]; bool repeat = ss.repeat > 0; sslen = Math.Max(1, ss.repeat); bool found = false; do { found = false; for (int ssoff = 0; ssoff < sslen; ++ssoff) { ss = sss[ssidx + ssoff]; for (int i = 0; i < subs.Count; ++i) { var sr = subs[i]; if (sr.Name == ss.name) { newsubs.Add(sr); subs.RemoveAt(i); found = true; break; } } } } while (found && repeat); } newsubs.AddRange(subs); rec.SubRecords.Clear(); rec.SubRecords.AddRange(newsubs); }
/// <summary> /// Clear any state /// </summary> public void ClearControl() { r = null; sr = null; ss = null; controlMap.Clear(); fpanel1.Controls.Clear(); Enabled = false; }
/// <summary> /// Clear any state. /// </summary> public void ClearControl() { this.r = null; this.sr = null; this.ss = null; this.controlMap.Clear(); this.fpanel1.Controls.Clear(); Enabled = false; }
public MediumLevelRecordEditor(SubRecord sr, SubrecordStructure ss, dFormIDLookupS formIDLookup, dFormIDScan formIDScan, dLStringLookup strIDLookup) { this.InitializeComponent(); Icon = Resources.tesv_ico; SuspendLayout(); this.sr = sr; this.ss = ss; this.formIDLookup = formIDLookup; this.formIDScan = formIDScan; this.strIDLookup = strIDLookup; int offset = 0; byte[] data = sr.GetReadonlyData(); this.boxes = new List <TextBox>(ss.elements.Length); this.valueTypes = new List <ElementValueType>(ss.elements.Length); this.elements = new List <Panel>(); int groupOffset = 0; int CurrentGroup = 0; try { for (int i = 0; i < ss.elements.Length; i++) { if (ss.elements[i].optional && offset == data.Length) { this.AddElement(ss.elements[i]); } else { this.AddElement(ss.elements[i], ref offset, data, ref groupOffset, ref CurrentGroup); if (ss.elements[i].repeat > 0) { this.repeatcount++; if (offset < data.Length) { i--; } } } } if (ss.elements[ss.elements.Length - 1].repeat > 0 && this.repeatcount > 0) { this.AddElement(ss.elements[ss.elements.Length - 1]); } } catch { MessageBox.Show("The subrecord doesn't appear to conform to the expected structure.\n" + "Saving is disabled, and the formatted information may be incorrect", "Warning"); this.bSave.Enabled = false; } ResumeLayout(); }
public MediumLevelRecordEditor(SubRecord sr, SubrecordStructure ss, dFormIDLookupS formIDLookup, dFormIDScan formIDScan, dLStringLookup strIDLookup) { this.InitializeComponent(); Icon = Resources.tesv_ico; SuspendLayout(); this.sr = sr; this.ss = ss; this.formIDLookup = formIDLookup; this.formIDScan = formIDScan; this.strIDLookup = strIDLookup; int offset = 0; byte[] data = sr.GetReadonlyData(); this.boxes = new List<TextBox>(ss.elements.Length); this.valueTypes = new List<ElementValueType>(ss.elements.Length); this.elements = new List<Panel>(); int groupOffset = 0; int CurrentGroup = 0; try { for (int i = 0; i < ss.elements.Length; i++) { if (ss.elements[i].optional > 0 && offset == data.Length) { this.AddElement(ss.elements[i]); } else { this.AddElement(ss.elements[i], ref offset, data, ref groupOffset, ref CurrentGroup); if (ss.elements[i].repeat > 0) { this.repeatcount++; if (offset < data.Length) { i--; } } } } if (ss.elements[ss.elements.Length - 1].repeat > 0 && this.repeatcount > 0) { this.AddElement(ss.elements[ss.elements.Length - 1]); } } catch { MessageBox.Show("The subrecord doesn't appear to conform to the expected structure.\n" + "Saving is disabled, and the formatted information may be incorrect", "Warning"); this.bSave.Enabled = false; } ResumeLayout(); }
/// <summary> /// Initializes a new instance of the <see cref="SubRecord" /> class. /// Create new subrecord using Structure as template /// </summary> /// <param name="srs"> /// </param> public SubRecord(SubrecordStructure srs) : this() { if (srs != null) { Name = srs.name; int size = 0; if (srs.size > 0) { size = srs.size; } else { foreach (var elem in srs.elements) { if (elem.optional == 0 || elem.repeat == 0) { switch (elem.type) { case ElementValueType.FormID: case ElementValueType.LString: case ElementValueType.Int: case ElementValueType.UInt: case ElementValueType.Float: case ElementValueType.Str4: case ElementValueType.IString: size += 4; break; case ElementValueType.BString: case ElementValueType.Short: case ElementValueType.UShort: size += 2; break; case ElementValueType.String: case ElementValueType.Byte: case ElementValueType.SByte: size += 1; break; } } } } this.Data = new byte[size]; // TODO: populate with defaults if provided... } }
public NewMediumLevelRecordEditor(Plugin p, Record r, SubRecord sr, SubrecordStructure ss) { this.InitializeComponent(); Icon = Resources.tesv_ico; SuspendLayout(); this.sr = sr; this.ss = ss; this.p = p; this.r = r; // walk each element in standard fashion int panelOffset = 0; try { foreach (var elem in ss.elements) { Control c = null; if (elem.options != null && elem.options.Length > 1) { c = new OptionsElement(); } else if (elem.flags != null && elem.flags.Length > 1) { c = new FlagsElement(); } else { switch (elem.type) { case ElementValueType.LString: c = new LStringElement(); break; case ElementValueType.FormID: c = new FormIDElement(); break; case ElementValueType.Blob: c = new HexElement(); break; default: c = new TextElement(); break; } } if (c is IElementControl) { var ec = c as IElementControl; ec.formIDLookup = p.GetRecordByID; ec.formIDScan = p.EnumerateRecords; ec.strIDLookup = p.LookupFormStrings; ec.Element = elem; if (elem.repeat > 0) { var ge = new RepeatingElement(); c = ge; c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; ge.InnerControl = ec; ge.Element = elem; ec = ge; } else if (elem.optional) { var re = new OptionalElement(); c = re; c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; re.InnerControl = ec; re.Element = elem; ec = re; c = re; } else { c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; } c.MinimumSize = c.Size; this.controlMap.Add(elem, ec); this.fpanel1.Controls.Add(c); panelOffset = c.Bottom; } } foreach (Element elem in r.EnumerateElements(sr, true)) { var es = elem.Structure; IElementControl c; if (this.controlMap.TryGetValue(es, out c)) { if (c is IGroupedElementControl) { var gc = c as IGroupedElementControl; gc.Elements.Add(elem.Data); } else { c.Data = elem.Data; } } } } catch { this.strWarnOnSave = "The subrecord doesn't appear to conform to the expected structure.\nThe formatted information may be incorrect."; this.Error.SetError(this.bSave, this.strWarnOnSave); this.Error.SetIconAlignment(this.bSave, ErrorIconAlignment.MiddleLeft); AcceptButton = this.bCancel; // remove save as default button when exception occurs CancelButton = this.bCancel; UpdateDefaultButton(); } ResumeLayout(); }
public void ConfigureRecords(IEnumerable<Record> records) { var recs = records.Select(rec => rec.GetStructure()).Distinct(); this.rec = (recs.Count() == 1) ? recs.FirstOrDefault() : null; if (this.rec == null) { this.filterTree.Roots = null; } else { //this.records = records; var srs = (from sr in this.rec.subrecords let children = sr.elements.Select(se => new BatchElement() { Name = se.name, Parent = null, Record = se, Type = BatchCondElementType.Set, Checked = false }).ToList() select new BatchSubrecord() { Name = string.Format("{0}: {1}", sr.name, sr.desc), Record = sr, Children = children, Checked = false, }).ToList(); // Construct specialized editors for FormID and related headers #if false { var elems = new List<TESVSnip.Data.SubrecordElement> { new TESVSnip.Data.SubrecordElement{name = "FormID", desc = "Form ID", hexview = true, type = "uint"}, new TESVSnip.Data.SubrecordElement{name = "Flags1", desc = "Flags 1", hexview = true, type = "uint"}, new TESVSnip.Data.SubrecordElement{name = "Flags2", desc = "Flags 2", hexview = true, type = "uint"}, new TESVSnip.Data.SubrecordElement{name = "Flags3", desc = "Flags 3", hexview = true, type = "uint"}, }; var frmHdr = new TESVSnip.Data.Subrecord { name = "Header", desc = "Record Header", Elements = elems }; var hdr = new SubrecordStructure(frmHdr); var hdrElems = hdr.elements.Select(se => new BatchElement { Name = se.name, Parent = null, Record = se, Type = BatchCondElementType.Set, Checked = false } ).ToList(); srs.Insert(0, new BatchSubrecord { Name = string.Format("{0}: {1}", hdr.name, hdr.desc), Record = hdr, Children = hdrElems, Checked = false, }); } #endif // fix parents after assignments foreach (var sr in srs) { foreach (var se in sr.Children) { se.Parent = sr; } } this.filterTree.Roots = srs; } }
public void ConfigureRecords(IEnumerable <Record> records) { var recs = records.Select( x => { RecordStructure rs; return(RecordStructure.Records.TryGetValue(x.Name, out rs) ? rs : null); }).Distinct(); this.rec = (recs.Count() == 1) ? recs.FirstOrDefault() : null; if (this.rec == null) { this.filterTree.Roots = null; } else { this.records = records; var srs = (from sr in this.rec.subrecords let children = sr.elements.Select(se => new BatchElement() { Name = se.name, Parent = null, Record = se, Type = BatchCondElementType.Set, Checked = false }).ToList() select new BatchSubrecord() { Name = string.Format("{0}: {1}", sr.name, sr.desc), Record = sr, Children = children, Checked = false, }).ToList(); // Construct specialized editors for FormID and related headers #if false { var elems = new List <TESVSnip.Data.SubrecordElement> { new TESVSnip.Data.SubrecordElement { name = "FormID", desc = "Form ID", hexview = true, type = "uint" }, new TESVSnip.Data.SubrecordElement { name = "Flags1", desc = "Flags 1", hexview = true, type = "uint" }, new TESVSnip.Data.SubrecordElement { name = "Flags2", desc = "Flags 2", hexview = true, type = "uint" }, new TESVSnip.Data.SubrecordElement { name = "Flags3", desc = "Flags 3", hexview = true, type = "uint" }, }; var frmHdr = new TESVSnip.Data.Subrecord { name = "Header", desc = "Record Header", Elements = elems }; var hdr = new SubrecordStructure(frmHdr); var hdrElems = hdr.elements.Select(se => new BatchElement { Name = se.name, Parent = null, Record = se, Type = BatchCondElementType.Set, Checked = false } ).ToList(); srs.Insert(0, new BatchSubrecord { Name = string.Format("{0}: {1}", hdr.name, hdr.desc), Record = hdr, Children = hdrElems, Checked = false, }); } #endif // fix parents after assignments foreach (var sr in srs) { foreach (var se in sr.Children) { se.Parent = sr; } } this.filterTree.Roots = srs; } }
public void DetachStructure() { this.Structure = null; }
public NewMediumLevelRecordEditor(Plugin p, Record r, SubRecord sr, SubrecordStructure ss) { this.InitializeComponent(); Icon = Resources.fosnip; SuspendLayout(); this.sr = sr; this.ss = ss; this.p = p; this.r = r; // walk each element in standard fashion int panelOffset = 0; try { this.fpanel1.ColumnStyles[0] = new ColumnStyle(SizeType.Percent, 100.0f); int maxWidth = this.fpanel1.Width - SystemInformation.VerticalScrollBarWidth - 8; int leftOffset = 0; // 8; foreach (var elem in ss.elements) { Control c = null; if (elem.options != null && elem.options.Length > 1) { c = new OptionsElement(); } else if (elem.flags != null && elem.flags.Length > 1) { c = new FlagsElement(); } else { switch (elem.type) { case ElementValueType.LString: c = new LStringElement(); break; case ElementValueType.FormID: c = new FormIDElement(); break; case ElementValueType.Blob: c = new HexElement(); break; default: c = new TextElement(); break; } } if (c is IElementControl) { var ec = c as IElementControl; ec.formIDLookup = p.GetRecordByID; ec.formIDScan = p.EnumerateRecords; ec.strIDLookup = p.LookupFormStrings; ec.Element = elem; if (elem.repeat > 0) { var ge = new RepeatingElement(); c = ge; c.Left = leftOffset; c.Width = maxWidth; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; ge.InnerControl = ec; ge.Element = elem; ec = ge; } else if (elem.optional > 0) { var re = new OptionalElement(); c = re; c.Left = leftOffset; c.Width = maxWidth; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; re.InnerControl = ec; re.Element = elem; ec = re; c = re; } else { c.Left = leftOffset; c.Width = maxWidth; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; } this.controlMap.Add(elem, ec); int idx = this.fpanel1.RowCount - 1; this.fpanel1.Controls.Add(c, 0, idx); var info = new RowStyle(SizeType.Absolute, c.Size.Height+2); if (idx == 0) this.fpanel1.RowStyles[0] = info; else this.fpanel1.RowStyles.Add(info); panelOffset = 0; ++this.fpanel1.RowCount; } } foreach (Element elem in r.EnumerateElements(sr, true)) { var es = elem.Structure; IElementControl c; if (this.controlMap.TryGetValue(es, out c)) { if (c is IGroupedElementControl) { var gc = c as IGroupedElementControl; gc.Elements.Add(elem.Data); } else { c.Data = elem.Data; } } } } catch { this.strWarnOnSave = "The subrecord doesn't appear to conform to the expected structure.\nThe formatted information may be incorrect."; this.Error.SetError(this.bSave, this.strWarnOnSave); this.Error.SetIconAlignment(this.bSave, ErrorIconAlignment.MiddleLeft); AcceptButton = this.bCancel; // remove save as default button when exception occurs CancelButton = this.bCancel; UpdateDefaultButton(); } ResumeLayout(); }
internal void AttachStructure(SubrecordStructure ss) { this.Structure = ss; }
public static void GetFormattedData(this SubRecord rec, StringBuilder s) { SubrecordStructure ss = rec.Structure; if (ss == null) { return; } var p = rec.GetPlugin(); dFormIDLookupI formIDLookup = p.LookupFormID; dLStringLookup strLookup = p.LookupFormStrings; dFormIDLookupR formIDLookupR = p.GetRecordByID; var recdata = rec.GetReadonlyData(); int offset = 0; s.AppendFormat("{0} ({1})", ss.name, ss.desc); s.AppendLine(); try { for (int eidx = 0, elen = 1; eidx < ss.elements.Length; eidx += elen) { var sselem = ss.elements[eidx]; bool repeat = sselem.repeat > 0; elen = sselem.repeat > 1 ? sselem.repeat : 1; do { for (int eoff = 0; eoff < elen && offset < recdata.Length; ++eoff) { sselem = ss.elements[eidx + eoff]; if (offset == recdata.Length && eidx == ss.elements.Length - 1 && sselem.optional > 0) { break; } if (!sselem.notininfo) { s.Append(sselem.name).Append(": "); } switch (sselem.type) { case ElementValueType.Int: { string tmps = TypeConverter.h2si(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]).ToString(); if (!sselem.notininfo) { if (sselem.hexview) { s.Append(TypeConverter.h2i(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]).ToString("X8")); } else { s.Append(tmps); } if (sselem.options != null && sselem.options.Length > 0) { for (int k = 0; k < sselem.options.Length; k += 2) { if (tmps == sselem.options[k + 1]) { s.AppendFormat(" ({0})", sselem.options[k]); } } } else if (sselem.flags != null && sselem.flags.Length > 0) { uint val = TypeConverter.h2i(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]); var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((val & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } if (tmp2.Length > 0) { s.AppendFormat(" ({0})", tmp2); } } } offset += 4; } break; case ElementValueType.UInt: { string tmps = TypeConverter.h2i(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]).ToString(); if (!sselem.notininfo) { if (sselem.hexview) { s.Append(TypeConverter.h2i(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]).ToString("X8")); } else { s.Append(tmps); } if (sselem.options != null && sselem.options.Length > 0) { for (int k = 0; k < sselem.options.Length; k += 2) { if (tmps == sselem.options[k + 1]) { s.AppendFormat(" ({0})", sselem.options[k]); } } } else if (sselem.flags != null && sselem.flags.Length > 0) { uint val = TypeConverter.h2i(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]); var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((val & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } if (tmp2.Length > 0) { s.AppendFormat(" ({0})", tmp2); } } } offset += 4; } break; case ElementValueType.Short: { string tmps = TypeConverter.h2ss(recdata[offset], recdata[offset + 1]).ToString(); if (!sselem.notininfo) { if (sselem.hexview) { s.Append(TypeConverter.h2ss(recdata[offset], recdata[offset + 1]).ToString("X4")); } else { s.Append(tmps); } if (sselem.options != null && sselem.options.Length > 0) { for (int k = 0; k < sselem.options.Length; k += 2) { if (tmps == sselem.options[k + 1]) { s.AppendFormat(" ({0})", sselem.options[k]); } } } else if (sselem.flags != null && sselem.flags.Length > 0) { uint val = TypeConverter.h2s(recdata[offset], recdata[offset + 1]); var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((val & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } if (tmp2.Length > 0) { s.AppendFormat(" ({0})", tmp2); } } } offset += 2; } break; case ElementValueType.UShort: { string tmps = TypeConverter.h2s(recdata[offset], recdata[offset + 1]).ToString(); if (!sselem.notininfo) { if (sselem.hexview) { s.Append(TypeConverter.h2s(recdata[offset], recdata[offset + 1]).ToString("X4")); } else { s.Append(tmps); } if (sselem.options != null && sselem.options.Length > 0) { for (int k = 0; k < sselem.options.Length; k += 2) { if (tmps == sselem.options[k + 1]) { s.Append(" (").Append(sselem.options[k]).Append(")"); } } } else if (sselem.flags != null && sselem.flags.Length > 0) { uint val = TypeConverter.h2s(recdata[offset], recdata[offset + 1]); var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((val & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } if (tmp2.Length > 0) { s.AppendFormat(" ({0})", tmp2); } } } offset += 2; } break; case ElementValueType.Byte: { string tmps = recdata[offset].ToString(); if (!sselem.notininfo) { if (sselem.hexview) { s.Append(recdata[offset].ToString("X2")); } else { s.Append(tmps); } if (sselem.options != null && sselem.options.Length > 0) { for (int k = 0; k < sselem.options.Length; k += 2) { if (tmps == sselem.options[k + 1]) { s.AppendFormat(" ({0})", sselem.options[k]); } } } else if (sselem.flags != null && sselem.flags.Length > 0) { int val = recdata[offset]; var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((val & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } if (tmp2.Length > 0) { s.AppendFormat(" ({0})", tmp2); } } } offset++; } break; case ElementValueType.SByte: { string tmps = ((sbyte)recdata[offset]).ToString(); if (!sselem.notininfo) { if (sselem.hexview) { s.Append(recdata[offset].ToString("X2")); } else { s.Append(tmps); } if (sselem.options != null && sselem.options.Length > 0) { for (int k = 0; k < sselem.options.Length; k += 2) { if (tmps == sselem.options[k + 1]) { s.AppendFormat(" ({0})", sselem.options[k]); } } } else if (sselem.flags != null && sselem.flags.Length > 0) { int val = recdata[offset]; var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((val & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } if (tmp2.Length > 0) { s.AppendFormat(" ({0})", tmp2); } } } offset++; } break; case ElementValueType.FormID: { uint id = TypeConverter.h2i(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]); if (!sselem.notininfo) { s.Append(id.ToString("X8")); } if (id != 0 && formIDLookup != null) { s.Append(": ").Append(formIDLookup(id)); } offset += 4; } break; case ElementValueType.Float: if (!sselem.notininfo) { s.Append(TypeConverter.h2f(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3])); } offset += 4; break; case ElementValueType.String: if (!sselem.notininfo) { while (recdata[offset] != 0) { s.Append((char)recdata[offset++]); } } else { while (recdata[offset] != 0) { offset++; } } offset++; break; case ElementValueType.Blob: if (!sselem.notininfo) { s.Append(TypeConverter.GetHexData(recdata, offset, recdata.Length - offset)); } offset += recdata.Length - offset; break; case ElementValueType.BString: { int len = TypeConverter.h2s(recdata[offset], recdata[offset + 1]); if (!sselem.notininfo) { s.Append(TESVSnip.Framework.Services.Encoding.Instance.GetString(recdata, offset + 2, len)); } offset += 2 + len; } break; case ElementValueType.IString: { int len = TypeConverter.h2si(recdata[offset], recdata[offset + 1], recdata[offset + 2], recdata[offset + 3]); if (!sselem.notininfo) { s.Append(TESVSnip.Framework.Services.Encoding.Instance.GetString(recdata, offset + 4, len)); } offset += 4 + len; } break; case ElementValueType.LString: { // Try to guess if string or string index. Do not know if the external string checkbox is set or not in this code int left = recdata.Length - offset; var data = new ArraySegment <byte>(recdata, offset, left); bool isString = TypeConverter.IsLikelyString(data); uint id = TypeConverter.h2i(data); string lvalue = strLookup(id); if (!string.IsNullOrEmpty(lvalue) || !isString) { if (!sselem.notininfo) { s.Append(id.ToString("X8")); } if (strLookup != null) { s.Append(": ").Append(lvalue); } offset += 4; } else { if (!sselem.notininfo) { while (recdata[offset] != 0) { s.Append((char)recdata[offset++]); } } else { while (recdata[offset] != 0) { offset++; } } offset++; } } break; case ElementValueType.Str4: { if (!sselem.notininfo) { s.Append(TESVSnip.Framework.Services.Encoding.Instance.GetString(recdata, offset, 4)); } offset += 4; } break; default: throw new ApplicationException(); } if (!sselem.notininfo) { s.AppendLine(); } } }while (repeat && offset < recdata.Length); } if (offset < recdata.Length) { s.AppendLine(); s.AppendLine("Remaining Data: "); s.Append(TypeConverter.GetHexData(recdata, offset, recdata.Length - offset)); } } catch { s.AppendLine("Warning: Subrecord doesn't seem to match the expected structure"); } }
public void SetContext(Record r, SubRecord sr, bool hexView) { if (this.r == r && this.sr == sr && this.hexView == hexView) { return; } if (r == null || sr == null) { this.ClearControl(); return; } // walk each element in standard fashion int panelOffset = 0; try { this.BeginUpdate(); this.ClearControl(); SuspendLayout(); this.fpanel1.SuspendLayout(); this.fpanel1.Width = Parent.Width; this.controlMap.Clear(); this.hexView = hexView; this.r = r; this.sr = sr; var p = this.GetPluginFromNode(r); this.ss = sr.Structure; // default to blob if no elements if (this.ss == null || this.ss.elements == null || hexView) { var c = new HexElement(); c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; var elem = r.EnumerateElements(sr, true).FirstOrDefault(); if (elem != null) { this.controlMap.Add(elem.Structure, c); this.fpanel1.Controls.Add(c); c.Data = elem.Data; } } else { foreach (var elem in this.ss.elements) { Control c = null; if (elem.options != null && elem.options.Length > 1) { c = new OptionsElement(); } else if (elem.flags != null && elem.flags.Length > 1) { c = new FlagsElement(); } else { switch (elem.type) { case ElementValueType.LString: c = new LStringElement(); break; case ElementValueType.FormID: c = new FormIDElement(); break; case ElementValueType.Blob: c = new HexElement(); break; default: c = new TextElement(); break; } } if (c is IElementControl) { var ec = c as IElementControl; ec.formIDLookup = p.GetRecordByID; ec.formIDScan = p.EnumerateRecords; ec.strIDLookup = p.LookupFormStrings; ec.Element = elem; if (elem.repeat > 0) { var ge = new RepeatingElement(); c = ge; c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; ge.InnerControl = ec; ge.Element = elem; ec = ge; } else if (elem.optional > 0) { var re = new OptionalElement(); c = re; c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; re.InnerControl = ec; re.Element = elem; ec = re; c = re; } else { c.Left = 8; c.Width = this.fpanel1.Width - 16; c.Top = panelOffset; c.Anchor = c.Anchor | AnchorStyles.Left | AnchorStyles.Right; } c.MinimumSize = c.Size; this.controlMap.Add(elem, ec); this.fpanel1.Controls.Add(c); panelOffset = c.Bottom; } } foreach (Element elem in r.EnumerateElements(sr, true)) { var es = elem.Structure; IElementControl c; if (this.controlMap.TryGetValue(es, out c)) { if (c is IGroupedElementControl) { var gc = c as IGroupedElementControl; gc.Elements.Add(elem.Data); } else { c.Data = elem.Data; } } } } Enabled = true; } catch { this.strWarnOnSave = "The subrecord doesn't appear to conform to the expected structure.\nThe formatted information may be incorrect."; } finally { this.fpanel1.ResumeLayout(); ResumeLayout(); this.EndUpdate(); Refresh(); } }
private static bool MatchRecordCheckCondition(Dictionary <int, Conditional> conditions, SubrecordStructure ss) { if (ss.Condition == CondType.Exists) { if (conditions.ContainsKey(ss.CondID)) { return(true); } else { return(false); } } else if (ss.Condition == CondType.Missing) { if (conditions.ContainsKey(ss.CondID)) { return(false); } else { return(true); } } Conditional cond; if (!conditions.TryGetValue(ss.CondID, out cond)) { return(false); } switch (cond.type) { case ElementValueType.SByte: case ElementValueType.Byte: case ElementValueType.UShort: case ElementValueType.Short: case ElementValueType.Int: case ElementValueType.UInt: case ElementValueType.FormID: { int i = Convert.ToInt32(cond.value), i2; if (!int.TryParse(ss.CondOperand, out i2)) { return(false); } switch (ss.Condition) { case CondType.Equal: return(i == i2); case CondType.Not: return(i != i2); case CondType.Less: return(i < i2); case CondType.Greater: return(i > i2); case CondType.GreaterEqual: return(i >= i2); case CondType.LessEqual: return(i <= i2); default: return(false); } } case ElementValueType.Float: { float i = (float)cond.value, i2; if (!float.TryParse(ss.CondOperand, out i2)) { return(false); } switch (ss.Condition) { case CondType.Equal: return(i == i2); case CondType.Not: return(i != i2); case CondType.Less: return(i < i2); case CondType.Greater: return(i > i2); case CondType.GreaterEqual: return(i >= i2); case CondType.LessEqual: return(i <= i2); default: return(false); } } case ElementValueType.Str4: case ElementValueType.BString: case ElementValueType.IString: case ElementValueType.String: { var s = (string)cond.value; switch (ss.Condition) { case CondType.Equal: return(s == ss.CondOperand); case CondType.Not: return(s != ss.CondOperand); case CondType.StartsWith: return(s.StartsWith(ss.CondOperand)); case CondType.EndsWith: return(s.EndsWith(ss.CondOperand)); case CondType.Contains: return(s.Contains(ss.CondOperand)); default: return(false); } } case ElementValueType.LString: { int i = (int)cond.value, i2; if (!int.TryParse(ss.CondOperand, out i2)) { return(false); } switch (ss.Condition) { case CondType.Equal: return(i == i2); case CondType.Not: return(i != i2); case CondType.Less: return(i < i2); case CondType.Greater: return(i > i2); case CondType.GreaterEqual: return(i >= i2); case CondType.LessEqual: return(i <= i2); default: return(false); } } default: return(false); } }
public static void GetFormattedData(this SubRecord rec, RTFBuilder s) { SubrecordStructure ss = rec.Structure; if (ss == null || ss.elements == null) { s.Append("String:\t").AppendLine(rec.GetStrData()).AppendLine(); s.Append("Hex: \t").AppendLine(rec.GetHexData()); s.AppendPara(); return; } bool addTerminatingParagraph = false; try { var p = rec.GetPlugin(); dFormIDLookupI formIDLookup = p.LookupFormID; dLStringLookup strLookup = p.LookupFormStrings; dFormIDLookupR formIDLookupR = p.GetRecordByID; // Table of items var table = new List <List <RTFCellDefinition> >(); // set up elements float maxWidth = 0; int maxFirstCellWidth = 0; var elems = rec.EnumerateElements(true).Where(x => x.Structure != null && !x.Structure.notininfo).ToList(); if (elems.Count == 0) { return; } foreach (var element in elems) { Size sz = s.MeasureText(element.Structure.name); int width = Math.Max(sz.Width / 11, 10); // approximate convert pixels to twips as the rtflib has crap documentation if (width > maxFirstCellWidth) { maxFirstCellWidth = width; } } foreach (var element in elems) { var row = new List <RTFCellDefinition>(); table.Add(row); var sselem = element.Structure; bool hasOptions = sselem.options != null && sselem.options.Length > 0; bool hasFlags = sselem.flags != null && sselem.flags.Length > 1; // setup borders for header var value = element.Value; var nameCell = new RTFCellDefinition(maxFirstCellWidth, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty); row.Add(nameCell); switch (sselem.type) { case ElementValueType.FormID: row.Add(new RTFCellDefinition(12, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); row.Add(new RTFCellDefinition(30, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); // Optional Add cell for break; case ElementValueType.LString: row.Add(new RTFCellDefinition(12, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); row.Add(new RTFCellDefinition(30, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); break; case ElementValueType.BString: case ElementValueType.IString: case ElementValueType.String: row.Add(new RTFCellDefinition(42, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); break; case ElementValueType.Int: case ElementValueType.UInt: case ElementValueType.Byte: case ElementValueType.SByte: case ElementValueType.Short: case ElementValueType.UShort: case ElementValueType.Float: row.Add(new RTFCellDefinition(20, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); row.Add(new RTFCellDefinition(30, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); break; case ElementValueType.Blob: row.Add(new RTFCellDefinition(42, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); break; case ElementValueType.Str4: row.Add(new RTFCellDefinition(42, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); break; default: row.Add(new RTFCellDefinition(42, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty)); break; } maxWidth = Math.Max(maxWidth, row.Sum(x => x.CellWidthRaw)); } var rowWidth = (int)(maxWidth * 100.0f); var pd = new Padding { All = 50 }; var hdrd = new RTFRowDefinition(rowWidth, RTFAlignment.TopLeft, RTFBorderSide.Default, 15, SystemColors.WindowText, pd); var hdrcds = new[] { new RTFCellDefinition(rowWidth, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 15, Color.DarkGray, Padding.Empty) }; addTerminatingParagraph = true; s.Reset(); using (IRTFRow ie = s.CreateRow(hdrd, hdrcds)) { foreach (var item in ie) { var rb = item.Content; item.Content.FontSize(s.DefaultFontSize + 1).FontStyle(FontStyle.Bold).ForeColor(KnownColor.DarkCyan).AppendFormat("{0} ({1})", ss.name, ss.desc); } } for (int rowIdx = 0; rowIdx < elems.Count; ++rowIdx) { var rd = new RTFRowDefinition(rowWidth, RTFAlignment.TopLeft, RTFBorderSide.Default, 15, SystemColors.WindowText, pd); var cds = table[rowIdx]; var elem = elems[rowIdx]; var sselem = elem.Structure; var value = elem.Value; string recprefix = null; Record record = null; string strValue = null; // value to display string strDesc = null; // first description string strDesc2 = null; // second description bool hasOptions = sselem.options != null && sselem.options.Length > 0; bool hasFlags = sselem.flags != null && sselem.flags.Length > 1; if (!string.IsNullOrWhiteSpace(elem.Structure.funcr)) { if (elem.Type == ElementValueType.Float) { value = PyInterpreter.ExecuteFunction <float>(elem, FunctionOperation.ForReading); } else if (elem.Type == ElementValueType.Int) { value = PyInterpreter.ExecuteFunction <int>(elem, FunctionOperation.ForReading); } else if (elem.Type == ElementValueType.Short) { value = PyInterpreter.ExecuteFunction <short>(elem, FunctionOperation.ForReading); } else if (elem.Type == ElementValueType.UShort) { value = PyInterpreter.ExecuteFunction <ushort>(elem, FunctionOperation.ForReading); } else if (elem.Type == ElementValueType.UInt) { value = PyInterpreter.ExecuteFunction <uint>(elem, FunctionOperation.ForReading); } } // Pre row write caching to avoid expensive duplicate calls between cells switch (sselem.type) { case ElementValueType.FormID: { var id = (uint)value; strValue = id.ToString("X8"); if (id != 0) { record = formIDLookupR != null?formIDLookupR(id) : null; } if (record != null) { var pref = record.GetPlugin(); recprefix = pref != null?string.Format("{0}@{1}", pref.Name, record.Name) : record.Name; strDesc = record.DescriptiveName; var full = record.SubRecords.FirstOrDefault(x => x.Name == "FULL"); if (full != null) { // split the cell 2 in 2 if full name found var data = new ArraySegment <byte>(full.GetReadonlyData()); bool isString = TypeConverter.IsLikelyString(data); string lvalue = isString ? full.GetStrData() : strLookup != null?strLookup(TypeConverter.h2i(data)) : null; if (!string.IsNullOrEmpty(lvalue)) { var first = cds[cds.Count - 1]; Size sz = s.MeasureText(lvalue); int width = Math.Min(40, Math.Max(sz.Width / 12, 10)); // approximate convert pixels to twips as the rtflib has crap documentation var second = new RTFCellDefinition(width, RTFAlignment.MiddleLeft, RTFBorderSide.Default, 0, Color.DarkGray, Padding.Empty); cds.Add(second); strDesc2 = lvalue; } } } } break; case ElementValueType.LString: { if (elem.Type == ElementValueType.String) { strValue = string.Empty; strDesc = value.ToString(); } else if (TypeConverter.IsLikelyString(elem.Data)) { strValue = string.Empty; strDesc = TypeConverter.GetString(elem.Data); } else { uint id = TypeConverter.h2i(elem.Data); strValue = id.ToString("X8"); strDesc = strLookup != null?strLookup(id) : null; } } break; case ElementValueType.Blob: strValue = TypeConverter.GetHexData(elem.Data); break; case ElementValueType.SByte: case ElementValueType.Int: case ElementValueType.Short: { if (sselem.hexview || hasFlags) { if (sselem.hexviewwithdec) { strValue = string.Format(string.Format("{{0:X{0}}}", elem.Data.Count * 2), value) + string.Format(" : {0}", value); } else { strValue = string.Format(string.Format("{{0:X{0}}}", elem.Data.Count * 2), value); } } else { strValue = value == null ? string.Empty : value.ToString(); } if (hasOptions) { int intVal = Convert.ToInt32(value); for (int k = 0; k < sselem.options.Length; k += 2) { int intValOption; if (int.TryParse(sselem.options[k + 1], out intValOption) && intVal == intValOption) { strDesc = sselem.options[k]; } } } else if (hasFlags) { int intVal = Convert.ToInt32(value); var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((intVal & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } strDesc = tmp2.ToString(); } } break; case ElementValueType.UInt: case ElementValueType.Byte: case ElementValueType.UShort: { if (sselem.hexview || hasFlags) { if (sselem.hexviewwithdec) { strValue = string.Format(string.Format("{{0:X{0}}}", elem.Data.Count * 2), value) + string.Format(" : {0}", value); } else { strValue = string.Format(string.Format("{{0:X{0}}}", elem.Data.Count * 2), value); } } else { strValue = value == null ? string.Empty : value.ToString(); } if (hasOptions) { uint intVal = Convert.ToUInt32(value); for (int k = 0; k < sselem.options.Length; k += 2) { if (intVal == uint.Parse(sselem.options[k + 1])) { strDesc = sselem.options[k]; } } } else if (hasFlags) { uint intVal = Convert.ToUInt32(value); var tmp2 = new StringBuilder(); for (int k = 0; k < sselem.flags.Length; k++) { if ((intVal & (1 << k)) != 0) { if (tmp2.Length > 0) { tmp2.Append(", "); } tmp2.Append(sselem.flags[k]); } } strDesc = tmp2.ToString(); } } break; case ElementValueType.Str4: strValue = TypeConverter.GetString(elem.Data); break; case ElementValueType.BString: strValue = TypeConverter.GetBString(elem.Data); break; case ElementValueType.IString: strValue = TypeConverter.GetIString(elem.Data); break; default: strValue = value == null ? string.Empty : value.ToString(); break; } // Now create row and fill in cells using (IRTFRow ie = s.CreateRow(rd, cds)) { int colIdx = 0; IEnumerator <IBuilderContent> ie2 = ie.GetEnumerator(); for (bool ok = ie2.MoveNext(); ok; ok = ie2.MoveNext(), ++colIdx) { using (var item = ie2.Current) { var rb = item.Content; if (colIdx == 0) { // name rb.FontStyle(FontStyle.Bold).Append(sselem.name); } else if (colIdx == 1) { // value switch (sselem.type) { case ElementValueType.FormID: if (((uint)value) == 0) { rb.Append(strValue); } else if (record != null) { RTFRenderer.AppendLink(rb, strValue, record.GetLink()); } else if (!string.IsNullOrEmpty(sselem.FormIDType)) { RTFRenderer.AppendLink(rb, strValue, string.Format("{0}:{1}", sselem.FormIDType, strValue)); } else { RTFRenderer.AppendLink(rb, strValue, string.Format("XXXX:{0}", strValue)); } break; default: rb.Append(strValue); break; } } else if (colIdx == 2) { // desc if (!string.IsNullOrEmpty(strDesc)) { rb.Append(strDesc); } } else if (colIdx == 3) { // desc2 if (!string.IsNullOrEmpty(strDesc2)) { rb.Append(strDesc2); } } } } } } } catch { s.AppendLine("Warning: Subrecord doesn't seem to match the expected structure"); } finally { if (addTerminatingParagraph) { s.Reset(); s.AppendPara(); } } }