1 /* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved. 2 3 This file is part of AFPL Ghostscript. 4 5 AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or 6 distributor accepts any responsibility for the consequences of using it, or 7 for whether it serves any particular purpose or works at all, unless he or 8 she says so in writing. Refer to the Aladdin Free Public License (the 9 "License") for full details. 10 11 Every copy of AFPL Ghostscript must include a copy of the License, normally 12 in a plain ASCII text file named PUBLIC. The License grants you the right 13 to copy, modify and redistribute AFPL Ghostscript, but only under certain 14 conditions described in the License. Among other things, the License 15 requires that the copyright notice and this notice be preserved on all 16 copies. 17 */ 18 19 /*$Id: srle.c,v 1.2 2000/09/19 19:00:51 lpd Exp $ */ 20 /* RunLengthEncode filter */ 21 #include "stdio_.h" /* includes std.h */ 22 #include "memory_.h" 23 #include "strimpl.h" 24 #include "srlx.h" 25 26 /* ------ RunLengthEncode ------ */ 27 28 private_st_RLE_state(); 29 30 /* Set defaults */ 31 private void 32 s_RLE_set_defaults(stream_state * st) 33 { 34 stream_RLE_state *const ss = (stream_RLE_state *) st; 35 36 s_RLE_set_defaults_inline(ss); 37 } 38 39 /* Initialize */ 40 private int 41 s_RLE_init(stream_state * st) 42 { 43 stream_RLE_state *const ss = (stream_RLE_state *) st; 44 45 return s_RLE_init_inline(ss); 46 } 47 48 /* Process a buffer */ 49 private int 50 s_RLE_process(stream_state * st, stream_cursor_read * pr, 51 stream_cursor_write * pw, bool last) 52 { 53 stream_RLE_state *const ss = (stream_RLE_state *) st; 54 register const byte *p = pr->ptr; 55 register byte *q = pw->ptr; 56 const byte *rlimit = pr->limit; 57 byte *wlimit = pw->limit; 58 int status = 0; 59 ulong rleft = ss->record_left; 60 61 /* 62 * We thought that the Genoa CET demands that the output from this 63 * filter be not just legal, but optimal, so we went to the trouble 64 * of ensuring this. It turned out that this wasn't actually 65 * necessary, but we didn't want to change the code back. 66 * 67 * For optimal output, we can't just break runs at buffer 68 * boundaries: unless we hit a record boundary or the end of the 69 * input, we have to look ahead far enough to know that we aren't 70 * breaking a run prematurely. 71 */ 72 73 /* Check for leftover output. */ 74 copy: 75 if (ss->copy_left) { 76 uint rcount = rlimit - p; 77 uint wcount = wlimit - q; 78 uint count = ss->copy_left; 79 80 if (rcount < count) 81 count = rcount; 82 if (wcount < count) 83 count = wcount; 84 if (rleft < count) 85 count = rleft; 86 memcpy(q + 1, p + 1, count); 87 pr->ptr = p += count; 88 pw->ptr = q += count; 89 if ((ss->record_left = rleft -= count) == 0) 90 ss->record_left = rleft = ss->record_size; 91 if ((ss->copy_left -= count) != 0) 92 return (rcount == 0 ? 0 : 1); 93 } 94 while (p < rlimit) { 95 const byte *beg = p; 96 const byte *p1; 97 uint count = rlimit - p; 98 bool end = last; 99 byte next; 100 101 if (count > rleft) 102 count = rleft, end = true; 103 if (count > 128) 104 count = 128, end = true; 105 p1 = p + count - 1; 106 if (count < 3) { 107 if (!end || count == 0) 108 break; /* can't look ahead far enough */ 109 if (count == 1) { 110 if (wlimit - q < 2) { 111 status = 1; 112 break; 113 } 114 *++q = 0; 115 } else { /* count == 2 */ 116 if (p[1] == p[2]) { 117 if (wlimit - q < 2) { 118 status = 1; 119 break; 120 } 121 *++q = 255; 122 } else { 123 if (wlimit - q < 3) { 124 status = 1; 125 break; 126 } 127 *++q = 1; 128 *++q = p[1]; 129 } 130 } 131 *++q = p1[1]; 132 p = p1 + 1; 133 } else if ((next = p[1]) == p[2] && next == p[3]) { 134 if (wlimit - q < 2) { 135 status = 1; 136 break; 137 } 138 /* Recognize leading repeated byte */ 139 do { 140 p++; 141 } 142 while (p < p1 && p[2] == next); 143 if (p == p1 && !end) { 144 p = beg; /* need to look ahead further */ 145 break; 146 } 147 p++; 148 *++q = (byte) (257 - (p - beg)); 149 *++q = next; 150 } else { 151 p1--; 152 while (p < p1 && (p[2] != p[1] || p[3] != p[1])) 153 p++; 154 if (p == p1) { 155 if (!end) { 156 p = beg; /* need to look ahead further */ 157 break; 158 } 159 p += 2; 160 } 161 count = p - beg; 162 if (wlimit - q < count + 1) { 163 p = beg; 164 if (q >= wlimit) { 165 status = 1; 166 break; 167 } 168 /* Copy some now and some later. */ 169 *++q = count - 1; 170 ss->copy_left = count; 171 goto copy; 172 } 173 *++q = count - 1; 174 memcpy(q + 1, beg + 1, count); 175 q += count; 176 } 177 rleft -= p - beg; 178 if (rleft == 0) 179 rleft = ss->record_size; 180 } 181 if (last && status == 0 && ss->EndOfData) { 182 if (q < wlimit) 183 *++q = 128; 184 else 185 status = 1; 186 } 187 pr->ptr = p; 188 pw->ptr = q; 189 ss->record_left = rleft; 190 return status; 191 } 192 193 /* Stream template */ 194 const stream_template s_RLE_template = { 195 &st_RLE_state, s_RLE_init, s_RLE_process, 129, 2, NULL, 196 s_RLE_set_defaults, s_RLE_init 197 }; 198