void readSegment(Jbig2Segment s)
        {
            int ptr = _ra.FilePointer;

            if (s.DataLength == 0xffffffffL)
            {
                // TODO figure this bit out, 7.2.7
                return;
            }

            byte[] data = new byte[(int)s.DataLength];
            _ra.Read(data);
            s.Data = data;

            if (s.Type == PAGE_INFORMATION)
            {
                int last = _ra.FilePointer;
                _ra.Seek(ptr);
                int pageBitmapWidth  = _ra.ReadInt();
                int pageBitmapHeight = _ra.ReadInt();
                _ra.Seek(last);
                Jbig2Page p = (Jbig2Page)_pages[s.Page];
                if (p == null)
                {
                    throw new InvalidOperationException("referring to widht/height of page we havent seen yet? " + s.Page);
                }

                p.PageBitmapWidth  = pageBitmapWidth;
                p.PageBitmapHeight = pageBitmapHeight;
            }
        }
        Jbig2Segment readHeader()
        {
            int ptr = _ra.FilePointer;
            // 7.2.1
            int          segmentNumber = _ra.ReadInt();
            Jbig2Segment s             = new Jbig2Segment(segmentNumber);

            // 7.2.3
            int  segmentHeaderFlags = _ra.Read();
            bool deferredNonRetain  = ((segmentHeaderFlags & 0x80) == 0x80);

            s.DeferredNonRetain = deferredNonRetain;
            bool pageAssociationSize = ((segmentHeaderFlags & 0x40) == 0x40);
            int  segmentType         = (segmentHeaderFlags & 0x3f);

            s.Type = segmentType;

            //7.2.4
            int referredToByte0           = _ra.Read();
            int countOfReferredToSegments = (referredToByte0 & 0xE0) >> 5;

            int[]  referredToSegmentNumbers;
            bool[] segmentRetentionFlags = null;

            if (countOfReferredToSegments == 7)
            {
                // at least five bytes
                _ra.Seek(_ra.FilePointer - 1);
                countOfReferredToSegments = (_ra.ReadInt() & 0x1fffffff);
                segmentRetentionFlags     = new bool[countOfReferredToSegments + 1];
                int i = 0;
                int referredToCurrentByte = 0;
                do
                {
                    int j = i % 8;
                    if (j == 0)
                    {
                        referredToCurrentByte = _ra.Read();
                    }
                    segmentRetentionFlags[i] = ((((0x1 << j) & referredToCurrentByte) >> j) == 0x1);
                    i++;
                } while (i <= countOfReferredToSegments);
            }
            else if (countOfReferredToSegments <= 4)
            {
                // only one byte
                segmentRetentionFlags = new bool[countOfReferredToSegments + 1];
                referredToByte0      &= 0x1f;
                for (int i = 0; i <= countOfReferredToSegments; i++)
                {
                    segmentRetentionFlags[i] = ((((0x1 << i) & referredToByte0) >> i) == 0x1);
                }
            }
            else if (countOfReferredToSegments == 5 || countOfReferredToSegments == 6)
            {
                throw new InvalidOperationException("count of referred-to segments had bad value in header for segment " + segmentNumber + " starting at " + ptr);
            }
            s.SegmentRetentionFlags     = segmentRetentionFlags;
            s.CountOfReferredToSegments = countOfReferredToSegments;

            // 7.2.5
            referredToSegmentNumbers = new int[countOfReferredToSegments + 1];
            for (int i = 1; i <= countOfReferredToSegments; i++)
            {
                if (segmentNumber <= 256)
                {
                    referredToSegmentNumbers[i] = _ra.Read();
                }
                else if (segmentNumber <= 65536)
                {
                    referredToSegmentNumbers[i] = _ra.ReadUnsignedShort();
                }
                else
                {
                    referredToSegmentNumbers[i] = (int)_ra.ReadUnsignedInt(); // TODO wtf ack
                }
            }
            s.ReferredToSegmentNumbers = referredToSegmentNumbers;

            // 7.2.6
            int segmentPageAssociation;
            int pageAssociationOffset = _ra.FilePointer - ptr;

            if (pageAssociationSize)
            {
                segmentPageAssociation = _ra.ReadInt();
            }
            else
            {
                segmentPageAssociation = _ra.Read();
            }
            if (segmentPageAssociation < 0)
            {
                throw new InvalidOperationException("page " + segmentPageAssociation + " invalid for segment " + segmentNumber + " starting at " + ptr);
            }
            s.Page = segmentPageAssociation;
            // so we can change the page association at embedding time.
            s.PageAssociationSize   = pageAssociationSize;
            s.PageAssociationOffset = pageAssociationOffset;

            if (segmentPageAssociation > 0 && !_pages.ContainsKey(segmentPageAssociation))
            {
                _pages[segmentPageAssociation] = new Jbig2Page(segmentPageAssociation, this);
            }
            if (segmentPageAssociation > 0)
            {
                ((Jbig2Page)_pages[segmentPageAssociation]).AddSegment(s);
            }
            else
            {
                _globals[s] = null;
            }

            // 7.2.7
            long segmentDataLength = _ra.ReadUnsignedInt();

            // TODO the 0xffffffff value that might be here, and how to understand those afflicted segments
            s.DataLength = segmentDataLength;

            int endPtr = _ra.FilePointer;

            _ra.Seek(ptr);
            byte[] headerData = new byte[endPtr - ptr];
            _ra.Read(headerData);
            s.HeaderData = headerData;

            return(s);
        }