VirtualBox

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

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

IPRT: RTZipBlock for block compression.

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