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;
            }
        }
        public void Read()
        {
            if (_read)
            {
                throw new InvalidOperationException("already attempted a Read() on this Jbig2 File");
            }
            _read = true;

            readFileHeader();
            // Annex D
            if (_sequential)
            {
                // D.1
                do
                {
                    Jbig2Segment tmp = readHeader();
                    readSegment(tmp);
                    _segments[tmp.SegmentNumber] = tmp;
                } while (_ra.FilePointer < _ra.Length);
            }
            else
            {
                // D.2
                Jbig2Segment tmp;
                do
                {
                    tmp = readHeader();
                    _segments[tmp.SegmentNumber] = tmp;
                } while (tmp.Type != END_OF_FILE);
                foreach (int ss in _segments.Keys)
                {
                    readSegment((Jbig2Segment)_segments[ss]);
                }
            }
        }
            /// <summary>
            /// return as a single byte array the header-data for each segment in segment number
            /// order, EMBEDDED organization, but i am putting the needed segments in SEQUENTIAL organization.
            /// if for_embedding, skip the segment types that are known to be not for acrobat.
            /// @throws IOException
            /// </summary>
            /// <param name="forEmbedding"></param>
            /// <returns>a byte array</returns>
            public byte[] GetData(bool forEmbedding)
            {
                MemoryStream os = new MemoryStream();

                foreach (int sn in _segs.Keys)
                {
                    Jbig2Segment s = (Jbig2Segment)_segs[sn];

                    // pdf reference 1.4, section 3.3.6 JBIG2Decode Filter
                    // D.3 Embedded organisation
                    if (forEmbedding &&
                        (s.Type == END_OF_FILE || s.Type == END_OF_PAGE))
                    {
                        continue;
                    }

                    if (forEmbedding)
                    {
                        // change the page association to page 1
                        byte[] headerDataEmb = CopyByteArray(s.HeaderData);
                        if (s.PageAssociationSize)
                        {
                            headerDataEmb[s.PageAssociationOffset]     = 0x0;
                            headerDataEmb[s.PageAssociationOffset + 1] = 0x0;
                            headerDataEmb[s.PageAssociationOffset + 2] = 0x0;
                            headerDataEmb[s.PageAssociationOffset + 3] = 0x1;
                        }
                        else
                        {
                            headerDataEmb[s.PageAssociationOffset] = 0x1;
                        }
                        os.Write(headerDataEmb, 0, headerDataEmb.Length);
                    }
                    else
                    {
                        os.Write(s.HeaderData, 0, s.HeaderData.Length);
                    }
                    os.Write(s.Data, 0, s.Data.Length);
                }

                return(os.ToArray());
            }
 public int CompareTo(Jbig2Segment s)
 {
     return(SegmentNumber - s.SegmentNumber);
 }
 public void AddSegment(Jbig2Segment s)
 {
     _segs[s.SegmentNumber] = s;
 }
        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);
        }
 public int CompareTo(Jbig2Segment s) => SegmentNumber - s.SegmentNumber;