1 /******************************************************************************
2 File: $Id: pclcomp.c,v 1.11 2000/10/07 17:51:57 Martin Rel $
3 Contents: Implementation of PCL compression routines
4 Author: Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
5 Germany. E-mail: Martin.Lottermoser@t-online.de.
6
7 *******************************************************************************
8 * *
9 * Copyright (C) 1996, 1997, 1998, 2000 by Martin Lottermoser *
10 * All rights reserved *
11 * *
12 *******************************************************************************
13
14 If you compile with NDEBUG defined, some runtime checks for programming
15 errors (mine and the interface's user's) are omitted.
16
17 ******************************************************************************/
18
19 /*****************************************************************************/
20
21 #ifndef _XOPEN_SOURCE
22 #define _XOPEN_SOURCE 500
23 #endif
24
25 /* Interface definition */
26 #include "pclgen.h"
27
28 /* Standard headers */
29 #include <assert.h>
30 #include <string.h>
31
32 /*****************************************************************************/
33
34 /* For TIFF compression, we need the two's complement representation of
35 numbers in the range [-127, -1], expressed in a 'pcl_Octet'.
36
37 The macro neg() must accept as an argument an 'int' expression with a value
38 in that range and convert it such that the result can be assigned to a
39 variable of type 'pcl_Octet' with the result that the value of the latter
40 becomes the two's complement representation of the number with respect to
41 256.
42
43 On most machines one can use a simple assignment. However, the C standard
44 specifies the behaviour in these cases (signed to unsigned where the source
45 has more bits than the target and the source value is negative) to be
46 implementation-defined. Hence the need for a portable solution.
47 Define PCLCOMP_NEG if you don't like it.
48 */
49
50 #ifdef PCLCOMP_NEG
51 #define neg(number) (number)
52 #else
53 #define neg(number) (256 + (number))
54 #endif
55
56 /******************************************************************************
57
58 Function: compress_runlength
59
60 This function performs runlength encoding.
61
62 Runlength encoding consists in preceding each octet by a repeat count octet
63 the value of which is one less than the repeat count.
64
65 'in' and 'incount' describe the row to be compressed, 'out' an area of at
66 least 'maxoutcount' octets to which the result is to be written. The function
67 returns the number of octets written or a negative value on error.
68
69 'incount' may be zero, in which case the values of the other arguments are
70 irrelevant. Otherwise, 'in' must be non-NULL, and if 'maxoutcount' is positive
71 'out' must be non-NULL as well.
72
73 ******************************************************************************/
74
compress_runlength(const pcl_Octet * in,int incount,pcl_Octet * out,int maxoutcount)75 static int compress_runlength(const pcl_Octet *in, int incount, pcl_Octet *out,
76 int maxoutcount)
77 {
78 int available = maxoutcount;
79
80 /* Here 'incount' is the number of octets to be encoded and 'in' points to
81 the first of them. 'available' is the number of octets available in the
82 output array and 'out' points to the first of them. */
83 while (incount > 0 && available > 1) {
84 int count = 0;
85
86 out++; /* skip repetition count octet, to be filled in later */
87 *out = *in;
88 do {
89 in++; incount--; count++;
90 } while (incount > 0 && *in == *out && count < 256);
91 *(out - 1) = count - 1;
92 out++; available -= 2;
93 }
94
95 if (incount > 0) return -1;
96 return maxoutcount - available;
97 }
98
99 /******************************************************************************
100
101 Function: compress_tiff
102
103 This function performs TIFF compression (compression method 2).
104
105 'in' and 'incount' describe the row to be compressed, 'out' an area of at
106 least 'maxoutcount' octets to which the result is to be written. The function
107 returns the number of octets written or a negative value on error.
108
109 'in' must be non-NULL, 'incount' must be positive, 'maxoutcount' must be
110 non-negative, and 'out' must be non-NULL is 'maxoutcount' is positive.
111
112 TIFF compression creates an octet stream consisting of three kinds of
113 octet sequences:
114 - an octet with value in the range [-127, -1] (two's complement)
115 followed by a single octet: this means the second octet is to be
116 repeated -<first octet>+1 times,
117 - an octet with value in the range [0, 127]: this means the next
118 <first octet>+1 octets have not been compressed,
119 - an octet with the value -128: this is a no-op and must be ignored.
120 The first octet determining the kind of sequence is called the "control
121 byte".
122
123 This routine generates an output string with a length which is minimal
124 for TIFF compression (if it doesn't, it's a bug). Readability of the code
125 and minimal execution speed were secondary considerations.
126
127 I have implemented this as a finite state machine. As can be seen from
128 the code, I sacrificed the rules of structured programming for this,
129 because I found a state transition diagram much more intelligible
130 than anything I could code. I then simply transferred it into C.
131
132 ******************************************************************************/
133
compress_tiff(const pcl_Octet * in,int incount,pcl_Octet * out,int maxoutcount)134 static int compress_tiff(const pcl_Octet *in, int incount, pcl_Octet *out,
135 int maxoutcount)
136 {
137 pcl_Octet
138 last; /* a remembered octet before the current 'in' value */
139 const pcl_Octet
140 *end = in + incount - 1; /* last position in 'in' */
141 int
142 available = maxoutcount, /* number of free octets left in 'out' */
143 repeated, /* repeat count during a compressed sequence */
144 stored; /* store count during a non-compressed sequence */
145
146 state1:
147 /* No octet is held over to be treated, 'in' points to the next one */
148 if (in == end) {
149 /* This is the last octet and a single one. */
150 if (available < 2) return -1;
151 *out = 0; out++; /* control byte */
152 *out = *in;
153 available -= 2;
154 goto finished;
155 }
156 last = *in; in++; /* Fetch one octet and remember it. */
157 /* to state2 */
158
159 /* state2: */
160 /* One octet to be treated is in 'last', 'in' points to the next. */
161 if (*in != last) {
162 if (available < 3) return -1;
163 out++; available--; /* Skip control byte to be filled in later */
164 stored = 0;
165 goto state4;
166 }
167 if (available < 2) return -1;
168 repeated = 2;
169 /* to state3 */
170
171 state3:
172 /* We have read 'repeated' occurrences of 'last', 'in' is positioned on
173 the last octet read. It is true that 2 <= repeated < 128 and
174 2 <= available. */
175 do {
176 if (in == end) break;
177 in++;
178 if (*in != last) break;
179 repeated++;
180 } while (repeated < 128);
181
182 /* Had to stop accumulating, for whatever reason. Write results. */
183 *out = neg(-repeated + 1); out++; /* control byte */
184 *out = last; out++;
185 available -= 2;
186
187 /* Decide where to go from here */
188 if (*in != last) goto state1;
189 if (in == end) goto finished;
190 in++;
191 goto state1;
192
193 state4:
194 /* We have read 'stored'+2 octets, 0 <= stored <= 126. All except the
195 last two have already been stored before the current value of 'out',
196 leaving space for the control byte at out[-stored-1]. The last two
197 octets can be found in 'last' and '*in', and they are not identical.
198 We also know that 'available' >= 2.
199 */
200 do {
201 *out = last; stored++; available--; out++;
202 if (in == end) {
203 *out = *in; stored++; available--;
204 out[-stored] = stored - 1; /* control byte */
205 goto finished;
206 }
207 if (available < 2) return -1;
208 last = *in;
209 in++;
210 } while (*in != last && stored <= 126);
211
212 if (*in == last) {
213 if (stored < 126) goto state5;
214 out[-stored-1] = stored - 1; /* control byte */
215 repeated = 2;
216 goto state3;
217 }
218
219 /* stored == 127, available >= 2 */
220 *out = last; stored++; available--; out++;
221 out[-stored-1] = stored - 1; /* control byte */
222 goto state1;
223
224 state5:
225 /* We have read 'stored'+2 octets, 'stored' < 126. 'stored' of them have
226 been stored before 'out' with the control byte still to be written to
227 out[-stored-1]. The last two octets can be found in 'last' and '*in',
228 and they are identical. We also know 2 <= available. */
229 if (in == end) {
230 *out = last; out++;
231 *out = *in;
232 stored += 2; available -= 2;
233 out[-stored] = stored - 1; /* control byte */
234 goto finished;
235 }
236 in++;
237 if (*in == last) {
238 out[-stored-1] = stored - 1; /* control byte */
239 repeated = 3;
240 goto state3;
241 }
242 if (available < 3) return -1;
243 *out = last; stored++; available--; out++; /* The first repeated octet */
244 goto state4;
245
246 finished:
247 return maxoutcount - available;
248 }
249
250 #undef neg
251
252 /******************************************************************************
253
254 Function: write_delta_replacement
255
256 This function writes a replacement string for delta compression (method 3),
257 i.e. the sequence of command byte, optional extension offset bytes, and the
258 replacement bytes.
259
260 'out' points to a sequence of at least 'available' octets to which the string
261 is to be written. 'reloffset' is the "left offset" value for the replacement.
262 'in' points to a sequence of 'replace_count' octets to be replaced.
263 'replace_count' must lie between 1 and 8, inclusive.
264
265 This function returns a negative value on error or the number of octets
266 written otherwise.
267
268 ******************************************************************************/
269
write_delta_replacement(pcl_Octet * out,int available,int reloffset,const pcl_Octet * in,int replace_count)270 static int write_delta_replacement(pcl_Octet *out, int available, int reloffset,
271 const pcl_Octet *in, int replace_count)
272 {
273 int used;
274 assert(1 <= replace_count && replace_count <= 8);
275
276 /* Prepare the command byte and, possibly, the extension offset bytes */
277 used = 1;
278 if (available < used) return -1;
279 *out = (replace_count - 1) << 5;
280 if (reloffset < 31) {
281 *out++ += reloffset;
282 }
283 else {
284 /* Large offset */
285 *out++ += 31;
286 reloffset -= 31;
287 used += reloffset/255 + 1;
288 if (available < used) return -1;
289 while (reloffset >= 255) {
290 *out++ = 255;
291 reloffset -= 255;
292 }
293 *out++ = reloffset;
294 }
295
296 /* Transfer the replacement bytes */
297 used += replace_count;
298 if (available < used) return -1;
299 while (replace_count > 0) {
300 *out++ = *in++;
301 replace_count--;
302 }
303
304 return used;
305 }
306
307 /******************************************************************************
308
309 Function: compress_delta
310
311 This function performs delta row compression (method 3).
312
313 The pairs (in, incount) and (prev, prevcount) describe the row to be
314 compressed and the row sent last (seed row), of course in uncompressed
315 form. (out, maxcount) refers to a storage area of 'maxoutcount' length to
316 which the compressed result for 'in' is to be written.
317 All three octet strings must be valid and any may be zero.
318
319 It is assumed that any difference in length between 'in' and 'prev' is
320 (logically) due to trailing zero octets having been suppressed in the shorter
321 of the two.
322
323 The function returns the number of octets written to 'out' (a zero value is
324 possible and refers to a row identical with the one sent last), or a negative
325 value on error.
326
327 ******************************************************************************/
328
329 /* First a macro needed several times for comparing old and new row.
330 Because we really need string substitution for the 'invalue', 'prevvalue'
331 and 'repstart' parameters this cannot be realized by a function.
332 This loop depends on the following variables external to it:
333 pos, absoffset, out, opos, maxoutcount.
334 */
335 #define delta_loop(bound, invalue, prevvalue, repstart) \
336 while (pos < bound) { \
337 if (invalue != prevvalue) { \
338 int reloffset = pos - absoffset; /* "left offset" */ \
339 absoffset = pos; /* first different octet */ \
340 \
341 /* Collect different octets, at most 8 */ \
342 do pos++; \
343 while (pos < bound && pos < absoffset + 8 && invalue != prevvalue); \
344 /* All the octets with positions in [absoffset, pos) have to */ \
345 /* be replaced, and there are at most 8 of them. */ \
346 \
347 /* Write the replacement string */ \
348 { \
349 int written; \
350 written = write_delta_replacement(out + opos, maxoutcount - opos, \
351 reloffset, repstart, pos - absoffset); \
352 if (written < 0) return -1; \
353 opos += written; \
354 } \
355 absoffset = pos; \
356 } \
357 else pos++; \
358 }
359
compress_delta(const pcl_Octet * in,int incount,const pcl_Octet * prev,int prevcount,pcl_Octet * out,int maxoutcount)360 static int compress_delta(const pcl_Octet *in, int incount,
361 const pcl_Octet *prev, int prevcount, pcl_Octet *out, int maxoutcount)
362 {
363 int
364 absoffset, /* absolute offset (starting with zero) */
365 mincount, /* min(incount, prevcount) */
366 opos, /* next position in the output */
367 pos; /* next position in the input rows */
368
369 /* Treat the special case of a zero output buffer (actually, the bad case is
370 merely the one where 'out' is NULL) */
371 if (maxoutcount == 0) {
372 if (incount == prevcount &&
373 (incount == 0 || memcmp(in, prev, incount) == 0)) return 0;
374 /* Can there be machines where memcmp() compares bits beyond those
375 used for the 'pcl_Octet's? Unlikely. */
376 return -1;
377 }
378
379 /* Initialization */
380 mincount = (incount < prevcount? incount: prevcount);
381 pos = 0; opos = 0;
382 absoffset = 0; /* first untreated octet, i.e. position after the last
383 unaltered octet. */
384
385 /* Loop over parts common to this and the last row */
386 delta_loop(mincount, in[pos], prev[pos], in + absoffset);
387 /* Note: This artificial separation at the 'mincount' position (logically,
388 both rows have equal length) is simpler to program but can result in
389 the compressed row being 1 octet longer than necessary. */
390
391 /* Treat length differences between 'in' and 'prev'. */
392 if (mincount < incount) {
393 /* We have to send all octets in the 'in' row which are non-zero. */
394 delta_loop(incount, in[pos], 0, in + absoffset);
395 }
396 else {
397 /* We have to replace all non-zero octets in the previous row. */
398 pcl_Octet zero_block[8] = {0, 0, 0, 0, 0, 0, 0, 0};
399 delta_loop(prevcount, 0, prev[pos], zero_block);
400 }
401 assert(opos <= maxoutcount);
402
403 return opos;
404 }
405
406 #undef delta_loop
407
408 /******************************************************************************
409
410 Function: write_crdr_header
411
412 This function writes the header for compressed replacement delta row encoding
413 (method 9). It returns the number of octets written or a negative value on
414 error.
415
416 ******************************************************************************/
417
write_crdr_header(pcl_bool compressed,pcl_Octet * out,int maxoutcount,int reloffset,int repcount)418 static int write_crdr_header(pcl_bool compressed, pcl_Octet *out,
419 int maxoutcount, int reloffset, int repcount)
420 {
421 int
422 maxvalue,
423 shift,
424 used = 1; /* command byte */
425
426 /* The command byte */
427 if (maxoutcount < 1) return -1;
428 if (compressed) *out = 0x80; /* control bit: compressed */
429 else *out = 0; /* control bit: uncompressed */
430 maxvalue = (compressed? 3: 15);
431 shift = (compressed? 5: 3);
432 if (reloffset < maxvalue) {
433 *out += reloffset << shift;
434 reloffset = -1;
435 }
436 else {
437 *out += maxvalue << shift;
438 reloffset -= maxvalue;
439 }
440 /* The value to be encoded for 'repcount' is different from 'repcount': */
441 if (compressed) repcount -= 2;
442 else repcount--;
443 assert(repcount >= 0);
444 maxvalue = (compressed? 31: 7);
445 if (repcount < maxvalue) {
446 *out += repcount;
447 repcount = -1;
448 }
449 else {
450 *out += maxvalue;
451 repcount -= maxvalue;
452 }
453 out++;
454
455 /* Optional offset bytes */
456 while (reloffset >= 0) {
457 if (used >= maxoutcount) return -1;
458 *out++ = (reloffset >= 255? 255: reloffset);
459 reloffset -= 255;
460 used++;
461 }
462
463 /* Optional replacement count bytes */
464 while (repcount >= 0) {
465 if (used >= maxoutcount) return -1;
466 *out++ = (repcount >= 255? 255: repcount);
467 repcount -= 255;
468 used++;
469 }
470
471 return used;
472 }
473
474 /******************************************************************************
475
476 Function: write_crdr_uncompressed
477
478 This function returns the number of octets written or a negative value on
479 error.
480
481 'in' may be NULL, indicating a sequence of 'repcount' null octets.
482 This case is practically irrelevant except for 'repcount' == 1.
483
484 ******************************************************************************/
485
write_crdr_uncompressed(pcl_Octet * out,int maxoutcount,int reloffset,const pcl_Octet * in,int repcount)486 static int write_crdr_uncompressed(pcl_Octet *out, int maxoutcount,
487 int reloffset, const pcl_Octet *in, int repcount)
488 {
489 int used = write_crdr_header(FALSE, out, maxoutcount, reloffset, repcount);
490 if (used < 0 || used + repcount > maxoutcount) return -1;
491
492 out += used;
493 if (in == NULL) memset(out, 0, repcount*sizeof(pcl_Octet));
494 else memcpy(out, in, repcount*sizeof(pcl_Octet));
495
496 return used + repcount;
497 }
498
499 /******************************************************************************
500
501 Function: write_crdr_compressed
502
503 This function returns the number of octets written or a negative value on
504 error.
505
506 ******************************************************************************/
507
write_crdr_compressed(pcl_Octet * out,int maxoutcount,int reloffset,pcl_Octet in,int repeat_count)508 static int write_crdr_compressed(pcl_Octet *out, int maxoutcount, int reloffset,
509 pcl_Octet in, int repeat_count)
510 {
511 int used = write_crdr_header(TRUE, out, maxoutcount, reloffset, repeat_count);
512 if (used < 0 || used >= maxoutcount) return -1;
513
514 out += used;
515 *out = in;
516
517 return used + 1;
518 }
519
520 /******************************************************************************
521
522 Function: write_crdr_replacement
523
524 This function returns the number of octets written to 'out' or a negative
525 value on error.
526
527 'in' may be NULL, indicating a sequence of 'repcount' null octets.
528 'repcount' must be positive.
529
530 ******************************************************************************/
531
write_crdr_replacement(pcl_Octet * out,int maxoutcount,int reloffset,const pcl_Octet * in,int repcount)532 static int write_crdr_replacement(pcl_Octet *out, int maxoutcount,
533 int reloffset, const pcl_Octet *in, int repcount)
534 {
535 const pcl_Octet *final;
536 int written = 0;
537
538 /* Treat the case of a null sequence */
539 if (in == NULL) {
540 if (repcount == 1)
541 return write_crdr_uncompressed(out, maxoutcount, reloffset, in, repcount);
542 return write_crdr_compressed(out, maxoutcount, reloffset, 0, repcount);
543 }
544
545 /* Loop over 'in', dividing it into sections at the boundaries of
546 sequences of repeated octets. */
547 final = in + repcount - 1;
548 while (repcount > 0) {
549 /* Advance 'bdup' over non-repeated octet */
550 const pcl_Octet *bdup;
551 bdup = in;
552 while (bdup < final && *bdup != *(bdup + 1)) bdup++;
553
554 /* If there is something either before a repeated section or before the
555 end, encode it uncompressed. */
556 if (in < bdup || bdup == final) {
557 int incount = (bdup == final? repcount: bdup - in);
558 int rc;
559 rc = write_crdr_uncompressed(out + written, maxoutcount - written,
560 reloffset, in, incount);
561 if (rc < 0) return rc;
562 written += rc;
563 reloffset = 0;
564 repcount -= incount;
565 if (repcount > 0) in += incount;
566 }
567
568 /* If we have encountered a repeated section, encode it compressed.
569 Note that the compressed version for a repetition is never longer than
570 the uncompressed one, not even for a repeat count of 2, although in this
571 case it might have equal length depending on the offset. */
572 if (bdup < final) {
573 const pcl_Octet *edup = bdup + 1;
574 int incount, rc;
575 while (edup < final && *(edup + 1) == *bdup) edup++;
576 incount = edup - bdup + 1;
577 rc = write_crdr_compressed(out + written, maxoutcount - written,
578 reloffset, *bdup, incount);
579 if (rc < 0) return rc;
580 written += rc;
581 reloffset = 0;
582 repcount -= incount;
583 if (repcount > 0) in = edup + 1;
584 }
585 }
586
587 return written;
588 }
589
590 /******************************************************************************
591
592 Function: compress_crdr
593
594 This function performs compressed replacement delta row encoding (compression
595 method 9).
596
597 The pairs (in, incount) and (prev, prevcount) describe the row to be
598 compressed and the row sent last (seed row), of course in uncompressed
599 form. (out, maxcount) refers to a storage area of 'maxoutcount' length to
600 which the compressed result for 'in' is to be written.
601 All three octet strings must be valid and any may be zero.
602
603 It is assumed that any difference in length between 'in' and 'prev' is
604 (logically) due to trailing zero octets having been suppressed in the shorter
605 of the two.
606
607 The function returns the number of octets written to 'out' (a zero value is
608 possible and refers to a row identical with the one sent last), or a negative
609 value on error.
610
611 This function and those it calls are very similar to the functions for delta
612 row compression.
613
614 ******************************************************************************/
615
616 /* Again, as for delta row compression, I'm using a macro for comparison. */
617 #define crdr_loop(bound, invalue, prevvalue, repstart) \
618 while (pos < bound) { \
619 if (invalue == prevvalue) pos++; \
620 else { \
621 int reloffset = pos - absoffset, written; \
622 absoffset = pos; \
623 do pos++; while (pos < bound && invalue != prevvalue); \
624 \
625 written = write_crdr_replacement(out + opos, maxoutcount - opos, \
626 reloffset, repstart, pos - absoffset); \
627 if (written < 0) return written; \
628 absoffset = pos; \
629 opos += written; \
630 } \
631 }
632
compress_crdr(const pcl_Octet * in,int incount,const pcl_Octet * prev,int prevcount,pcl_Octet * out,int maxoutcount)633 static int compress_crdr(const pcl_Octet *in, int incount,
634 const pcl_Octet *prev, int prevcount, pcl_Octet *out, int maxoutcount)
635 {
636 int
637 absoffset = 0,
638 mincount = (incount < prevcount? incount: prevcount),
639 opos = 0,
640 pos = 0;
641
642 /* Treat the special case of a zero output buffer (again, the bad case is
643 merely the one where 'out' is NULL) */
644 if (maxoutcount == 0) {
645 if (incount == prevcount &&
646 (incount == 0 || memcmp(in, prev, incount) == 0)) return 0;
647 return -1;
648 }
649
650 crdr_loop(mincount, in[pos], prev[pos], in + absoffset);
651 if (mincount < incount) {
652 crdr_loop(incount, in[pos], 0, in + absoffset);
653 }
654 else {
655 crdr_loop(prevcount, 0, prev[pos], NULL);
656 }
657
658 return opos;
659 }
660
661 #undef crdr_loop
662
663 /******************************************************************************
664
665 Function: pcl_compress
666
667 This function compresses an octet string using the compression algorithm
668 specified by 'method'.
669
670 The arguments 'in' and 'out' must be non-NULL. They point to the data to be
671 compressed ('in->length' octets starting at 'in->str') and the area to which
672 the compressed result should be written (at most 'out->length' octets
673 starting at 'out->str'). If '*in' and '*out' are both non-zero (see
674 definitions above), their storage areas ('in->str' to
675 'in->str + in->length - 1' and 'out->str' to 'out->str + out->length - 1')
676 should not overlap.
677
678 If 'method' refers to a method entailing "vertical" compression, i.e.
679 compression with respect to an octet string previously sent, 'prev' must
680 point to this previous string. This is the case for methods 3 and 9.
681 The variable is ignored otherwise and may be NULL. If it is needed, it should
682 not overlap with the storage area of '*out'.
683
684 The function returns a non-zero value in case of insufficient space in '*out'.
685 In that situation, part of 'out->str' may have been overwritten already.
686 Otherwise, a value of zero is returned and 'out->length' is set to the number
687 of octets the compressed result occupies in 'out->str'.
688
689 ******************************************************************************/
690
691 /* Test macro for an argument of type "pcl_OctetString *" */
692 #define is_valid(s) \
693 (s != NULL && ((s)->length == 0 || ((s)->length > 0 && (s)->str != NULL)))
694
pcl_compress(pcl_Compression method,const pcl_OctetString * in,const pcl_OctetString * prev,pcl_OctetString * out)695 int pcl_compress(pcl_Compression method, const pcl_OctetString *in,
696 const pcl_OctetString *prev, pcl_OctetString *out)
697 {
698 int result = -1;
699
700 /* Prevent silly mistakes with the arguments */
701 assert((is_valid(in) && is_valid(out) &&
702 method != pcl_cm_delta && method != pcl_cm_crdr) || is_valid(prev));
703
704 /* Treat zero-length case for the "purely horizontal" methods */
705 if (in->length == 0 && method != pcl_cm_delta && method != pcl_cm_crdr) {
706 out->length = 0;
707 return 0;
708 }
709
710 switch (method) {
711 case pcl_cm_none: /* oh, well... */
712 if (out->length <= in->length) {
713 memcpy(out->str, in->str, in->length*sizeof(pcl_Octet));
714 result = in->length;
715 }
716 break;
717 case pcl_cm_rl:
718 result = compress_runlength(in->str, in->length, out->str, out->length);
719 break;
720 case pcl_cm_tiff:
721 result = compress_tiff(in->str, in->length, out->str, out->length);
722 break;
723 case pcl_cm_delta:
724 result = compress_delta(in->str, in->length, prev->str, prev->length,
725 out->str, out->length);
726 break;
727 case pcl_cm_crdr:
728 result = compress_crdr(in->str, in->length, prev->str, prev->length,
729 out->str, out->length);
730 break;
731 default:
732 assert(0); /* Illegal value for compression method */
733 /* If NDEBUG is defined, we fall through with the default value for
734 'result' which is -1, i.e., failure. */
735 }
736
737 /* Assign the length of the output octet string */
738 if (result >= 0) {
739 out->length = result;
740 result = 0;
741 }
742
743 return result;
744 }
745