bsd_comp.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,161 行 · 第 1/3 页

C
1,161
字号
    default:	return NULL;    }    maxmaxcode = MAXCODE(bits);    newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));    MALLOC(db, struct bsd_db *, newlen, M_DEVBUF, M_NOWAIT);    if (!db)	return NULL;    bzero(db, sizeof(*db) - sizeof(db->dict));    if (!decomp) {	db->lens = NULL;    } else {	MALLOC(db->lens, u_int16_t *, (maxmaxcode+1) * sizeof(db->lens[0]),	       M_DEVBUF, M_NOWAIT);	if (!db->lens) {	    FREE(db, M_DEVBUF);	    return NULL;	}    }    db->totlen = newlen;    db->hsize = hsize;    db->hshift = hshift;    db->maxmaxcode = maxmaxcode;    db->maxbits = bits;    return (void *) db;}static voidbsd_free(state)    void *state;{    struct bsd_db *db = (struct bsd_db *) state;    if (db->lens)	FREE(db->lens, M_DEVBUF);    FREE(db, M_DEVBUF);}static void *bsd_comp_alloc(options, opt_len)    u_char *options;    int opt_len;{    return bsd_alloc(options, opt_len, 0);}static void *bsd_decomp_alloc(options, opt_len)    u_char *options;    int opt_len;{    return bsd_alloc(options, opt_len, 1);}/* * Initialize the database. */static intbsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)    struct bsd_db *db;    u_char *options;    int opt_len, unit, hdrlen, mru, debug, decomp;{    int i;    if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS	|| options[1] != CILEN_BSD_COMPRESS	|| BSD_VERSION(options[2]) != BSD_CURRENT_VERSION	|| BSD_NBITS(options[2]) != db->maxbits	|| (decomp && db->lens == NULL))	return 0;    if (decomp) {	i = LAST+1;	while (i != 0)	    db->lens[--i] = 1;    }    i = db->hsize;    while (i != 0) {	db->dict[--i].codem1 = BADCODEM1;	db->dict[i].cptr = 0;    }    db->unit = unit;    db->hdrlen = hdrlen;    db->mru = mru;#ifndef DEBUG    if (debug)#endif	db->debug = 1;    bsd_reset(db);    return 1;}static intbsd_comp_init(state, options, opt_len, unit, hdrlen, debug)    void *state;    u_char *options;    int opt_len, unit, hdrlen, debug;{    return bsd_init((struct bsd_db *) state, options, opt_len,		    unit, hdrlen, 0, debug, 0);}static intbsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)    void *state;    u_char *options;    int opt_len, unit, hdrlen, mru, debug;{    return bsd_init((struct bsd_db *) state, options, opt_len,		    unit, hdrlen, mru, debug, 1);}/* * compress a packet *	One change from the BSD compress command is that when the *	code size expands, we do not output a bunch of padding. */int					/* new slen */bsd_compress(state, mret, mp, slen, maxolen)    void *state;    struct mbuf **mret;		/* return compressed mbuf chain here */    struct mbuf *mp;		/* from here */    int slen;			/* uncompressed length */    int maxolen;		/* max compressed length */{    struct bsd_db *db = (struct bsd_db *) state;    int hshift = db->hshift;    u_int max_ent = db->max_ent;    u_int n_bits = db->n_bits;    u_int bitno = 32;    u_int32_t accm = 0, fcode;    struct bsd_dict *dictp;    u_char c;    int hval, disp, ent, ilen;    u_char *rptr, *wptr;    u_char *cp_end;    int olen;    struct mbuf *m;#define PUTBYTE(v) {					\    ++olen;						\    if (wptr) {						\	*wptr++ = (v);					\	if (wptr >= cp_end) {				\	    m->m_len = wptr - mtod(m, u_char *);	\	    MGET(m->m_next, M_DONTWAIT, MT_DATA);	\	    m = m->m_next;				\	    if (m) {					\		m->m_len = 0;				\		if (maxolen - olen > MLEN)		\		    MCLGET(m, M_DONTWAIT);		\		wptr = mtod(m, u_char *);		\		cp_end = wptr + M_TRAILINGSPACE(m);	\	    } else					\		wptr = NULL;				\	}						\    }							\}#define OUTPUT(ent) {					\    bitno -= n_bits;					\    accm |= ((ent) << bitno);				\    do {						\	PUTBYTE(accm >> 24);				\	accm <<= 8;					\	bitno += 8;					\    } while (bitno <= 24);				\}    /*     * If the protocol is not in the range we're interested in,     * just return without compressing the packet.  If it is,     * the protocol becomes the first byte to compress.     */    rptr = mtod(mp, u_char *);    ent = PPP_PROTOCOL(rptr);    if (ent < 0x21 || ent > 0xf9) {	*mret = NULL;	return slen;    }    /* Don't generate compressed packets which are larger than       the uncompressed packet. */    if (maxolen > slen)	maxolen = slen;    /* Allocate one mbuf to start with. */    MGET(m, M_DONTWAIT, MT_DATA);    *mret = m;    if (m != NULL) {	m->m_len = 0;	if (maxolen + db->hdrlen > MLEN)	    MCLGET(m, M_DONTWAIT);	m->m_data += db->hdrlen;	wptr = mtod(m, u_char *);	cp_end = wptr + M_TRAILINGSPACE(m);    } else	wptr = cp_end = NULL;    /*     * Copy the PPP header over, changing the protocol,     * and install the 2-byte packet sequence number.     */    if (wptr) {	*wptr++ = PPP_ADDRESS(rptr);	/* assumes the ppp header is */	*wptr++ = PPP_CONTROL(rptr);	/* all in one mbuf */	*wptr++ = 0;			/* change the protocol */	*wptr++ = PPP_COMP;	*wptr++ = db->seqno >> 8;	*wptr++ = db->seqno;    }    ++db->seqno;    olen = 0;    rptr += PPP_HDRLEN;    slen = mp->m_len - PPP_HDRLEN;    ilen = slen + 1;    for (;;) {	if (slen <= 0) {	    mp = mp->m_next;	    if (!mp)		break;	    rptr = mtod(mp, u_char *);	    slen = mp->m_len;	    if (!slen)		continue;   /* handle 0-length buffers */	    ilen += slen;	}	slen--;	c = *rptr++;	fcode = BSD_KEY(ent, c);	hval = BSD_HASH(ent, c, hshift);	dictp = &db->dict[hval];	/* Validate and then check the entry. */	if (dictp->codem1 >= max_ent)	    goto nomatch;	if (dictp->f.fcode == fcode) {	    ent = dictp->codem1+1;	    continue;	/* found (prefix,suffix) */	}	/* continue probing until a match or invalid entry */	disp = (hval == 0) ? 1 : hval;	do {	    hval += disp;	    if (hval >= db->hsize)		hval -= db->hsize;	    dictp = &db->dict[hval];	    if (dictp->codem1 >= max_ent)		goto nomatch;	} while (dictp->f.fcode != fcode);	ent = dictp->codem1 + 1;	/* finally found (prefix,suffix) */	continue;    nomatch:	OUTPUT(ent);		/* output the prefix */	/* code -> hashtable */	if (max_ent < db->maxmaxcode) {	    struct bsd_dict *dictp2;	    /* expand code size if needed */	    if (max_ent >= MAXCODE(n_bits))		db->n_bits = ++n_bits;	    /* Invalidate old hash table entry using	     * this code, and then take it over.	     */	    dictp2 = &db->dict[max_ent+1];	    if (db->dict[dictp2->cptr].codem1 == max_ent)		db->dict[dictp2->cptr].codem1 = BADCODEM1;	    dictp2->cptr = hval;	    dictp->codem1 = max_ent;	    dictp->f.fcode = fcode;	    db->max_ent = ++max_ent;	}	ent = c;    }    OUTPUT(ent);		/* output the last code */    db->bytes_out += olen;    db->in_count += ilen;    if (bitno < 32)	++db->bytes_out;	/* count complete bytes */    if (bsd_check(db))	OUTPUT(CLEAR);		/* do not count the CLEAR */    /*     * Pad dribble bits of last code with ones.     * Do not emit a completely useless byte of ones.     */    if (bitno != 32)	PUTBYTE((accm | (0xff << (bitno-8))) >> 24);    if (m != NULL) {	m->m_len = wptr - mtod(m, u_char *);	m->m_next = NULL;    }    /*     * Increase code size if we would have without the packet     * boundary and as the decompressor will.     */    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)	db->n_bits++;    db->uncomp_bytes += ilen;    ++db->uncomp_count;    if (olen + PPP_HDRLEN + BSD_OVHD > maxolen) {	/* throw away the compressed stuff if it is longer than uncompressed */	if (*mret != NULL) {	    m_freem(*mret);	    *mret = NULL;	}	++db->incomp_count;	db->incomp_bytes += ilen;    } else {	++db->comp_count;	db->comp_bytes += olen + BSD_OVHD;    }    return olen + PPP_HDRLEN + BSD_OVHD;#undef OUTPUT#undef PUTBYTE}/* * Update the "BSD Compress" dictionary on the receiver for * incompressible data by pretending to compress the incoming data. */static voidbsd_incomp(state, dmsg)    void *state;    struct mbuf *dmsg;{    struct bsd_db *db = (struct bsd_db *) state;    u_int hshift = db->hshift;    u_int max_ent = db->max_ent;    u_int n_bits = db->n_bits;    struct bsd_dict *dictp;    u_int32_t fcode;    u_char c;    u_int32_t hval, disp;    int slen, ilen;    u_int bitno = 7;    u_char *rptr;    u_int ent;    /*     * If the protocol is not in the range we're interested in,     * just return without looking at the packet.  If it is,     * the protocol becomes the first byte to "compress".     */    rptr = mtod(dmsg, u_char *);    ent = PPP_PROTOCOL(rptr);    if (ent < 0x21 || ent > 0xf9)	return;    db->seqno++;    ilen = 1;		/* count the protocol as 1 byte */    rptr += PPP_HDRLEN;    slen = dmsg->m_len - PPP_HDRLEN;    for (;;) {	if (slen <= 0) {	    dmsg = dmsg->m_next;	    if (!dmsg)		break;	    rptr = mtod(dmsg, u_char *);	    slen = dmsg->m_len;	    continue;	}	ilen += slen;	do {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?