public static int[] FindAllOfSubrecords( ReadOnlySpan <byte> data, GameConstants meta, ICollectionGetter <RecordType> recordTypes, bool navigateToContent = false) { List <int> ret = new List <int>(); int lenParsed = 0; while (data.Length > lenParsed) { var subMeta = meta.Subrecord(data.Slice(lenParsed)); if (recordTypes.Contains(subMeta.RecordType)) { if (navigateToContent) { ret.Add(subMeta.HeaderLength + lenParsed); } else { ret.Add(lenParsed); } } lenParsed += subMeta.TotalLength; } return(ret.ToArray()); }
public IEnumerable <T> Parse( MutagenFrame frame, BinaryMasterParseRecordDelegate <T> transl, ICollectionGetter <RecordType>?triggeringRecord = null, RecordTypeConverter?recordTypeConverter = null) { var ret = new List <T>(); while (!frame.Complete) { var nextRecord = HeaderTranslation.GetNextRecordType(frame.Reader); nextRecord = recordTypeConverter.ConvertToStandard(nextRecord); if (!triggeringRecord?.Contains(nextRecord) ?? false) { break; } if (!IsLoqui) { frame.Position += frame.MetaData.Constants.SubConstants.HeaderLength; } var startingPos = frame.Position; if (transl(frame, nextRecord, out var subIitem, recordTypeConverter)) { ret.Add(subIitem); } if (frame.Position == startingPos) { throw new ArgumentException($"Parsed item on the list consumed no data: {subIitem}"); } } return(ret); }
public IReadOnlyList <T> ParseRepeatedTypelessSubrecord <T>( OverlayStream stream, ICollectionGetter <RecordType> trigger, StreamTypedFactory <T> factory, RecordTypeConverter?recordTypeConverter) { var ret = new List <T>(); while (!stream.Complete) { var subMeta = stream.GetSubrecord(); var recType = subMeta.RecordType; if (!trigger.Contains(recType)) { break; } var minimumFinalPos = stream.Position + subMeta.TotalLength; ret.Add(factory(stream, recType, _package, recordTypeConverter)); if (stream.Position < minimumFinalPos) { stream.Position = minimumFinalPos; } } return(ret); }
public static int[] ParseRecordLocations( OverlayStream stream, ICollectionGetter <RecordType> triggers, RecordHeaderConstants constants, bool skipHeader, RecordTypeConverter?recordTypeConverter = null) { List <int> ret = new List <int>(); var startingPos = stream.Position; while (!stream.Complete) { var varMeta = constants.GetVariableMeta(stream); var recType = recordTypeConverter.ConvertToStandard(varMeta.RecordType); if (!triggers.Contains(recType)) { break; } if (skipHeader) { stream.Position += varMeta.HeaderLength; ret.Add(stream.Position - startingPos); stream.Position += (int)varMeta.RecordLength; } else { ret.Add(stream.Position - startingPos); stream.Position += (int)varMeta.TotalLength; } } return(ret.ToArray()); }
public ExtendedList <T> Parse( MutagenFrame reader, BinarySubParseRecordDelegate <T> transl, ICollectionGetter <RecordType>?triggeringRecord = null) { var ret = new ExtendedList <T>(); while (!reader.Complete) { var nextRecord = HeaderTranslation.GetNextRecordType(reader.Reader); if (!triggeringRecord?.Contains(nextRecord) ?? false) { break; } if (!IsLoqui) { reader.Position += reader.MetaData.Constants.SubConstants.HeaderLength; } var startingPos = reader.Position; if (transl(reader, nextRecord, out var subIitem)) { ret.Add(subIitem); } if (reader.Position == startingPos) { throw new ArgumentException($"Parsed item on the list consumed no data: {subIitem}"); } } return(ret); }
public IReadOnlyList <T> ParseRepeatedTypelessSubrecord <T>( OverlayStream stream, ICollectionGetter <RecordType> trigger, ConverterFactory <T> factory, RecordTypeConverter?recordTypeConverter) { return(ParseRepeatedTypelessSubrecord( stream, trigger, (s, r, p, recConv) => factory(s, p, recConv), recordTypeConverter)); }
/// <summary> /// Finds locations of a number of records given by count that match a set of record types. /// A new location is marked each time a record type that has already been encounterd is seen /// </summary> /// <param name="stream">Stream to read and progress</param> /// <param name="count">Number of expected records</param> /// <param name="trigger">Set of record types expected within one record</param> /// <param name="constants">Metadata for reference</param> /// <param name="skipHeader">Whether to skip the header in the return location values</param> /// <returns>Array of located positions relative to the stream's position at the start</returns> public static int[] ParseRecordLocationsByCount( OverlayStream stream, uint count, ICollectionGetter <RecordType> trigger, RecordHeaderConstants constants, bool skipHeader) { var ret = new List <int>(); var set = new HashSet <RecordType>(); var startingPos = stream.Position; while (!stream.Complete) { var varMeta = constants.GetVariableMeta(stream); var recType = varMeta.RecordType; if (trigger.Contains(recType)) { // If new record type we haven't seen before in our current record, just continue if (set.Add(recType) && ret.Count > 0) { stream.Position += (int)varMeta.TotalLength; continue; } // Otherwise mark as a new record location if (skipHeader) { stream.Position += varMeta.HeaderLength; ret.Add(stream.Position - startingPos); stream.Position += (int)varMeta.RecordLength; } else { ret.Add(stream.Position - startingPos); stream.Position += (int)varMeta.TotalLength; } // Clear set of seen types set.Clear(); set.Add(recType); } else if (ret.Count == count) { break; } else { throw new ArgumentException($"Unexpected record encountered: {recType}. Was expecting: {string.Join(", ", trigger)}"); } } return(ret.ToArray()); }
public static IReadOnlyList <T> FactoryByCountPerItem <T>( OverlayStream stream, BinaryOverlayFactoryPackage package, int countLength, ICollectionGetter <RecordType> subrecordType, RecordType countType, RecordTypeConverter?recordTypeConverter, BinaryOverlay.SpanRecordFactory <T> getter, bool skipHeader = true) { var mem = stream.RemainingMemory; var initialHeader = package.MetaData.Constants.SubrecordFrame(mem); var recType = initialHeader.RecordType; if (recType == countType) { var count = countLength switch { 1 => initialHeader.Content[0], 2 => BinaryPrimitives.ReadUInt16LittleEndian(initialHeader.Content), 4 => BinaryPrimitives.ReadUInt32LittleEndian(initialHeader.Content), _ => throw new NotImplementedException(), }; stream.Position += initialHeader.TotalLength; return(FactoryByArray( mem: stream.RemainingMemory, package: package, recordTypeConverter: recordTypeConverter, getter: getter, locs: BinaryOverlay.ParseRecordLocationsByCount( stream: stream, count: count, trigger: subrecordType, constants: package.MetaData.Constants.SubConstants, skipHeader: false))); } else { return(FactoryByArray( mem: stream.RemainingMemory, package: package, recordTypeConverter: recordTypeConverter, getter: getter, locs: BinaryOverlay.ParseRecordLocations( stream: stream, constants: package.MetaData.Constants.SubConstants, triggers: subrecordType, skipHeader: skipHeader, recordTypeConverter: recordTypeConverter))); } }
public BinaryOverlayListByStartIndexWithRecordSet( ReadOnlyMemorySlice <byte> mem, BinaryOverlayFactoryPackage package, BinaryOverlay.SpanFactory <T> getter, int itemLength, ICollectionGetter <RecordType> recordTypes) { this._mem = mem; this._package = package; this._getter = getter; this._itemLength = itemLength; this._recordTypes = recordTypes; this._totalItemLength = itemLength + this._package.MetaData.Constants.SubConstants.HeaderLength; }
public static IReadOnlyList <T> FactoryByCount <T>( ReadOnlyMemorySlice <byte> mem, BinaryOverlayFactoryPackage package, ICollectionGetter <RecordType> subrecordType, int itemLength, uint count, BinaryOverlay.SpanFactory <T> getter) { if ((mem.Length / (itemLength + package.MetaData.Constants.SubConstants.HeaderLength)) != count) { throw new ArgumentException("Item count and expected size did not match."); } return(new BinaryOverlayListByStartIndexWithRecordSet <T>( mem, package, getter, itemLength, subrecordType)); }
public static int[] ParseRecordLocations( OverlayStream stream, long finalPos, ICollectionGetter <RecordType> triggers, RecordType includeTrigger, RecordHeaderConstants constants, bool skipHeader) { List <int> ret = new List <int>(); var startingPos = stream.Position; while (!stream.Complete && stream.Position < finalPos) { var varMeta = constants.GetVariableMeta(stream); var recType = varMeta.RecordType; var trigger = triggers.Contains(recType); var isIncludeTrigger = recType == includeTrigger; if (!trigger && !isIncludeTrigger) { break; } if (trigger) { if (skipHeader) { stream.Position += varMeta.HeaderLength; ret.Add(stream.Position - startingPos); stream.Position += (int)varMeta.RecordLength; } else { ret.Add(stream.Position - startingPos); stream.Position += (int)varMeta.TotalLength; } } else { stream.Position += (int)varMeta.TotalLength; } } return(ret.ToArray()); }
public static int?FindFirstSubrecord( ReadOnlySpan <byte> data, GameConstants meta, ICollectionGetter <RecordType> recordTypes, bool navigateToContent = false, int?offset = null) { int loc = offset ?? 0; while (data.Length > loc) { var subMeta = meta.Subrecord(data.Slice(loc)); if (recordTypes.Contains(subMeta.RecordType)) { if (navigateToContent) { loc += meta.SubConstants.HeaderLength; } return(loc); } loc += subMeta.TotalLength; } return(null); }