2 * CPI.C: A program to examine MSDOS codepage files (*.cpi)
3 * and extract specific codepages.
4 * Compiles under Linux & DOS (using BC++ 3.1).
6 * Compile: gcc -o cpi cpi.c
7 * Call: codepage [-a|-l|nnn] file.cpi
9 * Author: Ahmed M. Naas (ahmed@oea.xs4all.nl)
10 * Many changes: aeb@cwi.nl [changed until it would handle all
11 * *.cpi files people have sent me; I have no documentation,
12 * so all this is experimental]
13 * Remains to do: DRDOS fonts.
15 * Copyright: Public domain.
23 int handle_codepage(int);
24 void handle_fontfile(void);
26 #define PACKED __attribute__ ((packed))
27 /* Use this (instead of the above) to compile under MSDOS */
31 unsigned char id0 PACKED;
32 unsigned char id[7] PACKED;
33 unsigned char res[8] PACKED;
34 unsigned short pnum PACKED; /* number of pointers */
35 unsigned char ptyp PACKED; /* type of pointers */
36 unsigned long fih_offset PACKED; /* FontInfoHeader offset */
43 unsigned char num_fonts PACKED; /* N = 4 fonts per code page*/
44 unsigned char font_height[N] PACKED;
45 unsigned long dfd_offset[N] PACKED; /* DisplayFontData offset */
46 } DRDOS_ExtendedFontFileHeader;
49 unsigned short num_codepages PACKED;
53 unsigned short size PACKED;
54 unsigned long off_nexthdr PACKED;
55 unsigned short device_type PACKED; /* screen=1; printer=2 */
56 unsigned char device_name[8] PACKED;
57 unsigned short codepage PACKED;
58 unsigned char res[6] PACKED;
59 unsigned long off_font PACKED;
63 unsigned short reserved PACKED;
64 unsigned short num_fonts PACKED;
65 unsigned short size PACKED;
69 unsigned char height PACKED;
70 unsigned char width PACKED;
71 unsigned short reserved PACKED;
72 unsigned short num_chars PACKED;
76 unsigned short printer_type PACKED;
77 unsigned short seqlength PACKED;
83 int opta, optc, optl, optL, optx;
87 unsigned short codepage;
89 int main (int argc, char *argv[]) {
93 opta = optc = optl = optL = optx = 0;
99 switch(getopt(argc, argv, "alLc")) {
122 if ((in = fopen(argv[optind], "r")) == NULL) {
123 printf("\nUnable to open file %s.\n", argv[optind]);
130 if (optind != argc) {
131 if (optind != argc-1 || opta)
133 codepage = atoi(argv[optind]);
143 printf("no page %d found\n", codepage);
155 j = fread(&FontFileHeader, 1, sizeof(FontFileHeader), in);
156 if (j != sizeof(FontFileHeader)) {
157 printf("error reading FontFileHeader - got %d chars\n", j);
161 printf("FontFileHeader: id=0x%x \"%7.7s\" res=%8.8s "
162 "num=%d typ=%d fih_offset=%ld\n\n",
163 FontFileHeader.id0, FontFileHeader.id, FontFileHeader.res,
164 FontFileHeader.pnum, FontFileHeader.ptyp,
165 FontFileHeader.fih_offset);
167 if (!strcmp(FontFileHeader.id, "DRFONT ")) {
169 j = fread(&DRDOS_ExtendedFontFileHeader, 1,
170 sizeof(DRDOS_ExtendedFontFileHeader), in);
171 if (j != sizeof(DRDOS_ExtendedFontFileHeader)) {
172 printf("error reading ExtendedFontFileHeader - "
173 "got %d chars\n", j);
176 if (DRDOS_ExtendedFontFileHeader.num_fonts != N) {
177 printf("found %d instead of 4 fonts in drfont\n",
178 DRDOS_ExtendedFontFileHeader.num_fonts);
182 printf("ExtendedFontFileHeader:\n");
183 for (j=0; j<N; j++) {
184 printf("font%d: height %d dfd_offset %d\n", j,
185 DRDOS_ExtendedFontFileHeader.font_height[j],
186 DRDOS_ExtendedFontFileHeader.dfd_offset[j]);
192 j = fread(&FontInfoHeader, 1, sizeof(FontInfoHeader), in);
193 if (j != sizeof(FontInfoHeader)) {
194 printf("error reading FontInfoHeader - got %d chars\n", j);
198 printf("FontInfoHeader: num_codepages=%d\n\n",
199 FontInfoHeader.num_codepages);
203 printf("this program cannot handle DRDOS font files\n");
208 for (i = FontInfoHeader.num_codepages; i; i--)
209 if (handle_codepage(i-1))
214 handle_codepage(int more_to_come) {
217 unsigned char *fonts;
220 j = fread(&CPEntryHeader, 1, sizeof(CPEntryHeader), in);
221 if (j != sizeof(CPEntryHeader)) {
222 printf("error reading CPEntryHeader - got %d chars\n", j);
226 int t = CPEntryHeader.device_type;
227 printf("CPEntryHeader: size=%d dev=%d [%s] name=%8.8s "
228 "codepage=%d\n\t\tres=%6.6s nxt=%ld off_font=%ld\n\n",
230 t, (t==1) ? "screen" : (t==2) ? "printer" : "?",
231 CPEntryHeader.device_name,
232 CPEntryHeader.codepage,
234 CPEntryHeader.off_nexthdr, CPEntryHeader.off_font);
236 printf("\nCodepage = %d\n", CPEntryHeader.codepage);
237 printf("Device = %.8s\n", CPEntryHeader.device_name);
240 if (CPEntryHeader.size != sizeof(CPEntryHeader)) {
241 /* seen 26 and 28, so that the difference below is -2 or 0 */
243 printf("Skipping %d bytes of garbage\n",
244 CPEntryHeader.size - sizeof(CPEntryHeader));
245 fseek(in, CPEntryHeader.size - sizeof(CPEntryHeader),
249 if (!opta && (!optx || CPEntryHeader.codepage != codepage) && !optc)
253 if (inpos != CPEntryHeader.off_font && !optc) {
255 printf("pos=%ld font at %ld\n", inpos, CPEntryHeader.off_font);
256 fseek(in, CPEntryHeader.off_font, SEEK_SET);
259 j = fread(&CPInfoHeader, 1, sizeof(CPInfoHeader), in);
260 if (j != sizeof(CPInfoHeader)) {
261 printf("error reading CPInfoHeader - got %d chars\n", j);
265 printf("Number of Fonts = %d\n", CPInfoHeader.num_fonts);
266 printf("Size of Bitmap = %d\n", CPInfoHeader.size);
268 if (CPInfoHeader.num_fonts == 0)
273 sprintf(outfile, "%d.cp", CPEntryHeader.codepage);
274 if ((out = fopen(outfile, "w")) == NULL) {
275 printf("\nUnable to open file %s.\n", outfile);
277 } else printf("\nWriting %s\n", outfile);
279 fonts = (unsigned char *) malloc(CPInfoHeader.size);
281 fread(fonts, CPInfoHeader.size, 1, in);
282 fwrite(&CPEntryHeader, sizeof(CPEntryHeader), 1, out);
283 fwrite(&CPInfoHeader, sizeof(CPInfoHeader), 1, out);
284 j = fwrite(fonts, 1, CPInfoHeader.size, out);
285 if (j != CPInfoHeader.size) {
286 printf("error writing %s - wrote %d chars\n", outfile, j);
294 * It seems that if entry headers and fonts are interspersed,
295 * then nexthdr will point past the font, regardless of
296 * whether more entries follow.
297 * Otherwise, first all entry headers are given, and then
298 * all fonts; in this case nexthdr will be 0 in the last entry.
300 nexthdr = CPEntryHeader.off_nexthdr;
301 if (nexthdr == 0 || nexthdr == -1) {
303 printf("more codepages expected, but nexthdr=%ld\n",
311 if (inpos != CPEntryHeader.off_nexthdr) {
313 printf("pos=%ld nexthdr at %ld\n", inpos, nexthdr);
314 if (opta && !more_to_come) {
315 printf("no more code pages, but nexthdr != 0\n");
319 fseek(in, CPEntryHeader.off_nexthdr, SEEK_SET);
327 printf("\nUsage: cpi code_page_file [-c] [-L] [-l] [-a|nnn]\n");
328 printf(" -c: input file is a single codepage\n");
329 printf(" -L: print header info (you don't want to see this)\n");
330 printf(" -l or no option: list all codepages contained in the file\n");
331 printf(" -a: extract all codepages from the file\n");
332 printf(" nnn (3 digits): extract codepage nnn from the file\n");
333 printf("Example: cpi ega.cpi 850 \n");
334 printf(" will create a file 850.cp containing the requested codepage.\n\n");