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());
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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());
        }
Exemple #5
0
        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);
        }
Exemple #6
0
 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));
 }
Exemple #7
0
        /// <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());
        }
Exemple #8
0
        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)));
            }
        }
Exemple #9
0
 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;
 }
Exemple #10
0
 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));
 }
Exemple #11
0
        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());
        }
Exemple #12
0
        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);
        }