1 /* Copyright (C) 2017-2018 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.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* PWGDecode filter */
18 #include "stdio_.h"		/* includes std.h */
19 #include "memory_.h"
20 #include "strimpl.h"
21 #include "spwgx.h"
22 
23 /* ------ RunLengthDecode ------ */
24 
25 private_st_PWGD_state();
26 
27 /* Set defaults */
28 static void
s_PWGD_set_defaults(stream_state * st)29 s_PWGD_set_defaults(stream_state * st)
30 {
31     stream_PWGD_state *const ss = (stream_PWGD_state *) st;
32 
33     (ss)->bpp = PWG_default_bpp;
34     (ss)->width = PWG_default_width;
35 }
36 
37 /* Initialize */
38 static int
s_PWGD_init(stream_state * st)39 s_PWGD_init(stream_state * st)
40 {
41     stream_PWGD_state *const ss = (stream_PWGD_state *) st;
42 
43     (ss)->line_pos = 0;
44     (ss)->line_rep = 0;
45     (ss)->state = 0;
46     (ss)->line_buffer = NULL;
47 
48     return 0;
49 }
50 
51 /* Refill the buffer */
52 static int
s_PWGD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)53 s_PWGD_process(stream_state * st, stream_cursor_read * pr,
54                stream_cursor_write * pw, bool last)
55 {
56     stream_PWGD_state *const ss = (stream_PWGD_state *) st;
57     register const byte *p = pr->ptr;
58     register byte *q = pw->ptr;
59     const byte *rlimit = pr->limit;
60     byte *wlimit = pw->limit;
61     int bpp = (ss->bpp+7)>>3;
62     int wb = ss->width * bpp;
63     int line_pos = ss->line_pos;
64 
65     if (ss->line_buffer == NULL) {
66         ss->line_buffer =
67                     gs_alloc_bytes_immovable(gs_memory_stable(ss->memory),
68                                              wb,
69                                              "s_PWGD_process(line_buffer)");
70         if (ss->line_buffer == NULL)
71             return ERRC;
72     }
73 
74     while (1) {
75         if (ss->state == 0) {
76             /* Copy any buffered data out */
77             if (ss->line_rep > 0) {
78                 int avail = wb - line_pos;
79                 if (avail > wlimit - q)
80                     avail = wlimit - q;
81                 if (avail != 0)
82                     memcpy(q+1, &ss->line_buffer[line_pos], avail);
83                 line_pos += avail;
84                 q += avail;
85                 if (line_pos == wb) {
86                     line_pos = 0;
87                     ss->line_rep--;
88                 }
89                 goto data_produced;
90             }
91             /* Now unpack data into the line buffer */
92             /* Awaiting line repeat value */
93             if (p == rlimit)
94                 goto need_data;
95             ss->line_rep = (*++p) + 1;
96             ss->state = 1; /* Wait for pixel repeat */
97         }
98         if (ss->state == 1) {
99             int rep;
100             /* Awaiting pixel repeat value */
101             if (p == rlimit)
102                 goto need_data;
103             rep = *++p;
104             if (rep < 0x80) {
105                 /* Repeat the next pixel multiple times */
106                 ss->state = (rep+1) * bpp + 1;
107                 if (line_pos + ss->state - 1 > wb)
108                     /* Too many repeats for this line! */
109                     goto error;
110             } else {
111                 /* Copy colors */
112                 ss->state = -(257 - rep) * bpp;
113                 if (line_pos + -ss->state > wb)
114                     /* Too many pixels for this line! */
115                     goto error;
116             }
117         }
118         if (ss->state > 1) {
119             /* Repeating a single pixel */
120             int pixel_pos = line_pos % bpp;
121             int avail = bpp - pixel_pos;
122             if (avail > rlimit - p)
123                 avail = rlimit - p;
124             if (avail != 0)
125                 memcpy(&ss->line_buffer[line_pos], p+1, avail);
126             p += avail;
127             line_pos += avail;
128             pixel_pos += avail;
129             ss->state -= avail;
130             if (pixel_pos != bpp)
131                 goto need_data;
132             while (ss->state > 1) {
133                 memcpy(&ss->line_buffer[line_pos], &ss->line_buffer[line_pos - bpp], bpp);
134                 line_pos += bpp;
135                 ss->state -= bpp;
136             }
137             if (line_pos == wb) {
138                 line_pos = 0;
139                 ss->state = 0;
140             } else
141                 ss->state = 1;
142         }
143         if (ss->state < 0) {
144             /* Copying literals */
145             int avail = -ss->state;
146             if (avail > rlimit - p)
147                 avail = rlimit - p;
148             memcpy(&ss->line_buffer[line_pos], p + 1, avail);
149             p += avail;
150             ss->state += avail;
151             line_pos += avail;
152             if (ss->state)
153                 goto need_data;
154             ss->state = 1;
155         }
156     }
157 need_data:
158     {
159         int status = 0; /* Need input data */
160         if (0) {
161 error:
162             status = ERRC;
163         } else if (0) {
164 data_produced:
165             status = 1; /* Need output space */
166         }
167         pr->ptr = p;
168         pw->ptr = q;
169         ss->line_pos = line_pos;
170         return status;
171     }
172 }
173 
174 static void
s_PWGD_release(stream_state * st)175 s_PWGD_release(stream_state * st)
176 {
177     stream_PWGD_state *const ss = (stream_PWGD_state *) st;
178 
179     gs_free_object(st->memory, ss->line_buffer, "PWGD(close)");
180     ss->line_buffer = NULL;
181 }
182 
183 /* Stream template */
184 const stream_template s_PWGD_template = {
185     &st_PWGD_state, s_PWGD_init, s_PWGD_process, 1, 1, s_PWGD_release,
186     s_PWGD_set_defaults
187 };
188