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;
        }
Example #2
0
        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;
                }

                var data = ss.GetReadonlyData();
                if (IsLikelyString(new ArraySegment<byte>(data, 0, (int) ss.Size)))
                {
                    if (++szCount > 10)
                    {
                        var elem = CreateType(null, "string");
                        sr.Items.Add(elem);
                        break;
                    }
                }
                else
                {
                    break;
                }
            }

            if (sr.Elements.Any())
            {
                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.Items.Add(elem);
                            elemSize = 2;
                            continue;
                        }
                        else
                        {
                            var elem = CreateType(index++, "byte");
                            elem.size = 1;
                            sr.Items.Add(elem);
                            elemSize = 1;
                            continue;
                        }
                    }

                    foreach (var ss in srs)
                    {
                        // .Random(srs.Length < 10 ? 0 : srs.Length / 10)
                        ++numTotal;
                        var 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)
                        {
                            var 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.Items.Add(elem);
                        }
                        else if (num2Short > 0 && shortPct > 0.5f)
                        {
                            var elem = CreateType(index++, "short");
                            elem.size = 2;
                            sr.Items.Add(elem);
                            sr.Items.Add(elem);
                            UpdateSize(sr);
                        }
                        else if (isFormID > 0 && formPct > 0.5f)
                        {
                            var elem = CreateType(index++, "formid");
                            elem.reftype = reftype;
                            elem.size = 4;
                            sr.Items.Add(elem);
                        }
                        else if (isLString > 0 && lstrPct > 0.5f)
                        {
                            var elem = CreateType(index++, "lstring");
                            elem.size = 4;
                            sr.Items.Add(elem);
                        }
                        else
                        {
                            var elem = CreateType(index++, "int");
                            elem.size = 4;
                            sr.Items.Add(elem);
                        }
                    }
                }
            }
            else
            {
                // guess dynamically sized object... default to blob
                if (!sr.Elements.Any())
                {
                    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)
                        {
                            var data = ss.GetReadonlyData();
                            int offset = 0;
                            uint ui4 = GetUInt32(data, offset);
                            if (ui4 < 100)
                            {
                                continue;
                            }

                            var 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.Items.Add(elem);
                        }
                    }
                }

                // check if it is a string else make it a blob
                sr.size = 0;

                if (!sr.Elements.Any())
                {
                    sr.Items.Add(CreateBlob());
                }
            }
        }
Example #3
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;

                var 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;
        }
Example #4
0
        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();
            }
        }
Example #5
0
 public void UpdateSize(Subrecord sr)
 {
     sr.size = 0;
     foreach (var sre in sr.Elements)
     {
         sr.size += sre.size;
     }
 }