xref: /plan9/sys/src/cmd/gs/src/genht.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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