Blame contrib/codepage.c

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
}