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 ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.