/// <summary> /// ReadPlugInRecordsSubRecords /// </summary> /// <param name="groupRec"></param> /// <param name="onlyReadRecord"></param> /// <param name="filtersRecords"></param> /// <param name="onlyTargetStrings"></param> private void ReadWritePlugInRecordsSubRecords(ref TESVSnip.GroupRecord groupRec, bool onlyReadRecord, bool filtersRecords, bool onlyTargetStrings, bool updateStringsPlugIn) { TESVSnip.Record record; DataRow row; bool translateRecord = false; bool continueProcessString = false; string groupName = String.Empty; string editorID = String.Empty; string itemDesc = String.Empty; string stringID = String.Empty; string recType = String.Empty; string recTypeTH = String.Empty; string stringType = String.Empty; string formIDHexa = String.Empty; TESVSnip.ElementValueType valueType; TESVSnip.GroupRecord groupRecRecursive; int countUpdatedRecords = 0; DataView dvPlugInFormIDHexa = null; DataRowView[] foundRows; //Counter for duplicate subrecord in same item int subRecord_ITXT_Counter = 0; int subRecord_NNAM_Counter = 0; int subRecord_CNAM_Counter = 0; int subRecord_DNAM_Counter = 0; int subRecord_TNAM_Counter = 0; int subRecord_PFO2_Counter = 0; int subRecord_ALFD_Counter = 0; int subRecord_FNAM_ounter = 0; int subRecord_WNAM_Counter = 0; int subRecord_BPTN_Counter = 0; int subRecord_EPF2_Counter = 0; int subRecord_RPLI_Counter = 0; int subRecord_PNAM_Counter = 0; int pos = groupRec.DescriptiveName.IndexOf("("); if (pos > 1) groupName = groupRec.DescriptiveName.Substring(pos).Trim().Replace("(", "").Replace(")", ""); else groupName = groupRec.DescriptiveName; //edtMemo.Text += Environment.NewLine + groupName; if (updateStringsPlugIn) { dvPlugInFormIDHexa = new DataView(); dvPlugInFormIDHexa.Table = tblPlugInStringsProject; dvPlugInFormIDHexa.Sort = "GroupName, FormIDHexa, RecordTypeTH"; } try { for (int recordCounter = 0; recordCounter < groupRec.Records.Count; recordCounter++) { if (groupRec.Records[recordCounter].GetType().FullName == "TESVSnip.GroupRecord") { groupRecRecursive = (TESVSnip.GroupRecord)groupRec.Records[recordCounter]; ReadWritePlugInRecordsSubRecords(ref groupRecRecursive, onlyReadRecord, filtersRecords, onlyTargetStrings, updateStringsPlugIn); } if (groupRec.Records[recordCounter].GetType().FullName == "TESVSnip.Record") //test if TESVSnip record { record = (TESVSnip.Record)groupRec.Records[recordCounter]; this.MainViewTH.UpdateMainTextForTH(record); bool matchRecordOK = record.MatchRecordStructureToRecord(); itemDesc = String.Empty; stringID = String.Empty; subRecord_ITXT_Counter = 0; subRecord_NNAM_Counter = 0; subRecord_CNAM_Counter = 0; subRecord_DNAM_Counter = 0; subRecord_TNAM_Counter = 0; subRecord_PFO2_Counter = 0; subRecord_ALFD_Counter = 0; subRecord_FNAM_ounter = 0; subRecord_WNAM_Counter = 0; subRecord_BPTN_Counter = 0; subRecord_EPF2_Counter = 0; subRecord_RPLI_Counter = 0; subRecord_PNAM_Counter = 0; editorID = String.Empty; itemDesc = String.Empty; stringID = String.Empty; recType = String.Empty; stringType = String.Empty; //if (record.FormID.ToString().ToLower() == "16855720") // stringType = String.Empty; foreach (var subRec in record.SubRecords) { if (subRec.Size > 1) { #region FORCED FILTER RECORD continueProcessString = true; if (subRec.Name == "PHWT") continueProcessString = false; #endregion #region EDID if (subRec.Name == "EDID" & continueProcessString) { editorID = subRec.GetStrData(); //edtMemo.Text += Environment.NewLine + " *** EDID:" + editorID + " Match:" + matchRecordOK.ToString(); } #endregion EDID #region OTHER if (subRec.Name != "EDID" & continueProcessString) { itemDesc = String.Empty; stringID = String.Empty; recType = String.Empty; stringType = String.Empty; continueProcessString = false; translateRecord = true; //if (subRec.Name == "NAM1" & subRec.Size >= 4)//RDMP RNAM MOD2 // translateRecord = true; if (matchRecordOK) { valueType = subRec.Structure.elements[0].type; if (valueType == TESVSnip.ElementValueType.LString) continueProcessString = true; if (valueType == TESVSnip.ElementValueType.Blob) continueProcessString = true; if (valueType == TESVSnip.ElementValueType.FormID) continueProcessString = false; } if (subRec.Size < 4) continueProcessString = false; if (continueProcessString) { if (subRec.Name == "ALFD") { subRecord_ALFD_Counter++; } if (subRec.Name == "BPTN") { subRecord_BPTN_Counter++; } if (subRec.Name == "CNAM") { subRecord_CNAM_Counter++; } if (subRec.Name == "EPF2") { subRecord_EPF2_Counter++; } if (subRec.Name == "FNAM") { subRecord_FNAM_ounter++; } if (subRec.Name == "ITXT") { subRecord_ITXT_Counter++; } if (subRec.Name == "NNAM") { subRecord_NNAM_Counter++; } if (subRec.Name == "PFO2") { subRecord_PFO2_Counter++; } if (subRec.Name == "DNAM") { subRecord_DNAM_Counter++; } if (subRec.Name == "TNAM") { subRecord_TNAM_Counter++; } if (subRec.Name == "RPLI") { subRecord_RPLI_Counter++; } if (subRec.Name == "WNAM") { subRecord_WNAM_Counter++; } if (subRec.Name == "PNAM") { subRecord_PNAM_Counter++; } ArraySegment<byte> dataSegment = new ArraySegment<byte>(subRec.GetData(), 0x00, (int)subRec.Size); bool isString = TypeConverter.IsLikelyString(dataSegment); string itemDescTemp = String.Empty; string stringIDTemp = String.Empty; if (isString) { if (subRec.Size == 4) { // Is Text or String ID ? Read all SetTextByID(dataSegment, ref itemDesc, ref stringID); SetTextAsString(dataSegment, ref itemDescTemp, ref stringIDTemp); itemDesc = itemDescTemp; } else SetTextAsString(dataSegment, ref itemDesc, ref stringID); } else if (subRec.Size > 4) { if (subRec.Name == "FULL" | subRec.Name == "DESC") SetTextAsString(dataSegment, ref itemDesc, ref stringID); //else // SetTextByID(dataSegment, ref itemDesc, ref stringID); } else { SetTextAsString(dataSegment, ref itemDescTemp, ref stringID); SetTextByID(dataSegment, ref itemDesc, ref stringID); if (itemDescTemp.Length <= 0) itemDesc = String.Empty; else if (itemDescTemp.Length >= 1) if (itemDescTemp[0] == '\0') { itemDesc = String.Empty; stringID = "00000000"; } //don't translate } translateRecord = true; if (filtersRecords) //filtersRecords=true for not populate listview for translation, filtersRecords=false it's only for generate dictionnary with full strings { if (subRec.Name == "FULL" | subRec.Name == "DESC") if (editorID == itemDesc) //do not translate if EDID:"ArmorAtronachFrostShield" = FULL:"ArmorAtronachFrostShield" translateRecord = false; } if (stringID == "00000001") translateRecord = false; if (stringID == "00000000" & itemDesc == String.Empty) translateRecord = false; if (itemDesc.Length >= 3) if (itemDesc.Substring(0, 3) == "...") translateRecord = false; if (translateRecord) if ((!String.IsNullOrEmpty(itemDesc)) | (!String.IsNullOrEmpty(stringID))) { //edtMemo.Text += Environment.NewLine + " * " + subRec.Name + ":" + " ContinueProcessstring:" + continueProcessString.ToString(); recType = subRec.Name; recTypeTH = subRec.Name; if (subRec.Name == "ALFD") recTypeTH = recType + ":" + subRecord_ALFD_Counter.ToString(); if (subRec.Name == "BPTN") recTypeTH = recType + ":" + subRecord_BPTN_Counter.ToString(); if (subRec.Name == "CNAM") recTypeTH = recType + ":" + subRecord_CNAM_Counter.ToString(); if (subRec.Name == "EPF2") recTypeTH = recType + ":" + subRecord_EPF2_Counter.ToString(); if (subRec.Name == "FNAM") recTypeTH = recType + ":" + subRecord_FNAM_ounter.ToString(); if (subRec.Name == "ITXT") recTypeTH = recType + ":" + subRecord_ITXT_Counter.ToString(); if (subRec.Name == "NNAM") recTypeTH = recType + ":" + subRecord_NNAM_Counter.ToString(); if (subRec.Name == "PFO2") recTypeTH = recType + ":" + subRecord_PFO2_Counter.ToString(); if (subRec.Name == "DNAM") recTypeTH = recType + ":" + subRecord_DNAM_Counter.ToString(); if (subRec.Name == "TNAM") recTypeTH = recType + ":" + subRecord_TNAM_Counter.ToString(); if (subRec.Name == "RPLI") recTypeTH = recType + ":" + subRecord_RPLI_Counter.ToString(); if (subRec.Name == "WNAM") recTypeTH = recType + ":" + subRecord_WNAM_Counter.ToString(); if (subRec.Name == "PNAM") recTypeTH = recType + ":" + subRecord_PNAM_Counter.ToString(); //if (recTypeTH=="PNAM:43") // recTypeTH = recType + ":" + subRecord_PNAM_Counter.ToString(); if (!updateStringsPlugIn) { row = tblPlugInStringsLoad.NewRow(); row["GroupName"] = groupName; row["RecordType"] = recType; row["RecordTypeTH"] = recTypeTH; row["StringType"] = GetDefaultStringType(recType); //default- good string type is given by UpdateProjectStrings(...) row["FormID"] = record.FormID; row["FormIDHexa"] = record.FormID.ToString("x8").ToUpperInvariant(); row["EditorID"] = editorID; row["SourceStringID"] = Convert.ToUInt32(stringID, 16); row["SourceStringIDHexa"] = stringID.ToUpperInvariant(); //row["SourceItemDesc"] = itemDesc.Replace("[", "").Replace("]", ""); row["SourceItemDesc"] = itemDesc; row["StringStatus"] = "?"; tblPlugInStringsLoad.Rows.Add(row); } if (updateStringsPlugIn) { formIDHexa = record.FormID.ToString("x8").ToUpperInvariant(); foundRows = dvPlugInFormIDHexa.FindRows(new object[] { groupName, formIDHexa, recTypeTH }); if (foundRows.Length == 1) { //this.MainViewTH.UpdateMainTextByTH(subRec); if (Convert.ToBoolean(foundRows[0]["WriteStringInPlugIn"])) { if (!String.IsNullOrEmpty(Convert.ToString(foundRows[0]["TargetItemDesc"]).Trim())) { byte[] itemName = TypeConverter.str2h(Convert.ToString(foundRows[0]["TargetItemDesc"])); subRec.SetData(itemName); countUpdatedRecords++; //this.MainViewTH.UpdateMainTextByTH(subRec); edtMemo.Text += Environment.NewLine + groupName + ": " + formIDHexa + " - " + recTypeTH; } } } } } } } #endregion OTHER } } } } totalRecordsWritingToplugIn += countUpdatedRecords; } catch (Exception ex) { edtMemo.Text += Environment.NewLine + "****** ERROR in ReadPlugInRecordsSubRecords ******" + ex.Message + Environment.NewLine + ex.Source + Environment.NewLine + ex.StackTrace; } }
internal GroupRecord(uint Size, BinaryReader br, TESVSnip.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)); } }
public void Process(TESVSnip.Data.Subrecord sr, SubRecord subrec) { TESVSnip.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; TESVSnip.Data.SubrecordElement elem = new TESVSnip.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) { TESVSnip.Data.SubrecordElement elem = new TESVSnip.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) { TESVSnip.Data.SubrecordElement elem = new TESVSnip.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) { TESVSnip.Data.SubrecordElement elem = new TESVSnip.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) { TESVSnip.Data.SubrecordElement elem = new TESVSnip.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) { TESVSnip.Data.SubrecordElement elem = new TESVSnip.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) { TESVSnip.Data.SubrecordElement elem = new TESVSnip.Data.SubrecordElement(); elem.name = "Unknown"; elem.type = "short"; elem.size = 2; sr.Elements.Add(elem); sr.Elements.Add(elem); } else { TESVSnip.Data.SubrecordElement elem = new TESVSnip.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 Record(string name, uint dataSize, BinaryReader recordReader, TESVSnip.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; }