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 #ifndef SEEK_SET	/* Why doesn't Pacific define this? */
23 #define SEEK_SET 0
24 #define SEEK_CUR 1
25 #define SEEK_END 2
26 #endif
27 
28 /* Convert a raw font to a .PSF font.
29  *
30  * If input is coming from a file, we can guess the height of glyphs by
31  * assuming 256 glyphs in the file. If input is coming from a pipe, the
32  * user has to specify glyph height.
33  */
34 
35 static char helpbuf[2048];
36 static int width  = 8;
37 static int height = 0;
38 static int skip   = 0;
39 static int doflip = 0;
40 static int first  = 0;
41 static int last   = 255;
42 static int v1 = 0, v2 = 0;
43 static PSF_MAPPING *codepage = NULL;
44 static PSF_FILE psf;
45 
46 /* Program name */
47 char *cnv_progname = "RAW2PSF";
48 
49 /* ddash = 1 if option started with a double-dash; else 0 */
50 /* Return NULL if OK, else error string */
cnv_set_option(int ddash,char * variable,char * value)51 char *cnv_set_option(int ddash, char *variable, char *value)
52     {
53     if (!stricmp(variable, "width"))  { width  = atoi(value); return NULL; }
54     if (!stricmp(variable, "height")) { height = atoi(value); return NULL; }
55     if (!stricmp(variable, "skip"))   { skip   = atoi(value); return NULL; }
56     if (!stricmp(variable, "first"))  { first  = atoi(value); return NULL; }
57     if (!stricmp(variable, "last"))   { last   = atoi(value); return NULL; }
58     if (!stricmp(variable, "flip"))   { doflip = 1; return NULL; }
59     if (!stricmp(variable, "psf1"))   { v1 = 1; return NULL; }
60     if (!stricmp(variable, "psf2"))   { v2 = 1; return NULL; }
61     if (!stricmp(variable, "512"))    { first = 0; last = 511; return NULL; }
62     if (!stricmp(variable, "codepage"))
63 	{
64 	codepage = psf_find_mapping(value);
65 	if (codepage == NULL) return "Code page name not recognised.";
66 	return NULL;
67 	}
68     if (strlen(variable) > 2000) variable[2000] = 0;
69     sprintf(helpbuf, "Unknown option: %s\n", variable);
70     return helpbuf;
71     }
72 
73 
74 /* Return help string */
cnv_help(void)75 char *cnv_help(void)
76     {
77     sprintf(helpbuf, "Syntax: %s rawfnt psffile { options }\n\n", cnv_progname);
78     strcat (helpbuf, "Options: \n"
79 	             "    --height=x     Height of glyphs\n"
80 	             "    --width=x      Width of glyphs (defaults to 8)\n"
81 	             "    --skip=x       Skip x characters at start of raw file (defaults to 0)\n"
82                      "    --first=x      First character to use in the PSF\n"
83 	             "    --last=x       Last character to go into PSF (defaults to 255)\n"
84 	             "    --codepage=x   Create a Unicode directory from the specified code page\n"
85 		     "    --flip         Mirror all bytes in the file\n"
86                      "    --512          Equivalent to --first=0 --last=511\n"
87                      "    --psf1         Output in PSF1 format\n"
88                      "    --psf2         Output in PSF2 format (default) \n");
89 
90     return helpbuf;
91     }
92 
93 
cnv_execute(FILE * infile,FILE * outfile)94 char *cnv_execute(FILE *infile, FILE *outfile)
95 {
96 	int rv, n, max;
97 	psf_dword count, pos;
98 	long len = 0;
99 
100 	count = last + 1;
101 	if (infile == stdin) pos = -1;
102 	else pos = ftell(infile);
103 
104 /* Guess height from file size, if possible */
105 	if (pos != -1)
106 	{
107 		if (fseek(infile, 0,   SEEK_END) >= 0 &&
108                     (len = ftell(infile))        >= 0 &&
109 		    fseek(infile, pos, SEEK_SET) >= 0);
110 		else  pos = -1;
111 	}
112 	if (pos != -1 && height == 0)
113 	{
114 		len -= pos;
115 		height = (len / count) / ((width + 7) /8);
116 		fprintf(stderr, "From file size: height=%d\n",height);
117 	}
118 
119 	if (height == 0)
120 	{
121 		return "Can't convert with no \"--height\" option";
122 	}
123 
124 	psf_file_new(&psf);
125 	rv = psf_file_create(&psf, width, height, last + 1, 0);
126 	if (!rv)
127 	{
128 		skip *= psf.psf_charlen;
129 		while (skip)
130 		{
131 			if (fgetc(infile) == EOF) return "Unexpected end of file";
132 			--skip;
133 		}
134 		if (fread(psf.psf_data + first * psf.psf_charlen,
135 				psf.psf_charlen, last + 1 - first, infile) < last + 1 - first)
136 		{
137 			psf_file_delete(&psf);
138 			return "Could not read the input file.";
139 		}
140 		if (doflip)
141 		{
142 			max = last * psf.psf_charlen;
143 			for (n = first * psf.psf_charlen;
144 			     n < max; n++)
145 			{
146 				psf.psf_data[n] = flip(psf.psf_data[n]);
147 			}
148 
149 		}
150 		if (codepage)
151 		{
152 			int n;
153 			psf_file_create_unicode(&psf);
154 			for (n = first; n < last; n++) if (n < 256)
155 				psf_unicode_addmap(&psf, n, codepage, n);
156 		}
157 
158 
159 		if (v1) psf_force_v1(&psf);
160 		if (v2) psf_force_v2(&psf);
161 		rv = psf_file_write(&psf, outfile);
162 	}
163 	psf_file_delete(&psf);
164 	if (rv) return psf_error_string(rv);
165 	return NULL;
166 }
167 
168