Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/jbig2dec/jbig2_refinement.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/*
17
    jbig2dec
18
*/
19
20
/**
21
 * Generic Refinement region handlers.
22
 **/
23
24
#ifdef HAVE_CONFIG_H
25
#include "config.h"
26
#endif
27
#include "os_types.h"
28
29
#include <stddef.h>
30
#include <string.h>             /* memcpy(), memset() */
31
32
#include <stdio.h>
33
34
#include "jbig2.h"
35
#include "jbig2_priv.h"
36
#include "jbig2_arith.h"
37
#include "jbig2_generic.h"
38
#include "jbig2_image.h"
39
#include "jbig2_page.h"
40
#include "jbig2_refinement.h"
41
#include "jbig2_segment.h"
42
43
#define pixel_outside_field(x, y) \
44
0
    ((y) < -128 || (y) > 0 || (x) < -128 || ((y) < 0 && (x) > 127) || ((y) == 0 && (x) >= 0))
45
#define refpixel_outside_field(x, y) \
46
0
    ((y) < -128 || (y) > 127 || (x) < -128 || (x) > 127)
47
48
static int
49
jbig2_decode_refinement_template0_unopt(Jbig2Ctx *ctx,
50
                                        Jbig2Segment *segment,
51
                                        const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats)
52
0
{
53
0
    const int GRW = image->width;
54
0
    const int GRH = image->height;
55
0
    Jbig2Image *ref = params->GRREFERENCE;
56
0
    const int dx = params->GRREFERENCEDX;
57
0
    const int dy = params->GRREFERENCEDY;
58
0
    uint32_t CONTEXT;
59
0
    int x, y;
60
0
    int bit;
61
62
0
    if (pixel_outside_field(params->grat[0], params->grat[1]) ||
63
0
        refpixel_outside_field(params->grat[2], params->grat[3]))
64
0
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
65
0
                           "adaptive template pixel is out of field");
66
67
0
    for (y = 0; y < GRH; y++) {
68
0
        for (x = 0; x < GRW; x++) {
69
0
            CONTEXT = 0;
70
0
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y + 0) << 0;
71
0
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
72
0
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
73
0
            CONTEXT |= jbig2_image_get_pixel(image, x + params->grat[0], y + params->grat[1]) << 3;
74
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
75
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
76
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 1) << 6;
77
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 7;
78
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 8;
79
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 9;
80
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10;
81
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11;
82
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12;
83
0
            bit = jbig2_arith_decode(ctx, as, &GR_stats[CONTEXT]);
84
0
            if (bit < 0)
85
0
                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode arithmetic code when handling refinement template0");
86
0
            jbig2_image_set_pixel(image, x, y, bit);
87
0
        }
88
0
    }
89
#ifdef JBIG2_DEBUG_DUMP
90
    {
91
        static count = 0;
92
        char name[32];
93
        int code;
94
95
        snprintf(name, 32, "refin-%d.pbm", count);
96
        code = jbig2_image_write_pbm_file(ref, name);
97
        if (code < 0)
98
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed write refinement input");
99
        snprintf(name, 32, "refout-%d.pbm", count);
100
        code = jbig2_image_write_pbm_file(image, name);
101
        if (code < 0)
102
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed write refinement output");
103
        count++;
104
    }
105
#endif
106
107
0
    return 0;
108
0
}
109
110
static int
111
jbig2_decode_refinement_template1_unopt(Jbig2Ctx *ctx,
112
                                        Jbig2Segment *segment,
113
                                        const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats)
114
0
{
115
0
    const int GRW = image->width;
116
0
    const int GRH = image->height;
117
0
    Jbig2Image *ref = params->GRREFERENCE;
118
0
    const int dx = params->GRREFERENCEDX;
119
0
    const int dy = params->GRREFERENCEDY;
120
0
    uint32_t CONTEXT;
121
0
    int x, y;
122
0
    int bit;
123
124
0
    for (y = 0; y < GRH; y++) {
125
0
        for (x = 0; x < GRW; x++) {
126
0
            CONTEXT = 0;
127
0
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y + 0) << 0;
128
0
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
129
0
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
130
0
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 3;
131
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
132
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
133
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 6;
134
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7;
135
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8;
136
0
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9;
137
0
            bit = jbig2_arith_decode(ctx, as, &GR_stats[CONTEXT]);
138
0
            if (bit < 0)
139
0
                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode arithmetic code when handling refinement template0");
140
0
            jbig2_image_set_pixel(image, x, y, bit);
141
0
        }
142
0
    }
