/*****************************************************************************/
/* */
-/* main.c */
+/* main.c */
/* */
/* Main program of the chrcvt vector font converter */
/* */
/* */
/* */
-/* (C) 2000-2009, Ullrich von Bassewitz */
+/* (C) 2000-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* common */
#include "cmdline.h"
+#include "fname.h"
#include "print.h"
#include "strbuf.h"
#include "xmalloc.h"
*
* Header portion:
* .byte $54, $43, $48, $00 ; "TCH" version
- * .word <size of char definitions>
+ * .word <size of data portion>
* Data portion:
- * .byte <top> ; Value from $88
- * .byte <baseline> ; Value from $89
- * .byte <bottom> ; Negative value from $8A
+ * .byte <top> ; Baseline to top
+ * .byte <bottom> ; Baseline to bottom
+ * .byte <height> ; Maximum char height
* .byte <width>, ... ; $5F width bytes
* .word <char definition offset>, ... ; $5F char def offsets
* Character definitions:
* .word <converted opcode>, ...
* .byte $80
*
+ * The baseline of the character is assume to be at position zero. top and
+ * bottom are both positive values. The former extends in positive, the other
+ * in negative direction of the baseline. height contains the sum of top and
+ * bottom and is stored here just for easier handling.
+ *
* The opcodes get converted for easier handling: END is marked by bit 7
* set in the first byte. The second byte of this opcode is not needed.
* Bit 7 of the second byte marks a MOVE (bit 7 = 0) or DRAW (bit 7 = 1).
* is stored in the header.
*
* Above structure allows a program to read the header portion of the file,
- * validate it, read the width and offset tables into static storage, allocate
- * memory for the character definitions read them into memory in one chunk.
+ * validate it, then read the remainder of the file into memory in one chunk.
* The character definition offsets will then be converted into pointers by
* adding the character definition base pointer to each.
*/
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
/* Print usage information and exit */
{
fprintf (stderr,
- "Usage: %s [options] file [options] [file]\n"
- "Short options:\n"
- " -h\t\t\tHelp (this text)\n"
- " -V\t\t\tPrint the version number and exit\n"
- "\n"
- "Long options:\n"
- " --help\t\tHelp (this text)\n"
- " --version\t\tPrint the version number and exit\n",
- ProgName);
+ "Usage: %s [options] file [options] [file]\n"
+ "Short options:\n"
+ " -h\t\t\tHelp (this text)\n"
+ " -v\t\t\tBe more verbose\n"
+ " -V\t\t\tPrint the version number and exit\n"
+ "\n"
+ "Long options:\n"
+ " --help\t\tHelp (this text)\n"
+ " --verbose\t\tBe more verbose\n"
+ " --version\t\tPrint the version number and exit\n",
+ ProgName);
}
static void OptHelp (const char* Opt attribute ((unused)),
- const char* Arg attribute ((unused)))
+ const char* Arg attribute ((unused)))
/* Print usage information and exit */
{
Usage ();
static void OptVerbose (const char* Opt attribute ((unused)),
- const char* Arg attribute ((unused)))
+ const char* Arg attribute ((unused)))
/* Increase verbosity */
{
++Verbosity;
static void OptVersion (const char* Opt attribute ((unused)),
- const char* Arg attribute ((unused)))
+ const char* Arg attribute ((unused)))
/* Print the assembler version */
{
fprintf (stderr,
- "%s V%s - (C) Copyright 2009, Ullrich von Bassewitz\n",
- ProgName, GetVersionAsString ());
+ "%s V%s - (C) Copyright 2009, Ullrich von Bassewitz\n",
+ ProgName, GetVersionAsString ());
}
-static void ConvertChar (StrBuf* Data, const unsigned char* Buf)
+static void ConvertChar (StrBuf* Data, const unsigned char* Buf, int Remaining)
/* Convert data for one character. Original data is in Buf, converted data
* will be placed in Data.
*/
{
- /* We should check here for reading past the end of the buffer in case the
- * input data is not sane.
- */
+ /* Convert all drawing vectors for this character */
while (1) {
+ unsigned Op;
+
+ /* Check if we have enough data left */
+ if (Remaining < 2) {
+ Error ("End of file while parsing character definitions");
+ }
+
/* Get the next op word */
- unsigned Op = (Buf[0] + (Buf[1] << 8)) & 0x8080;
+ Op = (Buf[0] + (Buf[1] << 8)) & 0x8080;
/* Check the opcode */
switch (Op) {
case 0x0000:
/* End */
- SB_AppendChar (Data, 0x80);
+ if (SB_IsEmpty (Data)) {
+ /* No ops. We need to add an empty one */
+ SB_AppendChar (Data, 0x00);
+ SB_AppendChar (Data, 0x00);
+ }
+ /* Add an end marker to the last op in the buffer */
+ SB_GetBuf (Data)[SB_GetLen (Data) - 2] |= 0x80;
return;
case 0x0080:
/* Next Op */
Buf += 2;
+ Remaining -= 2;
}
}
{
/* The header of a BGI vector font file */
static const unsigned char ChrHeader[] = {
- 0x50, 0x4B, 0x08, 0x08, 0x42, 0x47, 0x49, 0x20
+ /* According to the Borland docs, the following should work, but it
+ * doesn't. Seems like there are fonts that work, but don't have the
+ * "BGI" string in the header. So we use just the PK\b\b mark as
+ * a header.
+ *
+ * 0x50, 0x4B, 0x08, 0x08, 0x42, 0x47, 0x49, 0x20 */
+ 0x50, 0x4B, 0x08, 0x08
};
/* The header of a TGI vector font file */
/* Try to open the file for reading */
FILE* F = fopen (Input, "rb");
if (F == 0) {
- Error ("Cannot open input file `%s': %s", Input, strerror (errno));
+ Error ("Cannot open input file `%s': %s", Input, strerror (errno));
}
/* Seek to the end and determine the size */
FirstChar = Buf[0x84];
CharCount = Buf[0x81] + (Buf[0x82] << 8);
LastChar = FirstChar + CharCount - 1;
- if (FirstChar < 0x20 || LastChar < 0x7E) {
+ if (FirstChar > 0x20 || LastChar < 0x7E) {
+ Print (stderr, 1, "FirstChar = $%04X, CharCount = %u\n",
+ FirstChar, CharCount);
Error ("File `%s' doesn't contain the chars we need", Input);
} else if (LastChar >= 0x100) {
Error ("File `%s' contains too many character definitions", Input);
/* Convert the characters */
for (Char = 0x20; Char <= 0x7E; ++Char, OffsetBuf += 2) {
+ int Remaining;
+
/* Add the offset to the offset table */
Offs = SB_GetLen (&VectorData);
SB_AppendChar (&Offsets, Offs & 0xFF);
/* Get the offset of the vector data in the BGI data buffer */
Offs = OffsetBuf[0] + (OffsetBuf[1] << 8);
+ /* Calculate the remaining data in the buffer for this character */
+ Remaining = Size - (Offs + (VectorBuf - Buf));
+
/* Check if the offset is valid */
- if (Offs + (VectorBuf - Buf) > Size) {
+ if (Remaining <= 0) {
Error ("Invalid data offset in input file `%s'", Input);
}
/* Convert the vector data and place it into the buffer */
- ConvertChar (&VectorData, VectorBuf + Offs);
+ ConvertChar (&VectorData, VectorBuf + Offs, Remaining);
}
/* Complete the TCH header */
- Offs = SB_GetLen (&VectorData);
+ Offs = 3 + 0x5F + 2*0x5F + SB_GetLen (&VectorData);
TchHeader[4] = Offs & 0xFF;
TchHeader[5] = (Offs >> 8) & 0xFF;
TchHeader[6] = Buf[0x88];
- TchHeader[7] = Buf[0x89];
- TchHeader[8] = (unsigned char) -(signed char)(Buf[0x8A]);
+ TchHeader[7] = (unsigned char) -(signed char)(Buf[0x8A]);
+ TchHeader[8] = TchHeader[6] + TchHeader[7];
+
+ /* The baseline must be zero, otherwise we cannot convert */
+ if (Buf[0x89] != 0) {
+ Error ("Baseline of font in `%s' is not zero", Input);
+ }
+
+ /* If the output file is NULL, use the name of the input file with ".tch"
+ * appended.
+ */
+ if (Output == 0) {
+ Output = MakeFilename (Input, ".tch");
+ }
/* Open the output file */
F = fopen (Output, "wb");
if (F == 0) {
- Error ("Cannot open output file `%s': %s", Output, strerror (errno));
+ Error ("Cannot open output file `%s': %s", Output, strerror (errno));
}
/* Write the header to the output file */
}
/* Write the data to the output file */
+ Offs = SB_GetLen (&VectorData);
if (fwrite (SB_GetConstBuf (&VectorData), 1, Offs, F) != Offs) {
Error ("Error writing to `%s' (disk full?)", Output);
}
{
/* Program long options */
static const LongOpt OptTab[] = {
- { "--help", 0, OptHelp },
- { "--verbose", 0, OptVerbose },
- { "--version", 0, OptVersion },
+ { "--help", 0, OptHelp },
+ { "--verbose", 0, OptVerbose },
+ { "--version", 0, OptVersion },
};
unsigned I;
I = 1;
while (I < ArgCount) {
- /* Get the argument */
- const char* Arg = ArgVec[I];
+ /* Get the argument */
+ const char* Arg = ArgVec[I];
- /* Check for an option */
- if (Arg [0] == '-') {
- switch (Arg [1]) {
+ /* Check for an option */
+ if (Arg [0] == '-') {
+ switch (Arg [1]) {
- case '-':
- LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
- break;
+ case '-':
+ LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
+ break;
- case 'h':
- OptHelp (Arg, 0);
- break;
+ case 'h':
+ OptHelp (Arg, 0);
+ break;
- case 'V':
- OptVersion (Arg, 0);
- break;
+ case 'v':
+ OptVerbose (Arg, 0);
+ break;
- default:
- UnknownOption (Arg);
- break;
+ case 'V':
+ OptVersion (Arg, 0);
+ break;
- }
- } else {
- /* Filename. Dump it. */
- ConvertFile (Arg, "out.tch");
- ++FilesProcessed;
- }
+ default:
+ UnknownOption (Arg);
+ break;
+
+ }
+ } else {
+ /* Filename. Dump it. */
+ ConvertFile (Arg, 0);
+ ++FilesProcessed;
+ }
- /* Next argument */
- ++I;
+ /* Next argument */
+ ++I;
}
/* Print a message if we did not process any files */
if (FilesProcessed == 0) {
- fprintf (stderr, "%s: No input files\n", ProgName);
+ fprintf (stderr, "%s: No input files\n", ProgName);
}
/* Success */