Coverage Report

Created: 2026-09-14 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/lzo-2.10/src/lzo1.c
Line
Count
Source
1
/* lzo1.c -- implementation of the LZO1 algorithm
2
3
   This file is part of the LZO real-time data compression library.
4
5
   Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
6
   All Rights Reserved.
7
8
   The LZO library is free software; you can redistribute it and/or
9
   modify it under the terms of the GNU General Public License as
10
   published by the Free Software Foundation; either version 2 of
11
   the License, or (at your option) any later version.
12
13
   The LZO library is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
18
   You should have received a copy of the GNU General Public License
19
   along with the LZO library; see the file COPYING.
20
   If not, write to the Free Software Foundation, Inc.,
21
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23
   Markus F.X.J. Oberhumer
24
   <markus@oberhumer.com>
25
   http://www.oberhumer.com/opensource/lzo/
26
 */
27
28
29
#include "lzo_conf.h"
30
#include <lzo/lzo1.h>
31
32
33
/***********************************************************************
34
// The next two defines can be changed to customize LZO1.
35
// The default version is LZO1-5/1.
36
************************************************************************/
37
38
/* run bits (3 - 5) - the compressor and the decompressor
39
 * must use the same value. */
40
#if !defined(RBITS)
41
3.80M
#  define RBITS     5
42
#endif
43
44
/* compression level (1 - 9) - this only affects the compressor.
45
 * 1 is fastest, 9 is best compression ratio */
46
#if !defined(CLEVEL)
47
0
#  define CLEVEL    1           /* fastest by default */
48
#endif
49
50
51
/* check configuration */
52
#if (RBITS < 3 || RBITS > 5)
53
#  error "invalid RBITS"
54
#endif
55
#if (CLEVEL < 1 || CLEVEL > 9)
56
#  error "invalid CLEVEL"
57
#endif
58
59
60
/***********************************************************************
61
// You should not have to change anything below this line.
62
************************************************************************/
63
64
/*
65
     Format of the marker byte
66
67
68
     76543210
69
     --------
70
     00000000   a long run (a 'R0' run) - there are short and long R0 runs
71
     000rrrrr   a short run with len r
72
     mmmooooo   a short match (len = 2+m, o = offset low bits)
73
     111ooooo   a long match (o = offset low bits)
74
*/
75
76
77
938k
#define RSIZE   (1 << RBITS)
78
#define RMASK   (RSIZE - 1)
79
80
2.86M
#define OBITS   RBITS               /* offset and run-length use same bits */
81
473k
#define OSIZE   (1 << OBITS)
82
473k
#define OMASK   (OSIZE - 1)
83
84
1.14M
#define MBITS   (8 - OBITS)
85
1.14M
#define MSIZE   (1 << MBITS)
86
#define MMASK   (MSIZE - 1)
87
88
89
/* sanity checks */
90
#if (OBITS < 3 || OBITS > 5)
91
#  error "invalid OBITS"
92
#endif
93
#if (MBITS < 3 || MBITS > 5)
94
#  error "invalid MBITS"
95
#endif
96
97
98
/***********************************************************************
99
// some macros to improve readability
100
************************************************************************/
101
102
/* Minimum len of a match */
103
1.23M
#define MIN_MATCH           3
104
845k
#define THRESHOLD           (MIN_MATCH - 1)
105
106
/* Minimum len of match coded in 2 bytes */
107
#define MIN_MATCH_SHORT     MIN_MATCH
108
109
/* Maximum len of match coded in 2 bytes */
110
674k
#define MAX_MATCH_SHORT     (THRESHOLD + (MSIZE - 2))
111
/* MSIZE - 2: 0 is used to indicate runs,
112
 *            MSIZE-1 is used to indicate a long match */
