VirtualBox

source: vbox/trunk/src/VBox/Runtime/zip.cpp@ 5005

Last change on this file since 5005 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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