1 /*
2 psftools: Manipulate console fonts in the .PSF format
3 Copyright (C) 2005-6 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 #include "cpi.h"
22
23 /* Extract a font from a .CPI file.
24 *
25 */
26
27 static char helpbuf[2048];
28 static int height = -1;
29 static int cpage = -1;
30 static int v1 = 0, v2 = 0;
31 static PSF_MAPPING *codepage = NULL;
32 static PSF_FILE psf;
33 static CPI_FILE cpi;
34
35 /* Program name */
36 char *cnv_progname = "CPI2PSF";
37
38 /* ddash = 1 if option started with a double-dash; else 0 */
39 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)40 char *cnv_set_option(int ddash, char *variable, char *value)
41 {
42 if (!stricmp(variable, "srcpage") || !stricmp(variable, "codepage"))
43 {
44 char buf[20];
45 cpage = atoi(value);
46 sprintf(buf, "CP%d", cpage);
47 codepage = psf_find_mapping(buf);
48 if (codepage == NULL)
49 {
50 fprintf(stderr, "Warning: No Unicode mapping known for codepage %d\n", cpage);
51 }
52 return NULL;
53
54 }
55 if (!stricmp(variable, "height")) { height = atoi(value); return NULL; }
56 if (!stricmp(variable, "psf1")) { v1 = 1; return NULL; }
57 if (!stricmp(variable, "psf2")) { v2 = 1; return NULL; }
58 if (strlen(variable) > 2000) variable[2000] = 0;
59 sprintf(helpbuf, "Unknown option: %s\n", variable);
60 return helpbuf;
61 }
62
63
64 /* Return help string */
cnv_help(void)65 char *cnv_help(void)
66 {
67 sprintf(helpbuf, "Syntax: %s cpifile psffile { options }\n\n", cnv_progname);
68 strcat (helpbuf, "Options: \n"
69 " --height=x Extract the font with the given height\n"
70 " --srcpage=x Only extract codepage x\n"
71 " --psf1 Output in PSF1 format\n"
72 " --psf2 Output in PSF2 format (default) \n");
73
74 return helpbuf;
75 }
76
77 static psf_dword *unicodes = NULL;
78 static int unicodes_max = 0, unicodes_count = 0;
79
unicode_add(psf_dword * token)80 static psf_errno_t unicode_add(psf_dword *token)
81 {
82 psf_dword *tmp;
83 int n;
84
85 for (n = 0; n < unicodes_count; n++)
86 {
87 if (unicodes[n] == token[0]) return PSF_E_OK;
88 }
89
90 if (unicodes_count >= unicodes_max)
91 {
92 tmp = calloc(unicodes_max + 256, sizeof(psf_dword));
93 if (!tmp) return PSF_E_NOMEM;
94 if (unicodes) memcpy(tmp, unicodes,
95 unicodes_max * sizeof(psf_dword));
96 free(unicodes);
97 unicodes = tmp;
98 unicodes_max += 256;
99 }
100 unicodes[unicodes_count++] = token[0];
101 return PSF_E_OK;
102 }
103
cnv_execute(FILE * infile,FILE * outfile)104 char *cnv_execute(FILE *infile, FILE *outfile)
105 {
106 int rv, m, n, err;
107 CP_HEAD *cph;
108 CP_FONT *cpf;
109 int nchars, fontw = 0;
110 psf_dword glyph;
111 char buf[20];
112
113 nchars = 0;
114 err = cpi_loadfile(&cpi, infile);
115 if (err == CPI_ERR_BADFMT) return "File is not a valid CPI file";
116 /* This relies on the same error codes being used by the CPI & PSF libs */
117 if (err) return psf_error_string(err);
118
119 /* If no height given, take the first one we find. If there is a height
120 * given, then look it up anyway so we know the width to use for the
121 * output. */
122 fontw = -1;
123 for (cph = cpi.firstpage; cph != NULL; cph = cph->next)
124 for (cpf = cph->fonts; cpf != NULL; cpf = cpf->next)
125 {
126 if (height == -1 || cpf->height == height)
127 {
128 height = cpf->height;
129 fontw = cpf->width;
130 goto gotheight; /* Break out of 2 loops */
131 }
132 }
133 gotheight:
134 if (fontw < 0) return "Requested font size not found in CPI file.";
135 /* Prepare for dump... */
136 for (cph = cpi.firstpage; cph != NULL; cph = cph->next)
137 {
138 /* If user requested only one codepage, only do that
139 * codepage */
140 if (cpage != -1 && cph->codepage != cpage) continue;
141
142 sprintf(buf, "CP%d", cph->codepage);
143 codepage = psf_find_mapping(buf);
144 if (cpage == -1 && codepage == NULL)
145 {
146 fprintf(stderr, "Warning: No Unicode mapping "
147 "known for codepage %d; it will "
148 "be skipped.\n", cph->codepage);
149 continue;
150 }
151 if (!cph->fonts)
152 {
153 fprintf(stderr, "Codepage %d has no fonts; "
154 "it will be skipped.\n",
155 cph->codepage);
156 }
157 nchars = cph->fonts->nchars;
158 if (codepage)
159 {
160 if (nchars > 256) nchars = 256;
161 for (n = 0; n < nchars; n++)
162 {
163 if (unicode_add(codepage->psfm_tokens[n]))
164 return "Out of memory";
165 }
166 }
167 }
168 /* OK. There are unicodes_count unique codepoints */
169 psf_file_new(&psf);
170 if (unicodes_count)
171 {
172 /* 1.0.3: If extracting a single page, create a PSF that will hold 256
173 * characters, rather than merging identical Unicode codepoints */
174 if (cpage == -1)
175 rv = psf_file_create(&psf, fontw, height, unicodes_count, 1);
176 else rv = psf_file_create(&psf, fontw, height, nchars, 1);
177 }
178 else rv = psf_file_create(&psf, fontw, height, nchars, 0);
179 if (rv) return psf_error_string(rv);
180 /* Dump the character bitmaps */
181 for (cph = cpi.firstpage; cph != NULL; cph = cph->next)
182 {
183 /* Include this codepage? */
184 if (cpage != -1 && cph->codepage != cpage) continue;
185
186 sprintf(buf, "CP%d", cph->codepage);
187 codepage = psf_find_mapping(buf);
188 if (cpage == -1 && codepage == NULL) continue;
189 if (!cph->fonts) continue;
190 nchars = cph->fonts->nchars;
191 if (nchars > 256) nchars = 256;
192 for (n = 0; n < nchars; n++)
193 {
194 cpi_byte *dst = NULL;
195 cpi_byte *src = cpi_find_glyph(&cpi,
196 cph->codepage, height, fontw, n);
197 if (!src) continue;
198 /* psftools 1.0.3: If extracting a single page, then retain the order of
199 * characters that it used. For compatibility with the way --codepage works
200 * in other psftools. */
201 if (codepage && (cpage == -1))
202 {
203 glyph = codepage->psfm_tokens[n][0];
204 for (m = 0; m < unicodes_count; m++)
205 {
206 if (unicodes[m] == glyph)
207 {
208 dst = psf.psf_data + m * psf.psf_charlen;
209 /* Add the entry, if it doesn't exist */
210 if (psf_unicode_lookup(&psf, glyph, NULL) == PSF_E_NOTFOUND) psf_unicode_addmap(&psf, m, codepage, n);
211 break;
212 }
213 }
214 }
215 /* Extracting a single codepage, but we can add Unicode mappings */
216 else
217 {
218 dst = psf.psf_data + n * psf.psf_charlen;
219 if (codepage && (n < 256))
220 {
221 psf_unicode_addmap(&psf, n, codepage, n);
222 }
223 }
224 if (dst) memcpy(dst, src, psf.psf_charlen);
225 }
226 }
227 if (v1) psf_force_v1(&psf);
228 if (v2) psf_force_v2(&psf);
229 rv = psf_file_write(&psf, outfile);
230 psf_file_delete(&psf);
231 if (rv) return psf_error_string(rv);
232 return NULL;
233 }
234
235