diff options
Diffstat (limited to 'gs/base/srld.c')
-rw-r--r-- | gs/base/srld.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/gs/base/srld.c b/gs/base/srld.c new file mode 100644 index 000000000..afbd4c809 --- /dev/null +++ b/gs/base/srld.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* RunLengthDecode filter */ +#include "stdio_.h" /* includes std.h */ +#include "memory_.h" +#include "strimpl.h" +#include "srlx.h" + +/* ------ RunLengthDecode ------ */ + +private_st_RLD_state(); + +/* Set defaults */ +static void +s_RLD_set_defaults(stream_state * st) +{ + stream_RLD_state *const ss = (stream_RLD_state *) st; + + s_RLD_set_defaults_inline(ss); +} + +/* Initialize */ +static int +s_RLD_init(stream_state * st) +{ + stream_RLD_state *const ss = (stream_RLD_state *) st; + + return s_RLD_init_inline(ss); +} + +/* Refill the buffer */ +static int +s_RLD_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * pw, bool last) +{ + stream_RLD_state *const ss = (stream_RLD_state *) st; + register const byte *p = pr->ptr; + register byte *q = pw->ptr; + const byte *rlimit = pr->limit; + byte *wlimit = pw->limit; + int left; + int status = 0; + +top: + if ((left = ss->copy_left) > 0) { + /* + * We suspended because the output buffer was full:; + * try again now. + */ + uint avail = wlimit - q; + int copy_status = 1; + + if (left > avail) + left = avail; + if (ss->copy_data >= 0) + memset(q + 1, ss->copy_data, left); + else { + avail = rlimit - p; + if (left >= avail) { + copy_status = 0; + left = avail; + } + memcpy(q + 1, p + 1, left); + p += left; + } + q += left; + if ((ss->copy_left -= left) > 0) { + status = copy_status; + goto x; + } + } + while (p < rlimit) { + int b = *++p; + + if (b < 128) { + if (++b > rlimit - p || b > wlimit - q) { + ss->copy_left = b; + ss->copy_data = -1; + goto top; + } + memcpy(q + 1, p + 1, b); + p += b; + q += b; + } else if (b == 128) { /* end of data */ + if (ss->EndOfData) { + status = EOFC; + break; + } + } else if (p == rlimit) { + p--; + break; + } else if ((b = 257 - b) > wlimit - q) { + ss->copy_left = b; + ss->copy_data = *++p; + goto top; + } else { + memset(q + 1, *++p, b); + q += b; + } + } +x: pr->ptr = p; + pw->ptr = q; + return status; +} + +/* Stream template */ +const stream_template s_RLD_template = { + &st_RLD_state, s_RLD_init, s_RLD_process, 1, 1, NULL, + s_RLD_set_defaults +}; |