public void FillMajorRecords( OverlayStream stream, int finalPos, int offset, RecordTypeConverter?recordTypeConverter, RecordTypeFillWrapper fill) { int?lastParsed = null; while (!stream.Complete && stream.Position < finalPos) { MajorRecordHeader majorMeta = stream.GetMajorRecord(); var minimumFinalPos = stream.Position + majorMeta.TotalLength; var parsed = fill( stream: stream, finalPos: finalPos, offset: offset, type: majorMeta.RecordType, lastParsed: lastParsed, recordTypeConverter: recordTypeConverter); if (parsed.Failed) { break; } if (minimumFinalPos > stream.Position) { stream.Position = checked ((int)minimumFinalPos); } lastParsed = parsed.Value; } }
public void FillMajorRecords( OverlayStream stream, int finalPos, int offset, RecordTypeConverter?recordTypeConverter, RecordTypeFillWrapper fill) { int?lastParsed = null; Dictionary <RecordType, int>?recordParseCount = null; while (!stream.Complete && stream.Position < finalPos) { MajorRecordHeader majorMeta = stream.GetMajorRecord(); var minimumFinalPos = stream.Position + majorMeta.TotalLength; var parsed = fill( stream: stream, finalPos: finalPos, offset: offset, recordParseCount: recordParseCount, type: majorMeta.RecordType, lastParsed: lastParsed, recordTypeConverter: recordTypeConverter); if (!parsed.KeepParsing) { break; } if (parsed.DuplicateParseMarker != null) { if (recordParseCount == null) { recordParseCount = new Dictionary <RecordType, int>(); } recordParseCount[parsed.DuplicateParseMarker !.Value] = recordParseCount.GetOrAdd(parsed.DuplicateParseMarker !.Value) + 1;
public IReadOnlyList <T> ParseRepeatedTypelessSubrecord <T>( OverlayStream stream, RecordType trigger, SpanRecordFactory <T> factory, RecordTypeConverter?recordTypeConverter, bool skipHeader) { var ret = new List <T>(); while (!stream.Complete) { var subMeta = stream.GetSubrecord(); var recType = subMeta.RecordType; if (trigger != recType) { break; } var minimumFinalPos = stream.Position + subMeta.TotalLength; if (skipHeader) { stream.Position += subMeta.HeaderLength; } ret.Add(factory(stream.ReadMemory(skipHeader ? subMeta.ContentLength : subMeta.TotalLength), _package, recordTypeConverter)); if (stream.Position < minimumFinalPos) { stream.Position = minimumFinalPos; } } return(ret); }
public static int[] ParseRecordLocationsByCount( OverlayStream stream, uint count, RecordType trigger, RecordHeaderConstants constants, bool skipHeader) { List <int> ret = new List <int>(); var startingPos = stream.Position; for (uint i = 0; i < count; i++) { var varMeta = constants.GetVariableMeta(stream); var recType = varMeta.RecordType; if (trigger == recType) { 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 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 void FillGroupRecordsForWrapper( OverlayStream stream, int finalPos, int offset, RecordTypeConverter?recordTypeConverter, RecordTypeFillWrapper fill) { int?lastParsed = null; while (!stream.Complete && stream.Position < finalPos) { if (!stream.TryGetGroup(out var groupMeta)) { throw new DataMisalignedException(); } var subStream = new OverlayStream(stream.RemainingMemory.Slice(0, finalPos - stream.Position), stream.MetaData); var parsed = fill( stream: subStream, finalPos: subStream.Length, offset: 0, // unused type: groupMeta.RecordType, lastParsed: lastParsed, recordTypeConverter: recordTypeConverter); stream.Position += subStream.Position; if (parsed.Failed) { break; } lastParsed = parsed.Value; } }
public IReadOnlyList <T> ParseRepeatedTypelessSubrecord <T>( OverlayStream stream, 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, 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, trigger: subrecordType, skipHeader: skipHeader, recordTypeConverter: recordTypeConverter))); } }
public static IReadOnlyList <T> FactoryByCount <T>( OverlayStream stream, BinaryOverlayFactoryPackage package, uint count, BinaryOverlay.StreamFactory <T> getter) { var ret = new List <T>(checked ((int)count)); for (uint i = 0; i < count; i++) { ret.Add(getter(stream, package)); } return(ret); }
public static IReadOnlyList <T> FactoryByCount <T>( OverlayStream stream, BinaryOverlayFactoryPackage package, int itemLength, int countLength, RecordType subrecordType, RecordType countType, BinaryOverlay.SpanFactory <T> getter) { 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 => (int)BinaryPrimitives.ReadUInt16LittleEndian(initialHeader.Content), 4 => checked ((int)BinaryPrimitives.ReadUInt32LittleEndian(initialHeader.Content)), _ => throw new NotImplementedException(), }; stream.Position += initialHeader.TotalLength; if (!stream.TryReadSubrecordFrame(subrecordType, out var contentFrame)) { if (count == 0) { return(Array.Empty <T>()); } throw new ArgumentException($"List with a non zero {initialHeader.RecordType} counter did not follow up with expected type: {subrecordType}"); } return(new BinaryOverlayListByStartIndex <T>( contentFrame.Content, package, getter, itemLength)); } else { return(FactoryByStartIndex( mem: stream.RemainingMemory, package: package, getter: getter, itemLength: itemLength)); } }
public static IReadOnlyList <T>?FactoryByCountNullIfZero <T>( OverlayStream stream, BinaryOverlayFactoryPackage package, int itemLength, int countLength, RecordType subrecordType, RecordType countType, BinaryOverlay.SpanFactory <T> getter) { 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 => (int)BinaryPrimitives.ReadUInt16LittleEndian(initialHeader.Content), 4 => checked ((int)BinaryPrimitives.ReadUInt32LittleEndian(initialHeader.Content)), _ => throw new NotImplementedException(), }; stream.Position += initialHeader.TotalLength; if (count == 0) { return(null); } var contentFrame = stream.ReadSubrecordFrame(subrecordType); return(new BinaryOverlayListByStartIndex <T>( contentFrame.Content, package, getter, itemLength)); } else { return(FactoryByStartIndex( mem: stream.RemainingMemory, package: package, getter: getter, itemLength: itemLength)); } }
public static int[] ParseRecordLocations( OverlayStream stream, long finalPos, RecordType trigger, 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 isTrigger = trigger == recType; var isIncludeTrigger = includeTrigger == recType; if (!isTrigger && !isIncludeTrigger) { break; } if (isTrigger) { 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 IReadOnlyList <T> FactoryByLazyParse <T>( ReadOnlyMemorySlice <byte> mem, BinaryOverlayFactoryPackage package, BinaryOverlay.Factory <T> getter) { return(new BinaryOverlayLazyList <T>( mem, package, (m, p) => { var ret = new List <T>(); using (var stream = new OverlayStream(m, package)) { while (!stream.Complete) { ret.Add(getter(stream, p)); } } return ret; })); }