2 * Copyright (c) 2002-2004 Jan Dubiec <jdx@slackware.pl>
3 * Copyright (c) 2007 Alexander Motin <mav@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * MPPC decompression library.
33 * Note that Hi/Fn (later acquired by Exar Corporation) held US patents
34 * on some implementation-critical aspects of MPPC compression.
35 * These patents lapsed due to non-payment of fees in 2007 and by 2015
39 #include <sys/param.h>
40 #include <sys/systm.h>
44 #define MPPE_HIST_LEN 8192
46 #define HASH(x) (((40543*(((((x)[0]<<4)^(x)[1])<<4)^(x)[2]))>>4) & 0x1fff)
48 struct MPPC_comp_state
{
49 uint8_t hist
[2*MPPE_HIST_LEN
];
51 uint16_t hash
[MPPE_HIST_LEN
];
54 /* Inserts 1 to 8 bits into the output buffer. */
56 putbits8(uint8_t *buf
, uint32_t val
, const uint32_t n
, uint32_t *i
, uint32_t *l
)
62 *buf
= *buf
| (val
& 0xff);
72 *buf
= *buf
| ((val
>> 8) & 0xff);
73 *(++buf
) = val
& 0xff;
77 /* Inserts 9 to 16 bits into the output buffer. */
79 putbits16(uint8_t *buf
, uint32_t val
, const uint32_t n
, uint32_t *i
, uint32_t *l
)
86 *buf
= *buf
| ((val
>> 8) & 0xff);
87 *(++buf
) = val
& 0xff;
97 *buf
= *buf
| ((val
>> 16) & 0xff);
98 *(++buf
) = (val
>> 8) & 0xff;
99 *(++buf
) = val
& 0xff;
103 /* Inserts 17 to 24 bits into the output buffer. */
105 putbits24(uint8_t *buf
, uint32_t val
, const uint32_t n
, uint32_t *i
, uint32_t *l
)
112 *buf
= *buf
| ((val
>> 16) & 0xff);
113 *(++buf
) = (val
>> 8) & 0xff;
114 *(++buf
) = val
& 0xff;
121 (*i
)++; (*i
)++; (*i
)++;
124 *buf
= *buf
| ((val
>> 24) & 0xff);
125 *(++buf
) = (val
>> 16) & 0xff;
126 *(++buf
) = (val
>> 8) & 0xff;
127 *(++buf
) = val
& 0xff;
131 size_t MPPC_SizeOfCompressionHistory(void)
133 return (sizeof(struct MPPC_comp_state
));
136 void MPPC_InitCompressionHistory(char *history
)
138 struct MPPC_comp_state
*state
= (struct MPPC_comp_state
*)history
;
140 bzero(history
, sizeof(struct MPPC_comp_state
));
141 state
->histptr
= MPPE_HIST_LEN
;
144 int MPPC_Compress(u_char
**src
, u_char
**dst
, u_long
*srcCnt
, u_long
*dstCnt
, char *history
, int flags
, int undef
)
146 struct MPPC_comp_state
*state
= (struct MPPC_comp_state
*)history
;
147 uint32_t olen
, off
, len
, idx
, i
, l
;
148 uint8_t *hist
, *sbuf
, *p
, *q
, *r
, *s
;
152 * At this point, to avoid possible buffer overflow caused by packet
153 * expansion during/after compression, we should make sure we have
154 * space for the worst case.
156 * Maximum MPPC packet expansion is 12.5%. This is the worst case when
157 * all octets in the input buffer are >= 0x80 and we cannot find any
160 if (*dstCnt
< (*srcCnt
* 9 / 8 + 2)) {
165 /* We can't compress more then MPPE_HIST_LEN bytes in a call. */
166 if (*srcCnt
> MPPE_HIST_LEN
) {
171 hist
= state
->hist
+ MPPE_HIST_LEN
;
172 /* check if there is enough room at the end of the history */
173 if (state
->histptr
+ *srcCnt
>= 2*MPPE_HIST_LEN
) {
174 rtn
|= MPPC_RESTART_HISTORY
;
175 state
->histptr
= MPPE_HIST_LEN
;
176 memcpy(state
->hist
, hist
, MPPE_HIST_LEN
);
178 /* Add packet to the history. */
179 sbuf
= state
->hist
+ state
->histptr
;
180 memcpy(sbuf
, *src
, *srcCnt
);
181 state
->histptr
+= *srcCnt
;
185 **dst
= olen
= i
= 0;
187 while (i
< *srcCnt
- 2) {
190 /* Prognose matching position using hash function. */
192 p
= hist
+ state
->hash
[idx
];
193 state
->hash
[idx
] = (uint16_t) (s
- hist
);
194 if (p
> s
) /* It was before MPPC_RESTART_HISTORY. */
195 p
-= MPPE_HIST_LEN
; /* Try previous history buffer. */
198 /* Check our prognosis. */
199 if (off
> MPPE_HIST_LEN
- 1 || off
< 1 || *p
++ != *s
++ ||
200 *p
++ != *s
++ || *p
++ != *s
++) {
201 /* No match found; encode literal byte. */
202 if ((*src
)[i
] < 0x80) { /* literal byte < 0x80 */
203 putbits8(*dst
, (uint32_t) (*src
)[i
], 8, &olen
, &l
);
204 } else { /* literal byte >= 0x80 */
205 putbits16(*dst
, (uint32_t) (0x100|((*src
)[i
]&0x7f)), 9,
212 /* Find length of the matching fragment */
213 #if defined(__amd64__) || defined(__i386__)
214 /* Optimization for CPUs without strict data aligning requirements */
215 while ((*((uint32_t*)p
) == *((uint32_t*)s
)) && (s
< (r
- 3))) {
220 while((*p
++ == *s
++) && (s
<= r
));
224 /* At least 3 character match found; code data. */
226 if (off
< 64) { /* 10-bit offset; 0 <= offset < 64 */
227 putbits16(*dst
, 0x3c0|off
, 10, &olen
, &l
);
228 } else if (off
< 320) { /* 12-bit offset; 64 <= offset < 320 */
229 putbits16(*dst
, 0xe00|(off
-64), 12, &olen
, &l
);
230 } else if (off
< 8192) { /* 16-bit offset; 320 <= offset < 8192 */
231 putbits16(*dst
, 0xc000|(off
-320), 16, &olen
, &l
);
232 } else { /* NOTREACHED */
233 __assert_unreachable();
238 /* Encode length of match. */
239 if (len
< 4) { /* length = 3 */
240 putbits8(*dst
, 0, 1, &olen
, &l
);
241 } else if (len
< 8) { /* 4 <= length < 8 */
242 putbits8(*dst
, 0x08|(len
&0x03), 4, &olen
, &l
);
243 } else if (len
< 16) { /* 8 <= length < 16 */
244 putbits8(*dst
, 0x30|(len
&0x07), 6, &olen
, &l
);
245 } else if (len
< 32) { /* 16 <= length < 32 */
246 putbits8(*dst
, 0xe0|(len
&0x0f), 8, &olen
, &l
);
247 } else if (len
< 64) { /* 32 <= length < 64 */
248 putbits16(*dst
, 0x3c0|(len
&0x1f), 10, &olen
, &l
);
249 } else if (len
< 128) { /* 64 <= length < 128 */
250 putbits16(*dst
, 0xf80|(len
&0x3f), 12, &olen
, &l
);
251 } else if (len
< 256) { /* 128 <= length < 256 */
252 putbits16(*dst
, 0x3f00|(len
&0x7f), 14, &olen
, &l
);
253 } else if (len
< 512) { /* 256 <= length < 512 */
254 putbits16(*dst
, 0xfe00|(len
&0xff), 16, &olen
, &l
);
255 } else if (len
< 1024) { /* 512 <= length < 1024 */
256 putbits24(*dst
, 0x3fc00|(len
&0x1ff), 18, &olen
, &l
);
257 } else if (len
< 2048) { /* 1024 <= length < 2048 */
258 putbits24(*dst
, 0xff800|(len
&0x3ff), 20, &olen
, &l
);
259 } else if (len
< 4096) { /* 2048 <= length < 4096 */
260 putbits24(*dst
, 0x3ff000|(len
&0x7ff), 22, &olen
, &l
);
261 } else if (len
< 8192) { /* 4096 <= length < 8192 */
262 putbits24(*dst
, 0xffe000|(len
&0xfff), 24, &olen
, &l
);
263 } else { /* NOTREACHED */
269 /* Add remaining octets to the output. */
270 while(*srcCnt
- i
> 0) {
271 if ((*src
)[i
] < 0x80) { /* literal byte < 0x80 */
272 putbits8(*dst
, (uint32_t) (*src
)[i
++], 8, &olen
, &l
);
273 } else { /* literal byte >= 0x80 */
274 putbits16(*dst
, (uint32_t) (0x100|((*src
)[i
++]&0x7f)), 9, &olen
,
279 /* Reset unused bits of the last output octet. */
280 if ((l
!= 0) && (l
!= 8)) {
281 putbits8(*dst
, 0, l
, &olen
, &l
);
284 /* If result is bigger then original, set flag and flush history. */
285 if ((*srcCnt
< olen
) || ((flags
& MPPC_SAVE_HISTORY
) == 0)) {
287 rtn
|= MPPC_EXPANDED
;
288 bzero(history
, sizeof(struct MPPC_comp_state
));
289 state
->histptr
= MPPE_HIST_LEN
;