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