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