VirtualBox

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

Last change on this file since 21337 was 21337, checked in by vboxsync, 15 years ago

IPRT,HostDrv,AddDrv: Export public IPRT symbols for the linux kernel (pain).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 43.5 KB
Line 
1/* $Id: zip.cpp 21337 2009-07-07 14:58:27Z vboxsync $ */
2/** @file
3 * IPRT - Compression.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Defined Constants And Macros *
34*******************************************************************************/
35#define RTZIP_USE_STORE 1
36#define RTZIP_USE_ZLIB 1
37//#define RTZIP_USE_BZLIB 1
38#define RTZIP_USE_LZF 1
39
40
41/*******************************************************************************
42* Header Files *
43*******************************************************************************/
44#ifdef RTZIP_USE_BZLIB
45# include <bzlib.h>
46#endif
47#ifdef RTZIP_USE_ZLIB
48# include <zlib.h>
49#endif
50#ifdef RTZIP_USE_LZF
51# include <lzf.h>
52# include <iprt/crc32.h>
53#endif
54
55#include <iprt/zip.h>
56#include "internal/iprt.h"
57
58#include <iprt/alloc.h>
59#include <iprt/assert.h>
60#include <iprt/err.h>
61#include <iprt/log.h>
62#include <iprt/string.h>
63
64#include <errno.h>
65
66
67/*******************************************************************************
68* Structures and Typedefs *
69*******************************************************************************/
70
71#ifdef RTZIP_USE_LZF
72
73/**
74 * LZF block header.
75 */
76#pragma pack(1) /* paranoia */
77typedef struct RTZIPLZFHDR
78{
79 /** Magic word (RTZIPLZFHDR_MAGIC). */
80 uint16_t u16Magic;
81 /** The number of bytes of data following this header. */
82 uint16_t cbData;
83 /** The CRC32 of the block. */
84 uint32_t u32CRC;
85 /** The size of the uncompressed data in bytes. */
86 uint16_t cbUncompressed;
87} RTZIPLZFHDR;
88#pragma pack()
89/** Pointer to a LZF block header. */
90typedef RTZIPLZFHDR *PRTZIPLZFHDR;
91/** Pointer to a const LZF block header. */
92typedef const RTZIPLZFHDR *PCRTZIPLZFHDR;
93
94/** The magic of a LZF block header. */
95#define RTZIPLZFHDR_MAGIC ('Z' | ('V' << 8))
96
97/** The max compressed data size.
98 * The maximum size of a block is currently 16KB.
99 * This is very important so we don't have to move input buffers around. */
100#define RTZIPLZF_MAX_DATA_SIZE (16384 - sizeof(RTZIPLZFHDR))
101
102/** The max uncompressed data size.
103 * This is important so we don't overflow the spill buffer in the decompressor. */
104#define RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE (32*_1K)
105
106#endif /* RTZIP_USE_LZF */
107
108
109/**
110 * Compressor/Decompressor instance data.
111 */
112typedef struct RTZIPCOMP
113{
114 /** Output buffer. */
115 uint8_t abBuffer[_128K];
116 /** Compression output consumer. */
117 PFNRTZIPOUT pfnOut;
118 /** User argument for the callback. */
119 void *pvUser;
120
121 /**
122 * @copydoc RTZipCompress
123 */
124 DECLCALLBACKMEMBER(int, pfnCompress)(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf);
125
126 /**
127 * @copydoc RTZipCompFinish
128 */
129 DECLCALLBACKMEMBER(int, pfnFinish)(PRTZIPCOMP pZip);
130
131 /**
132 * @copydoc RTZipCompDestroy
133 */
134 DECLCALLBACKMEMBER(int, pfnDestroy)(PRTZIPCOMP pZip);
135
136 /** Compression type. */
137 RTZIPTYPE enmType;
138 /** Type specific data. */
139 union
140 {
141#ifdef RTZIP_USE_STORE
142 /** Simple storing. */
143 struct
144 {
145 /** Current buffer postition. (where to start write) */
146 uint8_t *pb;
147 } Store;
148#endif
149#ifdef RTZIP_USE_ZLIB
150 /** Zlib stream. */
151 z_stream Zlib;
152#endif
153#ifdef RTZIP_USE_BZLIB
154 /** BZlib stream. */
155 bz_stream BZlib;
156#endif
157#ifdef RTZIP_USE_LZF
158 /** LZF stream. */
159 struct
160 {
161 /** Current output buffer postition. */
162 uint8_t *pbOutput;
163 /** The input buffer position. */
164 uint8_t *pbInput;
165 /** The number of free bytes in the input buffer. */
166 size_t cbInputFree;
167 /** The input buffer. */
168 uint8_t abInput[RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE];
169 } LZF;
170#endif
171
172 } u;
173} RTZIPCOMP;
174
175
176
177/**
178 * Decompressor instance data.
179 */
180typedef struct RTZIPDECOMP
181{
182 /** Input buffer. */
183 uint8_t abBuffer[_128K];
184 /** Decompression input producer. */
185 PFNRTZIPIN pfnIn;
186 /** User argument for the callback. */
187 void *pvUser;
188
189 /**
190 * @copydoc RTZipDecompress
191 */
192 DECLCALLBACKMEMBER(int, pfnDecompress)(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
193
194 /**
195 * @copydoc RTZipDecompDestroy
196 */
197 DECLCALLBACKMEMBER(int, pfnDestroy)(PRTZIPDECOMP pZip);
198
199 /** Compression type. */
200 RTZIPTYPE enmType;
201 /** Type specific data. */
202 union
203 {
204#ifdef RTZIP_USE_STORE
205 /** Simple storing. */
206 struct
207 {
208 /** Current buffer postition. (where to start read) */
209 uint8_t *pb;
210 /** Number of bytes left in the buffer. */
211 size_t cbBuffer;
212 } Store;
213#endif
214#ifdef RTZIP_USE_ZLIB
215 /** Zlib stream. */
216 z_stream Zlib;
217#endif
218#ifdef RTZIP_USE_BZLIB
219 /** BZlib stream. */
220 bz_stream BZlib;
221#endif
222#ifdef RTZIP_USE_LZF
223 /** LZF 'stream'. */
224 struct
225 {
226 /** Current input buffer postition. */
227 uint8_t *pbInput;
228 /** The number of bytes left in the input buffer. */
229 size_t cbInput;
230 /** The spill buffer.
231 * LZF is a block based compressor and not a stream compressor. So,
232 * we have to decompress full blocks if we want to get any of the data.
233 * This buffer is to store the spill after decompressing a block. */
234 uint8_t abSpill[RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE];
235 /** The number of bytes left spill buffer. */
236 unsigned cbSpill;
237 /** The current spill buffer position. */
238 uint8_t *pbSpill;
239 } LZF;
240#endif
241
242 } u;
243} RTZIPDECOM;
244
245
246
247#ifdef RTZIP_USE_STORE
248#include <stdio.h>
249
250/**
251 * @copydoc RTZipCompress
252 */
253static DECLCALLBACK(int) rtZipStoreCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
254{
255 uint8_t *pbDst = pZip->u.Store.pb;
256 while (cbBuf)
257 {
258 /*
259 * Flush.
260 */
261 size_t cb = sizeof(pZip->abBuffer) - (size_t)(pbDst - &pZip->abBuffer[0]); /* careful here, g++ 4.1.2 screws up easily */
262 if (cb == 0)
263 {
264 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer));
265 if (RT_FAILURE(rc))
266 return rc;
267
268 cb = sizeof(pZip->abBuffer);
269 pbDst = &pZip->abBuffer[0];
270 }
271
272 /*
273 * Add to the buffer and advance.
274 */
275 if (cbBuf < cb)
276 cb = cbBuf;
277 memcpy(pbDst, pvBuf, cb);
278
279 pbDst += cb;
280 cbBuf -= cb;
281 pvBuf = (uint8_t *)pvBuf + cb;
282 }
283 pZip->u.Store.pb = pbDst;
284 return VINF_SUCCESS;
285}
286
287
288/**
289 * @copydoc RTZipCompFinish
290 */
291static DECLCALLBACK(int) rtZipStoreCompFinish(PRTZIPCOMP pZip)
292{
293 size_t cb = (uintptr_t)pZip->u.Store.pb - (uintptr_t)&pZip->abBuffer[0];
294 if (cb > 0)
295 {
296 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
297 if (RT_FAILURE(rc))
298 return rc;
299 }
300 return VINF_SUCCESS;
301}
302
303
304/**
305 * @copydoc RTZipCompDestroy
306 */
307static DECLCALLBACK(int) rtZipStoreCompDestroy(PRTZIPCOMP pZip)
308{
309 return VINF_SUCCESS;
310}
311
312
313/**
314 * Initializes the compressor instance.
315 * @returns iprt status code.
316 * @param pZip The compressor instance.
317 * @param enmLevel The desired compression level.
318 */
319static DECLCALLBACK(int) rtZipStoreCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
320{
321 pZip->pfnCompress = rtZipStoreCompress;
322 pZip->pfnFinish = rtZipStoreCompFinish;
323 pZip->pfnDestroy = rtZipStoreCompDestroy;
324
325 pZip->u.Store.pb = &pZip->abBuffer[1];
326 return VINF_SUCCESS;
327}
328
329
330/**
331 * @copydoc RTZipDecompress
332 */
333static DECLCALLBACK(int) rtZipStoreDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
334{
335 size_t cbWritten = 0;
336 while (cbBuf)
337 {
338 /*
339 * Fill buffer.
340 */
341 size_t cb = pZip->u.Store.cbBuffer;
342 if (cb <= 0)
343 {
344 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
345 if (RT_FAILURE(rc))
346 return rc;
347 pZip->u.Store.cbBuffer = cb;
348 pZip->u.Store.pb = &pZip->abBuffer[0];
349 }
350
351 /*
352 * No more data?
353 */
354 if (cb == 0)
355 {
356 if (pcbWritten)
357 {
358 *pcbWritten = cbWritten;
359 return VINF_SUCCESS;
360 }
361 return VERR_NO_DATA;
362 }
363
364 /*
365 * Add to the buffer and advance.
366 */
367 if (cbBuf < cb)
368 cb = cbBuf;
369 memcpy(pvBuf, pZip->u.Store.pb, cb);
370 pZip->u.Store.pb += cb;
371 pZip->u.Store.cbBuffer -= cb;
372 cbBuf -= cb;
373 pvBuf = (char *)pvBuf + cb;
374 cbWritten += cb;
375 }
376 if (pcbWritten)
377 *pcbWritten = cbWritten;
378 return VINF_SUCCESS;
379}
380
381
382/**
383 * @copydoc RTZipDecompDestroy
384 */
385static DECLCALLBACK(int) rtZipStoreDecompDestroy(PRTZIPDECOMP pZip)
386{
387 return VINF_SUCCESS;
388}
389
390
391/**
392 * Initialize the decompressor instance.
393 * @returns iprt status code.
394 * @param pZip The decompressor instance.
395 */
396static DECLCALLBACK(int) rtZipStoreDecompInit(PRTZIPDECOMP pZip)
397{
398 pZip->pfnDecompress = rtZipStoreDecompress;
399 pZip->pfnDestroy = rtZipStoreDecompDestroy;
400
401 pZip->u.Store.pb = &pZip->abBuffer[0];
402 pZip->u.Store.cbBuffer = 0;
403 return VINF_SUCCESS;
404}
405
406#endif
407
408
409#ifdef RTZIP_USE_ZLIB
410/**
411 * Convert from zlib errno to iprt status code.
412 * @returns iprt status code.
413 * @param rc Zlib error code.
414 */
415static int zipErrConvertFromZlib(int rc)
416{
417 /** @todo proper zlib error convertion. */
418 switch (rc)
419 {
420 case Z_ERRNO:
421 return RTErrConvertFromErrno(errno);
422 case Z_STREAM_ERROR:
423 case Z_DATA_ERROR:
424 case Z_MEM_ERROR:
425 case Z_BUF_ERROR:
426 case Z_VERSION_ERROR:
427 return VERR_GENERAL_FAILURE;
428 default:
429 if (rc >= 0)
430 return VINF_SUCCESS;
431 return VERR_GENERAL_FAILURE;
432 }
433}
434
435
436/**
437 * @copydoc RTZipCompress
438 */
439static DECLCALLBACK(int) rtZipZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
440{
441 pZip->u.Zlib.next_in = (Bytef *)pvBuf;
442 pZip->u.Zlib.avail_in = (uInt)cbBuf; Assert(pZip->u.Zlib.avail_in == cbBuf);
443 while (pZip->u.Zlib.avail_in > 0)
444 {
445 /*
446 * Flush output buffer?
447 */
448 if (pZip->u.Zlib.avail_out <= 0)
449 {
450 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.Zlib.avail_out);
451 if (RT_FAILURE(rc))
452 return rc;
453 pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer);
454 pZip->u.Zlib.next_out = &pZip->abBuffer[0];
455 }
456
457 /*
458 * Pass it on to zlib.
459 */
460 int rc = deflate(&pZip->u.Zlib, Z_NO_FLUSH);
461 if (rc != Z_OK)
462 return zipErrConvertFromZlib(rc);
463 }
464 return VINF_SUCCESS;
465}
466
467
468/**
469 * @copydoc RTZipCompFinish
470 */
471static DECLCALLBACK(int) rtZipZlibCompFinish(PRTZIPCOMP pZip)
472{
473 int rc = Z_OK;
474 for (;;)
475 {
476 /*
477 * Flush outstanding stuff. writes.
478 */
479 if (rc == Z_STREAM_END || pZip->u.Zlib.avail_out <= 0)
480 {
481 int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.Zlib.avail_out);
482 if (RT_FAILURE(rc2))
483 return rc2;
484 pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer);
485 pZip->u.Zlib.next_out = &pZip->abBuffer[0];
486 if (rc == Z_STREAM_END)
487 return VINF_SUCCESS;
488 }
489
490 /*
491 * Tell zlib to flush.
492 */
493 rc = deflate(&pZip->u.Zlib, Z_FINISH);
494 if (rc != Z_OK && rc != Z_STREAM_END)
495 return zipErrConvertFromZlib(rc);
496 }
497 return VINF_SUCCESS;
498}
499
500
501/**
502 * @copydoc RTZipCompDestroy
503 */
504static DECLCALLBACK(int) rtZipZlibCompDestroy(PRTZIPCOMP pZip)
505{
506 /*
507 * Terminate the deflate instance.
508 */
509 int rc = deflateEnd(&pZip->u.Zlib);
510 if (rc != Z_OK)
511 rc = zipErrConvertFromZlib(rc);
512 return rc;
513}
514
515
516/**
517 * Initializes the compressor instance.
518 * @returns iprt status code.
519 * @param pZip The compressor instance.
520 * @param enmLevel The desired compression level.
521 */
522static DECLCALLBACK(int) rtZipZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
523{
524 pZip->pfnCompress = rtZipZlibCompress;
525 pZip->pfnFinish = rtZipZlibCompFinish;
526 pZip->pfnDestroy = rtZipZlibCompDestroy;
527
528 int iLevel = Z_DEFAULT_COMPRESSION;
529 switch (enmLevel)
530 {
531 case RTZIPLEVEL_STORE: iLevel = 0; break;
532 case RTZIPLEVEL_FAST: iLevel = 2; break;
533 case RTZIPLEVEL_DEFAULT: iLevel = Z_DEFAULT_COMPRESSION; break;
534 case RTZIPLEVEL_MAX: iLevel = 9; break;
535 }
536
537 memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
538 pZip->u.Zlib.next_out = &pZip->abBuffer[1];
539 pZip->u.Zlib.avail_out = sizeof(pZip->abBuffer) - 1;
540 pZip->u.Zlib.opaque = pZip;
541
542 int rc = deflateInit(&pZip->u.Zlib, enmLevel);
543 return rc >= 0 ? rc = VINF_SUCCESS : zipErrConvertFromZlib(rc);
544}
545
546
547/**
548 * @copydoc RTZipDecompress
549 */
550static DECLCALLBACK(int) rtZipZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
551{
552 pZip->u.Zlib.next_out = (Bytef *)pvBuf;
553 pZip->u.Zlib.avail_out = (uInt)cbBuf; Assert(pZip->u.Zlib.avail_out == cbBuf);
554 int rc = Z_OK;
555 /* Be greedy reading input, even if no output buffer is left. It's possible
556 * that it's just the end of stream marker which needs to be read. Happens
557 * for incompressible blocks just larger than the input buffer size.*/
558 while (pZip->u.Zlib.avail_out > 0 || pZip->u.Zlib.avail_in <= 0)
559 {
560 /*
561 * Read more input?
562 */
563 if (pZip->u.Zlib.avail_in <= 0)
564 {
565 size_t cb = sizeof(pZip->abBuffer);
566 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
567 if (RT_FAILURE(rc))
568 return rc;
569 pZip->u.Zlib.avail_in = (uInt)cb; Assert(pZip->u.Zlib.avail_in == cb);
570 pZip->u.Zlib.next_in = &pZip->abBuffer[0];
571 }
572
573 /*
574 * Pass it on to zlib.
575 */
576 rc = inflate(&pZip->u.Zlib, Z_NO_FLUSH);
577 if (rc == Z_STREAM_END)
578 {
579 if (pcbWritten)
580 *pcbWritten = cbBuf - pZip->u.Zlib.avail_out;
581 else if (pZip->u.Zlib.avail_out > 0)
582 return VERR_NO_DATA;
583 break;
584 }
585 if (rc != Z_OK)
586 return zipErrConvertFromZlib(rc);
587 }
588 return VINF_SUCCESS;
589}
590
591
592/**
593 * @copydoc RTZipDecompDestroy
594 */
595static DECLCALLBACK(int) rtZipZlibDecompDestroy(PRTZIPDECOMP pZip)
596{
597 /*
598 * Terminate the deflate instance.
599 */
600 int rc = inflateEnd(&pZip->u.Zlib);
601 if (rc != Z_OK)
602 rc = zipErrConvertFromZlib(rc);
603 return rc;
604}
605
606
607/**
608 * Initialize the decompressor instance.
609 * @returns iprt status code.
610 * @param pZip The decompressor instance.
611 */
612static DECLCALLBACK(int) rtZipZlibDecompInit(PRTZIPDECOMP pZip)
613{
614 pZip->pfnDecompress = rtZipZlibDecompress;
615 pZip->pfnDestroy = rtZipZlibDecompDestroy;
616
617 memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
618 pZip->u.Zlib.opaque = pZip;
619
620 int rc = inflateInit(&pZip->u.Zlib);
621 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromZlib(rc);
622}
623
624#endif
625
626
627#ifdef RTZIP_USE_BZLIB
628/**
629 * Convert from BZlib errno to iprt status code.
630 * @returns iprt status code.
631 * @param rc BZlib error code.
632 */
633static int zipErrConvertFromBZlib(int rc)
634{
635 /** @todo proper bzlib error convertion. */
636 switch (rc)
637 {
638 case BZ_SEQUENCE_ERROR:
639 AssertMsgFailed(("BZ_SEQUENCE_ERROR shall not happen!\n"));
640 return VERR_GENERAL_FAILURE;
641 case BZ_PARAM_ERROR:
642 return VERR_INVALID_PARAMETER;
643 case BZ_MEM_ERROR:
644 return VERR_NO_MEMORY;
645 case BZ_DATA_ERROR:
646 case BZ_DATA_ERROR_MAGIC:
647 case BZ_IO_ERROR:
648 case BZ_UNEXPECTED_EOF:
649 case BZ_CONFIG_ERROR:
650 return VERR_GENERAL_FAILURE;
651 case BZ_OUTBUFF_FULL:
652 AssertMsgFailed(("BZ_OUTBUFF_FULL shall not happen!\n"));
653 return VERR_GENERAL_FAILURE;
654 default:
655 if (rc >= 0)
656 return VINF_SUCCESS;
657 return VERR_GENERAL_FAILURE;
658 }
659}
660
661
662/**
663 * @copydoc RTZipCompress
664 */
665static DECLCALLBACK(int) rtZipBZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
666{
667 pZip->u.BZlib.next_in = (char *)pvBuf;
668 pZip->u.BZlib.avail_in = cbBuf;
669 while (pZip->u.BZlib.avail_in > 0)
670 {
671 /*
672 * Flush output buffer?
673 */
674 if (pZip->u.BZlib.avail_out <= 0)
675 {
676 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
677 if (RT_FAILURE(rc))
678 return rc;
679 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
680 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
681 }
682
683 /*
684 * Pass it on to zlib.
685 */
686 int rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_RUN);
687 if (rc < 0 && rc != BZ_OUTBUFF_FULL)
688 return zipErrConvertFromBZlib(rc);
689 }
690 return VINF_SUCCESS;
691}
692
693
694/**
695 * @copydoc RTZipCompFinish
696 */
697static DECLCALLBACK(int) rtZipBZlibCompFinish(PRTZIPCOMP pZip)
698{
699 int rc = BZ_FINISH_OK;
700 for (;;)
701 {
702 /*
703 * Flush output buffer?
704 */
705 if (rc == BZ_STREAM_END || pZip->u.BZlib.avail_out <= 0)
706 {
707 int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
708 if (RT_FAILURE(rc2))
709 return rc2;
710 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
711 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
712 if (rc == BZ_STREAM_END)
713 return VINF_SUCCESS;
714 }
715
716 /*
717 * Tell BZlib to finish it.
718 */
719 rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_FINISH);
720 if (rc < 0 && rc != BZ_OUTBUFF_FULL)
721 return zipErrConvertFromBZlib(rc);
722 }
723 return VINF_SUCCESS;
724}
725
726
727/**
728 * @copydoc RTZipCompDestroy
729 */
730static DECLCALLBACK(int) rtZipBZlibCompDestroy(PRTZIPCOMP pZip)
731{
732 /*
733 * Terminate the deflate instance.
734 */
735 int rc = BZ2_bzCompressEnd(&pZip->u.BZlib);
736 if (rc != BZ_OK)
737 rc = zipErrConvertFromBZlib(rc);
738 return rc;
739}
740
741
742/**
743 * Initializes the compressor instance.
744 * @returns iprt status code.
745 * @param pZip The compressor instance.
746 * @param enmLevel The desired compression level.
747 */
748static DECLCALLBACK(int) rtZipBZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
749{
750 pZip->pfnCompress = rtZipBZlibCompress;
751 pZip->pfnFinish = rtZipBZlibCompFinish;
752 pZip->pfnDestroy = rtZipBZlibCompDestroy;
753
754 int iSize = 6;
755 int iWork = 0;
756 switch (enmLevel)
757 {
758 case RTZIPLEVEL_STORE: iSize = 1; iWork = 2; break;
759 case RTZIPLEVEL_FAST: iSize = 2; iWork = 0; break;
760 case RTZIPLEVEL_DEFAULT: iSize = 5; iWork = 0; break;
761 case RTZIPLEVEL_MAX: iSize = 9; iWork = 0; break;
762 }
763
764 memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
765 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[1];
766 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer) - 1;
767 pZip->u.BZlib.opaque = pZip;
768
769 int rc = BZ2_bzCompressInit(&pZip->u.BZlib, iSize, 0, iWork);
770 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);;
771}
772
773
774/**
775 * @copydoc RTZipDecompress
776 */
777static DECLCALLBACK(int) rtZipBZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
778{
779 pZip->u.BZlib.next_out = (char *)pvBuf;
780 pZip->u.BZlib.avail_out = cbBuf;
781 while (pZip->u.BZlib.avail_out > 0)
782 {
783 /*
784 * Read more output buffer?
785 */
786 if (pZip->u.BZlib.avail_in <= 0)
787 {
788 size_t cb;
789 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
790 if (RT_FAILURE(rc))
791 return rc;
792 pZip->u.BZlib.avail_in = cb;
793 pZip->u.BZlib.next_in = (char *)&pZip->abBuffer[0];
794 }
795
796 /*
797 * Pass it on to zlib.
798 */
799 int rc = BZ2_bzDecompress(&pZip->u.BZlib);
800 if (rc == BZ_STREAM_END || rc == BZ_OUTBUFF_FULL)
801 {
802 if (pcbWritten)
803 *pcbWritten = cbBuf - pZip->u.BZlib.avail_out;
804 else if (pZip->u.BZlib.avail_out > 0)
805 return VERR_NO_DATA;
806 break;
807 }
808 if (rc < 0)
809 return zipErrConvertFromBZlib(rc);
810 }
811 return VINF_SUCCESS;
812}
813
814
815/**
816 * @copydoc RTZipDecompDestroy
817 */
818static DECLCALLBACK(int) rtZipBZlibDecompDestroy(PRTZIPDECOMP pZip)
819{
820 /*
821 * Terminate the deflate instance.
822 */
823 int rc = BZ2_bzDecompressEnd(&pZip->u.BZlib);
824 if (rc != BZ_OK)
825 rc = zipErrConvertFromBZlib(rc);
826 return rc;
827}
828
829
830/**
831 * Initialize the decompressor instance.
832 * @returns iprt status code.
833 * @param pZip The decompressor instance.
834 */
835static DECLCALLBACK(int) rtZipBZlibDecompInit(PRTZIPDECOMP pZip)
836{
837 pZip->pfnDecompress = rtZipBZlibDecompress;
838 pZip->pfnDestroy = rtZipBZlibDecompDestroy;
839
840 memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
841 pZip->u.BZlib.opaque = pZip;
842
843 int rc = BZ2_bzDecompressInit(&pZip->u.BZlib, 0, 0);
844 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);
845}
846
847#endif
848
849
850#ifdef RTZIP_USE_LZF
851
852/**
853 * Flushes the output buffer.
854 * @returns iprt status code.
855 * @param pZip The compressor instance.
856 */
857static int rtZipLZFCompFlushOutput(PRTZIPCOMP pZip)
858{
859 size_t cb = pZip->u.LZF.pbOutput - &pZip->abBuffer[0];
860 pZip->u.LZF.pbOutput = &pZip->abBuffer[0];
861 return pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
862}
863
864
865/**
866 * Compresses a buffer using LZF.
867 *
868 * @returns VBox status code.
869 * @param pZip The compressor instance.
870 * @param pbBuf What to compress.
871 * @param cbBuf How much to compress.
872 */
873static int rtZipLZFCompressBuffer(PRTZIPCOMP pZip, const uint8_t *pbBuf, size_t cbBuf)
874{
875 bool fForceFlush = false;
876 while (cbBuf > 0)
877 {
878 /*
879 * Flush output buffer?
880 */
881 unsigned cbFree = (unsigned)(sizeof(pZip->abBuffer) - (pZip->u.LZF.pbOutput - &pZip->abBuffer[0]));
882 if ( fForceFlush
883 || cbFree < RTZIPLZF_MAX_DATA_SIZE + sizeof(RTZIPLZFHDR))
884 {
885 int rc = rtZipLZFCompFlushOutput(pZip);
886 if (RT_FAILURE(rc))
887 return rc;
888 fForceFlush = false;
889 cbFree = sizeof(pZip->abBuffer);
890 }
891
892 /*
893 * Setup the block header.
894 */
895 PRTZIPLZFHDR pHdr = (PRTZIPLZFHDR)pZip->u.LZF.pbOutput; /* warning: This might be unaligned! */
896 pHdr->u16Magic = RTZIPLZFHDR_MAGIC;
897 pHdr->cbData = 0;
898 pHdr->u32CRC = 0;
899 pHdr->cbUncompressed = 0;
900 cbFree -= sizeof(*pHdr);
901 pZip->u.LZF.pbOutput += sizeof(*pHdr);
902
903 /*
904 * Compress data for the block.
905 *
906 * We try compress as much as we have freespace for at first,
907 * but if it turns out the compression is inefficient, we'll
908 * reduce the size of data we try compress till it fits the
909 * output space.
910 */
911 cbFree = RT_MIN(cbFree, RTZIPLZF_MAX_DATA_SIZE);
912 unsigned cbInput = (unsigned)RT_MIN(RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE, cbBuf);
913 unsigned cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
914 if (!cbOutput)
915 {
916 /** @todo add an alternative method which stores the raw data if bad compression. */
917 do
918 {
919 cbInput /= 2;
920 if (!cbInput)
921 {
922 AssertMsgFailed(("lzf_compress bug! cbFree=%zu\n", cbFree));
923 return VERR_INTERNAL_ERROR;
924 }
925 cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
926 } while (!cbOutput);
927 fForceFlush = true;
928 }
929
930 /*
931 * Upate the header and advance the input buffer.
932 */
933 pHdr->cbData = cbOutput;
934 //pHdr->u32CRC = RTCrc32(pbBuf, cbInput); - too slow
935 pHdr->cbUncompressed = cbInput;
936
937 pZip->u.LZF.pbOutput += cbOutput;
938 cbBuf -= cbInput;
939 pbBuf += cbInput;
940 }
941 return VINF_SUCCESS;
942}
943
944
945/**
946 * Flushes the input buffer.
947 * @returns iprt status code.
948 * @param pZip The compressor instance.
949 */
950static int rtZipLZFCompFlushInput(PRTZIPCOMP pZip)
951{
952 size_t cb = pZip->u.LZF.pbInput - &pZip->u.LZF.abInput[0];
953 pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
954 pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
955 if (cb)
956 return rtZipLZFCompressBuffer(pZip, pZip->u.LZF.abInput, cb);
957 return VINF_SUCCESS;
958}
959
960
961/**
962 * @copydoc RTZipCompress
963 */
964static DECLCALLBACK(int) rtZipLZFCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
965{
966#define RTZIPLZF_SMALL_CHUNK (128)
967
968 /*
969 * Flush the input buffer if necessary.
970 */
971 if ( ( cbBuf <= RTZIPLZF_SMALL_CHUNK
972 && cbBuf > pZip->u.LZF.cbInputFree)
973 || ( cbBuf > RTZIPLZF_SMALL_CHUNK
974 && pZip->u.LZF.cbInputFree != sizeof(pZip->u.LZF.abInput))
975 )
976 {
977 int rc = rtZipLZFCompFlushInput(pZip);
978 if (RT_FAILURE(rc))
979 return rc;
980 }
981
982 /*
983 * If it's a relativly small block put it in the input buffer, elsewise
984 * compress directly it.
985 */
986 if (cbBuf <= RTZIPLZF_SMALL_CHUNK)
987 {
988 Assert(pZip->u.LZF.cbInputFree >= cbBuf);
989 memcpy(pZip->u.LZF.pbInput, pvBuf, cbBuf);
990 pZip->u.LZF.pbInput += cbBuf;
991 pZip->u.LZF.cbInputFree -= cbBuf;
992 }
993 else
994 {
995 Assert(pZip->u.LZF.cbInputFree == sizeof(pZip->u.LZF.abInput));
996 int rc = rtZipLZFCompressBuffer(pZip, (const uint8_t *)pvBuf, cbBuf);
997 if (RT_FAILURE(rc))
998 return rc;
999 }
1000 return VINF_SUCCESS;
1001}
1002
1003
1004/**
1005 * @copydoc RTZipCompFinish
1006 */
1007static DECLCALLBACK(int) rtZipLZFCompFinish(PRTZIPCOMP pZip)
1008{
1009 int rc = rtZipLZFCompFlushInput(pZip);
1010 if (RT_SUCCESS(rc))
1011 rc = rtZipLZFCompFlushOutput(pZip);
1012 return rc;
1013}
1014
1015
1016/**
1017 * @copydoc RTZipCompDestroy
1018 */
1019static DECLCALLBACK(int) rtZipLZFCompDestroy(PRTZIPCOMP pZip)
1020{
1021 return VINF_SUCCESS;
1022}
1023
1024
1025/**
1026 * Initializes the compressor instance.
1027 * @returns iprt status code.
1028 * @param pZip The compressor instance.
1029 * @param enmLevel The desired compression level.
1030 */
1031static DECLCALLBACK(int) rtZipLZFCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
1032{
1033 pZip->pfnCompress = rtZipLZFCompress;
1034 pZip->pfnFinish = rtZipLZFCompFinish;
1035 pZip->pfnDestroy = rtZipLZFCompDestroy;
1036
1037 pZip->u.LZF.pbOutput = &pZip->abBuffer[1];
1038 pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
1039 pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
1040 return VINF_SUCCESS;
1041}
1042
1043
1044/**
1045 * This will validate a header and to all the necessary bitching if it's invalid.
1046 * @returns true if valid.
1047 * @returns false if invalid.
1048 * @param pHdr Pointer to the header.\
1049 */
1050static bool rtZipLZFValidHeader(PCRTZIPLZFHDR pHdr)
1051{
1052 if ( pHdr->u16Magic != RTZIPLZFHDR_MAGIC
1053 || !pHdr->cbData
1054 || pHdr->cbData > RTZIPLZF_MAX_DATA_SIZE
1055 || !pHdr->cbUncompressed
1056 || pHdr->cbUncompressed > RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE
1057 )
1058 {
1059 AssertMsgFailed(("Invalid LZF header! %.*%Rhxs\n", sizeof(pHdr), pHdr));
1060 return false;
1061 }
1062 return true;
1063}
1064
1065
1066/**
1067 * @copydoc RTZipDecompress
1068 */
1069static DECLCALLBACK(int) rtZipLZFDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1070{
1071 /*
1072 * Decompression loop.
1073 *
1074 * This a bit ugly because we have to deal with reading block...
1075 * To simplify matters we've put a max block size and will never
1076 * fill the input buffer with more than allows us to complete
1077 * any partially read blocks.
1078 *
1079 * When possible we decompress directly to the user buffer, when
1080 * not possible we'll use the spill buffer.
1081 */
1082 while (cbBuf > 0)
1083 {
1084 /*
1085 * Anything in the spill buffer?
1086 */
1087 if (pZip->u.LZF.cbSpill > 0)
1088 {
1089 unsigned cb = (unsigned)RT_MIN(pZip->u.LZF.cbSpill, cbBuf);
1090 memcpy(pvBuf, pZip->u.LZF.pbSpill, cb);
1091 pZip->u.LZF.pbSpill += cb;
1092 pZip->u.LZF.cbSpill -= cb;
1093 cbBuf -= cb;
1094 if (pcbWritten)
1095 *pcbWritten = cb;
1096 if (!cbBuf)
1097 break;
1098 pvBuf = (uint8_t *)pvBuf + cb;
1099 }
1100
1101 /*
1102 * Incomplete header or nothing at all.
1103 */
1104 PCRTZIPLZFHDR pHdr;
1105 if (pZip->u.LZF.cbInput < sizeof(RTZIPLZFHDR))
1106 {
1107 if (pZip->u.LZF.cbInput <= 0)
1108 {
1109 /* empty, fill the buffer. */
1110 size_t cb = 0;
1111 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0],
1112 sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE, &cb);
1113 if (RT_FAILURE(rc))
1114 return rc;
1115 pZip->u.LZF.pbInput = &pZip->abBuffer[0];
1116 pZip->u.LZF.cbInput = cb;
1117 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1118 }
1119 else
1120 {
1121 /* move the header up and fill the buffer. */
1122 size_t cbCur = pZip->u.LZF.cbInput;
1123 memmove(&pZip->abBuffer[0], pZip->u.LZF.pbInput, cbCur);
1124 pZip->u.LZF.pbInput = &pZip->abBuffer[0];
1125
1126 size_t cb = 0;
1127 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[cbCur],
1128 sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE - cbCur, &cb);
1129 if (RT_FAILURE(rc))
1130 return rc;
1131 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1132 pZip->u.LZF.cbInput += cb;
1133 }
1134
1135 /*
1136 * Validate the header.
1137 */
1138 if (!rtZipLZFValidHeader(pHdr))
1139 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1140 }
1141 else
1142 {
1143 /*
1144 * Validate the header and check if it's an incomplete block.
1145 */
1146 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1147 if (!rtZipLZFValidHeader(pHdr))
1148 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1149
1150 if (pHdr->cbData > pZip->u.LZF.cbInput - sizeof(*pHdr))
1151 {
1152 /* read the remainder of the block. */
1153 size_t cbToRead = pHdr->cbData - (pZip->u.LZF.cbInput - sizeof(*pHdr));
1154 Assert(&pZip->u.LZF.pbInput[pZip->u.LZF.cbInput + cbToRead] <= &pZip->u.LZF.pbInput[sizeof(pZip->abBuffer)]);
1155 int rc = pZip->pfnIn(pZip->pvUser, &pZip->u.LZF.pbInput[pZip->u.LZF.cbInput],
1156 cbToRead, NULL);
1157 if (RT_FAILURE(rc))
1158 return rc;
1159 pZip->u.LZF.cbInput += cbToRead;
1160 }
1161 }
1162 AssertMsgReturn(sizeof(*pHdr) + pHdr->cbData <= pZip->u.LZF.cbInput,
1163 ("cbData=%#x cbInput=%#x\n", pHdr->cbData, pZip->u.LZF.cbInput),
1164 VERR_GENERAL_FAILURE); /** @todo Get better error codes for RTZip! */
1165
1166 /*
1167 * Does the uncompressed data fit into the supplied buffer?
1168 * If so we uncompress it directly into the user buffer, else we'll have to use the spill buffer.
1169 */
1170 unsigned cbUncompressed = pHdr->cbUncompressed;
1171 if (cbUncompressed <= cbBuf)
1172 {
1173 unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pvBuf, cbUncompressed);
1174 if (cbOutput != cbUncompressed)
1175 {
1176 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1177 errno, cbOutput, cbUncompressed));
1178 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1179 }
1180 cbBuf -= cbUncompressed;
1181 pvBuf = (uint8_t *)pvBuf + cbUncompressed;
1182 }
1183 else
1184 {
1185 unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pZip->u.LZF.abSpill, cbUncompressed);
1186 if (cbOutput != cbUncompressed)
1187 {
1188 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1189 errno, cbOutput, cbUncompressed));
1190 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1191 }
1192 pZip->u.LZF.pbSpill = &pZip->u.LZF.abSpill[0];
1193 pZip->u.LZF.cbSpill = cbUncompressed;
1194 }
1195
1196 /* advance the input buffer */
1197 pZip->u.LZF.cbInput -= pHdr->cbData + sizeof(*pHdr);
1198 pZip->u.LZF.pbInput += pHdr->cbData + sizeof(*pHdr);
1199 if (pcbWritten)
1200 *pcbWritten += cbUncompressed;
1201 }
1202
1203 return VINF_SUCCESS;
1204}
1205
1206
1207/**
1208 * @copydoc RTZipDecompDestroy
1209 */
1210static DECLCALLBACK(int) rtZipLZFDecompDestroy(PRTZIPDECOMP pZip)
1211{
1212 return VINF_SUCCESS;
1213}
1214
1215
1216/**
1217 * Initalize the decompressor instance.
1218 * @returns iprt status code.
1219 * @param pZip The decompressor instance.
1220 */
1221static DECLCALLBACK(int) rtZipLZFDecompInit(PRTZIPDECOMP pZip)
1222{
1223 pZip->pfnDecompress = rtZipLZFDecompress;
1224 pZip->pfnDestroy = rtZipLZFDecompDestroy;
1225
1226 pZip->u.LZF.pbInput = NULL;
1227 pZip->u.LZF.cbInput = 0;
1228 pZip->u.LZF.cbSpill = 0;
1229 pZip->u.LZF.pbSpill = NULL;
1230
1231 return VINF_SUCCESS;
1232}
1233
1234#endif /* RTZIP_USE_LZF */
1235
1236
1237/**
1238 * Create a compressor instance.
1239 *
1240 * @returns iprt status code.
1241 * @param ppZip Where to store the instance handle.
1242 * @param pvUser User argument which will be passed on to pfnOut and pfnIn.
1243 * @param pfnOut Callback for consuming output of compression.
1244 * @param enmType Type of compressor to create.
1245 * @param enmLevel Compression level.
1246 */
1247RTDECL(int) RTZipCompCreate(PRTZIPCOMP *ppZip, void *pvUser, PFNRTZIPOUT pfnOut, RTZIPTYPE enmType, RTZIPLEVEL enmLevel)
1248{
1249 /*
1250 * Validate input.
1251 */
1252 if ( enmType < RTZIPTYPE_AUTO
1253 || enmType > RTZIPTYPE_LZF)
1254 {
1255 AssertMsgFailed(("Invalid enmType=%d\n", enmType));
1256 return VERR_INVALID_PARAMETER;
1257 }
1258 if ( enmLevel < RTZIPLEVEL_STORE
1259 || enmLevel > RTZIPLEVEL_MAX)
1260 {
1261 AssertMsgFailed(("Invalid enmLevel=%d\n", enmLevel));
1262 return VERR_INVALID_PARAMETER;
1263 }
1264 if (!pfnOut || !ppZip)
1265 {
1266 AssertMsgFailed(("Must supply pfnOut and ppZip!\n"));
1267 return VERR_INVALID_PARAMETER;
1268 }
1269
1270 /*
1271 * Allocate memory for the instance data.
1272 */
1273 PRTZIPCOMP pZip = (PRTZIPCOMP)RTMemAlloc(sizeof(RTZIPCOMP));
1274 if (!pZip)
1275 return VERR_NO_MEMORY;
1276
1277 /*
1278 * Determin auto type.
1279 */
1280 if (enmType == RTZIPTYPE_AUTO)
1281 {
1282 if (enmLevel == RTZIPLEVEL_STORE)
1283 enmType = RTZIPTYPE_STORE;
1284 else
1285 {
1286#if defined(RTZIP_USE_ZLIB) && defined(RTZIP_USE_BZLIB)
1287 if (enmLevel == RTZIPLEVEL_MAX)
1288 enmType = RTZIPTYPE_BZLIB;
1289 else
1290 enmType = RTZIPTYPE_ZLIB;
1291#elif defined(RTZIP_USE_ZLIB)
1292 enmType = RTZIPTYPE_ZLIB;
1293#elif defined(RTZIP_USE_BZLIB)
1294 enmType = RTZIPTYPE_BZLIB;
1295#else
1296 enmType = RTZIPTYPE_STORE;
1297#endif
1298 }
1299 }
1300
1301 /*
1302 * Init instance.
1303 */
1304 pZip->pfnOut = pfnOut;
1305 pZip->enmType = enmType;
1306 pZip->pvUser = pvUser;
1307 pZip->abBuffer[0] = enmType; /* first byte is the compression type. */
1308 int rc = VINF_SUCCESS;
1309 switch (enmType)
1310 {
1311#ifdef RTZIP_USE_STORE
1312 case RTZIPTYPE_STORE:
1313 rc = rtZipStoreCompInit(pZip, enmLevel);
1314 break;
1315#endif
1316
1317#ifdef RTZIP_USE_ZLIB
1318 case RTZIPTYPE_ZLIB:
1319 rc = rtZipZlibCompInit(pZip, enmLevel);
1320 break;
1321#endif
1322
1323#ifdef RTZIP_USE_BZLIB
1324 case RTZIPTYPE_BZLIB:
1325 rc = rtZipBZlibCompInit(pZip, enmLevel);
1326 break;
1327#endif
1328
1329#ifdef RTZIP_USE_LZF
1330 case RTZIPTYPE_LZF:
1331 rc = rtZipLZFCompInit(pZip, enmLevel);
1332 break;
1333#endif
1334
1335 default:
1336 AssertMsgFailed(("Not implemented!\n"));
1337 rc = VERR_NOT_IMPLEMENTED;
1338 break;
1339 }
1340
1341 if (RT_SUCCESS(rc))
1342 *ppZip = pZip;
1343 else
1344 RTMemFree(pZip);
1345 return rc;
1346}
1347RT_EXPORT_SYMBOL(RTZipCompCreate);
1348
1349
1350/**
1351 * Compresses a chunk of memory.
1352 *
1353 * @returns iprt status code.
1354 * @param pZip The compressor instance.
1355 * @param pvBuf Pointer to buffer containing the bits to compress.
1356 * @param cbBuf Number of bytes to compress.
1357 */
1358RTDECL(int) RTZipCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
1359{
1360 if (!cbBuf)
1361 return VINF_SUCCESS;
1362 return pZip->pfnCompress(pZip, pvBuf, cbBuf);
1363}
1364RT_EXPORT_SYMBOL(RTZipCompress);
1365
1366
1367/**
1368 * Finishes the compression.
1369 * This will flush all data and terminate the compression data stream.
1370 *
1371 * @returns iprt status code.
1372 * @param pZip The compressor instance.
1373 */
1374RTDECL(int) RTZipCompFinish(PRTZIPCOMP pZip)
1375{
1376 return pZip->pfnFinish(pZip);
1377}
1378RT_EXPORT_SYMBOL(RTZipCompFinish);
1379
1380
1381/**
1382 * Destroys the compressor instance.
1383 *
1384 * @returns iprt status code.
1385 * @param pZip The compressor instance.
1386 */
1387RTDECL(int) RTZipCompDestroy(PRTZIPCOMP pZip)
1388{
1389 /*
1390 * Compressor specific destruction attempt first.
1391 */
1392 int rc = pZip->pfnDestroy(pZip);
1393 AssertRCReturn(rc, rc);
1394
1395 /*
1396 * Free the instance memory.
1397 */
1398 pZip->enmType = RTZIPTYPE_INVALID;
1399 RTMemFree(pZip);
1400 return VINF_SUCCESS;
1401}
1402RT_EXPORT_SYMBOL(RTZipCompDestroy);
1403
1404
1405/**
1406 * @copydoc RTZipDecompress
1407 */
1408static DECLCALLBACK(int) rtZipStubDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1409{
1410 return VERR_NOT_SUPPORTED;
1411}
1412
1413
1414/**
1415 * @copydoc RTZipDecompDestroy
1416 */
1417static DECLCALLBACK(int) rtZipStubDecompDestroy(PRTZIPDECOMP pZip)
1418{
1419 return VINF_SUCCESS;
1420}
1421
1422
1423/**
1424 * Create a decompressor instance.
1425 *
1426 * @returns iprt status code.
1427 * @param ppZip Where to store the instance handle.
1428 * @param pvUser User argument which will be passed on to pfnOut and pfnIn.
1429 * @param pfnIn Callback for producing input for decompression.
1430 */
1431RTDECL(int) RTZipDecompCreate(PRTZIPDECOMP *ppZip, void *pvUser, PFNRTZIPIN pfnIn)
1432{
1433 /*
1434 * Validate input.
1435 */
1436 if (!pfnIn || !ppZip)
1437 {
1438 AssertMsgFailed(("Must supply pfnIn and ppZip!\n"));
1439 return VERR_INVALID_PARAMETER;
1440 }
1441
1442 /*
1443 * Allocate memory for the instance data.
1444 */
1445 PRTZIPDECOMP pZip = (PRTZIPDECOMP)RTMemAlloc(sizeof(RTZIPDECOMP));
1446 if (!pZip)
1447 return VERR_NO_MEMORY;
1448
1449 /*
1450 * Init instance.
1451 */
1452 pZip->pfnIn = pfnIn;
1453 pZip->enmType = RTZIPTYPE_INVALID;
1454 pZip->pvUser = pvUser;
1455 pZip->pfnDecompress = NULL;
1456 pZip->pfnDestroy = rtZipStubDecompDestroy;
1457
1458 *ppZip = pZip;
1459 return VINF_SUCCESS;
1460}
1461RT_EXPORT_SYMBOL(RTZipDecompCreate);
1462
1463
1464/**
1465 * Lazy init of the decompressor.
1466 * @returns iprt status code.
1467 * @param pZip The decompressor instance.
1468 */
1469static int rtzipDecompInit(PRTZIPDECOMP pZip)
1470{
1471 /*
1472 * Read the first byte from the stream so we can determin the type.
1473 */
1474 uint8_t u8Type;
1475 int rc = pZip->pfnIn(pZip->pvUser, &u8Type, sizeof(u8Type), NULL);
1476 if (RT_FAILURE(rc))
1477 return rc;
1478
1479 /*
1480 * Determin type and do type specific init.
1481 */
1482 pZip->enmType = (RTZIPTYPE)u8Type;
1483 switch (pZip->enmType)
1484 {
1485#ifdef RTZIP_USE_STORE
1486 case RTZIPTYPE_STORE:
1487 rc = rtZipStoreDecompInit(pZip);
1488 break;
1489#endif
1490
1491 case RTZIPTYPE_ZLIB:
1492#ifdef RTZIP_USE_ZLIB
1493 rc = rtZipZlibDecompInit(pZip);
1494#else
1495 AssertMsgFailedReturn(("Zlib is not include in this build!\n"), VERR_NOT_IMPLEMENTED);
1496#endif
1497 break;
1498
1499 case RTZIPTYPE_BZLIB:
1500#ifdef RTZIP_USE_BZLIB
1501 rc = rtZipBZlibDecompInit(pZip);
1502#else
1503 AssertMsgFailedReturn(("BZlib is not include in this build!\n"), VERR_NOT_IMPLEMENTED);
1504#endif
1505 break;
1506
1507 case RTZIPTYPE_LZF:
1508#ifdef RTZIP_USE_LZF
1509 rc = rtZipLZFDecompInit(pZip);
1510#else
1511 AssertMsgFailedReturn(("LZF is not include in this build!\n"), VERR_NOT_IMPLEMENTED);
1512#endif
1513 break;
1514
1515 case RTZIPTYPE_INVALID:
1516 AssertMsgFailed(("Invalid compression type RTZIPTYPE_INVALID!\n"));
1517 rc = VERR_NOT_IMPLEMENTED;
1518 break;
1519
1520 case RTZIPTYPE_AUTO:
1521 AssertMsgFailed(("Invalid compression type RTZIPTYPE_AUTO!\n"));
1522 rc = VERR_INVALID_MAGIC;
1523 break;
1524
1525 default:
1526 AssertMsgFailed(("Unknown compression type %d\n\n", pZip->enmType));
1527 rc = VERR_INVALID_MAGIC;
1528 break;
1529 }
1530 if (RT_FAILURE(rc))
1531 {
1532 pZip->pfnDecompress = rtZipStubDecompress;
1533 pZip->pfnDestroy = rtZipStubDecompDestroy;
1534 }
1535
1536 return rc;
1537}
1538
1539/**
1540 * Decompresses a chunk of memory.
1541 *
1542 * @returns iprt status code.
1543 * @param pZip The decompressor instance.
1544 * @param pvBuf Where to store the decompressed data.
1545 * @param cbBuf Number of bytes to produce. If pcbWritten is set
1546 * any number of bytes up to cbBuf might be returned.
1547 * @param pcbWritten Number of bytes actually written to the buffer. If NULL
1548 * cbBuf number of bytes must be written.
1549 */
1550RTDECL(int) RTZipDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1551{
1552 /*
1553 * Skip empty requests.
1554 */
1555 if (!cbBuf)
1556 return VINF_SUCCESS;
1557
1558 /*
1559 * Lazy init.
1560 */
1561 if (!pZip->pfnDecompress)
1562 {
1563 int rc = rtzipDecompInit(pZip);
1564 if (RT_FAILURE(rc))
1565 return rc;
1566 }
1567
1568 /*
1569 * 'Read' the decompressed stream.
1570 */
1571 return pZip->pfnDecompress(pZip, pvBuf, cbBuf, pcbWritten);
1572}
1573RT_EXPORT_SYMBOL(RTZipDecompress);
1574
1575
1576/**
1577 * Destroys the decompressor instance.
1578 *
1579 * @returns iprt status code.
1580 * @param pZip The decompressor instance.
1581 */
1582RTDECL(int) RTZipDecompDestroy(PRTZIPDECOMP pZip)
1583{
1584 /*
1585 * Destroy compressor instance and flush the output buffer.
1586 */
1587 int rc = pZip->pfnDestroy(pZip);
1588 AssertRCReturn(rc, rc);
1589
1590 /*
1591 * Free the instance memory.
1592 */
1593 pZip->enmType = RTZIPTYPE_INVALID;
1594 RTMemFree(pZip);
1595 return rc;
1596}
1597RT_EXPORT_SYMBOL(RTZipDecompDestroy);
1598
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette