summaryrefslogtreecommitdiff
path: root/dviware/textool/pkstuff.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/textool/pkstuff.c
Initial commit
Diffstat (limited to 'dviware/textool/pkstuff.c')
-rw-r--r--dviware/textool/pkstuff.c618
1 files changed, 618 insertions, 0 deletions
diff --git a/dviware/textool/pkstuff.c b/dviware/textool/pkstuff.c
new file mode 100644
index 0000000000..32de8ed7e2
--- /dev/null
+++ b/dviware/textool/pkstuff.c
@@ -0,0 +1,618 @@
+/*
+ * This is the font part of textool, dealing with PK format files.
+ * The low level routines to deal with the PK format
+ * were transliterated from pktopx
+ * See the pktopx documentation for details.
+ * For V2.3, 29 Mar 88
+- * Fixed stupid errors in skip_specials() that caused specials to be
+missed
+
+ */
+
+#include "defs.h"
+#include <stdio.h>
+#include <sys/file.h> /* for access() stuff */
+#include <pixrect/pixrect_hs.h> /* for LoadAChar() */
+
+char *index();
+int strlen();
+char *strcpy();
+char *sprintf();
+
+/* procedures in sunstuff */
+extern void Fatal();
+extern void Warning();
+
+/* procedures in dvistuff */
+extern float ActualFactor();
+extern FILE *OpenFontFile();
+
+/* procedures here */
+void ReadCharDefs();
+void LoadAChar();
+
+/* a few global variables and data structures */
+#include "globals.h"
+
+#define PK_XXX1 240
+#define PK_XXX2 241
+#define PK_XXX3 242
+#define PK_XXX4 243
+#define PK_YYY 244
+#define PK_POST 245
+#define PK_NOP 246
+#define PK_PRE 247
+#define PK_ID 89
+
+#define ROWSIZE 64 /* maximum width of raster in 16 bit words */
+
+static FILE *pkfp;
+static long pk_loc; /* points to next byte to be read in file */
+static long pk_char_start;
+static int repeat_count;
+static int dyn_f;
+static int word_width;
+static int char_height;
+static int char_width;
+static Boolean got_pk_post;
+static Boolean turn_on;
+static int bit_weight;
+static int flag_byte;
+static int packet_length;
+static int char_code;
+static int tfm_width;
+static int hor_esc;
+static int vert_esc;
+static int h_off;
+static int v_off;
+static int nybindex;
+static short row[ROWSIZE];
+static short *rowptr;
+static short *imageptr;
+
+static int power[16] =
+ {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
+ 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};
+static int gpower[17] =
+ {0, 1, 3, 7, 15, 0x1f, 0x3f, 0x7f,
+ 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff};
+
+#define get_pk_byte() (pk_loc++, getc(pkfp))
+
+
+int
+get_pk_word()
+{
+ int myword;
+
+ myword = get_pk_byte() << 8;
+ return (myword + get_pk_byte());
+}
+
+
+int
+get_pk_double()
+{
+ register int mydouble;
+
+ mydouble = get_pk_byte() << 8;
+ mydouble += get_pk_byte();
+ mydouble = (mydouble << 8) + get_pk_byte();
+ return ((mydouble << 8) + get_pk_byte());
+}
+
+
+ /*
+ * This returns the next nybble from the pk file
+ * The variable nybindex controls which nybble is
+ * returned. This is initialised to 0 in normal_raster()
+ * as a previous normal_raster() may have read an odd
+ * number of nybbles.
+ */
+int
+get_pk_nybble()
+{
+ static int mynybble;
+
+ if (nybindex) {
+ nybindex = 0;
+ return (mynybble & 0xf);
+ }
+ else {
+ mynybble = get_pk_byte();
+ nybindex = 1;
+ return (mynybble >> 4);
+ }
+}
+
+
+ /*
+ * This returns a non-zero value if the next pk file
+ * bit is a one. It is only used in an if (..) so
+ * the actual value is not important.
+ * The variable bit_weight is used to count the bits
+ * between calls to get_pk_byte(). It is initialised
+ * to 0 in bitmap_raster() so a byte is fetched the
+ * first time.
+ * The function is given for illustration. The macro
+ * following is used for speed.
+ */
+/*
+ *int
+ *get_pk_bit()
+ *{
+ * static int byte_for_bits;
+ *
+ * if (bit_weight <= 1) {
+ * bit_weight = 256;
+ * byte_for_bits = get_pk_byte();
+ * }
+ * bit_weight = bit_weight >> 1;
+ * return (byte_for_bits & bit_weight);
+ *}
+ */
+static int byte_for_bits;
+#define get_pk_bit() (((bit_weight<=1) ?\
+ (bit_weight = 128, byte_for_bits=get_pk_byte()) : (bit_weight>>=1)),\
+ byte_for_bits&bit_weight)
+
+
+void
+send_row()
+{
+ register short *dp;
+ register int i;
+ register int repcount;
+
+ dp = imageptr;
+ repcount = repeat_count + 1;
+ while (repcount--) {
+ rowptr = row;
+ i = word_width;
+ while(i--)
+ *dp++ = *rowptr++;
+ }
+ imageptr=dp; /* save for next call */
+}
+
+
+void
+skip_specials()
+{
+ register int i;
+
+ do {
+ i = 0;
+ flag_byte = get_pk_byte();
+ if (flag_byte >= PK_XXX1)
+ switch (flag_byte) {
+ case PK_XXX4:
+ i = get_pk_byte();
+ case PK_XXX3:
+ i = (i<<8) + get_pk_byte();
+ case PK_XXX2:
+ i = (i<<8) + get_pk_byte();
+ case PK_XXX1:
+ i = (i<<8) + get_pk_byte();
+ while (i--)
+ (void)get_pk_byte();
+ break;
+ case PK_YYY:
+ (void)get_pk_double();
+ break;
+ case PK_POST:
+#ifdef DEBUG
+ if (ExtraDebug)
+ fprintf(stderr, "Got pk_post in skip_specials()\n");
+#endif
+ got_pk_post = TRUE;
+ return;
+ case PK_NOP:
+ break;
+ default:
+ Fatal("Bad pk command byte (%d) in skip_specials()",
+ flag_byte);
+ return;
+ }
+ } while (flag_byte >= PK_XXX1);
+}
+
+
+ /*
+ * This routine returns the next run count from the pk
+ * character description. It will set the global repeat_count
+ * to any repeat count value encountered.
+ */
+int
+pk_packed_num()
+{
+ register int i, j;
+
+ i = get_pk_nybble();
+ if (i == 0) {
+ do {
+ j = get_pk_nybble();
+ i++;
+ } while (j == 0);
+ while (i--)
+ j = (j<<4) + get_pk_nybble();
+ return (j - 15 + ((13 - dyn_f)<<4) + dyn_f);
+ }
+ else if (i <= dyn_f)
+ return (i);
+ else if (i < 14)
+ return (((i - dyn_f - 1)<<4) + get_pk_nybble() + dyn_f + 1);
+ else {
+ if (i == 14)
+ repeat_count = pk_packed_num();
+ else /* i must be 15 */
+ repeat_count = 1;
+ return (pk_packed_num());
+ }
+}
+
+ /*
+ * This deals with run count encoded rasters.
+ * It uses pk_packed_num() which in turn uses get_pk_nybble().
+ */
+void
+normal_raster(dp)
+short *dp;
+{
+ register int word = 0;
+ register int count;
+ register int h_bit = char_width;
+ register int word_weight = 16;
+ register int rows_left = char_height;
+
+ repeat_count = 0;
+ nybindex = 0;
+ imageptr = dp;
+ rowptr = row;
+
+ while (rows_left > 0) {
+ count = pk_packed_num();
+ while (count > 0) {
+ if ((count < word_weight) && (count < h_bit)) {
+ if (turn_on)
+ word += gpower[word_weight] - gpower[word_weight - count];
+ h_bit -= count;
+ word_weight -= count;
+ count = 0;
+ }
+ else if ((count >= h_bit) && (h_bit <= word_weight)) {
+ if (turn_on)
+ word += gpower[word_weight] - gpower[word_weight - h_bit];
+ *rowptr++ = word;
+ send_row();
+ rowptr = row;
+ rows_left -= repeat_count + 1;
+ repeat_count = 0;
+ word = 0;
+ word_weight = 16;
+ count -= h_bit;
+ h_bit = char_width;
+ }
+ else {
+ if (turn_on)
+ word += gpower[word_weight];
+ *rowptr++ = word;
+ word = 0;
+ count -= word_weight;
+ h_bit -= word_weight;
+ word_weight = 16;
+ }
+ }
+ turn_on ^= 1;
+ }
+ if ((rows_left != 0) || (h_bit != char_width)) {
+ Fatal("Bad pk file - more bits than required\n");
+ return;
+ }
+}
+
+
+ /*
+ * This deals with bit mapped raster (dyn_f = 14).
+ * It uses get_pk_bit().
+ */
+void
+bitmap_raster(dp)
+short *dp;
+{
+ register int i;
+ register int j;
+ register int word;
+ register int word_weight;
+
+ bit_weight = 0;
+
+ for (i = 0; i < char_height; i++) {
+ word = 0;
+ word_weight = 15;
+ for (j = 0; j < char_width; j++) {
+ if (get_pk_bit())
+ word += power[word_weight];
+ if (word_weight-- == 0) {
+ *dp++ = word;
+ word = 0;
+ word_weight = 15;
+ }
+ }
+ if (word_weight < 15)
+ *dp++ = word;
+ }
+}
+
+
+ /*
+ * This reads the pk file preamble and rejects the file
+ * if it does not start correctly.
+ */
+void
+get_pk_preamble()
+{
+ register int comment_length;
+
+ got_pk_post = FALSE;
+ fseek(pkfp, 0L, 0);
+ pk_loc = 0;
+ if (get_pk_byte() != PK_PRE) {
+ Fatal("Bad pk file - doesn't start with pk_pre\n");
+ return;
+ }
+ if (get_pk_byte() != PK_ID) {
+ Fatal("Bad pk file - wrong pk_id byte\n");
+ return;
+ }
+ comment_length = get_pk_byte();
+ while (comment_length--)
+ get_pk_byte();
+ (void)get_pk_double();
+ (void)get_pk_double();
+ (void)get_pk_double();
+ (void)get_pk_double();
+}
+
+
+ /*
+ * This reads the preamble for one character up to the tfm width.
+ * The tfm width is read as when it is stored in the char_entry
+ * struct it needs to be multiplied by the font "s" parameter.
+ * ReadCharDefs() is passed a pointer to the font_entry struct
+ * so it can do this whereas LoadAChar() can't.
+ * The rest of the char will either be skipped or read with
+ * get_pk_char_dimen().
+ * flag_byte will have been set by a previous skip_specials().
+ */
+void
+get_pk_char_code()
+{
+ dyn_f = flag_byte >> 4;
+ turn_on = (flag_byte & 0x8) >> 3;
+ flag_byte &= 0x7;
+ pk_char_start = pk_loc - 1; /* - 1 as flag byte has been read */
+
+ if (flag_byte < 4) { /* short preamble */
+ packet_length = (flag_byte << 8) + get_pk_byte();
+ char_code = get_pk_byte();
+ tfm_width = get_pk_byte() << 16;
+ tfm_width += get_pk_word();
+ packet_length -= 3; /* correct for reading tfm_width */
+ }
+ else if (flag_byte < 7) { /* extended short preamble */
+ packet_length = ((flag_byte - 4) << 16) + get_pk_word();
+ char_code = get_pk_byte();
+ tfm_width = get_pk_byte() << 16;
+ tfm_width += get_pk_word();
+ packet_length -= 3;
+ }
+ else { /* long preamble */
+ packet_length = get_pk_double();
+ char_code = get_pk_double();
+ tfm_width = get_pk_double();
+ packet_length -= 4;
+ }
+}
+
+ /*
+ * This reads the char preamble starting after the tfm width,
+ * carrying on where get_pk_char_code() left off.
+ */
+void
+get_pk_char_dimen()
+{
+ if (flag_byte < 4) { /* short preamble */
+ hor_esc = get_pk_byte();
+ char_width = get_pk_byte();
+ word_width = (char_width + 15)>>4;
+ char_height = get_pk_byte();
+ h_off = (char)get_pk_byte();
+ v_off = (char)get_pk_byte();
+ }
+ else if (flag_byte < 7) { /* extended short preamble */
+ hor_esc = get_pk_word();
+ char_width = get_pk_word();
+ word_width = (char_width + 15)>>4;
+ char_height = get_pk_word();
+ h_off = (short)get_pk_word();
+ v_off = (short)get_pk_word();
+ }
+ else { /* long preamble */
+ hor_esc = get_pk_double();
+ vert_esc = get_pk_double();
+ char_width = get_pk_double();
+ word_width = (char_width + 15)>>4;
+ char_height = get_pk_double();
+ h_off = get_pk_double();
+ v_off = get_pk_double();
+ }
+}
+
+
+ /*
+ * This reads the preamble for one character.
+ */
+void
+get_pk_char_preamble()
+{
+ flag_byte = get_pk_byte();
+ get_pk_char_code();
+ get_pk_char_dimen();
+}
+
+
+/*
+ * Now here are the routines called by the rest of textool
+ */
+
+/*-->FindFontFile*/
+
+void
+FindFontFile(tfontptr, mag)
+struct font_entry *tfontptr;
+unsigned int mag;
+{
+ char *direct, *tcp, *tcp1;
+ int found;
+ char curarea[STRSIZE];
+
+ tfontptr->font_mag = (int)(
+ ActualFactor((int)(((float)tfontptr->s/(float)tfontptr->d)*1000.0+0.5))
+#ifdef USEGLOBALMAG
+ * ActualFactor(mag)
+#endif
+ * (float)RESOLUTION + 0.5);
+#ifdef DEBUG
+ if (ExtraDebug) {
+ fprintf(stderr, "FindFontFile():\n");
+ fprintf(stderr, " mag = %d\n", mag);
+ fprintf(stderr, " s = %d\n", tfontptr->s);
+ fprintf(stderr, " d = %d\n", tfontptr->d);
+ fprintf(stderr, " font_mag = %d\n", tfontptr->font_mag);
+ }
+#endif
+ if (tfontptr->a != 0) {
+ sprintf(tfontptr->name, "%s.%dpk", tfontptr->n, tfontptr->font_mag);
+ } else {
+ direct = PKpath;
+ found = FALSE;
+ do {
+ tcp = index(direct, ':');
+ if (tcp == NULL) tcp = strlen(direct) + direct;
+ strncpy(curarea, direct, tcp-direct);
+ tcp1 = curarea + (tcp - direct);
+ *tcp1++ = '/';
+ *tcp1++ = '\0';
+
+ sprintf(tfontptr->name, "%s%s.%dpk",
+ curarea, tfontptr->n, tfontptr->font_mag);
+ found = (access(tfontptr->name, R_OK) == 0);
+ if (*tcp) direct = tcp + 1; else direct = tcp;
+ } while ( !found && *direct != '\0');
+ }
+#ifdef DEBUG
+ if (ExtraDebug)
+ fprintf(stderr, "FindFontFile() returns with name %s\n",
+ tfontptr->name);
+#endif
+}
+
+
+/*-->LoadAChar*/
+
+void
+LoadAChar(ptr)
+register struct char_entry *ptr;
+{
+ register Pixrect *pr;
+ register short *dp;
+
+ pkfp = OpenFontFile();
+ if (ptr->where.address.fileOffset == 0) {
+ ptr->where.address.pixrectptr = NULL;
+ return;
+ }
+ fseek(pkfp, ptr->where.address.fileOffset, 0);
+ get_pk_char_preamble();
+ ptr->width = char_width;
+ ptr->height = char_height;
+ ptr->xOffset= h_off;
+ ptr->yOffset = v_off;
+ if ((pr = mem_create(ptr->width, ptr->height, 1)) == NULL) {
+ Fatal("Couldn't allocate pixrect");
+ return;
+ }
+ dp = ((struct mpr_data *)pr->pr_data)->md_image;
+ if (dyn_f == 14)
+ bitmap_raster(dp);
+ else
+ normal_raster(dp);
+ ptr->where.address.pixrectptr = pr;
+ ptr->where.isloaded = TRUE;
+}
+
+
+/*-->ReadCharDefs*/
+
+void
+ReadCharDefs(tfontptr, fp)
+struct font_entry *tfontptr;
+FILE *fp;
+{
+ register struct char_entry *tcharptr; /* temporary char_entry pointer */
+ register Pixrect *pr;
+ register int junk_count;
+ short *dp;
+
+#ifdef DEBUG
+ if (ExtraDebug)
+ fprintf(stderr, "ReadCharDefs() for font %s\n", tfontptr->name);
+#endif
+ pkfp = fp;
+ get_pk_preamble();
+ skip_specials();
+ while (!got_pk_post) {
+ get_pk_char_code();
+ tcharptr = &(tfontptr->ch[char_code]);
+ tcharptr->tfmw = tfm_width * (float)tfontptr->s / (float)(1<<20);
+ if (BigPreLoad) {
+ /*
+ * Load the rest of the character info.
+ */
+ get_pk_char_dimen();
+ tcharptr->width = char_width;
+ tcharptr->height = char_height;
+ tcharptr->xOffset= h_off;
+ tcharptr->yOffset = v_off;
+ if ((pr = mem_create(char_width, char_height, 1)) == NULL) {
+ Fatal("Couldn't allocate pixrect");
+ return;
+ }
+ dp = ((struct mpr_data *)pr->pr_data)->md_image;
+ if (dyn_f == 14)
+ bitmap_raster(dp);
+ else
+ normal_raster(dp);
+ tcharptr->where.address.pixrectptr = pr;
+ tcharptr->where.isloaded = TRUE;
+ }
+ else {
+ tcharptr->where.isloaded = FALSE;
+ tcharptr->where.address.fileOffset = pk_char_start;
+ /*
+ * Otherwise skip the rest of the char.
+ * The bytes are read rather than using fseek as the pk files
+ * are small and the whole thing is likely to fit in one stdio
+ * buffer so this will not involve any function calls.
+ */
+ junk_count = packet_length;
+ while (junk_count--)
+ getc(pkfp);
+ pk_loc += packet_length;
+ }
+ skip_specials();
+ }
+}
+
+