113
114
/* Minimum len of match coded in 3 bytes */
115
674k
#define MIN_MATCH_LONG      (MAX_MATCH_SHORT + 1)
116
117
/* Maximum len of match coded in 3 bytes */
118
250k
#define MAX_MATCH_LONG      (MIN_MATCH_LONG + 255)
119
120
/* Maximum offset of a match */
121
#define MAX_OFFSET          (1 << (8 + OBITS))
122
123
124
/*
125
126
RBITS | MBITS  MIN  THR.  MSIZE  MAXS  MINL  MAXL   MAXO  R0MAX R0FAST
127
======+===============================================================
128
  3   |   5      3    2     32    32    33    288   2048    263   256
129
  4   |   4      3    2     16    16    17    272   4096    271   264
130
  5   |   3      3    2      8     8     9    264   8192    287   280
131
132
 */
133
134
135
/***********************************************************************
136
// internal configuration
137
// all of these affect compression only
138
************************************************************************/
139
140
/* choose the hashing strategy */
141
#ifndef LZO_HASH
142
#define LZO_HASH    LZO_HASH_LZO_INCREMENTAL_A
143
#endif
144
14.3M
#define D_INDEX1(d,p)       d = DM(DMUL(0x21,DX2(p,5,5)) >> 5)
145
9.33M
#define D_INDEX2(d,p)       d = d ^ D_MASK
146
147
#define DBITS       (8 + RBITS)
148
#include "lzo_dict.h"
149
1.75k
#define DVAL_LEN    DVAL_LOOKAHEAD
150
151
152
/***********************************************************************
153
// get algorithm info, return memory required for compression
154
************************************************************************/
155
156
LZO_EXTERN(lzo_uint) lzo1_info ( int *rbits, int *clevel );
157
158
LZO_PUBLIC(lzo_uint)
159
lzo1_info ( int *rbits, int *clevel )
160
0
{
161
0
    if (rbits)
162
0
        *rbits = RBITS;
163
0
    if (clevel)
164
0
        *clevel = CLEVEL;
165
0
    return D_SIZE * lzo_sizeof(lzo_bytep);
166
0
}
167
168
169
/***********************************************************************
170
// decode a R0 literal run (a long run)
171
************************************************************************/
172
173
938k
#define R0MIN   (RSIZE)             /* Minimum len of R0 run of literals */
174
79.6k
#define R0MAX   (R0MIN + 255)       /* Maximum len of R0 run of literals */
175
79.6k
#define R0FAST  (R0MAX & ~7u)       /* R0MAX aligned to 8 byte boundary */
176
177
#if (R0MAX - R0FAST != 7) || ((R0FAST & 7) != 0)
178
#  error "something went wrong"
179
#endif
180
181
/* 7 special codes from R0FAST+1 .. R0MAX
182
 * these codes mean long R0 runs with lengths
183
 * 512, 1024, 2048, 4096, 8192, 16384, 32768 */
184
185
186
/***********************************************************************
187
// LZO1 decompress a block of data.
188
//
189
// Could be easily translated into assembly code.
190
************************************************************************/
191
192
LZO_PUBLIC(int)
193
lzo1_decompress  ( const lzo_bytep in , lzo_uint  in_len,
194
                         lzo_bytep out, lzo_uintp out_len,
195
                         lzo_voidp wrkmem )
