Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8619 | maxcodehac | 1 | /* |
2 | jbig2dec |
||
3 | |||
4 | Copyright (C) 2002-2005 Artifex Software, Inc. |
||
5 | |||
6 | This software is distributed under license and may not |
||
7 | be copied, modified or distributed except as expressly |
||
8 | authorized under the terms of the license contained in |
||
9 | the file LICENSE in this distribution. |
||
10 | |||
11 | For further licensing information refer to http://artifex.com/ or |
||
12 | contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, |
||
13 | San Rafael, CA 94903, U.S.A., +1(415)492-9861. |
||
14 | */ |
||
15 | |||
16 | #ifdef HAVE_CONFIG_H |
||
17 | #include "config.h" |
||
18 | #endif |
||
19 | #include "os_types.h" |
||
20 | |||
21 | #include |
||
22 | |||
23 | #include "jbig2.h" |
||
24 | #include "jbig2_priv.h" |
||
25 | #include "jbig2_symbol_dict.h" |
||
26 | #include "jbig2_metadata.h" |
||
27 | |||
28 | Jbig2Segment * |
||
29 | jbig2_parse_segment_header (Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, |
||
30 | size_t *p_header_size) |
||
31 | { |
||
32 | Jbig2Segment *result; |
||
33 | uint8_t rtscarf; |
||
34 | uint32_t rtscarf_long; |
||
35 | uint32_t *referred_to_segments; |
||
36 | int referred_to_segment_count; |
||
37 | int referred_to_segment_size; |
||
38 | int pa_size; |
||
39 | int offset; |
||
40 | |||
41 | /* minimum possible size of a jbig2 segment header */ |
||
42 | if (buf_size < 11) |
||
43 | return NULL; |
||
44 | |||
45 | result = (Jbig2Segment *)jbig2_alloc(ctx->allocator, |
||
46 | sizeof(Jbig2Segment)); |
||
47 | |||
48 | /* 7.2.2 */ |
||
49 | result->number = jbig2_get_int32(buf); |
||
50 | |||
51 | /* 7.2.3 */ |
||
52 | result->flags = buf[4]; |
||
53 | |||
54 | /* 7.2.4 referred-to segments */ |
||
55 | rtscarf = buf[5]; |
||
56 | if ((rtscarf & 0xe0) == 0xe0) |
||
57 | { |
||
58 | rtscarf_long = jbig2_get_int32(buf + 5); |
||
59 | referred_to_segment_count = rtscarf_long & 0x1fffffff; |
||
60 | offset = 5 + 4 + (referred_to_segment_count + 1) / 8; |
||
61 | } |
||
62 | else |
||
63 | { |
||
64 | referred_to_segment_count = (rtscarf >> 5); |
||
65 | offset = 5 + 1; |
||
66 | } |
||
67 | result->referred_to_segment_count = referred_to_segment_count; |
||
68 | |||
69 | /* we now have enough information to compute the full header length */ |
||
70 | referred_to_segment_size = result->number <= 256 ? 1: |
||
71 | result->number <= 65536 ? 2 : 4; /* 7.2.5 */ |
||
72 | pa_size = result->flags & 0x40 ? 4 : 1; /* 7.2.6 */ |
||
73 | if (offset + referred_to_segment_count*referred_to_segment_size + pa_size + 4 > buf_size) |
||
74 | { |
||
75 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, |
||
76 | "jbig2_parse_segment_header() called with insufficient data", -1); |
||
77 | jbig2_free (ctx->allocator, result); |
||
78 | return NULL; |
||
79 | } |
||
80 | |||
81 | /* 7.2.5 */ |
||
82 | if (referred_to_segment_count) |
||
83 | { |
||
84 | int i; |
||
85 | |||
86 | referred_to_segments = jbig2_alloc(ctx->allocator, referred_to_segment_count * referred_to_segment_size * sizeof(uint32_t)); |
||
87 | |||
88 | for (i = 0; i < referred_to_segment_count; i++) { |
||
89 | referred_to_segments[i] = |
||
90 | (referred_to_segment_size == 1) ? buf[offset] : |
||
91 | (referred_to_segment_size == 2) ? jbig2_get_int16(buf+offset) : |
||
92 | jbig2_get_int32(buf + offset); |
||
93 | offset += referred_to_segment_size; |
||
94 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, |
||
95 | "segment %d refers to segment %d", |
||
96 | result->number, referred_to_segments[i]); |
||
97 | } |
||
98 | result->referred_to_segments = referred_to_segments; |
||
99 | } |
||
100 | else /* no referred-to segments */ |
||
101 | { |
||
102 | result->referred_to_segments = NULL; |
||
103 | } |
||
104 | |||
105 | /* 7.2.6 */ |
||
106 | if (result->flags & 0x40) { |
||
107 | result->page_association = jbig2_get_int32(buf + offset); |
||
108 | offset += 4; |
||
109 | } else { |
||
110 | result->page_association = buf[offset++]; |
||
111 | } |
||
112 | jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, |
||
113 | "segment %d is associated with page %d", |
||
114 | result->number, result->page_association); |
||
115 | |||
116 | /* 7.2.7 */ |
||
117 | result->data_length = jbig2_get_int32(buf + offset); |
||
118 | *p_header_size = offset + 4; |
||
119 | |||
120 | /* no body parsing results yet */ |
||
121 | result->result = NULL; |
||
122 | |||
123 | return result; |
||
124 | } |
||
125 | |||
126 | void |
||
127 | jbig2_free_segment (Jbig2Ctx *ctx, Jbig2Segment *segment) |
||
128 | { |
||
129 | if (segment->referred_to_segments != NULL) { |
||
130 | jbig2_free(ctx->allocator, segment->referred_to_segments); |
||
131 | } |
||
132 | /* todo: we need either some separate fields or |
||
133 | a more complex result object rather than this |
||
134 | brittle special casing */ |
||
135 | switch (segment->flags & 63) { |
||
136 | case 0: /* symbol dictionary */ |
||
137 | if (segment->result != NULL) |
||
138 | jbig2_sd_release(ctx, segment->result); |
||
139 | break; |
||
140 | case 4: /* intermediate text region */ |
||
141 | case 40: /* intermediate refinement region */ |
||
142 | if (segment->result != NULL) |
||
143 | jbig2_image_release(ctx, segment->result); |
||
144 | break; |
||
145 | case 62: |
||
146 | if (segment->result != NULL) |
||
147 | jbig2_metadata_free(ctx, segment->result); |
||
148 | break; |
||
149 | default: |
||
150 | /* anything else is probably an undefined pointer */ |
||
151 | break; |
||
152 | } |
||
153 | jbig2_free (ctx->allocator, segment); |
||
154 | } |
||
155 | |||
156 | /* find a segment by number */ |
||
157 | Jbig2Segment * |
||
158 | jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number) |
||
159 | { |
||
160 | int index, index_max = ctx->segment_index - 1; |
||
161 | const Jbig2Ctx *global_ctx = ctx->global_ctx; |
||
162 | |||
163 | /* FIXME: binary search would be better */ |
||
164 | for (index = index_max; index >= 0; index--) |
||
165 | if (ctx->segments[index]->number == number) |
||
166 | return (ctx->segments[index]); |
||
167 | |||
168 | if (global_ctx) |
||
169 | for (index = global_ctx->segment_index - 1; index >= 0; index--) |
||
170 | if (global_ctx->segments[index]->number == number) |
||
171 | return (global_ctx->segments[index]); |
||
172 | |||
173 | /* didn't find a match */ |
||
174 | return NULL; |
||
175 | } |
||
176 | |||
177 | /* parse the generic portion of a region segment data header */ |
||
178 | void |
||
179 | jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, |
||
180 | const uint8_t *segment_data) |
||
181 | { |
||
182 | /* 7.4.1 */ |
||
183 | info->width = jbig2_get_int32(segment_data); |
||
184 | info->height = jbig2_get_int32(segment_data + 4); |
||
185 | info->x = jbig2_get_int32(segment_data + 8); |
||
186 | info->y = jbig2_get_int32(segment_data + 12); |
||
187 | info->flags = segment_data[16]; |
||
188 | info->op = info->flags & 0x7; |
||
189 | } |
||
190 | |||
191 | /* dispatch code for extension segment parsing */ |
||
192 | int jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, |
||
193 | const uint8_t *segment_data) |
||
194 | { |
||
195 | uint32_t type; |
||
196 | bool reserved, dependent, necessary; |
||
197 | |||
198 | type = jbig2_get_int32(segment_data); |
||
199 | |||
200 | reserved = type & 0x20000000; |
||
201 | dependent = type & 0x40000000; |
||
202 | necessary = type & 0x80000000; |
||
203 | |||
204 | if (necessary && !reserved) { |
||
205 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
206 | "extension segment is marked 'necessary' but not 'reservered' contrary to spec"); |
||
207 | } |
||
208 | |||
209 | switch (type) { |
||
210 | case 0x20000000: return jbig2_comment_ascii(ctx, segment, segment_data); |
||
211 | case 0x20000002: return jbig2_comment_unicode(ctx, segment, segment_data); |
||
212 | default: |
||
213 | if (necessary) { |
||
214 | return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, |
||
215 | "unhandled necessary extension segment type 0x%08x", type); |
||
216 | } else { |
||
217 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
218 | "unhandled extension segment"); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | return 0; |
||
223 | } |
||
224 | |||
225 | /* general segment parsing dispatch */ |
||
226 | int jbig2_parse_segment (Jbig2Ctx *ctx, Jbig2Segment *segment, |
||
227 | const uint8_t *segment_data) |
||
228 | { |
||
229 | jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
230 | "Segment %d, flags=%x, type=%d, data_length=%d", |
||
231 | segment->number, segment->flags, segment->flags & 63, |
||
232 | segment->data_length); |
||
233 | switch (segment->flags & 63) |
||
234 | { |
||
235 | case 0: |
||
236 | return jbig2_symbol_dictionary(ctx, segment, segment_data); |
||
237 | case 4: /* intermediate text region */ |
||
238 | case 6: /* immediate text region */ |
||
239 | case 7: /* immediate lossless text region */ |
||
240 | return jbig2_text_region(ctx, segment, segment_data); |
||
241 | #ifdef JBIG2_HALFTONE |
||
242 | case 16: |
||
243 | return jbig2_pattern_dictionary(ctx, segment, segment_data); |
||
244 | case 20: /* intermediate halftone region */ |
||
245 | case 22: /* immediate halftone region */ |
||
246 | case 23: /* immediate lossless halftone region */ |
||
247 | return jbig2_halftone_region(ctx, segment, segment_data); |
||
248 | #else |
||
249 | case 16: |
||
250 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
251 | "unhandled segment type 'pattern dictionary'"); |
||
252 | case 20: |
||
253 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
254 | "unhandled segment type 'intermediate halftone region'"); |
||
255 | case 22: |
||
256 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
257 | "unhandled segment type 'immediate halftone region'"); |
||
258 | case 23: |
||
259 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
260 | "unhandled segment type 'immediate lossless halftone region'"); |
||
261 | #endif |
||
262 | case 36: |
||
263 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
264 | "unhandled segment type 'intermediate generic region'"); |
||
265 | case 38: /* immediate generic region */ |
||
266 | case 39: /* immediate lossless generic region */ |
||
267 | return jbig2_immediate_generic_region(ctx, segment, segment_data); |
||
268 | case 40: /* intermediate generic refinement region */ |
||
269 | case 42: /* immediate generic refinement region */ |
||
270 | case 43: /* immediate lossless generic refinement region */ |
||
271 | return jbig2_refinement_region(ctx, segment, segment_data); |
||
272 | case 48: |
||
273 | return jbig2_page_info(ctx, segment, segment_data); |
||
274 | case 49: |
||
275 | return jbig2_end_of_page(ctx, segment, segment_data); |
||
276 | case 50: |
||
277 | return jbig2_end_of_stripe(ctx, segment, segment_data); |
||
278 | case 51: |
||
279 | ctx->state = JBIG2_FILE_EOF; |
||
280 | return jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, |
||
281 | "end of file"); |
||
282 | case 52: |
||
283 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
284 | "unhandled segment type 'profile'"); |
||
285 | case 53: |
||
286 | return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
287 | "unhandled table segment"); |
||
288 | case 62: |
||
289 | return jbig2_parse_extension_segment(ctx, segment, segment_data); |
||
290 | default: |
||
291 | jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, |
||
292 | "unknown segment type %d", segment->flags & 63); |
||
293 | } |
||
294 | return 0; |
||
295 | }>=>=>> |