| 144 | } |
| 145 | |
| 146 | int MPPC_Compress(u_char **src, u_char **dst, u_long *srcCnt, u_long *dstCnt, char *history, int flags, int undef) |
| 147 | { |
| 148 | struct MPPC_comp_state *state = (struct MPPC_comp_state*)history; |
| 149 | uint32_t olen, off, len, idx, i, l; |
| 150 | uint8_t *hist, *sbuf, *p, *q, *r, *s; |
| 151 | int rtn = MPPC_OK; |
| 152 | |
| 153 | /* |
| 154 | * At this point, to avoid possible buffer overflow caused by packet |
| 155 | * expansion during/after compression, we should make sure we have |
| 156 | * space for the worst case. |
| 157 | |
| 158 | * Maximum MPPC packet expansion is 12.5%. This is the worst case when |
| 159 | * all octets in the input buffer are >= 0x80 and we cannot find any |
| 160 | * repeated tokens. |
| 161 | */ |
| 162 | if (*dstCnt < (*srcCnt * 9 / 8 + 2)) { |
| 163 | rtn &= ~MPPC_OK; |
| 164 | return (rtn); |
| 165 | } |
| 166 | |
| 167 | /* We can't compress more then MPPE_HIST_LEN bytes in a call. */ |
| 168 | if (*srcCnt > MPPE_HIST_LEN) { |
| 169 | rtn &= ~MPPC_OK; |
| 170 | return (rtn); |
| 171 | } |
| 172 | |
| 173 | hist = state->hist + MPPE_HIST_LEN; |
| 174 | /* check if there is enough room at the end of the history */ |
| 175 | if (state->histptr + *srcCnt >= 2*MPPE_HIST_LEN) { |
| 176 | rtn |= MPPC_RESTART_HISTORY; |
| 177 | state->histptr = MPPE_HIST_LEN; |
| 178 | memcpy(state->hist, hist, MPPE_HIST_LEN); |
| 179 | } |
| 180 | /* Add packet to the history. */ |
| 181 | sbuf = state->hist + state->histptr; |
| 182 | memcpy(sbuf, *src, *srcCnt); |
| 183 | state->histptr += *srcCnt; |
| 184 | |
| 185 | /* compress data */ |
| 186 | r = sbuf + *srcCnt; |
| 187 | **dst = olen = i = 0; |
| 188 | l = 8; |
| 189 | while (i < *srcCnt - 2) { |
| 190 | s = q = sbuf + i; |
| 191 | |
| 192 | /* Prognose matching position using hash function. */ |
| 193 | idx = HASH(s); |
| 194 | p = hist + state->hash[idx]; |
| 195 | state->hash[idx] = (uint16_t) (s - hist); |
| 196 | if (p > s) /* It was before MPPC_RESTART_HISTORY. */ |
| 197 | p -= MPPE_HIST_LEN; /* Try previous history buffer. */ |
| 198 | off = s - p; |
| 199 | |
| 200 | /* Check our prognosis. */ |
| 201 | if (off > MPPE_HIST_LEN - 1 || off < 1 || *p++ != *s++ || |
| 202 | *p++ != *s++ || *p++ != *s++) { |
| 203 | /* No match found; encode literal byte. */ |