|
Packit Service |
50ad14 |
/*
|
|
Packit Service |
50ad14 |
* CPI.C: A program to examine MSDOS codepage files (*.cpi)
|
|
Packit Service |
50ad14 |
* and extract specific codepages.
|
|
Packit Service |
50ad14 |
* Compiles under Linux & DOS (using BC++ 3.1).
|
|
Packit Service |
50ad14 |
*
|
|
Packit Service |
50ad14 |
* Compile: gcc -o cpi cpi.c
|
|
Packit Service |
50ad14 |
* Call: codepage [-a|-l|nnn] file.cpi
|
|
Packit Service |
50ad14 |
*
|
|
Packit Service |
50ad14 |
* Author: Ahmed M. Naas (ahmed@oea.xs4all.nl)
|
|
Packit Service |
50ad14 |
* Many changes: aeb@cwi.nl [changed until it would handle all
|
|
Packit Service |
50ad14 |
* *.cpi files people have sent me; I have no documentation,
|
|
Packit Service |
50ad14 |
* so all this is experimental]
|
|
Packit Service |
50ad14 |
* Remains to do: DRDOS fonts.
|
|
Packit Service |
50ad14 |
*
|
|
Packit Service |
50ad14 |
* Copyright: Public domain.
|
|
Packit Service |
50ad14 |
*/
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
#include <stdio.h>
|
|
Packit Service |
50ad14 |
#include <stdlib.h>
|
|
Packit Service |
50ad14 |
#include <string.h>
|
|
Packit Service |
50ad14 |
#include <unistd.h>
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
int handle_codepage(int);
|
|
Packit Service |
50ad14 |
void handle_fontfile(void);
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
#define PACKED __attribute__((packed))
|
|
Packit Service |
50ad14 |
/* Use this (instead of the above) to compile under MSDOS */
|
|
Packit Service |
50ad14 |
/*#define PACKED */
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned char id0 PACKED;
|
|
Packit Service |
50ad14 |
unsigned char id[7] PACKED;
|
|
Packit Service |
50ad14 |
unsigned char res[8] PACKED;
|
|
Packit Service |
50ad14 |
unsigned short pnum PACKED; /* number of pointers */
|
|
Packit Service |
50ad14 |
unsigned char ptyp PACKED; /* type of pointers */
|
|
Packit Service |
50ad14 |
unsigned long fih_offset PACKED; /* FontInfoHeader offset */
|
|
Packit Service |
50ad14 |
} FontFileHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
int drfont = 0;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
#define N 4
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned char num_fonts PACKED; /* N = 4 fonts per code page*/
|
|
Packit Service |
50ad14 |
unsigned char font_height[N] PACKED;
|
|
Packit Service |
50ad14 |
unsigned long dfd_offset[N] PACKED; /* DisplayFontData offset */
|
|
Packit Service |
50ad14 |
} DRDOS_ExtendedFontFileHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned short num_codepages PACKED;
|
|
Packit Service |
50ad14 |
} FontInfoHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned short size PACKED;
|
|
Packit Service |
50ad14 |
unsigned long off_nexthdr PACKED;
|
|
Packit Service |
50ad14 |
unsigned short device_type PACKED; /* screen=1; printer=2 */
|
|
Packit Service |
50ad14 |
unsigned char device_name[8] PACKED;
|
|
Packit Service |
50ad14 |
unsigned short codepage PACKED;
|
|
Packit Service |
50ad14 |
unsigned char res[6] PACKED;
|
|
Packit Service |
50ad14 |
unsigned long off_font PACKED;
|
|
Packit Service |
50ad14 |
} CPEntryHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned short reserved PACKED;
|
|
Packit Service |
50ad14 |
unsigned short num_fonts PACKED;
|
|
Packit Service |
50ad14 |
unsigned short size PACKED;
|
|
Packit Service |
50ad14 |
} CPInfoHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned char height PACKED;
|
|
Packit Service |
50ad14 |
unsigned char width PACKED;
|
|
Packit Service |
50ad14 |
unsigned short reserved PACKED;
|
|
Packit Service |
50ad14 |
unsigned short num_chars PACKED;
|
|
Packit Service |
50ad14 |
} ScreenFontHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
struct {
|
|
Packit Service |
50ad14 |
unsigned short printer_type PACKED;
|
|
Packit Service |
50ad14 |
unsigned short seqlength PACKED;
|
|
Packit Service |
50ad14 |
} PrinterFontHeader;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
FILE *in, *out;
|
|
Packit Service |
50ad14 |
void usage(void);
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
int opta, optc, optl, optL, optx;
|
|
Packit Service |
50ad14 |
extern int optind;
|
|
Packit Service |
50ad14 |
extern char *optarg;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
unsigned short codepage;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
int main(int argc, char *argv[])
|
|
Packit Service |
50ad14 |
{
|
|
Packit Service |
50ad14 |
if (argc < 2)
|
|
Packit Service |
50ad14 |
usage();
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
opta = optc = optl = optL = optx = 0;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
if (argc == 2)
|
|
Packit Service |
50ad14 |
optl = 1;
|
|
Packit Service |
50ad14 |
else
|
|
Packit Service |
50ad14 |
while (1) {
|
|
Packit Service |
50ad14 |
switch (getopt(argc, argv, "alLc")) {
|
|
Packit Service |
50ad14 |
case 'a':
|
|
Packit Service |
50ad14 |
opta = 1;
|
|
Packit Service |
50ad14 |
continue;
|
|
Packit Service |
50ad14 |
case 'c':
|
|
Packit Service |
50ad14 |
optc = 1;
|
|
Packit Service |
50ad14 |
continue;
|
|
Packit Service |
50ad14 |
case 'L':
|
|
Packit Service |
50ad14 |
optL = 1;
|
|
Packit Service |
50ad14 |
continue;
|
|
Packit Service |
50ad14 |
case 'l':
|
|
Packit Service |
50ad14 |
optl = 1;
|
|
Packit Service |
50ad14 |
continue;
|
|
Packit Service |
50ad14 |
case '?':
|
|
Packit Service |
50ad14 |
default:
|
|
Packit Service |
50ad14 |
usage();
|
|
Packit Service |
50ad14 |
case -1:
|
|
Packit Service |
50ad14 |
break;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
break;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
if (optind < argc) {
|
|
Packit Service |
50ad14 |
if ((in = fopen(argv[optind], "r")) == NULL) {
|
|
Packit Service |
50ad14 |
printf("\nUnable to open file %s.\n", argv[optind]);
|
|
Packit Service |
50ad14 |
exit(0);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
optind++;
|
|
Packit Service |
50ad14 |
} else
|
|
Packit Service |
50ad14 |
usage();
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
if (optind != argc) {
|
|
Packit Service |
50ad14 |
if (optind != argc - 1 || opta)
|
|
Packit Service |
50ad14 |
usage();
|
|
Packit Service |
50ad14 |
codepage = atoi(argv[optind]);
|
|
Packit Service |
50ad14 |
optx = 1;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
if (optc)
|
|
Packit Service |
50ad14 |
handle_codepage(0);
|
|
Packit Service |
50ad14 |
else
|
|
Packit Service |
50ad14 |
handle_fontfile();
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
if (optx) {
|
|
Packit Service |
50ad14 |
printf("no page %d found\n", codepage);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
fclose(in);
|
|
Packit Service |
50ad14 |
return (0);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
void handle_fontfile()
|
|
Packit Service |
50ad14 |
{
|
|
Packit Service |
50ad14 |
int i, j;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
j = fread(&FontFileHeader, 1, sizeof(FontFileHeader), in);
|
|
Packit Service |
50ad14 |
if (j != sizeof(FontFileHeader)) {
|
|
Packit Service |
50ad14 |
printf("error reading FontFileHeader - got %d chars\n", j);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (optL)
|
|
Packit Service |
50ad14 |
printf("FontFileHeader: id=0x%x \"%7.7s\" res=%8.8s "
|
|
Packit Service |
50ad14 |
"num=%d typ=%d fih_offset=%ld\n\n",
|
|
Packit Service |
50ad14 |
FontFileHeader.id0, FontFileHeader.id, FontFileHeader.res,
|
|
Packit Service |
50ad14 |
FontFileHeader.pnum, FontFileHeader.ptyp,
|
|
Packit Service |
50ad14 |
FontFileHeader.fih_offset);
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
if (!strcmp(FontFileHeader.id, "DRFONT ")) {
|
|
Packit Service |
50ad14 |
drfont = 1;
|
|
Packit Service |
50ad14 |
j = fread(&DRDOS_ExtendedFontFileHeader, 1,
|
|
Packit Service |
50ad14 |
sizeof(DRDOS_ExtendedFontFileHeader), in);
|
|
Packit Service |
50ad14 |
if (j != sizeof(DRDOS_ExtendedFontFileHeader)) {
|
|
Packit Service |
50ad14 |
printf("error reading ExtendedFontFileHeader - "
|
|
Packit Service |
50ad14 |
"got %d chars\n",
|
|
Packit Service |
50ad14 |
j);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (DRDOS_ExtendedFontFileHeader.num_fonts != N) {
|
|
Packit Service |
50ad14 |
printf("found %d instead of 4 fonts in drfont\n",
|
|
Packit Service |
50ad14 |
DRDOS_ExtendedFontFileHeader.num_fonts);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (optL) {
|
|
Packit Service |
50ad14 |
printf("ExtendedFontFileHeader:\n");
|
|
Packit Service |
50ad14 |
for (j = 0; j < N; j++) {
|
|
Packit Service |
50ad14 |
printf("font%d: height %d dfd_offset %d\n", j,
|
|
Packit Service |
50ad14 |
DRDOS_ExtendedFontFileHeader.font_height[j],
|
|
Packit Service |
50ad14 |
DRDOS_ExtendedFontFileHeader.dfd_offset[j]);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
printf("\n");
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
j = fread(&FontInfoHeader, 1, sizeof(FontInfoHeader), in);
|
|
Packit Service |
50ad14 |
if (j != sizeof(FontInfoHeader)) {
|
|
Packit Service |
50ad14 |
printf("error reading FontInfoHeader - got %d chars\n", j);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (optL)
|
|
Packit Service |
50ad14 |
printf("FontInfoHeader: num_codepages=%d\n\n",
|
|
Packit Service |
50ad14 |
FontInfoHeader.num_codepages);
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
#if 1
|
|
Packit Service |
50ad14 |
if (drfont) {
|
|
Packit Service |
50ad14 |
printf("this program cannot handle DRDOS font files\n");
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
#endif
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
for (i = FontInfoHeader.num_codepages; i; i--)
|
|
Packit Service |
50ad14 |
if (handle_codepage(i - 1))
|
|
Packit Service |
50ad14 |
break;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
int handle_codepage(int more_to_come)
|
|
Packit Service |
50ad14 |
{
|
|
Packit Service |
50ad14 |
int j;
|
|
Packit Service |
50ad14 |
char outfile[20];
|
|
Packit Service |
50ad14 |
unsigned char *fonts;
|
|
Packit Service |
50ad14 |
long inpos, nexthdr;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
j = fread(&CPEntryHeader, 1, sizeof(CPEntryHeader), in);
|
|
Packit Service |
50ad14 |
if (j != sizeof(CPEntryHeader)) {
|
|
Packit Service |
50ad14 |
printf("error reading CPEntryHeader - got %d chars\n", j);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (optL) {
|
|
Packit Service |
50ad14 |
int t = CPEntryHeader.device_type;
|
|
Packit Service |
50ad14 |
printf("CPEntryHeader: size=%d dev=%d [%s] name=%8.8s "
|
|
Packit Service |
50ad14 |
"codepage=%d\n\t\tres=%6.6s nxt=%ld off_font=%ld\n\n",
|
|
Packit Service |
50ad14 |
CPEntryHeader.size,
|
|
Packit Service |
50ad14 |
t, (t == 1) ? "screen" : (t == 2) ? "printer" : "?",
|
|
Packit Service |
50ad14 |
CPEntryHeader.device_name,
|
|
Packit Service |
50ad14 |
CPEntryHeader.codepage,
|
|
Packit Service |
50ad14 |
CPEntryHeader.res,
|
|
Packit Service |
50ad14 |
CPEntryHeader.off_nexthdr, CPEntryHeader.off_font);
|
|
Packit Service |
50ad14 |
} else if (optl) {
|
|
Packit Service |
50ad14 |
printf("\nCodepage = %d\n", CPEntryHeader.codepage);
|
|
Packit Service |
50ad14 |
printf("Device = %.8s\n", CPEntryHeader.device_name);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
#if 0
|
|
Packit Service |
50ad14 |
if (CPEntryHeader.size != sizeof(CPEntryHeader)) {
|
|
Packit Service |
50ad14 |
/* seen 26 and 28, so that the difference below is -2 or 0 */
|
|
Packit Service |
50ad14 |
if (optl)
|
|
Packit Service |
50ad14 |
printf("Skipping %d bytes of garbage\n",
|
|
Packit Service |
50ad14 |
CPEntryHeader.size - sizeof(CPEntryHeader));
|
|
Packit Service |
50ad14 |
fseek(in, CPEntryHeader.size - sizeof(CPEntryHeader),
|
|
Packit Service |
50ad14 |
SEEK_CUR);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
#endif
|
|
Packit Service |
50ad14 |
if (!opta && (!optx || CPEntryHeader.codepage != codepage) && !optc)
|
|
Packit Service |
50ad14 |
goto next;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
inpos = ftell(in);
|
|
Packit Service |
50ad14 |
if (inpos != CPEntryHeader.off_font && !optc) {
|
|
Packit Service |
50ad14 |
if (optL)
|
|
Packit Service |
50ad14 |
printf("pos=%ld font at %ld\n", inpos, CPEntryHeader.off_font);
|
|
Packit Service |
50ad14 |
fseek(in, CPEntryHeader.off_font, SEEK_SET);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
j = fread(&CPInfoHeader, 1, sizeof(CPInfoHeader), in);
|
|
Packit Service |
50ad14 |
if (j != sizeof(CPInfoHeader)) {
|
|
Packit Service |
50ad14 |
printf("error reading CPInfoHeader - got %d chars\n", j);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (optl) {
|
|
Packit Service |
50ad14 |
printf("Number of Fonts = %d\n", CPInfoHeader.num_fonts);
|
|
Packit Service |
50ad14 |
printf("Size of Bitmap = %d\n", CPInfoHeader.size);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
if (CPInfoHeader.num_fonts == 0)
|
|
Packit Service |
50ad14 |
goto next;
|
|
Packit Service |
50ad14 |
if (optc)
|
|
Packit Service |
50ad14 |
return 0;
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
sprintf(outfile, "%d.cp", CPEntryHeader.codepage);
|
|
Packit Service |
50ad14 |
if ((out = fopen(outfile, "w")) == NULL) {
|
|
Packit Service |
50ad14 |
printf("\nUnable to open file %s.\n", outfile);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
} else
|
|
Packit Service |
50ad14 |
printf("\nWriting %s\n", outfile);
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
fonts = (unsigned char *)malloc(CPInfoHeader.size);
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
fread(fonts, CPInfoHeader.size, 1, in);
|
|
Packit Service |
50ad14 |
fwrite(&CPEntryHeader, sizeof(CPEntryHeader), 1, out);
|
|
Packit Service |
50ad14 |
fwrite(&CPInfoHeader, sizeof(CPInfoHeader), 1, out);
|
|
Packit Service |
50ad14 |
j = fwrite(fonts, 1, CPInfoHeader.size, out);
|
|
Packit Service |
50ad14 |
if (j != CPInfoHeader.size) {
|
|
Packit Service |
50ad14 |
printf("error writing %s - wrote %d chars\n", outfile, j);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
fclose(out);
|
|
Packit Service |
50ad14 |
free(fonts);
|
|
Packit Service |
50ad14 |
if (optx)
|
|
Packit Service |
50ad14 |
exit(0);
|
|
Packit Service |
50ad14 |
next:
|
|
Packit Service |
50ad14 |
/*
|
|
Packit Service |
50ad14 |
* It seems that if entry headers and fonts are interspersed,
|
|
Packit Service |
50ad14 |
* then nexthdr will point past the font, regardless of
|
|
Packit Service |
50ad14 |
* whether more entries follow.
|
|
Packit Service |
50ad14 |
* Otherwise, first all entry headers are given, and then
|
|
Packit Service |
50ad14 |
* all fonts; in this case nexthdr will be 0 in the last entry.
|
|
Packit Service |
50ad14 |
*/
|
|
Packit Service |
50ad14 |
nexthdr = CPEntryHeader.off_nexthdr;
|
|
Packit Service |
50ad14 |
if (nexthdr == 0 || nexthdr == -1) {
|
|
Packit Service |
50ad14 |
if (more_to_come) {
|
|
Packit Service |
50ad14 |
printf("more codepages expected, but nexthdr=%ld\n",
|
|
Packit Service |
50ad14 |
nexthdr);
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
} else
|
|
Packit Service |
50ad14 |
return 1;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
inpos = ftell(in);
|
|
Packit Service |
50ad14 |
if (inpos != CPEntryHeader.off_nexthdr) {
|
|
Packit Service |
50ad14 |
if (optL)
|
|
Packit Service |
50ad14 |
printf("pos=%ld nexthdr at %ld\n", inpos, nexthdr);
|
|
Packit Service |
50ad14 |
if (opta && !more_to_come) {
|
|
Packit Service |
50ad14 |
printf("no more code pages, but nexthdr != 0\n");
|
|
Packit Service |
50ad14 |
return 1;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
fseek(in, CPEntryHeader.off_nexthdr, SEEK_SET);
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
return 0;
|
|
Packit Service |
50ad14 |
}
|
|
Packit Service |
50ad14 |
|
|
Packit Service |
50ad14 |
void usage(void)
|
|
Packit Service |
50ad14 |
{
|
|
Packit Service |
50ad14 |
printf("\nUsage: cpi code_page_file [-c] [-L] [-l] [-a|nnn]\n");
|
|
Packit Service |
50ad14 |
printf(" -c: input file is a single codepage\n");
|
|
Packit Service |
50ad14 |
printf(" -L: print header info (you don't want to see this)\n");
|
|
Packit Service |
50ad14 |
printf(" -l or no option: list all codepages contained in the file\n");
|
|
Packit Service |
50ad14 |
printf(" -a: extract all codepages from the file\n");
|
|
Packit Service |
50ad14 |
printf(" nnn (3 digits): extract codepage nnn from the file\n");
|
|
Packit Service |
50ad14 |
printf("Example: cpi ega.cpi 850 \n");
|
|
Packit Service |
50ad14 |
printf(" will create a file 850.cp containing the requested codepage.\n\n");
|
|
Packit Service |
50ad14 |
exit(1);
|
|
Packit Service |
50ad14 |
}
|