VirtualBox

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

Last change on this file since 11280 was 8245, checked in by vboxsync, 17 years ago

rebranding: IPRT files again.

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