1 /* $XConsortium: t1io.c,v 1.4 91/10/10 11:19:41 rws Exp $ */
2 /* Copyright International Business Machines,Corp. 1991
3  * All Rights Reserved
4  *
5  * License to use, copy, modify, and distribute this software
6  * and its documentation for any purpose and without fee is
7  * hereby granted, provided that the above copyright notice
8  * appear in all copies and that both that copyright notice and
9  * this permission notice appear in supporting documentation,
10  * and that the name of IBM not be used in advertising or
11  * publicity pertaining to distribution of the software without
12  * specific, written prior permission.
13  *
14  * IBM PROVIDES THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES
15  * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT
16  * LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT OF
18  * THIRD PARTY RIGHTS.  THE ENTIRE RISK AS TO THE QUALITY AND
19  * PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
20  * OR MAINTAIN, BELONGS TO THE LICENSEE.  SHOULD ANY PORTION OF
21  * THE SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM) ASSUMES
22  * THE ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION.  IN
23  * NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
25  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
26  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
27  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28  * SOFTWARE.
29  *
30  * Author: Carol H. Thompson  IBM Almaden Research Center
31  */
32 /*******************************************************************
33 *  I/O package for Type 1 font reading
34 ********************************************************************/
35 
36 #ifndef STATIC
37 #define STATIC static
38 #endif
39 
40 #if defined(_MSC_VER)
41 # include <io.h>
42 # include <sys/types.h>
43 # include <sys/stat.h>
44 #else
45 # include <unistd.h>
46 #endif
47 #include <stdio.h>
48 #include <fcntl.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <stdlib.h>
52 
53 #include "t1stdio.h"
54 #include "t1hdigit.h"
55 
56 /* we define this to switch to decrypt-debugging mode. The stream of
57    decrypted bytes will be written to stdout! This contains binary
58    charstring data */
59 /* #define DEBUG_DECRYPTION */
60 /* #define DEBUG_PFB_BLOCKS  */
61 
62 /* Constants and variables used in the decryption */
63 #define c1 ((unsigned short)52845)
64 #define c2 ((unsigned short)22719)
65 static unsigned short r;
66 static int asc, Decrypt;
67 static int extrach;
68 static int haveextrach;
69 
70 static int starthex80=0;
71 static long pfbblocklen=0;
72 static long accu=0;
73 static unsigned long bytecnt=0;
74 static int eexec_startOK=0;
75 static int eexec_endOK=0;
76 static int in_eexec=0;
77 
78 
79 /* Our single FILE structure and buffer for this package */
80 STATIC F_FILE TheFile;
81 STATIC unsigned char TheBuffer[F_BUFSIZ];
82 
83 /* Our routines */
84 F_FILE *T1Open(), *T1eexec();
85 int T1Close(F_FILE *);
86 int T1Read(), T1Getc(F_FILE *), T1Ungetc(int,F_FILE *);
87 void T1io_reset(void);
88 STATIC int T1Decrypt(), T1Fill();
89 
90 /* -------------------------------------------------------------- */
91 /*ARGSUSED*/
T1Open(fn,mode)92 F_FILE *T1Open(fn, mode)
93   char *fn;    /* Pointer to filename */
94   char *mode;  /* Pointer to open mode string */
95 {
96   F_FILE *of = &TheFile;
97   char c;
98 
99 
100   Decrypt = 0;
101   eexec_startOK=0;
102   eexec_endOK=0;
103 
104 #ifndef O_BINARY
105 #  define O_BINARY 0x0
106 #endif
107 
108   /* We know we are only reading */
109   if ((of->fd=open(fn, O_RDONLY | O_BINARY)) < 0) return NULL;
110 
111   /* We check for pfa/pfb file */
112   if (read( of->fd, &c, 1)!=1) {
113     close( of->fd);
114     return(NULL);
115   }
116   else
117     if (c==(char)0x80){
118       starthex80=1;
119     }
120   lseek( of->fd, 0, SEEK_SET);
121 
122   /* Initialize the buffer information of our file descriptor */
123   of->b_base = TheBuffer;
124   of->b_size = F_BUFSIZ;
125   of->b_ptr = NULL;
126   of->b_cnt = 0;
127   of->flags = 0;
128   of->error = 0;
129   haveextrach = 0;
130   return &TheFile;
131 } /* end Open */
132 
133 /* -------------------------------------------------------------- */
T1Getc(f)134 int T1Getc(f)        /* Read one character */
135   F_FILE *f;         /* Stream descriptor */
136 {
137   if (f->b_base == NULL) return EOF;  /* already closed */
138 
139   if (f->flags & UNGOTTENC) { /* there is an ungotten c */
140     f->flags &= ~UNGOTTENC;
141     return (int) f->ungotc;
142   }
143 
144   if (f->b_cnt == 0)  /* Buffer needs to be (re)filled */
145     f->b_cnt = T1Fill(f);
146   if (f->b_cnt > 0) return (f->b_cnt--, (int) *(f->b_ptr++));
147   else {
148     f->flags |= FIOEOF;
149     return EOF;
150   }
151 } /* end Getc */
152 
153 /*  This function is added by RMz:
154     T1Gets(): Read a line of the file and save it to string. At most,
155     (size-1) bytes are read. The user *must* ensure (by making size large
156     enough) that "eexec" does not get split between two calls because
157     in this case, eexec-decryption does not set in.
158     ------------------------------------------------------------ */
T1Gets(char * string,int size,F_FILE * f)159 int T1Gets(char *string,
160 	   int size,
161 	   F_FILE *f) /* Read a line */
162 {
163   int i=0;
164   char *eexecP;
165 
166   if (string == NULL) {
167     return( i);
168   }
169   if (f->b_base == NULL)
170     return( i);  /* already closed */
171   if (size<2)   /* no bytes to be read. For size = 1 we only had
172 		   room for the \0-character. */
173     return( i);
174 
175   if (f->flags & UNGOTTENC) { /* there is an ungotten c */
176     f->flags &= ~UNGOTTENC;
177     string[i++]=f->ungotc;
178     size--;
179   }
180 
181   size--; /* we have to leave room for one \0-character */
182 
183   while ( size>0) {
184     if (f->b_cnt == 0) { /* Buffer needs to be (re)filled */
185       f->b_cnt = T1Fill(f);
186     }
187     if (f->b_cnt == 0) { /* no more bytes available. Put \0-char
188 			    and return. */
189       if ( i==0) { /* we did not already store one single char to string */
190 	f->flags |= FIOEOF;
191 	return( i);
192       }
193       else {
194 	f->flags |= FIOEOF;
195 	string[i]='\0';
196 	return( i);
197       }
198     }
199 
200     /* do not skip white space as required by Adobe spec, because
201        I have found fonts where the first encrypted byte was of
202        white space type. */
203     if ( (eexec_startOK==1) && (eexec_endOK==1)) {
204       T1eexec( f);
205       eexec_startOK=0;
206       eexec_endOK=0;
207       in_eexec=1;
208       /* we are now in the encrypted portion. */
209     }
210     string[i]=*(f->b_ptr);
211 
212     /* Check whether eexec appears in the string just setup */
213     if ( (Decrypt==0) &&
214 	 ((eexecP=strstr( string, "eexec"))!=NULL) ) {
215       /* if eexec is an isolated token, start decryption */
216       if ( (eexec_startOK==1) &&
217 	   (isspace( (int)string[i])!=0) ) {
218 	eexec_endOK=1;
219       }
220       if ( (eexec_startOK==0) &&
221 	   (isspace( (int)string[i-5])!=0) ) {
222 	eexec_startOK=1;
223       }
224     }
225     i++;
226     /* Under UNIX, '\n' is the accepted newline. For pfb-files it is also
227        common to use '\r' as the newline indicator. I have, however, never
228        seen a pfb-file which uses the sequence '\r''\n' as a newline
229        indicator, as known from DOS. So we don't take care for this case
230        and simply map both single characters \r and \n into \n. Of course,
231        this can only be done in the ASCII section of the font.
232 
233        2002-10-26: Well, life life is teaching me better: There *are* fonts
234        out there, ASCII encoded pfa's, that use the crappy DOSian 0x0d 0x0a
235        sequence as line separation. In order to make it still work, we absorb
236        the byte 0x0a. Failure to do so result in decryption failure. The
237        workaround is implemented T1eexec():
238 
239     */
240     if ( *(f->b_ptr)=='\n' || *(f->b_ptr)=='\r') {
241       if (in_eexec==0)
242 	string[i-1]='\n';
243       string[i]='\0';
244       f->b_cnt--;
245       f->b_ptr++;
246       return( i);
247     }
248 
249     f->b_cnt--;
250     f->b_ptr++;
251     size--;
252   } /* end of while (size>0) */
253 
254   string[i]='\0'; /* finish string */
255   return( i);
256 
257 } /* end of T1Gets() */
258 
259 
260 
T1GetDecrypt(void)261 int T1GetDecrypt( void)
262 {
263   return( in_eexec);
264 }
265 
266 
267 /* Return the optional contents after the final cleartomark token.
268    There might appear some PostScript code which is not important
269    for t1lib, but which becomes important if subsetted fonts are
270    embedded in PostScript files. */
T1GetTrailer(char * string,int size,F_FILE * f)271 int T1GetTrailer(char *string,
272 		 int size,
273 		 F_FILE *f)
274 {
275   unsigned long off_save;
276   char *buf;
277   char *ctmP;
278   int i=0, j;
279   int datasize;
280   int len;
281 
282   datasize=size;
283 
284   off_save=lseek( f->fd, 0, SEEK_CUR);
285   if ((buf=(char *)malloc( size+1))==NULL ) {
286     return( -1);
287   }
288   lseek( f->fd, -size, SEEK_END);
289   read(f->fd, buf, size);
290   buf[size]='\0';   /* to be ablo perform a strstr() on this memory */
291 
292   i=datasize;
293   j=datasize-11;   /* length of "cleartomark" plus terminating white
294 		      space or newline */
295 
296   while ((j--)>-1) {
297     if ((unsigned char)buf[i]==0x80) {
298       datasize=i; /* we skip the segment marker of pfb-files */
299     }
300     if ((ctmP=strstr( &(buf[j]), "cleartomark"))!=NULL) {
301       /* buf[i-1] now is the first character after cleartomark. Advance now
302 	 to the next non white character of EOF. */
303       len = datasize - i;
304       while ( (isspace( (int)(buf[i-1])) != 0) &&
305 	      (i < datasize) ) {
306 	++i;
307       }
308       memcpy( string, &(buf[i-1]), len);
309       string[len]='\0';
310       lseek( f->fd, off_save, SEEK_SET);
311       free( buf);
312       return len;
313     }
314     i--;
315   }
316   lseek( f->fd, off_save, SEEK_SET);
317   free( buf);
318   return( -1);
319 }
320 
321 
322 
T1GetFileSize(F_FILE * f)323 unsigned long T1GetFileSize( F_FILE *f)
324 {
325   unsigned long off_save;
326   unsigned long filesize;
327 
328   off_save=lseek( f->fd, 0, SEEK_CUR);
329   filesize=lseek( f->fd, 0, SEEK_END);
330   lseek( f->fd, off_save, SEEK_SET);
331   return( filesize);
332 }
333 
334 
335 
336 /* -------------------------------------------------------------- */
T1Ungetc(c,f)337 int T1Ungetc(c, f)   /* Put back one character */
338   int c;
339   F_FILE *f;         /* Stream descriptor */
340 {
341   if (c != EOF) {
342     f->ungotc = c;
343     f->flags |= UNGOTTENC;  /* set flag */
344     f->flags &= ~FIOEOF;    /* reset EOF */
345   }
346   return c;
347 } /* end Ungetc */
348 
349 /* -------------------------------------------------------------- */
T1Read(buffP,size,n,f)350 int T1Read(buffP, size, n, f)  /* Read n items into caller's buffer */
351   char *buffP;       /* Buffer to be filled */
352   int   size;        /* Size of each item */
353   int   n;           /* Number of items to read */
354   F_FILE *f;         /* Stream descriptor */
355 {
356   int bytelen, cnt, i;
357   F_char *p = (F_char *)buffP;
358   int  icnt;         /* Number of characters to read */
359 
360   if (f->b_base == NULL) return 0;  /* closed */
361   icnt = (size!=1)?n*size:n;  /* Number of bytes we want */
362 
363   if (f->flags & UNGOTTENC) { /* there is an ungotten c */
364     f->flags &= ~UNGOTTENC;
365     *(p++) = f->ungotc;
366     icnt--; bytelen = 1;
367   }
368   else bytelen = 0;
369 
370   while (icnt > 0) {
371     /* First use any bytes we have buffered in the stream buffer */
372     if ((cnt=f->b_cnt) > 0) {
373       if (cnt > icnt) cnt = icnt;
374       for (i=0; i<cnt; i++) *(p++) = *(f->b_ptr++);
375       f->b_cnt -= cnt;
376       icnt -= cnt;
377       bytelen += cnt;
378     }
379 
380     if ((icnt == 0) || (f->flags & FIOEOF)) break;
381 
382     f->b_cnt = T1Fill(f);
383   }
384   return ((size!=1)?bytelen/size:bytelen);
385 } /* end Read */
386 
387 /* -------------------------------------------------------------- */
T1Close(f)388 int T1Close(f)       /* Close the file */
389   F_FILE *f;         /* Stream descriptor */
390 {
391   if (f->b_base == NULL) return 0;  /* already closed */
392   f->b_base = NULL;  /* no valid stream */
393   return close(f->fd);
394 } /* end Close */
395 
396 
397 /* -------------------------------------------------------------- */
T1eexec(f)398 F_FILE *T1eexec(f)   /* Initialization */
399   F_FILE *f;         /* Stream descriptor */
400 {
401   int i;
402   int H;
403 
404   unsigned char *p;
405   int testchar;
406   unsigned char randomP[8];
407 
408   r = 55665;  /* initial key */
409   asc = 1;    /* indicate ASCII form */
410 
411 #ifdef DEBUG_DECRYPTION
412   printf("T1eexec(1): first 20 bytes=%.20s, b_cnt=%d\n", f->b_ptr, f->b_cnt);
413 #endif
414 
415   /* As the very first action we check the first byte against 0x0a.
416      This mmight happen in context with the T1gets() function for
417      pfa files that use DOSian linefeed style. If that character appears
418      here, we absorb it (see also T1Gets()!).
419   */
420   if ( ( testchar = T1Getc( f)) != 0x0a )
421     T1Ungetc( testchar, f);
422 
423   /* Consume the 4 random bytes, determining if we are also to
424      ASCIIDecodeHex as we process our input.  (See pages 63-64
425      of the Adobe Type 1 Font Format book.)  */
426 
427   /* Skipping over initial white space chars has been removed since
428      it could lead to unprocessable pfb-fonts if accindentally the
429      first cipher text byte was of the class HWHITE_SPACE.
430      Instead, we just read ahead, this should suffice for any
431      Type 1 font program. (RMz, 08/02/1998) */
432 
433   /* If ASCII, the next 7 chars are guaranteed consecutive */
434   randomP[0] = getc(f);  /* store first non white space char */
435   fread(randomP+1, 1, 3, f);  /* read 3 more, for a total of 4 */
436   /* store first four chars */
437   for (i=0,p=randomP; i<4; i++) {  /* Check 4 valid ASCIIEncode chars */
438     if (HighHexP[*p++] > LAST_HDIGIT) {  /* non-ASCII byte */
439       asc = 0;
440       break;
441     }
442   }
443   if (asc) {  /* ASCII form, convert first eight bytes to binary */
444     fread(randomP+4, 1, 4, f);  /* Need four more */
445     for (i=0,p=randomP; i<4; i++) {  /* Convert */
446       H = HighHexP[*p++];
447       randomP[i] = H | LowHexP[*p++];
448     }
449   }
450 
451   /* Adjust our key */
452   for (i=0,p=randomP; i<4; i++) {
453     r = (*p++ + r) * c1 + c2;
454   }
455 
456   /* Decrypt the remaining buffered bytes */
457   f->b_cnt = T1Decrypt(f->b_ptr, f->b_cnt);
458   Decrypt = 1;
459 
460 #ifdef DEBUG_DECRYPTION
461   printf("T1eexec(2): first 120 bytes=%.120s, b_cnt=%d\n", f->b_ptr, f->b_cnt);
462 #endif
463 
464   return (feof(f))?NULL:f;
465 } /* end eexec */
466 
467 /* -------------------------------------------------------------- */
T1Decrypt(p,len)468 STATIC int T1Decrypt(p, len)
469   unsigned char *p;
470   int len;
471 {
472   int n;
473   int H=0, L=0;
474   unsigned char *inp = p;
475   unsigned char *tblP;
476 
477 #ifdef DEBUG_DECRYPTION
478   printf("T1_Decrypt(): called with len=%d\n",len);
479 #endif
480   if (asc) {
481     if (haveextrach) {
482       H = extrach;
483       tblP = LowHexP;
484     }
485     else tblP = HighHexP;
486     for (n=0; len>0; len--) {
487       L = tblP[*inp++];
488 #ifdef DEBUG_DECRYPTION
489       printf("L=0x%X, %d, inp=%c (%d)\n", L,L, *(inp-1), *(inp-1));
490 #endif
491       if (L == HWHITE_SPACE) {
492 #ifdef DEBUG_DECRYPTION
493 	printf("continue\n");
494 #endif
495 	continue;
496       }
497       if (L > LAST_HDIGIT) {
498 #ifdef DEBUG_DECRYPTION
499 	printf("L=0x%X, --> break\n", L);
500 #endif
501 	break;
502       }
503 
504       if (tblP == HighHexP) { /* Got first hexit value */
505         H = L;
506         tblP = LowHexP;
507       } else { /* Got second hexit value; compute value and store it */
508         n++;
509         tblP = HighHexP;
510         H |= L;
511         /* H is an int, 0 <= H <= 255, so all of this will work */
512         *p++ = H ^ (r >> 8);
513         r = (H + r) * c1 + c2;
514       }
515     }
516     if (tblP != HighHexP) {  /* We had an odd number of hexits */
517       extrach = H;
518       haveextrach = 1;
519     } else haveextrach = 0;
520 #ifdef DEBUG_DECRYPTION
521     printf("T1_Decrypt(): Decrypted %d bytes\n",n);
522 #endif
523     return n;
524   } else {
525     for (n = len; n>0; n--) {
526       H = *inp++;
527       *p++ = H ^ (r >> 8);
528       r = (H + r) * c1 + c2;
529     }
530     return len;
531   }
532 } /* end Decrypt */
533 
534 /* -------------------------------------------------------------- */
535 /* This function has been adapted to support pfb-files with multiple
536    data segments */
T1Fill(f)537 STATIC int T1Fill(f) /* Refill stream buffer */
538   F_FILE *f;         /* Stream descriptor */
539 {
540   int rc,i;
541   static unsigned char hdr_buf[6];
542 
543   if (starthex80){ /* we have a pfb-file -> be aware of pfb-blocks */
544     if ( pfbblocklen-accu >= F_BUFSIZ){
545       /* fill the buffer */
546       rc = read(f->fd, f->b_base, F_BUFSIZ);
547       bytecnt+=rc;
548       accu +=rc;
549     }
550     else{
551       if (pfbblocklen-accu>0){
552 	/* read the remaining of the pfb-block ... */
553 	rc = read(f->fd, f->b_base, pfbblocklen-accu);
554 	bytecnt +=rc;
555 	accu +=rc;
556 	/* ... and examine the next header */
557 	i=read(f->fd, hdr_buf, 6);
558 	bytecnt +=i;
559 	pfbblocklen=0;
560 	pfbblocklen += hdr_buf[2]&0xFF  ;
561 	pfbblocklen += (hdr_buf[3] & 0xFF)  <<8;
562 	pfbblocklen += (hdr_buf[4] & 0xFF)  <<16;
563 	pfbblocklen += (hdr_buf[5] & 0xFF)  <<24;
564 #ifdef DEBUG_PFB_BLOCKS
565 	printf("t1io: New segment, length=%d, type=%d\n",
566 	       pfbblocklen, hdr_buf[1]);
567 #endif
568 	accu=0;
569       }
570       else{
571 	/* We are at the beginning of a new block ->
572 	   examine header */
573 	i=read(f->fd, hdr_buf, 6);
574 	pfbblocklen=0;
575 	pfbblocklen += hdr_buf[2]&0xFF  ;
576 	pfbblocklen += (hdr_buf[3] & 0xFF)  <<8;
577 	pfbblocklen += (hdr_buf[4] & 0xFF)  <<16;
578 	pfbblocklen += (hdr_buf[5] & 0xFF)  <<24;
579 #ifdef DEBUG_PFB_BLOCKS
580 	printf("t1io: New segment, length=%d, type=%d\n",
581 	       pfbblocklen, hdr_buf[1]);
582 #endif
583 	accu=0;
584 	/* header read, now fill the buffer */
585 	if (pfbblocklen-accu >= F_BUFSIZ){
586 	  rc = read(f->fd, f->b_base, F_BUFSIZ);
587 	  accu +=rc;
588 	}
589 	else{
590 	  /* we have the unusual case that the pfb-block size is
591 	     shorter than F_BUFSIZ -> Read this block only */
592 	  rc = read(f->fd, f->b_base, pfbblocklen);
593 	  accu +=rc;
594 	}
595       }
596     }
597   }
598   else{
599     /* We have a pfa-file -> read straight ahead and fill buffer */
600     rc = read(f->fd, f->b_base, F_BUFSIZ);
601   }
602 
603   /* propagate any error or eof to current file */
604   if (rc <= 0) {
605     if (rc == 0)    /* means EOF */
606       f->flags |= FIOEOF;
607     else {
608       f->error = (short)-rc;
609       f->flags |= FIOERROR;
610       rc = 0;
611     }
612   }
613 
614   f->b_ptr = f->b_base;
615 #ifdef DEBUG_DECRYPTION
616   printf("T1_Fill(): read %d bytes\n", rc);
617 #endif
618 
619   if (Decrypt){
620     rc = T1Decrypt(f->b_base, rc);
621 #ifdef DEBUG_DECRYPTION
622     printf("T1_Fill(): decrypted %d bytes\n", rc);
623 #endif
624   }
625 
626   return rc;
627 } /* end Fill */
628 
629 
T1io_reset(void)630 void T1io_reset(void)
631 {
632   pfbblocklen=0;
633   accu=0;
634   starthex80=0;
635   eexec_startOK=0;
636   eexec_endOK=0;
637   in_eexec=0;
638 }
639 
640 
641 
642