/src/ghostpdl/base/srle.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 | | /* RunLengthEncode filter */ |
18 | | #include "stdio_.h" /* includes std.h */ |
19 | | #include "memory_.h" |
20 | | #include "strimpl.h" |
21 | | #include "srlx.h" |
22 | | |
23 | | /* ------ RunLengthEncode ------ */ |
24 | | |
25 | | private_st_RLE_state(); |
26 | | |
27 | | /* Set defaults */ |
28 | | static void |
29 | | s_RLE_set_defaults(stream_state * st) |
30 | 241k | { |
31 | 241k | stream_RLE_state *const ss = (stream_RLE_state *) st; |
32 | | |
33 | 241k | s_RLE_set_defaults_inline(ss); |
34 | 241k | } |
35 | | |
36 | | /* Initialize */ |
37 | | static int |
38 | | s_RLE_init(stream_state * st) |
39 | 241k | { |
40 | 241k | stream_RLE_state *const ss = (stream_RLE_state *) st; |
41 | | |
42 | 241k | return s_RLE_init_inline(ss); |
43 | 241k | } |
44 | | |
45 | | enum { |
46 | | /* Initial state - Nothing read (but may be mid run). */ |
47 | | state_0, |
48 | | |
49 | | /* 0 bytes into a run, n0 read. */ |
50 | | state_eq_0, |
51 | | |
52 | | /* 0 bytes into a run, n0 and n1 read. */ |
53 | | state_eq_01, |
54 | | |
55 | | /* n bytes into a literal run, n0 and n1 read. */ |
56 | | state_gt_01, |
57 | | |
58 | | /* n bytes into a literal run, n0,n1,n2 read. */ |
59 | | state_gt_012, |
60 | | |
61 | | /* -n bytes into a repeated run, n0 and n1 read. */ |
62 | | state_lt_01, |
63 | | |
64 | | /* We have reached the end of data, but not written the marker. */ |
65 | | state_eod_unmarked, |
66 | | |
67 | | /* We have reached the end of data, and written the marker. */ |
68 | | state_eod |
69 | | }; |
70 | | |
71 | | #ifdef DEBUG_RLE |
72 | | static void |
73 | | debug_ate(const byte *p, const byte *plimit, |
74 | | const byte *q, const byte *qlimit, |
75 | | int ret) |
76 | | { |
77 | | if (p != plimit) { |
78 | | dlprintf("CONSUMED"); |
79 | | while (p != plimit) { |
80 | | dlprintf1(" %02x", *++p); |
81 | | } |
82 | | dlprintf("\n"); |
83 | | } |
84 | | if (q != qlimit) { |
85 | | dlprintf("PRODUCED\n"); |
86 | | while (q != qlimit) { |
87 | | int n = *++q; |
88 | | if (n == 128) { |
89 | | dlprintf1(" EOD(%02x)", n); |
90 | | } else if (n < 128) { |
91 | | dlprintf2(" %d(%02x)(", n+1, n); |
92 | | n++; |
93 | | while (n-- && q != qlimit) { |
94 | | dlprintf1(" %02x", *++q); |
95 | | } |
96 | | if (n != -1) { |
97 | | dlprintf1(" %d missing!", n+1); |
98 | | } |
99 | | dlprintf(" )\n"); |
100 | | } else { |
101 | | dlprintf2(" %d(%02x) - ", 257-n, n); |
102 | | if (q == qlimit) { |
103 | | dlprintf("WTF!"); |
104 | | } |
105 | | dlprintf1("%02x\n", *++q); |
106 | | } |
107 | | } |
108 | | dlprintf("\n"); |
109 | | } |
110 | | dlprintf1("RETURNED %d\n", ret); |
111 | | } |
112 | | #else |
113 | 3.88M | #define debug_ate(a,b,c,d,e) do { } while (0) |
114 | | #endif |
115 | | |
116 | | /* Process a buffer */ |
117 | | static int |
118 | | s_RLE_process(stream_state * st, stream_cursor_read * pr, |
119 | | stream_cursor_write * pw, bool last) |
120 | 3.88M | { |
121 | 3.88M | stream_RLE_state *const ss = (stream_RLE_state *) st; |
122 | 3.88M | register const byte *p = pr->ptr; |
123 | 3.88M | register byte *q = pw->ptr; |
124 | 3.88M | const byte *plimit = pr->limit; |
125 | 3.88M | byte *wlimit = pw->limit; |
126 | 3.88M | ulong rleft = ss->record_left; |
127 | 3.88M | int run_len = ss->run_len, ret = 0; |
128 | 3.88M | byte n0 = ss->n0; |
129 | 3.88M | byte n1 = ss->n1; |
130 | 3.88M | byte n2 = ss->n2; |
131 | 3.88M | const byte *rlimit = p + rleft; |
132 | | #ifdef DEBUG_RLE |
133 | | const byte *pinit = p; |
134 | | const byte *qinit = q; |
135 | | static int entry = -1; |
136 | | |
137 | | entry++; |
138 | | dlprintf7("ENTERED(%d): avail_in=%d avail_out=%d run_len=%d n0=%02x n1=%02x n2=%02x\n", |
139 | | entry, plimit-p, wlimit-q, run_len, n0, n1, n2); |
140 | | #endif |
141 | | |
142 | 3.88M | switch (ss->state) { |
143 | 0 | default: |
144 | 0 | dlprintf("Inconsistent state in s_RLE_process!\n"); |
145 | | /* fall through */ |
146 | 2.71M | case state_0: |
147 | 123M | while (p != plimit) { |
148 | 121M | if (run_len == 0) { |
149 | | /* About to start a new run */ |
150 | 812k | n0 = *++p; |
151 | 1.08M | case state_eq_0: |
152 | 3.90M | run_len_0_n0_read: |
153 | 3.90M | if (p == rlimit || (p == plimit && last)) { |
154 | | /* flush the record here, and restart */ |
155 | 181 | if (wlimit - q < 2){ |
156 | 71 | ss->state = state_eq_0; |
157 | | /* no_output_room_n0_read */ |
158 | 71 | goto no_output_room; |
159 | 71 | } |
160 | 110 | *++q = 0; /* Single literal */ |
161 | 110 | *++q = n0; |
162 | 110 | rlimit = p + ss->record_size; |
163 | 110 | continue; |
164 | 181 | } |
165 | 3.89M | if (p == plimit) { |
166 | 267k | ss->state = state_eq_0; |
167 | | /* no_more_data_n0_read */ |
168 | 267k | goto no_more_data; |
169 | 267k | } |
170 | 3.63M | n1 = *++p; |
171 | 3.63M | case state_eq_01: |
172 | 3.63M | if (p == rlimit || (p == plimit && last)) { |
173 | | /* flush the record here, and restart */ |
174 | 82.2k | if (wlimit - q < 3 - (n0 == n1)) { |
175 | 588 | ss->state = state_eq_01; |
176 | | /* no_output_room_n0n1_read */ |
177 | 588 | goto no_output_room; |
178 | 588 | } |
179 | 81.7k | if (n0 == n1) { |
180 | 25 | *++q = 0xff; /* Repeat 2 */ |
181 | 25 | *++q = n0; |
182 | 81.6k | } else { |
183 | 81.6k | *++q = 1; /* Two literals */ |
184 | 81.6k | *++q = n0; |
185 | 81.6k | *++q = n1; |
186 | 81.6k | } |
187 | 81.7k | run_len = 0; |
188 | 81.7k | rlimit = p + ss->record_size; |
189 | 81.7k | continue; |
190 | 82.2k | } |
191 | 3.54M | if (n0 == n1) { |
192 | | /* Start of a repeated run */ |
193 | 317k | run_len = -2; |
194 | 3.23M | } else { |
195 | | /* A literal run of at least 1. */ |
196 | 3.23M | run_len = 1; |
197 | 3.23M | ss->literals[0] = n0; |
198 | 3.23M | n0 = n1; |
199 | 3.23M | } |
200 | 3.54M | if (p == plimit) { |
201 | 105k | ss->state = state_0; |
202 | 105k | goto no_more_data; |
203 | 105k | } |
204 | 120M | } else if (run_len > 0) { |
205 | | /* We are in the middle of a run of literals */ |
206 | 94.2M | n1 = *++p; |
207 | 95.1M | case state_gt_01: |
208 | 95.1M | if (p == rlimit || run_len == 126 || |
209 | 95.1M | (n0 == n1 && p == plimit && last)) { |
210 | | /* flush the record here, and restart */ |
211 | | /* <len> <queue> n0 n1 */ |
212 | 586k | if (wlimit - q < run_len+3) { |
213 | 90.7k | ss->state = state_gt_01; |
214 | | /* no_output_room_gt_n0n1_read */ |
215 | 90.7k | goto no_output_room; |
216 | 90.7k | } |
217 | 496k | *++q = run_len+1; |
218 | 496k | memcpy(q+1, ss->literals, run_len); |
219 | 496k | q += run_len; |
220 | 496k | *++q = n0; |
221 | 496k | *++q = n1; |
222 | 496k | run_len = 0; |
223 | 496k | if (p == rlimit) |
224 | 0 | rlimit = p + ss->record_size; |
225 | 496k | continue; |
226 | 586k | } |
227 | 94.5M | if (n0 == n1) { |
228 | 5.16M | if (p == plimit) { |
229 | 895k | ss->state = state_gt_01; |
230 | | /* no_more_data_n0n1_read */ |
231 | 895k | goto no_more_data; |
232 | 895k | } |
233 | 4.27M | n2 = *++p; |
234 | 4.27M | case state_gt_012: |
235 | 4.27M | if (p == rlimit || run_len == 125) { |
236 | | /* flush the record here, and restart */ |
237 | | /* <len> <queue> n0 n1 n2 */ |
238 | 6.79k | if (wlimit - q < run_len+4) { |
239 | 1.13k | ss->state = state_gt_012; |
240 | | /* no_output_room_n0n1n2_read */ |
241 | 1.13k | goto no_output_room; |
242 | 1.13k | } |
243 | 5.65k | *++q = run_len+2; |
244 | 5.65k | memcpy(q+1, ss->literals, run_len); |
245 | 5.65k | q += run_len; |
246 | 5.65k | *++q = n0; |
247 | 5.65k | *++q = n1; |
248 | 5.65k | *++q = n2; |
249 | 5.65k | run_len = 0; |
250 | 5.65k | if (p == rlimit) |
251 | 0 | rlimit = p + ss->record_size; |
252 | 5.65k | continue; |
253 | 6.79k | } |
254 | 4.26M | if (n0 != n2) { |
255 | | /* Stick with a literal run */ |
256 | 1.62M | ss->literals[run_len++] = n0; |
257 | 1.62M | ss->literals[run_len++] = n1; |
258 | 1.62M | n0 = n2; |
259 | 2.63M | } else { |
260 | | /* Flush current run, start a repeated run */ |
261 | | /* <len> <queue> */ |
262 | 2.63M | if (wlimit - q < run_len+1) { |
263 | 43.7k | ss->state = state_gt_012; |
264 | | /* no_output_room_n0n1n2_read */ |
265 | 43.7k | goto no_output_room; |
266 | 43.7k | } |
267 | 2.59M | *++q = run_len-1; |
268 | 2.59M | memcpy(q+1, ss->literals, run_len); |
269 | 2.59M | q += run_len; |
270 | 2.59M | run_len = -3; /* Repeated run of length 3 */ |
271 | 2.59M | } |
272 | 89.3M | } else { |
273 | | /* Continue literal run */ |
274 | 89.3M | ss->literals[run_len++] = n0; |
275 | 89.3M | n0 = n1; |
276 | 89.3M | } |
277 | 94.5M | } else { |
278 | | /* We are in the middle of a repeated run */ |
279 | | /* <n0 repeated -run_len times> */ |
280 | 26.0M | n1 = *++p; |
281 | 26.0M | if (n0 == n1) |
282 | 23.2M | run_len--; /* Repeated run got longer */ |
283 | 26.0M | case state_lt_01: |
284 | 26.0M | if (n0 != n1 || p == rlimit || run_len == -128) { |
285 | | /* flush the record here, and restart */ |
286 | 2.90M | if (wlimit - q < 2) { |
287 | 13.9k | ss->state = state_lt_01; |
288 | | /* no_output_room_lt_n0n1_read */ |
289 | 13.9k | goto no_output_room; |
290 | 13.9k | } |
291 | 2.88M | *++q = 257+run_len; /* Repeated run */ |
292 | 2.88M | *++q = n0; |
293 | 2.88M | run_len = 0; |
294 | 2.88M | if (p == rlimit) |
295 | 0 | rlimit = p + ss->record_size; |
296 | 2.88M | if (n0 != n1) { |
297 | 2.81M | n0 = n1; |
298 | 2.81M | goto run_len_0_n0_read; |
299 | 2.81M | } |
300 | 2.88M | } |
301 | 26.0M | } |
302 | 121M | } |
303 | | /* n1 is never valid here */ |
304 | | |
305 | 2.46M | if (last) { |
306 | 90.8k | if (run_len == 0) { |
307 | | /* EOD */ |
308 | 81.9k | if (wlimit - q < 1) { |
309 | 249 | ss->state = state_0; |
310 | 249 | goto no_output_room; |
311 | 249 | } |
312 | 81.9k | } else if (run_len > 0) { |
313 | | /* Flush literal run + EOD */ |
314 | 1.79k | if (wlimit - q < run_len+2) { |
315 | 1.66k | ss->state = state_0; |
316 | 1.66k | goto no_output_room; |
317 | 1.66k | } |
318 | 130 | *++q = run_len; |
319 | 130 | memcpy(q+1, ss->literals, run_len); |
320 | 130 | q += run_len; |
321 | 130 | *++q = n0; |
322 | 7.16k | } else if (run_len < 0) { |
323 | | /* Flush repeated run + EOD */ |
324 | 7.16k | if (wlimit - q < 3) { |
325 | 1.09k | ss->state = state_0; |
326 | 1.09k | goto no_output_room; |
327 | 1.09k | } |
328 | 6.07k | *++q = 257+run_len; /* Repeated run */ |
329 | 6.07k | *++q = n0; |
330 | 6.07k | } |
331 | 87.8k | case state_eod_unmarked: |
332 | 87.8k | if (!ss->omitEOD) { |
333 | 87.8k | if (wlimit - q < 1) { |
334 | 20 | ss->state = state_eod_unmarked; |
335 | 20 | goto no_output_room; |
336 | 20 | } |
337 | 87.8k | *++q = 128; /* EOD */ |
338 | 87.8k | } |
339 | 87.8k | case state_eod: |
340 | 87.8k | ss->run_len = 0; |
341 | 87.8k | ss->state = state_0; |
342 | 87.8k | pr->ptr = p; |
343 | 87.8k | pw->ptr = q; |
344 | 87.8k | ss->record_left = rlimit - p; |
345 | 87.8k | debug_ate(pinit, p, qinit, q, EOFC); |
346 | 87.8k | return EOFC; |
347 | 87.8k | } |
348 | 3.88M | } |
349 | | |
350 | | /* Normal exit */ |
351 | 2.37M | ss->run_len = run_len; |
352 | 2.37M | ss->state = state_0; |
353 | 2.37M | ss->n0 = n0; |
354 | 2.37M | ss->n1 = n1; |
355 | 2.37M | pr->ptr = p; |
356 | 2.37M | pw->ptr = q; |
357 | 2.37M | ss->record_left = rlimit - p; |
358 | 2.37M | debug_ate(pinit, p, qinit, q, 0); |
359 | 2.37M | return 0; |
360 | | |
361 | 153k | no_output_room: |
362 | 153k | ret = 1; |
363 | 1.42M | no_more_data: |
364 | 1.42M | ss->n0 = n0; |
365 | 1.42M | ss->n1 = n1; |
366 | 1.42M | ss->n2 = n2; |
367 | 1.42M | ss->run_len = run_len; |
368 | 1.42M | pr->ptr = p; |
369 | 1.42M | pw->ptr = q; |
370 | 1.42M | ss->record_left = rlimit - p; |
371 | 1.42M | debug_ate(pinit, p, qinit, q, ret); |
372 | 1.42M | return ret; |
373 | 153k | } |
374 | | |
375 | | /* Stream template */ |
376 | | const stream_template s_RLE_template = { |
377 | | &st_RLE_state, s_RLE_init, s_RLE_process, 1, 129, NULL, |
378 | | s_RLE_set_defaults, s_RLE_init |
379 | | }; |