143
144
#ifdef JBIG2_DEBUG_DUMP
145
    {
146
        static count = 0;
147
        char name[32];
148
149
        snprintf(name, 32, "refin-%d.pbm", count);
150
        code = jbig2_image_write_pbm_file(ref, name);
151
        if (code < 0)
152
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to write refinement input");
153
        snprintf(name, 32, "refout-%d.pbm", count);
154
        code = jbig2_image_write_pbm_file(image, name);
155
        if (code < 0)
156
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to write refinement output");
157
        count++;
158
    }
159
#endif
160
161
0
    return 0;
162
0
}
163
164
#if 0                           /* currently not used */
165
static int
166
jbig2_decode_refinement_template1(Jbig2Ctx *ctx,
167
                                  Jbig2Segment *segment,
168
                                  const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats)
169
{
170
    const int GRW = image->width;
171
    const int GRH = image->height;
172
    const int stride = image->stride;
173
    const int refstride = params->reference->stride;
174
    const int dy = params->DY;
175
    byte *grreg_line = (byte *) image->data;
176
    byte *grref_line = (byte *) params->reference->data;
177
    int x, y;
178
179
    for (y = 0; y < GRH; y++) {
180
        const int padded_width = (GRW + 7) & -8;
181
        uint32_t CONTEXT;
182
        uint32_t refline_m1;    /* previous line of the reference bitmap */
183
        uint32_t refline_0;     /* current line of the reference bitmap */
184
        uint32_t refline_1;     /* next line of the reference bitmap */
185
        uint32_t line_m1;       /* previous line of the decoded bitmap */
186
187
        line_m1 = (y >= 1) ? grreg_line[-stride] : 0;
188
        refline_m1 = ((y - dy) >= 1) ? grref_line[(-1 - dy) * stride] << 2 : 0;
189
        refline_0 = (((y - dy) > 0) && ((y - dy) < GRH)) ? grref_line[(0 - dy) * stride] << 4 : 0;
190
        refline_1 = (y < GRH - 1) ? grref_line[(+1 - dy) * stride] << 7 : 0;
191
        CONTEXT = ((line_m1 >> 5) & 0x00e) | ((refline_1 >> 5) & 0x030) | ((refline_0 >> 5) & 0x1c0) | ((refline_m1 >> 5) & 0x200);
192
193
        for (x = 0; x < padded_width; x += 8) {
194
            byte result = 0;
195
            int x_minor;
196
            const int minor_width = GRW - x > 8 ? 8 : GRW - x;
197
198
            if (y >= 1) {
199
                line_m1 = (line_m1 << 8) | (x + 8 < GRW ? grreg_line[-stride + (x >> 3) + 1] : 0);
200
                refline_m1 = (refline_m1 << 8) | (x + 8 < GRW ? grref_line[-refstride + (x >> 3) + 1] << 2 : 0);
201
            }
202
203
            refline_0 = (refline_0 << 8) | (x + 8 < GRW ? grref_line[(x >> 3) + 1] << 4 : 0);
204
205
            if (y < GRH - 1)
206
                refline_1 = (refline_1 << 8) | (x + 8 < GRW ? grref_line[+refstride + (x >> 3) + 1] << 7 : 0);
207
            else
208
                refline_1 = 0;
209
210
            /* this is the speed critical inner-loop */
211
            for (x_minor = 0; x_minor < minor_width; x_minor++) {
212
                int bit;
213
214
                bit = jbig2_arith_decode(ctx, as, &GR_stats[CONTEXT]);
215
                if (bit < 0)
216
                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode arithmetic code when handling refinement template1");
217
                result |= bit << (7 - x_minor);
218
                CONTEXT = ((CONTEXT & 0x0d6) << 1) | bit |
219
                          ((line_m1 >> (9 - x_minor)) & 0x002) |
220
                          ((refline_1 >> (9 - x_minor)) & 0x010) | ((refline_0 >> (9 - x_minor)) & 0x040) | ((refline_m1 >> (9 - x_minor)) & 0x200);
221
            }
222
223
            grreg_line[x >> 3] = result;
224
225
        }
226
227
        grreg_line += stride;
228
        grref_line += refstride;
229
230
    }
231
232
    return 0;
233
234
}
235
#endif
236
237
typedef uint32_t(*ContextBuilder)(const Jbig2RefinementRegionParams *, Jbig2Image *, int, int);
238
239
static int
240
implicit_value(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int x, int y)
241
0
{
242
0
    Jbig2Image *ref = params->GRREFERENCE;
243
0
    int i = x - params->GRREFERENCEDX;
244
0
    int j = y - params->GRREFERENCEDY;
245
0
    int m = jbig2_image_get_pixel(ref, i, j);
246
247
0
    return ((jbig2_image_get_pixel(ref, i - 1, j - 1) == m) &&
248
0
            (jbig2_image_get_pixel(ref, i, j - 1) == m) &&
249
0
            (jbig2_image_get_pixel(ref, i + 1, j - 1) == m) &&
250
0
            (jbig2_image_get_pixel(ref, i - 1, j) == m) &&
251
0
            (jbig2_image_get_pixel(ref, i + 1, j) == m) &&
252
0
            (jbig2_image_get_pixel(ref, i - 1, j + 1) == m) &&
253
0
            (jbig2_image_get_pixel(ref, i, j + 1) == m) &&
254
0
            (jbig2_image_get_pixel(ref, i + 1, j + 1) == m)
255
0
           )? m : -1;
256
0
}
257
258
static uint32_t
259
mkctx0(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int x, int y)
260
0
{
261
0
    Jbig2Image *ref = params->GRREFERENCE;
262
0
    const int dx = params->GRREFERENCEDX;
263
0
    const int dy = params->GRREFERENCEDY;
264
0
    uint32_t CONTEXT;
265
266
0
    CONTEXT = jbig2_image_get_pixel(image, x - 1, y + 0);
267
0
    CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
268
0
    CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
269
0
    CONTEXT |= jbig2_image_get_pixel(image, x + params->grat[0], y + params->grat[1]) << 3;
270
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
271
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
272
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 1) << 6;
273
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 7;
274
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 8;
275
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 9;
276
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10;
277
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11;
278
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12;
279
0
    return CONTEXT;
