Back to index

tetex-bin  3.0
t1io.c
Go to the documentation of this file.
00001 /* $XConsortium: t1io.c,v 1.4 91/10/10 11:19:41 rws Exp $ */
00002 /* Copyright International Business Machines,Corp. 1991
00003  * All Rights Reserved
00004  *
00005  * License to use, copy, modify, and distribute this software
00006  * and its documentation for any purpose and without fee is
00007  * hereby granted, provided that the above copyright notice
00008  * appear in all copies and that both that copyright notice and
00009  * this permission notice appear in supporting documentation,
00010  * and that the name of IBM not be used in advertising or
00011  * publicity pertaining to distribution of the software without
00012  * specific, written prior permission.
00013  *
00014  * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
00015  * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
00016  * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
00017  * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
00018  * THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE QUALITY AND
00019  * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
00020  * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF
00021  * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
00022  * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN
00023  * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
00024  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
00025  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
00026  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00027  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00028  * SOFTWARE.
00029  *
00030  * Author: Carol H. Thompson  IBM Almaden Research Center
00031  */
00032 /*******************************************************************
00033 *  I/O package for Type 1 font reading
00034 ********************************************************************/
00035  
00036 #ifndef STATIC
00037 #define STATIC static
00038 #endif
00039  
00040 #if defined(_MSC_VER)
00041 # include <io.h>
00042 # include <sys/types.h>
00043 # include <sys/stat.h>
00044 #else
00045 # include <unistd.h>
00046 #endif
00047 #include <stdio.h>
00048 #include <fcntl.h>
00049 #include <string.h>
00050 #include <ctype.h>
00051 #include <stdlib.h>
00052 
00053 #include "t1stdio.h"
00054 #include "t1hdigit.h"
00055 
00056 /* we define this to switch to decrypt-debugging mode. The stream of
00057    decrypted bytes will be written to stdout! This contains binary
00058    charstring data */
00059 /* #define DEBUG_DECRYPTION */
00060 /* #define DEBUG_PFB_BLOCKS  */
00061 
00062 /* Constants and variables used in the decryption */
00063 #define c1 ((unsigned short)52845)
00064 #define c2 ((unsigned short)22719)
00065 static unsigned short r;
00066 static int asc, Decrypt;
00067 static int extrach;
00068 static int haveextrach;
00069 
00070 static int starthex80=0;
00071 static long pfbblocklen=0;
00072 static long accu=0;
00073 static unsigned long bytecnt=0;
00074 static int eexec_startOK=0;
00075 static int eexec_endOK=0;
00076 static int in_eexec=0;
00077 
00078  
00079 /* Our single FILE structure and buffer for this package */
00080 STATIC F_FILE TheFile;
00081 STATIC unsigned char TheBuffer[F_BUFSIZ];
00082  
00083 /* Our routines */
00084 F_FILE *T1Open(), *T1eexec();
00085 int T1Close();
00086 int T1Read(), T1Getc(), T1Ungetc();
00087 void T1io_reset(void);
00088 STATIC int T1Decrypt(), T1Fill();
00089  
00090 /* -------------------------------------------------------------- */
00091 /*ARGSUSED*/
00092 F_FILE *T1Open(fn, mode)
00093   char *fn;    /* Pointer to filename */
00094   char *mode;  /* Pointer to open mode string */
00095 {
00096   F_FILE *of = &TheFile;
00097   char c;
00098   
00099  
00100   Decrypt = 0;
00101   eexec_startOK=0;
00102   eexec_endOK=0;
00103  
00104 #ifndef O_BINARY
00105 #  define O_BINARY 0x0
00106 #endif
00107  
00108   /* We know we are only reading */
00109   if ((of->fd=open(fn, O_RDONLY | O_BINARY)) < 0) return NULL;
00110 
00111   /* We check for pfa/pfb file */
00112   if (read( of->fd, &c, 1)!=1) {
00113     close( of->fd);
00114     return(NULL);
00115   }
00116   else
00117     if (c==(char)0x80){
00118       starthex80=1;
00119     }
00120   lseek( of->fd, 0, SEEK_SET);
00121   
00122   /* Initialize the buffer information of our file descriptor */
00123   of->b_base = TheBuffer;
00124   of->b_size = F_BUFSIZ;
00125   of->b_ptr = NULL;
00126   of->b_cnt = 0;
00127   of->flags = 0;
00128   of->error = 0;
00129   haveextrach = 0;
00130   return &TheFile;
00131 } /* end Open */
00132  
00133 /* -------------------------------------------------------------- */
00134 int T1Getc(f)        /* Read one character */
00135   F_FILE *f;         /* Stream descriptor */
00136 {
00137   if (f->b_base == NULL) return EOF;  /* already closed */
00138  
00139   if (f->flags & UNGOTTENC) { /* there is an ungotten c */
00140     f->flags &= ~UNGOTTENC;
00141     return (int) f->ungotc;
00142   }
00143  
00144   if (f->b_cnt == 0)  /* Buffer needs to be (re)filled */
00145     f->b_cnt = T1Fill(f);
00146   if (f->b_cnt > 0) return (f->b_cnt--, (int) *(f->b_ptr++));
00147   else {
00148     f->flags |= FIOEOF;
00149     return EOF;
00150   }
00151 } /* end Getc */
00152  
00153 /*  This function is added by RMz:
00154     T1Gets(): Read a line of the file and save it to string. At most,
00155     (size-1) bytes are read. The user *must* ensure (by making size large
00156     enough) that "eexec" does not get split between two calls because
00157     in this case, eexec-decryption does not set in.
00158     ------------------------------------------------------------ */
00159 int T1Gets(char *string,
00160           int size,
00161           F_FILE *f) /* Read a line */
00162 {
00163   int i=0;
00164   char *eexecP;
00165   
00166   if (string == NULL) {
00167     return( i);
00168   }
00169   if (f->b_base == NULL)
00170     return( i);  /* already closed */
00171   if (size<2)   /* no bytes to be read. For size = 1 we only had
00172                  room for the \0-character. */
00173     return( i);
00174   
00175   if (f->flags & UNGOTTENC) { /* there is an ungotten c */
00176     f->flags &= ~UNGOTTENC;
00177     string[i++]=f->ungotc;
00178     size--;
00179   }
00180 
00181   size--; /* we have to leave room for one \0-character */
00182   
00183   while ( size>0) {
00184     if (f->b_cnt == 0) { /* Buffer needs to be (re)filled */
00185       f->b_cnt = T1Fill(f);
00186     }
00187     if (f->b_cnt == 0) { /* no more bytes available. Put \0-char
00188                          and return. */
00189       if ( i==0) { /* we did not already store one single char to string */
00190        f->flags |= FIOEOF;
00191        return( i);
00192       }
00193       else {
00194        f->flags |= FIOEOF;
00195        string[i]='\0';
00196        return( i);
00197       }
00198     }
00199 
00200     /* do not skip white space as required by Adobe spec, because
00201        I have found fonts where the first encrypted byte was of
00202        white space type. */
00203     if ( (eexec_startOK==1) && (eexec_endOK==1)) {
00204       T1eexec( f);
00205       eexec_startOK=0;
00206       eexec_endOK=0;
00207       in_eexec=1;
00208       /* we are now in the encrypted portion. */
00209     }
00210     string[i]=*(f->b_ptr);
00211     
00212     /* Check whether eexec appears in the string just setup */
00213     if ( (Decrypt==0) &&
00214         ((eexecP=strstr( string, "eexec"))!=NULL) ) {
00215       /* if eexec is an isolated token, start decryption */
00216       if ( (eexec_startOK==1) &&
00217           (isspace( (int)string[i])!=0) ) {
00218        eexec_endOK=1;
00219       }
00220       if ( (eexec_startOK==0) &&
00221           (isspace( (int)string[i-5])!=0) ) {
00222        eexec_startOK=1;
00223       }
00224     }
00225     i++;
00226     /* Under UNIX, '\n' is the accepted newline. For pfb-files it is also
00227        common to use '\r' as the newline indicator. I have, however, never
00228        seen a pfb-file which uses the sequence '\r''\n' as a newline
00229        indicator, as known from DOS. So we don't take care for this case
00230        and simply map both single characters \r and \n into \n. Of course,
00231        this can only be done in the ASCII section of the font.
00232 
00233        2002-10-26: Well, life life is teaching me better: There *are* fonts
00234        out there, ASCII encoded pfa's, that use the crappy DOSian 0x0d 0x0a
00235        sequence as line separation. In order to make it still work, we absorb
00236        the byte 0x0a. Failure to do so result in decryption failure. The
00237        workaround is implemented T1eexec():
00238        
00239     */
00240     if ( *(f->b_ptr)=='\n' || *(f->b_ptr)=='\r') {
00241       if (in_eexec==0)
00242        string[i-1]='\n';  
00243       string[i]='\0'; 
00244       f->b_cnt--;
00245       f->b_ptr++;
00246       return( i);
00247     }
00248     
00249     f->b_cnt--;
00250     f->b_ptr++;
00251     size--;
00252   } /* end of while (size>0) */
00253   
00254   string[i]='\0'; /* finish string */
00255   return( i);
00256   
00257 } /* end of T1Gets() */
00258 
00259 
00260 
00261 int T1GetDecrypt( void) 
00262 {
00263   return( in_eexec);
00264 }
00265 
00266 
00267 /* Return the optional contents after the final cleartomark token.
00268    There might appear some PostScript code which is not important
00269    for t1lib, but which becomes important if subsetted fonts are
00270    embedded in PostScript files. */
00271 int T1GetTrailer(char *string,
00272                int size,
00273                F_FILE *f)
00274 {
00275   unsigned long off_save;
00276   char *buf;
00277   char *ctmP;
00278   int i=0, j;
00279   int datasize;
00280   int len;
00281   
00282   datasize=size;
00283   
00284   off_save=lseek( f->fd, 0, SEEK_CUR);
00285   if ((buf=(char *)malloc( size+1))==NULL ) {
00286     return( -1);
00287   }
00288   lseek( f->fd, -size, SEEK_END);
00289   read(f->fd, buf, size);
00290   buf[size]='\0';   /* to be ablo perform a strstr() on this memory */
00291   
00292   i=datasize;
00293   j=datasize-11;   /* length of "cleartomark" plus terminating white
00294                     space or newline */
00295    
00296   while ((j--)>-1) {
00297     if ((unsigned char)buf[i]==0x80) {
00298       datasize=i; /* we skip the segment marker of pfb-files */
00299     }
00300     if ((ctmP=strstr( &(buf[j]), "cleartomark"))!=NULL) {
00301       /* buf[i-1] now is the first character after cleartomark. Advance now
00302         to the next non white character of EOF. */
00303       len = datasize - i;
00304       while ( (isspace( (int)(buf[i-1])) != 0) &&
00305              (i < datasize) ) {
00306        ++i;
00307       }
00308       memcpy( string, &(buf[i-1]), len);
00309       string[len]='\0';
00310       lseek( f->fd, off_save, SEEK_SET);
00311       free( buf);
00312       return len;
00313     }
00314     i--;
00315   }
00316   lseek( f->fd, off_save, SEEK_SET);
00317   free( buf);
00318   return( -1);
00319 }
00320 
00321 
00322 
00323 unsigned long T1GetFileSize( F_FILE *f) 
00324 {
00325   unsigned long off_save;
00326   unsigned long filesize;
00327   
00328   off_save=lseek( f->fd, 0, SEEK_CUR);
00329   filesize=lseek( f->fd, 0, SEEK_END);
00330   lseek( f->fd, off_save, SEEK_SET);
00331   return( filesize);
00332 }
00333 
00334 
00335 
00336 /* -------------------------------------------------------------- */
00337 int T1Ungetc(c, f)   /* Put back one character */
00338   int c;
00339   F_FILE *f;         /* Stream descriptor */
00340 {
00341   if (c != EOF) {
00342     f->ungotc = c;
00343     f->flags |= UNGOTTENC;  /* set flag */
00344     f->flags &= ~FIOEOF;    /* reset EOF */
00345   }
00346   return c;
00347 } /* end Ungetc */
00348  
00349 /* -------------------------------------------------------------- */
00350 int T1Read(buffP, size, n, f)  /* Read n items into caller's buffer */
00351   char *buffP;       /* Buffer to be filled */
00352   int   size;        /* Size of each item */
00353   int   n;           /* Number of items to read */
00354   F_FILE *f;         /* Stream descriptor */
00355 {
00356   int bytelen, cnt, i;
00357   F_char *p = (F_char *)buffP;
00358   int  icnt;         /* Number of characters to read */
00359  
00360   if (f->b_base == NULL) return 0;  /* closed */
00361   icnt = (size!=1)?n*size:n;  /* Number of bytes we want */
00362  
00363   if (f->flags & UNGOTTENC) { /* there is an ungotten c */
00364     f->flags &= ~UNGOTTENC;
00365     *(p++) = f->ungotc;
00366     icnt--; bytelen = 1;
00367   }
00368   else bytelen = 0;
00369  
00370   while (icnt > 0) {
00371     /* First use any bytes we have buffered in the stream buffer */
00372     if ((cnt=f->b_cnt) > 0) {
00373       if (cnt > icnt) cnt = icnt;
00374       for (i=0; i<cnt; i++) *(p++) = *(f->b_ptr++);
00375       f->b_cnt -= cnt;
00376       icnt -= cnt;
00377       bytelen += cnt;
00378     }
00379  
00380     if ((icnt == 0) || (f->flags & FIOEOF)) break;
00381  
00382     f->b_cnt = T1Fill(f);
00383   }
00384   return ((size!=1)?bytelen/size:bytelen);
00385 } /* end Read */
00386  
00387 /* -------------------------------------------------------------- */
00388 int T1Close(f)       /* Close the file */
00389   F_FILE *f;         /* Stream descriptor */
00390 {
00391   if (f->b_base == NULL) return 0;  /* already closed */
00392   f->b_base = NULL;  /* no valid stream */
00393   return close(f->fd);
00394 } /* end Close */
00395  
00396 
00397 /* -------------------------------------------------------------- */
00398 F_FILE *T1eexec(f)   /* Initialization */
00399   F_FILE *f;         /* Stream descriptor */
00400 {
00401   int i;
00402   int H;
00403   
00404   unsigned char *p;
00405   int testchar;
00406   unsigned char randomP[8];
00407  
00408   r = 55665;  /* initial key */
00409   asc = 1;    /* indicate ASCII form */
00410 
00411 #ifdef DEBUG_DECRYPTION
00412   printf("T1eexec(1): first 20 bytes=%.20s, b_cnt=%d\n", f->b_ptr, f->b_cnt);
00413 #endif
00414 
00415   /* As the very first action we check the first byte against 0x0a.
00416      This mmight happen in context with the T1gets() function for
00417      pfa files that use DOSian linefeed style. If that character appears
00418      here, we absorb it (see also T1Gets()!). 
00419   */
00420   if ( ( testchar = T1Getc( f)) != 0x0a )
00421     T1Ungetc( testchar, f);
00422     
00423   /* Consume the 4 random bytes, determining if we are also to
00424      ASCIIDecodeHex as we process our input.  (See pages 63-64
00425      of the Adobe Type 1 Font Format book.)  */
00426 
00427   /* Skipping over initial white space chars has been removed since
00428      it could lead to unprocessable pfb-fonts if accindentally the
00429      first cipher text byte was of the class HWHITE_SPACE.
00430      Instead, we just read ahead, this should suffice for any
00431      Type 1 font program. (RMz, 08/02/1998) */
00432 
00433   /* If ASCII, the next 7 chars are guaranteed consecutive */
00434   randomP[0] = getc(f);  /* store first non white space char */
00435   fread(randomP+1, 1, 3, f);  /* read 3 more, for a total of 4 */
00436   /* store first four chars */
00437   for (i=0,p=randomP; i<4; i++) {  /* Check 4 valid ASCIIEncode chars */
00438     if (HighHexP[*p++] > LAST_HDIGIT) {  /* non-ASCII byte */
00439       asc = 0;
00440       break;
00441     }
00442   }
00443   if (asc) {  /* ASCII form, convert first eight bytes to binary */
00444     fread(randomP+4, 1, 4, f);  /* Need four more */
00445     for (i=0,p=randomP; i<4; i++) {  /* Convert */
00446       H = HighHexP[*p++];
00447       randomP[i] = H | LowHexP[*p++];
00448     }
00449   }
00450   
00451   /* Adjust our key */
00452   for (i=0,p=randomP; i<4; i++) {
00453     r = (*p++ + r) * c1 + c2;
00454   }
00455 
00456   /* Decrypt the remaining buffered bytes */
00457   f->b_cnt = T1Decrypt(f->b_ptr, f->b_cnt);
00458   Decrypt = 1;
00459   
00460 #ifdef DEBUG_DECRYPTION
00461   printf("T1eexec(2): first 120 bytes=%.120s, b_cnt=%d\n", f->b_ptr, f->b_cnt);
00462 #endif
00463   
00464   return (feof(f))?NULL:f;
00465 } /* end eexec */
00466  
00467 /* -------------------------------------------------------------- */
00468 STATIC int T1Decrypt(p, len)
00469   unsigned char *p;
00470   int len;
00471 {
00472   int n;
00473   int H=0, L=0;
00474   unsigned char *inp = p;
00475   unsigned char *tblP;
00476  
00477 #ifdef DEBUG_DECRYPTION
00478   printf("T1_Decrypt(): called with len=%d\n",len);
00479 #endif
00480   if (asc) {
00481     if (haveextrach) {
00482       H = extrach;
00483       tblP = LowHexP;
00484     }
00485     else tblP = HighHexP;
00486     for (n=0; len>0; len--) {
00487       L = tblP[*inp++];
00488 #ifdef DEBUG_DECRYPTION
00489       printf("L=0x%X, %d, inp=%c (%d)\n", L,L, *(inp-1), *(inp-1));
00490 #endif
00491       if (L == HWHITE_SPACE) {
00492 #ifdef DEBUG_DECRYPTION     
00493        printf("continue\n");
00494 #endif
00495        continue;
00496       }
00497       if (L > LAST_HDIGIT) {
00498 #ifdef DEBUG_DECRYPTION
00499        printf("L=0x%X, --> break\n", L);
00500 #endif
00501        break;
00502       }
00503       
00504       if (tblP == HighHexP) { /* Got first hexit value */
00505         H = L;
00506         tblP = LowHexP;
00507       } else { /* Got second hexit value; compute value and store it */
00508         n++;
00509         tblP = HighHexP;
00510         H |= L;
00511         /* H is an int, 0 <= H <= 255, so all of this will work */
00512         *p++ = H ^ (r >> 8);
00513         r = (H + r) * c1 + c2;
00514       }
00515     }
00516     if (tblP != HighHexP) {  /* We had an odd number of hexits */
00517       extrach = H;
00518       haveextrach = 1;
00519     } else haveextrach = 0;
00520 #ifdef DEBUG_DECRYPTION
00521     printf("T1_Decrypt(): Decrypted %d bytes\n",n);
00522 #endif
00523     return n;
00524   } else {
00525     for (n = len; n>0; n--) {
00526       H = *inp++;
00527       *p++ = H ^ (r >> 8);
00528       r = (H + r) * c1 + c2;
00529     }
00530     return len;
00531   }
00532 } /* end Decrypt */
00533  
00534 /* -------------------------------------------------------------- */
00535 /* This function has been adapted to support pfb-files with multiple
00536    data segments */
00537 STATIC int T1Fill(f) /* Refill stream buffer */
00538   F_FILE *f;         /* Stream descriptor */
00539 {
00540   int rc,i;
00541   static unsigned char hdr_buf[6];
00542 
00543   if (starthex80){ /* we have a pfb-file -> be aware of pfb-blocks */
00544     if ( pfbblocklen-accu >= F_BUFSIZ){
00545       /* fill the buffer */
00546       rc = read(f->fd, f->b_base, F_BUFSIZ);
00547       bytecnt+=rc;
00548       accu +=rc;
00549     }
00550     else{
00551       if (pfbblocklen-accu>0){
00552        /* read the remaining of the pfb-block ... */
00553        rc = read(f->fd, f->b_base, pfbblocklen-accu);
00554        bytecnt +=rc;
00555        accu +=rc;
00556        /* ... and examine the next header */
00557        i=read(f->fd, hdr_buf, 6);
00558        bytecnt +=i;
00559        pfbblocklen=0;
00560        pfbblocklen += hdr_buf[2]&0xFF  ;
00561        pfbblocklen += (hdr_buf[3] & 0xFF)  <<8;
00562        pfbblocklen += (hdr_buf[4] & 0xFF)  <<16;
00563        pfbblocklen += (hdr_buf[5] & 0xFF)  <<24;
00564 #ifdef DEBUG_PFB_BLOCKS     
00565        printf("t1io: New segment, length=%d, type=%d\n",
00566               pfbblocklen, hdr_buf[1]);
00567 #endif 
00568        accu=0;
00569       }
00570       else{
00571        /* We are at the beginning of a new block ->
00572           examine header */
00573        i=read(f->fd, hdr_buf, 6);
00574        pfbblocklen=0;
00575        pfbblocklen += hdr_buf[2]&0xFF  ;
00576        pfbblocklen += (hdr_buf[3] & 0xFF)  <<8;
00577        pfbblocklen += (hdr_buf[4] & 0xFF)  <<16;
00578        pfbblocklen += (hdr_buf[5] & 0xFF)  <<24;
00579 #ifdef DEBUG_PFB_BLOCKS     
00580        printf("t1io: New segment, length=%d, type=%d\n",
00581               pfbblocklen, hdr_buf[1]);
00582 #endif
00583        accu=0;
00584        /* header read, now fill the buffer */
00585        if (pfbblocklen-accu >= F_BUFSIZ){
00586          rc = read(f->fd, f->b_base, F_BUFSIZ);
00587          accu +=rc;
00588        }
00589        else{
00590          /* we have the unusual case that the pfb-block size is
00591             shorter than F_BUFSIZ -> Read this block only */
00592          rc = read(f->fd, f->b_base, pfbblocklen);
00593          accu +=rc;
00594        }
00595       }
00596     }
00597   }
00598   else{
00599     /* We have a pfa-file -> read straight ahead and fill buffer */
00600     rc = read(f->fd, f->b_base, F_BUFSIZ);
00601   }
00602   
00603   /* propagate any error or eof to current file */
00604   if (rc <= 0) {
00605     if (rc == 0)    /* means EOF */
00606       f->flags |= FIOEOF;
00607     else {
00608       f->error = (short)-rc;
00609       f->flags |= FIOERROR;
00610       rc = 0;
00611     }
00612   }
00613 
00614   f->b_ptr = f->b_base;
00615 #ifdef DEBUG_DECRYPTION
00616   printf("T1_Fill(): read %d bytes\n", rc);
00617 #endif
00618   
00619   if (Decrypt){
00620     rc = T1Decrypt(f->b_base, rc);
00621 #ifdef DEBUG_DECRYPTION
00622     printf("T1_Fill(): decrypted %d bytes\n", rc);
00623 #endif
00624   }
00625   
00626   return rc;
00627 } /* end Fill */
00628 
00629 
00630 void T1io_reset(void)
00631 {
00632   pfbblocklen=0;
00633   accu=0;
00634   starthex80=0;
00635   eexec_startOK=0;
00636   eexec_endOK=0;
00637   in_eexec=0;
00638 }
00639 
00640 
00641