VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/zip/zip.cpp

Last change on this file was 103013, checked in by vboxsync, 4 months ago

iprt/asm-mem.h,zip.cpp,tstRTInlineAsm.cpp: Eliminated unused ASMMemIsZeroPage function.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 57.5 KB
Line 
1/* $Id: zip.cpp 103013 2024-01-24 00:50:12Z vboxsync $ */
2/** @file
3 * IPRT - Compression.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41#define RTZIP_USE_STORE 1
42#define RTZIP_USE_ZLIB 1
43//#define RTZIP_USE_BZLIB 1
44#if !defined(IN_GUEST) && !defined(IPRT_NO_CRT)
45# define RTZIP_USE_LZF 1
46#endif
47#define RTZIP_LZF_BLOCK_BY_BLOCK
48//#define RTZIP_USE_LZJB 1
49//#define RTZIP_USE_LZO 1
50
51/** @todo FastLZ? QuickLZ? Others? */
52
53
54/*********************************************************************************************************************************
55* Header Files *
56*********************************************************************************************************************************/
57#include <iprt/cdefs.h>
58#ifdef RTZIP_USE_BZLIB
59# include <bzlib.h>
60#endif
61#ifdef RTZIP_USE_ZLIB
62# include <zlib.h>
63#endif
64#ifdef RTZIP_USE_LZF
65 RT_C_DECLS_BEGIN
66# include <lzf.h>
67 RT_C_DECLS_END
68# include <iprt/crc.h>
69#endif
70#ifdef RTZIP_USE_LZJB
71# include "lzjb.h"
72#endif
73#ifdef RTZIP_USE_LZO
74# include <lzo/lzo1x.h>
75#endif
76
77#include <iprt/zip.h>
78#include "internal/iprt.h"
79
80/*#include <iprt/asm.h>*/
81#include <iprt/alloc.h>
82#include <iprt/assert.h>
83#include <iprt/err.h>
84#include <iprt/log.h>
85#include <iprt/string.h>
86
87#ifndef IPRT_NO_CRT
88# include <errno.h>
89#endif
90
91
92/*********************************************************************************************************************************
93* Structures and Typedefs *
94*********************************************************************************************************************************/
95
96#ifdef RTZIP_USE_LZF
97
98/**
99 * LZF block header.
100 */
101#pragma pack(1) /* paranoia */
102typedef struct RTZIPLZFHDR
103{
104 /** Magic word (RTZIPLZFHDR_MAGIC). */
105 uint16_t u16Magic;
106 /** The number of bytes of data following this header. */
107 uint16_t cbData;
108 /** The CRC32 of the block. */
109 uint32_t u32CRC;
110 /** The size of the uncompressed data in bytes. */
111 uint16_t cbUncompressed;
112} RTZIPLZFHDR;
113#pragma pack()
114/** Pointer to a LZF block header. */
115typedef RTZIPLZFHDR *PRTZIPLZFHDR;
116/** Pointer to a const LZF block header. */
117typedef const RTZIPLZFHDR *PCRTZIPLZFHDR;
118
119/** The magic of a LZF block header. */
120#define RTZIPLZFHDR_MAGIC ('Z' | ('V' << 8))
121
122/** The max compressed data size.
123 * The maximum size of a block is currently 16KB.
124 * This is very important so we don't have to move input buffers around. */
125#define RTZIPLZF_MAX_DATA_SIZE (16384 - sizeof(RTZIPLZFHDR))
126
127/** The max uncompressed data size.
128 * This is important so we don't overflow the spill buffer in the decompressor. */
129#define RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE (32*_1K)
130
131#endif /* RTZIP_USE_LZF */
132
133
134/**
135 * Compressor/Decompressor instance data.
136 */
137typedef struct RTZIPCOMP
138{
139 /** Output buffer. */
140 uint8_t abBuffer[_128K];
141 /** Compression output consumer. */
142 PFNRTZIPOUT pfnOut;
143 /** User argument for the callback. */
144 void *pvUser;
145
146 /**
147 * @copydoc RTZipCompress
148 */
149 DECLCALLBACKMEMBER(int, pfnCompress,(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf));
150
151 /**
152 * @copydoc RTZipCompFinish
153 */
154 DECLCALLBACKMEMBER(int, pfnFinish,(PRTZIPCOMP pZip));
155
156 /**
157 * @copydoc RTZipCompDestroy
158 */
159 DECLCALLBACKMEMBER(int, pfnDestroy,(PRTZIPCOMP pZip));
160
161 /** Compression type. */
162 RTZIPTYPE enmType;
163 /** Type specific data. */
164 union
165 {
166#ifdef RTZIP_USE_STORE
167 /** Simple storing. */
168 struct
169 {
170 /** Current buffer position. (where to start write) */
171 uint8_t *pb;
172 } Store;
173#endif
174#ifdef RTZIP_USE_ZLIB
175 /** Zlib stream. */
176 z_stream Zlib;
177#endif
178#ifdef RTZIP_USE_BZLIB
179 /** BZlib stream. */
180 bz_stream BZlib;
181#endif
182#ifdef RTZIP_USE_LZF
183 /** LZF stream. */
184 struct
185 {
186 /** Current output buffer position. */
187 uint8_t *pbOutput;
188 /** The input buffer position. */
189 uint8_t *pbInput;
190 /** The number of free bytes in the input buffer. */
191 size_t cbInputFree;
192 /** The input buffer. */
193 uint8_t abInput[RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE];
194 } LZF;
195#endif
196
197 } u;
198} RTZIPCOMP;
199
200
201
202/**
203 * Decompressor instance data.
204 */
205typedef struct RTZIPDECOMP
206{
207 /** Input buffer. */
208 uint8_t abBuffer[_128K];
209 /** Decompression input producer. */
210 PFNRTZIPIN pfnIn;
211 /** User argument for the callback. */
212 void *pvUser;
213
214 /**
215 * @copydoc RTZipDecompress
216 */
217 DECLCALLBACKMEMBER(int, pfnDecompress,(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten));
218
219 /**
220 * @copydoc RTZipDecompDestroy
221 */
222 DECLCALLBACKMEMBER(int, pfnDestroy,(PRTZIPDECOMP pZip));
223
224 /** Compression type. */
225 RTZIPTYPE enmType;
226 /** Type specific data. */
227 union
228 {
229#ifdef RTZIP_USE_STORE
230 /** Simple storing. */
231 struct
232 {
233 /** Current buffer position. (where to start read) */
234 uint8_t *pb;
235 /** Number of bytes left in the buffer. */
236 size_t cbBuffer;
237 } Store;
238#endif
239#ifdef RTZIP_USE_ZLIB
240 /** Zlib stream. */
241 z_stream Zlib;
242#endif
243#ifdef RTZIP_USE_BZLIB
244 /** BZlib stream. */
245 bz_stream BZlib;
246#endif
247#ifdef RTZIP_USE_LZF
248 /** LZF 'stream'. */
249 struct
250 {
251# ifndef RTZIP_LZF_BLOCK_BY_BLOCK
252 /** Current input buffer position. */
253 uint8_t *pbInput;
254 /** The number of bytes left in the input buffer. */
255 size_t cbInput;
256# endif
257 /** The spill buffer.
258 * LZF is a block based compressor and not a stream compressor. So,
259 * we have to decompress full blocks if we want to get any of the data.
260 * This buffer is to store the spill after decompressing a block. */
261 uint8_t abSpill[RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE];
262 /** The number of bytes left spill buffer. */
263 unsigned cbSpill;
264 /** The current spill buffer position. */
265 uint8_t *pbSpill;
266 } LZF;
267#endif
268
269 } u;
270} RTZIPDECOM;
271
272
273
274#ifdef RTZIP_USE_STORE
275
276/**
277 * @copydoc RTZipCompress
278 */
279static DECLCALLBACK(int) rtZipStoreCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
280{
281 uint8_t *pbDst = pZip->u.Store.pb;
282 while (cbBuf)
283 {
284 /*
285 * Flush.
286 */
287 size_t cb = sizeof(pZip->abBuffer) - (size_t)(pbDst - &pZip->abBuffer[0]); /* careful here, g++ 4.1.2 screws up easily */
288 if (cb == 0)
289 {
290 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer));
291 if (RT_FAILURE(rc))
292 return rc;
293
294 cb = sizeof(pZip->abBuffer);
295 pbDst = &pZip->abBuffer[0];
296 }
297
298 /*
299 * Add to the buffer and advance.
300 */
301 if (cbBuf < cb)
302 cb = cbBuf;
303 memcpy(pbDst, pvBuf, cb);
304
305 pbDst += cb;
306 cbBuf -= cb;
307 pvBuf = (uint8_t *)pvBuf + cb;
308 }
309 pZip->u.Store.pb = pbDst;
310 return VINF_SUCCESS;
311}
312
313
314/**
315 * @copydoc RTZipCompFinish
316 */
317static DECLCALLBACK(int) rtZipStoreCompFinish(PRTZIPCOMP pZip)
318{
319 size_t cb = (uintptr_t)pZip->u.Store.pb - (uintptr_t)&pZip->abBuffer[0];
320 if (cb > 0)
321 {
322 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
323 if (RT_FAILURE(rc))
324 return rc;
325 }
326 return VINF_SUCCESS;
327}
328
329
330/**
331 * @copydoc RTZipCompDestroy
332 */
333static DECLCALLBACK(int) rtZipStoreCompDestroy(PRTZIPCOMP pZip)
334{
335 NOREF(pZip);
336 return VINF_SUCCESS;
337}
338
339
340/**
341 * Initializes the compressor instance.
342 * @returns iprt status code.
343 * @param pZip The compressor instance.
344 * @param enmLevel The desired compression level.
345 */
346static DECLCALLBACK(int) rtZipStoreCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
347{
348 NOREF(enmLevel);
349 pZip->pfnCompress = rtZipStoreCompress;
350 pZip->pfnFinish = rtZipStoreCompFinish;
351 pZip->pfnDestroy = rtZipStoreCompDestroy;
352
353 pZip->u.Store.pb = &pZip->abBuffer[1];
354 return VINF_SUCCESS;
355}
356
357
358/**
359 * @copydoc RTZipDecompress
360 */
361static DECLCALLBACK(int) rtZipStoreDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
362{
363 size_t cbWritten = 0;
364 while (cbBuf)
365 {
366 /*
367 * Fill buffer.
368 */
369 size_t cb = pZip->u.Store.cbBuffer;
370 if (cb <= 0)
371 {
372 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
373 if (RT_FAILURE(rc))
374 return rc;
375 pZip->u.Store.cbBuffer = cb;
376 pZip->u.Store.pb = &pZip->abBuffer[0];
377 }
378
379 /*
380 * No more data?
381 */
382 if (cb == 0)
383 {
384 if (pcbWritten)
385 {
386 *pcbWritten = cbWritten;
387 return VINF_SUCCESS;
388 }
389 return VERR_NO_DATA;
390 }
391
392 /*
393 * Add to the buffer and advance.
394 */
395 if (cbBuf < cb)
396 cb = cbBuf;
397 memcpy(pvBuf, pZip->u.Store.pb, cb);
398 pZip->u.Store.pb += cb;
399 pZip->u.Store.cbBuffer -= cb;
400 cbBuf -= cb;
401 pvBuf = (char *)pvBuf + cb;
402 cbWritten += cb;
403 }
404 if (pcbWritten)
405 *pcbWritten = cbWritten;
406 return VINF_SUCCESS;
407}
408
409
410/**
411 * @copydoc RTZipDecompDestroy
412 */
413static DECLCALLBACK(int) rtZipStoreDecompDestroy(PRTZIPDECOMP pZip)
414{
415 NOREF(pZip);
416 return VINF_SUCCESS;
417}
418
419
420/**
421 * Initialize the decompressor instance.
422 * @returns iprt status code.
423 * @param pZip The decompressor instance.
424 */
425static DECLCALLBACK(int) rtZipStoreDecompInit(PRTZIPDECOMP pZip)
426{
427 pZip->pfnDecompress = rtZipStoreDecompress;
428 pZip->pfnDestroy = rtZipStoreDecompDestroy;
429
430 pZip->u.Store.pb = &pZip->abBuffer[0];
431 pZip->u.Store.cbBuffer = 0;
432 return VINF_SUCCESS;
433}
434
435#endif /* RTZIP_USE_STORE */
436
437
438#ifdef RTZIP_USE_ZLIB
439
440/*
441 * Missing definitions from zutil.h. We need these constants for calling
442 * inflateInit2() / deflateInit2().
443 */
444# ifndef Z_DEF_WBITS
445# define Z_DEF_WBITS MAX_WBITS
446# endif
447# ifndef Z_DEF_MEM_LEVEL
448# define Z_DEF_MEM_LEVEL 8
449# endif
450
451/**
452 * Convert from zlib errno to iprt status code.
453 * @returns iprt status code.
454 * @param rc Zlib error code.
455 * @param fCompressing Set if we're compressing, clear if decompressing.
456 */
457static int zipErrConvertFromZlib(int rc, bool fCompressing)
458{
459 switch (rc)
460 {
461 case Z_OK:
462 return VINF_SUCCESS;
463
464 case Z_STREAM_ERROR:
465 return VERR_ZIP_CORRUPTED;
466
467 case Z_DATA_ERROR:
468 return fCompressing ? VERR_ZIP_ERROR : VERR_ZIP_CORRUPTED;
469
470 case Z_MEM_ERROR:
471 return VERR_ZIP_NO_MEMORY;
472
473 case Z_BUF_ERROR:
474 return VERR_ZIP_ERROR;
475
476 case Z_VERSION_ERROR:
477 return VERR_ZIP_UNSUPPORTED_VERSION;
478
479 case Z_ERRNO: /* We shouldn't see this status! */
480 default:
481 AssertMsgFailed(("%d\n", rc));
482 if (rc >= 0)
483 return VINF_SUCCESS;
484 return VERR_ZIP_ERROR;
485 }
486}
487
488
489/**
490 * @copydoc RTZipCompress
491 */
492static DECLCALLBACK(int) rtZipZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
493{
494 pZip->u.Zlib.next_in = (Bytef *)pvBuf;
495 pZip->u.Zlib.avail_in = (uInt)cbBuf; Assert(pZip->u.Zlib.avail_in == cbBuf);
496 while (pZip->u.Zlib.avail_in > 0)
497 {
498 /*
499 * Flush output buffer?
500 */
501 if (pZip->u.Zlib.avail_out <= 0)
502 {
503 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.Zlib.avail_out);
504 if (RT_FAILURE(rc))
505 return rc;
506 pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer);
507 pZip->u.Zlib.next_out = &pZip->abBuffer[0];
508 }
509
510 /*
511 * Pass it on to zlib.
512 */
513 int rc = deflate(&pZip->u.Zlib, Z_NO_FLUSH);
514 if (rc != Z_OK)
515 return zipErrConvertFromZlib(rc, true /*fCompressing*/);
516 }
517 return VINF_SUCCESS;
518}
519
520
521/**
522 * @copydoc RTZipCompFinish
523 */
524static DECLCALLBACK(int) rtZipZlibCompFinish(PRTZIPCOMP pZip)
525{
526 int rc = Z_OK;
527 for (;;)
528 {
529 /*
530 * Flush outstanding stuff. writes.
531 */
532 if (rc == Z_STREAM_END || pZip->u.Zlib.avail_out <= 0)
533 {
534 int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.Zlib.avail_out);
535 if (RT_FAILURE(rc2))
536 return rc2;
537 pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer);
538 pZip->u.Zlib.next_out = &pZip->abBuffer[0];
539 if (rc == Z_STREAM_END)
540 return VINF_SUCCESS;
541 }
542
543 /*
544 * Tell zlib to flush.
545 */
546 rc = deflate(&pZip->u.Zlib, Z_FINISH);
547 if (rc != Z_OK && rc != Z_STREAM_END)
548 return zipErrConvertFromZlib(rc, true /*fCompressing*/);
549 }
550}
551
552
553/**
554 * @copydoc RTZipCompDestroy
555 */
556static DECLCALLBACK(int) rtZipZlibCompDestroy(PRTZIPCOMP pZip)
557{
558 /*
559 * Terminate the deflate instance.
560 */
561 int rc = deflateEnd(&pZip->u.Zlib);
562 if (rc != Z_OK)
563 rc = zipErrConvertFromZlib(rc, true /*fCompressing*/);
564 return rc;
565}
566
567
568/**
569 * Initializes the compressor instance.
570 * @returns iprt status code.
571 * @param pZip The compressor instance.
572 * @param enmLevel The desired compression level.
573 * @param fZlibHeader If true, write the Zlib header.
574 */
575static DECLCALLBACK(int) rtZipZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel, bool fZlibHeader)
576{
577 pZip->pfnCompress = rtZipZlibCompress;
578 pZip->pfnFinish = rtZipZlibCompFinish;
579 pZip->pfnDestroy = rtZipZlibCompDestroy;
580
581 int iLevel = Z_DEFAULT_COMPRESSION;
582 switch (enmLevel)
583 {
584 case RTZIPLEVEL_STORE: iLevel = 0; break;
585 case RTZIPLEVEL_FAST: iLevel = 2; break;
586 case RTZIPLEVEL_DEFAULT: iLevel = Z_DEFAULT_COMPRESSION; break;
587 case RTZIPLEVEL_MAX: iLevel = 9; break;
588 }
589
590 memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
591 pZip->u.Zlib.next_out = &pZip->abBuffer[1];
592 pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer) - 1;
593 pZip->u.Zlib.opaque = pZip;
594
595 int rc = deflateInit2(&pZip->u.Zlib, iLevel, Z_DEFLATED, fZlibHeader ? Z_DEF_WBITS : -Z_DEF_WBITS,
596 Z_DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
597 return rc >= 0 ? rc = VINF_SUCCESS : zipErrConvertFromZlib(rc, true /*fCompressing*/);
598}
599
600
601/**
602 * @copydoc RTZipDecompress
603 */
604static DECLCALLBACK(int) rtZipZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
605{
606 pZip->u.Zlib.next_out = (Bytef *)pvBuf;
607 pZip->u.Zlib.avail_out = (uInt)cbBuf;
608 Assert(pZip->u.Zlib.avail_out == cbBuf);
609
610 /*
611 * Be greedy reading input, even if no output buffer is left. It's possible
612 * that it's just the end of stream marker which needs to be read. Happens
613 * for incompressible blocks just larger than the input buffer size.
614 */
615 while (pZip->u.Zlib.avail_out > 0 || pZip->u.Zlib.avail_in <= 0)
616 {
617 /*
618 * Read more input?
619 */
620 if (pZip->u.Zlib.avail_in <= 0)
621 {
622 size_t cb = sizeof(pZip->abBuffer);
623 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
624 if (RT_FAILURE(rc))
625 return rc;
626 pZip->u.Zlib.avail_in = (uInt)cb; Assert(pZip->u.Zlib.avail_in == cb);
627 pZip->u.Zlib.next_in = &pZip->abBuffer[0];
628 }
629
630 /*
631 * Pass it on to zlib.
632 */
633 int rc = inflate(&pZip->u.Zlib, Z_NO_FLUSH);
634 if (rc == Z_STREAM_END)
635 {
636 if (pcbWritten)
637 *pcbWritten = cbBuf - pZip->u.Zlib.avail_out;
638 else if (pZip->u.Zlib.avail_out > 0)
639 return VERR_NO_DATA;
640 break;
641 }
642 if (rc != Z_OK)
643 return zipErrConvertFromZlib(rc, false /*fCompressing*/);
644 }
645 return VINF_SUCCESS;
646}
647
648
649/**
650 * @copydoc RTZipDecompDestroy
651 */
652static DECLCALLBACK(int) rtZipZlibDecompDestroy(PRTZIPDECOMP pZip)
653{
654 /*
655 * Terminate the deflate instance.
656 */
657 int rc = inflateEnd(&pZip->u.Zlib);
658 if (rc != Z_OK)
659 rc = zipErrConvertFromZlib(rc, false /*fCompressing*/);
660 return rc;
661}
662
663
664/**
665 * Initialize the decompressor instance.
666 * @returns iprt status code.
667 * @param pZip The decompressor instance.
668 * @param fZlibHeader If true, expect the Zlib header.
669 */
670static DECLCALLBACK(int) rtZipZlibDecompInit(PRTZIPDECOMP pZip, bool fZlibHeader)
671{
672 pZip->pfnDecompress = rtZipZlibDecompress;
673 pZip->pfnDestroy = rtZipZlibDecompDestroy;
674
675 memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
676 pZip->u.Zlib.opaque = pZip;
677
678 int rc = inflateInit2(&pZip->u.Zlib, fZlibHeader ? Z_DEF_WBITS : -Z_DEF_WBITS);
679 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromZlib(rc, false /*fCompressing*/);
680}
681
682#endif /* RTZIP_USE_ZLIB */
683
684
685#ifdef RTZIP_USE_BZLIB
686/**
687 * Convert from BZlib errno to iprt status code.
688 * @returns iprt status code.
689 * @param rc BZlib error code.
690 */
691static int zipErrConvertFromBZlib(int rc)
692{
693 /** @todo proper bzlib error conversion. */
694 switch (rc)
695 {
696 case BZ_SEQUENCE_ERROR:
697 AssertMsgFailed(("BZ_SEQUENCE_ERROR shall not happen!\n"));
698 return VERR_GENERAL_FAILURE;
699 case BZ_PARAM_ERROR:
700 return VERR_INVALID_PARAMETER;
701 case BZ_MEM_ERROR:
702 return VERR_NO_MEMORY;
703 case BZ_DATA_ERROR:
704 case BZ_DATA_ERROR_MAGIC:
705 case BZ_IO_ERROR:
706 case BZ_UNEXPECTED_EOF:
707 case BZ_CONFIG_ERROR:
708 return VERR_GENERAL_FAILURE;
709 case BZ_OUTBUFF_FULL:
710 AssertMsgFailed(("BZ_OUTBUFF_FULL shall not happen!\n"));
711 return VERR_GENERAL_FAILURE;
712 default:
713 if (rc >= 0)
714 return VINF_SUCCESS;
715 return VERR_GENERAL_FAILURE;
716 }
717}
718
719
720/**
721 * @copydoc RTZipCompress
722 */
723static DECLCALLBACK(int) rtZipBZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
724{
725 pZip->u.BZlib.next_in = (char *)pvBuf;
726 pZip->u.BZlib.avail_in = cbBuf;
727 while (pZip->u.BZlib.avail_in > 0)
728 {
729 /*
730 * Flush output buffer?
731 */
732 if (pZip->u.BZlib.avail_out <= 0)
733 {
734 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
735 if (RT_FAILURE(rc))
736 return rc;
737 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
738 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
739 }
740
741 /*
742 * Pass it on to zlib.
743 */
744 int rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_RUN);
745 if (rc < 0 && rc != BZ_OUTBUFF_FULL)
746 return zipErrConvertFromBZlib(rc);
747 }
748 return VINF_SUCCESS;
749}
750
751
752/**
753 * @copydoc RTZipCompFinish
754 */
755static DECLCALLBACK(int) rtZipBZlibCompFinish(PRTZIPCOMP pZip)
756{
757 int rc = BZ_FINISH_OK;
758 for (;;)
759 {
760 /*
761 * Flush output buffer?
762 */
763 if (rc == BZ_STREAM_END || pZip->u.BZlib.avail_out <= 0)
764 {
765 int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
766 if (RT_FAILURE(rc2))
767 return rc2;
768 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
769 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
770 if (rc == BZ_STREAM_END)
771 return VINF_SUCCESS;
772 }
773
774 /*
775 * Tell BZlib to finish it.
776 */
777 rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_FINISH);
778 if (rc < 0 && rc != BZ_OUTBUFF_FULL)
779 return zipErrConvertFromBZlib(rc);
780 }
781 return VINF_SUCCESS;
782}
783
784
785/**
786 * @copydoc RTZipCompDestroy
787 */
788static DECLCALLBACK(int) rtZipBZlibCompDestroy(PRTZIPCOMP pZip)
789{
790 /*
791 * Terminate the deflate instance.
792 */
793 int rc = BZ2_bzCompressEnd(&pZip->u.BZlib);
794 if (rc != BZ_OK)
795 rc = zipErrConvertFromBZlib(rc);
796 return rc;
797}
798
799
800/**
801 * Initializes the compressor instance.
802 * @returns iprt status code.
803 * @param pZip The compressor instance.
804 * @param enmLevel The desired compression level.
805 */
806static DECLCALLBACK(int) rtZipBZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
807{
808 pZip->pfnCompress = rtZipBZlibCompress;
809 pZip->pfnFinish = rtZipBZlibCompFinish;
810 pZip->pfnDestroy = rtZipBZlibCompDestroy;
811
812 int iSize = 6;
813 int iWork = 0;
814 switch (enmLevel)
815 {
816 case RTZIPLEVEL_STORE: iSize = 1; iWork = 2; break;
817 case RTZIPLEVEL_FAST: iSize = 2; iWork = 0; break;
818 case RTZIPLEVEL_DEFAULT: iSize = 5; iWork = 0; break;
819 case RTZIPLEVEL_MAX: iSize = 9; iWork = 0; break;
820 }
821
822 memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
823 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[1];
824 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer) - 1;
825 pZip->u.BZlib.opaque = pZip;
826
827 int rc = BZ2_bzCompressInit(&pZip->u.BZlib, iSize, 0, iWork);
828 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);;
829}
830
831
832/**
833 * @copydoc RTZipDecompress
834 */
835static DECLCALLBACK(int) rtZipBZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
836{
837 pZip->u.BZlib.next_out = (char *)pvBuf;
838 pZip->u.BZlib.avail_out = cbBuf;
839 while (pZip->u.BZlib.avail_out > 0)
840 {
841 /*
842 * Read more output buffer?
843 */
844 if (pZip->u.BZlib.avail_in <= 0)
845 {
846 size_t cb;
847 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
848 if (RT_FAILURE(rc))
849 return rc;
850 pZip->u.BZlib.avail_in = cb;
851 pZip->u.BZlib.next_in = (char *)&pZip->abBuffer[0];
852 }
853
854 /*
855 * Pass it on to zlib.
856 */
857 int rc = BZ2_bzDecompress(&pZip->u.BZlib);
858 if (rc == BZ_STREAM_END || rc == BZ_OUTBUFF_FULL)
859 {
860 if (pcbWritten)
861 *pcbWritten = cbBuf - pZip->u.BZlib.avail_out;
862 else if (pZip->u.BZlib.avail_out > 0)
863 return VERR_NO_DATA;
864 break;
865 }
866 if (rc < 0)
867 return zipErrConvertFromBZlib(rc);
868 }
869 return VINF_SUCCESS;
870}
871
872
873/**
874 * @copydoc RTZipDecompDestroy
875 */
876static DECLCALLBACK(int) rtZipBZlibDecompDestroy(PRTZIPDECOMP pZip)
877{
878 /*
879 * Terminate the deflate instance.
880 */
881 int rc = BZ2_bzDecompressEnd(&pZip->u.BZlib);
882 if (rc != BZ_OK)
883 rc = zipErrConvertFromBZlib(rc);
884 return rc;
885}
886
887
888/**
889 * Initialize the decompressor instance.
890 * @returns iprt status code.
891 * @param pZip The decompressor instance.
892 */
893static DECLCALLBACK(int) rtZipBZlibDecompInit(PRTZIPDECOMP pZip)
894{
895 pZip->pfnDecompress = rtZipBZlibDecompress;
896 pZip->pfnDestroy = rtZipBZlibDecompDestroy;
897
898 memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
899 pZip->u.BZlib.opaque = pZip;
900
901 int rc = BZ2_bzDecompressInit(&pZip->u.BZlib, 0, 0);
902 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);
903}
904
905#endif /* RTZIP_USE_BZLIB */
906
907
908#ifdef RTZIP_USE_LZF
909
910/**
911 * Flushes the output buffer.
912 * @returns iprt status code.
913 * @param pZip The compressor instance.
914 */
915static int rtZipLZFCompFlushOutput(PRTZIPCOMP pZip)
916{
917 size_t cb = pZip->u.LZF.pbOutput - &pZip->abBuffer[0];
918 pZip->u.LZF.pbOutput = &pZip->abBuffer[0];
919 return pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
920}
921
922
923/**
924 * Compresses a buffer using LZF.
925 *
926 * @returns VBox status code.
927 * @param pZip The compressor instance.
928 * @param pbBuf What to compress.
929 * @param cbBuf How much to compress.
930 */
931static int rtZipLZFCompressBuffer(PRTZIPCOMP pZip, const uint8_t *pbBuf, size_t cbBuf)
932{
933 bool fForceFlush = false;
934 while (cbBuf > 0)
935 {
936 /*
937 * Flush output buffer?
938 */
939 unsigned cbFree = (unsigned)(sizeof(pZip->abBuffer) - (pZip->u.LZF.pbOutput - &pZip->abBuffer[0]));
940 if ( fForceFlush
941 || cbFree < RTZIPLZF_MAX_DATA_SIZE + sizeof(RTZIPLZFHDR))
942 {
943 int rc = rtZipLZFCompFlushOutput(pZip);
944 if (RT_FAILURE(rc))
945 return rc;
946 fForceFlush = false;
947 cbFree = sizeof(pZip->abBuffer);
948 }
949
950 /*
951 * Setup the block header.
952 */
953 PRTZIPLZFHDR pHdr = (PRTZIPLZFHDR)pZip->u.LZF.pbOutput; /* warning: This might be unaligned! */
954 pHdr->u16Magic = RTZIPLZFHDR_MAGIC;
955 pHdr->cbData = 0;
956 pHdr->u32CRC = 0;
957 pHdr->cbUncompressed = 0;
958 cbFree -= sizeof(*pHdr);
959 pZip->u.LZF.pbOutput += sizeof(*pHdr);
960
961 /*
962 * Compress data for the block.
963 *
964 * We try compress as much as we have freespace for at first,
965 * but if it turns out the compression is inefficient, we'll
966 * reduce the size of data we try compress till it fits the
967 * output space.
968 */
969 cbFree = RT_MIN(cbFree, RTZIPLZF_MAX_DATA_SIZE);
970 unsigned cbInput = (unsigned)RT_MIN(RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE, cbBuf);
971 unsigned cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
972 if (!cbOutput)
973 {
974 /** @todo add an alternative method which stores the raw data if bad compression. */
975 do
976 {
977 cbInput /= 2;
978 if (!cbInput)
979 {
980 AssertMsgFailed(("lzf_compress bug! cbFree=%zu\n", cbFree));
981 return VERR_INTERNAL_ERROR;
982 }
983 cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
984 } while (!cbOutput);
985 fForceFlush = true;
986 }
987
988 /*
989 * Update the header and advance the input buffer.
990 */
991 pHdr->cbData = cbOutput;
992 //pHdr->u32CRC = RTCrc32(pbBuf, cbInput); - too slow
993 pHdr->cbUncompressed = cbInput;
994
995 pZip->u.LZF.pbOutput += cbOutput;
996 cbBuf -= cbInput;
997 pbBuf += cbInput;
998 }
999 return VINF_SUCCESS;
1000}
1001
1002
1003/**
1004 * Flushes the input buffer.
1005 * @returns iprt status code.
1006 * @param pZip The compressor instance.
1007 */
1008static int rtZipLZFCompFlushInput(PRTZIPCOMP pZip)
1009{
1010 size_t cb = pZip->u.LZF.pbInput - &pZip->u.LZF.abInput[0];
1011 pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
1012 pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
1013 if (cb)
1014 return rtZipLZFCompressBuffer(pZip, pZip->u.LZF.abInput, cb);
1015 return VINF_SUCCESS;
1016}
1017
1018
1019/**
1020 * @copydoc RTZipCompress
1021 */
1022static DECLCALLBACK(int) rtZipLZFCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
1023{
1024#define RTZIPLZF_SMALL_CHUNK (128)
1025
1026 /*
1027 * Flush the input buffer if necessary.
1028 */
1029 if ( ( cbBuf <= RTZIPLZF_SMALL_CHUNK
1030 && cbBuf > pZip->u.LZF.cbInputFree)
1031 || ( cbBuf > RTZIPLZF_SMALL_CHUNK
1032 && pZip->u.LZF.cbInputFree != sizeof(pZip->u.LZF.abInput))
1033 )
1034 {
1035 int rc = rtZipLZFCompFlushInput(pZip);
1036 if (RT_FAILURE(rc))
1037 return rc;
1038 }
1039
1040 /*
1041 * If it's a relativly small block put it in the input buffer, elsewise
1042 * compress directly it.
1043 */
1044 if (cbBuf <= RTZIPLZF_SMALL_CHUNK)
1045 {
1046 Assert(pZip->u.LZF.cbInputFree >= cbBuf);
1047 memcpy(pZip->u.LZF.pbInput, pvBuf, cbBuf);
1048 pZip->u.LZF.pbInput += cbBuf;
1049 pZip->u.LZF.cbInputFree -= cbBuf;
1050 }
1051 else
1052 {
1053 Assert(pZip->u.LZF.cbInputFree == sizeof(pZip->u.LZF.abInput));
1054 int rc = rtZipLZFCompressBuffer(pZip, (const uint8_t *)pvBuf, cbBuf);
1055 if (RT_FAILURE(rc))
1056 return rc;
1057 }
1058 return VINF_SUCCESS;
1059}
1060
1061
1062/**
1063 * @copydoc RTZipCompFinish
1064 */
1065static DECLCALLBACK(int) rtZipLZFCompFinish(PRTZIPCOMP pZip)
1066{
1067 int rc = rtZipLZFCompFlushInput(pZip);
1068 if (RT_SUCCESS(rc))
1069 rc = rtZipLZFCompFlushOutput(pZip);
1070 return rc;
1071}
1072
1073
1074/**
1075 * @copydoc RTZipCompDestroy
1076 */
1077static DECLCALLBACK(int) rtZipLZFCompDestroy(PRTZIPCOMP pZip)
1078{
1079 NOREF(pZip);
1080 return VINF_SUCCESS;
1081}
1082
1083
1084/**
1085 * Initializes the compressor instance.
1086 * @returns iprt status code.
1087 * @param pZip The compressor instance.
1088 * @param enmLevel The desired compression level.
1089 */
1090static DECLCALLBACK(int) rtZipLZFCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
1091{
1092 NOREF(enmLevel);
1093 pZip->pfnCompress = rtZipLZFCompress;
1094 pZip->pfnFinish = rtZipLZFCompFinish;
1095 pZip->pfnDestroy = rtZipLZFCompDestroy;
1096
1097 pZip->u.LZF.pbOutput = &pZip->abBuffer[1];
1098 pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
1099 pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
1100 return VINF_SUCCESS;
1101}
1102
1103
1104/**
1105 * This will validate a header and to all the necessary bitching if it's invalid.
1106 * @returns true if valid.
1107 * @returns false if invalid.
1108 * @param pHdr Pointer to the header.\
1109 */
1110static bool rtZipLZFValidHeader(PCRTZIPLZFHDR pHdr)
1111{
1112 if ( pHdr->u16Magic != RTZIPLZFHDR_MAGIC
1113 || !pHdr->cbData
1114 || pHdr->cbData > RTZIPLZF_MAX_DATA_SIZE
1115 || !pHdr->cbUncompressed
1116 || pHdr->cbUncompressed > RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE
1117 )
1118 {
1119 AssertMsgFailed(("Invalid LZF header! %.*Rhxs\n", sizeof(*pHdr), pHdr));
1120 return false;
1121 }
1122 return true;
1123}
1124
1125
1126/**
1127 * @copydoc RTZipDecompress
1128 */
1129static DECLCALLBACK(int) rtZipLZFDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1130{
1131 /*
1132 * Decompression loop.
1133 *
1134 * This a bit ugly because we have to deal with reading block...
1135 * To simplify matters we've put a max block size and will never
1136 * fill the input buffer with more than allows us to complete
1137 * any partially read blocks.
1138 *
1139 * When possible we decompress directly to the user buffer, when
1140 * not possible we'll use the spill buffer.
1141 */
1142# ifdef RTZIP_LZF_BLOCK_BY_BLOCK
1143 size_t cbWritten = 0;
1144 while (cbBuf > 0)
1145 {
1146 /*
1147 * Anything in the spill buffer?
1148 */
1149 if (pZip->u.LZF.cbSpill > 0)
1150 {
1151 unsigned cb = (unsigned)RT_MIN(pZip->u.LZF.cbSpill, cbBuf);
1152 memcpy(pvBuf, pZip->u.LZF.pbSpill, cb);
1153 pZip->u.LZF.pbSpill += cb;
1154 pZip->u.LZF.cbSpill -= cb;
1155 cbWritten += cb;
1156 cbBuf -= cb;
1157 if (!cbBuf)
1158 break;
1159 pvBuf = (uint8_t *)pvBuf + cb;
1160 }
1161
1162 /*
1163 * We always read and work one block at a time.
1164 */
1165 RTZIPLZFHDR Hdr;
1166 int rc = pZip->pfnIn(pZip->pvUser, &Hdr, sizeof(Hdr), NULL);
1167 if (RT_FAILURE(rc))
1168 return rc;
1169 if (!rtZipLZFValidHeader(&Hdr))
1170 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1171 if (Hdr.cbData > 0)
1172 {
1173 rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], Hdr.cbData, NULL);
1174 if (RT_FAILURE(rc))
1175 return rc;
1176 }
1177
1178 /*
1179 * Does the uncompressed data fit into the supplied buffer?
1180 * If so we uncompress it directly into the user buffer, else we'll have to use the spill buffer.
1181 */
1182 unsigned cbUncompressed = Hdr.cbUncompressed;
1183 if (cbUncompressed <= cbBuf)
1184 {
1185 unsigned cbOutput = lzf_decompress(&pZip->abBuffer[0], Hdr.cbData, pvBuf, cbUncompressed);
1186 if (cbOutput != cbUncompressed)
1187 {
1188# ifndef IPRT_NO_CRT /* no errno */
1189 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1190 errno, cbOutput, cbUncompressed));
1191# endif
1192 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1193 }
1194 cbBuf -= cbUncompressed;
1195 pvBuf = (uint8_t *)pvBuf + cbUncompressed;
1196 cbWritten += cbUncompressed;
1197 }
1198 else
1199 {
1200 unsigned cbOutput = lzf_decompress(&pZip->abBuffer[0], Hdr.cbData, pZip->u.LZF.abSpill, cbUncompressed);
1201 if (cbOutput != cbUncompressed)
1202 {
1203# ifndef IPRT_NO_CRT /* no errno */
1204 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1205 errno, cbOutput, cbUncompressed));
1206# endif
1207 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1208 }
1209 pZip->u.LZF.pbSpill = &pZip->u.LZF.abSpill[0];
1210 pZip->u.LZF.cbSpill = cbUncompressed;
1211 }
1212 }
1213
1214 if (pcbWritten)
1215 *pcbWritten = cbWritten;
1216# else /* !RTZIP_LZF_BLOCK_BY_BLOCK */
1217 while (cbBuf > 0)
1218 {
1219 /*
1220 * Anything in the spill buffer?
1221 */
1222 if (pZip->u.LZF.cbSpill > 0)
1223 {
1224 unsigned cb = (unsigned)RT_MIN(pZip->u.LZF.cbSpill, cbBuf);
1225 memcpy(pvBuf, pZip->u.LZF.pbSpill, cb);
1226 pZip->u.LZF.pbSpill += cb;
1227 pZip->u.LZF.cbSpill -= cb;
1228 cbBuf -= cb;
1229 if (pcbWritten)
1230 *pcbWritten = cb;
1231 if (!cbBuf)
1232 break;
1233 pvBuf = (uint8_t *)pvBuf + cb;
1234 }
1235
1236 /*
1237 * Incomplete header or nothing at all.
1238 */
1239 PCRTZIPLZFHDR pHdr;
1240 if (pZip->u.LZF.cbInput < sizeof(RTZIPLZFHDR))
1241 {
1242 if (pZip->u.LZF.cbInput <= 0)
1243 {
1244 /* empty, fill the buffer. */
1245 size_t cb = 0;
1246 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0],
1247 sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE, &cb);
1248 if (RT_FAILURE(rc))
1249 return rc;
1250 pZip->u.LZF.pbInput = &pZip->abBuffer[0];
1251 pZip->u.LZF.cbInput = cb;
1252 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1253 }
1254 else
1255 {
1256 /* move the header up and fill the buffer. */
1257 size_t cbCur = pZip->u.LZF.cbInput;
1258 memmove(&pZip->abBuffer[0], pZip->u.LZF.pbInput, cbCur);
1259 pZip->u.LZF.pbInput = &pZip->abBuffer[0];
1260
1261 size_t cb = 0;
1262 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[cbCur],
1263 sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE - cbCur, &cb);
1264 if (RT_FAILURE(rc))
1265 return rc;
1266 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1267 pZip->u.LZF.cbInput += cb;
1268 }
1269
1270 /*
1271 * Validate the header.
1272 */
1273 if (!rtZipLZFValidHeader(pHdr))
1274 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1275 }
1276 else
1277 {
1278 /*
1279 * Validate the header and check if it's an incomplete block.
1280 */
1281 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1282 if (!rtZipLZFValidHeader(pHdr))
1283 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1284
1285 if (pHdr->cbData > pZip->u.LZF.cbInput - sizeof(*pHdr))
1286 {
1287 /* read the remainder of the block. */
1288 size_t cbToRead = pHdr->cbData - (pZip->u.LZF.cbInput - sizeof(*pHdr));
1289 Assert(&pZip->u.LZF.pbInput[pZip->u.LZF.cbInput + cbToRead] <= &pZip->u.LZF.pbInput[sizeof(pZip->abBuffer)]);
1290 int rc = pZip->pfnIn(pZip->pvUser, &pZip->u.LZF.pbInput[pZip->u.LZF.cbInput],
1291 cbToRead, NULL);
1292 if (RT_FAILURE(rc))
1293 return rc;
1294 pZip->u.LZF.cbInput += cbToRead;
1295 }
1296 }
1297 AssertMsgReturn(sizeof(*pHdr) + pHdr->cbData <= pZip->u.LZF.cbInput,
1298 ("cbData=%#x cbInput=%#x\n", pHdr->cbData, pZip->u.LZF.cbInput),
1299 VERR_GENERAL_FAILURE); /** @todo Get better error codes for RTZip! */
1300
1301 /*
1302 * Does the uncompressed data fit into the supplied buffer?
1303 * If so we uncompress it directly into the user buffer, else we'll have to use the spill buffer.
1304 */
1305 unsigned cbUncompressed = pHdr->cbUncompressed;
1306 if (cbUncompressed <= cbBuf)
1307 {
1308 unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pvBuf, cbUncompressed);
1309 if (cbOutput != cbUncompressed)
1310 {
1311 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1312 errno, cbOutput, cbUncompressed));
1313 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1314 }
1315 cbBuf -= cbUncompressed;
1316 pvBuf = (uint8_t *)pvBuf + cbUncompressed;
1317 }
1318 else
1319 {
1320 unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pZip->u.LZF.abSpill, cbUncompressed);
1321 if (cbOutput != cbUncompressed)
1322 {
1323 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1324 errno, cbOutput, cbUncompressed));
1325 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1326 }
1327 pZip->u.LZF.pbSpill = &pZip->u.LZF.abSpill[0];
1328 pZip->u.LZF.cbSpill = cbUncompressed;
1329 }
1330
1331 /* advance the input buffer */
1332 pZip->u.LZF.cbInput -= pHdr->cbData + sizeof(*pHdr);
1333 pZip->u.LZF.pbInput += pHdr->cbData + sizeof(*pHdr);
1334 if (pcbWritten)
1335 *pcbWritten += cbUncompressed;
1336 }
1337# endif /* !RTZIP_LZF_BLOCK_BY_BLOCK */
1338 return VINF_SUCCESS;
1339}
1340
1341
1342/**
1343 * @copydoc RTZipDecompDestroy
1344 */
1345static DECLCALLBACK(int) rtZipLZFDecompDestroy(PRTZIPDECOMP pZip)
1346{
1347 NOREF(pZip);
1348 return VINF_SUCCESS;
1349}
1350
1351
1352/**
1353 * Initialize the decompressor instance.
1354 * @returns iprt status code.
1355 * @param pZip The decompressor instance.
1356 */
1357static DECLCALLBACK(int) rtZipLZFDecompInit(PRTZIPDECOMP pZip)
1358{
1359 pZip->pfnDecompress = rtZipLZFDecompress;
1360 pZip->pfnDestroy = rtZipLZFDecompDestroy;
1361
1362# ifndef RTZIP_LZF_BLOCK_BY_BLOCK
1363 pZip->u.LZF.pbInput = NULL;
1364 pZip->u.LZF.cbInput = 0;
1365# endif
1366 pZip->u.LZF.cbSpill = 0;
1367 pZip->u.LZF.pbSpill = NULL;
1368
1369 return VINF_SUCCESS;
1370}
1371
1372#endif /* RTZIP_USE_LZF */
1373
1374
1375/**
1376 * Create a compressor instance.
1377 *
1378 * @returns iprt status code.
1379 * @param ppZip Where to store the instance handle.
1380 * @param pvUser User argument which will be passed on to pfnOut and pfnIn.
1381 * @param pfnOut Callback for consuming output of compression.
1382 * @param enmType Type of compressor to create.
1383 * @param enmLevel Compression level.
1384 */
1385RTDECL(int) RTZipCompCreate(PRTZIPCOMP *ppZip, void *pvUser, PFNRTZIPOUT pfnOut, RTZIPTYPE enmType, RTZIPLEVEL enmLevel)
1386{
1387 /*
1388 * Validate input.
1389 */
1390 AssertReturn(enmType >= RTZIPTYPE_INVALID && enmType < RTZIPTYPE_END, VERR_INVALID_PARAMETER);
1391 AssertReturn(enmLevel >= RTZIPLEVEL_STORE && enmLevel <= RTZIPLEVEL_MAX, VERR_INVALID_PARAMETER);
1392 AssertPtrReturn(pfnOut, VERR_INVALID_POINTER);
1393 AssertPtrReturn(ppZip, VERR_INVALID_POINTER);
1394
1395 /*
1396 * Allocate memory for the instance data.
1397 */
1398 PRTZIPCOMP pZip = (PRTZIPCOMP)RTMemAlloc(sizeof(RTZIPCOMP));
1399 if (!pZip)
1400 return VERR_NO_MEMORY;
1401
1402 /*
1403 * Determine auto type.
1404 */
1405 if (enmType == RTZIPTYPE_AUTO)
1406 {
1407 if (enmLevel == RTZIPLEVEL_STORE)
1408 enmType = RTZIPTYPE_STORE;
1409 else
1410 {
1411#if defined(RTZIP_USE_ZLIB) && defined(RTZIP_USE_BZLIB)
1412 if (enmLevel == RTZIPLEVEL_MAX)
1413 enmType = RTZIPTYPE_BZLIB;
1414 else
1415 enmType = RTZIPTYPE_ZLIB;
1416#elif defined(RTZIP_USE_ZLIB)
1417 enmType = RTZIPTYPE_ZLIB;
1418#elif defined(RTZIP_USE_BZLIB)
1419 enmType = RTZIPTYPE_BZLIB;
1420#else
1421 enmType = RTZIPTYPE_STORE;
1422#endif
1423 }
1424 }
1425
1426 /*
1427 * Init instance.
1428 */
1429 pZip->pfnOut = pfnOut;
1430 pZip->enmType = enmType;
1431 pZip->pvUser = pvUser;
1432 pZip->abBuffer[0] = enmType; /* first byte is the compression type. */
1433 int rc = VERR_NOT_IMPLEMENTED;
1434 switch (enmType)
1435 {
1436 case RTZIPTYPE_STORE:
1437#ifdef RTZIP_USE_STORE
1438 rc = rtZipStoreCompInit(pZip, enmLevel);
1439#endif
1440 break;
1441
1442 case RTZIPTYPE_ZLIB:
1443 case RTZIPTYPE_ZLIB_NO_HEADER:
1444#ifdef RTZIP_USE_ZLIB
1445 rc = rtZipZlibCompInit(pZip, enmLevel, enmType == RTZIPTYPE_ZLIB /*fZlibHeader*/);
1446#endif
1447 break;
1448
1449 case RTZIPTYPE_BZLIB:
1450#ifdef RTZIP_USE_BZLIB
1451 rc = rtZipBZlibCompInit(pZip, enmLevel);
1452#endif
1453 break;
1454
1455 case RTZIPTYPE_LZF:
1456#ifdef RTZIP_USE_LZF
1457 rc = rtZipLZFCompInit(pZip, enmLevel);
1458#endif
1459 break;
1460
1461 case RTZIPTYPE_LZJB:
1462 case RTZIPTYPE_LZO:
1463 break;
1464
1465 default:
1466 AssertFailedBreak();
1467 }
1468
1469 if (RT_SUCCESS(rc))
1470 *ppZip = pZip;
1471 else
1472 RTMemFree(pZip);
1473 return rc;
1474}
1475RT_EXPORT_SYMBOL(RTZipCompCreate);
1476
1477
1478/**
1479 * Compresses a chunk of memory.
1480 *
1481 * @returns iprt status code.
1482 * @param pZip The compressor instance.
1483 * @param pvBuf Pointer to buffer containing the bits to compress.
1484 * @param cbBuf Number of bytes to compress.
1485 */
1486RTDECL(int) RTZipCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
1487{
1488 if (!cbBuf)
1489 return VINF_SUCCESS;
1490 return pZip->pfnCompress(pZip, pvBuf, cbBuf);
1491}
1492RT_EXPORT_SYMBOL(RTZipCompress);
1493
1494
1495/**
1496 * Finishes the compression.
1497 * This will flush all data and terminate the compression data stream.
1498 *
1499 * @returns iprt status code.
1500 * @param pZip The compressor instance.
1501 */
1502RTDECL(int) RTZipCompFinish(PRTZIPCOMP pZip)
1503{
1504 return pZip->pfnFinish(pZip);
1505}
1506RT_EXPORT_SYMBOL(RTZipCompFinish);
1507
1508
1509/**
1510 * Destroys the compressor instance.
1511 *
1512 * @returns iprt status code.
1513 * @param pZip The compressor instance.
1514 */
1515RTDECL(int) RTZipCompDestroy(PRTZIPCOMP pZip)
1516{
1517 /*
1518 * Compressor specific destruction attempt first.
1519 */
1520 int rc = pZip->pfnDestroy(pZip);
1521 AssertRCReturn(rc, rc);
1522
1523 /*
1524 * Free the instance memory.
1525 */
1526 pZip->enmType = RTZIPTYPE_INVALID;
1527 RTMemFree(pZip);
1528 return VINF_SUCCESS;
1529}
1530RT_EXPORT_SYMBOL(RTZipCompDestroy);
1531
1532
1533/**
1534 * @copydoc RTZipDecompress
1535 */
1536static DECLCALLBACK(int) rtZipStubDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1537{
1538 NOREF(pZip); NOREF(pvBuf); NOREF(cbBuf); NOREF(pcbWritten);
1539 return VERR_NOT_SUPPORTED;
1540}
1541
1542
1543/**
1544 * @copydoc RTZipDecompDestroy
1545 */
1546static DECLCALLBACK(int) rtZipStubDecompDestroy(PRTZIPDECOMP pZip)
1547{
1548 NOREF(pZip);
1549 return VINF_SUCCESS;
1550}
1551
1552
1553/**
1554 * Create a decompressor instance.
1555 *
1556 * @returns iprt status code.
1557 * @param ppZip Where to store the instance handle.
1558 * @param pvUser User argument which will be passed on to pfnOut and pfnIn.
1559 * @param pfnIn Callback for producing input for decompression.
1560 */
1561RTDECL(int) RTZipDecompCreate(PRTZIPDECOMP *ppZip, void *pvUser, PFNRTZIPIN pfnIn)
1562{
1563 /*
1564 * Validate input.
1565 */
1566 AssertPtrReturn(pfnIn, VERR_INVALID_POINTER);
1567 AssertPtrReturn(ppZip, VERR_INVALID_POINTER);
1568
1569 /*
1570 * Allocate memory for the instance data.
1571 */
1572 PRTZIPDECOMP pZip = (PRTZIPDECOMP)RTMemAlloc(sizeof(RTZIPDECOMP));
1573 if (!pZip)
1574 return VERR_NO_MEMORY;
1575
1576 /*
1577 * Init instance.
1578 */
1579 pZip->pfnIn = pfnIn;
1580 pZip->enmType = RTZIPTYPE_INVALID;
1581 pZip->pvUser = pvUser;
1582 pZip->pfnDecompress = NULL;
1583 pZip->pfnDestroy = rtZipStubDecompDestroy;
1584
1585 *ppZip = pZip;
1586 return VINF_SUCCESS;
1587}
1588RT_EXPORT_SYMBOL(RTZipDecompCreate);
1589
1590
1591/**
1592 * Lazy init of the decompressor.
1593 * @returns iprt status code.
1594 * @param pZip The decompressor instance.
1595 */
1596static int rtzipDecompInit(PRTZIPDECOMP pZip)
1597{
1598 /*
1599 * Read the first byte from the stream so we can determine the type.
1600 */
1601 uint8_t u8Type;
1602 int rc = pZip->pfnIn(pZip->pvUser, &u8Type, sizeof(u8Type), NULL);
1603 if (RT_FAILURE(rc))
1604 return rc;
1605
1606 /*
1607 * Determine type and do type specific init.
1608 */
1609 pZip->enmType = (RTZIPTYPE)u8Type;
1610 rc = VERR_NOT_SUPPORTED;
1611 switch (pZip->enmType)
1612 {
1613 case RTZIPTYPE_STORE:
1614#ifdef RTZIP_USE_STORE
1615 rc = rtZipStoreDecompInit(pZip);
1616#else
1617 AssertMsgFailed(("Store is not include in this build!\n"));
1618#endif
1619 break;
1620
1621 case RTZIPTYPE_ZLIB:
1622 case RTZIPTYPE_ZLIB_NO_HEADER:
1623#ifdef RTZIP_USE_ZLIB
1624 rc = rtZipZlibDecompInit(pZip, pZip->enmType == RTZIPTYPE_ZLIB /*fHeader*/);
1625#else
1626 AssertMsgFailed(("Zlib is not include in this build!\n"));
1627#endif
1628 break;
1629
1630 case RTZIPTYPE_BZLIB:
1631#ifdef RTZIP_USE_BZLIB
1632 rc = rtZipBZlibDecompInit(pZip);
1633#else
1634 AssertMsgFailed(("BZlib is not include in this build!\n"));
1635#endif
1636 break;
1637
1638 case RTZIPTYPE_LZF:
1639#ifdef RTZIP_USE_LZF
1640 rc = rtZipLZFDecompInit(pZip);
1641#else
1642 AssertMsgFailed(("LZF is not include in this build!\n"));
1643#endif
1644 break;
1645
1646 case RTZIPTYPE_LZJB:
1647#ifdef RTZIP_USE_LZJB
1648 AssertMsgFailed(("LZJB streaming support is not implemented yet!\n"));
1649#else
1650 AssertMsgFailed(("LZJB is not include in this build!\n"));
1651#endif
1652 break;
1653
1654 case RTZIPTYPE_LZO:
1655#ifdef RTZIP_USE_LZJB
1656 AssertMsgFailed(("LZO streaming support is not implemented yet!\n"));
1657#else
1658 AssertMsgFailed(("LZO is not include in this build!\n"));
1659#endif
1660 break;
1661
1662 default:
1663 AssertMsgFailed(("Invalid compression type %d (%#x)!\n", pZip->enmType, pZip->enmType));
1664 rc = VERR_INVALID_MAGIC;
1665 break;
1666 }
1667 if (RT_FAILURE(rc))
1668 {
1669 pZip->pfnDecompress = rtZipStubDecompress;
1670 pZip->pfnDestroy = rtZipStubDecompDestroy;
1671 }
1672
1673 return rc;
1674}
1675
1676
1677/**
1678 * Decompresses a chunk of memory.
1679 *
1680 * @returns iprt status code.
1681 * @param pZip The decompressor instance.
1682 * @param pvBuf Where to store the decompressed data.
1683 * @param cbBuf Number of bytes to produce. If pcbWritten is set
1684 * any number of bytes up to cbBuf might be returned.
1685 * @param pcbWritten Number of bytes actually written to the buffer. If NULL
1686 * cbBuf number of bytes must be written.
1687 */
1688RTDECL(int) RTZipDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1689{
1690 /*
1691 * Skip empty requests.
1692 */
1693 if (!cbBuf)
1694 return VINF_SUCCESS;
1695
1696 /*
1697 * Lazy init.
1698 */
1699 if (!pZip->pfnDecompress)
1700 {
1701 int rc = rtzipDecompInit(pZip);
1702 if (RT_FAILURE(rc))
1703 return rc;
1704 }
1705
1706 /*
1707 * 'Read' the decompressed stream.
1708 */
1709 return pZip->pfnDecompress(pZip, pvBuf, cbBuf, pcbWritten);
1710}
1711RT_EXPORT_SYMBOL(RTZipDecompress);
1712
1713
1714/**
1715 * Destroys the decompressor instance.
1716 *
1717 * @returns iprt status code.
1718 * @param pZip The decompressor instance.
1719 */
1720RTDECL(int) RTZipDecompDestroy(PRTZIPDECOMP pZip)
1721{
1722 /*
1723 * Destroy compressor instance and flush the output buffer.
1724 */
1725 int rc = pZip->pfnDestroy(pZip);
1726 AssertRCReturn(rc, rc);
1727
1728 /*
1729 * Free the instance memory.
1730 */
1731 pZip->enmType = RTZIPTYPE_INVALID;
1732 RTMemFree(pZip);
1733 return rc;
1734}
1735RT_EXPORT_SYMBOL(RTZipDecompDestroy);
1736
1737
1738RTDECL(int) RTZipBlockCompress(RTZIPTYPE enmType, RTZIPLEVEL enmLevel, uint32_t fFlags,
1739 void const *pvSrc, size_t cbSrc,
1740 void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW_DEF
1741{
1742 /* input validation - the crash and burn approach as speed is essential here. */
1743 Assert(enmLevel <= RTZIPLEVEL_MAX && enmLevel >= RTZIPLEVEL_STORE); RT_NOREF_PV(enmLevel);
1744 Assert(!fFlags); RT_NOREF_PV(fFlags);
1745
1746 /*
1747 * Deal with flags involving prefixes.
1748 */
1749 /** @todo later: type and/or compressed length prefix. */
1750
1751 /*
1752 * The type specific part.
1753 */
1754 switch (enmType)
1755 {
1756 case RTZIPTYPE_LZF:
1757 {
1758#ifdef RTZIP_USE_LZF
1759# if 0
1760 static const uint8_t s_abZero4K[] =
1761 {
1762 0x01, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff,
1763 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0,
1764 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00,
1765 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff,
1766 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0,
1767 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00,
1768 0xe0, 0x7d, 0x00
1769 };
1770 if ( cbSrc == _4K
1771 && !((uintptr_t)pvSrc & 15)
1772 && ASMMemIsZero(pvSrc, _4K))
1773 {
1774 if (RT_UNLIKELY(cbDst < sizeof(s_abZero4K)))
1775 return VERR_BUFFER_OVERFLOW;
1776 memcpy(pvDst, s_abZero4K, sizeof(s_abZero4K));
1777 *pcbDstActual = sizeof(s_abZero4K);
1778 break;
1779 }
1780# endif
1781
1782 unsigned cbDstActual = lzf_compress(pvSrc, (unsigned)cbSrc, pvDst, (unsigned)cbDst); /** @todo deal with size type overflows */
1783 if (RT_UNLIKELY(cbDstActual < 1))
1784 return VERR_BUFFER_OVERFLOW;
1785 *pcbDstActual = cbDstActual;
1786 break;
1787#else
1788 return VERR_NOT_SUPPORTED;
1789#endif
1790 }
1791
1792 case RTZIPTYPE_STORE:
1793 {
1794 if (cbDst < cbSrc)
1795 return VERR_BUFFER_OVERFLOW;
1796 memcpy(pvDst, pvSrc, cbSrc);
1797 *pcbDstActual = cbSrc;
1798 break;
1799 }
1800
1801 case RTZIPTYPE_LZJB:
1802 {
1803#ifdef RTZIP_USE_LZJB
1804 AssertReturn(cbDst > cbSrc, VERR_BUFFER_OVERFLOW);
1805 size_t cbDstActual = lzjb_compress((void *)pvSrc, (uint8_t *)pvDst + 1, cbSrc, cbSrc, 0 /*??*/);
1806 if (cbDstActual == cbSrc)
1807 *(uint8_t *)pvDst = 0;
1808 else
1809 *(uint8_t *)pvDst = 1;
1810 *pcbDstActual = cbDstActual + 1;
1811 break;
1812#else
1813 return VERR_NOT_SUPPORTED;
1814#endif
1815 }
1816
1817 case RTZIPTYPE_LZO:
1818 {
1819#ifdef RTZIP_USE_LZO
1820 uint64_t Scratch[RT_ALIGN(LZO1X_1_MEM_COMPRESS, sizeof(uint64_t)) / sizeof(uint64_t)];
1821 int rc = lzo_init();
1822 if (RT_UNLIKELY(rc != LZO_E_OK))
1823 return VERR_INTERNAL_ERROR;
1824
1825 lzo_uint cbDstInOut = cbDst;
1826 rc = lzo1x_1_compress((const lzo_bytep)pvSrc, cbSrc, (lzo_bytep )pvDst, &cbDstInOut, &Scratch[0]);
1827 if (RT_UNLIKELY(rc != LZO_E_OK))
1828 switch (rc)
1829 {
1830 case LZO_E_OUTPUT_OVERRUN: return VERR_BUFFER_OVERFLOW;
1831 default: return VERR_GENERAL_FAILURE;
1832 }
1833 *pcbDstActual = cbDstInOut;
1834 break;
1835#else
1836 return VERR_NOT_SUPPORTED;
1837#endif
1838 }
1839
1840 case RTZIPTYPE_ZLIB:
1841 case RTZIPTYPE_BZLIB:
1842 return VERR_NOT_SUPPORTED;
1843
1844 default:
1845 AssertMsgFailed(("%d\n", enmType));
1846 return VERR_INVALID_PARAMETER;
1847 }
1848
1849 return VINF_SUCCESS;
1850}
1851RT_EXPORT_SYMBOL(RTZipBlockCompress);
1852
1853
1854RTDECL(int) RTZipBlockDecompress(RTZIPTYPE enmType, uint32_t fFlags,
1855 void const *pvSrc, size_t cbSrc, size_t *pcbSrcActual,
1856 void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW_DEF
1857{
1858 /* input validation - the crash and burn approach as speed is essential here. */
1859 Assert(!fFlags); RT_NOREF_PV(fFlags);
1860
1861 /*
1862 * Deal with flags involving prefixes.
1863 */
1864 /** @todo later: type and/or compressed length prefix. */
1865
1866 /*
1867 * The type specific part.
1868 */
1869 switch (enmType)
1870 {
1871 case RTZIPTYPE_LZF:
1872 {
1873#ifdef RTZIP_USE_LZF
1874 unsigned cbDstActual = lzf_decompress(pvSrc, (unsigned)cbSrc, pvDst, (unsigned)cbDst); /** @todo deal with size type overflows */
1875 if (RT_UNLIKELY(cbDstActual < 1))
1876 {
1877# ifndef IPRT_NO_CRT /* no errno */
1878 if (errno == E2BIG)
1879 return VERR_BUFFER_OVERFLOW;
1880 Assert(errno == EINVAL);
1881# endif
1882 return VERR_GENERAL_FAILURE;
1883 }
1884 if (pcbDstActual)
1885 *pcbDstActual = cbDstActual;
1886 if (pcbSrcActual)
1887 *pcbSrcActual = cbSrc;
1888 break;
1889#else
1890 return VERR_NOT_SUPPORTED;
1891#endif
1892 }
1893
1894 case RTZIPTYPE_STORE:
1895 {
1896 if (cbDst < cbSrc)
1897 return VERR_BUFFER_OVERFLOW;
1898 memcpy(pvDst, pvSrc, cbSrc);
1899 if (pcbDstActual)
1900 *pcbDstActual = cbSrc;
1901 if (pcbSrcActual)
1902 *pcbSrcActual = cbSrc;
1903 break;
1904 }
1905
1906 case RTZIPTYPE_LZJB:
1907 {
1908#ifdef RTZIP_USE_LZJB
1909 if (*(uint8_t *)pvSrc == 1)
1910 {
1911 int rc = lzjb_decompress((uint8_t *)pvSrc + 1, pvDst, cbSrc - 1, cbDst, 0 /*??*/);
1912 if (RT_UNLIKELY(rc != 0))
1913 return VERR_GENERAL_FAILURE;
1914 if (pcbDstActual)
1915 *pcbDstActual = cbDst;
1916 }
1917 else
1918 {
1919 AssertReturn(cbDst >= cbSrc - 1, VERR_BUFFER_OVERFLOW);
1920 memcpy(pvDst, (uint8_t *)pvSrc + 1, cbSrc - 1);
1921 if (pcbDstActual)
1922 *pcbDstActual = cbSrc - 1;
1923 }
1924 if (pcbSrcActual)
1925 *pcbSrcActual = cbSrc;
1926 break;
1927#else
1928 return VERR_NOT_SUPPORTED;
1929#endif
1930 }
1931
1932 case RTZIPTYPE_LZO:
1933 {
1934#ifdef RTZIP_USE_LZO
1935 int rc = lzo_init();
1936 if (RT_UNLIKELY(rc != LZO_E_OK))
1937 return VERR_INTERNAL_ERROR;
1938 lzo_uint cbDstInOut = cbDst;
1939 rc = lzo1x_decompress((const lzo_bytep)pvSrc, cbSrc, (lzo_bytep)pvDst, &cbDstInOut, NULL);
1940 if (RT_UNLIKELY(rc != LZO_E_OK))
1941 switch (rc)
1942 {
1943 case LZO_E_OUTPUT_OVERRUN: return VERR_BUFFER_OVERFLOW;
1944 default:
1945 case LZO_E_INPUT_OVERRUN: return VERR_GENERAL_FAILURE;
1946 }
1947 if (pcbSrcActual)
1948 *pcbSrcActual = cbSrc;
1949 if (pcbDstActual)
1950 *pcbDstActual = cbDstInOut;
1951 break;
1952#else
1953 return VERR_NOT_SUPPORTED;
1954#endif
1955 }
1956
1957 case RTZIPTYPE_ZLIB:
1958 case RTZIPTYPE_ZLIB_NO_HEADER:
1959 {
1960#ifdef RTZIP_USE_ZLIB
1961 AssertReturn(cbSrc == (uInt)cbSrc, VERR_TOO_MUCH_DATA);
1962 AssertReturn(cbDst == (uInt)cbDst, VERR_OUT_OF_RANGE);
1963
1964 z_stream ZStrm;
1965 RT_ZERO(ZStrm);
1966 ZStrm.next_in = (Bytef *)pvSrc;
1967 ZStrm.avail_in = (uInt)cbSrc;
1968 ZStrm.next_out = (Bytef *)pvDst;
1969 ZStrm.avail_out = (uInt)cbDst;
1970
1971 int rc;
1972 if (enmType == RTZIPTYPE_ZLIB)
1973 rc = inflateInit(&ZStrm);
1974 else if (enmType == RTZIPTYPE_ZLIB_NO_HEADER)
1975 rc = inflateInit2(&ZStrm, -Z_DEF_WBITS);
1976 else
1977 AssertFailedReturn(VERR_INTERNAL_ERROR);
1978
1979 if (RT_UNLIKELY(rc != Z_OK))
1980 return zipErrConvertFromZlib(rc, false /*fCompressing*/);
1981 rc = inflate(&ZStrm, Z_FINISH);
1982 if (rc != Z_STREAM_END)
1983 {
1984 inflateEnd(&ZStrm);
1985 if ((rc == Z_BUF_ERROR && ZStrm.avail_in == 0) || rc == Z_NEED_DICT)
1986 return VERR_ZIP_CORRUPTED;
1987 if (rc == Z_BUF_ERROR)
1988 return VERR_BUFFER_OVERFLOW;
1989 AssertReturn(rc < Z_OK, VERR_GENERAL_FAILURE);
1990 return zipErrConvertFromZlib(rc, false /*fCompressing*/);
1991 }
1992 rc = inflateEnd(&ZStrm);
1993 if (rc != Z_OK)
1994 return zipErrConvertFromZlib(rc, false /*fCompressing*/);
1995
1996 if (pcbSrcActual)
1997 *pcbSrcActual = cbSrc - ZStrm.avail_in;
1998 if (pcbDstActual)
1999 *pcbDstActual = ZStrm.total_out;
2000 break;
2001#else
2002 return VERR_NOT_SUPPORTED;
2003#endif
2004 }
2005
2006 case RTZIPTYPE_BZLIB:
2007 return VERR_NOT_SUPPORTED;
2008
2009 default:
2010 AssertMsgFailed(("%d\n", enmType));
2011 return VERR_INVALID_PARAMETER;
2012 }
2013 return VINF_SUCCESS;
2014}
2015RT_EXPORT_SYMBOL(RTZipBlockDecompress);
2016
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use