280
0
}
281
282
static uint32_t
283
mkctx1(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int x, int y)
284
0
{
285
0
    Jbig2Image *ref = params->GRREFERENCE;
286
0
    const int dx = params->GRREFERENCEDX;
287
0
    const int dy = params->GRREFERENCEDY;
288
0
    uint32_t CONTEXT;
289
290
0
    CONTEXT = jbig2_image_get_pixel(image, x - 1, y + 0);
291
0
    CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
292
0
    CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
293
0
    CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 3;
294
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
295
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
296
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 6;
297
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7;
298
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8;
299
0
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9;
300
0
    return CONTEXT;
301
0
}
302
303
static int
304
jbig2_decode_refinement_TPGRON(Jbig2Ctx *ctx, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats)
305
0
{
306
0
    const int GRW = image->width;
307
0
    const int GRH = image->height;
308
0
    int x, y, iv, LTP = 0;
309
0
    uint32_t start_context = (params->GRTEMPLATE ? 0x40 : 0x100);
310
0
    ContextBuilder mkctx = (params->GRTEMPLATE ? mkctx1 : mkctx0);
311
312
0
    if (params->GRTEMPLATE == 0 &&
313
0
        (pixel_outside_field(params->grat[0], params->grat[1]) ||
314
0
        refpixel_outside_field(params->grat[2], params->grat[3])))
315
0
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER,
316
0
                           "adaptive template pixel is out of field");
317
318
0
    for (y = 0; y < GRH; y++) {
319
0
        int bit = jbig2_arith_decode(ctx, as, &GR_stats[start_context]);
320
0
        if (bit < 0)
321
0
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode arithmetic code when handling refinement TPGRON1");
322
0
        LTP ^= bit;
323
0
        if (!LTP) {
324
0
            for (x = 0; x < GRW; x++) {
325
0
                bit = jbig2_arith_decode(ctx, as, &GR_stats[mkctx(params, image, x, y)]);
326
0
                if (bit < 0)
327
0
                    return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode arithmetic code when handling refinement TPGRON1");
328
0
                jbig2_image_set_pixel(image, x, y, bit);
329
0
            }
330
0
        } else {
331
0
            for (x = 0; x < GRW; x++) {
332
0
                iv = implicit_value(params, image, x, y);
333
0
                if (iv < 0) {
334
0
                    int bit = jbig2_arith_decode(ctx, as, &GR_stats[mkctx(params, image, x, y)]);
335
0
                    if (bit < 0)
336
0
                        return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, JBIG2_UNKNOWN_SEGMENT_NUMBER, "failed to decode arithmetic code when handling refinement TPGRON1");
337
0
                    jbig2_image_set_pixel(image, x, y, bit);
338
0
                } else
339
0
                    jbig2_image_set_pixel(image, x, y, iv);
340
0
            }
341
0
        }
