Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/scfe.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
/* CCITTFax encoding filter */
18
#include "stdio_.h"   /* includes std.h */
19
#include "memory_.h"
20
#include "gdebug.h"
21
#include "strimpl.h"
22
#include "scf.h"
23
#include "scfx.h"
24
25
/* ------ Macros and support routines ------ */
26
27
/* Statistics */
28
/* #define COLLECT_STATS_SCFE */
29
30
#ifdef COLLECT_STATS_SCFE
31
typedef struct stats_runs_s {
32
    ulong termination[64];
33
    ulong make_up[41];
34
} stats_runs_t;
35
static stats_runs_t stats_white_runs, stats_black_runs;
36
37
#define COUNT_RUN(tab, i) (tab)[i]++;
38
39
static void
40
print_run_stats(const gs_memory_t *mem, const stats_runs_t * stats)
41
{
42
    int i;
43
    ulong total;
44
45
    for (i = 0, total = 0; i < 41; i++)
46
        dmprintf1(mem, " %lu", stats->make_up[i]),
47
            total += stats->make_up[i];
48
    dmprintf1(mem, " total=%lu\n\t", total);
49
    for (i = 0, total = 0; i < 64; i++)
50
        dmprintf1(mem, " %lu", stats->termination[i]),
51
            total += stats->termination[i];
52
    dmprintf1(mem, " total=%lu\n", total);
53
}
54
55
#else /* !defined(COLLECT_STATS_SCFE) */
56
57
500M
#define COUNT_RUN(cnt, i) DO_NOTHING
58
59
#endif /* DEBUG */
60
61
/* Put a run onto the output stream. */
62
/* Free variables: q, bits, bits_left. */
63
64
471M
#define CF_PUT_RUN(ss, lenv, rt, stats)\
65
471M
BEGIN\
66
471M
    cfe_run rr;\
67
471M
\
68
471M
    if ( lenv >= 64 ) {\
69
24.2M
        hce_store_state();\
70
24.2M
        q = cf_put_long_run(ss, q, lenv, &rt);\
71
24.2M
        hce_load_state();\
72
24.2M
        lenv &= 63;\
73
24.2M
    }\
74
471M
    rr = rt.termination[lenv];\
75
471M
    COUNT_RUN(stats.termination, lenv);\
76
471M
    hc_put_value(ss, q, rr.code, rr.code_length);\
77
471M
END
78
79
static byte *
80
cf_put_long_run(stream_CFE_state * ss, byte * q, int lenv, const cf_runs * prt)
81
24.2M
{
82
24.2M
    hce_declare_state;
83
24.2M
    cfe_run rr;
84
85
#ifdef COLLECT_STATS_SCFE
86
    stats_runs_t *pstats =
87
    (prt == &cf_white_runs ? &stats_white_runs : &stats_black_runs);
88
#endif
89
90
24.2M
    hce_load_state();
91
28.3M
    while (lenv >= 2560 + 64) {
92
4.11M
        rr = prt->make_up[40];
93
4.11M
        COUNT_RUN(pstats->make_up, 40);
94
4.11M
        hc_put_value(ss, q, rr.code, rr.code_length);
95
4.11M
        lenv -= 2560;
96
4.11M
    }
97
24.2M
    rr = prt->make_up[lenv >> 6];
98
24.2M
    COUNT_RUN(pstats->make_up, lenv >> 6);
99
24.2M
    hc_put_value(ss, q, rr.code, rr.code_length);
100
24.2M
    hce_store_state();
101
24.2M
    return q;
102
24.2M
}
103
104
#define CF_PUT_WHITE_RUN(ss, lenv)\
105
243M
  CF_PUT_RUN(ss, lenv, cf_white_runs, stats_white_runs)
106
107
#define CF_PUT_BLACK_RUN(ss, lenv)\
108
228M
  CF_PUT_RUN(ss, lenv, cf_black_runs, stats_black_runs)
