internal PdfValue                    pdfReadObj(PdfReferenceReader reference)
        {
            try {
                if (reference.CompressedObj == null)
                {
                    var reader = new PdfStreamReader(this, _stream, reference.Position);

                    int id       = reader.ReadInt();
                    int revision = reader.ReadInt();
                    reader.ReadToken(PdfValueType.ObjectBegin);

                    if (id != reference.Id || revision != reference.Revision)
                    {
                        throw new PdfException("Object id d'not match with xreftable.");
                    }

                    var obj = _readObj(reader, false);

                    if (obj is PdfObjectReader && ((PdfObjectReader)obj).NamedType == "ObjStm")
                    {
                        obj = new PdfObjStmReader(this, (PdfObjectReader)obj);
                    }

                    return(obj);
                }
                else
                {
                    if (!(_xrefTable[reference.CompressedObj.Id].Value is PdfObjStmReader objStm))
                    {
                        throw new PdfException("Obj not ObjStm.");
                    }

                    return(_readObj(new PdfStreamReader(this, objStm.GetStream(reference.Position, reference.Id), 0), true));
                }
            }
            catch (Exception err) {
                throw new PdfExceptionReader("Can't read object " + reference.Id.ToString(CultureInfo.InvariantCulture) + "/" + reference.Revision.ToString(CultureInfo.InvariantCulture) + ".", err);
            }
        }
        private void                        _readXrefObject(int pos, PdfStreamReader reader, PdfValue firstToken)
        {
            int id       = ((PdfInteger)firstToken).Value;
            int revision = reader.ReadInt();

            reader.ReadToken(PdfValueType.ObjectBegin);
            _allocateXrefTable(id + 1);
            var rr = new PdfReferenceReader(this, id, revision, pos);

            if (!(_readObj(reader, false) is PdfObjectReader obj))
            {
                throw new PdfExceptionReader("Invalid Xref obj.");
            }
            rr.setValue(obj);
            _xrefTable[id] = rr;

            var                dictionary = obj.Dictionary.Children;
            PdfValueList       w          = null;
            PdfValueList       index      = null;
            int                size       = 0;
            PdfReferenceReader prev       = null;

            for (int i = 0; i < dictionary.Count; ++i)
            {
                var entry = dictionary[i];
                if (entry is PdfName)
                {
                    switch (((PdfName)entry).Value)
                    {
                    case "W":       w = ((PdfArray)dictionary[++i]).Children;               break;

                    case "Index":   index = ((PdfArray)dictionary[++i]).Children;               break;

                    case "Size":    size = ((PdfInteger)dictionary[++i]).Value;                break;

                    case "Prev":    prev = (PdfReferenceReader)dictionary[++i];                break;

                    case "Root":    _rootReference = (PdfReferenceReader)dictionary[++i];                break;

                    case "Encrypt": _encryptReference = (PdfReferenceReader)dictionary[++i];                break;

                    case "Info":    _infoReference = (PdfReferenceReader)dictionary[++i];                break;

                    case "ID":      _id = ((PdfArray)dictionary[++i]).Children.ToArray();     break;
                    }
                }
            }

            if (obj.NamedType != "XRef" || w == null || index == null)
            {
                throw new PdfExceptionReader("Invalid xref object.");
            }

            int s1 = ((PdfInteger)w[0]).Value;
            int s2 = ((PdfInteger)w[1]).Value;
            int s3 = ((PdfInteger)w[2]).Value;

            id = ((PdfInteger)index[0]).Value;

            _allocateXrefTable(((PdfInteger)index[1]).Value);

            using (var r = new PdfXrefStreamReader(obj.GetUncompressStream())) {
                while (!r.EOF)
                {
                    int t  = r.ReadValue(s1);
                    int v2 = r.ReadValue(s2);
                    int v3 = r.ReadValue(s3);

                    switch (t)
                    {
                    case 0:                                                                             break;

                    case 1:     pdfGetReference(id, v3).setPosition(v2);                                break;

                    case 2:     pdfGetReference(id, 0).setCompressed(v3, pdfGetReference(v2, 0));       break;

                    default:    throw new PdfExceptionReader("cross-reference stream type #" + t + " unknown.");
                    }

                    ++id;
                }
            }
        }
        private void                        _readXrefTable(PdfStreamReader reader)
        {
            PdfValue Token;

            // Read xref table

            while ((Token = reader.ReadToken()).Type == PdfValueType.Integer)
            {
                int Id    = ((PdfInteger)Token).Value;
                int Count = reader.ReadInt();

                _allocateXrefTable(Id + Count);

                while (Count-- > 0)
                {
                    int  EntryPosition = reader.ReadInt();
                    int  EntryRevision = reader.ReadInt();
                    bool EntryUsed     = (reader.ReadByte() == 'n');

                    if (EntryPosition >= 10 && EntryUsed)
                    {
                        _xrefTable[Id] = new PdfReferenceReader(this, Id, EntryRevision, EntryPosition);
                    }

                    ++Id;
                }
            }

            // Read trailer
            if (Token.Type != PdfValueType.Trailer)
            {
                throw new PdfExceptionReader("PDF stream corrupt: 'trailer' expected.");
            }

            reader.ReadToken(PdfValueType.DictionaryBegin);

            while ((Token = reader.ReadToken()).Type != PdfValueType.DictionaryEnd)
            {
                if (Token.Type == PdfValueType.Name)
                {
                    switch (((PdfName)Token).Value)
                    {
                    case "Size":
                        if (reader.ReadInt() != _xrefTable.Length)
                        {
                            throw new PdfExceptionReader("PDF stream corrupt: Xref table size d'not match trailer 'Size'.");
                        }
                        break;

                    case "Prev": {
                        var p = reader.ReadInt();
                        reader.ReadToken(PdfValueType.Xref);
                        _readXrefTable(new PdfStreamReader(this, _stream, p));
                    }
                    break;

                    case "Root":
                        _rootReference = pdfGetReference(reader.ReadReference());
                        break;

                    case "Encrypt":
                        _encryptReference = pdfGetReference(reader.ReadReference());
                        break;

                    case "Info":
                        _infoReference = pdfGetReference(reader.ReadReference());
                        break;

                    case "ID": {
                        List <PdfValue> ID = new List <PdfValue>();

                        reader.ReadToken(PdfValueType.ArrayBegin);

                        while ((Token = reader.ReadToken()).Type != PdfValueType.ArrayEnd)
                        {
                            ID.Add(Token);
                        }

                        _id = ID.ToArray();
                    }
                    break;
                    }
                }
            }
        }