196
820
{
197
820
    lzo_bytep op;
198
820
    const lzo_bytep ip;
199
820
    const lzo_bytep const ip_end = in + in_len;
200
820
    lzo_uint t;
201
202
820
    LZO_UNUSED(wrkmem);
203
204
820
    op = out;
205
820
    ip = in;
206
643k
    while (ip < ip_end)
207
642k
    {
208
642k
        t = *ip++;  /* get marker */
209
210
642k
        if (t < R0MIN)          /* a literal run */
211
169k
        {
212
169k
            if (t == 0)             /* a R0 literal run */
213
34.1k
            {
214
34.1k
                t = *ip++;
215
34.1k
                if (t >= R0FAST - R0MIN)            /* a long R0 run */
216
13.0k
                {
217
13.0k
                    t -= R0FAST - R0MIN;
218
13.0k
                    if (t == 0)
219
4.98k
                        t = R0FAST;
220
8.02k
                    else
221
8.02k
                    {
222
#if 0
223
                        t = 256u << ((unsigned) t);
224
#else
225
                        /* help the optimizer */
226
8.02k
                        lzo_uint tt = 256;
227
16.8k
                        do tt <<= 1; while (--t > 0);
228
8.02k
                        t = tt;
229
8.02k
#endif
230
8.02k
                    }
231
13.0k
                    MEMCPY8_DS(op,ip,t);
232
13.0k
                    continue;
233
13.0k
                }
234
21.1k
                t += R0MIN;
235
21.1k
            }
236
156k
            MEMCPY_DS(op,ip,t);
237
156k
        }
238
473k
        else                    /* a match */
239
473k
        {
240
473k
            lzo_uint tt;
241
            /* get match offset */
242
473k
            const lzo_bytep m_pos = op - 1;
243
473k
            m_pos -= (lzo_uint)(t & OMASK) | (((lzo_uint) *ip++) << OBITS);
244
245
            /* get match len */
246
473k
            if (t >= ((MSIZE - 1) << OBITS))                /* all m-bits set */
247
171k
                tt = (MIN_MATCH_LONG - THRESHOLD) + *ip++;  /* a long match */
248
301k
            else
249
301k
                tt = t >> OBITS;                            /* a short match */
250
251
473k
            assert(m_pos >= out);
252
473k
            assert(m_pos <  op);
253
            /* a half unrolled loop */
254
473k
            *op++ = *m_pos++;
255
473k
            *op++ = *m_pos++;
256
473k
            MEMCPY_DS(op,m_pos,tt);
257
473k
        }
258
642k
    }
259
260
820
    *out_len = pd(op, out);
261
262
    /* the next line is the only check in the decompressor ! */
263
820
    return (ip == ip_end ? LZO_E_OK :
264
820
           (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
265
820
}
266
267
268
/***********************************************************************
269
// code a literal run
270
************************************************************************/
271
272
static
273
#if LZO_ARCH_AVR
274
__lzo_noinline
275
#endif
276
lzo_bytep
277
store_run(lzo_bytep op, const lzo_bytep ii, lzo_uint r_len)
278
17.5k
{
279
17.5k
    assert(r_len > 0);
280
281
    /* code a long R0 run */
282
17.5k
    if (r_len >= 512)
283
3.27k
    {
284
3.27k
        unsigned r_bits = 7;        /* 256 << 7 == 32768 */
285
22.9k
        do {
286
27.6k
            while (r_len >= (256u << r_bits))
287
4.78k
            {
288
4.78k
                r_len -= (256u << r_bits);
289
4.78k
                *op++ = 0; *op++ = LZO_BYTE((R0FAST - R0MIN) + r_bits);
290
4.78k
                MEMCPY8_DS(op, ii, (256u << r_bits));
291
4.78k
            }
292
22.9k
        } while (--r_bits > 0);
293
3.27k
    }
294
20.8k
    while (r_len >= R0FAST)
295
3.32k
    {
296
3.32k
        r_len -= R0FAST;
297
3.32k
        *op++ = 0; *op++ = R0FAST - R0MIN;
298
3.32k
        MEMCPY8_DS(op, ii, R0FAST);
299
3.32k
    }
300
301
17.5k
    if (r_len >= R0MIN)
302
15.7k
    {
303
        /* code a short R0 run */
304
15.7k
        *op++ = 0; *op++ = LZO_BYTE(r_len - R0MIN);
305
15.7k
        MEMCPY_DS(op, ii, r_len);
306
15.7k
    }
307
1.77k
    else if (r_len > 0)
308
1.41k
    {
309
        /* code a 'normal' run */
310
1.41k
        *op++ = LZO_BYTE(r_len);
311
1.41k
        MEMCPY_DS(op, ii, r_len);
312
1.41k
    }
313
314
17.5k
    assert(r_len == 0);
315
17.5k
    return op;
316
17.5k
}
317
318
319
320
/***********************************************************************
321
// LZO1 compress a block of data.
322
//
323
// Could be translated into assembly code without too much effort.
324
//
325
// I apologize for the spaghetti code, but it really helps the optimizer.
326
************************************************************************/
327
328
static int
329
do_compress    ( const lzo_bytep in , lzo_uint  in_len,
330
                       lzo_bytep out, lzo_uintp out_len,
331
                       lzo_voidp wrkmem )
332
437
{
333
437
    const lzo_bytep ip;
334
437
#if defined(__LZO_HASH_INCREMENTAL)
335
437
    lzo_xint dv;
336
437
#endif
337
437
    lzo_bytep op;
338
437
    const lzo_bytep m_pos;
339
437
    const lzo_bytep const ip_end = in+in_len - DVAL_LEN - MIN_MATCH_LONG;
340
437
    const lzo_bytep const in_end = in+in_len - DVAL_LEN;
341
437
    const lzo_bytep ii;
342
437
    lzo_dict_p const dict = (lzo_dict_p) wrkmem;
343
344
#if !defined(NDEBUG)
345
    const lzo_bytep m_pos_sav;
346
#endif
347
348
437
    op = out;
349
437
    ip = in;
350
437
    ii = ip;                /* point to start of literal run */
351
437
    if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1)
352
0
        goto the_end;
353
354
    /* init dictionary */
355
437
#if (LZO_DETERMINISTIC)
356
437
    BZERO8_PTR(wrkmem,sizeof(lzo_dict_t),D_SIZE);
357
437
#endif
358
359
437
    DVAL_FIRST(dv,ip);
360
437
    UPDATE_D(dict,0,dv,ip,in);
361
437
    ip++;
362
437
    DVAL_NEXT(dv,ip);
363
364
14.3M
    do {
365
14.3M
        LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0);
366
14.3M
        lzo_uint dindex;
367
368
14.3M
        DINDEX1(dindex,ip);
369
14.3M
        GINDEX(m_pos,m_off,dict,dindex,in);
370
14.3M
        if (LZO_CHECK_MPOS(m_pos,m_off,in,ip,MAX_OFFSET))
371
5.04M
            goto literal;
372
9.33M
        if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2])