342
0
    }
343
344
0
    return 0;
345
0
}
346
347
/**
348
 * jbig2_decode_refinement_region: Decode a generic refinement region.
349
 * @ctx: The context for allocation and error reporting.
350
 * @segment: A segment reference for error reporting.
351
 * @params: Decoding parameter set.
352
 * @as: Arithmetic decoder state.
353
 * @image: Where to store the decoded image.
354
 * @GR_stats: Arithmetic stats.
355
 *
356
 * Decodes a generic refinement region, according to section 6.3.
357
 * an already allocated Jbig2Image object in @image for the result.
358
 *
359
 * Because this API is based on an arithmetic decoding state, it is
360
 * not suitable for MMR decoding.
361
 *
362
 * Return code: 0 on success.
363
 **/
364
int
365
jbig2_decode_refinement_region(Jbig2Ctx *ctx,
366
                               Jbig2Segment *segment,
367
                               const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats)
368
0
{
369
0
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
370
0
                "decoding generic refinement region with offset %d,%x, GRTEMPLATE=%d, TPGRON=%d",
371
0
                params->GRREFERENCEDX, params->GRREFERENCEDY, params->GRTEMPLATE, params->TPGRON);
372
373
0
    if (params->TPGRON)
374
0
        return jbig2_decode_refinement_TPGRON(ctx, params, as, image, GR_stats);
375
376
0
    if (params->GRTEMPLATE)
377
0
        return jbig2_decode_refinement_template1_unopt(ctx, segment, params, as, image, GR_stats);
378
0
    else
379
0
        return jbig2_decode_refinement_template0_unopt(ctx, segment, params, as, image, GR_stats);
380
0
}
381
382
/**
383
 * Find the first referred-to intermediate region segment
384
 * with a non-NULL result for use as a reference image
385
 */
386
static Jbig2Segment *
387
jbig2_region_find_referred(Jbig2Ctx *ctx, Jbig2Segment *segment)
388
0
{
389
0
    const int nsegments = segment->referred_to_segment_count;
390
0
    Jbig2Segment *rsegment;
391
0
    int index;
392
393
0
    for (index = 0; index < nsegments; index++) {
394
0
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
395
0
        if (rsegment == NULL) {
396
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to find referred to segment %d", segment->referred_to_segments[index]);
397
0
            continue;
398
0
        }
399
0
        switch (rsegment->flags & 63) {
400
0
        case 4:                /* intermediate text region */
401
0
        case 20:               /* intermediate halftone region */
402
0
        case 36:               /* intermediate generic region */
403
0
        case 40:               /* intermediate generic refinement region */
404
0
            if (rsegment->result)
405
0
                return rsegment;
406
0
            break;
407
0
        default:               /* keep looking */
408
0
            break;
409
0
        }
410
0
    }
411
    /* no appropriate reference was found. */
412
0
    return NULL;
413
0
}
414
415
/**
416
 * Handler for generic refinement region segments
417
 */
418
int
419
jbig2_refinement_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
420
0
{
421
0
    Jbig2RefinementRegionParams params;
422
0
    Jbig2RegionSegmentInfo rsi;
423
0
    int offset = 0;
424
0
    byte seg_flags;
425
0
    int code = 0;
426
427
    /* 7.4.7 */
428
0
    if (segment->data_length < 18)
429
0
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
430
431
0
    jbig2_get_region_segment_info(&rsi, segment_data);
432
0
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "generic region: %u x %u @ (%u, %u), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags);
433
434
    /* 7.4.7.2 */
435
0
    seg_flags = segment_data[17];
436
0
    params.GRTEMPLATE = seg_flags & 0x01;
437
0
    params.TPGRON = seg_flags & 0x02 ? 1 : 0;
438
0
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
439
0
                "segment flags = %02x %s%s", seg_flags, params.GRTEMPLATE ? " GRTEMPLATE" : "", params.TPGRON ? " TPGRON" : "");
440
0
    if (seg_flags & 0xFC)
441
0
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "reserved segment flag bits are non-zero");
442
0
    offset += 18;
443
444
    /* 7.4.7.3 */
