Back to index

tetex-bin  3.0
pkin.c
Go to the documentation of this file.
00001 /*
00002  * NAME
00003  *     pkin.c - implementation of readchar()
00004  * DESCRIPTION
00005  *     This implementation of readchar() uses parts of the program dvips
00006  *     written by Tomas Rokicki--the inventor of the pkformat--(loadfont.c,
00007  *     download.c and unpack.c). Dvips in turn is derived from pktype. 
00008  *     Pktype(TeX) is described in debt in ``The PKtype processor'', 
00009  *     which is available as pktype.weave as part of the METAFONTware.
00010  *     What was needed to implement readchar() is rearranged in pkfile.c to 
00011  *     get more modularity in the style of MODULA2.
00012  * REDESIGN
00013  *     Piet Tutelaers
00014  *     rcpt@urc.tue.nl
00015  */
00016 
00017 #ifdef DEBUG
00018 #include <stdio.h>
00019 #endif
00020 
00021 #include <stdlib.h>  /* malloc() */
00022 #include "basics.h"  /* basic definitions */
00023 #include "pkin.h"
00024 
00025 /*
00026  * Forward declaration
00027  */
00028 static void error();
00029 
00030 /*
00031  *   Now we have some routines to get stuff from the pk file.  pkbyte returns
00032  *   the next byte from the pk file.
00033  */
00034 
00035 static FILE *pkfile ;
00036 
00037 static shalfword
00038 pkbyte()
00039 {
00040    register shalfword i ;
00041 
00042    if ((i=getc(pkfile))==EOF)
00043       error("! unexpected eof in pk file") ;
00044    return(i) ;
00045 }
00046 
00047 static integer
00048 pkquad()
00049 {
00050    register integer i ;
00051 
00052    i = pkbyte() ;
00053    if (i > 127)
00054       i -= 256 ;
00055    i = i * 256 + pkbyte() ;
00056    i = i * 256 + pkbyte() ;
00057    i = i * 256 + pkbyte() ;
00058    return(i) ;
00059 }
00060 
00061 static integer
00062 pktrio()
00063 {
00064    register integer i ;
00065 
00066    i = pkbyte() ;
00067    i = i * 256 + pkbyte() ;
00068    i = i * 256 + pkbyte() ;
00069    return(i) ;
00070 }
00071 
00072 static integer
00073 pkpair()
00074 {
00075   register integer i ;
00076   
00077   i = pkbyte() ;
00078   i = i * 256 + pkbyte() ;
00079   return (i);
00080 }
00081 
00082 static integer
00083 pkspair()
00084 {
00085   register integer i ;
00086   
00087   i = pkbyte() ;
00088   if (i > 127)
00089     i -= 256;
00090   i = i * 256 + pkbyte();
00091   return (i);
00092 }
00093 
00094 static char errbuf[80] ;
00095 /*
00096  *   pkopen opens the pk file.  This is system dependent.
00097  */
00098 
00099 static Boolean       
00100 pkopen(name)
00101        char name[] ;
00102 {
00103    if ((pkfile=fopen(name, RB))==NULL) {
00104       (void)sprintf(errbuf, "Could not open %s", name) ;
00105       error(errbuf) ;
00106       return(0) ;
00107    } else
00108       return(1) ;
00109 }
00110 
00111 /*
00112  *   The next part is devoted to unpacking the character data.
00113  */
00114 
00115 /*
00116  *   We need procedures to get a nybble, bit, and packed word from the
00117  *   packed data structure.
00118  */
00119 
00120 static halfword inputbyte, flagbyte ; 
00121 static halfword bitweight ; 
00122 static halfword dynf ;
00123 static halfword repeatcount ;
00124 
00125 static shalfword
00126 getnyb ()
00127 {   halfword temp;
00128     if ( bitweight == 0 ) 
00129     { bitweight = 16 ; 
00130       inputbyte = pkbyte();
00131       temp = inputbyte >> 4 ;
00132     } else {
00133       bitweight = 0 ;
00134       temp = inputbyte & 15 ;
00135     }
00136     return(temp);
00137 } 
00138 
00139 static Boolean
00140 getbit ()
00141 {
00142     bitweight >>= 1 ; 
00143     if ( bitweight == 0 ) 
00144     { inputbyte = pkbyte();
00145       bitweight = 128 ;
00146     } 
00147     return(inputbyte & bitweight) ;
00148 }
00149 
00150 static halfword (*realfunc)() ;
00151 long PKremainder ;
00152 static halfword handlehuge() ;
00153 
00154 static halfword pkpackednum () {
00155 register halfword i, j ; 
00156     i = getnyb () ; 
00157     if ( i == 0 ) 
00158     { do { j = getnyb () ; 
00159         i++ ; 
00160         } while ( ! ( j != 0 ) ) ; 
00161       if ( i > 3 ) {
00162 /*
00163  *   Damn, we got a huge count!  We *fake* it by giving an artificially
00164  *   large repeat count.
00165  */
00166          return( handlehuge ( i , j ) ) ;
00167       } else {
00168          while ( i > 0 ) 
00169            { j = j * 16 + getnyb () ; 
00170              i-- ; 
00171              } 
00172            return ( j - 15 + ( 13 - dynf ) * 16 + dynf ) ; 
00173          } 
00174       }
00175     else if ( i <= dynf ) return ( i ) ; 
00176     else if ( i < 14 ) return ( ( i - dynf - 1 ) * 16 + getnyb () + dynf + 1 
00177     ) ; 
00178     else 
00179     { if ( i == 14 ) repeatcount = pkpackednum () ; 
00180       else repeatcount = 1 ; 
00181 #ifdef DEBUG
00182       printf("[%d]", repeatcount);
00183 #endif
00184       return ( (*realfunc)() ) ;
00185       } 
00186     } 
00187 
00188 static halfword rest ()
00189 {
00190    halfword i ;
00191 
00192    if (PKremainder < 0) {
00193       PKremainder = - PKremainder ;
00194       return ( 0 ) ;
00195    } else if (PKremainder > 0) {
00196       if (PKremainder > 4000) {
00197          PKremainder = 4000 - PKremainder ;
00198          return ( 4000 ) ;
00199       } else {
00200          i = PKremainder ;
00201          PKremainder = 0 ;
00202          realfunc = pkpackednum ;
00203          return ( i ) ;
00204       }
00205    } else {
00206       error("! shouldn't happen") ;
00207    }
00208 
00209    /*NOTREACHED*/
00210    return 0;
00211 }
00212 
00213 static halfword handlehuge ( i , k )
00214 halfword i , k ;
00215 {
00216    register long j = k ;
00217 
00218    while (i) {
00219       j = (j << 4L) + getnyb() ;
00220       i-- ;
00221    }
00222    PKremainder = j - 15 + ( 13 - dynf ) * 16 + dynf ;
00223    realfunc = rest ;
00224    return ( rest() ) ;
00225 }
00226 
00227 /*
00228  *   And now we have our unpacking routine.
00229  */
00230 
00231 static halfword gpower[17] = { 0 , 1 , 3 , 7 , 15 , 31 , 63 , 127 ,
00232      255 , 511 , 1023 , 2047 , 4095 , 8191 , 16383 , 32767 , 65535 } ; 
00233 
00234 static void
00235 unpack(cd)
00236 chardesc *cd;
00237 { 
00238   register integer i, j ; 
00239   register halfword word, wordweight ;
00240   halfword *raster;
00241   shalfword rowsleft ; 
00242   Boolean turnon ; 
00243   shalfword hbit ; 
00244   halfword count ; 
00245   shalfword  wordwidth ;
00246 
00247       wordwidth = (cd->cwidth + 15) / 16 ;
00248       i = 2 * cd->cheight * (long)wordwidth ;
00249       if (i <= 0)
00250          i = 2 ;
00251       cd->raster = (halfword *)malloc((unsigned)i) ;
00252       if (cd->raster == NULL)
00253          error("! out of memory during allocation") ;
00254       raster = cd->raster;
00255       realfunc = pkpackednum ;
00256       dynf = flagbyte / 16 ; 
00257       turnon = flagbyte & 8 ; 
00258       if ( dynf == 14 ) 
00259       { bitweight = 0 ; 
00260         for ( i = 1 ; i <= cd->cheight ; i ++ ) 
00261           { word = 0 ; 
00262             wordweight = 32768 ; 
00263             for ( j = 1 ; j <= cd->cwidth ; j ++ ) 
00264               { if ( getbit () ) word += wordweight ; 
00265                 wordweight >>= 1 ;
00266                 if ( wordweight == 0 ) 
00267                 { *raster++ = word ; 
00268                   word = 0 ;
00269                   wordweight = 32768 ; 
00270                   } 
00271                 } 
00272               if ( wordweight != 32768 ) 
00273                  *raster++ = word ; 
00274             } 
00275       } else {
00276         rowsleft = cd->cheight ; 
00277         hbit = cd->cwidth ; 
00278         repeatcount = 0 ; 
00279         wordweight = 16 ; 
00280         word = 0 ; 
00281         bitweight = 0 ;
00282         while ( rowsleft > 0 ) 
00283           { count = (*realfunc)() ; 
00284 #ifdef DEBUG
00285             if (turnon) printf("(%d) ",count);
00286             else printf("%d ",count);
00287 #endif
00288             while ( count != 0 ) 
00289               { if ( ( count < wordweight ) && ( count < hbit ) ) 
00290                 { if ( turnon ) word += gpower [ wordweight ] - gpower 
00291                   [ wordweight - count ] ; 
00292                   hbit -= count ; 
00293                   wordweight -= count ; 
00294                   count = 0 ; 
00295                   } 
00296                 else if ( ( count >= hbit ) && ( hbit <= wordweight ) ) 
00297                 { if ( turnon )
00298                      word += gpower [ wordweight ] - gpower 
00299                   [ wordweight - hbit ] ; 
00300                   *raster++ = word ; 
00301                   for ( i = 1 ; i <= repeatcount ; i ++ ) {
00302                     for ( j = 1 ; j <= wordwidth ; j ++ ) {
00303                       *raster = *(raster - wordwidth) ;
00304                       raster++ ;
00305                     }
00306                   }
00307                   rowsleft -= repeatcount + 1 ; 
00308                   repeatcount = 0 ; 
00309                   word = 0 ; 
00310                   wordweight = 16 ; 
00311                   count -= hbit ; 
00312                   hbit = cd->cwidth ; 
00313                   } 
00314                 else 
00315                 { if ( turnon ) word += gpower [ wordweight ] ; 
00316                   *raster++ = word ;
00317                   word = 0 ; 
00318                   count -= wordweight ; 
00319                   hbit -= wordweight ; 
00320                   wordweight = 16 ; 
00321                   } 
00322                 } 
00323               turnon = ! turnon ; 
00324          }
00325           putchar('\n') ;
00326           if ( ( rowsleft != 0 ) || ( hbit != cd->cwidth ) ) 
00327           error ( "! error while unpacking; more bits than required" ) ; 
00328         } 
00329 }
00330 
00331 /*
00332  *   readchar(): the main routine
00333  *   Reads the character definition of character `c' into `cd' if available,
00334  *   return FALSE (0) otherwise.
00335  */
00336 int
00337 readchar(name, c, cd)
00338 char name[];
00339 shalfword c;
00340 chardesc *cd;
00341 {
00342    register shalfword i ;
00343    register integer k ;
00344    register integer length = 0;
00345 
00346    if (!pkopen(name)) return(0);
00347 /*
00348  *   Check the preamble of the pkfile
00349  */
00350    if (pkbyte()!=247)
00351       error("! bad pk file, expected pre") ;
00352    if (pkbyte()!=89)
00353       error("! bad version of pk file") ;
00354    for(i=pkbyte(); i>0; i--)       /* creator of pkfile */
00355       (void)pkbyte() ;             
00356    (void)pkquad(); /* design size */
00357    k = pkquad() ;  /* checksum    */
00358    k = pkquad() ;  /* hppp        */
00359    k = pkquad() ;  /* vppp    */
00360 /*
00361  *   Now we skip to the desired character definition
00362  */
00363    while ((flagbyte=pkbyte())!=245) {
00364       if (flagbyte < 240) {
00365          switch (flagbyte & 7) {
00366 case 0: case 1: case 2: case 3:
00367             length = (flagbyte & 7) * 256 + pkbyte() - 4 ;
00368             cd->charcode = pkbyte() ;
00369             (void) pktrio() ;             /* TFMwidth */
00370             (void) pkbyte() ;             /* pixel width */
00371             break ;
00372 case 4:
00373             length = pkbyte() * 256 ;
00374             length = length + pkbyte() - 5 ;
00375             cd->charcode = pkbyte() ;
00376             (void) pktrio() ;             /* TFMwidth */
00377             i = pkbyte() ;
00378             i =  i * 256 + pkbyte() ;   /* pixelwidth */
00379             break ;
00380 case 5: case 6:
00381             error("! lost sync in pk file (character too big)") ;
00382 case 7:
00383             length = pkquad() - 12 ;
00384             cd->charcode = pkquad() ;
00385             (void) pkquad() ;             /* TFMwidth */
00386 /*          cd->pixelwidth = (pkquad() + 32768) >> 16 ; */
00387            (void) pkquad();        /* pixelwidth */
00388             k = pkquad() ;
00389          }
00390          if (cd->charcode == c) {
00391             if (flagbyte & 4) {
00392                if ((flagbyte & 7) == 7) { /* long format */
00393                   cd->cwidth = pkquad() ;
00394                   cd->cheight = pkquad() ;
00395                   cd->xoff = pkquad() ;
00396                   cd->yoff = pkquad() ;
00397                } else { /* extended format */
00398                   cd->cwidth = pkpair(); ;
00399                   cd->cheight = pkpair() ;
00400                   cd->xoff = pkspair() ;
00401                   cd->yoff = pkspair() ;
00402                }
00403             } else { /* short format */
00404                cd->cwidth = pkbyte() ;
00405                cd->cheight = pkbyte() ;
00406                cd->xoff = pkbyte() ;
00407                cd->yoff = pkbyte() ;
00408                if (cd->xoff > 127)
00409                   cd->xoff -= 256 ;
00410                if (cd->yoff > 127)
00411                   cd->yoff -= 256 ;
00412             }
00413             unpack(cd);
00414             (void)fclose(pkfile) ;
00415             return(1);
00416          }
00417          for (; length>0; length--) /* skip this character */
00418             (void) pkbyte() ;
00419       } else {
00420          k = 0 ;
00421          switch (flagbyte) {
00422 case 243:
00423             k = pkbyte() ;
00424             if (k > 127)
00425                k -= 256 ;
00426 case 242:
00427             k = k * 256 + pkbyte() ;
00428 case 241:
00429             k = k * 256 + pkbyte() ;
00430 case 240:
00431             k = k * 256 + pkbyte() ;
00432             while (k-- > 0)
00433                i = pkbyte() ;
00434             break ;
00435 case 244:
00436             k = pkquad() ;
00437             break ;
00438 case 246:
00439             break ;
00440 default:
00441             error("! lost sync in pk file") ;
00442          }
00443       }
00444    }
00445    (void)fclose(pkfile) ;
00446    return(0); /* character not found */
00447 }
00448 
00449 static void error(s)
00450 char s[];
00451 {
00452    fprintf(stderr, "%s\n", s);
00453    exit(1);
00454 }