1 /*
2     psftools: Manipulate console fonts in the .PSF format
3     Copyright (C) 2003  John Elliott
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include "cnvshell.h"
20 #include "psflib.h"
21 
22 /* Convert an MDA character ROM to a .PSF font.
23  *
24  * We assume the MDA ROM format, with 256 characters, each one 8x14. The
25  * ninth column is synthesized.
26  */
27 
28 static char helpbuf[2048];
29 static int v1 = 0;
30 static int v2 = 0;
31 static PSF_FILE psf;
32 
33 /* Program name */
34 char *cnv_progname = "TXT2PSF";
35 
36 /* ddash = 1 if option started with a double-dash; else 0 */
37 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)38 char *cnv_set_option(int ddash, char *variable, char *value)
39 {
40 	if (!stricmp(variable, "psf1")) { v1 = 1; return NULL; }
41 	if (!stricmp(variable, "psf2")) { v2 = 1; return NULL; }
42 
43 	if (strlen(variable) > 2000) variable[2000] = 0;
44 	sprintf(helpbuf, "Unknown option: %s\n", variable);
45 	return helpbuf;
46 }
47 
48 
49 /* Return help string */
cnv_help(void)50 char *cnv_help(void)
51 {
52     sprintf(helpbuf, "Syntax: %s textfile psffile { options }\n\n", cnv_progname);
53     strcat (helpbuf, "Options:\n\n"
54 		    "--psf1: Save in PSF1 format.\n"
55 		    "--psf2: Save in PSF2 format.\n");
56 
57     return helpbuf;
58 }
59 
60 #define ATSTART  0
61 #define INHEADER 1
62 #define INCHAR   2
63 #define INBITMAP 3
64 
cnv_execute(FILE * infile,FILE * outfile)65 char *cnv_execute(FILE *infile, FILE *outfile)
66 {
67 	int rv, n, x = 0, y = 0;
68 	int state = 0;
69 	char linebuf[2000];
70 	char unibuf[2000];
71 	char *c;
72 	int version = -1, flags = -1, length = -1, width = -1, height = -1;
73 	int nchar = 0;
74 	int line = 0, wb = 0, havebitmap = 0;
75 	psf_byte *charbits = NULL;
76 
77 	psf_file_new(&psf);
78 	while (fgets(linebuf, sizeof(linebuf), infile))
79 	{
80 		++line;
81 /* If a long line, devour the rest of it */
82 		if (!strchr(linebuf, '\n'))
83 		{
84 			do
85 			{
86 				n = fgetc(infile);
87 			}
88 			while (n != EOF && n != '\n');
89 		}
90 		c = strchr(linebuf, '\n'); if (c) *c = 0;
91 		c = strstr(linebuf, "//"); if (c) *c = 0;
92 
93 		if (linebuf[0] == 0) continue;
94 		if (linebuf[0] == '%')
95 		{
96 			if (!strncmp(linebuf + 1, "PSF2", 4) && state == ATSTART)
97 			{
98 				state = INHEADER;
99 				continue;
100 			}
101 /* %STOP: Immediately stop parsing */
102 			else if (!strncmp(linebuf + 1, "STOP", 4))
103 			{
104 				break;
105 			}
106 			else if (state == INHEADER)
107 			{
108 				if (version == -1) return "Version not set";
109 				if (flags == -1)   return "Flags not set";
110 				if (width == -1)   return "Width not set";
111 				if (height == -1)  return "Height not set";
112 				if (length == -1)  return "Length not set";
113 				if (version > 0)   return "Versions greater than 0 are not supported";
114 				rv = psf_file_create(&psf, width, height,
115 					       length, (flags & 1));
116 				if (!rv)
117 				{
118 					charbits = malloc(psf.psf_charlen);
119 					if (!charbits) rv = PSF_E_NOMEM;
120 				}
121 				if (rv) return psf_error_string(rv);
122 				state = INCHAR;
123 				unibuf[0] = 0;
124 				wb = ((width + 7) / 8);
125 			}
126 			else if (state == INCHAR || state == INBITMAP)
127 			{
128 				if (version == -1) return "Version not set";
129 				if (nchar < psf.psf_length) memcpy
130 					(psf.psf_data + nchar * psf.psf_charlen,
131 					charbits, psf.psf_charlen);
132 				if (unibuf[0])
133 				{
134 					rv = psf_unicode_from_string(&psf, nchar, unibuf);
135 					if (rv)
136 					{
137 						fprintf(stderr, "Line %d: Failed to decode %s\n", line, unibuf);
138 						return psf_error_string(rv);
139 					}
140 				}
141 				havebitmap = 0;
142 				state = INCHAR;
143 				nchar++;
144 				unibuf[0] = 0;
145 			}
146 			else
147 			{
148 				fprintf(stderr, "Line %d: Unexpected %% line\n", line);
149 				return "Invalid input format";
150 			}
151 		}
152 		else
153 		{
154 			c = strstr(linebuf, ": ");
155 			if (c)
156 			{
157 				*c = 0;
158 				c++;
159 				while (*c == ' ') c++;
160 				if (state == INHEADER)
161 				{
162 					if (!strcmp(linebuf, "Version"))
163 						version = atol(c);
164 					else if (!strcmp(linebuf, "Flags"))
165 						flags = atol(c);
166 					else if (!strcmp(linebuf, "Width"))
167 						width = atol(c);
168 					else if (!strcmp(linebuf, "Height"))
169 						height = atol(c);
170 					else if (!strcmp(linebuf, "Length"))
171 						length = atol(c);
172 					else
173 					{
174 						fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf);
175 						return "Invalid input format";
176 					}
177 				}
178 				else if (state == INCHAR)
179 				{
180 					if (!strcmp(linebuf, "Unicode"))
181 						strcpy(unibuf, c);
182 					else if (!strcmp(linebuf, "Bitmap"))
183 					{
184 						strcpy(linebuf, c);
185 						state = INBITMAP;
186 						havebitmap = 0;
187 						x = y = 0;
188 					}
189 					else
190 					{
191 						fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf);
192 						return "Invalid input format";
193 					}
194 				}
195 				else	/* Not INCHAR and not INHEADER */
196 				{
197 					fprintf(stderr, "Line %d: Unknown variable name '%s'\n", line, linebuf);
198 					return "Invalid input format";
199 				}
200 				if (state != INBITMAP) continue;
201 			} /* end if (c) */
202 			if (state == INBITMAP)
203 			{
204 				psf_byte *dest, mask;
205 				c = linebuf;
206 				while (*c)
207 				{
208 					if (*c != '-' && *c != '#')
209 					{
210 						c++;
211 						continue;
212 					}
213 					dest = charbits + (y * wb) + (x/8);
214 					mask = 0x80 >> (x & 7);
215 					if (*c == '#') *dest |= mask;
216 					else	       *dest &= ~mask;
217 					x++;
218 					if (x >= psf.psf_width) { x = 0; y++; }
219 					if (y >= psf.psf_height)
220 					{
221 						state = INCHAR;
222 						havebitmap = 1;
223 						break;
224 					}
225 					++c;
226 				}
227 				continue;
228 			}
229 			fprintf(stderr, "Line %d: Not a Variable: Value pair\n", line);
230 			return "Invalid input format";
231 		}
232 	}
233 	if (state == INCHAR && havebitmap)
234 	{
235 		if (nchar < psf.psf_length) memcpy(psf.psf_data + nchar *
236 				psf.psf_charlen, charbits, psf.psf_charlen);
237 		if (unibuf[0])
238 		{
239 			rv = psf_unicode_from_string(&psf, nchar, unibuf);
240 			if (rv) return psf_error_string(rv);
241 		}
242 	}
243 	if (v1) psf_force_v1(&psf);
244 	if (v2) psf_force_v2(&psf);
245 	rv = psf_file_write(&psf, outfile);
246 	psf_file_delete(&psf);
247 	if (rv) return psf_error_string(rv);
248 	return NULL;
249 }
250 
251