109
110
/* ------ CCITTFaxEncode ------ */
111
112
private_st_CFE_state();
113
114
static void s_CFE_release(stream_state *);
115
116
/* Set default parameter values. */
117
static void
118
s_CFE_set_defaults(register stream_state * st)
119
141k
{
120
141k
    stream_CFE_state *const ss = (stream_CFE_state *) st;
121
122
141k
    s_CFE_set_defaults_inline(ss);
123
141k
}
124
125
/* Initialize CCITTFaxEncode filter */
126
static int
127
s_CFE_init(register stream_state * st)
128
2.43M
{
129
2.43M
    stream_CFE_state *const ss = (stream_CFE_state *) st;
130
2.43M
    int columns = ss->Columns;
131
132
    /*
133
     * The worst case for encoding is alternating white and black pixels.
134
     * For 1-D encoding, the worst case is 9 bits per 2 pixels; for 2-D
135
     * (horizontal), 12 bits per 2 pixels. However, for 2D vertical encoding
136
     * an offset 3 vertically encoded requires 7 bits of encoding. So we need
137
     * to allow 14 bits for this, not 12 (see bug 696413). To fill out a scan line,
138
     * we may add up to 6 12-bit EOL codes.
139
     */
140
2.43M
    int code_bytes =
141
2.43M
    (((columns * (ss->K == 0 ? 9 : 14)) + 15) >> 4) + 20;  /* add slop */
142
2.43M
    int raster = ss->raster =
143
2.43M
        ROUND_UP((columns + 7) >> 3, ss->DecodedByteAlign);
144
145
2.43M
    s_hce_init_inline(ss);
146
2.43M
    ss->lbuf = ss->lprev = ss->lcode = 0; /* in case we have to release */
147
2.43M
    if (columns > cfe_max_width)
148
0
        return ERRC;
149
/****** WRONG ******/
150
    /* Because skip_white_pixels can look as many as 4 bytes ahead, */
151
    /* we need to allow 4 extra bytes at the end of the row buffers. */
152
2.43M
    ss->lbufstart = gs_alloc_bytes(st->memory, raster + 8, "CFE lbuf");
153
2.43M
    ss->lcode = gs_alloc_bytes(st->memory, code_bytes, "CFE lcode");
154
2.43M
    if (ss->lbufstart == 0 || ss->lcode == 0) {
155
0
        s_CFE_release(st);
156
0
        return ERRC;
157
/****** WRONG ******/
158
0
    }
159
2.43M
    ss->lbuf = ss->lbufstart + 4;
160
2.43M
    memset(ss->lbuf + raster, 0, 4); /* to pacify Valgrind */
161
2.43M
    if (ss->K != 0) {
162
2.42M
        ss->lprevstart = gs_alloc_bytes(st->memory, raster + 8, "CFE lprev");
163
2.42M
        if (ss->lprevstart == 0) {
164
0
            s_CFE_release(st);
165
0
            return ERRC;
166
/****** WRONG ******/
167
0
        }
168
2.42M
        ss->lprev = ss->lprevstart + 4;
169
        /* Clear the initial reference line for 2-D encoding. */
170
        /* Make sure it is terminated properly. */
171
2.42M
        memset(ss->lprev, (ss->BlackIs1 ? 0 : 0xff), raster + 4); /* +4 to pacify Valgrind */
172
2.42M
        if (columns & 7)
173
114k
            ss->lprev[raster - 1] ^= 0x80 >> (columns & 7);
174
2.31M
        else
175
2.31M
            ss->lprev[raster] = ~ss->lprev[0];
176
2.42M
    }
177
2.43M
    ss->read_count = raster;
178
2.43M
    ss->write_count = 0;
179
2.43M
    ss->k_left = (ss->K > 0 ? 1 : ss->K);
180
2.43M
    ss->max_code_bytes = code_bytes;
181
2.43M
    return 0;
182
2.43M
}
183
184
/* Release the filter. */
185
static void
186
s_CFE_release(stream_state * st)
187
2.43M
{
188
2.43M
    stream_CFE_state *const ss = (stream_CFE_state *) st;
189
190
2.43M
    gs_free_object(st->memory, ss->lprevstart, "CFE lprev(close)");
191
2.43M
    gs_free_object(st->memory, ss->lcode, "CFE lcode(close)");
192
2.43M
    gs_free_object(st->memory, ss->lbufstart, "CFE lbuf(close)");
193
2.43M
}
194
195
/* Flush the buffer */
196
static void cf_encode_1d(stream_CFE_state *, const byte *,
197
                          stream_cursor_write *);
198
static void cf_encode_2d(stream_CFE_state *, const byte *,
199
                          stream_cursor_write *, const byte *);
200
static int
201
s_CFE_process(stream_state * st, stream_cursor_read * pr,
202
              stream_cursor_write * pw, bool last)
