VirtualBox

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

Last change on this file since 7709 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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