1 /* ft2sswf.c - written by Alexis Wilke for Made to Order Software Corp. (c) 2002-2009 */
2 
3 /*
4 
5 Copyright (c) 2002-2009 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 
35 #include	<stdio.h>
36 #include	<stdlib.h>
37 #include	<string.h>
38 #include	<errno.h>
39 #include	<ctype.h>
40 
41 #include	<ft2build.h>
42 #include	FT_FREETYPE_H
43 
44 /* defines the wc_t type for the printf(3C) */
45 #include	"sswf/libsswf-config.h"
46 
47 
48 #ifdef _MSVC
49 #define	strcasecmp		stricmp
50 // VC8 defines MB_CUR_MAX as a variable!
51 #ifndef MB_CUR_MAX
52 #define MB_CUR_MAX	64
53 //#elif !MB_CUR_MAX
54 //#undef MB_CUR_MAX
55 //#define MB_CUR_MAX	64
56 #endif
57 #endif
58 
59 
60 const char *		progname = "ft2sswf";		/* default name of this tool */
61 const char *		version = TO_STR(SSWF_VERSION);	/* version of this tool */
62 const char *		glyphs;				/* glyhps to print out */
63 wchar_t *		sorted_glyphs;			/* the list of glyphs to print out - sorted and unique */
64 long			errcnt;				/* count errors, if 1 or more occurs, then exit with 1 */
65 long			encoding;			/* whether to print out the encoding (0, 1 or 2) */
66 long			verbose;			/* writes out what we're doing */
67 long			output_control;			/* if true, print out the control characters too */
68 long			comment;			/* whether comments are generated */
69 long			include_null;			/* by default skip any empty character (except the space) */
70 double			factor;				/* multiply all the points (positions) by this factor */
71 double			advance;			/* the default number of pixels to the advance to the next character */
72 FILE *			output;				/* the output file (default stdout) */
73 FT_Library		library;			/* the font library pointer */
74 FT_Encoding		char_map_encoding;		/* what character map to use to read the chars (default -1 -- i.e. use 1st entry available) */
75 
76 struct option_to_char {
77 	size_t		length;		/* total length so far */
78 	int		index;		/* start at 0 */
79 	const char *	glyphs;		/* the original string */
80 	wchar_t		letter;		/* the last letter returned */
81 };
82 
83 struct encoding_list {
84 	const char *	name;
85 	FT_Encoding	encoding;
86 };
87 
88 struct encoding_list		list_of_encodings[] = {
89 	{ "default",		-1 },
90 	{ "none",		ft_encoding_none },
91 	{ "symbol",		ft_encoding_symbol },
92 	{ "unicode",		ft_encoding_unicode },
93 	{ "latin 1",		ft_encoding_latin_1 },
94 	{ "latin1",		ft_encoding_latin_1 },
95 	{ "latin 2",		ft_encoding_latin_2 },
96 	{ "latin2",		ft_encoding_latin_2 },
97 	{ "japanese",		ft_encoding_sjis },
98 	{ "sjis",		ft_encoding_sjis },
99 	{ "gb2312",		ft_encoding_gb2312 },
100 	{ "big 5",		ft_encoding_big5 },
101 	{ "big5",		ft_encoding_big5 },
102 	{ "wansung",		ft_encoding_wansung },
103 	{ "johab",		ft_encoding_johab },
104 	{ "adobe standard",	ft_encoding_adobe_standard },
105 	{ "adobe-standard",	ft_encoding_adobe_standard },
106 	{ "adobe std",		ft_encoding_adobe_standard },
107 	{ "adobe-std",		ft_encoding_adobe_standard },
108 	{ "adobe expert",	ft_encoding_adobe_expert },
109 	{ "adobe-expert",	ft_encoding_adobe_expert },
110 	{ "adobe custom",	ft_encoding_adobe_custom },
111 	{ "adobe-custom",	ft_encoding_adobe_custom },
112 	{ "apple roman",	ft_encoding_apple_roman },
113 	{ "apple-roman",	ft_encoding_apple_roman },
114 	{ "apple",		ft_encoding_apple_roman }
115 };
116 #define	MAX_ENCODINGS	(sizeof(list_of_encodings) / sizeof(struct encoding_list))
117 
118 
encoding_to_name(FT_Encoding value,char * enc)119 const char *encoding_to_name(FT_Encoding value, char *enc)
120 {
121 	struct encoding_list	*l;
122 	int			i;
123 
124 	enc[0] = value >> 24;
125 	enc[1] = value >> 16;
126 	enc[2] = value >> 8;
127 	enc[3] = value;
128 	enc[4] = '\0';
129 
130 	l = list_of_encodings;
131 	for(i = 0; i < MAX_ENCODINGS; i++, l++) {
132 		if(value == l->encoding) {
133 			return l->name;
134 		}
135 	}
136 
137 	return "(unknown at time of compilation)";
138 }
139 
140 
escape_char(const char ** s)141 wchar_t escape_char(const char **s)
142 {
143 	const char	*esc;
144 	unsigned char	c;
145 	wchar_t		r;
146 
147 	esc = *s;
148 	c = *esc++;
149 	if(c != '\\') {
150 		*s = esc;
151 		return c;
152 	}
153 	c = *esc++;
154 	switch(c) {
155 	case '\0':
156 		/* special case of a backslash at the end of a string */
157 		esc--;
158 		r = '\0';
159 		break;
160 
161 	case 'a':
162 		r = '\a';
163 		break;
164 
165 	case 'b':
166 		r = '\b';
167 		break;
168 
169 	case 'f':
170 		r = '\f';
171 		break;
172 
173 	case 'n':
174 		r = '\n';
175 		break;
176 
177 	case 'r':
178 		r = '\r';
179 		break;
180 
181 	case 't':
182 		r = '\t';
183 		break;
184 
185 	case 'v':
186 		r = '\v';
187 		break;
188 
189 	case 'x':
190 		r = 0;
191 		for(;;) {
192 			if(*esc >= '0' && *esc <= '9') {
193 				r = r * 16 + (*esc & 15);
194 			}
195 			else if(*esc >= 'a' && *esc <= 'f') {
196 				r = r * 16 + (*esc - 'a' + 10);
197 			}
198 			else if(*esc >= 'A' && *esc <= 'F') {
199 				r = r * 16 + (*esc - 'A' + 10);
200 			}
201 			else {
202 				break;
203 			}
204 			esc++;
205 		}
206 		break;
207 
208 	case '0':
209 	case '1':
210 	case '2':
211 	case '3':
212 	case '4':
213 	case '5':
214 	case '6':
215 	case '7':
216 		r = c & 7;
217 		while(*esc >= '0' && *esc <= '7') {
218 			r = r * 8 + (*esc & 7);
219 			esc++;
220 		}
221 		break;
222 
223 	default:
224 		/* copy any other character as is (including '\\') */
225 		r = c;
226 		break;
227 
228 	}
229 
230 	*s = esc;
231 
232 	return r;
233 }
234 
235 
next_char(struct option_to_char * o2c)236 wchar_t next_char(struct option_to_char *o2c)
237 {
238 	const char	*g, *save;
239 	wchar_t		c1, c2, c3;
240 
241 	/* here we determine the next character
242 	 * note that the o2c->index isn't an index from
243 	 * the start but instead in the current o2c->glyphs
244 	 * also the oc2->glyphs pointer is modified as we go
245 	 * this makes things much faster
246 	 */
247 
248 	g = o2c->glyphs;
249 
250 	/* end of string? nothing to do here! */
251 	if(g == NULL || *g == '\0') {
252 		o2c->letter = L'\0';
253 		return L'\0';
254 	}
255 
256 	o2c->length++;
257 
258 	/* determine the 1st character */
259 	c1 = escape_char(&g);
260 	save = g;
261 
262 	c2 = escape_char(&g);
263 	if(c2 != L'-') {
264 		/* no range, return c1 and save g after we read c1 */
265 		o2c->glyphs = save;
266 		o2c->index = 0;
267 		o2c->letter = c1;
268 		return c1;
269 	}
270 
271 	c3 = escape_char(&g);
272 	if(c1 > c3) {
273 		/* swap so it is ordered */
274 		c2 = c1;
275 		c1 = c3;
276 		c3 = c2;
277 	}
278 
279 	c2 = c1 + o2c->index;
280 
281 	if(o2c->index + 1 > c3 - c1) {
282 		/* Ha! We are done - next time read the following character */
283 		o2c->glyphs = g;
284 		o2c->index = 0;
285 	}
286 	else {
287 		o2c->index++;
288 	}
289 
290 	o2c->letter = c2;
291 	return c2;
292 }
293 
294 
295 
sort_glyphs(void)296 void sort_glyphs(void)
297 {
298 	wchar_t			wc, swap, *d;
299 	struct option_to_char	o2c;
300 
301 	/* first we sort the glyphs */
302 	o2c.length = 0;
303 	o2c.index = 0;
304 	o2c.glyphs = glyphs;
305 	o2c.letter = 0;
306 
307 	/* define the total length including duplicates */
308 	while((wc = next_char(&o2c)) != L'\0');
309 
310 	/* allocate the destination */
311 	if(sorted_glyphs != NULL) {
312 		/* first free previous instance */
313 		free(sorted_glyphs);
314 	}
315 	/*
316 	 * Note: this may allocate a HUGE buffer, the only
317 	 * way around would be to regenerate the ranges
318 	 * in the output string... We will see with usage
319 	 * whether this would be necessary or not.
320 	 */
321 	sorted_glyphs = malloc((o2c.length + 1) * sizeof(wchar_t));
322 	if(sorted_glyphs == NULL) {
323 		fprintf(stderr, "ERROR: out of memory trying to allocate a buffer to sort glyphs.\n");
324 		exit(1);
325 	}
326 
327 	/* reset the o2c parameters which we use next */
328 	o2c.index = 0;
329 	o2c.glyphs = glyphs;
330 	*sorted_glyphs = L'\0';
331 	while((wc = next_char(&o2c)) != L'\0') {
332 		d = sorted_glyphs;
333 		while(*d != '\0') {
334 			if(*d == wc) {
335 				goto skip_duplicate;
336 			}
337 			if(*d > wc) {
338 				break;
339 			}
340 			d++;
341 		}
342 		/* insert this character */
343 		wc = o2c.letter;
344 		do {
345 			swap = *d;
346 			*d = wc;
347 			d++;
348 			wc = swap;
349 		} while(wc != '\0');
350 		*d = '\0';
351 skip_duplicate:;
352 	}
353 }
354 
355 
356 
357 struct point {
358 	double		x;
359 	double		y;
360 };
361 
362 struct entry {
363 	long		count;		/* the number of points */
364 	long		points_index;	/* index to the first point in pts array */
365 };
366 
367 struct array {
368 	long		max_points;	/* total size of pts */
369 	long		idx_points;	/* next available pts structure */
370 	struct point	*points;
371 
372 	long		max_entries;	/* total size of entries */
373 	long		idx_entries;	/* next available entry */
374 	struct entry	*entries;
375 };
376 
377 
init_array(struct array * array,long points)378 void init_array(struct array *array, long points)
379 {
380 	memset(array, 0, sizeof(array));
381 
382 	array->max_points = points * 2;
383 	array->idx_points = 0;
384 	array->points = malloc(array->max_points * sizeof(struct point));
385 
386 	array->max_entries = 100;
387 	array->idx_entries = 0;
388 	array->entries = malloc(array->max_entries * sizeof(struct entry));
389 
390 	if(array->points == NULL || array->entries == NULL) {
391 		fprintf(stderr, "ERROR: out of memory trying to allocate an array for a glyph outline\n");
392 		exit(1);
393 	}
394 }
395 
396 
alloc_point(struct array * array,long x,long y)397 void alloc_point(struct array *array, long x, long y)
398 {
399 	struct point	*p;
400 
401 	if(array->idx_points >= array->max_points) {
402 		/* enlarge buffer */
403 		array->max_points += 100;
404 		array->points = realloc(array->points, array->max_points * sizeof(struct point));
405 		if(array->points == NULL) {
406 			fprintf(stderr, "ERROR: out of memory trying to enlarge an array of points for a glyph outline\n");
407 			exit(1);
408 		}
409 	}
410 
411 	/* one more point in this set of entries */
412 	array->entries[array->idx_entries - 1].count++;
413 
414 	p = array->points + array->idx_points++;
415 	p->x = x;
416 	p->y = y;
417 }
418 
419 
alloc_entry(struct array * array)420 void alloc_entry(struct array *array)
421 {
422 	long		i;
423 
424 	if(array->idx_entries >= array->max_entries) {
425 		/* enlarge buffer */
426 		array->max_entries += 100;
427 		array->entries = realloc(array->entries, array->max_entries * sizeof(struct entry));
428 		if(array->entries == NULL) {
429 			fprintf(stderr, "ERROR: out of memory trying to enlarge an array of entires for a glyph outline\n");
430 			exit(1);
431 		}
432 	}
433 
434 	i = array->idx_entries++;
435 
436 	array->entries[i].count = 0;
437 	array->entries[i].points_index = array->idx_points;
438 }
439 
440 
441 
442 /*
443  * The inputs are u and points
444  * u will vary from 0.0 (start point) to 1.0 (end point)
445  * the points array must point to 4 points - 2 anchors and 2 control points
446  * (start anchor, ctrl1, ctrl2, and end anchor)
447  *
448  * This function was simplified as much as possible (as far as I can tell)
449  * and thus it doesn't look clear at, does it?
450  *
451  * The computation is as follow:
452  *
453  * R = (U . B) / 6 . P
454  *
455  * Where the matrix U is defined as:
456  *
457  *     | u ** 3 |
458  * U = | u ** 2 |
459  *     |   u    |
460  *     |   1    |
461  *
462  * The matrix B is defined as:
463  *
464  *     | -1  3 -3  1 |
465  * B = |  3 -6  3  0 |
466  *     | -3  0  3  0 |
467  *     |  1  4  1  0 |
468  *
469  * And P is defined from the input points - this works in 3 dimensional
470  * space, and since we only have an X and Y set of coordinates, we assume
471  * Z is always zero.
472  *
473  *     | x1 y1 0 1 |
474  * P = | x2 y2 0 1 |
475  *     | x3 y3 0 1 |
476  *     | x4 y4 0 1 |
477  *
478  * R is the result of the products.
479  *
480  * Note: you can reuse this function with a Quadratic bezier curve by
481  *       setting the P matrix as follow (repeat the control point twice):
482  *
483  *     | x1 y1 0 1 |
484  * P = | x2 y2 0 1 |
485  *     | x2 y2 0 1 |
486  *     | x3 y3 0 1 |
487  *
488  */
bspline_point_at_u(double u,const struct point * points,struct point * result)489 void bspline_point_at_u(double u, const struct point *points, struct point *result)
490 {
491 	double		u2, u3, u3_div_6, r0, r1, r2;
492 
493 #define	u1	u
494 #define	r3	u3_div_6
495 
496 	/* u2 - u1 square, u3 - u1 cube */
497 	u3_div_6 = (u3 = (u2 = u1 * u1) * u1) / 6.0;
498 
499 	r0 = 0.5 * (u2 - u1) - u3_div_6 + 1.0 / 6.0;
500 	r1 = u3 * 0.5 - u2 + 2.0 / 3.0;
501 	r2 = 0.5 * (u2 - u3 + u1) + 1.0 / 6.0;
502 
503 	result->x =	r0 * points[0].x +
504 			r1 * points[1].x +
505 			r2 * points[2].x +
506 			r3 * points[3].x;
507 
508 	result->y =	r0 * points[0].y +
509 			r1 * points[1].y +
510 			r2 * points[2].y +
511 			r3 * points[3].y;
512 
513 #undef	u1
514 #undef	r3
515 }
516 
517 
close_entry(struct array * array)518 void close_entry(struct array *array)
519 {
520 	long		i, idx, index, max;
521 	struct point	*points, r, p;
522 
523 	i = array->idx_entries - 1;
524 
525 	max = array->entries[i].count;
526 	if(max <= 3) {
527 		/*
528 		 * a line or a curve which already is a quadratic curve
529 		 * doesn't require any changes
530 		 */
531 		return;
532 	}
533 
534 	/* in this case we have a "complex" bezier curve which requires simplification */
535 	points = malloc(max * sizeof(struct point));
536 	if(points == NULL) {
537 		fprintf(stderr, "ERROR: out of memory in trying to allocate a buffer to copy a the points of a bezier curve.\n");
538 		exit(1);
539 	}
540 
541 	/* copy the curve in a temp. buffer, then free the entry and its points */
542 	index = array->entries[i].points_index;
543 	memcpy(points, array->points + index, max * sizeof(struct point));
544 	array->idx_points = index;
545 	array->idx_entries = i;		/* we will re-allocate this entry later */
546 
547 	/* now we compute the new curve with only quadratic bezier curves */
548 
549 	/*
550 	 * The algorithm supports any degree of B-spline curves and transforms
551 	 * them in only quadratic Bezier curves. At this time the precision is
552 	 * no good!
553 	 */
554 
555 	p = points[0];
556 	max -= 2;
557 	for(idx = 1; idx < max; idx++) {
558 		/* compute the middle point -- this is a really bad approximation at times! */
559 		bspline_point_at_u(0.5, points + idx - 1, &r);
560 
561 		/* TODO: before to save that we should check to see if the precision is
562 		 * good enough (it usually is fairly close but at times you can see that
563 		 * the curve isn't that good)
564 		 */
565 		alloc_entry(array);
566 		alloc_point(array, (long) p.x, (long) p.y);
567 		alloc_point(array, (long) points[idx].x, (long) points[idx].y);
568 		alloc_point(array, (long) r.x, (long) r.y);
569 
570 		p = r;
571 	}
572 
573 	alloc_entry(array);
574 	alloc_point(array, (long) r.x, (long) r.y);
575 	alloc_point(array, (long) points[idx].x, (long) points[idx].y);
576 	alloc_point(array, (long) points[idx + 1].x, (long) points[idx + 1].y);
577 
578 	free(points);
579 }
580 
581 
add_point(struct array * array,double x,double y,long ctrl)582 void add_point(struct array *array, double x, double y, long ctrl)
583 {
584 	long		i;
585 
586 	i = array->idx_entries;
587 	if(ctrl) {
588 		if(i <= 0) {
589 			/* changed from ERROR to WARNING proposed by Steve Crook - Sept 2003 */
590 			fprintf(stderr, "WARNING: found a glyph which starts with a control point.\n");
591 			printf("\n/* NOTE: this glyph starts with a control point */\n");
592 			/* exit(1); */
593 			alloc_entry(array);
594 		}
595 		alloc_point(array, (long) x, (long) y);
596 	}
597 	else {
598 		if(i > 0) {
599 			/* "close" this entry with this new point then "open" a new entry */
600 			alloc_point(array, (long) x, (long) y);
601 			close_entry(array);
602 		}
603 		alloc_entry(array);
604 		alloc_point(array, (long) x, (long) y);
605 	}
606 }
607 
608 
empty_glyph(FT_Face face,wchar_t wc)609 int empty_glyph(FT_Face face, wchar_t wc)
610 {
611 	return include_null == 0 && wc != ' '
612 		&& face->glyph->outline.n_points == 0;
613 }
614 
615 
print_glyph(FT_Face face,wchar_t wc)616 void print_glyph(FT_Face face, wchar_t wc)
617 {
618 	char		buf[256], *s, *flg;
619 	int		c, i, maxcnt, maxpts, done, sx, sy;
620 	FT_Vector	*pts;
621 	struct array	array;
622 	struct point	*points;
623 
624 	/* skip empty glyphs as required */
625 	if(empty_glyph(face, wc)) {
626 		return;
627 	}
628 
629 	/* give the name of this letter in a comment */
630 	s = buf;
631 	*s++ = '\'';
632 	if(wc < ' ') {
633 		*s++ = '^';
634 		*s++ = wc + '@';
635 	}
636 	else if(wc < 0x7F) {
637 		*s++ = (char) wc;
638 	}
639 	else if(wc == 0x7F) {
640 		*s++ = '^';
641 		*s++ = '?';
642 	}
643 	else if(wc < 0xA0) {
644 		*s++ = '?';
645 		*s++ = wc - 0x40;
646 	}
647 	/* This only works if you're in ISO-8859-1.
648 	else if(wc < 0xFF) {
649 		*s++ = (char) wc;
650 	}
651 	*/
652 	else {
653 		s += sprintf(s, "\\x%lX", (unsigned long) wc);
654 	}
655 	*s++ = '\'';
656 	*s = '\0';
657 
658 	if(face->glyph->format != ft_glyph_format_outline) {
659 		fprintf(stderr, "ERROR: glyph format for \"%s\" not supported (only outlines are supported).\n", buf);
660 		return;
661 	}
662 
663 	/*
664 	 * the pts and flg pointers are always increased in the following loop
665 	 * and never reset
666 	 */
667 	pts = face->glyph->outline.points;
668 	flg = face->glyph->outline.tags;
669 	init_array(&array, face->glyph->outline.n_points);
670 	done = 0;
671 	maxcnt = face->glyph->outline.n_contours;
672 	fprintf(output, "\t\t\t\t/* Glyph: %s */\n", buf);
673 	fprintf(output, "\t\t\t\tglyph \"c_%04lX\" {\n", (unsigned long) wc);
674 	fprintf(output, "\t\t\t\t\tdefinitions.fill_glyph;\n");
675 
676 /* define the set of points */
677 	for(c = 0; c < maxcnt; c++) {
678 
679 		/*
680 		 * get the number of points in this entry
681 		 * then convert the font points in an array
682 		 * that we understand; finally we save the
683 		 * result in the output
684 		 */
685 		array.idx_points = 0;		/* reset the counters */
686 		array.idx_entries = 0;
687 		maxpts = face->glyph->outline.contours[c] + 1 - done;
688 		done += maxpts;
689 		sx = pts->x;
690 		sy = pts->y;
691 		while(maxpts > 0) {
692 			maxpts--;
693 			add_point(&array, (double) (pts->x - face->bbox.xMin) / factor, (double) (face->bbox.yMax - pts->y) / factor, (*flg & 1) == 0);
694 			pts++;
695 			flg++;
696 		}
697 		/* we now need to close the shape with a last call */
698 		alloc_point(&array, (long) ((double) (sx - face->bbox.xMin) / factor), (long) ((double) (face->bbox.yMax - sy) / factor));
699 		close_entry(&array);
700 
701 /*
702  * We have to use the face->bbox.yMax to invert the Y coordinates because the
703  * descender may not include the entire font (it can be smaller). The descender
704  * + ascender should be used to draw multiple lines of text, but can otherwise
705  * be ignored.
706 printf("Ascender %d descender %d - bbox.yMin %ld, bbox.yMax %ld\n",
707 		face->ascender, face->descender, face->bbox.yMin, face->bbox.yMax);
708 */
709 		/*
710 		 * at this point any curve which wasn't a quadratic bezier curve
711 		 * was already reduced
712 		 */
713 
714 		fprintf(output, "\t\t\t\t\tmove: %g, %g;\n", array.points[0].x, array.points[0].y);
715 
716 		fprintf(output, "\t\t\t\t\tpoints {");
717 		maxpts = array.idx_entries;
718 		for(i = 0; i < maxpts; i++) {
719 			/* once we reach here we have only two types of entries: 2 points or 3 points */
720 			points = array.points + array.entries[i].points_index;
721 			if(array.entries[i].count == 2) {
722 				fprintf(output, " %g, %g;",
723 					points[1].x, points[1].y);
724 			}
725 			else {
726 				fprintf(output, " %g, %g, %g, %g;",
727 					points[1].x, points[1].y,
728 					points[2].x, points[2].y);
729 			}
730 		}
731 		fprintf(output, " };\n");
732 	}
733 
734 	/* save the full bounding box (when SSWF knows how to compute this, we should remove it from here) */
735 	fprintf(output, "\t\t\t\t\trect { %d, %ld, %ld, %ld };\n",
736 			0,
737 			-face->bbox.yMax * 1024 / face->units_per_EM,
738 			face->bbox.xMax - face->bbox.xMin,
739 			-face->bbox.yMin * 1024 / face->units_per_EM);
740 	fprintf(output, "\t\t\t\t};\n");
741 }
742 
743 
ref_glyph(FT_Face face,FT_ULong wc,double adv)744 void ref_glyph(FT_Face face, FT_ULong wc, double adv)
745 {
746 	double		width;
747 
748 	/* skip empty glyphs as required */
749 	if(empty_glyph(face, (wchar_t) wc)) {
750 		return;
751 	}
752 
753 	fprintf(output, "\t\t\t\t\tchar: \"");
754 	if(wc >= ' ' && wc <= 0x7E) {
755 		if(wc == '"' || wc == '\\') {
756 			fprintf(output, "\\%c", (unsigned char) wc);
757 		}
758 		else {
759 			fprintf(output, "%c", (unsigned char) wc);
760 		}
761 	}
762 	else {
763 		fprintf(output, "\\\\x%04lX", wc);
764 	}
765 	fprintf(output, "\", c_%04lX", (unsigned long) wc);
766 
767 	width = (double) face->glyph->advance.x / factor;
768 	if(width != adv) {
769 		fprintf(output, ", %g", width);
770 	}
771 	fprintf(output, ";\n");
772 }
773 
774 
font_to_sswf(FT_Face face,const char * filename)775 void font_to_sswf(FT_Face face, const char *filename)
776 {
777 	FT_Error		error;
778 	FT_UInt			gindex;
779 	FT_ULong		wc;
780 	int			c, len, all;
781 	double			adv;
782 	char			*name, *d, enc[5];
783 #ifdef _MSVC
784 	char			*mbs;
785 #else
786 	char			mbs[MB_CUR_MAX];
787 #endif
788 	const char		*s, *encoding_name;
789 	const wchar_t		*ws;
790 
791 	/* fix the name of the font so we can use it
792 	 * in SSWF scripts without the $( ... ) operator
793 	 */
794 	len = strlen(face->family_name);
795 	name = malloc(len + 2);
796 	if(name == NULL) {
797 		fprintf(stderr, "ERROR: out of memory trying to allocate a buffer for the font name.\n");
798 		exit(1);
799 	}
800 	s = face->family_name;
801 	d = name;
802 	/* can't start with a digit or a period */
803 	if((*s >= '0' && *s <= '9') || *s == '.') {
804 		*d++ = '_';
805 	}
806 	while(*s != '\0') {
807 		if(strchr(" !@#$%^&*()-+={}[]\\|:;\"'`<>,./?~", *s) == NULL) {
808 			*d = *s;
809 		}
810 		else if(d == name || d[-1] != '_') {
811 			/* we try to avoid having multiple '_' in a row */
812 			*d = '_';
813 		}
814 		d++;
815 		s++;
816 	}
817 	*d = '\0';
818 
819 	/* the user wants to know the encodings only */
820 	if(encoding) {
821 		fprintf(output, "Family: \"%s\"\n", name);
822 		for(c = 0; c < face->num_charmaps; c++) {
823 			encoding_name = encoding_to_name(face->charmaps[c]->encoding, enc);
824 			fprintf(output, "\t%s - %s\n", enc, encoding_name);
825 		}
826 		free(name);
827 		return;
828 	}
829 
830 	if(face->num_charmaps <= 0) {
831 		fprintf(stderr, "ERROR: font \"%s\" doesn't have any encoding information.\n", name);
832 		free(name);
833 		return;
834 	}
835 
836 	/* select the encoding now */
837 	if(char_map_encoding == ft_encoding_none || char_map_encoding == (FT_Encoding) -1) {
838 		/* use 1st available encoding */
839 		FT_Set_Charmap(face, face->charmaps[0]);
840 	}
841 	else {
842 		error = FT_Select_Charmap(face, char_map_encoding);
843 		if(error) {
844 			encoding_name = encoding_to_name(char_map_encoding, enc);
845 			fprintf(stderr, "ERROR: can't find specified encoding (%s/%s) in this font (%s).\n",
846 					enc, encoding_name, name);
847 			free(name);
848 			return;
849 		}
850 	}
851 
852 	/*
853 	 * The file is actually only in ASCII, but defining the encoding as
854 	 * ISO-8859-1 is better because then the parser doesn't do any
855 	 * translation (the parser isn't smart enough to just understand
856 	 * ASCII...)
857 	 */
858 	fprintf(output, "/* encoding=\"iso8859-1\" */\n");
859 	fprintf(output, "block sswf {\n");
860 	fprintf(output, "\tblock fnt {\n");
861 	fprintf(output, "\t\tlist \"%s\" {\n", name);
862 
863 	/* the following is really only so we can reference a fill - the color isn't used */
864 	fprintf(output, "\t\t\tlist definitions {\n");
865 	fprintf(output, "\t\t\t\tfill style \"fill_glyph\" { color { 0, 0, 0 } };\n");
866 	fprintf(output, "\t\t\t};\n");
867 	fprintf(output, "\t\t\tlist insert {\n");
868 
869 
870 
871 	// Ask for the font to be setup according to the Flash
872 	// movies specifications (i.e. an EM of 1024x1024). The
873 	// DPI isn't specified so we try for 75x75 since that's
874 	// the usual to draw on a screen device.
875 	FT_Set_Char_Size(face, 1024 << 6, 1024 << 6, 75, 75);
876 	//FT_Set_Pixel_Sizes(face, 1024, 1024);
877 
878 	// in the following we first generate the list of glyphs
879 	// note that we use the 'glyphs' variable as defined by
880 	// the end user to know which glyphs to print out; note
881 	// however that the special case "*" means all in which
882 	// case we go through the entire map
883 	all = glyphs == NULL || strcmp(glyphs, "*") == 0;
884 	if(all) {
885 		if(comment != 0) {
886 			fprintf(output, "\t\t\t\t/* Extract all the available characters */\n");
887 		}
888 		wc = FT_Get_First_Char(face, &gindex);
889 		while(gindex != 0) {
890 			/*
891 			 * skip ^@ at all times - it doesn't work well in C strings anyway
892 			 * also, keep control characters only if requested to do so
893 			 */
894 			if(wc != 0 && (output_control || wc >= ' ')) {
895 				error = FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP);
896 				if(error) {
897 					fprintf(stderr, "ERROR: couldn't load glyph 0x%04X from file \"%s\" (Error: %d).\n", (int) wc, filename, error);
898 				}
899 				else if(empty_glyph(face, (wchar_t) wc)) {
900 					fprintf(stderr, "WARNING: the requested character 0x%04X from file \"%s\" is empty.\n", (int) wc, filename);
901 				}
902 				else {
903 					print_glyph(face, (wchar_t) wc);
904 				}
905 			}
906 			wc = FT_Get_Next_Char(face, wc, &gindex);
907 		}
908 	}
909 	else {
910 		if(comment != 0) {
911 			/* TODO: the 2nd string needs control characters to be remapped */
912 			fprintf(output, "\t\t\t\t/* Extracted characters: \"%s\" (%ls) */\n", glyphs, sorted_glyphs);
913 		}
914 		ws = sorted_glyphs;
915 		while(*ws != L'\0') {
916 			wc = *ws;
917 			error = FT_Load_Char(face, wc, FT_LOAD_NO_BITMAP);
918 			len = wctomb(NULL, wc);
919 #ifdef _MSVC
920 			mbs = malloc(len + 1);
921 #endif
922 			mbs[wctomb(mbs, wc)] = '\0';
923 			if(error) {
924 				fprintf(stderr, "ERROR: couldn't load char #%s (0x%04X) from file \"%s\" (Error: %d).\n", mbs, (int) wc, filename, error);
925 			}
926 			else if(empty_glyph(face, (wchar_t) wc)) {
927 				fprintf(stderr, "WARNING: the requested character %s (0x%04X) from file \"%s\" is empty.\n", mbs, (int) wc, filename);
928 			}
929 			else {
930 				print_glyph(face, (wchar_t) wc);
931 			}
932 #ifdef _MSVC
933 			free(mbs);
934 #endif
935 			ws++;
936 		}
937 	}
938 
939 	fprintf(output, "\t\t\t\tfont \"fnt\" {\n");
940 	fprintf(output, "\t\t\t\t\t\"%s\";\n", face->family_name);
941 
942 	/* try to determine the width of the space character */
943 	adv = advance;
944 	error = FT_Load_Char(face, ' ', FT_LOAD_NO_BITMAP);
945 	if(error == 0) {
946 		fprintf(output, "\t\t\t\t\tspace: %g;\n", (double) face->glyph->advance.x / factor);
947 		if(advance == 0.0) {
948 			/* use the space advance as the default when user didn't define one */
949 			/* TODO: once we have a list of all the glyphs advance then we could
950 			 * compute the one which is used the most and thus will be useful
951 			 * to declare here
952 			 */
953 			adv = (double) face->glyph->advance.x / factor;
954 		}
955 	}
956 	if(adv != 0.0) {
957 		fprintf(output, "\t\t\t\t\tadvance: %g;\n", adv);
958 	}
959 	fprintf(output, "\t\t\t\t\tlayout: %d, %ld, %d; // Original units per EM was %u\n",
960 			face->ascender * 1024 / face->units_per_EM,
961 			labs(face->descender) * 1024 / face->units_per_EM,	/* the FT_... doc says it should be positive... but it isn't! */
962 			face->height * 1024 / face->units_per_EM,
963 			face->units_per_EM);
964 
965 	switch(face->charmap->encoding) {
966 	case ft_encoding_unicode:
967 		fprintf(output, "\t\t\t\t\ttype: \"unicode\"");
968 		break;
969 
970 	case ft_encoding_sjis:
971 		fprintf(output, "\t\t\t\t\ttype: \"shiftjis\"");
972 		break;
973 
974 	default:
975 		fprintf(output, "\t\t\t\t\ttype: \"ascii\"");
976 		break;
977 
978 	}
979 	if(face->style_flags & FT_STYLE_FLAG_BOLD) {
980 		fprintf(output, ", \"bold\"");
981 	}
982 	if(face->style_flags & FT_STYLE_FLAG_ITALIC) {
983 		fprintf(output, ", \"italic\"");
984 	}
985 	fprintf(output, ";\n");
986 
987 	if(all) {
988 		wc = FT_Get_First_Char(face, &gindex);
989 		while(gindex != 0) {
990 			if(wc != 0 && (output_control || wc >= ' ')) {
991 				error = FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP);
992 				if(error == 0 && !empty_glyph(face, (wchar_t) wc)) {
993 					ref_glyph(face, wc, advance);
994 				}
995 			}
996 			wc = FT_Get_Next_Char(face, wc, &gindex);
997 		}
998 	}
999 	else {
1000 		ws = sorted_glyphs;
1001 		while(*ws != L'\0') {
1002 			wc = *ws;
1003 			error = FT_Load_Char(face, wc, FT_LOAD_NO_BITMAP);
1004 			if(error == 0 && !empty_glyph(face, (wchar_t) wc)) {
1005 				ref_glyph(face, wc, advance);
1006 			}
1007 			ws++;
1008 		}
1009 	}
1010 
1011 
1012 
1013 	fprintf(output, "\t\t\t\t};\n");
1014 
1015 	fprintf(output, "\t\t\t} px;\n");	/* closes the list \"font name\" ... */
1016 	fprintf(output, "\t\t};\n");	/* closes the list \"font name\" ... */
1017 	fprintf(output, "\t};\n");
1018 	fprintf(output, "};\n");
1019 
1020 	free(name);
1021 }
1022 
1023 
1024 
read_stdin(size_t * size)1025 FT_Byte *read_stdin(size_t *size)
1026 {
1027 	int		c, left;
1028 	size_t		max;
1029 	FT_Byte		*buf, *s;
1030 
1031 	buf = malloc(1024);
1032 	if(buf == NULL) {
1033 		fprintf(stderr, "ERROR: can't allocate a memory buffer for the stdin file.\n");
1034 		exit(1);
1035 	}
1036 	max = 1024;
1037 	left = 1024;
1038 	s = buf;
1039 	while((c = getchar()) != EOF) {
1040 		if(left <= 0) {
1041 			max += 1024;
1042 			buf = realloc(buf, max);
1043 			if(buf == NULL) {
1044 				fprintf(stderr, "ERROR: can't allocate a memory buffer for the stdin file.\n");
1045 				exit(1);
1046 			}
1047 			left = 1024;
1048 			s = buf + max - left;
1049 		}
1050 		*s++ = c;
1051 		left--;
1052 	}
1053 
1054 	*size = max - left;
1055 
1056 	return buf;
1057 }
1058 
1059 
run_font(const char * filename)1060 void run_font(const char *filename)
1061 {
1062 	FT_Error	error;
1063 	FT_Face		face;
1064 	size_t		size;
1065 	FT_Byte		*font_buffer;
1066 
1067 	if(strcmp(filename, "-") == 0) {
1068 		/* we have to read the stdin file instead */
1069 		if(verbose != 0) {
1070 			fprintf(stderr, "INFO: reading the standard input.\n");
1071 		}
1072 		font_buffer = read_stdin(&size);
1073 		error = FT_New_Memory_Face(library, font_buffer, size, 0, &face);
1074 		if(error) {
1075 			fprintf(stderr, "ERROR: the standard input doesn't represent a valid font.\n");
1076 			errcnt++;
1077 			free(font_buffer);
1078 			return;
1079 		}
1080 		font_to_sswf(face, filename);
1081 		error = FT_Done_Face(face);
1082 		if(error) {
1083 			fprintf(stderr, "WARNING: the standard input font face generated an error on closure.\n");
1084 		}
1085 		free(font_buffer);
1086 	}
1087 	else {
1088 		if(verbose != 0) {
1089 			fprintf(stderr, "INFO: reading the font from file \"%s\".\n", filename);
1090 		}
1091 		error = FT_New_Face(library, filename, 0, &face);
1092 		if(error) {
1093 			fprintf(stderr, "ERROR: the file \"%s\" can't either be open, read or is an invalid font file.\n", filename);
1094 			errcnt++;
1095 			return;
1096 		}
1097 		font_to_sswf(face, filename);
1098 		error = FT_Done_Face(face);
1099 		if(error) {
1100 			fprintf(stderr, "WARNING: the font face read from the file \"%s\" generated an error on closure.\n", filename);
1101 		}
1102 	}
1103 }
1104 
1105 
show_encodings(void)1106 void show_encodings(void)
1107 {
1108 	int		i, j;
1109 	char		enc[5];
1110 
1111 	enc[4] = '\0';
1112 	for(i = 0; i < MAX_ENCODINGS; i++) {
1113 		enc[0] = list_of_encodings[i].encoding >> 24;
1114 		enc[1] = list_of_encodings[i].encoding >> 16;
1115 		enc[2] = list_of_encodings[i].encoding >> 8;
1116 		enc[3] = list_of_encodings[i].encoding;
1117 		for(j = 0; j < 4; j++) {
1118 			if(enc[j] == (char) 0xFF) {
1119 				enc[j] = '?';
1120 			}
1121 			else if(enc[j] == (char) 0) {
1122 				enc[j] = ' ';
1123 			}
1124 			else if(enc[j] < ' ' || enc[j] >= 0x7F) {
1125 				enc[j] = '.';
1126 			}
1127 		}
1128 		printf("%5d. %s - %s\n", i + 1, enc, list_of_encodings[i].name);
1129 	}
1130 
1131 	exit(1);
1132 }
1133 
1134 
string_to_encoding(const char * str)1135 FT_Encoding string_to_encoding(const char *str)
1136 {
1137 	struct encoding_list	*l;
1138 	int			i;
1139 	char			*s, buf[256];
1140 	FT_Encoding		value;
1141 
1142 	/* first we clip the string (remove starting and ending spaces) */
1143 	while(isspace((unsigned char) *str)) {
1144 		str++;
1145 	}
1146 	strncpy(buf, str, sizeof(buf) - 1);
1147 	buf[sizeof(buf) - 1] = '\0';
1148 	s = buf + strlen(buf);
1149 	while(s > buf && isspace((unsigned char) s[-1])) {
1150 		s--;
1151 	}
1152 	*s = '\0';
1153 
1154 	/* people may give us a name or directly an encoding */
1155 	if(s - buf <= 4) {
1156 		value = 0;
1157 		s = buf;
1158 		for(i = 0; i < 4; i++) {
1159 			if(*s == '\0') {
1160 				/* fill with spaces */
1161 				value = (value << 8) + ' ';
1162 			}
1163 			else {
1164 				value = (value << 8) + *s;
1165 				s++;
1166 			}
1167 		}
1168 	}
1169 	else {
1170 		/* no encoding equals -1 -- so use -2 as a "bad" encoding */
1171 		value = (FT_Encoding) -2;
1172 	}
1173 
1174 	l = list_of_encodings;
1175 	for(i = 0; i < MAX_ENCODINGS; i++) {
1176 		if(strcasecmp(str, l[i].name) == 0 || l[i].encoding == value) {
1177 			return l[i].encoding;
1178 		}
1179 	}
1180 
1181 	fprintf(stderr, "ERROR: can't determine what encoding \"%s\" is.\n", str);
1182 
1183 	return -1;
1184 }
1185 
1186 
usage(const char * cmd)1187 void usage(const char *cmd)
1188 {
1189 	fprintf(stderr, "%s V%s -- Written by Alexis Wilke for Made to Order Software Corp. (c) 2002-2009\n", progname, version);
1190 	fprintf(stderr, "Usage: %s [-opt] <font-file> ...\n", cmd);
1191 	fprintf(stderr, "\n");
1192 	fprintf(stderr, "<font-file> can be \"-\" to process the standard input as a font.\n");
1193 	fprintf(stderr, "\n");
1194 	fprintf(stderr, "The special option \"--\" can be used to stop parsing options and take\n");
1195 	fprintf(stderr, "all the other parameters as font filenames\n");
1196 	fprintf(stderr, "\n");
1197 	fprintf(stderr, "-opt can be one or more of the following:\n");
1198 	fprintf(stderr, "\n");
1199 	fprintf(stderr, "  NOTE: options given after a given font-file don't apply to that\n");
1200 	fprintf(stderr, "        font-file but only the following ones\n");
1201 	fprintf(stderr, "\n");
1202 	fprintf(stderr, "  --advance(=| )<value>\n");
1203 	fprintf(stderr, "                      specify the default number of pixels to use to advanced\n");
1204 	fprintf(stderr, "                      to the next character.\n");
1205 	fprintf(stderr, "  -c[0|1]             print comments in output file\n");
1206 	fprintf(stderr, "  --control           print out the control characters (otherwise starts at\n");
1207 	fprintf(stderr, "                      0x20 -- space)\n");
1208 	fprintf(stderr, "  -e[0|1|2]           output the encodings only\n");
1209 	fprintf(stderr, "  -f[ ]<factor>       multiply all of the font coordinates by factor\n");
1210 	fprintf(stderr, "                      (a floating-point value)\n");
1211 	fprintf(stderr, "  -g[ ]<glyphs> or --glyphs(=| )[<glyphs>]\n");
1212 	fprintf(stderr, "                      list of characters to extract from the font (ISO-8859-1 only)\n");
1213 	fprintf(stderr, "  -h or --help        prints out this help screen\n");
1214 	fprintf(stderr, "  -m[ ]<name> or --map(=| )[<name>]\n");
1215 	fprintf(stderr, "                      specify which encoding map to use; use -e to have a list\n");
1216 	fprintf(stderr, "                      of available encodings in a given font; by default, use\n");
1217 	fprintf(stderr, "                      the 1st entry\n");
1218 	fprintf(stderr, "  -n[0|1] or --include-null or --no-null\n");
1219 	fprintf(stderr, "                      include all characters even when empty\n");
1220 	fprintf(stderr, "  -o[ ][<filename>] or --output(=| )[<filename>]\n");
1221 	fprintf(stderr, "                      specify a filename where the result is written; the\n");
1222 	fprintf(stderr, "                      default is stdout\n");
1223 	fprintf(stderr, "  -q                  quiet, i.e. no verbosity (default)\n");
1224 	fprintf(stderr, "  -v                  increase verbosity by one\n");
1225 	fprintf(stderr, "  --version           print out the version of this tool and exit\n");
1226 	exit(1);
1227 }
1228 
run_command_line(int argc,char * argv[])1229 void run_command_line(int argc, char *argv[])
1230 {
1231 	int		i, j, len, moreoptions;
1232 	char		*s, *output_filename;
1233 
1234 	// define the current program name
1235 	len = strlen(argv[0]);
1236 	s = argv[0] + len;
1237 	while(s > argv[0]) {
1238 		if(s[-1] == '/') {
1239 			break;
1240 		}
1241 		s--;
1242 	}
1243 	progname = s;
1244 
1245 	output = stdout;			/* the default output */
1246 	char_map_encoding = (FT_Encoding) -1;	/* use the 1st entry by default */
1247 	factor = 64.0;
1248 
1249 	moreoptions = 1;
1250 	for(i = 1; i < argc; i++) {
1251 		if(argv[i][0] == '-' && moreoptions != 0) {
1252 			if(argv[i][1] == '-') {
1253 				/* full word options */
1254 				if(argv[i][2] == '\0') {
1255 					moreoptions = 0;
1256 				}
1257 				else if(strncmp(argv[i] + 2, "advance", 7) == 0) {
1258 					advance = 0.0;
1259 					if(argv[i][2 + 7] == '=') {
1260 						/* name stuck with the option */
1261 						advance = strtod(argv[i] + 2 + 7 + 1, NULL);
1262 					}
1263 					else {
1264 						/* get the next argv[] unless it starts with a '-' */
1265 						if(i + 1 < argc
1266 						&& argv[i + 1][0] != '-') {
1267 							i++;
1268 							advance = strtod(argv[i], NULL);
1269 						}
1270 					}
1271 				}
1272 				else if(strcmp(argv[i] + 2, "control") == 0) {
1273 					output_control = 1;
1274 				}
1275 				else if(strncmp(argv[i] + 2, "glyphs", 6) == 0) {
1276 					glyphs = NULL;
1277 					if(argv[i][2 + 6] == '=') {
1278 						/* name stuck with the option */
1279 						glyphs = argv[i] + 2 + 6 + 1;
1280 						sort_glyphs();
1281 					}
1282 					else {
1283 						/* get the next argv[] unless it starts with a '-' */
1284 						if(i + 1 < argc
1285 						&& argv[i + 1][0] != '-') {
1286 							i++;
1287 							glyphs = argv[i];
1288 							sort_glyphs();
1289 						}
1290 					}
1291 				}
1292 				else if(strcmp(argv[i] + 2, "include-null") == 0) {
1293 					include_null = 1;
1294 				}
1295 				else if(strncmp(argv[i] + 2, "map", 3) == 0) {
1296 					/* first, we revert to the default */
1297 					char_map_encoding = (FT_Encoding) -1;
1298 					if(argv[i][2 + 3] == '=') {
1299 						/* name stuck with the option */
1300 						char_map_encoding = string_to_encoding(argv[i] + 2 + 3 + 1);
1301 					}
1302 					else {
1303 						/* get the next argv[] unless it starts with a '-' */
1304 						if(i + 1 < argc
1305 						&& argv[i + 1][0] != '-') {
1306 							i++;
1307 							char_map_encoding = string_to_encoding(argv[i]);
1308 						}
1309 					}
1310 				}
1311 				else if(strcmp(argv[i] + 2, "no-null") == 0) {
1312 					include_null = 0;
1313 				}
1314 				else if(strncmp(argv[i] + 2, "output", 6) == 0) {
1315 					/* first, we revert to the default */
1316 					if(output != stdout) {
1317 						fclose(output);
1318 						output = stdout;
1319 					}
1320 					output_filename = NULL;
1321 					if(argv[i][2 + 6] == '=') {
1322 						/* name stuck with the option */
1323 						output_filename = argv[i] + 2 + 6 + 1;
1324 						if(output_filename[0] != '\0'
1325 						&& strcmp(output_filename, "-") != 0) {
1326 							output = fopen(output_filename, "w");
1327 						}
1328 					}
1329 					else {
1330 						/* get the next argv[] unless it starts with a '-' */
1331 						if(i + 1 < argc
1332 						&& argv[i + 1][0] != '-') {
1333 							i++;
1334 							output_filename = argv[i];
1335 							output = fopen(output_filename, "w");
1336 						}
1337 					}
1338 					if(output == NULL) {
1339 						fprintf(stderr, "ERROR: can't open ouptut file \"%s\" (errno: %d).\n", output_filename, errno);
1340 						exit(1);
1341 					}
1342 				}
1343 				else if(strcmp(argv[i] + 2, "version") == 0) {
1344 					printf("%s\n", version);
1345 					exit(1);
1346 				}
1347 				else if(strcmp(argv[i] + 2, "help") == 0) {
1348 					usage(argv[0]);
1349 					/*NOTREACHED*/
1350 				}
1351 				else {
1352 					fprintf(stderr, "ERROR: unknown option \"%s\", process stopped.\n", argv[i]);
1353 					exit(1);
1354 				}
1355 			}
1356 			else if(argv[i][1] == '\0') {
1357 				// got a request to process stdin as a font...
1358 				run_font("-");
1359 			}
1360 			else {
1361 				len = strlen(argv[i]);
1362 				for(j = 1; j < len; j++) {
1363 					switch(argv[i][j]) {
1364 					case 'c':
1365 						switch(argv[i][j + 1]) {
1366 						case '0':
1367 							comment = 0;
1368 							j++;
1369 							break;
1370 
1371 						case '1':
1372 							comment = 1;
1373 							j++;
1374 							break;
1375 
1376 						default:
1377 							comment = 1;
1378 							break;
1379 
1380 						}
1381 						break;
1382 
1383 					case 'e':
1384 						switch(argv[i][j + 1]) {
1385 						case '0':
1386 							encoding = 0;
1387 							j++;
1388 							break;
1389 
1390 						case '1':
1391 							encoding = 1;
1392 							j++;
1393 							break;
1394 
1395 						case '2':
1396 							show_encodings();
1397 							/*NOTREACHED*/
1398 							break;
1399 
1400 						default:
1401 							encoding = 1;
1402 							break;
1403 
1404 						}
1405 						break;
1406 
1407 					case 'f':
1408 						if(argv[i][j + 1] != '\0') {
1409 							factor = strtod(argv[i] + j + 1, NULL) * 64.0;
1410 						}
1411 						else if(i + 1 < argc) {
1412 							i++;
1413 							factor = strtod(argv[i], NULL) * 64.0;
1414 						}
1415 						else {
1416 							factor = 64.0;
1417 						}
1418 						j = len;
1419 						break;
1420 
1421 					case 'g':
1422 						if(argv[i][j + 1] != '\0') {
1423 							glyphs = argv[i] + j + 1;
1424 							sort_glyphs();
1425 						}
1426 						else if(i + 1 < argc) {
1427 							i++;
1428 							glyphs = argv[i];
1429 							sort_glyphs();
1430 						}
1431 						else {
1432 							glyphs = NULL;
1433 						}
1434 						j = len;
1435 						break;
1436 
1437 					case 'h':
1438 						usage(argv[0]);
1439 						/*NOTREACHED*/
1440 						break;
1441 
1442 					case 'm':
1443 						if(argv[i][j + 1] != '\0') {
1444 							char_map_encoding = string_to_encoding(argv[i] + j + 1);
1445 						}
1446 						else if(i + 1 < argc) {
1447 							i++;
1448 							char_map_encoding = string_to_encoding(argv[i]);
1449 						}
1450 						else {
1451 							char_map_encoding = (FT_Encoding) -1;
1452 						}
1453 						j = len;
1454 						break;
1455 
1456 					case 'n':
1457 						include_null = 1;
1458 						switch(argv[i][j + 1]) {
1459 						case '0':
1460 							include_null = 0;
1461 							j++;
1462 							break;
1463 
1464 						case '1':
1465 							j++;
1466 							break;
1467 
1468 						}
1469 						break;
1470 
1471 					case 'o':
1472 						if(output != stdout) {
1473 							fclose(output);
1474 							output = stdout;
1475 						}
1476 						output_filename = NULL;
1477 						if(argv[i][j + 1] != '\0') {
1478 							output_filename = argv[i] + j + 1;
1479 						}
1480 						else if(i + 1 < argc) {
1481 							i++;
1482 							output_filename = argv[i];
1483 						}
1484 						j = len;
1485 						if(output_filename != NULL) {
1486 							output = fopen(output_filename, "w");
1487 							if(output == NULL) {
1488 								fprintf(stderr, "ERROR: can't open ouptut file \"%s\" (errno: %d).\n", output_filename, errno);
1489 								exit(1);
1490 							}
1491 						}
1492 						break;
1493 
1494 					case 'q':
1495 						verbose = 0;
1496 						break;
1497 
1498 					case 'v':
1499 						verbose++;
1500 						break;
1501 
1502 					default:
1503 						fprintf(stderr, "ERROR: unknown option \"-%c\", process stopped.\n", argv[i][j]);
1504 						exit(1);
1505 
1506 					}
1507 				}
1508 			}
1509 		}
1510 		else {
1511 			/* got a filename, process this font */
1512 			run_font(argv[i]);
1513 		}
1514 	}
1515 }
1516 
1517 
main(int argc,char * argv[])1518 int main(int argc, char *argv[])
1519 {
1520 	FT_Error	error;
1521 
1522 	/* we need to initialize the free font library only once */
1523 	error = FT_Init_FreeType(&library);
1524 	if(error) {
1525 		fprintf(stderr, "ERROR: can't initialize the free type library.\n");
1526 		exit(1);
1527 	}
1528 
1529 	run_command_line(argc, argv);
1530 
1531 	error = FT_Done_FreeType(library);
1532 	if(error) {
1533 		fprintf(stderr, "WARNING: the release of the FreeFont library failed.\n");
1534 	}
1535 
1536 	exit(errcnt == 0 ? 0 : 1);
1537 	return 0;
1538 }
1539 
1540