VirtualBox

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

Last change on this file since 39627 was 39083, checked in by vboxsync, 13 years ago

IPRT: -Wunused-parameter.

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