373
342k
            goto match;
374
8.99M
        DINDEX2(dindex,ip);
375
8.99M
        GINDEX(m_pos,m_off,dict,dindex,in);
376
8.99M
        if (LZO_CHECK_MPOS(m_pos,m_off,in,ip,MAX_OFFSET))
377
2.42M
            goto literal;
378
6.56M
        if (m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2])
379
45.4k
            goto match;
380
6.52M
        goto literal;
381
382
383
13.9M
literal:
384
13.9M
        UPDATE_I(dict,0,dindex,ip,in);
385
13.9M
        if (++ip >= ip_end)
386
207
            break;
387
13.9M
        continue;
388
389
13.9M
match:
390
387k
        UPDATE_I(dict,0,dindex,ip,in);
391
#if !defined(NDEBUG) && (LZO_DICT_USE_PTR)
392
        m_pos_sav = m_pos;
393
#endif
394
387k
        m_pos += 3;
395
387k
        {
396
    /* we have found a match (of at least length 3) */
397
#if !defined(NDEBUG) && !(LZO_DICT_USE_PTR)
398
            assert((m_pos_sav = ip - m_off) == (m_pos - 3));
399
#endif
400
            /* 1) store the current literal run */
401
387k
            if (pd(ip,ii) > 0)
402
127k
            {
403
127k
                lzo_uint t = pd(ip,ii);
404
127k
#if 1
405
                /* OPTIMIZED: inline the copying of a short run */
406
127k
                if (t < R0MIN)
407
109k
                {
408
109k
                    *op++ = LZO_BYTE(t);
409
109k
                    MEMCPY_DS(op, ii, t);
410
109k
                }
411
17.1k
                else
412
17.1k
#endif
413
17.1k
                    op = store_run(op,ii,t);
414
127k
            }
415
416
            /* 2a) compute match len */
417
387k
            ii = ip;        /* point to start of current match */
418
419
            /* we already matched MIN_MATCH bytes,
420
             * m_pos also already advanced MIN_MATCH bytes */
421
387k
            ip += MIN_MATCH;
422
387k
            assert(m_pos < ip);
423
424
            /* try to match another MIN_MATCH_LONG - MIN_MATCH bytes
425
             * to see if we get a long match */
426
427
3.23M
#define PS  *m_pos++ != *ip++
428
429
#if (MIN_MATCH_LONG - MIN_MATCH == 2)                   /* MBITS == 2 */
430
            if (PS || PS)
431
#elif (MIN_MATCH_LONG - MIN_MATCH == 6)                 /* MBITS == 3 */
432
387k
            if (PS || PS || PS || PS || PS || PS)
433
#elif (MIN_MATCH_LONG - MIN_MATCH == 14)                /* MBITS == 4 */
434
            if (PS || PS || PS || PS || PS || PS || PS ||
435
                PS || PS || PS || PS || PS || PS || PS)
436
#elif (MIN_MATCH_LONG - MIN_MATCH == 30)                /* MBITS == 5 */
437
            if (PS || PS || PS || PS || PS || PS || PS || PS ||
438
                PS || PS || PS || PS || PS || PS || PS || PS ||
439
                PS || PS || PS || PS || PS || PS || PS || PS ||
440
                PS || PS || PS || PS || PS || PS)
441
#else
442
#  error "MBITS not yet implemented"
443
#endif
444
262k
            {
445
262k
                lzo_uint m_len;
446
447
            /* 2b) code a short match */
448
262k
                    assert(pd(ip,m_pos) == m_off);
449
262k
                --ip;   /* ran one too far, point back to non-match */
450
262k
                m_len = pd(ip, ii);
451
262k
                    assert(m_len >= MIN_MATCH_SHORT);
452
262k
                    assert(m_len <= MAX_MATCH_SHORT);
453
262k
                    assert(m_off > 0);
454
262k
                    assert(m_off <= MAX_OFFSET);
455
262k
                    assert(ii-m_off == m_pos_sav);
456
262k
                    assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0);
457
262k
                --m_off;
458
                /* code short match len + low offset bits */
459
262k
                *op++ = LZO_BYTE(((m_len - THRESHOLD) << OBITS) |
460
262k
                                 (m_off & OMASK));
461
                /* code high offset bits */
462
262k
                *op++ = LZO_BYTE(m_off >> OBITS);
463
464
465
            /* 2c) Insert phrases (beginning with ii+1) into the dictionary. */
466
467
262k
#define SI      /* nothing */
468
262k
#define DI      ++ii; DVAL_NEXT(dv,ii); UPDATE_D(dict,0,dv,ii,in);
469
387k
#define XI      assert(ii < ip); ii = ip; DVAL_FIRST(dv,(ip));
470
471
#if (CLEVEL == 9) || (CLEVEL >= 7 && MBITS <= 4) || (CLEVEL >= 5 && MBITS <= 3)
472
            /* Insert the whole match (ii+1)..(ip-1) into dictionary.  */
473
                ++ii;
474
                do {
475
                    DVAL_NEXT(dv,ii);
476
                    UPDATE_D(dict,0,dv,ii,in);
477
                } while (++ii < ip);
478
                DVAL_NEXT(dv,ii);
479
                assert(ii == ip);
480
                DVAL_ASSERT(dv,ip);
481
#elif (CLEVEL >= 3)
482
                SI   DI DI   XI
483
#elif (CLEVEL >= 2)
484
                SI   DI      XI
485
#else
486
262k
                             XI
487
262k
#endif
488
489
262k
            }
