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); }
internal static unsafe ulong GenHash(MArrayPosition <byte> str, bool isFolder) { fixed(byte *ptr = &str.Array[str.Offset]) { return(GenHash(ptr, isFolder)); } }
public static BethesdaFile Save(Record root) { FinalizeHeader(root); byte[] rec = new byte[CalculateSize(root, true)]; MArrayPosition <byte> pos = new MArrayPosition <byte>(rec); var(record, subgroups) = Write(root, ref pos); return(new BethesdaFile(record, subgroups)); }
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); }
private static (BethesdaRecord record, BethesdaGroup[] subgroups) Write(Record record, ref MArrayPosition <byte> pos) { var result = default((BethesdaRecord record, BethesdaGroup[] subgroups)); if (record.IsDummy) { goto groups; } result.record = new BethesdaRecord(pos) { RecordType = record.RecordType, DataSize = unchecked ((uint)(CalculateSize(record, false) - 24)), Flags = record.Flags, Id = record.Id, Revision = record.Revision, Version = record.Version, UNKNOWN_22 = record.UNKNOWN_22 }; pos += 24; byte[] payload = record.Flags.HasFlag(BethesdaRecordFlags.Compressed) ? GetCompressedPayload(record) : GetUncompressedPayload(record); int payloadLength = payload.Length; MBuffer.BlockCopy(payload, 0, pos, 0, payloadLength); pos += payloadLength; groups: result.subgroups = new BethesdaGroup[record.Subgroups.Count]; for (int i = 0; i < result.subgroups.Length; i++) { result.subgroups[i] = Write(record.Subgroups[i], ref pos); } return(result); }