Coverage Report

Created: 2026-10-17 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/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
180k
    ((y) < -128 || (y) > 0 || (x) < -128 || ((y) < 0 && (x) > 127) || ((y) == 0 && (x) >= 0))
48
#define refpixel_outside_field(x, y) \
49
90.4k
    ((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
90.1k
{
56
90.1k
    const int64_t GRW = image->width;
57
90.1k
    const int64_t GRH = image->height;
58
90.1k
    Jbig2Image *ref = params->GRREFERENCE;
59
90.1k
    const int32_t dx = params->GRREFERENCEDX;
60
90.1k
    const int32_t dy = params->GRREFERENCEDY;
61
90.1k
    uint32_t CONTEXT;
62
90.1k
    int64_t x, y;
63
90.1k
    int bit;
64
65
90.1k
    if (pixel_outside_field(params->grat[0], params->grat[1]) ||
66
90.1k
        refpixel_outside_field(params->grat[2], params->grat[3]))
67
12
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
68
12
                           "adaptive template pixel is out of field");
69
70
1.77M
    for (y = 0; y < GRH; y++) {
71
109M
        for (x = 0; x < GRW; x++) {
72
107M
            CONTEXT = 0;
73
107M
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y + 0) << 0;
74
107M
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
75
107M
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
76
107M
            CONTEXT |= jbig2_image_get_pixel(image, x + params->grat[0], y + params->grat[1]) << 3;
77
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
78
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
79
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 1) << 6;
80
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 7;
81
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 8;
82
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 9;
83
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10;
84
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11;
85
107M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12;
86
107M
            bit = jbig2_arith_decode(ctx, as, &GR_stats[CONTEXT]);
87
107M
            if (bit < 0)
88
0
                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode arithmetic code when handling refinement template0");
89
107M
            jbig2_image_set_pixel(image, x, y, bit);
90
107M
        }
91
1.68M
    }
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
90.1k
    return 0;
111
90.1k
}
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
6.50k
{
118
6.50k
    const int64_t GRW = image->width;
119
6.50k
    const int64_t GRH = image->height;
120
6.50k
    Jbig2Image *ref = params->GRREFERENCE;
121
6.50k
    const int32_t dx = params->GRREFERENCEDX;
122
6.50k
    const int32_t dy = params->GRREFERENCEDY;
123
6.50k
    uint32_t CONTEXT;
124
6.50k
    int64_t x, y;
125
6.50k
    int bit;
126
127
16.8M
    for (y = 0; y < GRH; y++) {
128
247M
        for (x = 0; x < GRW; x++) {
129
231M
            CONTEXT = 0;
130
231M
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y + 0) << 0;
131
231M
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
132
231M
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
133
231M
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 3;
134
231M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
135
231M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
136
231M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 6;
137
231M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7;
138
231M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8;
139
231M
            CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9;
140
231M
            bit = jbig2_arith_decode(ctx, as, &GR_stats[CONTEXT]);
141
231M
            if (bit < 0)
142
0
                return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode arithmetic code when handling refinement template0");
143
231M
            jbig2_image_set_pixel(image, x, y, bit);
144
231M
        }
145
16.8M
    }
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
6.50k
    return 0;
166
6.50k
}
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
94.6M
{
246
94.6M
    Jbig2Image *ref = params->GRREFERENCE;
247
94.6M
    const int64_t i = x - params->GRREFERENCEDX;
248
94.6M
    const int64_t j = y - params->GRREFERENCEDY;
249
94.6M
    int m = jbig2_image_get_pixel(ref, i, j);
250
251
94.6M
    (void) image;
252
253
94.6M
    return ((jbig2_image_get_pixel(ref, i - 1, j - 1) == m) &&
254
94.2M
            (jbig2_image_get_pixel(ref, i, j - 1) == m) &&
255
94.1M
            (jbig2_image_get_pixel(ref, i + 1, j - 1) == m) &&
256
94.1M
            (jbig2_image_get_pixel(ref, i - 1, j) == m) &&
257
94.0M
            (jbig2_image_get_pixel(ref, i + 1, j) == m) &&
258
94.0M
            (jbig2_image_get_pixel(ref, i - 1, j + 1) == m) &&
259
94.0M
            (jbig2_image_get_pixel(ref, i, j + 1) == m) &&
260
94.0M
            (jbig2_image_get_pixel(ref, i + 1, j + 1) == m)
261
94.6M
           )? m : -1;
262
94.6M
}
263
264
static uint32_t
265
mkctx0(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int64_t x, int64_t y)
266
92.2M
{
267
92.2M
    Jbig2Image *ref = params->GRREFERENCE;
268
92.2M
    const int32_t dx = params->GRREFERENCEDX;
269
92.2M
    const int32_t dy = params->GRREFERENCEDY;
270
92.2M
    uint32_t CONTEXT;
271
272
92.2M
    CONTEXT = jbig2_image_get_pixel(image, x - 1, y + 0);
273
92.2M
    CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
274
92.2M
    CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
275
92.2M
    CONTEXT |= jbig2_image_get_pixel(image, x + params->grat[0], y + params->grat[1]) << 3;
276
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
277
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
278
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 1) << 6;
279
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 7;
280
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 8;
281
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 9;
282
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10;
283
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11;
284
92.2M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12;
285
92.2M
    return CONTEXT;
