Project

General

Profile

v42bis.c

dexter, 08/01/2016 04:45 PM

 
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
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
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
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
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
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
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
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
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
int v42bis_release(v42bis_state_t *s)
691
{
692
    return 0;
693
}
694
/*- End of function --------------------------------------------------------*/
695

    
696
int v42bis_free(v42bis_state_t *s)
697
{
698
    free(s);
699
    return 0;
700
}
701
/*- End of function --------------------------------------------------------*/
702
/*- End of file ------------------------------------------------------------*/
Add picture from clipboard (Maximum size: 48.8 MB)