Coverage Report

Created: 2026-07-24 07:44

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