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