203
195M
{
204
195M
    stream_CFE_state *const ss = (stream_CFE_state *) st;
205
195M
    const byte *rlimit = pr->limit;
206
195M
    byte *wlimit = pw->limit;
207
195M
    int raster = ss->raster;
208
195M
    byte end_mask = 1 << (-ss->Columns & 7);
209
195M
    int status = 0;
210
211
    /* Update the pointers we actually use, in case GC moved the buffer */
212
195M
    ss->lbuf = ss->lbufstart + 4;
213
195M
    ss->lprev = ss->lprevstart + 4;
214
215
276M
    for (;;) {
216
276M
        stream_cursor_write w;
217
218
276M
        if_debug2m('w', ss->memory, "[w]CFE: read_count = %d, write_count=%d,\n",
219
276M
                   ss->read_count, ss->write_count);
220
276M
        if_debug6m('w', ss->memory, "    pr = "PRI_INTPTR"(%d)"PRI_INTPTR", pw = "PRI_INTPTR"(%d)"PRI_INTPTR"\n",
221
276M
                   (intptr_t) pr->ptr, (int)(rlimit - pr->ptr), (intptr_t) rlimit,
222
276M
                   (intptr_t) pw->ptr, (int)(wlimit - pw->ptr), (intptr_t) wlimit);
223
276M
        if (ss->write_count) {
224
            /* Copy more of an encoded line to the caller. */
225
25.4M
            int wcount = wlimit - pw->ptr;
226
25.4M
            int ccount = min(wcount, ss->write_count);
227
228
25.4M
            memcpy(pw->ptr + 1, ss->lcode + ss->code_bytes - ss->write_count,
229
25.4M
                   ccount);
230
25.4M
            pw->ptr += ccount;
231
25.4M
            if ((ss->write_count -= ccount) > 0) {
232
337k
                status = 1;
233
337k
                break;
234
337k
            }
235
25.4M
        }
236
276M
        if (ss->read_count) {
237
            /* Copy more of an unencoded line from the caller. */
238
276M
            int rcount = rlimit - pr->ptr;
239
276M
            int ccount = min(rcount, ss->read_count);
240
241
276M
            if (rcount == 0 && last)
242
2.36M
                break;
243
274M
            memcpy(ss->lbuf + raster - ss->read_count,
244
274M
                   pr->ptr + 1, ccount);
245
274M
            pr->ptr += ccount;
246
274M
            if ((ss->read_count -= ccount) != 0)
247
193M
                break;
248
274M
        }
249
        /*
250
         * We have a full scan line in lbuf.  Ensure that it ends with
251
         * two polarity changes.
252
         */
253
80.8M
        {
254
80.8M
            byte *end = ss->lbuf + raster - 1;
255
80.8M
            byte end_bit = *end & end_mask;
256
80.8M
            byte not_bit = end_bit ^ end_mask;
257
258
80.8M
            *end &= -end_mask;
259
80.8M
            if (end_mask == 1)
260
70.8M
                end[1] = (end_bit ? 0x40 : 0x80);
261
9.95M
            else if (end_mask == 2)
262
924k
                *end |= not_bit >> 1, end[1] = end_bit << 7;
263
9.02M
            else
264
9.02M
                *end |= (not_bit >> 1) | (end_bit >> 2);
265
80.8M
        }
266
        /*
267
         * Write the output directly to the caller's buffer if it's large
268
         * enough, otherwise to our own buffer.
269
         */
270
80.8M
        if (wlimit - pw->ptr >= ss->max_code_bytes) {
271
18.8M
            w = *pw;
272
61.9M
        } else {
273
61.9M
            w.ptr = ss->lcode - 1;
274
61.9M
            w.limit = w.ptr + ss->max_code_bytes;
275
61.9M
        }
276
#ifdef DEBUG
277
        if (ss->K > 0) {
278
            if_debug2m('w', ss->memory, "[w2]new %d-D row, k_left=%d\n",
279
                       (ss->k_left == 1 ? 1 : 2), ss->k_left);
280
        } else {
281
            if_debug1m('w', ss->memory, "[w%d]new row\n", (ss->K < 0 ? 2 : 1));
282
        }
283
#endif
284
        /*
285
         * Write an EOL (actually a "beginning of line") if requested.
286
         */
287
80.8M
        if (ss->EndOfLine) {
288
15.1M
            const cfe_run *rp =
289
15.1M
            (ss->K <= 0 ? &cf_run_eol :
290
15.1M
             ss->k_left > 1 ? &cf2_run_eol_2d :
291
0
             &cf2_run_eol_1d);
292
15.1M
            cfe_run run;
293
294
15.1M
            hce_declare_state;
295
296
15.1M
            hce_load_state();
297
15.1M
            if (ss->EncodedByteAlign) {
298
0
                run = *rp;
299
                /* Pad the run on the left */
300
                /* so it winds up byte-aligned. */
301
0
                run.code_length +=
302
0
                    (bits_left - run_eol_code_length) & 7;
303
0
                if (run.code_length > 16) /* <= 23 */
304
0
                    bits_left -= run.code_length & 7,
305
0
                        run.code_length = 16;
306
0
                rp = &run;
307
0
            }
308
15.1M
            hc_put_code(ss, w.ptr, rp);
309
15.1M
            hce_store_state();
310
65.6M
        } else if (ss->EncodedByteAlign)
311
0
            ss->bits_left &= ~7;
312
        /* Encode the line. */
313
80.8M
        if (ss->K == 0)
314
15.1M
            cf_encode_1d(ss, ss->lbuf, &w);  /* pure 1-D */
315
65.6M
        else if (ss->K < 0)
316
65.6M
            cf_encode_2d(ss, ss->lbuf, &w, ss->lprev);  /* pure 2-D */
317
0
        else if (--(ss->k_left)) /* mixed, use 2-D */
318
0
            cf_encode_2d(ss, ss->lbuf, &w, ss->lprev);
319
0
        else {     /* mixed, use 1-D */
320
0
            cf_encode_1d(ss, ss->lbuf, &w);
321
0
            ss->k_left = ss->K;
322
0
        }
323
        /*
324
         * If we didn't write directly to the client's buffer, schedule
325
         * the output data to be written.
326
         */
327
80.8M
        if (w.limit == wlimit)
328
18.8M
            pw->ptr = w.ptr;
329
61.9M
        else
330
61.9M
            ss->write_count = ss->code_bytes = w.ptr - (ss->lcode - 1);
331
80.8M
        if (ss->K != 0) {
332
            /* In 2-D modes, swap the current and previous scan lines. */
333
65.6M
            byte *temp = ss->lbuf;
334
65.6M
            byte *temp1 = ss->lbufstart;
335
336
65.6M
            ss->lbuf = ss->lprev;
337
65.6M
            ss->lbufstart = ss->lprevstart;
338
65.6M
            ss->lprev = temp;
339
65.6M
            ss->lprevstart = temp1;
340
65.6M
        }
341
        /* Note that the input buffer needs refilling. */
342
80.8M
        ss->read_count = raster;
343
80.8M
    }
344
    /*
345
     * When we exit from the loop, we know that write_count = 0, and
346
     * there is no line waiting to be processed in the input buffer.
347
     */
348
195M
    if (last && status == 0) {
349
2.36M
        const cfe_run *rp =
350
2.36M
        (ss->K > 0 ? &cf2_run_eol_1d : &cf_run_eol);
351
2.36M
        int i = (!ss->EndOfBlock ? 0 : ss->K < 0 ? 2 : 6);
352
2.36M
        uint bits_to_write =
353
2.36M
        hc_bits_size - ss->bits_left + i * rp->code_length;
354
2.36M
        byte *q = pw->ptr;
355
356
2.36M
        hce_declare_state;
357
358
2.36M
        if (wlimit - q < (bits_to_write + 7) >> 3) {
359
217k
            status = 1;
360
217k
            goto out;
361
217k
        }
362
2.14M
        hce_load_state();
363
2.14M
        if (ss->EncodedByteAlign)
364
0
            bits_left &= ~7;
365
6.15M
        while (--i >= 0)
366
4.00M
            hc_put_code(ss, q, rp);
367
        /* Force out the last byte or bytes. */
368
2.14M
        pw->ptr = hc_put_last_bits((stream_hc_state *) ss, q);
369
2.14M
    }
370
195M
  out:
371
195M
    if_debug9m('w', ss->memory, "[w]CFE exit %d: read_count = %d, write_count = %d,\n"
372
195M
               "     pr = "PRI_INTPTR"(%d)"PRI_INTPTR"; pw = "PRI_INTPTR"(%d)"PRI_INTPTR"\n",
373
195M
               status, ss->read_count, ss->write_count,
374
195M
               (intptr_t) pr->ptr, (int)(rlimit - pr->ptr), (intptr_t) rlimit,
375
195M
               (intptr_t) pw->ptr, (int)(wlimit - pw->ptr), (intptr_t) wlimit);
376
#ifdef DEBUG
377
    if (pr->ptr > rlimit || pw->ptr > wlimit) {
378
        lprintf("Pointer overrun!\n");
379
        status = ERRC;
380
    }
381
#ifdef COLLECT_STATS_SCFE
382
    if (gs_debug_c('w') && status == 1) {
383
        dmlputs(ss->memory, "[w]white runs:");
384
        print_run_stats(ss->memory, &stats_white_runs);
385
        dmlputs(ss->memory, "[w]black runs:");
386
        print_run_stats(ss->memory, &stats_black_runs);
387
    }
388
#endif
389
#endif
390
195M
    return status;
391
195M
}
392
393
/* Encode a 1-D scan line. */
394
/* Attempt to stop coverity thinking skip_white_pixels() taints lbuf:*/
395
/* coverity[ -tainted_data_return ] */
396
/* coverity[ -tainted_data_argument arg-2 ] */
397
static void
398
cf_encode_1d(stream_CFE_state * ss, const byte * lbuf, stream_cursor_write * pw)
399
15.1M
{
400
15.1M
    uint count = ss->raster << 3;
401
15.1M
    byte *q = pw->ptr;
402
15.1M
    int end_count = -ss->Columns & 7;
403
15.1M
    int rlen;
404
405
15.1M
    hce_declare_state;
406
15.1M
    const byte *p = lbuf;
407
15.1M
    byte invert = (ss->BlackIs1 ? 0 : 0xff);
408
409
    /* Invariant: data = p[-1] ^ invert. */
410
15.1M
    uint data = *p++ ^ invert;
411
412
15.1M
    hce_load_state();
413
232M
    while (count != end_count) {
414
        /* Parse a white run. */
415
232M
        skip_white_pixels(data, p, count, invert, rlen);
416
232M
        CF_PUT_WHITE_RUN(ss, rlen);
417
232M
        if (count == end_count)
418
15.0M
            break;
419
        /* Parse a black run. */
420
232M
        skip_black_pixels(data, p, count, invert, rlen);
421
217M
        CF_PUT_BLACK_RUN(ss, rlen);
422
217M
    }
423
15.1M
    hce_store_state();
424
15.1M
    pw->ptr = q;
425
15.1M
}
426
427
/* Encode a 2-D scan line. */
428
/* coverity[ -tainted_data_argument : arg-1 ] */
429
static void
430
cf_encode_2d(stream_CFE_state * ss, const byte * lbuf, stream_cursor_write * pw,
431
             const byte * lprev)
