1 /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: genht.c,v 1.5 2005/10/04 06:30:02 ray Exp $ */
18 /* Generate C code for compiling halftones into ROM. */
19 #include "malloc_.h"
20 #include "stdio_.h"
21 #include "string_.h"
22 #include "gscdefs.h"
23 #include "gsmemory.h"
24 #include "gxbitmap.h"
25 #include "gxhttile.h"
26 #include "gxtmap.h"
27 #include "gxdht.h"
28 #include "gxdhtres.h"
29 #include "strimpl.h"
30 #include "sstring.h"
31
32 /*
33 * This program translates PostScript halftone resources into C data
34 * structures that can then be compiled into executables and put in shared,
35 * read-only memory. The syntax of the resource file is a subset of
36 * PostScript, tightly constrained so that it can be parsed easily. Blank
37 * lines and PostScript comments are ignored, but otherwise each halftone
38 * in the file (there may be more than one) must follow this format,
39 * where ... indicates arbitrary text:
40 (optionally:)
41 /halftone_name ...
42 /HalftoneType 5
43 (zero or more times:)
44 /halftone_name ...
45 /HalftoneType 3
46 /Width xxx
47 /Height xxx
48 /Thresholds ...
49 --hex data terminated by a >--
50 (zero or more times:)
51 /halftone_name 1 index
52 (finally)
53 ... defineresource
54 * Lines that don't follow the above syntax may appear anywhere in the file
55 * except in the middle of the hex data. Width and Height must precede
56 * Thresholds, but otherwise the 4 parameters may appear in any order.
57 * White space at the beginning or end of a line is ignored, and any
58 * amount of white space may separate the parameter name from its value.
59 *
60 * We envision that this format will eventually be extended to cover
61 * HalftoneType 16 halftones with a single rectangle, allowing 16-bit
62 * threshold values.
63 */
64
65 /* Read a source file into memory. */
66 private char *
read_file(FILE * in,char * cname)67 read_file(FILE *in, char *cname)
68 {
69 int len, nread;
70 char *cont;
71
72 fseek(in, 0L, 2 /*SEEK_END*/);
73 len = ftell(in);
74 cont = malloc(len + 1);
75 if (cont == 0) {
76 fprintf(stderr, "Can't allocate %d bytes to read %s.\n",
77 len + 1, cname);
78 return 0;
79 }
80 rewind(in);
81 nread = fread(cont, 1, len, in);
82 cont[nread] = 0;
83 return cont;
84 }
85
86 /* Parse a Halftone resource file into memory. */
87 private bool
parse_line(char ** pstr,char ** pline)88 parse_line(char **pstr, char **pline)
89 {
90 char *str = *pstr;
91
92 top:
93 while (*str && strchr(" \t\r\n", *str)) /* trim leading space */
94 ++str;
95 if (*str == 0) {
96 *pline = 0;
97 return false;
98 }
99 *pline = str;
100 while (*str && !strchr("\r\n", *str)) /* find EOL */
101 ++str;
102 while (str > *pline && strchr(" \t", str[-1])) /* trim trailing space */
103 --str;
104 *str = 0;
105 *pstr = str + 1;
106 return true;
107 }
108 private int
parse_halftone(gx_device_halftone_resource_t * phtr,byte ** pThresholds,char ** pprefix,char ** pcont)109 parse_halftone(gx_device_halftone_resource_t *phtr, byte **pThresholds,
110 char **pprefix, char **pcont)
111 {
112 char *str;
113 char *line;
114 char *rname = 0;
115 int HalftoneType = -1;
116 int Width = -1, Height = -1;
117 byte *Thresholds = 0;
118 stream_AXD_state ss;
119
120 /* Parse the file. */
121 for (str = *pcont; parse_line(&str, &line);) {
122 char *end;
123 char *prefix;
124 char terminator;
125
126 if (line[0] == '%')
127 continue;
128 if (strlen(line) >= 14 &&
129 !strcmp(line + strlen(line) - 14, "defineresource")
130 )
131 break;
132 if (line[0] != '/')
133 continue;
134 if (strlen(line) >= 8 &&
135 !strcmp(line + strlen(line) - 8, " 1 index")
136 )
137 continue;
138 end = ++line;
139 while (*end && !strchr(" \t<", *end)) /* find end of name */
140 ++end;
141 terminator = *end;
142 *end = 0;
143 if (rname == 0) { /* first name is halftone name */
144 rname = malloc(strlen(line) + 1);
145 strcpy(rname, line);
146 continue;
147 }
148 if (terminator == 0) /* name alone */
149 continue;
150 ++end;
151 if (!strcmp(line, "HalftoneType")) {
152 if (sscanf(end, "%d", &HalftoneType) != 1) {
153 fprintf(stderr, "Invalid HalftoneType syntax: %s\n", line - 1);
154 return -1;
155 }
156 switch (HalftoneType) {
157 case 3:
158 break;
159 case 5:
160 if (*pprefix)
161 free(*pprefix);
162 *pprefix = rname;
163 rname = 0;
164 break;
165 default:
166 fprintf(stderr, "Invalid HalftoneType: %s\n", end);
167 return -1;
168 }
169 continue;
170 } else if (!strcmp(line, "Width")) {
171 if (sscanf(end, "%d", &Width) != 1 ||
172 Width <= 0 || Width > 0x4000
173 ) {
174 fprintf(stderr, "Invalid Width: %s\n", end);
175 return -1;
176 }
177 } else if (!strcmp(line, "Height")) {
178 if (sscanf(end, "%d", &Height) != 1 ||
179 Height <= 0 || Height > 0x4000
180 ) {
181 fprintf(stderr, "Invalid Height: %s\n", end);
182 return -1;
183 }
184 } else if (!strcmp(line, "Thresholds")) {
185 uint ignore;
186 uint num_levels = 256;
187 uint num_bits = Width * Height;
188 char *eol = end + strlen(end); /* skip rest of line */
189 stream_cursor_read r;
190 stream_cursor_write w;
191
192 if (Width < 0 || Height < 0) {
193 fprintf(stderr, "Width and Height must precede Thresholds.\n");
194 return -1;
195 }
196 phtr->num_levels = num_levels;
197 phtr->levels =
198 malloc(num_levels * sizeof(*phtr->levels));
199 phtr->bit_data =
200 malloc(num_bits * sizeof(ushort));
201 Thresholds = malloc(num_bits);
202 s_AXD_init_inline(&ss);
203 r.ptr = (const byte *)eol;
204 r.limit = (const byte *)eol + strlen(eol + 1);
205 w.ptr = Thresholds - 1;
206 w.limit = w.ptr + num_bits;
207 s_AXD_template.process((stream_state *)&ss, &r, &w, true);
208 str = (char *)r.ptr + 1;
209 break;
210 }
211 }
212
213 /* Check for successful parsing. */
214 if (rname == 0)
215 return 1; /* end of definitions */
216 if (HalftoneType < 0)
217 fprintf(stderr, "HalftoneType not found.\n");
218 if (Width < 0)
219 fprintf(stderr, "Width not found.\n");
220 if (Height < 0)
221 fprintf(stderr, "Height not found.\n");
222 if (Thresholds == 0)
223 fprintf(stderr, "Thresholds not found.\n");
224 if (rname == 0 || Thresholds == 0)
225 return -1;
226 phtr->rname = rname;
227 phtr->HalftoneType = HalftoneType;
228 phtr->Width = Width;
229 phtr->Height = Height;
230 *pThresholds = Thresholds;
231 *pcont = str;
232 return 0;
233 }
234
235 /* Write a halftone as a C procedure. */
236 private int
write_halftone(FILE * out,gx_device_halftone_resource_t * phtr,const char * prefix,int index)237 write_halftone(FILE *out, gx_device_halftone_resource_t *phtr,
238 const char *prefix, int index)
239 {
240 int num_bits = phtr->Width * phtr->Height;
241 int i;
242
243 /* Write the initial comment. */
244 fputs("\n/* ", out);
245 if (prefix)
246 fprintf(out, "%s.", prefix);
247 fprintf(out, "%s */\n", phtr->rname);
248
249 /* Write the levels array. */
250 fprintf(out, "static const unsigned int levels_%d[] = {", index);
251 for (i = 0; i < phtr->num_levels; ++i) {
252 if (i % 10 == 0)
253 fputs("\n", out);
254 fprintf(out, "%5u,", phtr->levels[i]);
255 }
256 fputs("\n0};\n", out);
257
258 /* Write the bit_data array. */
259 fprintf(out, "static const unsigned short bit_data_%d[] = {", index);
260 for (i = 0; i < num_bits; ++i) {
261 if (i % 10 == 0)
262 fputs("\n", out);
263 fprintf(out, "%5u,", ((const ushort *)phtr->bit_data)[i]);
264 }
265 fputs("\n0};\n", out);
266
267 /* Write the top-level structure. */
268 fprintf(out, "static const gx_device_halftone_resource_t res_%d = {\n \"%s\", %d, %d, %d, %d, levels_%d, bit_data_%d, %u\n};\n",
269 index, phtr->rname, phtr->HalftoneType, phtr->Width, phtr->Height,
270 phtr->num_levels, index, index,
271 ht_order_procs_short.bit_data_elt_size);
272
273 return 0;
274 }
275
276 /* Main program */
277 int
main(int argc,char * argv[])278 main(int argc, char *argv[])
279 {
280 char *iname;
281 FILE *in;
282 char *oname;
283 FILE *out;
284 int code;
285 char *cont;
286 char *line;
287 gx_device_halftone_resource_t res;
288 char *prefix = 0;
289 byte *Thresholds;
290 gx_ht_order order;
291 int index, i;
292
293 if (argc != 3) {
294 fprintf(stderr, "Usage: genht ht_res.ps ht_data.c\n");
295 exit(1);
296 }
297 iname = argv[1];
298 oname = argv[2];
299 in = fopen(iname, "rb");
300 if (in == 0) {
301 in = fopen(iname, "r");
302 if (in == 0) {
303 fprintf(stderr, "Can't read %s.\n", iname);
304 exit(1);
305 }
306 }
307 cont = read_file(in, iname);
308 if (cont == 0)
309 exit(1);
310 fclose(in);
311 out = fopen(oname, "w");
312 if (out == 0) {
313 fprintf(stderr, "Can't open %s for output.\n", oname);
314 exit(1);
315 }
316 fprintf(out, "/*\n * This file %s was generated from %s by genht.\n * Do not edit this file.\n *\n", oname, iname);
317 /* Copy initial comments from the input file. */
318 while (parse_line(&cont, &line) && line[0] == '%')
319 if (line[1] != '!')
320 fprintf(out, " * %s\n", line + 1);
321 cont[-1] = '\n';
322 cont = line;
323 fputs(" */\n#include \"gxdhtres.h\"\n", out);
324 for (index = 0;
325 (code = parse_halftone(&res, &Thresholds, &prefix, &cont)) == 0;
326 ++index) {
327 order.width = res.Width;
328 order.num_levels = res.num_levels;
329 order.levels = (uint *)res.levels;
330 order.num_bits = res.Width * res.Height;
331 order.bit_data = (void *)res.bit_data;
332 ht_order_procs_short.construct_order(&order, Thresholds);
333 write_halftone(out, &res, prefix, index);
334 }
335 if (prefix == 0)
336 prefix = res.rname;
337 fputs("/* Check the prototype. */\n", out);
338 fprintf(out, "DEVICE_HALFTONE_RESOURCE_PROC(gs_dht_%s);\n", prefix);
339 fputs("\nconst gx_device_halftone_resource_t *const *\n", out);
340 fprintf(out, "gs_dht_%s(void)\n{\n static const gx_device_halftone_resource_t *const res[] = {\n\t",
341 prefix);
342 for (i = 0; i < index; ++i)
343 fprintf(out, "&res_%d, ", i);
344 fputs("0\n };\n return res;\n}\n", out);
345 fclose(out);
346 if (code < 0)
347 exit(1);
348 return 0;
349 }
350
351 /* Stubs */
ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)352 ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)
353 {
354 return 0;
355 ENUM_PTRS_END_PROC
356 }
RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)357 RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)
358 {
359 }
360 RELOC_PTRS_END
361 public_st_stream_state();
362 void
gx_ht_complete_threshold_order(gx_ht_order * porder)363 gx_ht_complete_threshold_order(gx_ht_order *porder)
364 {
365 }
366
367 /*
368 * In order to avoid a linking step, we #include the required files here
369 * rather than compiling them separately.
370 */
371 #include "gxhtbit.c"
372 #include "scantab.c"
373 #include "sstring.c"
374
375 const gx_dht_proc gx_device_halftone_list[] = { 0 };
376