Coverage Report

Created: 2025-06-13 07:22

/src/libfmapi/libfmapi/libfmapi_lzfu.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * LZFu (de)compression functions
3
 *
4
 * Copyright (C) 2009-2024, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program 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 Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libfmapi_checksum.h"
28
#include "libfmapi_libcerror.h"
29
#include "libfmapi_libcnotify.h"
30
#include "libfmapi_lzfu.h"
31
32
347
#define LIBFMAPI_LZFU_SIGNATURE_COMPRESSED        0x75465a4c
33
129
#define LIBFMAPI_LZFU_SIGNATURE_UNCOMPRESSED      0x414c454d
34
35
const char *libfmapi_lzfu_rtf_dictionary = \
36
  "{\\rtf1\\ansi\\mac\\deff0\\deftab720"
37
  "{\\fonttbl;}"
38
  "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier"
39
  "{\\colortbl\\red0\\green0\\blue0\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx";
40
41
/* Determines the uncompressed data size from the LZFu header in the compressed data
42
 * Returns 1 on success or -1 on error
43
 */
44
int libfmapi_lzfu_get_uncompressed_data_size(
45
     const uint8_t *compressed_data,
46
     size_t compressed_data_size,
47
     size_t *uncompressed_data_size,
48
     libcerror_error_t **error )
