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