286
92.2M
}
287
288
static uint32_t
289
mkctx1(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int64_t x, int64_t y)
290
86.8M
{
291
86.8M
    Jbig2Image *ref = params->GRREFERENCE;
292
86.8M
    const int32_t dx = params->GRREFERENCEDX;
293
86.8M
    const int32_t dy = params->GRREFERENCEDY;
294
86.8M
    uint32_t CONTEXT;
295
296
86.8M
    CONTEXT = jbig2_image_get_pixel(image, x - 1, y + 0);
297
86.8M
    CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1;
298
86.8M
    CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2;
299
86.8M
    CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 3;
300
86.8M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4;
301
86.8M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5;
302
86.8M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 6;
303
86.8M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7;
304
86.8M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8;
305
86.8M
    CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9;
306
86.8M
    return CONTEXT;
307
86.8M
}
308
309
static int
310
jbig2_decode_refinement_TPGRON(Jbig2Ctx *ctx, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats)
311
484
{
312
484
    const int64_t GRW = image->width;
313
484
    const int64_t GRH = image->height;
314
484
    int64_t x, y;
315
484
    int iv, LTP = 0;
316
484
    uint32_t start_context = (params->GRTEMPLATE ? 0x40 : 0x100);
317
484
    ContextBuilder mkctx = (params->GRTEMPLATE ? mkctx1 : mkctx0);
318
319
484
    if (params->GRTEMPLATE == 0 &&
320
331
        (pixel_outside_field(params->grat[0], params->grat[1]) ||
321
326
        refpixel_outside_field(params->grat[2], params->grat[3])))
322
5
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, JBIG2_UNKNOWN_SEGMENT_NUMBER,
323
5
                           "adaptive template pixel is out of field");
324
325
22.1M
    for (y = 0; y < GRH; y++) {
326
22.1M
        int bit = jbig2_arith_decode(ctx, as, &GR_stats[start_context]);
327
22.1M
        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
22.1M
        LTP ^= bit;
330
22.1M
        if (!LTP) {
331
191M
            for (x = 0; x < GRW; x++) {
332
178M
                bit = jbig2_arith_decode(ctx, as, &GR_stats[mkctx(params, image, x, y)]);
333
178M
                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
178M
                jbig2_image_set_pixel(image, x, y, bit);
336
178M
            }
337
12.9M
        } else {
338
103M
            for (x = 0; x < GRW; x++) {
339
94.6M
                iv = implicit_value(params, image, x, y);
340
94.6M
                if (iv < 0) {
341
644k
                    int bit = jbig2_arith_decode(ctx, as, &GR_stats[mkctx(params, image, x, y)]);
342
644k
                    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
644k
                    jbig2_image_set_pixel(image, x, y, bit);
345
644k
                } else
346
94.0M
                    jbig2_image_set_pixel(image, x, y, iv);
347
94.6M
            }
348
9.15M
        }
349
22.1M
    }
350
351
479
    return 0;
352
479
}
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
97.1k
{
376
97.1k
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
377
97.1k
                "decoding generic refinement region with offset %d,%x, GRTEMPLATE=%d, TPGRON=%d",
378
97.1k
                params->GRREFERENCEDX, params->GRREFERENCEDY, params->GRTEMPLATE, params->TPGRON);
379
380
97.1k
    if (params->TPGRON)
381
484
        return jbig2_decode_refinement_TPGRON(ctx, params, as, image, GR_stats);
382
383
96.6k
    if (params->GRTEMPLATE)
384
6.50k
        return jbig2_decode_refinement_template1_unopt(ctx, segment, params, as, image, GR_stats);
385
90.1k
    else
386
90.1k
        return jbig2_decode_refinement_template0_unopt(ctx, segment, params, as, image, GR_stats);
387
96.6k
}
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
210
{
396
210
    const int nsegments = segment->referred_to_segment_count;
397
210
    Jbig2Segment *rsegment;
398
210
    int index;
399
400
4.15k
    for (index = 0; index < nsegments; index++) {
401
4.12k
        rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]);
402
4.12k
        if (rsegment == NULL) {
403
2.74k
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to find referred to segment %d", segment->referred_to_segments[index]);
404
2.74k
            continue;
405
2.74k
        }
406
1.37k
        switch (rsegment->flags & 63) {
407
748
        case 4:                /* intermediate text region */
408
753
        case 20:               /* intermediate halftone region */
409
753
        case 36:               /* intermediate generic region */
410
957
        case 40:               /* intermediate generic refinement region */
411
957
            if (rsegment->result)
412
183
                return rsegment;
413
774
            break;
414
774
        default:               /* keep looking */
415
419
            break;
416
1.37k
        }
417
1.37k
    }
418
    /* no appropriate reference was found. */
419
27
    return NULL;
