private static void ReadNextStreamObject(int type, long objectNumber, CrossReferenceStreamFieldSize fieldSizes,
                                                 CrossReferenceTablePartBuilder builder, byte[] lineBuffer)
        {
            switch (type)
            {
            case 0:
                // Ignore free objects.
                break;

            case 1:
                // Non object stream entries.
                int offset = 0;
                for (int i = 0; i < fieldSizes.Field2Size; i++)
                {
                    offset += (lineBuffer[i + fieldSizes.Field1Size] & 0x00ff) << ((fieldSizes.Field2Size - i - 1) * 8);
                }
                int genNum = 0;
                for (int i = 0; i < fieldSizes.Field3Size; i++)
                {
                    genNum += (lineBuffer[i + fieldSizes.Field1Size + fieldSizes.Field2Size] & 0x00ff) << ((fieldSizes.Field3Size - i - 1) * 8);
                }

                builder.Add(objectNumber, genNum, offset);

                break;

            case 2:
                /*
                 * object stored in object stream:
                 * 2nd argument is object number of object stream
                 * 3rd argument is index of object within object stream
                 *
                 * For sequential PDFParser we do not need this information
                 * because
                 * These objects are handled by the dereferenceObjects() method
                 * since they're only pointing to object numbers
                 *
                 * However for XRef aware parsers we have to know which objects contain
                 * object streams. We will store this information in normal xref mapping
                 * table but add object stream number with minus sign in order to
                 * distinguish from file offsets
                 */
                int objstmObjNr = 0;
                for (int i = 0; i < fieldSizes.Field2Size; i++)
                {
                    objstmObjNr += (lineBuffer[i + fieldSizes.Field1Size] & 0x00ff) << ((fieldSizes.Field2Size - i - 1) * 8);
                }

                builder.Add(objectNumber, 0, -objstmObjNr);

                break;
            }
        }
        /// <summary>
        /// Parses through the unfiltered stream and populates the xrefTable HashMap.
        /// </summary>
        public CrossReferenceTablePart Parse(long streamOffset, StreamToken stream)
        {
            var decoded = stream.Decode(filterProvider);

            var fieldSizes = new CrossReferenceStreamFieldSize(stream.StreamDictionary);

            var lineCount = decoded.Count / fieldSizes.LineLength;

            long previousOffset = -1;

            if (stream.StreamDictionary.TryGet(NameToken.Prev, out var prevToken) && prevToken is NumericToken prevNumeric)
            {
                previousOffset = prevNumeric.Long;
            }

            var builder = new CrossReferenceTablePartBuilder
            {
                Offset     = streamOffset,
                Previous   = previousOffset,
                Dictionary = stream.StreamDictionary,
                XRefType   = CrossReferenceType.Stream
            };

            var objectNumbers = GetObjectNumbers(stream.StreamDictionary);

            var lineNumber = 0;
            var lineBuffer = new byte[fieldSizes.LineLength];

            foreach (var objectNumber in objectNumbers)
            {
                if (lineNumber >= lineCount)
                {
                    break;
                }

                var byteOffset = lineNumber * fieldSizes.LineLength;

                for (var i = 0; i < fieldSizes.LineLength; i++)
                {
                    lineBuffer[i] = decoded[byteOffset + i];
                }

                int type;
                if (fieldSizes.Field1Size == 0)
                {
                    type = 1;
                }
                else
                {
                    type = 0;

                    for (var i = 0; i < fieldSizes.Field1Size; i++)
                    {
                        type += (lineBuffer[i] & 0x00ff) << ((fieldSizes.Field1Size - i - 1) * 8);
                    }
                }

                ReadNextStreamObject(type, objectNumber, fieldSizes, builder, lineBuffer);

                lineNumber++;
            }

            return(builder.Build());
        }