Back to index

tetex-bin  3.0
pk.c
Go to the documentation of this file.
00001 /*========================================================================*\
00002 
00003 Copyright (c) 1990-2004  Paul Vojta
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to
00007 deal in the Software without restriction, including without limitation the
00008 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00009 sell copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00018 PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00019 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00020 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00021 OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 NOTE:
00024        xdvi is based on prior work, as noted in the modification history
00025        in xdvi.c.
00026 
00027 \*========================================================================*/
00028 
00029 /*
00030  *     PK font reading routines.
00031  *     Public routines are read_PK_index and read_PK_char.
00032  */
00033 
00034 #include "xdvi-config.h"
00035 #include "xdvi.h"
00036 #include "dvi-init.h"
00037 #include "util.h"
00038 
00039 #define PK_ID      89
00040 #define PK_CMD_START 240
00041 #define PK_X1     240
00042 #define PK_X2     241
00043 #define PK_X3     242
00044 #define PK_X4     243
00045 #define PK_Y      244
00046 #define PK_POST   245
00047 #define PK_NOOP   246
00048 #define PK_PRE    247
00049 
00050 static int PK_flag_byte;
00051 static unsigned PK_input_byte;
00052 static int PK_bitpos;
00053 static int PK_dyn_f;
00054 static int PK_repeat_count;
00055 
00056 static int
00057 PK_get_nyb(FILE *fp)
00058 {
00059     unsigned temp;
00060     if (PK_bitpos < 0) {
00061        PK_input_byte = get_byte(fp);
00062        PK_bitpos = 4;
00063     }
00064     temp = PK_input_byte >> PK_bitpos;
00065     PK_bitpos -= 4;
00066     return (temp & 0xf);
00067 }
00068 
00069 
00070 static int
00071 PK_packed_num(FILE *fp)
00072 {
00073     int i, j;
00074 
00075     if ((i = PK_get_nyb(fp)) == 0) {
00076        do {
00077            j = PK_get_nyb(fp);
00078            ++i;
00079        }
00080        while (j == 0);
00081        while (i > 0) {
00082            j = (j << 4) | PK_get_nyb(fp);
00083            --i;
00084        }
00085        return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f);
00086     }
00087     else {
00088        if (i <= PK_dyn_f)
00089            return i;
00090        if (i < 14)
00091            return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp)
00092                   + PK_dyn_f + 1);
00093        if (i == 14)
00094            PK_repeat_count = PK_packed_num(fp);
00095        else
00096            PK_repeat_count = 1;
00097        return PK_packed_num(fp);
00098     }
00099 }
00100 
00101 
00102 static void
00103 PK_skip_specials(struct font *fontp)
00104 {
00105     int i, j;
00106     FILE *fp = fontp->file;
00107 
00108     do {
00109        PK_flag_byte = get_byte(fp);
00110        if (PK_flag_byte >= PK_CMD_START) {
00111            switch (PK_flag_byte) {
00112            case PK_X1:
00113            case PK_X2:
00114            case PK_X3:
00115            case PK_X4:
00116               i = 0;
00117               for (j = PK_CMD_START; j <= PK_flag_byte; ++j)
00118                   i = (i << 8) | get_byte(fp);
00119               while (i--)
00120                   (void)get_byte(fp);
00121               break;
00122            case PK_Y:
00123               (void)get_bytes(fp, 4);
00124            case PK_POST:
00125            case PK_NOOP:
00126               break;
00127            default:
00128               XDVI_FATAL((stderr, "Unexpected %d in PK file %s", PK_flag_byte,
00129                          fontp->filename));
00130               break;
00131            }
00132        }
00133     }
00134     while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START);
00135 }
00136 
00137 /*
00138  *     Public routines
00139  */
00140 
00141 static void
00142 read_PK_char(struct font *fontp,
00143             wide_ubyte ch)
00144 {
00145     int i, j;
00146     int n;
00147     int row_bit_pos;
00148     Boolean paint_switch;
00149     bmUnitT *cp;
00150     struct glyph *g;
00151     FILE *fp = fontp->file;
00152     long fpwidth;
00153     bmUnitT word = 0;
00154     int word_weight, bytes_wide;
00155     int rows_left, h_bit, count;
00156 
00157     g = &fontp->glyph[ch];
00158     PK_flag_byte = g->x2;
00159     PK_dyn_f = PK_flag_byte >> 4;
00160     paint_switch = ((PK_flag_byte & 8) != 0);
00161     PK_flag_byte &= 0x7;
00162     if (PK_flag_byte == 7)
00163        n = 4;
00164     else if (PK_flag_byte > 3)
00165        n = 2;
00166     else
00167        n = 1;
00168 
00169     if (globals.debug & DBG_PK)
00170        printf("loading pk char %d, char type %d ", ch, n);
00171 
00172     /*
00173      * now read rest of character preamble
00174      */
00175     if (n != 4)
00176        fpwidth = get_bytes(fp, 3);
00177     else {
00178        fpwidth = get_lbytes(fp, 4);
00179        (void)get_bytes(fp, 4);     /* horizontal escapement */
00180     }
00181     (void)get_bytes(fp, n); /* vertical escapement */
00182     {
00183        unsigned long w, h;
00184 
00185        w = get_bytes(fp, n);
00186        h = get_bytes(fp, n);
00187        /* bitmap.w and bitmap.h are of type `unsigned short', so check for possible
00188           overflow here. USHRT_MAX should be sufficient, since a character of
00189           30pt at 1200dpi requires about 560 x 560 pixels; and the maximum
00190           bitmap of size USHRT_MAX * USHRT_MAX would consume USHRT_MAX * USHRT_MAX / 8
00191           bytes ~= 530MB of RAM (per character/font!)
00192        */
00193        if (w > USHRT_MAX || h > USHRT_MAX)
00194            XDVI_FATAL((stderr, "Character %d too large (%ld x %ld, max is %d x %d) in file %s",
00195                      ch, w, h, USHRT_MAX, USHRT_MAX, fontp->fontname));
00196        g->bitmap.w = w;
00197        g->bitmap.h = h;
00198     }
00199     g->x = get_lbytes(fp, n);
00200     g->y = get_lbytes(fp, n);
00201 
00202     g->dvi_adv = fontp->dimconv * fpwidth;
00203 
00204     if (globals.debug & DBG_PK) {
00205        if (g->bitmap.w != 0)
00206            printf(", size=%dx%d, dvi_adv=%ld", g->bitmap.w, g->bitmap.h,
00207                  g->dvi_adv);
00208        putchar('\n');
00209     }
00210 
00211     alloc_bitmap(&g->bitmap);
00212     cp = (bmUnitT *) g->bitmap.bits;
00213 
00214     /*
00215      * read character data into *cp
00216      */
00217     bytes_wide = ROUNDUP((int)g->bitmap.w, BMBITS) * BMBYTES;
00218     PK_bitpos = -1;
00219     if (PK_dyn_f == 14) {   /* get raster by bits */
00220        memset(g->bitmap.bits, 0, (int)g->bitmap.h * bytes_wide);
00221        for (i = 0; i < (int)g->bitmap.h; i++) {  /* get all rows */
00222            cp = ADD(g->bitmap.bits, i * bytes_wide);
00223 #ifndef       WORDS_BIGENDIAN
00224            row_bit_pos = -1;
00225 #else
00226            row_bit_pos = BMBITS;
00227 #endif
00228            for (j = 0; j < (int)g->bitmap.w; j++) {     /* get one row */
00229               if (--PK_bitpos < 0) {
00230                   word = get_byte(fp);
00231                   PK_bitpos = 7;
00232               }
00233 #ifndef       WORDS_BIGENDIAN
00234               if (++row_bit_pos >= BMBITS) {
00235                   cp++;
00236                   row_bit_pos = 0;
00237               }
00238 #else
00239               if (--row_bit_pos < 0) {
00240                   cp++;
00241                   row_bit_pos = BMBITS - 1;
00242               }
00243 #endif
00244               if (word & (1 << PK_bitpos))
00245                   *cp |= 1 << row_bit_pos;
00246            }
00247        }
00248     }
00249     else {    /* get packed raster */
00250        rows_left = g->bitmap.h;
00251        h_bit = g->bitmap.w;
00252        PK_repeat_count = 0;
00253        word_weight = BMBITS;
00254        word = 0;
00255        while (rows_left > 0) {
00256            count = PK_packed_num(fp);
00257            while (count > 0) {
00258               if (count < word_weight && count < h_bit) {
00259 #ifndef       WORDS_BIGENDIAN
00260                   if (paint_switch)
00261                      word |= bit_masks[count] << (BMBITS - word_weight);
00262 #endif
00263                   h_bit -= count;
00264                   word_weight -= count;
00265 #ifdef WORDS_BIGENDIAN
00266                   if (paint_switch)
00267                      word |= bit_masks[count] << word_weight;
00268 #endif
00269                   count = 0;
00270               }
00271               else if (count >= h_bit && h_bit <= word_weight) {
00272                   if (paint_switch)
00273                      word |= bit_masks[h_bit] <<
00274 #ifndef       WORDS_BIGENDIAN
00275                          (BMBITS - word_weight);
00276 #else
00277                   (word_weight - h_bit);
00278 #endif
00279                   *cp++ = word;
00280                   /* "output" row(s) */
00281                   for (i = PK_repeat_count * bytes_wide / BMBYTES; i > 0; --i) {
00282                      *cp = *SUB(cp, bytes_wide);
00283                      ++cp;
00284                   }
00285                   rows_left -= PK_repeat_count + 1;
00286                   PK_repeat_count = 0;
00287                   word = 0;
00288                   word_weight = BMBITS;
00289                   count -= h_bit;
00290                   h_bit = g->bitmap.w;
00291               }
00292               else {
00293                   if (paint_switch)
00294 #ifndef       WORDS_BIGENDIAN
00295                      word |= bit_masks[word_weight] <<
00296                          (BMBITS - word_weight);
00297 #else
00298                   word |= bit_masks[word_weight];
00299 #endif
00300                   *cp++ = word;
00301                   word = 0;
00302                   count -= word_weight;
00303                   h_bit -= word_weight;
00304                   word_weight = BMBITS;
00305               }
00306            }
00307            paint_switch = 1 - paint_switch;
00308        }
00309        if (cp != ((bmUnitT *) (g->bitmap.bits + bytes_wide * g->bitmap.h)))
00310            XDVI_FATAL((stderr, "Wrong number of bits stored:  char. %d, font %s", ch,
00311                      fontp->fontname));
00312        if (rows_left != 0 || h_bit != g->bitmap.w)
00313            XDVI_FATAL((stderr, "Bad pk file (%s), too many bits", fontp->fontname));
00314     }
00315 }
00316 
00317 void
00318 read_PK_index(struct font *fontp, wide_bool hushcs)
00319 {
00320     int hppp, vppp;
00321     long checksum;
00322 
00323     fontp->read_char = read_PK_char;
00324     if (globals.debug & DBG_PK)
00325        printf("Reading PK pixel file %s\n", fontp->filename);
00326 
00327     fseek(fontp->file, (long)get_byte(fontp->file), SEEK_CUR); /* skip comment */
00328 
00329     (void)get_bytes(fontp->file, 4);      /* skip design size */
00330     checksum = get_bytes(fontp->file, 4);
00331     if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
00332        && !hushcs)
00333        XDVI_WARNING((stderr, "Checksum mismatch (dvi = %lu, pk = %lu) in font file %s",
00334                     fontp->checksum, checksum, fontp->filename));
00335     hppp = get_lbytes(fontp->file, 4);
00336     vppp = get_lbytes(fontp->file, 4);
00337     if (hppp != vppp && (globals.debug & DBG_PK))
00338        printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp);
00339     /*
00340      * Prepare glyph array.
00341      */
00342     fontp->glyph = xmalloc(256 * sizeof(struct glyph));
00343     memset((char *)fontp->glyph, 0, 256 * sizeof(struct glyph));
00344     /*
00345      * Read glyph directory (really a whole pass over the file).
00346      */
00347     for (;;) {
00348        int bytes_left, flag_low_bits;
00349        unsigned int ch;
00350 
00351        PK_skip_specials(fontp);
00352        if (PK_flag_byte == PK_POST)
00353            break;
00354        flag_low_bits = PK_flag_byte & 0x7;
00355        if (flag_low_bits == 7) {
00356            bytes_left = get_bytes(fontp->file, 4);
00357            ch = get_bytes(fontp->file, 4);
00358        }
00359        else if (flag_low_bits > 3) {
00360            bytes_left = ((flag_low_bits - 4) << 16) + get_bytes(fontp->file, 2);
00361            ch = get_byte(fontp->file);
00362        }
00363        else {
00364            bytes_left = (flag_low_bits << 8) + get_byte(fontp->file);
00365            ch = get_byte(fontp->file);
00366        }
00367        fontp->glyph[ch].addr = ftell(fontp->file);
00368        fontp->glyph[ch].x2 = PK_flag_byte;
00369 #ifdef linux
00370 # ifndef SHORTSEEK
00371 #  define SHORTSEEK 2048
00372 # endif
00373        /* A bug in Linux libc (as of 18oct94) makes a short read faster
00374           than a short forward seek. Totally non-intuitive.  */
00375        if (bytes_left > 0 && bytes_left < SHORTSEEK) {
00376            char *dummy = xmalloc(bytes_left);
00377            fread(dummy, 1, bytes_left, fontp->file);
00378            free(dummy);
00379        }
00380        else
00381            /* seek backward, or long forward */
00382 #endif /* linux */
00383            fseek(fontp->file, (long)bytes_left, SEEK_CUR);
00384        if (globals.debug & DBG_PK)
00385            printf("Scanning pk char %u, at %ld.\n", ch, fontp->glyph[ch].addr);
00386     }
00387 }