420
210
}
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
858
{
428
858
    Jbig2RefinementRegionParams params;
429
858
    Jbig2RegionSegmentInfo rsi;
430
858
    int offset = 0;
431
858
    byte seg_flags;
432
858
    int code = 0;
433
434
    /* 7.4.7 */
435
858
    if (segment->data_length < 18)
436
8
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
437
438
850
    jbig2_get_region_segment_info(&rsi, segment_data);
439
850
    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
850
    seg_flags = segment_data[17];
443
850
    params.GRTEMPLATE = seg_flags & 0x01;
444
850
    params.TPGRON = seg_flags & 0x02 ? 1 : 0;
445
850
    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
446
850
                "segment flags = %02x %s%s", seg_flags, params.GRTEMPLATE ? " GRTEMPLATE" : "", params.TPGRON ? " TPGRON" : "");
447
850
    if (seg_flags & 0xFC)
448
455
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "reserved segment flag bits are non-zero");
449
850
    offset += 18;
450
451
    /* 7.4.7.3 */
452
850
    if (!params.GRTEMPLATE) {
453
516
        if (segment->data_length < 22)
454
3
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
455
513
        params.grat[0] = segment_data[offset + 0];
456
513
        params.grat[1] = segment_data[offset + 1];
457
513
        params.grat[2] = segment_data[offset + 2];
458
513
        params.grat[3] = segment_data[offset + 3];
459
513
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
460
513
                    "grat1: (%d, %d) grat2: (%d, %d)", params.grat[0], params.grat[1], params.grat[2], params.grat[3]);
461
513
        offset += 4;
462
513
    }
463
464
    /* 7.4.7.4 - set up the reference image */
465
847
    if (segment->referred_to_segment_count) {
466
210
        Jbig2Segment *ref;
467
468
210
        ref = jbig2_region_find_referred(ctx, segment);
469
210
        if (ref == NULL)
470
27
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to find reference bitmap");
471
183
        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
183
        params.GRREFERENCE = jbig2_image_reference(ctx, (Jbig2Image *) ref->result);
479
183
        jbig2_image_release(ctx, (Jbig2Image *) ref->result);
480
183
        ref->result = NULL;
481
183
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "found reference bitmap in segment %d", ref->number);
482
637
    } else {
483
        /* the reference is just (a subset of) the page buffer */
484
637
        if (ctx->pages[ctx->current_page].image == NULL)
485
4
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "reference page bitmap has no decoded image");
486
633
        params.GRREFERENCE = jbig2_image_reference(ctx, ctx->pages[ctx->current_page].image);
487
        /* TODO: subset the image if appropriate */
488
633
    }
489
490
    /* 7.4.7.5 */
491
816
    params.GRREFERENCEDX = 0;
492
816
    params.GRREFERENCEDY = 0;
493
816
    {
494
816
        Jbig2WordStream *ws = NULL;
495
816
        Jbig2ArithState *as = NULL;
496
816
        Jbig2ArithCx *GR_stats = NULL;
497
816
        int stats_size;
498
816
        Jbig2Image *image = NULL;
499
500
816
        image = jbig2_image_new(ctx, rsi.width, rsi.height);
501
816
        if (image == NULL) {
502
8
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate refinement image");
503
8
            goto cleanup;
504
8
        }
505
808
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, rsi.height);
506
507
808
        stats_size = params.GRTEMPLATE ? 1 << 10 : 1 << 13;
508
808
        GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
509
808
        if (GR_stats == NULL) {
510
1
            code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate arithmetic decoder state for generic refinement regions");
511
1
            goto cleanup;
512
1
        }
513
807
        memset(GR_stats, 0, stats_size);
514
515
807
        ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset);
516
807
        if (ws == NULL) {
517
1
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate word stream when handling refinement region");
518
1
            goto cleanup;
519
1
        }
520
521
806
        as = jbig2_arith_new(ctx, ws);
522
806
        if (as == NULL) {
523
2
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate arithmetic coding state when handling refinement region");
524
2
            goto cleanup;
525
2
        }
526
527
804
        code = jbig2_decode_refinement_region(ctx, segment, &params, as, image, GR_stats);
528
804
        if (code < 0) {
529
9
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to decode refinement region");
530
9
            goto cleanup;
531
9
        }
532
533
795
        if ((segment->flags & 63) == 40) {
534
            /* intermediate region. save the result for later */
535
205
            segment->result = jbig2_image_reference(ctx, image);
536
590
        } else {
537
            /* immediate region. composite onto the page */
538
590
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
539
590
                        "composing %dx%d decoded refinement region onto page at (%d, %d)", rsi.width, rsi.height, rsi.x, rsi.y);
540
590
            code = jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, rsi.x, rsi.y, rsi.op);
541
590
            if (code < 0) {
542
108
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to add refinement region to page");
543
108
                goto cleanup;
544
108
            }
545
590
        }
546
547
816
cleanup:
548
816
        jbig2_image_release(ctx, image);
549
816
        jbig2_image_release(ctx, params.GRREFERENCE);
550
816
        jbig2_free(ctx->allocator, as);
551
816
        jbig2_word_stream_buf_free(ctx, ws);
552
816
        jbig2_free(ctx->allocator, GR_stats);
553
816
    }
554
555
0
    return code;
556
795
}