1 /* Copyright (C) 2001-2012 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.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* RunLengthDecode filter */
18 #include "stdio_.h"		/* includes std.h */
19 #include "memory_.h"
20 #include "strimpl.h"
21 #include "srlx.h"
22 
23 /* ------ RunLengthDecode ------ */
24 
25 private_st_RLD_state();
26 
27 /* Set defaults */
28 static void
s_RLD_set_defaults(stream_state * st)29 s_RLD_set_defaults(stream_state * st)
30 {
31     stream_RLD_state *const ss = (stream_RLD_state *) st;
32 
33     s_RLD_set_defaults_inline(ss);
34 }
35 
36 /* Initialize */
37 static int
s_RLD_init(stream_state * st)38 s_RLD_init(stream_state * st)
39 {
40     stream_RLD_state *const ss = (stream_RLD_state *) st;
41 
42     return s_RLD_init_inline(ss);
43 }
44 
45 /* Refill the buffer */
46 static int
s_RLD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)47 s_RLD_process(stream_state * st, stream_cursor_read * pr,
48               stream_cursor_write * pw, bool last)
49 {
50     stream_RLD_state *const ss = (stream_RLD_state *) st;
51     register const byte *p = pr->ptr;
52     register byte *q = pw->ptr;
53     const byte *rlimit = pr->limit;
54     byte *wlimit = pw->limit;
55     int left;
56     int status = 0;
57 
58 top:
59     if ((left = ss->copy_left) > 0) {
60         /*
61          * We suspended because the output buffer was full:;
62          * try again now.
63          */
64         uint avail = wlimit - q;
65         int copy_status = 1;
66 
67         if (left > avail)
68             left = avail;
69         if (ss->copy_data >= 0)
70             memset(q + 1, ss->copy_data, left);
71         else {
72             avail = rlimit - p;
73             if (left >= avail) {
74                 copy_status = 0;
75                 left = avail;
76             }
77             memcpy(q + 1, p + 1, left);
78             p += left;
79         }
80         q += left;
81         if ((ss->copy_left -= left) > 0) {
82             status = copy_status;
83             goto x;
84         }
85     }
86     while (p < rlimit) {
87         int b = *++p;
88 
89         if (b < 128) {
90             if (++b > rlimit - p || b > wlimit - q) {
91                 ss->copy_left = b;
92                 ss->copy_data = -1;
93                 goto top;
94             }
95             memcpy(q + 1, p + 1, b);
96             p += b;
97             q += b;
98         } else if (b == 128) {	/* end of data */
99             if (ss->EndOfData) {
100                 status = EOFC;
101                 break;
102             }
103         } else if (p == rlimit) {
104             p--;
105             break;
106         } else if ((b = 257 - b) > wlimit - q) {
107             ss->copy_left = b;
108             ss->copy_data = *++p;
109             goto top;
110         } else {
111             memset(q + 1, *++p, b);
112             q += b;
113         }
114     }
115 x:  pr->ptr = p;
116     pw->ptr = q;
117     return status;
118 }
119 
120 /* Stream template */
121 const stream_template s_RLD_template = {
122     &st_RLD_state, s_RLD_init, s_RLD_process, 1, 1, NULL,
123     s_RLD_set_defaults
124 };
125