/*
* 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<tsend; p++, q++)
*q = *p ;
free((char *)tempstore) ;
tempstore = tsp ;
tsp = q ;
}
tsend = tempstore + tslen ;
}
*tsp++ = what ;
}
/* Next, a routine that discovers how to do the compression. */
#define rsh(a,b) ( ((a)==0) ? ((b)==128) : ( ((a)==255) ? ((b)==127) :\
((b)==(((a)>>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<height; j++, f = from, from += widthc) {
diffrow = 0 ;
for (i=0, t=from, d=specdata; i<width; i++, f++, t++, d++) {
if (*f == *t) {
if (*t == 0)
*d = WHTPOSSIB ;
else if (*t == 255)
*d = BLKPOSSIB ;
else
*d = 0 ;
} else {
accum = DIFFERENT ;
if (rsh(*f, *t))
accum |= RSHPOSSIB ;
else if (lsh(*f, *t))
accum |= LSHPOSSIB ;
if (*t == 0)
accum |= WHTPOSSIB ;
else if (*t == 255)
accum |= BLKPOSSIB ;
*d = accum ;
diffrow++ ;
}
} /* end 'for i' */
*d = ENDROW ;
if (diffrow == 0) {
repeatcount++ ;
} else {
if (repeatcount) {
while (repeatcount > 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<width;) {
if ((*d & DIFFERENT) == 0) {
i++ ;
d++ ;
f++ ;
} else {
accum = 0 ;
if (pos != i)
lit = NOSHIFT(*d) ;
else /* N.B.: 'lit' does not imply literate programming here */
lit = NOPOSSIB(*d) ;
for (e=d; ;e++) {
if (NOPOSSIB(*e))
lit = 1 ;
if ((*e & DIFFERENT) == 0)
break ;
if ((*e & WHTPOSSIB) &&
(e[1] & WHTPOSSIB)) {
while (*e & WHTPOSSIB) {
e++ ;
accum++ ;
}
cmd = CLRX ;
e -= accum ;
break ;
} else if ((*e & BLKPOSSIB) &&
(e[1] & BLKPOSSIB)) {
while (*e & BLKPOSSIB) {
e++ ;
accum++ ;
}
cmd = SETX ;
e -= accum ;
break ;
}
} /* end 'for e'; d pts to first bad byte, e to next good one */
while (i - pos > 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<MAXOUT; kk++)
addts((unsigned char)(*f++)) ;
d += MAXOUT ;
pos += MAXOUT ;
i += MAXOUT ;
k -= MAXOUT ;
}
addtse((unsigned char)(CHGX + k)) ;
pos += k ;
for (; d<e; d++, i++, f++)
addts((unsigned char)(*f)) ;
} else {
if (k == 1) {
if (i == pos+MAXOUT) {
addts((unsigned char)(ADVX + MAXOUT)) ;
pos = i ;
}
addtse((unsigned char)(ADVXCHG1 + i - pos)) ;
addts((unsigned char)(*f)) ;
i++ ;
pos = i ;
d++ ;
f++ ;
} else {
if (i == pos+MAXOUT) {
addts((unsigned char)(ADVX + MAXOUT)) ;
pos = i ;
}
addtse((unsigned char)(ADVXCHG2 + i - pos)) ;
addts((unsigned char)(*f)) ;
addts((unsigned char)(f[1])) ;
i += 2 ;
pos = i ;
d += 2 ;
f += 2 ;
}
}
} else {
while (e > 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 ;
}
|