diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/textool/pkstuff.c |
Initial commit
Diffstat (limited to 'dviware/textool/pkstuff.c')
-rw-r--r-- | dviware/textool/pkstuff.c | 618 |
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(); + } +} + + |