internal Record(string name, uint dataSize, BinaryReader recordReader, FalloutSnip.Domain.Data.DomainDefinition define) { this.dataSize = dataSize; int estimatedCount = Math.Max( Math.Min(16, (int)dataSize/10), 0 ); SubRecords = new AdvancedList<SubRecord>(estimatedCount) { AllowSorting = false }; Name = name; Flags1 = recordReader.ReadUInt32(); FormID = recordReader.ReadUInt32(); if (define.RecSize >= 12) Flags2 = recordReader.ReadUInt32(); if (define.RecSize >= 16) Flags3 = recordReader.ReadUInt32(); bool compressed = (Flags1 & 0x00040000) != 0; uint amountRead = 0; uint realSize = dataSize; if (compressed) { realSize = recordReader.ReadUInt32(); dataSize -= 4; } using (var stream = new MemoryStream(recordReader.ReadBytes((int)dataSize),false)) using (var br = new BinaryReader(stream)) { var dataReader = compressed ? Decompressor.Decompress(br, (int)dataSize, (int)realSize, out compressLevel) : br; { while (true) { long left = dataReader.BaseStream.Length - dataReader.BaseStream.Position; if (left < 4) { break; } string type = ReadRecName(dataReader); uint size; if (type == "XXXX") { dataReader.ReadUInt16(); size = dataReader.ReadUInt32(); type = ReadRecName(dataReader); dataReader.ReadUInt16(); } else { size = define.HEDRRecSize == 2 ? dataReader.ReadUInt16() : dataReader.ReadUInt32(); } var record = new SubRecord(this, type, dataReader, size); SubRecords.Add(record); amountRead += (uint)record.Size2; } } } if (amountRead > realSize) { Debug.Print( " * ERROR: SUB-RECORD {0} DATA DOESN'T MATCH THE SIZE SPECIFIED IN THE HEADER: DATA-SIZE={1} REAL-SIZE={2} AMOUNT-READ={3}", name, dataSize, realSize, amountRead); throw new TESParserException( string.Format( "Subrecord block did not match the size specified in the record header: ExpectedSize={0} ReadSize={1} DataSize={2}", realSize, amountRead, dataSize)); } descNameOverride = DefaultDescriptiveName; UpdateShortDescription(); // br.BaseStream.Position+=Size; }
public void Process(FalloutSnip.Data.Subrecord sr, SubRecord subrec) { FalloutSnip.Data.SubrecordElement expectedElement = (sr.Elements.Count >= 1) ? sr.Elements[0] : null; if (expectedElement != null && expectedElement.type == "blob") return; byte[] data = subrec.GetReadonlyData(); if (data.Length == 0) { if (sr.Elements.Count == 0) sr.Elements.Add(CreateBlob()); return; } if (data.Length == 2) { // common scenarios if (expectedElement != null && expectedElement.size == 2) return; FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "short"; elem.size = 2; sr.Elements.Add(elem); UpdateSize(sr); return; } if (data.Length > 0) { bool isAscii = true; for (int i = 0; i < data.Length - 1 && isAscii; ++i) isAscii = !Char.IsControl((char)data[i]); isAscii = (isAscii && data[data.Length - 1] == 0); if (isAscii) { // test if its a string if (expectedElement == null) { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "string"; sr.Elements.Add(elem); } else if (expectedElement.type != "string") { sr.Elements.Clear(); sr.Elements.Add(CreateBlob()); } return; } } for (int offset = 0, elemSize = 4; offset < data.Length; offset += elemSize) { if (IsCanceled) return; int left = data.Length - offset; if (left >= 4) { // common scenarios if (expectedElement != null && expectedElement.size == 4) continue; ushort lhs = TypeConverter.h2s(data[offset], data[offset + 1]); ushort uhs = TypeConverter.h2s(data[offset + 2], data[offset + 3]); uint ui4 = TypeConverter.h2i(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); if (ui4 == 0) { if (expectedElement == null) { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "int"; elem.size = 4; sr.Elements.Add(elem); UpdateSize(sr); continue; } } else { float flt = TypeConverter.h2f(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]); if (IsLikelyFloat(flt)) { // replace element which is int with float if (expectedElement == null) { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "float"; elem.size = 4; sr.Elements.Add(elem); } else { if (expectedElement.type == "int") expectedElement.type = "float"; } continue; } else { Record r = this.FormLookup(ui4); if (r != null) { string reftype = r.DescriptiveName.Substring(0, 4); // ??? if (expectedElement == null) { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "ID"; elem.type = "formid"; elem.reftype = reftype; elem.size = 4; sr.Elements.Add(elem); } else { if (expectedElement.type == "formid") { if (expectedElement.reftype != reftype) expectedElement.reftype = string.Empty; } } continue; } else { string s = this.StringLookup(ui4); if (!string.IsNullOrEmpty(s)) { if (expectedElement == null) { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "string"; sr.Elements.Add(elem); } continue; } } if (expectedElement == null) { if (lhs > 0 && lhs < 255 && uhs > 0 && uhs < 255) { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "short"; elem.size = 2; sr.Elements.Add(elem); sr.Elements.Add(elem); } else { FalloutSnip.Data.SubrecordElement elem = new FalloutSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "int"; elem.size = 4; sr.Elements.Add(elem); UpdateSize(sr); } } } } } } if (sr.Elements.Count == 0) { sr.Elements.Add(CreateBlob()); } UpdateSize(sr); }
internal GroupRecord(uint Size, BinaryReader br, FalloutSnip.Domain.Data.DomainDefinition define, Func<string, bool> recFilter, bool filterAll) { Name = "GRUP"; this.data = br.ReadBytes(4); this.groupType = br.ReadUInt32(); this.dateStamp = br.ReadUInt32(); string contentType = this.groupType == 0 ? Encoding.Instance.GetString(this.data) : string.Empty; if (define.RecSize >= 16) { this.flags = br.ReadUInt32(); } uint amountRead = 0; while (amountRead < Size - (define.RecSize+8)) { string s = ReadRecName(br); uint recsize = br.ReadUInt32(); if (s == "GRUP") { try { bool skip = filterAll || (recFilter != null && !recFilter(contentType)); var gr = new GroupRecord(recsize, br, define, recFilter, skip); if (!filterAll) { this.AddRecord(gr); } } catch (Exception e) { Alerts.Show(e.Message); } finally { amountRead += recsize; } } else { bool skip = filterAll || (recFilter != null && !recFilter(contentType)); if (skip) { long size = recsize + define.RecSize; // if ((br.ReadUInt32() & 0x00040000) > 0) size += 4; br.BaseStream.Position += size; // just read past the data amountRead += (uint)(recsize + (define.RecSize+8)); } else { try { var r = new Record(s, recsize, br, define); this.AddRecord(r); } catch (Exception e) { Alerts.Show(e.Message); } finally { amountRead += (uint)(recsize + (define.RecSize+8)); } } } } this.UpdateShortDescription(); if (amountRead != (Size - (define.RecSize+8))) { throw new TESParserException( string.Format("Record block did not match the size specified in the group header! Header Size={0:D} Group Size={1:D}", Size - (define.RecSize+8), amountRead)); } }