Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/v42bis.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * v42bis.c | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2005 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU General Public License version 2, as | |
14 * published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: v42bis.c,v 1.29 2006/12/01 18:00:48 steveu Exp $ | |
26 */ | |
27 | |
28 /* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. | |
29 Currently it performs the core compression and decompression functions OK. | |
30 However, a number of the bells and whistles in V.42bis are incomplete. */ | |
31 | |
32 /*! \file */ | |
33 | |
34 #ifdef HAVE_CONFIG_H | |
35 #include <config.h> | |
36 #endif | |
37 | |
38 #include <stdio.h> | |
39 #include <stdlib.h> | |
40 #include <inttypes.h> | |
41 #include <string.h> | |
42 #include <errno.h> | |
43 #include <fcntl.h> | |
44 #include <ctype.h> | |
45 #include <assert.h> | |
46 | |
47 #include "spandsp/telephony.h" | |
48 #include "spandsp/logging.h" | |
49 #include "spandsp/bit_operations.h" | |
50 #include "spandsp/v42bis.h" | |
51 | |
52 /* Fixed parameters from the spec. */ | |
53 #define V42BIS_N3 8 /* Character size (bits) */ | |
54 #define V42BIS_N4 256 /* Number of characters in the alphabet */ | |
55 #define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) /* Index number of first dictionary entry used to store a string */ | |
56 #define V42BIS_N6 3 /* Number of control codewords */ | |
57 | |
58 /* Control code words in compressed mode */ | |
59 enum | |
60 { | |
61 V42BIS_ETM = 0, /* Enter transparent mode */ | |
62 V42BIS_FLUSH = 1, /* Flush data */ | |
63 V42BIS_STEPUP = 2 /* Step up codeword size */ | |
64 }; | |
65 | |
66 /* Command codes in transparent mode */ | |
67 enum | |
68 { | |
69 V42BIS_ECM = 0, /* Enter compression mode */ | |
70 V42BIS_EID = 1, /* Escape character in data */ | |
71 V42BIS_RESET = 2 /* Force reinitialisation */ | |
72 }; | |
73 | |
74 static __inline__ void push_compressed_raw_octet(v42bis_compress_state_t *ss, int octet) | |
75 { | |
76 ss->output_buf[ss->output_octet_count++] = (uint8_t) octet; | |
77 if (ss->output_octet_count >= ss->max_len) | |
78 { | |
79 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
80 ss->output_octet_count = 0; | |
81 } | |
82 } | |
83 /*- End of function --------------------------------------------------------*/ | |
84 | |
85 static __inline__ void push_compressed_code(v42bis_compress_state_t *ss, int code) | |
86 { | |
87 ss->output_bit_buffer |= code << (32 - ss->v42bis_parm_c2 - ss->output_bit_count); | |
88 ss->output_bit_count += ss->v42bis_parm_c2; | |
89 while (ss->output_bit_count >= 8) | |
90 { | |
91 push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); | |
92 ss->output_bit_buffer <<= 8; | |
93 ss->output_bit_count -= 8; | |
94 } | |
95 } | |
96 /*- End of function --------------------------------------------------------*/ | |
97 | |
98 static __inline__ void push_compressed_octet(v42bis_compress_state_t *ss, int code) | |
99 { | |
100 ss->output_bit_buffer |= code << (32 - 8 - ss->output_bit_count); | |
101 ss->output_bit_count += 8; | |
102 while (ss->output_bit_count >= 8) | |
103 { | |
104 push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); | |
105 ss->output_bit_buffer <<= 8; | |
106 ss->output_bit_count -= 8; | |
107 } | |
108 } | |
109 /*- End of function --------------------------------------------------------*/ | |
110 | |
111 int v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len) | |
112 { | |
113 int ptr; | |
114 int i; | |
115 uint32_t octet; | |
116 uint32_t code; | |
117 v42bis_compress_state_t *ss; | |
118 | |
119 ss = &s->compress; | |
120 if ((s->v42bis_parm_p0 & 2) == 0) | |
121 { | |
122 /* Compression is off - just push the incoming data out */ | |
123 for (i = 0; i < len - ss->max_len; i += ss->max_len) | |
124 ss->handler(ss->user_data, buf + i, ss->max_len); | |
125 if (i < len) | |
126 ss->handler(ss->user_data, buf + i, len - i); | |
127 return 0; | |
128 } | |
129 ptr = 0; | |
130 if (ss->first && len > 0) | |
131 { | |
132 octet = buf[ptr++]; | |
133 ss->string_code = octet + V42BIS_N6; | |
134 if (ss->transparent) | |
135 push_compressed_octet(ss, octet); | |
136 ss->first = FALSE; | |
137 } | |
138 while (ptr < len) | |
139 { | |
140 octet = buf[ptr++]; | |
141 if ((ss->dict[ss->string_code].children[octet >> 5] & (1 << (octet & 0x1F)))) | |
142 { | |
143 /* The leaf exists. Now find it in the table. */ | |
144 /* TODO: This is a brute force scan for a match. We need something better. */ | |
145 for (code = 0; code < ss->v42bis_parm_c3; code++) | |
146 { | |
147 if (ss->dict[code].parent_code == ss->string_code && ss->dict[code].node_octet == octet) | |
148 break; | |
149 } | |
150 } | |
151 else | |
152 { | |
153 /* The leaf does not exist. */ | |
154 code = s->v42bis_parm_n2; | |
155 } | |
156 /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry | |
157 created by the last invocation of the string matching procedure, then the | |
158 next character shall be read and appended to the string and this step | |
159 repeated. */ | |
160 if (code < ss->v42bis_parm_c3 && code != ss->latest_code) | |
161 { | |
162 /* The string was found */ | |
163 ss->string_code = code; | |
164 ss->string_length++; | |
165 } | |
166 else | |
167 { | |
168 /* The string is not in the table. */ | |
169 if (!ss->transparent) | |
170 { | |
171 /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ | |
172 while (ss->v42bis_parm_c1 >= ss->v42bis_parm_c3 && ss->v42bis_parm_c3 <= s->v42bis_parm_n2) | |
173 { | |
174 /* We need to increase the codeword size */ | |
175 /* 7.4(a) */ | |
176 push_compressed_code(ss, V42BIS_STEPUP); | |
177 /* 7.4(b) */ | |
178 ss->v42bis_parm_c2++; | |
179 /* 7.4(c) */ | |
180 ss->v42bis_parm_c3 <<= 1; | |
181 /* 7.4(d) this might need to be repeated, so we loop */ | |
182 } | |
183 /* 7.5 Transfer - output the last state of the string */ | |
184 push_compressed_code(ss, ss->string_code); | |
185 } | |
186 /* 7.6 Dictionary updating */ | |
187 /* 6.4 Add the string to the dictionary */ | |
188 /* 6.4(b) The string is not in the table. */ | |
189 if (code != ss->latest_code && ss->string_length < s->v42bis_parm_n7) | |
190 { | |
191 ss->latest_code = ss->v42bis_parm_c1; | |
192 /* 6.4(a) The length of the string is in range for adding to the dictionary */ | |
193 /* If the last code was a leaf, it no longer is */ | |
194 ss->dict[ss->string_code].leaves++; | |
195 ss->dict[ss->string_code].children[octet >> 5] |= (1 << (octet & 0x1F)); | |
196 /* The new one is definitely a leaf */ | |
197 ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->string_code; | |
198 ss->dict[ss->v42bis_parm_c1].leaves = 0; | |
199 ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) octet; | |
200 /* 7.7 Node recovery */ | |
201 /* 6.5 Recovering a dictionary entry to use next */ | |
202 for (;;) | |
203 { | |
204 /* 6.5(a) and (b) */ | |
205 if ((int) (++ss->v42bis_parm_c1) >= s->v42bis_parm_n2) | |
206 ss->v42bis_parm_c1 = V42BIS_N5; | |
207 /* 6.5(c) We need to reuse a leaf node */ | |
208 if (ss->dict[ss->v42bis_parm_c1].leaves) | |
209 continue; | |
210 if (ss->dict[ss->v42bis_parm_c1].parent_code == 0xFFFF) | |
211 break; | |
212 /* 6.5(d) Detach the leaf node from its parent, and re-use it */ | |
213 /* Possibly make the parent a leaf node again */ | |
214 ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; | |
215 ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].children[ss->dict[ss->v42bis_parm_c1].node_octet >> 5] &= ~(1 << (ss->dict[ss->v42bis_parm_c1].node_octet & 0x1F)); | |
216 ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; | |
217 break; | |
218 } | |
219 } | |
220 else | |
221 { | |
222 ss->latest_code = 0xFFFFFFFF; | |
223 } | |
224 /* 7.8 Data compressibility test */ | |
225 /* Filter on the balance of what went into the compressor, and what came out */ | |
226 ss->compressibility_filter += ((((8*ss->string_length - ss->v42bis_parm_c2) << 20) - ss->compressibility_filter) >> 10); | |
227 if (ss->compression_mode == V42BIS_COMPRESSION_MODE_DYNAMIC) | |
228 { | |
229 /* Work out if it is appropriate to change between transparent and | |
230 compressed mode. */ | |
231 if (ss->transparent) | |
232 { | |
233 if (ss->compressibility_filter > 0) | |
234 { | |
235 if (++ss->compressibility_persistence > 1000) | |
236 { | |
237 /* Schedule a switch to compressed mode */ | |
238 ss->change_transparency = -1; | |
239 ss->compressibility_persistence = 0; | |
240 } | |
241 } | |
242 else | |
243 { | |
244 ss->compressibility_persistence = 0; | |
245 } | |
246 } | |
247 else | |
248 { | |
249 if (ss->compressibility_filter < 0) | |
250 { | |
251 if (++ss->compressibility_persistence > 1000) | |
252 { | |
253 /* Schedule a switch to transparent mode */ | |
254 ss->change_transparency = 1; | |
255 ss->compressibility_persistence = 0; | |
256 } | |
257 } | |
258 else | |
259 { | |
260 ss->compressibility_persistence = 0; | |
261 } | |
262 } | |
263 } | |
264 if (ss->change_transparency) | |
265 { | |
266 if (ss->change_transparency < 0) | |
267 { | |
268 if (ss->transparent) | |
269 { | |
270 printf("Going compressed\n"); | |
271 /* 7.8.1 Transition to compressed mode */ | |
272 /* Switch out of transparent now, between codes. We need to send the octet which did not | |
273 match, just before switching. */ | |
274 if (octet == ss->escape_code) | |
275 { | |
276 push_compressed_octet(ss, ss->escape_code++); | |
277 push_compressed_octet(ss, V42BIS_EID); | |
278 } | |
279 else | |
280 { | |
281 push_compressed_octet(ss, octet); | |
282 } | |
283 push_compressed_octet(ss, ss->escape_code++); | |
284 push_compressed_octet(ss, V42BIS_ECM); | |
285 ss->transparent = FALSE; | |
286 } | |
287 } | |
288 else | |
289 { | |
290 if (!ss->transparent) | |
291 { | |
292 printf("Going transparent\n"); | |
293 /* 7.8.2 Transition to transparent mode */ | |
294 /* Switch into transparent now, between codes, and the unmatched octet should | |
295 go out in transparent mode, just below */ | |
296 push_compressed_code(ss, V42BIS_ETM); | |
297 ss->transparent = TRUE; | |
298 } | |
299 } | |
300 ss->change_transparency = 0; | |
301 } | |
302 /* 7.8.3 Reset function - TODO */ | |
303 ss->string_code = octet + V42BIS_N6; | |
304 ss->string_length = 1; | |
305 } | |
306 if (ss->transparent) | |
307 { | |
308 if (octet == ss->escape_code) | |
309 { | |
310 push_compressed_octet(ss, ss->escape_code++); | |
311 push_compressed_octet(ss, V42BIS_EID); | |
312 } | |
313 else | |
314 { | |
315 push_compressed_octet(ss, octet); | |
316 } | |
317 } | |
318 } | |
319 return 0; | |
320 } | |
321 /*- End of function --------------------------------------------------------*/ | |
322 | |
323 int v42bis_compress_flush(v42bis_state_t *s) | |
324 { | |
325 v42bis_compress_state_t *ss; | |
326 | |
327 ss = &s->compress; | |
328 if (!ss->transparent) | |
329 { | |
330 /* Output the last state of the string */ | |
331 push_compressed_code(ss, ss->string_code); | |
332 /* TODO: We use a positive FLUSH at all times. It is really needed, if the | |
333 previous step resulted in no leftover bits. */ | |
334 push_compressed_code(ss, V42BIS_FLUSH); | |
335 } | |
336 while (ss->output_bit_count > 0) | |
337 { | |
338 push_compressed_raw_octet(ss, ss->output_bit_buffer >> 24); | |
339 ss->output_bit_buffer <<= 8; | |
340 ss->output_bit_count -= 8; | |
341 } | |
342 /* Now push out anything remaining. */ | |
343 if (ss->output_octet_count > 0) | |
344 { | |
345 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
346 ss->output_octet_count = 0; | |
347 } | |
348 return 0; | |
349 } | |
350 /*- End of function --------------------------------------------------------*/ | |
351 | |
352 #if 0 | |
353 int v42bis_compress_dump(v42bis_state_t *s) | |
354 { | |
355 int i; | |
356 | |
357 for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) | |
358 { | |
359 if (s->compress.dict[i].parent_code != 0xFFFF) | |
360 { | |
361 printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet); | |
362 } | |
363 } | |
364 return 0; | |
365 } | |
366 /*- End of function --------------------------------------------------------*/ | |
367 #endif | |
368 | |
369 int v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len) | |
370 { | |
371 int ptr; | |
372 int i; | |
373 int this_length; | |
374 uint8_t *string; | |
375 uint32_t code; | |
376 uint32_t new_code; | |
377 int code_len; | |
378 v42bis_decompress_state_t *ss; | |
379 uint8_t decode_buf[V42BIS_MAX_STRING_SIZE]; | |
380 | |
381 ss = &s->decompress; | |
382 if ((s->v42bis_parm_p0 & 1) == 0) | |
383 { | |
384 /* Compression is off - just push the incoming data out */ | |
385 for (i = 0; i < len - ss->max_len; i += ss->max_len) | |
386 ss->handler(ss->user_data, buf + i, ss->max_len); | |
387 if (i < len) | |
388 ss->handler(ss->user_data, buf + i, len - i); | |
389 return 0; | |
390 } | |
391 ptr = 0; | |
392 code_len = (ss->transparent) ? 8 : ss->v42bis_parm_c2; | |
393 for (;;) | |
394 { | |
395 /* Fill up the bit buffer. */ | |
396 while (ss->input_bit_count < 32 - 8 && ptr < len) | |
397 { | |
398 ss->input_bit_count += 8; | |
399 ss->input_bit_buffer |= (uint32_t) buf[ptr++] << (32 - ss->input_bit_count); | |
400 } | |
401 if (ss->input_bit_count < code_len) | |
402 break; | |
403 new_code = ss->input_bit_buffer >> (32 - code_len); | |
404 ss->input_bit_count -= code_len; | |
405 ss->input_bit_buffer <<= code_len; | |
406 if (ss->transparent) | |
407 { | |
408 code = new_code; | |
409 if (ss->escaped) | |
410 { | |
411 ss->escaped = FALSE; | |
412 if (code == V42BIS_ECM) | |
413 { | |
414 printf("Hit V42BIS_ECM\n"); | |
415 ss->transparent = FALSE; | |
416 code_len = ss->v42bis_parm_c2; | |
417 } | |
418 else if (code == V42BIS_EID) | |
419 { | |
420 printf("Hit V42BIS_EID\n"); | |
421 ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1; | |
422 if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) | |
423 { | |
424 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
425 ss->output_octet_count = 0; | |
426 } | |
427 } | |
428 else if (code == V42BIS_RESET) | |
429 { | |
430 printf("Hit V42BIS_RESET\n"); | |
431 } | |
432 else | |
433 { | |
434 printf("Hit V42BIS_???? - %" PRIu32 "\n", code); | |
435 } | |
436 } | |
437 else if (code == ss->escape_code) | |
438 { | |
439 ss->escape_code++; | |
440 ss->escaped = TRUE; | |
441 } | |
442 else | |
443 { | |
444 ss->output_buf[ss->output_octet_count++] = (uint8_t) code; | |
445 if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) | |
446 { | |
447 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
448 ss->output_octet_count = 0; | |
449 } | |
450 } | |
451 } | |
452 else | |
453 { | |
454 if (new_code < V42BIS_N6) | |
455 { | |
456 /* We have a control code. */ | |
457 switch (new_code) | |
458 { | |
459 case V42BIS_ETM: | |
460 printf("Hit V42BIS_ETM\n"); | |
461 ss->transparent = TRUE; | |
462 code_len = 8; | |
463 break; | |
464 case V42BIS_FLUSH: | |
465 printf("Hit V42BIS_FLUSH\n"); | |
466 v42bis_decompress_flush(s); | |
467 break; | |
468 case V42BIS_STEPUP: | |
469 /* We need to increase the codeword size */ | |
470 printf("Hit V42BIS_STEPUP\n"); | |
471 if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2) | |
472 { | |
473 /* Invalid condition */ | |
474 return -1; | |
475 } | |
476 code_len = ++ss->v42bis_parm_c2; | |
477 ss->v42bis_parm_c3 <<= 1; | |
478 break; | |
479 } | |
480 continue; | |
481 } | |
482 if (ss->first) | |
483 { | |
484 ss->first = FALSE; | |
485 ss->octet = new_code - V42BIS_N6; | |
486 ss->output_buf[0] = (uint8_t) ss->octet; | |
487 ss->output_octet_count = 1; | |
488 if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) | |
489 { | |
490 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
491 ss->output_octet_count = 0; | |
492 } | |
493 ss->old_code = new_code; | |
494 continue; | |
495 } | |
496 /* Start at the end of the buffer, and decode backwards */ | |
497 string = &decode_buf[V42BIS_MAX_STRING_SIZE - 1]; | |
498 /* Check the received code is valid. It can't be too big, as we pulled only the expected number | |
499 of bits from the input stream. It could, however, be unknown. */ | |
500 if (ss->dict[new_code].parent_code == 0xFFFF) | |
501 return -1; | |
502 /* Otherwise we do a straight decode of the new code. */ | |
503 code = new_code; | |
504 /* Trace back through the octets which form the string, and output them. */ | |
505 while (code >= V42BIS_N5) | |
506 { | |
507 if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);} | |
508 *string-- = ss->dict[code].node_octet; | |
509 code = ss->dict[code].parent_code; | |
510 } | |
511 *string = (uint8_t) (code - V42BIS_N6); | |
512 ss->octet = code - V42BIS_N6; | |
513 /* Output the decoded string. */ | |
514 this_length = V42BIS_MAX_STRING_SIZE - (int) (string - decode_buf); | |
515 memcpy(ss->output_buf + ss->output_octet_count, string, this_length); | |
516 ss->output_octet_count += this_length; | |
517 if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7) | |
518 { | |
519 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
520 ss->output_octet_count = 0; | |
521 } | |
522 /* 6.4 Add the string to the dictionary */ | |
523 if (ss->last_length < s->v42bis_parm_n7) | |
524 { | |
525 /* 6.4(a) The string does not exceed N7 in length */ | |
526 if (ss->last_old_code != ss->old_code | |
527 || | |
528 ss->last_extra_octet != *string) | |
529 { | |
530 /* 6.4(b) The string is not in the table. */ | |
531 ss->dict[ss->old_code].leaves++; | |
532 /* The new one is definitely a leaf */ | |
533 ss->dict[ss->v42bis_parm_c1].parent_code = (uint16_t) ss->old_code; | |
534 ss->dict[ss->v42bis_parm_c1].leaves = 0; | |
535 ss->dict[ss->v42bis_parm_c1].node_octet = (uint8_t) ss->octet; | |
536 /* 6.5 Recovering a dictionary entry to use next */ | |
537 for (;;) | |
538 { | |
539 /* 6.5(a) and (b) */ | |
540 if (++ss->v42bis_parm_c1 >= s->v42bis_parm_n2) | |
541 ss->v42bis_parm_c1 = V42BIS_N5; | |
542 /* 6.5(c) We need to reuse a leaf node */ | |
543 if (ss->dict[ss->v42bis_parm_c1].leaves) | |
544 continue; | |
545 /* 6.5(d) This is a leaf node, so re-use it */ | |
546 /* Possibly make the parent a leaf node again */ | |
547 if (ss->dict[ss->v42bis_parm_c1].parent_code != 0xFFFF) | |
548 ss->dict[ss->dict[ss->v42bis_parm_c1].parent_code].leaves--; | |
549 ss->dict[ss->v42bis_parm_c1].parent_code = 0xFFFF; | |
550 break; | |
551 } | |
552 } | |
553 } | |
554 /* Record the addition to the dictionary, so we can check for repeat attempts | |
555 at the next code - see II.4.3 */ | |
556 ss->last_old_code = ss->old_code; | |
557 ss->last_extra_octet = *string; | |
558 | |
559 ss->old_code = new_code; | |
560 ss->last_length = this_length; | |
561 } | |
562 } | |
563 return 0; | |
564 } | |
565 /*- End of function --------------------------------------------------------*/ | |
566 | |
567 int v42bis_decompress_flush(v42bis_state_t *s) | |
568 { | |
569 v42bis_decompress_state_t *ss; | |
570 | |
571 ss = &s->decompress; | |
572 /* Push out anything remaining. */ | |
573 if (ss->output_octet_count > 0) | |
574 { | |
575 ss->handler(ss->user_data, ss->output_buf, ss->output_octet_count); | |
576 ss->output_octet_count = 0; | |
577 } | |
578 return 0; | |
579 } | |
580 /*- End of function --------------------------------------------------------*/ | |
581 | |
582 #if 0 | |
583 int v42bis_decompress_dump(v42bis_state_t *s) | |
584 { | |
585 int i; | |
586 | |
587 for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) | |
588 { | |
589 if (s->decompress.dict[i].parent_code != 0xFFFF) | |
590 { | |
591 printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet); | |
592 } | |
593 } | |
594 return 0; | |
595 } | |
596 /*- End of function --------------------------------------------------------*/ | |
597 #endif | |
598 | |
599 void v42bis_compression_control(v42bis_state_t *s, int mode) | |
600 { | |
601 s->compress.compression_mode = mode; | |
602 switch (mode) | |
603 { | |
604 case V42BIS_COMPRESSION_MODE_ALWAYS: | |
605 s->compress.change_transparency = -1; | |
606 break; | |
607 case V42BIS_COMPRESSION_MODE_NEVER: | |
608 s->compress.change_transparency = 1; | |
609 break; | |
610 } | |
611 } | |
612 /*- End of function --------------------------------------------------------*/ | |
613 | |
614 v42bis_state_t *v42bis_init(v42bis_state_t *s, | |
615 int negotiated_p0, | |
616 int negotiated_p1, | |
617 int negotiated_p2, | |
618 v42bis_frame_handler_t frame_handler, | |
619 void *frame_user_data, | |
620 int max_frame_len, | |
621 v42bis_data_handler_t data_handler, | |
622 void *data_user_data, | |
623 int max_data_len) | |
624 { | |
625 int i; | |
626 | |
627 if (negotiated_p1 < 512 || negotiated_p1 > 65535) | |
628 return NULL; | |
629 if (negotiated_p2 < 6 || negotiated_p2 > V42BIS_MAX_STRING_SIZE) | |
630 return NULL; | |
631 if (s == NULL) | |
632 { | |
633 if ((s = (v42bis_state_t *) malloc(sizeof(*s))) == NULL) | |
634 return NULL; | |
635 } | |
636 memset(s, 0, sizeof(*s)); | |
637 | |
638 s->compress.handler = frame_handler; | |
639 s->compress.user_data = frame_user_data; | |
640 s->compress.max_len = (max_frame_len < 1024) ? max_frame_len : 1024; | |
641 | |
642 s->decompress.handler = data_handler; | |
643 s->decompress.user_data = data_user_data; | |
644 s->decompress.max_len = (max_data_len < 1024) ? max_data_len : 1024; | |
645 | |
646 s->v42bis_parm_p0 = negotiated_p0; /* default is both ways off */ | |
647 | |
648 s->v42bis_parm_n1 = top_bit(negotiated_p1 - 1) + 1; | |
649 s->v42bis_parm_n2 = negotiated_p1; | |
650 s->v42bis_parm_n7 = negotiated_p2; | |
651 | |
652 /* 6.5 */ | |
653 s->compress.v42bis_parm_c1 = | |
654 s->decompress.v42bis_parm_c1 = V42BIS_N5; | |
655 | |
656 s->compress.v42bis_parm_c2 = | |
657 s->decompress.v42bis_parm_c2 = V42BIS_N3 + 1; | |
658 | |
659 s->compress.v42bis_parm_c3 = | |
660 s->decompress.v42bis_parm_c3 = 2*V42BIS_N4; | |
661 | |
662 s->compress.first = | |
663 s->decompress.first = TRUE; | |
664 for (i = 0; i < V42BIS_MAX_CODEWORDS; i++) | |
665 { | |
666 s->compress.dict[i].parent_code = | |
667 s->decompress.dict[i].parent_code = 0xFFFF; | |
668 s->compress.dict[i].leaves = | |
669 s->decompress.dict[i].leaves = 0; | |
670 } | |
671 /* Point the root nodes for decompression to themselves. It doesn't matter much what | |
672 they are set to, as long as they are considered "known" codes. */ | |
673 for (i = 0; i < V42BIS_N5; i++) | |
674 s->decompress.dict[i].parent_code = (uint16_t) i; | |
675 s->compress.string_code = 0xFFFFFFFF; | |
676 s->compress.latest_code = 0xFFFFFFFF; | |
677 | |
678 s->decompress.last_old_code = 0xFFFFFFFF; | |
679 s->decompress.last_extra_octet = -1; | |
680 | |
681 s->compress.compression_mode = V42BIS_COMPRESSION_MODE_DYNAMIC; | |
682 | |
683 return s; | |
684 } | |
685 /*- End of function --------------------------------------------------------*/ | |
686 | |
687 int v42bis_release(v42bis_state_t *s) | |
688 { | |
689 free(s); | |
690 return 0; | |
691 } | |
692 /*- End of function --------------------------------------------------------*/ | |
693 /*- End of file ------------------------------------------------------------*/ |