49
0
{
50
0
  libfmapi_lzfu_header_t lzfu_header;
51
52
0
  static char *function              = "libfmapi_lzfu_get_uncompressed_data_size";
53
0
  size_t compressed_data_offset      = 0;
54
55
#if defined( HAVE_DEBUG_OUTPUT )
56
  uint8_t lz_buffer[ 4096 ];
57
58
  const uint8_t *lzfu_reference_data = NULL;
59
  size_t uncompressed_data_offset    = 0;
60
  uint16_t lz_buffer_iterator        = 0;
61
  uint16_t reference_iterator        = 0;
62
  uint16_t reference_offset          = 0;
63
  uint16_t reference_size            = 0;
64
  uint8_t flag_byte                  = 0;
65
  uint8_t flag_byte_bit_mask         = 0;
66
#endif
67
68
0
  if( compressed_data == NULL )
69
0
  {
70
0
    libcerror_error_set(
71
0
     error,
72
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
73
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
74
0
     "%s: invalid compressed data.",
75
0
     function );
76
77
0
    return( -1 );
78
0
  }
79
0
  if( ( compressed_data_size < sizeof( libfmapi_lzfu_header_t ) )
80
0
   || ( compressed_data_size > (size_t) SSIZE_MAX ) )
81
0
  {
82
0
    libcerror_error_set(
83
0
     error,
84
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
85
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
86
0
     "%s: invalid compressed data size value out of bounds.",
87
0
     function );
88
89
0
    return( -1 );
90
0
  }
91
0
  if( uncompressed_data_size == NULL )
92
0
  {
93
0
    libcerror_error_set(
94
0
     error,
95
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
96
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
97
0
     "%s: invalid uncompressed data size.",
98
0
     function );
99
100
0
    return( -1 );
101
0
  }
102
0
  byte_stream_copy_to_uint32_little_endian(
103
0
   &( compressed_data[ compressed_data_offset ] ),
104
0
   lzfu_header.compressed_data_size );
105
106
0
  compressed_data_offset += 4;
107
108
0
  byte_stream_copy_to_uint32_little_endian(
109
0
   &( compressed_data[ compressed_data_offset ] ),
110
0
   lzfu_header.uncompressed_data_size );
111
112
0
  compressed_data_offset += 4;
113
114
0
  byte_stream_copy_to_uint32_little_endian(
115
0
   &( compressed_data[ compressed_data_offset ] ),
116
0
   lzfu_header.signature );
117
118
0
  compressed_data_offset += 8;
119
120
0
  if( ( lzfu_header.signature != LIBFMAPI_LZFU_SIGNATURE_COMPRESSED )
121
0
   && ( lzfu_header.signature != LIBFMAPI_LZFU_SIGNATURE_UNCOMPRESSED ) )
122
0
  {
123
0
    libcerror_error_set(
124
0
     error,
125
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
126
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
127
0
     "%s: unsupported compression signature: 0x%08" PRIx32 ".",
128
0
     function,
129
0
     lzfu_header.signature );
130
131
0
    return( -1 );
132
0
  }
133
  /* The compressed data size includes 12 bytes of the header
134
   */
135
0
  if( ( lzfu_header.compressed_data_size < 12 )
136
0
   || ( (size_t) ( lzfu_header.compressed_data_size - 12 ) != ( compressed_data_size - sizeof( libfmapi_lzfu_header_t ) ) ) )
137
0
  {
138
0
    libcerror_error_set(
139
0
     error,
140
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
141
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
142
0
     "%s: mismatch in compressed data size (%" PRIu32 " != %" PRIzd ").",
143
0
     function,
144
0
     lzfu_header.compressed_data_size,
145
0
     compressed_data_size );
146
147
0
    return( -1 );
148
0
  }
149
0
  lzfu_header.compressed_data_size -= 12;
150
151
#if defined( HAVE_DEBUG_OUTPUT )
152
  if( libcnotify_verbose != 0 )
153
  {
154
    if( memory_copy(
155
         lz_buffer,
156
         libfmapi_lzfu_rtf_dictionary,
157
         207 ) == NULL )
158
    {
159
      libcerror_error_set(
160
       error,
161
       LIBCERROR_ERROR_DOMAIN_MEMORY,
162
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
163
       "%s: unable to initialize lz buffer.",
164
       function );
165
166
      return( -1 );
167
    }
168
    lz_buffer_iterator = 207;
169
170
    if( memory_set(
171
         &( lz_buffer[ lz_buffer_iterator ] ),
172
         0,
173
         4096 - lz_buffer_iterator ) == NULL )
174
    {
175
      libcerror_error_set(
176
       error,
177
       LIBCERROR_ERROR_DOMAIN_MEMORY,
178
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
179
       "%s: unable to clear lz buffer.",
180
       function );
181
182
      return( -1 );
183
    }
184
    while( compressed_data_offset < compressed_data_size )
185
    {
186
      flag_byte = compressed_data[ compressed_data_offset++ ];
187
188
      /* Check every bit in the chunk flag byte from LSB to MSB
189
       */
190
      for( flag_byte_bit_mask = 0x01;
191
           flag_byte_bit_mask != 0x00;
192
           flag_byte_bit_mask <<= 1 )
193
      {
194
        if( compressed_data_offset == compressed_data_size )
195
        {
196
          break;
197
        }
198
        /* Check if the byte value is a literal or a reference
199
         */
200
        if( ( flag_byte & flag_byte_bit_mask ) == 0 )
201
        {
202
          lz_buffer[ lz_buffer_iterator++ ] = compressed_data[ compressed_data_offset ];
203
204
          compressed_data_offset++;
205
          uncompressed_data_offset++;
206
207
          /* Make sure the lz buffer iterator wraps around
208
           */
209
          lz_buffer_iterator %= 4096;
210
211
          lz_buffer[ lz_buffer_iterator ] = 0;
212
        }
213
        else
214
        {
215
          lzfu_reference_data = &( compressed_data[ compressed_data_offset ] );
216
217
          compressed_data_offset += 2;
218
219
          byte_stream_copy_to_uint16_big_endian(
220
           lzfu_reference_data,
221
           reference_offset );
222
223
          reference_size     = ( reference_offset & 0x000f ) + 2;
224
          reference_offset >>= 4;
225
226
          for( reference_iterator = 0; reference_iterator < reference_size; reference_iterator++ )
227
          {
228
            lz_buffer[ lz_buffer_iterator++ ] = lz_buffer[ reference_offset ];
229
230
            uncompressed_data_offset++;
231
            reference_offset++;
232
233
            /* Make sure the lz buffer iterator and reference offset wrap around
234
             */
235
            lz_buffer_iterator %= 4096;
236
            reference_offset   %= 4096;
237
238
            lz_buffer[ lz_buffer_iterator ] = 0;
239
          }
240
        }
241
      }
242
    }
243
    if( (size_t) ( lzfu_header.uncompressed_data_size + 2 ) != uncompressed_data_offset )
244
    {
245
      libcnotify_printf(
246
       "%s: mismatch in uncompressed data size (in header: %" PRIu32 " != required: %" PRIzd ").\n",
247
       function,
248
       lzfu_header.uncompressed_data_size + 2,
249
       uncompressed_data_offset );
250
    }
251
  }
252
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
253
254
  /* Compensate for the 2 trailing zero bytes
255
   */
256
0
  *uncompressed_data_size = lzfu_header.uncompressed_data_size + 2;
257
258
0
  return( 1 );
259
0
}
260
261
/* Decompresses data using LZFu compression
262
 * Returns 1 on success or -1 on error
263
 */
