17dd7cddfSDavid du Colombier /* Copyright (C) 1995, 1996, 1997, 1998 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: srle.c,v 1.4 2002/02/21 22:24:54 giles Exp $ */
187dd7cddfSDavid du Colombier /* RunLengthEncode filter */
197dd7cddfSDavid du Colombier #include "stdio_.h" /* includes std.h */
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "strimpl.h"
227dd7cddfSDavid du Colombier #include "srlx.h"
237dd7cddfSDavid du Colombier
247dd7cddfSDavid du Colombier /* ------ RunLengthEncode ------ */
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier private_st_RLE_state();
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier /* Set defaults */
297dd7cddfSDavid du Colombier private void
s_RLE_set_defaults(stream_state * st)307dd7cddfSDavid du Colombier s_RLE_set_defaults(stream_state * st)
317dd7cddfSDavid du Colombier {
327dd7cddfSDavid du Colombier stream_RLE_state *const ss = (stream_RLE_state *) st;
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier s_RLE_set_defaults_inline(ss);
357dd7cddfSDavid du Colombier }
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier /* Initialize */
387dd7cddfSDavid du Colombier private int
s_RLE_init(stream_state * st)397dd7cddfSDavid du Colombier s_RLE_init(stream_state * st)
407dd7cddfSDavid du Colombier {
417dd7cddfSDavid du Colombier stream_RLE_state *const ss = (stream_RLE_state *) st;
427dd7cddfSDavid du Colombier
437dd7cddfSDavid du Colombier return s_RLE_init_inline(ss);
447dd7cddfSDavid du Colombier }
457dd7cddfSDavid du Colombier
467dd7cddfSDavid du Colombier /* Process a buffer */
477dd7cddfSDavid du Colombier private int
s_RLE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)487dd7cddfSDavid du Colombier s_RLE_process(stream_state * st, stream_cursor_read * pr,
497dd7cddfSDavid du Colombier stream_cursor_write * pw, bool last)
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier stream_RLE_state *const ss = (stream_RLE_state *) st;
527dd7cddfSDavid du Colombier register const byte *p = pr->ptr;
537dd7cddfSDavid du Colombier register byte *q = pw->ptr;
547dd7cddfSDavid du Colombier const byte *rlimit = pr->limit;
557dd7cddfSDavid du Colombier byte *wlimit = pw->limit;
567dd7cddfSDavid du Colombier int status = 0;
577dd7cddfSDavid du Colombier ulong rleft = ss->record_left;
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier /*
607dd7cddfSDavid du Colombier * We thought that the Genoa CET demands that the output from this
617dd7cddfSDavid du Colombier * filter be not just legal, but optimal, so we went to the trouble
627dd7cddfSDavid du Colombier * of ensuring this. It turned out that this wasn't actually
637dd7cddfSDavid du Colombier * necessary, but we didn't want to change the code back.
647dd7cddfSDavid du Colombier *
657dd7cddfSDavid du Colombier * For optimal output, we can't just break runs at buffer
667dd7cddfSDavid du Colombier * boundaries: unless we hit a record boundary or the end of the
677dd7cddfSDavid du Colombier * input, we have to look ahead far enough to know that we aren't
687dd7cddfSDavid du Colombier * breaking a run prematurely.
697dd7cddfSDavid du Colombier */
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier /* Check for leftover output. */
727dd7cddfSDavid du Colombier copy:
737dd7cddfSDavid du Colombier if (ss->copy_left) {
747dd7cddfSDavid du Colombier uint rcount = rlimit - p;
757dd7cddfSDavid du Colombier uint wcount = wlimit - q;
767dd7cddfSDavid du Colombier uint count = ss->copy_left;
777dd7cddfSDavid du Colombier
787dd7cddfSDavid du Colombier if (rcount < count)
797dd7cddfSDavid du Colombier count = rcount;
807dd7cddfSDavid du Colombier if (wcount < count)
817dd7cddfSDavid du Colombier count = wcount;
827dd7cddfSDavid du Colombier if (rleft < count)
837dd7cddfSDavid du Colombier count = rleft;
847dd7cddfSDavid du Colombier memcpy(q + 1, p + 1, count);
857dd7cddfSDavid du Colombier pr->ptr = p += count;
867dd7cddfSDavid du Colombier pw->ptr = q += count;
877dd7cddfSDavid du Colombier if ((ss->record_left = rleft -= count) == 0)
887dd7cddfSDavid du Colombier ss->record_left = rleft = ss->record_size;
897dd7cddfSDavid du Colombier if ((ss->copy_left -= count) != 0)
907dd7cddfSDavid du Colombier return (rcount == 0 ? 0 : 1);
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier while (p < rlimit) {
937dd7cddfSDavid du Colombier const byte *beg = p;
947dd7cddfSDavid du Colombier const byte *p1;
957dd7cddfSDavid du Colombier uint count = rlimit - p;
967dd7cddfSDavid du Colombier bool end = last;
977dd7cddfSDavid du Colombier byte next;
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier if (count > rleft)
1007dd7cddfSDavid du Colombier count = rleft, end = true;
1017dd7cddfSDavid du Colombier if (count > 128)
1027dd7cddfSDavid du Colombier count = 128, end = true;
1037dd7cddfSDavid du Colombier p1 = p + count - 1;
1047dd7cddfSDavid du Colombier if (count < 3) {
1057dd7cddfSDavid du Colombier if (!end || count == 0)
1067dd7cddfSDavid du Colombier break; /* can't look ahead far enough */
1077dd7cddfSDavid du Colombier if (count == 1) {
1087dd7cddfSDavid du Colombier if (wlimit - q < 2) {
1097dd7cddfSDavid du Colombier status = 1;
1107dd7cddfSDavid du Colombier break;
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier *++q = 0;
1137dd7cddfSDavid du Colombier } else { /* count == 2 */
1147dd7cddfSDavid du Colombier if (p[1] == p[2]) {
1157dd7cddfSDavid du Colombier if (wlimit - q < 2) {
1167dd7cddfSDavid du Colombier status = 1;
1177dd7cddfSDavid du Colombier break;
1187dd7cddfSDavid du Colombier }
1197dd7cddfSDavid du Colombier *++q = 255;
1207dd7cddfSDavid du Colombier } else {
1217dd7cddfSDavid du Colombier if (wlimit - q < 3) {
1227dd7cddfSDavid du Colombier status = 1;
1237dd7cddfSDavid du Colombier break;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier *++q = 1;
1267dd7cddfSDavid du Colombier *++q = p[1];
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier *++q = p1[1];
1307dd7cddfSDavid du Colombier p = p1 + 1;
1317dd7cddfSDavid du Colombier } else if ((next = p[1]) == p[2] && next == p[3]) {
1327dd7cddfSDavid du Colombier if (wlimit - q < 2) {
1337dd7cddfSDavid du Colombier status = 1;
1347dd7cddfSDavid du Colombier break;
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier /* Recognize leading repeated byte */
1377dd7cddfSDavid du Colombier do {
1387dd7cddfSDavid du Colombier p++;
1397dd7cddfSDavid du Colombier }
1407dd7cddfSDavid du Colombier while (p < p1 && p[2] == next);
1417dd7cddfSDavid du Colombier if (p == p1 && !end) {
1427dd7cddfSDavid du Colombier p = beg; /* need to look ahead further */
1437dd7cddfSDavid du Colombier break;
1447dd7cddfSDavid du Colombier }
1457dd7cddfSDavid du Colombier p++;
1467dd7cddfSDavid du Colombier *++q = (byte) (257 - (p - beg));
1477dd7cddfSDavid du Colombier *++q = next;
1487dd7cddfSDavid du Colombier } else {
1497dd7cddfSDavid du Colombier p1--;
1507dd7cddfSDavid du Colombier while (p < p1 && (p[2] != p[1] || p[3] != p[1]))
1517dd7cddfSDavid du Colombier p++;
1527dd7cddfSDavid du Colombier if (p == p1) {
1537dd7cddfSDavid du Colombier if (!end) {
1547dd7cddfSDavid du Colombier p = beg; /* need to look ahead further */
1557dd7cddfSDavid du Colombier break;
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier p += 2;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier count = p - beg;
1607dd7cddfSDavid du Colombier if (wlimit - q < count + 1) {
1617dd7cddfSDavid du Colombier p = beg;
1627dd7cddfSDavid du Colombier if (q >= wlimit) {
1637dd7cddfSDavid du Colombier status = 1;
1647dd7cddfSDavid du Colombier break;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier /* Copy some now and some later. */
1677dd7cddfSDavid du Colombier *++q = count - 1;
1687dd7cddfSDavid du Colombier ss->copy_left = count;
1697dd7cddfSDavid du Colombier goto copy;
1707dd7cddfSDavid du Colombier }
1717dd7cddfSDavid du Colombier *++q = count - 1;
1727dd7cddfSDavid du Colombier memcpy(q + 1, beg + 1, count);
1737dd7cddfSDavid du Colombier q += count;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier rleft -= p - beg;
1767dd7cddfSDavid du Colombier if (rleft == 0)
1777dd7cddfSDavid du Colombier rleft = ss->record_size;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier if (last && status == 0 && ss->EndOfData) {
1807dd7cddfSDavid du Colombier if (q < wlimit)
1817dd7cddfSDavid du Colombier *++q = 128;
1827dd7cddfSDavid du Colombier else
1837dd7cddfSDavid du Colombier status = 1;
1847dd7cddfSDavid du Colombier }
1857dd7cddfSDavid du Colombier pr->ptr = p;
1867dd7cddfSDavid du Colombier pw->ptr = q;
1877dd7cddfSDavid du Colombier ss->record_left = rleft;
1887dd7cddfSDavid du Colombier return status;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier
1917dd7cddfSDavid du Colombier /* Stream template */
1927dd7cddfSDavid du Colombier const stream_template s_RLE_template = {
1937dd7cddfSDavid du Colombier &st_RLE_state, s_RLE_init, s_RLE_process, 129, 2, NULL,
1947dd7cddfSDavid du Colombier s_RLE_set_defaults, s_RLE_init
1957dd7cddfSDavid du Colombier };
196