JBIG2Segment ReadHeader() {
int ptr = ra.FilePointer;
// 7.2.1
int segment_number = ra.ReadInt();
JBIG2Segment s = new JBIG2Segment(segment_number);
// 7.2.3
int segment_header_flags = ra.Read();
bool deferred_non_retain = (( segment_header_flags & 0x80 ) == 0x80);
s.deferredNonRetain = deferred_non_retain;
bool page_association_size = (( segment_header_flags & 0x40 ) == 0x40);
int segment_type = ( segment_header_flags & 0x3f );
s.type = segment_type;
//7.2.4
int referred_to_byte0 = ra.Read();
int count_of_referred_to_segments = (referred_to_byte0 & 0xE0) >> 5;
int[] referred_to_segment_numbers = null;
bool[] segment_retention_flags = null;
if ( count_of_referred_to_segments == 7 ) {
// at least five bytes
ra.Seek(ra.FilePointer - 1);
count_of_referred_to_segments = ( ra.ReadInt() & 0x1fffffff );
segment_retention_flags = new bool[count_of_referred_to_segments+1];
int i = 0;
int referred_to_current_byte = 0;
do {
int j = i % 8;
if ( j == 0) {
referred_to_current_byte = ra.Read();
}
segment_retention_flags[i] = (((( 0x1 << j ) & referred_to_current_byte) >> j) == 0x1);
i++;
} while ( i <= count_of_referred_to_segments );
} else if ( count_of_referred_to_segments <= 4 ) {
// only one byte
segment_retention_flags = new bool[count_of_referred_to_segments+1];
referred_to_byte0 &= 0x1f;
for ( int i = 0; i <= count_of_referred_to_segments; i++ ) {
segment_retention_flags[i] = (((( 0x1 << i ) & referred_to_byte0) >> i) == 0x1);
}
} else if ( count_of_referred_to_segments == 5 || count_of_referred_to_segments == 6 ) {
throw new InvalidOperationException("count of referred-to segments had bad value in header for segment " + segment_number + " starting at " + ptr);
}
s.segmentRetentionFlags = segment_retention_flags;
s.countOfReferredToSegments = count_of_referred_to_segments;
// 7.2.5
referred_to_segment_numbers = new int[count_of_referred_to_segments+1];
for ( int i = 1; i <= count_of_referred_to_segments; i++ ) {
if ( segment_number <= 256 ) {
referred_to_segment_numbers[i] = ra.Read();
} else if ( segment_number <= 65536 ) {
referred_to_segment_numbers[i] = ra.ReadUnsignedShort();
} else {
referred_to_segment_numbers[i] = (int)ra.ReadUnsignedInt(); // TODO wtf ack
}
}
s.referredToSegmentNumbers = referred_to_segment_numbers;
// 7.2.6
int segment_page_association;
int page_association_offset = ra.FilePointer - ptr;
if ( page_association_size ) {
segment_page_association = ra.ReadInt();
} else {
segment_page_association = ra.Read();
}
if ( segment_page_association < 0 ) {
throw new InvalidOperationException("page " + segment_page_association + " invalid for segment " + segment_number + " starting at " + ptr);
}
s.page = segment_page_association;
// so we can change the page association at embedding time.
s.page_association_size = page_association_size;
s.page_association_offset = page_association_offset;
if ( segment_page_association > 0 && ! pages.ContainsKey(segment_page_association) ) {
pages[segment_page_association] = new JBIG2Page(segment_page_association, this);
}
if ( segment_page_association > 0 ) {
((JBIG2Page)pages[segment_page_association]).AddSegment(s);
} else {
globals[s] = null;
}
// 7.2.7
long segment_data_length = ra.ReadUnsignedInt();
// TODO the 0xffffffff value that might be here, and how to understand those afflicted segments
s.dataLength = segment_data_length;
int end_ptr = ra.FilePointer;
ra.Seek(ptr);
byte[] header_data = new byte[end_ptr - ptr];
ra.Read(header_data);
s.headerData = header_data;
return s;
}