490
125k
            else
491
125k
            {
492
            /* we've found a long match - see how far we can still go */
493
125k
                const lzo_bytep end;
494
125k
                lzo_uint m_len;
495
496
125k
                assert(ip <= in_end);
497
125k
                assert(ii == ip - MIN_MATCH_LONG);
498
499
125k
                if (pd(in_end,ip) <= (MAX_MATCH_LONG - MIN_MATCH_LONG))
500
345
                    end = in_end;
501
125k
                else
502
125k
                {
503
125k
                    end = ip + (MAX_MATCH_LONG - MIN_MATCH_LONG);
504
125k
                    assert(end < in_end);
505
125k
                }
506
507
15.9M
                while (ip < end && *m_pos == *ip)
508
15.8M
                    { m_pos++; ip++; }
509
125k
                assert(ip <= in_end);
510
511
            /* 2b) code the long match */
512
125k
                m_len = pd(ip, ii);
513
125k
                    assert(m_len >= MIN_MATCH_LONG);
514
125k
                    assert(m_len <= MAX_MATCH_LONG);
515
125k
                    assert(m_off > 0);
516
125k
                    assert(m_off <= MAX_OFFSET);
517
125k
                    assert(ii-m_off == m_pos_sav);
518
125k
                    assert(lzo_memcmp(m_pos_sav,ii,m_len) == 0);
519
125k
                    assert(pd(ip,m_pos) == m_off);
520
125k
                --m_off;
521
                /* code long match flag + low offset bits */
522
125k
                *op++ = LZO_BYTE(((MSIZE - 1) << OBITS) | (m_off & OMASK));
523
                /* code high offset bits */
524
125k
                *op++ = LZO_BYTE(m_off >> OBITS);
525
                /* code match len */
526
125k
                *op++ = LZO_BYTE(m_len - MIN_MATCH_LONG);
527
528
529
            /* 2c) Insert phrases (beginning with ii+1) into the dictionary. */
530
#if (CLEVEL == 9)
531
            /* Insert the whole match (ii+1)..(ip-1) into dictionary.  */
532
            /* This is not recommended because it is slow. */
533
                ++ii;
534
                do {
535
                    DVAL_NEXT(dv,ii);
536
                    UPDATE_D(dict,0,dv,ii,in);
537
                } while (++ii < ip);
538
                DVAL_NEXT(dv,ii);
539
                assert(ii == ip);
540
                DVAL_ASSERT(dv,ip);
541
#elif (CLEVEL >= 8)
542
                SI   DI DI DI DI DI DI DI DI   XI
543
#elif (CLEVEL >= 7)
544
                SI   DI DI DI DI DI DI DI      XI
545
#elif (CLEVEL >= 6)
546
                SI   DI DI DI DI DI DI         XI
547
#elif (CLEVEL >= 5)
548
                SI   DI DI DI DI               XI
549
#elif (CLEVEL >= 4)
550
                SI   DI DI DI                  XI
551
#elif (CLEVEL >= 3)
552
                SI   DI DI                     XI
553
#elif (CLEVEL >= 2)
554
                SI   DI                        XI
555
#else
556
125k
                                               XI
557
125k
#endif
558
125k
            }
559
560
            /* ii now points to the start of next literal run */
561
387k
            assert(ii == ip);
562
387k
        }
563
14.3M
    } while (ip < ip_end);
564
565
566
567
437
the_end:
568
437
    assert(ip <= in_end);
569
570
571
#if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE)
572
    /* return -1 if op == out to indicate that we
573
     * couldn't compress and didn't copy anything.
574
     */
575
    if (op == out)
576
    {
577
        *out_len = 0;
578
        return LZO_E_NOT_COMPRESSIBLE;
579
    }
580
#endif
581
582
583
    /* store the final literal run */
584
437
    if (pd(in_end+DVAL_LEN,ii) > 0)
585
437
        op = store_run(op,ii,pd(in_end+DVAL_LEN,ii));
586
587
437
    *out_len = pd(op, out);
588
437
    return 0;               /* compression went ok */
589
437
}
590
591
592
/***********************************************************************
593
// compress public entry point.
594
************************************************************************/
595
596
LZO_PUBLIC(int)
597
lzo1_compress ( const lzo_bytep in , lzo_uint  in_len,
598
                      lzo_bytep out, lzo_uintp out_len,
599
                      lzo_voidp wrkmem )
600
447
{
601
447
    int r = LZO_E_OK;
602
603
    /* don't try to compress a block that's too short */
604
447
    if (in_len == 0)
605
1
        *out_len = 0;
606
446
    else if (in_len <= MIN_MATCH_LONG + DVAL_LEN + 1)
607
9
    {
608
#if defined(LZO_RETURN_IF_NOT_COMPRESSIBLE)
609
        r = LZO_E_NOT_COMPRESSIBLE;
610
#else
611
9
        *out_len = pd(store_run(out,in,in_len), out);
612
9
#endif
613
9
    }
614
437
    else
615
437
        r = do_compress(in,in_len,out,out_len,wrkmem);
616
617
447
    return r;
618
447
}
619
620
621
/* vim:set ts=4 sw=4 et: */