432
65.6M
{
433
65.6M
    byte invert_white = (ss->BlackIs1 ? 0 : 0xff);
434
65.6M
    byte invert = invert_white;
435
65.6M
    uint count = ss->raster << 3;
436
65.6M
    int end_count = -ss->Columns & 7;
437
65.6M
    const byte *p = lbuf;
438
65.6M
    byte *q = pw->ptr;
439
65.6M
    uint data = *p++ ^ invert;
440
441
65.6M
    hce_declare_state;
442
    /*
443
     * In order to handle the nominal 'changing white' at the beginning of
444
     * each scan line, we need to suppress the test for an initial black bit
445
     * in the reference line when we are at the very beginning of the scan
446
     * line.  To avoid an extra test, we use two different mask tables.
447
     */
448
65.6M
    static const byte initial_count_bit[8] =
449
65.6M
    {
450
65.6M
        0, 1, 2, 4, 8, 0x10, 0x20, 0x40
451
65.6M
    };
452
65.6M
    static const byte further_count_bit[8] =
453
65.6M
    {
454
65.6M
        0x80, 1, 2, 4, 8, 0x10, 0x20, 0x40
455
65.6M
    };
456
65.6M
    const byte *count_bit = initial_count_bit;
457
458
65.6M
    hce_load_state();
459
347M
    while (count != end_count) {
460
        /*
461
         * If invert == invert_white, white and black have their
462
         * correct meanings; if invert == ~invert_white,
463
         * black and white are interchanged.
464
         */
465
281M
        uint a0 = count;
466
281M
        uint a1;
467
468
281M
#define b1 (a1 - diff)    /* only for printing */
469
281M
        int diff;
470
281M
        uint prev_count = count;
471
281M
        const byte *prev_p = p - lbuf + lprev;
472
281M
        byte prev_data = prev_p[-1] ^ invert;
473
281M
        int rlen;
474
475
        /* Find the a1 and b1 transitions. */
476
281M
        skip_white_pixels(data, p, count, invert, rlen);
477
281M
        a1 = count;
478
281M
        if ((prev_data & count_bit[prev_count & 7])) {
479
            /* Look for changing white first. */
480
35.7M
            skip_black_pixels(prev_data, prev_p, prev_count, invert, rlen);
481
35.7M
        }
482
281M
        count_bit = further_count_bit;  /* no longer at beginning */
483
286M
      pass:
484
286M
        if (prev_count != end_count)
485
286M
            skip_white_pixels(prev_data, prev_p, prev_count, invert, rlen);
486
286M
        diff = a1 - prev_count; /* i.e., logical b1 - a1 */
487
        /* In all the comparisons below, remember that count */
488
        /* runs downward, not upward, so the comparisons are */
489
        /* reversed. */
490
286M
        if (diff <= -2) {
491
            /* Could be a pass mode.  Find b2. */
492
11.0M
            if (prev_count != end_count)
493
11.0M
                skip_black_pixels(prev_data, prev_p,
494
11.0M
                                  prev_count, invert, rlen);
495
11.0M
            if (prev_count > a1) {
496
                /* Use pass mode. */
497
4.44M
                if_debug4m('W', ss->memory, "[W]pass: count = %d, a1 = %d, b1 = %d, new count = %d\n",
498
4.44M
                           a0, a1, b1, prev_count);
499
4.44M
                hc_put_value(ss, q, cf2_run_pass_value, cf2_run_pass_length);
500
4.44M
                a0 = prev_count;
501
4.44M
                goto pass;
502
4.44M
            }
503
11.0M
        }
504
        /* Check for vertical coding. */
505
281M
        if (diff <= 3 && diff >= -3) {
506
            /* Use vertical coding. */
507
271M
            const cfe_run *cp = &cf2_run_vertical[diff + 3];
508
509
271M
            if_debug5m('W', ss->memory, "[W]vertical %d: count = %d, a1 = %d, b1 = %d, new count = %d\n",
510
271M
                       diff, a0, a1, b1, count);
511
271M
            hc_put_code(ss, q, cp);
512
271M
            invert = ~invert; /* a1 polarity changes */
513
271M
            data ^= 0xff;
514
271M
            continue;
515
271M
        }
516
        /* No luck, use horizontal coding. */
517
10.5M
        if (count != end_count)
518
10.5M
            skip_black_pixels(data, p, count, invert, rlen); /* find a2 */
519
10.5M
        hc_put_value(ss, q, cf2_run_horizontal_value,
520
10.5M
                     cf2_run_horizontal_length);
521
10.5M
        a0 -= a1;
522
10.5M
        a1 -= count;
523
10.5M
        if (invert == invert_white) {
524
6.54M
            if_debug3m('W', ss->memory, "[W]horizontal: white = %d, black = %d, new count = %d\n",
525
6.54M
                      a0, a1, count);
526
6.54M
            CF_PUT_WHITE_RUN(ss, a0);
527
6.54M
            CF_PUT_BLACK_RUN(ss, a1);
528
6.54M
        } else {
529
4.03M
            if_debug3m('W', ss->memory, "[W]horizontal: black = %d, white = %d, new count = %d\n",
530
4.03M
                       a0, a1, count);
531
4.03M
            CF_PUT_BLACK_RUN(ss, a0);
532
4.03M
            CF_PUT_WHITE_RUN(ss, a1);
533
4.03M
#undef b1
534
4.03M
        }
535
10.5M
    }
536
65.6M
    hce_store_state();
537
65.6M
    pw->ptr = q;
538
65.6M
}
539
540
/* Stream template */
541
const stream_template s_CFE_template =
542
{
543
    &st_CFE_state, s_CFE_init, s_CFE_process, 1, 1,
544
    s_CFE_release, s_CFE_set_defaults
545
};