264
int libfmapi_lzfu_decompress(
265
     const uint8_t *compressed_data,
266
     size_t compressed_data_size,
267
     uint8_t *uncompressed_data,
268
     size_t *uncompressed_data_size,
269
     libcerror_error_t **error )
270
353
{
271
353
  libfmapi_lzfu_header_t lzfu_header;
272
273
353
  uint8_t lz_buffer[ 4096 ];
274
275
353
  const uint8_t *lzfu_reference_data = NULL;
276
353
  static char *function              = "libfmapi_lzfu_decompress";
277
353
  size_t compressed_data_offset      = 0;
278
353
  size_t safe_uncompressed_data_size = 0;
279
353
  size_t uncompressed_data_offset    = 0;
280
353
  uint32_t calculated_checksum       = 0;
281
353
  uint16_t lz_buffer_iterator        = 0;
282
353
  uint16_t reference_iterator        = 0;
283
353
  uint16_t reference_offset          = 0;
284
353
  uint16_t reference_size            = 0;
285
353
  uint8_t flag_byte                  = 0;
286
353
  uint8_t flag_byte_bit_mask         = 0;
287
288
353
  if( compressed_data == NULL )
289
0
  {
290
0
    libcerror_error_set(
291
0
     error,
292
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
293
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
294
0
     "%s: invalid compressed data.",
295
0
     function );
296
297
0
    return( -1 );
298
0
  }
299
353
  if( ( compressed_data_size < sizeof( libfmapi_lzfu_header_t ) )
300
353
   || ( compressed_data_size > (size_t) SSIZE_MAX ) )
301
6
  {
302
6
    libcerror_error_set(
303
6
     error,
304
6
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
305
6
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
306
6
     "%s: invalid compressed data size value out of bounds.",
307
6
     function );
308
309
6
    return( -1 );
310
6
  }
311
347
  if( uncompressed_data == NULL )
312
0
  {
313
0
    libcerror_error_set(
314
0
     error,
315
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
316
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
317
0
     "%s: invalid uncompressed data.",
318
0
     function );
319
320
0
    return( -1 );
321
0
  }
322
347
  if( uncompressed_data_size == NULL )
323
0
  {
324
0
    libcerror_error_set(
325
0
     error,
326
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
327
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
328
0
     "%s: invalid uncompressed data size.",
329
0
     function );
330
331
0
    return( -1 );
332
0
  }
333
347
  safe_uncompressed_data_size = *uncompressed_data_size;
334
335
#if defined( HAVE_DEBUG_OUTPUT )
336
  if( libcnotify_verbose != 0 )
337
  {
338
    libcnotify_printf(
339
     "%s: LZFu compressed data:\n",
340
     function );
341
    libcnotify_print_data(
342
     compressed_data,
343
     compressed_data_size,
344
     0 );
345
  }
346
#endif
347
347
  if( memory_copy(
348
347
       lz_buffer,
349
347
       libfmapi_lzfu_rtf_dictionary,
350
347
       207 ) == NULL )
351
0
  {
352
0
    libcerror_error_set(
353
0
     error,
354
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
355
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
356
0
     "%s: unable to initialize lz buffer.",
357
0
     function );
358
359
0
    return( -1 );
360
0
  }
361
347
  lz_buffer_iterator = 207;
362
363
347
  if( memory_set(
364
347
       &( lz_buffer[ lz_buffer_iterator ] ),
365
347
       0,
366
347
       4096 - lz_buffer_iterator ) == NULL )
367
0
  {
368
0
    libcerror_error_set(
369
0
     error,
370
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
371
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
372
0
     "%s: unable to clear lz buffer.",
373
0
     function );
374
375
0
    return( -1 );
376
0
  }
377
347
  byte_stream_copy_to_uint32_little_endian(
378
347
   &( compressed_data[ compressed_data_offset ] ),
379
347
   lzfu_header.compressed_data_size );
380
381
347
  compressed_data_offset += 4;
382
383
347
  byte_stream_copy_to_uint32_little_endian(
384
347
   &( compressed_data[ compressed_data_offset ] ),
385
347
   lzfu_header.uncompressed_data_size );
386
387
347
  compressed_data_offset += 4;
388
389
347
  byte_stream_copy_to_uint32_little_endian(
390
347
   &( compressed_data[ compressed_data_offset ] ),
391
347
   lzfu_header.signature );
392
393
347
  compressed_data_offset += 4;
394
395
347
  byte_stream_copy_to_uint32_little_endian(
396
347
   &( compressed_data[ compressed_data_offset ] ),
397
347
   lzfu_header.checksum );
398
399
347
  compressed_data_offset += 4;
400
401
#if defined( HAVE_DEBUG_OUTPUT )
402
  if( libcnotify_verbose != 0 )
403
  {
404
    libcnotify_printf(
405
     "%s: lzfu header compressed data size\t\t: %" PRIu32 "\n",
406
     function,
407
     lzfu_header.compressed_data_size );
408
409
    libcnotify_printf(
410
     "%s: lzfu header uncompressed data size\t\t: %" PRIu32 "\n",
411
     function,
412
     lzfu_header.uncompressed_data_size );
413
414
    libcnotify_printf(
415
     "%s: lzfu header signature\t\t\t\t: 0x08%" PRIx32 "\n",
416
     function,
417
     lzfu_header.signature );
418
419
    libcnotify_printf(
420
     "%s: lzfu header checksum\t\t\t\t: %" PRIu32 "\n",
421
     function,
422
     lzfu_header.checksum );
423
  }
424
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
425
426
347
  if( ( lzfu_header.signature != LIBFMAPI_LZFU_SIGNATURE_COMPRESSED )
427
347
   && ( lzfu_header.signature != LIBFMAPI_LZFU_SIGNATURE_UNCOMPRESSED ) )
428
84
  {
429
84
    libcerror_error_set(
430
84
     error,
431
84
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
432
84
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
433
84
     "%s: unsupported compression signature: 0x%08" PRIx32 ".",
434
84
     function,
435
84
     lzfu_header.signature );
436
437
84
    return( -1 );
438
84
  }
439
  /* The compressed data size includes 12 bytes of the header
440
   */
441
263
  if( ( lzfu_header.compressed_data_size < 12 )
442
263
   || ( (size_t) ( lzfu_header.compressed_data_size - 12 ) != ( compressed_data_size - sizeof( libfmapi_lzfu_header_t ) ) ) )
443
73
  {
444
73
    libcerror_error_set(
445
73
     error,
446
73
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
447
73
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
448
73
     "%s: mismatch in compressed data size (%" PRIu32 " != %" PRIzd ").",
449
73
     function,
450
73
     lzfu_header.compressed_data_size,
451
73
     compressed_data_size );
452
453
73
    return( -1 );
454
73
  }
455
190
  lzfu_header.compressed_data_size -= 12;
456
457
  /* Make sure the uncompressed buffer is large enough
458
   */
459
190
  if( safe_uncompressed_data_size < lzfu_header.uncompressed_data_size )
460
15
  {
461
15
    libcerror_error_set(
462
15
     error,
463
15
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
464
15
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
465
15
     "%s: uncompressed data too small.",
466
15
     function );
467
468
15
    *uncompressed_data_size = lzfu_header.uncompressed_data_size;
469
470
15
    return( -1 );
471
15
  }
472
175
  if( libfmapi_checksum_calculate_weak_crc32(
473
175
       &calculated_checksum,
474
175
       &( compressed_data[ compressed_data_offset ] ),
475
175
       (size_t) lzfu_header.compressed_data_size,
476
175
       0,
477
175
       error ) != 1 )
478
0
  {
479
0
    libcerror_error_set(
480
0
     error,
481
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
482
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
483
0
     "%s: unable to calculate weak CRC-32.",
484
0
     function );
485
486
0
    return( -1 );
487
0
  }
488
175
  if( lzfu_header.checksum != calculated_checksum )
489
55
  {
490
55
    libcerror_error_set(
491
55
     error,
492
55
     LIBCERROR_ERROR_DOMAIN_INPUT,
493
55
     LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
494
55
     "%s: mismatch in checksum ( %" PRIu32 " != %" PRIu32 " ).",
495
55
     function,
496
55
     lzfu_header.checksum,
497
55
     calculated_checksum );
498
499
55
    return( -1 );
500
55
  }
501
73.3k
  while( compressed_data_offset < compressed_data_size )
502
73.2k
  {
503
73.2k
    flag_byte = compressed_data[ compressed_data_offset++ ];
504
505
    /* Check every bit in the chunk flag byte from LSB to MSB
506
     */
507
73.2k
    for( flag_byte_bit_mask = 0x01;
508
658k
         flag_byte_bit_mask != 0x00;
509
585k
         flag_byte_bit_mask <<= 1 )
510
585k
    {
511
585k
      if( compressed_data_offset == compressed_data_size )
512
67
      {
513
67
        break;
514
67
      }
515
      /* Check if the byte value is a literal or a reference
516
       */
517
585k
      if( ( flag_byte & flag_byte_bit_mask ) == 0 )
518
407k
      {
519
407k
        if( compressed_data_offset >= compressed_data_size )
520
0
        {
521
0
          libcerror_error_set(
522
0
           error,
523
0
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
524
0
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
525
0
           "%s: missing compressed data.",
526
0
           function );
527
528
0
          *uncompressed_data_size = 0;
529
530
0
          return( -1 );
531
0
        }
532
407k
        if( uncompressed_data_offset >= safe_uncompressed_data_size )
533
4
        {
534
4
          libcerror_error_set(
535
4
           error,
536
4
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
537
4
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
538
4
           "%s: uncompressed data too small.",
539
4
           function );
540
541
4
          *uncompressed_data_size = uncompressed_data_offset;
542
543
4
          return( -1 );
544
4
        }
545
407k
        lz_buffer[ lz_buffer_iterator++ ]               = compressed_data[ compressed_data_offset ];
546
407k
        uncompressed_data[ uncompressed_data_offset++ ] = compressed_data[ compressed_data_offset ];
547
548
407k
        compressed_data_offset++;
549
550
        /* Make sure the lz buffer iterator wraps around
551
         */
552
407k
        lz_buffer_iterator %= 4096;
553
554
407k
        lz_buffer[ lz_buffer_iterator ] = 0;
555
407k
      }
556
178k
      else
557
178k
      {
558
178k
        if( compressed_data_offset > ( compressed_data_size - 2 ) )
559
18
        {
560
18
          libcerror_error_set(
561
18
           error,
562
18
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
563
18
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
564
18
           "%s: missing compressed data.",
565
18
           function );
566
567
18
          *uncompressed_data_size = 0;
568
569
18
          return( -1 );
570
18
        }
571
178k
        lzfu_reference_data = &( compressed_data[ compressed_data_offset ] );
572
573
178k
        compressed_data_offset += 2;
574
575
178k
        byte_stream_copy_to_uint16_big_endian(
576
178k
         lzfu_reference_data,
577
178k
         reference_offset );
578
579
178k
        reference_size     = ( reference_offset & 0x000f ) + 2;
580
178k
        reference_offset >>= 4;
581
582
178k
        if( ( uncompressed_data_offset + reference_size - 1 ) >= safe_uncompressed_data_size )
583
17
        {
584
17
          libcerror_error_set(
585
17
           error,
586
17
           LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
587
17
           LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
588
17
           "%s: uncompressed data too small.",
589
17
           function );
590
591
17
          *uncompressed_data_size = uncompressed_data_offset + reference_size;
592
593
17
          return( -1 );
594
17
        }
595
1.55M
        for( reference_iterator = 0; reference_iterator < reference_size; reference_iterator++ )
596
1.37M
        {
597
1.37M
          lz_buffer[ lz_buffer_iterator++ ]               = lz_buffer[ reference_offset ];
598
1.37M
          uncompressed_data[ uncompressed_data_offset++ ] = lz_buffer[ reference_offset ];
599
600
1.37M
          reference_offset++;
601
602
          /* Make sure the lz buffer iterator and reference offset wrap around
603
           */
604
1.37M
          lz_buffer_iterator %= 4096;
605
1.37M
          reference_offset   %= 4096;
606
607
1.37M
          lz_buffer[ lz_buffer_iterator ] = 0;
608
1.37M
        }
609
178k
      }
610
585k
    }
611
73.2k
  }
612
81
  *uncompressed_data_size = uncompressed_data_offset;
613
614
81
  return( 1 );
615
120
}
616