1 /* Copyright (C) 2001-2020 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16 /*
17 jbig2dec
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include "os_types.h"
24
25 #include <stdlib.h>
26
27 #ifdef OUTPUT_PBM
28 #include <stdio.h>
29 #endif
30
31 #include "jbig2.h"
32 #include "jbig2_priv.h"
33 #include "jbig2_image.h"
34 #include "jbig2_page.h"
35 #include "jbig2_segment.h"
36
37 /* dump the page struct info */
38 static void
dump_page_info(Jbig2Ctx * ctx,Jbig2Segment * segment,Jbig2Page * page)39 dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page)
40 {
41 if (page->x_resolution == 0) {
42 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (unknown res)", page->number, page->width, page->height);
43 } else if (page->x_resolution == page->y_resolution) {
44 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (%d ppm)", page->number, page->width, page->height, page->x_resolution);
45 } else {
46 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
47 "page %d image is %dx%d (%dx%d ppm)", page->number, page->width, page->height, page->x_resolution, page->y_resolution);
48 }
49 if (page->striped) {
50 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "\tmaximum stripe size: %d", page->stripe_size);
51 }
52 }
53
54 /**
55 * jbig2_page_info: parse page info segment
56 *
57 * Parse the page info segment data and fill out a corresponding
58 * Jbig2Page struct and ready it for subsequent rendered data,
59 * including allocating an image buffer for the page (or the first stripe)
60 **/
61 int
jbig2_page_info(Jbig2Ctx * ctx,Jbig2Segment * segment,const uint8_t * segment_data)62 jbig2_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
63 {
64 Jbig2Page *page, *pages;
65
66 /* a new page info segment implies the previous page is finished */
67 page = &(ctx->pages[ctx->current_page]);
68 if (page->number != 0 && (page->state == JBIG2_PAGE_NEW || page->state == JBIG2_PAGE_FREE)) {
69 page->state = JBIG2_PAGE_COMPLETE;
70 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unexpected page info segment, marking previous page finished");
71 }
72
73 /* find a free page */
74 {
75 size_t index, j;
76
77 index = ctx->current_page;
78 while (ctx->pages[index].state != JBIG2_PAGE_FREE) {
79 index++;
80 if (index >= ctx->max_page_index) {
81 /* grow the list */
82
83 if (ctx->max_page_index == UINT32_MAX) {
84 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "too many pages in jbig2 image");
85 }
86 else if (ctx->max_page_index > (UINT32_MAX >> 2)) {
87 ctx->max_page_index = UINT32_MAX;
88 }
89
90 pages = jbig2_renew(ctx, ctx->pages, Jbig2Page, (ctx->max_page_index <<= 2));
91 if (pages == NULL) {
92 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to reallocate pages");
93 }
94 ctx->pages = pages;
95 for (j = index; j < ctx->max_page_index; j++) {
96 ctx->pages[j].state = JBIG2_PAGE_FREE;
97 ctx->pages[j].number = 0;
98 ctx->pages[j].image = NULL;
99 }
100 }
101 }
102 page = &(ctx->pages[index]);
103 ctx->current_page = index;
104 page->state = JBIG2_PAGE_NEW;
105 page->number = segment->page_association;
106 }
107
108 /* FIXME: would be nice if we tried to work around this */
109 if (segment->data_length < 19) {
110 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
111 }
112
113 /* 7.4.8.x */
114 page->width = jbig2_get_uint32(segment_data);
115 page->height = jbig2_get_uint32(segment_data + 4);
116
117 page->x_resolution = jbig2_get_uint32(segment_data + 8);
118 page->y_resolution = jbig2_get_uint32(segment_data + 12);
119 page->flags = segment_data[16];
120 /* Check for T.88 amendment 3 */
121 if (page->flags & 0x80)
122 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "page segment indicates use of color segments (NYI)");
123
124 /* 7.4.8.6 */
125 {
126 int16_t striping = jbig2_get_int16(segment_data + 17);
127
128 if (striping & 0x8000) {
129 page->striped = TRUE;
130 page->stripe_size = striping & 0x7FFF;
131 } else {
132 page->striped = FALSE;
133 page->stripe_size = 0; /* would page->height be better? */
134 }
135 }
136 if (page->height == 0xFFFFFFFF && page->striped == FALSE) {
137 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "height is unspecified but page is not marked as striped, assuming striped with maximum strip size");
138 page->striped = TRUE;
139 page->stripe_size = 0x7FFF;
140 }
141 page->end_row = 0;
142
143 if (segment->data_length > 19) {
144 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extra data in segment");
145 }
146
147 dump_page_info(ctx, segment, page);
148
149 /* allocate an appropriate page image buffer */
150 /* 7.4.8.2 */
151 if (page->height == 0xFFFFFFFF) {
152 page->image = jbig2_image_new(ctx, page->width, page->stripe_size);
153 } else {
154 page->image = jbig2_image_new(ctx, page->width, page->height);
155 }
156 if (page->image == NULL) {
157 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate buffer for page image");
158 } else {
159 /* 8.2 (3) fill the page with the default pixel value */
160 jbig2_image_clear(ctx, page->image, (page->flags & 4));
161 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
162 "allocated %dx%d page image (%d bytes)", page->image->width, page->image->height, page->image->stride * page->image->height);
163 }
164
165 return 0;
166 }
167
168 /**
169 * jbig2_end_of_stripe: parse and implement an end of stripe segment
170 **/
171 int
jbig2_end_of_stripe(Jbig2Ctx * ctx,Jbig2Segment * segment,const uint8_t * segment_data)172 jbig2_end_of_stripe(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
173 {
174 Jbig2Page *page = &ctx->pages[ctx->current_page];
175 uint32_t end_row;
176
177 if (segment->data_length < 4)
178 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
179 end_row = jbig2_get_uint32(segment_data);
180 if (end_row < page->end_row) {
181 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
182 "end of stripe segment with non-positive end row advance (new end row %d vs current end row %d)", end_row, page->end_row);
183 } else {
184 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of stripe: advancing end row from %u to %u", page->end_row, end_row);
185 }
186
187 page->end_row = end_row;
188
189 return 0;
190 }
191
192 /**
193 * jbig2_complete_page: complete a page image
194 *
195 * called upon seeing an 'end of page' segment, this routine
196 * marks a page as completed so it can be returned.
197 * compositing will have already happened in the previous
198 * segment handlers.
199 **/
200 int
jbig2_complete_page(Jbig2Ctx * ctx)201 jbig2_complete_page(Jbig2Ctx *ctx)
202 {
203 int code;
204
205 /* check for unfinished segments */
206 if (ctx->segment_index != ctx->n_segments) {
207 Jbig2Segment *segment = ctx->segments[ctx->segment_index];
208
209 /* Some versions of Xerox Workcentre generate PDF files
210 with the segment data length field of the last segment
211 set to -1. Try to cope with this here. */
212 if ((segment->data_length & 0xffffffff) == 0xffffffff) {
213 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "file has an invalid segment data length; trying to decode using the available data");
214 segment->data_length = ctx->buf_wr_ix - ctx->buf_rd_ix;
215 code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
216 ctx->buf_rd_ix += segment->data_length;
217 ctx->segment_index++;
218 if (code < 0) {
219 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to parse segment");
220 }
221 }
222 }
223
224 /* ensure image exists before marking page as complete */
225 if (ctx->pages[ctx->current_page].image == NULL) {
226 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page has no image, cannot be completed");
227 }
228
229 ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE;
230 return 0;
231 }
232
233 /**
234 * jbig2_end_of_page: parse and implement an end of page segment
235 **/
236 int
jbig2_end_of_page(Jbig2Ctx * ctx,Jbig2Segment * segment,const uint8_t * segment_data)237 jbig2_end_of_page(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
238 {
239 uint32_t page_number = ctx->pages[ctx->current_page].number;
240 int code;
241
242 if (segment->page_association != page_number) {
243 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
244 "end of page marker for page %d doesn't match current page number %d", segment->page_association, page_number);
245 }
246
247 jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of page %d", page_number);
248
249 code = jbig2_complete_page(ctx);
250 if (code < 0)
251 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to complete page");
252
253 #ifdef OUTPUT_PBM
254 code = jbig2_image_write_pbm(ctx->pages[ctx->current_page].image, stdout);
255 if (code < 0)
256 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to write page image");
257 #endif
258
259 return 0;
260 }
261
262 /**
263 * jbig2_add_page_result: composite a decoding result onto a page
264 *
265 * this is called to add the results of segment decode (when it
266 * is an image) to a page image buffer
267 **/
268 int
jbig2_page_add_result(Jbig2Ctx * ctx,Jbig2Page * page,Jbig2Image * image,uint32_t x,uint32_t y,Jbig2ComposeOp op)269 jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *image, uint32_t x, uint32_t y, Jbig2ComposeOp op)
270 {
271 int code;
272
273 if (x > INT32_MAX || y > INT32_MAX)
274 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unsupported image coordinates");
275
276 /* ensure image exists first */
277 if (page->image == NULL)
278 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page info possibly missing, no image defined");
279
280 /* grow the page to accommodate a new stripe if necessary */
281 if (page->striped && page->height == 0xFFFFFFFF) {
282 uint32_t new_height;
283
284 if (y > UINT32_MAX - image->height)
285 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "adding image at coordinate would grow page out of bounds");
286 new_height = y + image->height;
287
288 if (page->image->height < new_height) {
289 Jbig2Image *resized_image = NULL;
290
291 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "growing page buffer to %u rows to accommodate new stripe", new_height);
292 resized_image = jbig2_image_resize(ctx, page->image, page->image->width, new_height, page->flags & 4);
293 if (resized_image == NULL) {
294 return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER, "unable to resize image to accommodate new stripe");
295 }
296 page->image = resized_image;
297 }
298 }
299
300 code = jbig2_image_compose(ctx, page->image, image, x, y, op);
301 if (code < 0)
302 return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to compose image with page");
303
304 return 0;
305 }
306
307 /**
308 * jbig2_get_page: return the next available page image buffer
309 *
310 * the client can call this at any time to check if any pages
311 * have been decoded. If so, it returns the first available
312 * one. The client should then call jbig2_release_page() when
313 * it no longer needs to refer to the image buffer.
314 *
315 * since this is a public routine for the library clients, we
316 * return an image structure pointer, even though the function
317 * name refers to a page; the page structure is private.
318 **/
319 Jbig2Image *
jbig2_page_out(Jbig2Ctx * ctx)320 jbig2_page_out(Jbig2Ctx *ctx)
321 {
322 uint32_t index;
323
324 /* search for a completed page */
325 for (index = 0; index < ctx->max_page_index; index++) {
326 if (ctx->pages[index].state == JBIG2_PAGE_COMPLETE) {
327 Jbig2Image *img = ctx->pages[index].image;
328 uint32_t page_number = ctx->pages[index].number;
329
330 if (img == NULL) {
331 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d returned with no associated image", page_number);
332 continue;
333 }
334
335 ctx->pages[index].state = JBIG2_PAGE_RETURNED;
336 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d returned to the client", page_number);
337 return jbig2_image_reference(ctx, img);
338 }
339 }
340
341 /* no pages available */
342 return NULL;
343 }
344
345 /**
346 * jbig2_release_page: tell the library a page can be freed
347 **/
348 void
jbig2_release_page(Jbig2Ctx * ctx,Jbig2Image * image)349 jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image)
350 {
351 uint32_t index;
352
353 if (image == NULL)
354 return;
355
356 /* find the matching page struct and mark it released */
357 for (index = 0; index < ctx->max_page_index; index++) {
358 if (ctx->pages[index].image == image) {
359 jbig2_image_release(ctx, image);
360 ctx->pages[index].state = JBIG2_PAGE_RELEASED;
361 jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, JBIG2_UNKNOWN_SEGMENT_NUMBER, "page %d released by the client", ctx->pages[index].number);
362 return;
363 }
364 }
365
366 /* no matching pages */
367 jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to release unknown page");
368 }
369