/* * Compressed TeX fonts in PostScript. * By Radical Eye Software. * (Slight mods by Don Knuth in December 89.) */ #include "dvips.h" /* The copyright notice in that file is included too! */ #ifdef DEBUG extern integer debug_flag; #endif /* DEBUG */ /* Given a raster that has been unpacked from PK format, * we compress it by another scheme that is suitable for * a PostScript-oriented unpacking. We write instructions for * a little interpreter whose one-byte instructions have the form * 18*opcode+parameter. The interpreter forms each row based * on simple transformations to the previous row. */ #define MAXOUT (18) #define CMD(n) (MAXOUT*(n)) #define ADVXCHG1 CMD(0) #define ADVXCHG1END CMD(1) #define CHGX CMD(2)-1 #define CHGXEND CMD(3)-1 #define ADVXLSH CMD(4) #define ADVXLSHEND CMD(5) #define ADVXRSH CMD(6) #define ADVXRSHEND CMD(7) #define ADVX CMD(8)-1 #define REPX CMD(9)-1 #define SETX CMD(10)-1 #define CLRX CMD(11)-1 #define ADVXCHG2 CMD(12) #define ADVXCHG2END CMD(13) #define END CMD(14) #include "protos.h" static int rowlength = -1 ; static unsigned char *specdata ; static long tslen = 0 ; static unsigned char *tempstore, *tsp, *tsend ; void putlong P2C(register char *, a, long, i) { a[0] = i >> 24 ; a[1] = i >> 16 ; a[2] = i >> 8 ; a[3] = i ; } long getlong P1C(register unsigned char *, a) { return ((((((a[0] << 8L) + a[1]) << 8L) + a[2]) << 8L) + a[3]) ; } /* First, a routine that appends one byte to the compressed output. */ #define addtse(n) {lcm=tsp-tempstore;addts(n);} /* mark END option position */ static void addts P1C(register unsigned char, what) { register unsigned char *p, *q ; if (tsp >= tsend) { if (tempstore == NULL) { tslen = 2020 ; tempstore = (unsigned char *)mymalloc((integer)tslen) ; tsp = tempstore ; } else { tslen = 2 * tslen ; tsp = (unsigned char *)mymalloc((integer)tslen) ; for (p=tempstore, q=tsp; p>1)|((a)&128))) )) #define lsh(a,b) ( ((a)==0) ? ((b)==1) : ( ((a)==255) ? ((b)==254) :\ ((b)==((((a)<<1)&255)|((a)&1))) )) #define DIFFERENT (1) #define LSHPOSSIB (2) #define RSHPOSSIB (4) #define BLKPOSSIB (8) #define WHTPOSSIB (16) #define ENDROW (32) #define NOPOSSIB(n) ((n&(LSHPOSSIB|RSHPOSSIB|BLKPOSSIB|WHTPOSSIB))==0) #define NOSHIFT(n) ((n&(LSHPOSSIB|RSHPOSSIB))==0) /* * Our input bytes are packed to the 16-bit word. On output, * they're packed to bytes. Thus, we may have to skip a byte at * the end of each row. */ void dochar P3C(unsigned char *, from, short, width, short, height) { register int i ; register unsigned char *f, *t, *d ; register unsigned char *e ; register int accum ; int j, k, kk ; int diffrow ; int repeatcount ; int lit, pos, cmd = 0 ; long lcm ; int widthc ; widthc = width + (width & 1) ; /* halfword correction */ lcm = -1 ; if (widthc > rowlength) { if (rowlength > 0) free((char *)specdata) ; rowlength = widthc + 30 ; specdata = (unsigned char *)mymalloc((integer)(rowlength + 15)) ; } for (i= -15, t=specdata; i<=widthc; i++, t++) *t = 0 ; repeatcount = 0 ; f = specdata + 2 ; for (j=0; j MAXOUT) { addts((unsigned char)(REPX+MAXOUT)) ; repeatcount -= MAXOUT ; } addts((unsigned char)(REPX+repeatcount)) ; repeatcount = 0 ; } pos = 0 ; for (i=0, d=specdata, f=t-width; i MAXOUT) { addts((unsigned char)(ADVX+MAXOUT)) ; pos += MAXOUT ; } if (0 != (k = (e - d))) { if (lit) { if (k > 2) { if (i > pos) { addts((unsigned char)(ADVX + i - pos)) ; pos = i ; } while (k > MAXOUT) { addts((unsigned char)(CHGX + MAXOUT)) ; for (kk=0; kk d) { if (*d & LSHPOSSIB) { if (i == pos+MAXOUT) { addts((unsigned char)(ADVX + MAXOUT)) ; pos = i ; } addtse((unsigned char)(ADVXLSH + i - pos)) ; } else if (*d & RSHPOSSIB) { if (i == pos+MAXOUT) { addts((unsigned char)(ADVX + MAXOUT)) ; pos = i ; } addtse((unsigned char)(ADVXRSH + i - pos)) ; } else if (*d & WHTPOSSIB) { /* i==pos */ addts((unsigned char)(CLRX + 1)) ; lcm = -1 ; } else if (*d & BLKPOSSIB) { /* i==pos */ addts((unsigned char)(SETX + 1)) ; lcm = -1 ; } else error("! bug") ; /* why wasn't lit true? */ d++ ; f++ ; i++ ; pos = i ; } /* end 'while e>d' */ } } /* end 'if e>d' */ if (accum > 0) { if (i > pos) { addts((unsigned char)(ADVX + i - pos)) ; pos = i ; } i += accum ; d += accum ; f += accum ; while (accum > MAXOUT) { addts((unsigned char)(cmd + MAXOUT)) ; accum -= MAXOUT ; pos += MAXOUT ; } lcm = -1 ; addts((unsigned char)(cmd + accum)) ; pos += accum ; } } /* end 'else DIFFERENT' */ } /* end 'for i' */ if (lcm != -1) { tempstore[lcm] += MAXOUT ; /* append END */ lcm = -1 ; } else { addts((unsigned char)(END)) ; } } /* end 'else rows different' */ #ifdef DEBUG if (d != specdata + width) error("! internal inconsistency in repack") ; #endif } /* end 'for j' */ if (repeatcount) { while (repeatcount > MAXOUT) { addts((unsigned char)(REPX+MAXOUT)) ; repeatcount -= MAXOUT ; } addts((unsigned char)(REPX+repeatcount)) ; repeatcount = 0 ; } } extern long bytesleft ; extern quarterword *raster ; long mbytesleft ; quarterword *mraster ; char * makecopy P3C(register unsigned char *, what, register long, len, register unsigned char *, p) { register unsigned char *q ; if (p == NULL) { if (len > MINCHUNK) p = (unsigned char *)mymalloc((integer)len) ; else { if (bytesleft < len) { raster = (quarterword *)mymalloc((integer)RASTERCHUNK) ; bytesleft = RASTERCHUNK ; } p = (unsigned char *)raster ; bytesleft -= len ; raster += len ; } } q = p ; while (len > 0) { *p++ = *what++ ; len -- ; } return ((char *)q) ; } /* Now the main routine, which is called when a character is used for the very first time. */ void repack P1C(register chardesctype *, cp) { register long i, j ; register unsigned char *p ; register int width, height ; register int wwidth ; char startbytes ; int smallchar ; p = cp->packptr ; if (p == NULL) error("! no raster?") ; tsp = tempstore ; tsend = tempstore + tslen ; addts(*p) ; /* copy the PK flag byte */ if (*p & 4) { if ((*p & 7) == 7) { startbytes = 17 ; width = getlong(p + 1) ; height = getlong(p + 5) ; for (i=0; i<12; i++) addts(*++p) ; } else { startbytes = 9 ; width = p[1] * 256 + p[2] ; height = p[3] * 256 + p[4] ; addts(*++p) ; addts(*++p) ; addts(*++p) ; addts(*++p) ; } } else { startbytes = 5 ; width = p[1] ; height = p[2] ; } addts(*++p) ; addts(*++p) ; addts(*++p) ; addts(*++p) ; p++ ; /* OK, p now points to beginning of the nibbles */ addts((unsigned char)0) ; addts((unsigned char)0) ; addts((unsigned char)0) ; addts((unsigned char)0) ; /* leave room to stick in a new length field */ wwidth = (width + 15) / 16 ; i = 2 * height * (long)wwidth ; if (i <= 0) i = 2 ; if ((cp->flags & BIGCHAR) == 0) smallchar = 5 ; else smallchar = 0 ; i += smallchar ; if (mbytesleft < i) { if (mbytesleft >= RASTERCHUNK) (void) free((char *) mraster) ; if (RASTERCHUNK > i) { mraster = (quarterword *)mymalloc((integer)RASTERCHUNK) ; mbytesleft = RASTERCHUNK ; } else { i += i / 4 ; mraster = (quarterword *)mymalloc((integer)(i + 3)) ; mbytesleft = i ; } } while (i > 0) mraster[--i] = 0 ; i = startbytes + unpack(p, (halfword *)mraster, (halfword)width, (halfword)height, *(cp->packptr)) ; dochar(mraster, (width + 7) >> 3, height) ; if (smallchar) { addts((unsigned char)0) ; addts((unsigned char)0) ; addts((unsigned char)0) ; addts((unsigned char)0) ; addts((unsigned char)0) ; } j = tsp - tempstore ; #ifdef DEBUG if (dd(D_COMPRESS)) (void)fprintf(stderr,"PK %ld bytes, unpacked %ld, compressed %ld\n", i-(long)startbytes, (long)((width+7L)/8)*height, j-(long)startbytes-4) ; #endif /* DEBUG */ if ( i < j ) { if (i > MINCHUNK) free(cp->packptr) ; cp->packptr = (unsigned char *)makecopy(tempstore, j, (unsigned char *)0) ; } else makecopy(tempstore, j, (unsigned char *)cp->packptr) ; putlong((char *)(cp->packptr+startbytes), j-startbytes-4-smallchar) ; cp->flags |= REPACKED ; }