/// <summary> /// Extracts a color from binary span. /// If the span more than 3 bytes, the 4th byte will be interpreted as alpha. /// Will throw an exception if there is not at least 3 bytes. /// </summary> /// <param name="span">Span to read from</param> /// <param name="binaryType">Format to read the color as</param> /// <returns>Bytes converted to a Color object</returns> public static Color ReadColor(this ReadOnlyMemorySlice <byte> span, ColorBinaryType binaryType) { return(span.Span.ReadColor(binaryType)); }
public static sbyte Int8(this ReadOnlyMemorySlice <byte> span) { return((sbyte)span[0]); }
public static int Int32(this ReadOnlyMemorySlice <byte> span) { return(BinaryPrimitives.ReadInt32LittleEndian(span)); }
public static float Float(this ReadOnlyMemorySlice <byte> span) => BinaryPrimitives.ReadSingleLittleEndian(span);
public static string StringUTF8(this ReadOnlyMemorySlice <byte> span) => span.Span.StringUTF8();
private void ParseRegionData(OverlayStream stream, int offset) { int loc = stream.Position - offset; var rdatFrame = stream.ReadSubrecordFrame(); RegionData.RegionDataType dataType = (RegionData.RegionDataType)BinaryPrimitives.ReadUInt32LittleEndian(rdatFrame.Content); var len = rdatFrame.TotalLength; if (!stream.Complete) { var contentMeta = stream.GetSubrecord(); var recType = contentMeta.RecordType; if (recType == RecordTypes.ICON) { var totalLen = contentMeta.TotalLength; len += totalLen; // Skip icon subrecord for now contentMeta = stream.GetSubrecord(offset: rdatFrame.TotalLength + totalLen); } if (RegionBinaryCreateTranslation.IsExpected(dataType, contentMeta.RecordType)) { len += contentMeta.TotalLength; stream.Position += contentMeta.TotalLength; } } switch (dataType) { case RegionData.RegionDataType.Object: _ObjectsSpan = this._data.Slice(loc, len); break; case RegionData.RegionDataType.Map: _MapSpan = this._data.Slice(loc, len); break; case RegionData.RegionDataType.Grass: _GrassesSpan = this._data.Slice(loc, len); break; case RegionData.RegionDataType.Land: _LandSpan = this._data.Slice(loc, len); break; case RegionData.RegionDataType.Sound: if (stream.TryGetSubrecord(out var nextRec) && (nextRec.RecordType.Equals(RegionBinaryCreateTranslation.RDSA) || nextRec.RecordType.Equals(RegionBinaryCreateTranslation.RDMO))) { len += nextRec.TotalLength; } _SoundsSpan = this._data.Slice(loc, len); break; case RegionData.RegionDataType.Weather: _WeatherSpan = this._data.Slice(loc, len); break; default: throw new NotImplementedException(); } }
private static void AlignWorldChildren( IMutagenReadStream reader, MutagenWriter writer) { reader.WriteTo(writer.BaseStream, 4); ReadOnlyMemorySlice <byte>?roadStorage = null; ReadOnlyMemorySlice <byte>?cellStorage = null; var grupBytes = new List <ReadOnlyMemorySlice <byte> >(); for (int i = 0; i < 3; i++) { MajorRecordHeader majorMeta = reader.GetMajorRecord(); switch (majorMeta.RecordType.Type) { case "ROAD": roadStorage = reader.ReadMemory(checked ((int)majorMeta.TotalLength)); break; case "CELL": if (cellStorage != null) { throw new ArgumentException(); } var startPos = reader.Position; var cellMeta = reader.GetMajorRecord(); reader.Position += cellMeta.TotalLength; var cellGroupMeta = reader.GetGroup(); long cellGrupLen; if (cellGroupMeta.IsGroup && cellGroupMeta.GroupType == (int)GroupTypeEnum.CellChildren) { cellGrupLen = cellGroupMeta.TotalLength; } else { cellGrupLen = 0; } reader.Position = startPos; cellStorage = reader.ReadMemory(checked ((int)(cellMeta.TotalLength + cellGrupLen))); break; case "GRUP": if (roadStorage != null && cellStorage != null) { i = 3; // end loop continue; } var groupMeta = reader.GetGroup(); grupBytes.Add(reader.ReadMemory(checked ((int)groupMeta.TotalLength))); break; case "WRLD": i = 3; // end loop continue; default: throw new NotImplementedException(); } } if (roadStorage != null) { writer.Write(roadStorage.Value); } if (cellStorage != null) { writer.Write(cellStorage.Value); } foreach (var item in grupBytes) { writer.Write(item); } }
public GroupHeader Group(ReadOnlyMemorySlice <byte> span) => new GroupHeader(this, span);
public GroupFrame GroupFrame(ReadOnlyMemorySlice <byte> span) => new GroupFrame(this, span);
/// <summary> /// Constructor /// </summary> /// <param name="meta">Game metadata to use as reference for alignment</param> /// <param name="span">Span to overlay on, aligned to the start of the Group's header</param> public ModHeader(GameConstants meta, ReadOnlyMemorySlice <byte> span) { this.Meta = meta; this.Span = span.Slice(0, meta.ModHeaderLength); }
public ModHeader ModHeader(ReadOnlyMemorySlice <byte> span) => new ModHeader(this, span);
/// <summary> /// Constructor /// </summary> /// <param name="constants">Record constants to use as reference for alignment</param> /// <param name="span">Span to overlay on, aligned to the start of the header</param> public VariableHeader(RecordHeaderConstants constants, ReadOnlyMemorySlice <byte> span) { this.Constants = constants; this.Span = span.Slice(0, constants.HeaderLength); }
public NumberedEnumList(ReadOnlyMemorySlice <byte> mem, int amount, byte enumLength) { this.Amount = amount; this.Memory = mem; this.EnumLength = enumLength; }
/// <summary> /// Constructor /// </summary> /// <param name="meta">Game metadata to use as reference for alignment</param> /// <param name="span">Span to overlay on, aligned to the start of the Major Record's header</param> public MajorRecordHeader(GameConstants meta, ReadOnlyMemorySlice <byte> span) { this.Meta = meta; this.HeaderData = span.Slice(0, meta.MajorConstants.HeaderLength); }
public static ReadOnlyMemorySlice <byte> ExtractSubrecordMemory(ReadOnlyMemorySlice <byte> span, int loc, GameConstants meta) { var subMeta = meta.Subrecord(span.Slice(loc)); return(span.Slice(loc + subMeta.HeaderLength, subMeta.ContentLength)); }
public MajorRecordHeader MajorRecord(ReadOnlyMemorySlice <byte> span) => new MajorRecordHeader(this, span);
public static ReadOnlyMemorySlice <byte> ExtractSubrecordMemory(ReadOnlyMemorySlice <byte> span, GameConstants meta, TypedParseParams?parseParams = null) { var subMeta = meta.Subrecord(span); return(span.Slice(subMeta.HeaderLength, parseParams?.LengthOverride ?? subMeta.ContentLength)); }
public MajorRecordFrame MajorRecordFrame(ReadOnlyMemorySlice <byte> span) => new MajorRecordFrame(this, span);
private static void AlignMajorRecordsByRules( IMutagenReadStream inputStream, MutagenWriter writer, AlignmentRules alignmentRules, RecordLocator.FileLocations fileLocs) { while (!inputStream.Complete) { // Import until next listed major record long noRecordLength; if (fileLocs.ListedRecords.TryGetInDirection( inputStream.Position, higher: true, result: out var nextRec)) { var recordLocation = fileLocs.ListedRecords.Keys[nextRec.Key]; noRecordLength = recordLocation - inputStream.Position; } else { noRecordLength = inputStream.Remaining; } inputStream.WriteTo(writer.BaseStream, (int)noRecordLength); // If complete overall, return if (inputStream.Complete) { break; } var recType = HeaderTranslation.ReadNextRecordType( inputStream, out var len); IEnumerable <RecordType>?stopMarkers; if (!alignmentRules.StopMarkers.TryGetValue(recType, out stopMarkers)) { stopMarkers = null; } if (!alignmentRules.Alignments.TryGetValue(recType, out var alignments)) { throw new ArgumentException($"Encountered an unknown record: {recType}"); } writer.Write(recType.TypeInt); writer.Write(len); inputStream.WriteTo(writer.BaseStream, 12); var endPos = inputStream.Position + len; Dictionary <RecordType, byte[]> dataDict = new Dictionary <RecordType, byte[]>(); ReadOnlyMemorySlice <byte>? rest = null; while (inputStream.Position < endPos) { var subType = HeaderTranslation.GetNextSubrecordType( inputStream, out var subLen); if (stopMarkers?.Contains(subType) ?? false) { rest = inputStream.ReadMemory((int)(endPos - inputStream.Position), readSafe: true); break; } if (!alignments.TryGetValue(subType, out var rule)) { throw new ArgumentException($"Encountered an unknown record: {subType}"); } dataDict[subType] = rule.GetBytes(inputStream); } foreach (var alignment in alignmentRules.Alignments[recType]) { if (dataDict.TryGetValue( alignment.Key, out var data)) { writer.Write(data); dataDict.Remove(alignment.Key); } } if (dataDict.Count > 0) { throw new ArgumentException($"Encountered an unknown record: {dataDict.First().Key}"); } if (rest != null) { writer.Write(rest.Value); } } }
public SubrecordHeader Subrecord(ReadOnlyMemorySlice <byte> span) => new SubrecordHeader(this, span);
/// <summary> /// Parses span data and enumerates pairs of record type -> locations /// /// It is assumed the span contains only subrecords /// </summary> /// <param name="span">Bytes containing subrecords</param> /// <param name="meta">Metadata to use in subrecord parsing</param> /// <returns>Enumerable of KeyValue pairs of encountered RecordTypes and their locations relative to the input span</returns> public static IEnumerable <KeyValuePair <RecordType, int> > EnumerateSubrecords(ReadOnlyMemorySlice <byte> span, GameConstants meta) { int loc = 0; while (span.Length > loc) { var subMeta = meta.Subrecord(span.Slice(loc)); var len = subMeta.TotalLength; yield return(new KeyValuePair <RecordType, int>(subMeta.RecordType, loc)); loc += len; } }
public SubrecordFrame SubrecordFrame(ReadOnlyMemorySlice <byte> span) => new SubrecordFrame(this, span);
public static double Double(this ReadOnlyMemorySlice <byte> span) => BinaryPrimitives.ReadDoubleLittleEndian(span);
/// <summary> /// Constructor /// </summary> /// <param name="meta">Game metadata to use as reference for alignment</param> /// <param name="span">Span to overlay on, aligned to the start of the header</param> public GroupFrame(GameConstants meta, ReadOnlyMemorySlice <byte> span) { this._header = meta.Group(span); this.HeaderAndContentData = span.Slice(0, checked ((int)this._header.TotalLength)); }
public static byte UInt8(this ReadOnlyMemorySlice <byte> span) { return(span[0]); }
/// <summary> /// Constructor /// </summary> /// <param name="header">Existing GroupHeader struct</param> /// <param name="span">Span to overlay on, aligned to the start of the Group's header</param> public GroupFrame(GroupHeader header, ReadOnlyMemorySlice <byte> span) { this._header = header; this.HeaderAndContentData = span.Slice(0, checked ((int)this._header.TotalLength)); }
public static ushort UInt16(this ReadOnlyMemorySlice <byte> span) { return(BinaryPrimitives.ReadUInt16LittleEndian(span)); }
/// <summary> /// Constructor /// </summary> /// <param name="meta">Game metadata to use as reference for alignment</param> /// <param name="span">Span to overlay on, aligned to the start of the Group's header</param> public GroupHeader(GameConstants meta, ReadOnlyMemorySlice <byte> span) { this.Meta = meta; this.HeaderData = span.Slice(0, meta.GroupConstants.HeaderLength); }
public static ulong UInt64(this ReadOnlyMemorySlice <byte> span) { return(BinaryPrimitives.ReadUInt64LittleEndian(span)); }
public VariableHeader VariableMeta(ReadOnlyMemorySlice <byte> span) => new VariableHeader(this, span);