445
0
    if (!params.GRTEMPLATE) {
446
0
        if (segment->data_length < 22)
447
0
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
448
0
        params.grat[0] = segment_data[offset + 0];
449
0
        params.grat[1] = segment_data[offset + 1];
450
0
        params.grat[2] = segment_data[offset + 2];
451
0
        params.grat[3] = segment_data[offset + 3];
452
0
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
453
0
                    "grat1: (%d, %d) grat2: (%d, %d)", params.grat[0], params.grat[1], params.grat[2], params.grat[3]);
454
0
        offset += 4;
455
0
    }
456
457
    /* 7.4.7.4 - set up the reference image */
458
0
    if (segment->referred_to_segment_count) {
459
0
        Jbig2Segment *ref;
460
461
0
        ref = jbig2_region_find_referred(ctx, segment);
462
0
        if (ref == NULL)
463
0
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to find reference bitmap");
464
0
        if (ref->result == NULL)
465
0
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "reference bitmap has no decoded image");
466
        /* the reference bitmap is the result of a previous
467
           intermediate region segment; the reference selection
468
           rules say to use the first one available, and not to
469
           reuse any intermediate result, so we simply take another
470
           reference to it and free the original to keep track of this. */
471
0
        params.GRREFERENCE = jbig2_image_reference(ctx, (Jbig2Image *) ref->result);
472
0
        jbig2_image_release(ctx, (Jbig2Image *) ref->result);
473
0
        ref->result = NULL;
474
0
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "found reference bitmap in segment %d", ref->number);
475
0
    } else {
476
        /* the reference is just (a subset of) the page buffer */
477
0
        if (ctx->pages[ctx->current_page].image == NULL)
478
0
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "reference page bitmap has no decoded image");
479
0
        params.GRREFERENCE = jbig2_image_reference(ctx, ctx->pages[ctx->current_page].image);
480
        /* TODO: subset the image if appropriate */
481
0
    }
482
483
    /* 7.4.7.5 */
484
0
    params.GRREFERENCEDX = 0;
485
0
    params.GRREFERENCEDY = 0;
486
0
    {
487
0
        Jbig2WordStream *ws = NULL;
488
0
        Jbig2ArithState *as = NULL;
489
0
        Jbig2ArithCx *GR_stats = NULL;
490
0
        int stats_size;
491
0
        Jbig2Image *image = NULL;
492
493
0
        image = jbig2_image_new(ctx, rsi.width, rsi.height);
494
0
        if (image == NULL) {
495
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate refinement image");
496
0
            goto cleanup;
497
0
        }
498
0
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, rsi.height);
499
500
0
        stats_size = params.GRTEMPLATE ? 1 << 10 : 1 << 13;
501
0
        GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
502
0
        if (GR_stats == NULL) {
503
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder state for generic refinement regions");
504
0
            goto cleanup;
505
0
        }
506
0
        memset(GR_stats, 0, stats_size);
507
508
0
        ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
509
0
        if (ws == NULL) {
510
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate word stream when handling refinement region");
511
0
            goto cleanup;
512
0
        }
513
514
0
        as = jbig2_arith_new(ctx, ws);
515
0
        if (as == NULL) {
516
0
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding state when handling refinement region");
517
0
            goto cleanup;
518
0
        }
519
520
0
        code = jbig2_decode_refinement_region(ctx, segment, &params, as, image, GR_stats);
521
0
        if (code < 0) {
522
0
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode refinement region");
523
0
            goto cleanup;
524
0
        }
525
526
0
        if ((segment->flags & 63) == 40) {
527
            /* intermediate region. save the result for later */
528
0
            segment->result = jbig2_image_reference(ctx, image);
529
0
        } else {
530
            /* immediate region. composite onto the page */
531
0
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
532
0
                        "composing %dx%d decoded refinement region onto page at (%d, %d)", rsi.width, rsi.height, rsi.x, rsi.y);
533
0
            code = jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, rsi.x, rsi.y, rsi.op);
534
0
            if (code < 0) {
535
0
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to add refinement region to page");
536
0
                goto cleanup;
537
0
            }
538
0
        }
539
540
0
cleanup:
541
0
        jbig2_image_release(ctx, image);
542
0
        jbig2_image_release(ctx, params.GRREFERENCE);
543
0
        jbig2_free(ctx->allocator, as);
544
0
        jbig2_word_stream_buf_free(ctx, ws);
545
0
        jbig2_free(ctx->allocator, GR_stats);
546
0
    }
547
548
0
    return code;
549
0
}