VirtualBox

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

Last change on this file since 16291 was 16164, checked in by vboxsync, 16 years ago

rtZipStoreCompress: g++ (GCC) 4.1.2 (Gentoo 4.1.2 p1.1) generates incorrect code if '(uintptr_t)&pZip->abBuffer[sizeof(pZip->abBuffer)] - (uintptr_t)pZip->u.Store.pb' is used to calc remaining buffer space, 'sizeof(pZip->abBuffer) - (size_t)(pbDst - &pZip->abBuffer[0])' seems to work though. (It was looping endlessly, with cb=0, seems it had figured that the branch wasn't gonna be taken then.)

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