private static byte[] GetUncompressedPayload(Record record) { byte[] result = new byte[GetUncompressedPayloadSize(record)]; MArrayPosition <byte> pos = new MArrayPosition <byte>(result); foreach (var field in record.Fields) { int fieldLength = field.Payload.Length; ushort storedFieldLength = unchecked ((ushort)fieldLength); if (fieldLength > UInt16.MaxValue) { MBitConverter.Set(pos, XXXX); pos += 4; MBitConverter.Set(pos, (ushort)4); pos += 2; MBitConverter.Set(pos, fieldLength); pos += 4; storedFieldLength = 0; } MBitConverter.Set(pos, field.FieldType); pos += 4; MBitConverter.Set(pos, storedFieldLength); pos += 2; MBuffer.BlockCopy(field.Payload, 0, pos, 0, fieldLength); pos += fieldLength; } return(result); }
private static bool FieldsAreIdentical(B4S recordType, Field f1, Field f2) { // clear out unused bytes before doing the check. switch (f1.FieldType) { case _CTDA: if (recordType != IDLE) { goto default; } f1 = new Field(f1); f2 = new Field(f2); MBitConverter.Set(f1.Payload, 0, (uint)f1.Payload[0]); MBitConverter.Set(f2.Payload, 0, (uint)f2.Payload[0]); MBitConverter.Set(f1.Payload, 10, (ushort)0); MBitConverter.Set(f2.Payload, 10, (ushort)0); // TODO: ugh, [IDLE:00013344]'s field is apparently allowed // to differ non-trivially. goto default; case _ENAM: if (f1.Payload.LongLength != f2.Payload.LongLength) { return(false); } if (recordType != IDLE) { goto default; } // ENAM is apparently case-insensitive, according to xEdit. f1 = new Field(f1); f2 = new Field(f2); for (long i = 0; i < f1.Payload.LongLength; i++) { f1.Payload[i] = unchecked ((byte)(f1.Payload[i] & 0xDF)); f2.Payload[i] = unchecked ((byte)(f1.Payload[i] & 0xDF)); } goto default; default: return(f1.Payload.SequenceEqual(f2.Payload)); } }
private static byte[] CompressDNAM(byte[] dnamPayload) { MArrayPosition <byte> pos = new MArrayPosition <byte>(dnamPayload); for (int i = 0; i < dnamPayload.Length; i += 8) { ulong val = MBitConverter.To <ulong>(dnamPayload, i); if (val == 0) { continue; } MBitConverter.Set(pos, val); pos += 8; } Array.Resize(ref dnamPayload, pos.Offset); return(dnamPayload); }
private static void FinalizeHeader(Record root) { var onamField = root.Fields.SingleOrDefault(f => f.FieldType == ONAM); if (onamField == null) { goto afterOnam; } HashSet <uint> prevOnams = Doer.GetOnams(root); List <uint> currOnams = new List <uint>(prevOnams.Count); foreach (Record rec in Doer.FindRecords(root)) { if (prevOnams.Remove(rec.Id) && (!rec.Flags.HasFlag(BethesdaRecordFlags.InitiallyDisabled) || !rec.Flags.HasFlag(BethesdaRecordFlags.PersistentReference))) { currOnams.Add(rec.Id); } } uint[] onamsArray = currOnams.ToArray(); Array.Sort(onamsArray); onamField.Payload = new byte[unchecked ((uint)(onamsArray.Length) * 4u)]; MArrayPosition <byte> pos = new MArrayPosition <byte>(onamField.Payload); foreach (uint onam in onamsArray) { MBitConverter.Set(pos, onam); pos += 4; } root.CompressedFieldData = null; afterOnam: MBitConverter.Set(new MArrayPosition <byte>(root.Fields.Single(f => f.FieldType == HEDR).Payload, 4), Doer.CountItems(root) - 1); }
private static BethesdaGroup Write(Group group, ref MArrayPosition <byte> pos) { MBitConverter.Set(pos, GRUP); BethesdaGroup grp = new BethesdaGroup(pos) { DataSize = unchecked ((uint)(CalculateSize(group) - 24)), Label = group.Label, GroupType = group.GroupType, Stamp = group.Stamp, UNKNOWN_18 = group.UNKNOWN_18, Version = group.Version, UNKNOWN_22 = group.UNKNOWN_22 }; pos += 24; foreach (var rec in group.Records) { Write(rec, ref pos); } return(grp); }
// assumes all IDs were deleted by PerformDeletes. public static void PerformUDRs(Record root, Merged master, IEnumerable <uint> ids) { foreach (uint id in ids) { Record orig = master.FindRecord(id); orig = new Record(orig) { Parent = orig.Parent }; orig.Flags |= BethesdaRecordFlags.InitiallyDisabled; if (orig.RecordType == ACHR || orig.RecordType == ACRE) { orig.Flags |= BethesdaRecordFlags.PersistentReference; } if (orig.Flags.HasFlag(BethesdaRecordFlags.PersistentReference) && orig.Parent.GroupType != BethesdaGroupType.CellPersistentChildren) { Record wrldParent = null; // persistent children of the HIGHEST cell in the world while (orig.Parent != null) { Record rrrr = orig.Parent.Parent; if (rrrr.RecordType == WRLD) { wrldParent = rrrr; } orig.Parent = rrrr.Parent; } orig.Parent = wrldParent.Subgroups .Single(g => g.GroupType == BethesdaGroupType.WorldChildren) .Records .Single(r => r.RecordType == CELL) .Subgroups .Single(g => g.GroupType == BethesdaGroupType.CellChildren) .Records .Single() .Subgroups .Single(g => g.GroupType == BethesdaGroupType.CellPersistentChildren); } bool isPersistent = orig.Flags.HasFlag(BethesdaRecordFlags.PersistentReference); if (!isPersistent) { Field dataField = orig.Fields.Find(f => f.FieldType == DATA); if (dataField == null) { orig.Fields.Add(dataField = new Field { FieldType = DATA, Payload = new byte[24] }); } MBitConverter.Set(dataField.Payload, 8, 3337248768); } Field xespField = orig.Fields.Find(f => f.FieldType == XESP); if (xespField == null) { orig.Fields.Add(xespField = new Field { FieldType = XESP, Payload = new byte[8] }); } MBitConverter.Set(xespField.Payload, 0, (uint)0x14); MBitConverter.Set(xespField.Payload, 4, (uint)0x01); orig.CompressedFieldData = null; MergeInto(orig, root); } }