VirtualBox

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

Last change on this file since 48242 was 47516, checked in by vboxsync, 11 years ago

Backed out r87679: Still working on the wrong solution... Sigh.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 54.0 KB
Line 
1/* $Id: zip.cpp 47516 2013-08-01 18:33:39Z vboxsync $ */
2/** @file
3 * IPRT - Compression.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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, iLevel);
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;
578 Assert(pZip->u.Zlib.avail_out == cbBuf);
579
580 /*
581 * Be greedy reading input, even if no output buffer is left. It's possible
582 * that it's just the end of stream marker which needs to be read. Happens
583 * for incompressible blocks just larger than the input buffer size.
584 */
585 while (pZip->u.Zlib.avail_out > 0 || pZip->u.Zlib.avail_in <= 0)
586 {
587 /*
588 * Read more input?
589 */
590 if (pZip->u.Zlib.avail_in <= 0)
591 {
592 size_t cb = sizeof(pZip->abBuffer);
593 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
594 if (RT_FAILURE(rc))
595 return rc;
596 pZip->u.Zlib.avail_in = (uInt)cb; Assert(pZip->u.Zlib.avail_in == cb);
597 pZip->u.Zlib.next_in = &pZip->abBuffer[0];
598 }
599
600 /*
601 * Pass it on to zlib.
602 */
603 int rc = inflate(&pZip->u.Zlib, Z_NO_FLUSH);
604 if (rc == Z_STREAM_END)
605 {
606 if (pcbWritten)
607 *pcbWritten = cbBuf - pZip->u.Zlib.avail_out;
608 else if (pZip->u.Zlib.avail_out > 0)
609 return VERR_NO_DATA;
610 break;
611 }
612 if (rc != Z_OK)
613 return zipErrConvertFromZlib(rc, false /*fCompressing*/);
614 }
615 return VINF_SUCCESS;
616}
617
618
619/**
620 * @copydoc RTZipDecompDestroy
621 */
622static DECLCALLBACK(int) rtZipZlibDecompDestroy(PRTZIPDECOMP pZip)
623{
624 /*
625 * Terminate the deflate instance.
626 */
627 int rc = inflateEnd(&pZip->u.Zlib);
628 if (rc != Z_OK)
629 rc = zipErrConvertFromZlib(rc, false /*fCompressing*/);
630 return rc;
631}
632
633
634/**
635 * Initialize the decompressor instance.
636 * @returns iprt status code.
637 * @param pZip The decompressor instance.
638 */
639static DECLCALLBACK(int) rtZipZlibDecompInit(PRTZIPDECOMP pZip)
640{
641 pZip->pfnDecompress = rtZipZlibDecompress;
642 pZip->pfnDestroy = rtZipZlibDecompDestroy;
643
644 memset(&pZip->u.Zlib, 0, sizeof(pZip->u.Zlib));
645 pZip->u.Zlib.opaque = pZip;
646
647 int rc = inflateInit(&pZip->u.Zlib);
648 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromZlib(rc, false /*fCompressing*/);
649}
650
651#endif /* RTZIP_USE_ZLIB */
652
653
654#ifdef RTZIP_USE_BZLIB
655/**
656 * Convert from BZlib errno to iprt status code.
657 * @returns iprt status code.
658 * @param rc BZlib error code.
659 */
660static int zipErrConvertFromBZlib(int rc)
661{
662 /** @todo proper bzlib error conversion. */
663 switch (rc)
664 {
665 case BZ_SEQUENCE_ERROR:
666 AssertMsgFailed(("BZ_SEQUENCE_ERROR shall not happen!\n"));
667 return VERR_GENERAL_FAILURE;
668 case BZ_PARAM_ERROR:
669 return VERR_INVALID_PARAMETER;
670 case BZ_MEM_ERROR:
671 return VERR_NO_MEMORY;
672 case BZ_DATA_ERROR:
673 case BZ_DATA_ERROR_MAGIC:
674 case BZ_IO_ERROR:
675 case BZ_UNEXPECTED_EOF:
676 case BZ_CONFIG_ERROR:
677 return VERR_GENERAL_FAILURE;
678 case BZ_OUTBUFF_FULL:
679 AssertMsgFailed(("BZ_OUTBUFF_FULL shall not happen!\n"));
680 return VERR_GENERAL_FAILURE;
681 default:
682 if (rc >= 0)
683 return VINF_SUCCESS;
684 return VERR_GENERAL_FAILURE;
685 }
686}
687
688
689/**
690 * @copydoc RTZipCompress
691 */
692static DECLCALLBACK(int) rtZipBZlibCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
693{
694 pZip->u.BZlib.next_in = (char *)pvBuf;
695 pZip->u.BZlib.avail_in = cbBuf;
696 while (pZip->u.BZlib.avail_in > 0)
697 {
698 /*
699 * Flush output buffer?
700 */
701 if (pZip->u.BZlib.avail_out <= 0)
702 {
703 int rc = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
704 if (RT_FAILURE(rc))
705 return rc;
706 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
707 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
708 }
709
710 /*
711 * Pass it on to zlib.
712 */
713 int rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_RUN);
714 if (rc < 0 && rc != BZ_OUTBUFF_FULL)
715 return zipErrConvertFromBZlib(rc);
716 }
717 return VINF_SUCCESS;
718}
719
720
721/**
722 * @copydoc RTZipCompFinish
723 */
724static DECLCALLBACK(int) rtZipBZlibCompFinish(PRTZIPCOMP pZip)
725{
726 int rc = BZ_FINISH_OK;
727 for (;;)
728 {
729 /*
730 * Flush output buffer?
731 */
732 if (rc == BZ_STREAM_END || pZip->u.BZlib.avail_out <= 0)
733 {
734 int rc2 = pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer) - pZip->u.BZlib.avail_out);
735 if (RT_FAILURE(rc2))
736 return rc2;
737 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer);
738 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[0];
739 if (rc == BZ_STREAM_END)
740 return VINF_SUCCESS;
741 }
742
743 /*
744 * Tell BZlib to finish it.
745 */
746 rc = BZ2_bzCompress(&pZip->u.BZlib, BZ_FINISH);
747 if (rc < 0 && rc != BZ_OUTBUFF_FULL)
748 return zipErrConvertFromBZlib(rc);
749 }
750 return VINF_SUCCESS;
751}
752
753
754/**
755 * @copydoc RTZipCompDestroy
756 */
757static DECLCALLBACK(int) rtZipBZlibCompDestroy(PRTZIPCOMP pZip)
758{
759 /*
760 * Terminate the deflate instance.
761 */
762 int rc = BZ2_bzCompressEnd(&pZip->u.BZlib);
763 if (rc != BZ_OK)
764 rc = zipErrConvertFromBZlib(rc);
765 return rc;
766}
767
768
769/**
770 * Initializes the compressor instance.
771 * @returns iprt status code.
772 * @param pZip The compressor instance.
773 * @param enmLevel The desired compression level.
774 */
775static DECLCALLBACK(int) rtZipBZlibCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
776{
777 pZip->pfnCompress = rtZipBZlibCompress;
778 pZip->pfnFinish = rtZipBZlibCompFinish;
779 pZip->pfnDestroy = rtZipBZlibCompDestroy;
780
781 int iSize = 6;
782 int iWork = 0;
783 switch (enmLevel)
784 {
785 case RTZIPLEVEL_STORE: iSize = 1; iWork = 2; break;
786 case RTZIPLEVEL_FAST: iSize = 2; iWork = 0; break;
787 case RTZIPLEVEL_DEFAULT: iSize = 5; iWork = 0; break;
788 case RTZIPLEVEL_MAX: iSize = 9; iWork = 0; break;
789 }
790
791 memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
792 pZip->u.BZlib.next_out = (char *)&pZip->abBuffer[1];
793 pZip->u.BZlib.avail_out = sizeof(pZip->abBuffer) - 1;
794 pZip->u.BZlib.opaque = pZip;
795
796 int rc = BZ2_bzCompressInit(&pZip->u.BZlib, iSize, 0, iWork);
797 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);;
798}
799
800
801/**
802 * @copydoc RTZipDecompress
803 */
804static DECLCALLBACK(int) rtZipBZlibDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
805{
806 pZip->u.BZlib.next_out = (char *)pvBuf;
807 pZip->u.BZlib.avail_out = cbBuf;
808 while (pZip->u.BZlib.avail_out > 0)
809 {
810 /*
811 * Read more output buffer?
812 */
813 if (pZip->u.BZlib.avail_in <= 0)
814 {
815 size_t cb;
816 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], sizeof(pZip->abBuffer), &cb);
817 if (RT_FAILURE(rc))
818 return rc;
819 pZip->u.BZlib.avail_in = cb;
820 pZip->u.BZlib.next_in = (char *)&pZip->abBuffer[0];
821 }
822
823 /*
824 * Pass it on to zlib.
825 */
826 int rc = BZ2_bzDecompress(&pZip->u.BZlib);
827 if (rc == BZ_STREAM_END || rc == BZ_OUTBUFF_FULL)
828 {
829 if (pcbWritten)
830 *pcbWritten = cbBuf - pZip->u.BZlib.avail_out;
831 else if (pZip->u.BZlib.avail_out > 0)
832 return VERR_NO_DATA;
833 break;
834 }
835 if (rc < 0)
836 return zipErrConvertFromBZlib(rc);
837 }
838 return VINF_SUCCESS;
839}
840
841
842/**
843 * @copydoc RTZipDecompDestroy
844 */
845static DECLCALLBACK(int) rtZipBZlibDecompDestroy(PRTZIPDECOMP pZip)
846{
847 /*
848 * Terminate the deflate instance.
849 */
850 int rc = BZ2_bzDecompressEnd(&pZip->u.BZlib);
851 if (rc != BZ_OK)
852 rc = zipErrConvertFromBZlib(rc);
853 return rc;
854}
855
856
857/**
858 * Initialize the decompressor instance.
859 * @returns iprt status code.
860 * @param pZip The decompressor instance.
861 */
862static DECLCALLBACK(int) rtZipBZlibDecompInit(PRTZIPDECOMP pZip)
863{
864 pZip->pfnDecompress = rtZipBZlibDecompress;
865 pZip->pfnDestroy = rtZipBZlibDecompDestroy;
866
867 memset(&pZip->u.BZlib, 0, sizeof(pZip->u.BZlib));
868 pZip->u.BZlib.opaque = pZip;
869
870 int rc = BZ2_bzDecompressInit(&pZip->u.BZlib, 0, 0);
871 return rc >= 0 ? VINF_SUCCESS : zipErrConvertFromBZlib(rc);
872}
873
874#endif /* RTZIP_USE_BZLIB */
875
876
877#ifdef RTZIP_USE_LZF
878
879/**
880 * Flushes the output buffer.
881 * @returns iprt status code.
882 * @param pZip The compressor instance.
883 */
884static int rtZipLZFCompFlushOutput(PRTZIPCOMP pZip)
885{
886 size_t cb = pZip->u.LZF.pbOutput - &pZip->abBuffer[0];
887 pZip->u.LZF.pbOutput = &pZip->abBuffer[0];
888 return pZip->pfnOut(pZip->pvUser, &pZip->abBuffer[0], cb);
889}
890
891
892/**
893 * Compresses a buffer using LZF.
894 *
895 * @returns VBox status code.
896 * @param pZip The compressor instance.
897 * @param pbBuf What to compress.
898 * @param cbBuf How much to compress.
899 */
900static int rtZipLZFCompressBuffer(PRTZIPCOMP pZip, const uint8_t *pbBuf, size_t cbBuf)
901{
902 bool fForceFlush = false;
903 while (cbBuf > 0)
904 {
905 /*
906 * Flush output buffer?
907 */
908 unsigned cbFree = (unsigned)(sizeof(pZip->abBuffer) - (pZip->u.LZF.pbOutput - &pZip->abBuffer[0]));
909 if ( fForceFlush
910 || cbFree < RTZIPLZF_MAX_DATA_SIZE + sizeof(RTZIPLZFHDR))
911 {
912 int rc = rtZipLZFCompFlushOutput(pZip);
913 if (RT_FAILURE(rc))
914 return rc;
915 fForceFlush = false;
916 cbFree = sizeof(pZip->abBuffer);
917 }
918
919 /*
920 * Setup the block header.
921 */
922 PRTZIPLZFHDR pHdr = (PRTZIPLZFHDR)pZip->u.LZF.pbOutput; /* warning: This might be unaligned! */
923 pHdr->u16Magic = RTZIPLZFHDR_MAGIC;
924 pHdr->cbData = 0;
925 pHdr->u32CRC = 0;
926 pHdr->cbUncompressed = 0;
927 cbFree -= sizeof(*pHdr);
928 pZip->u.LZF.pbOutput += sizeof(*pHdr);
929
930 /*
931 * Compress data for the block.
932 *
933 * We try compress as much as we have freespace for at first,
934 * but if it turns out the compression is inefficient, we'll
935 * reduce the size of data we try compress till it fits the
936 * output space.
937 */
938 cbFree = RT_MIN(cbFree, RTZIPLZF_MAX_DATA_SIZE);
939 unsigned cbInput = (unsigned)RT_MIN(RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE, cbBuf);
940 unsigned cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
941 if (!cbOutput)
942 {
943 /** @todo add an alternative method which stores the raw data if bad compression. */
944 do
945 {
946 cbInput /= 2;
947 if (!cbInput)
948 {
949 AssertMsgFailed(("lzf_compress bug! cbFree=%zu\n", cbFree));
950 return VERR_INTERNAL_ERROR;
951 }
952 cbOutput = lzf_compress(pbBuf, cbInput, pZip->u.LZF.pbOutput, cbFree);
953 } while (!cbOutput);
954 fForceFlush = true;
955 }
956
957 /*
958 * Update the header and advance the input buffer.
959 */
960 pHdr->cbData = cbOutput;
961 //pHdr->u32CRC = RTCrc32(pbBuf, cbInput); - too slow
962 pHdr->cbUncompressed = cbInput;
963
964 pZip->u.LZF.pbOutput += cbOutput;
965 cbBuf -= cbInput;
966 pbBuf += cbInput;
967 }
968 return VINF_SUCCESS;
969}
970
971
972/**
973 * Flushes the input buffer.
974 * @returns iprt status code.
975 * @param pZip The compressor instance.
976 */
977static int rtZipLZFCompFlushInput(PRTZIPCOMP pZip)
978{
979 size_t cb = pZip->u.LZF.pbInput - &pZip->u.LZF.abInput[0];
980 pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
981 pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
982 if (cb)
983 return rtZipLZFCompressBuffer(pZip, pZip->u.LZF.abInput, cb);
984 return VINF_SUCCESS;
985}
986
987
988/**
989 * @copydoc RTZipCompress
990 */
991static DECLCALLBACK(int) rtZipLZFCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
992{
993#define RTZIPLZF_SMALL_CHUNK (128)
994
995 /*
996 * Flush the input buffer if necessary.
997 */
998 if ( ( cbBuf <= RTZIPLZF_SMALL_CHUNK
999 && cbBuf > pZip->u.LZF.cbInputFree)
1000 || ( cbBuf > RTZIPLZF_SMALL_CHUNK
1001 && pZip->u.LZF.cbInputFree != sizeof(pZip->u.LZF.abInput))
1002 )
1003 {
1004 int rc = rtZipLZFCompFlushInput(pZip);
1005 if (RT_FAILURE(rc))
1006 return rc;
1007 }
1008
1009 /*
1010 * If it's a relativly small block put it in the input buffer, elsewise
1011 * compress directly it.
1012 */
1013 if (cbBuf <= RTZIPLZF_SMALL_CHUNK)
1014 {
1015 Assert(pZip->u.LZF.cbInputFree >= cbBuf);
1016 memcpy(pZip->u.LZF.pbInput, pvBuf, cbBuf);
1017 pZip->u.LZF.pbInput += cbBuf;
1018 pZip->u.LZF.cbInputFree -= cbBuf;
1019 }
1020 else
1021 {
1022 Assert(pZip->u.LZF.cbInputFree == sizeof(pZip->u.LZF.abInput));
1023 int rc = rtZipLZFCompressBuffer(pZip, (const uint8_t *)pvBuf, cbBuf);
1024 if (RT_FAILURE(rc))
1025 return rc;
1026 }
1027 return VINF_SUCCESS;
1028}
1029
1030
1031/**
1032 * @copydoc RTZipCompFinish
1033 */
1034static DECLCALLBACK(int) rtZipLZFCompFinish(PRTZIPCOMP pZip)
1035{
1036 int rc = rtZipLZFCompFlushInput(pZip);
1037 if (RT_SUCCESS(rc))
1038 rc = rtZipLZFCompFlushOutput(pZip);
1039 return rc;
1040}
1041
1042
1043/**
1044 * @copydoc RTZipCompDestroy
1045 */
1046static DECLCALLBACK(int) rtZipLZFCompDestroy(PRTZIPCOMP pZip)
1047{
1048 NOREF(pZip);
1049 return VINF_SUCCESS;
1050}
1051
1052
1053/**
1054 * Initializes the compressor instance.
1055 * @returns iprt status code.
1056 * @param pZip The compressor instance.
1057 * @param enmLevel The desired compression level.
1058 */
1059static DECLCALLBACK(int) rtZipLZFCompInit(PRTZIPCOMP pZip, RTZIPLEVEL enmLevel)
1060{
1061 NOREF(enmLevel);
1062 pZip->pfnCompress = rtZipLZFCompress;
1063 pZip->pfnFinish = rtZipLZFCompFinish;
1064 pZip->pfnDestroy = rtZipLZFCompDestroy;
1065
1066 pZip->u.LZF.pbOutput = &pZip->abBuffer[1];
1067 pZip->u.LZF.pbInput = &pZip->u.LZF.abInput[0];
1068 pZip->u.LZF.cbInputFree = sizeof(pZip->u.LZF.abInput);
1069 return VINF_SUCCESS;
1070}
1071
1072
1073/**
1074 * This will validate a header and to all the necessary bitching if it's invalid.
1075 * @returns true if valid.
1076 * @returns false if invalid.
1077 * @param pHdr Pointer to the header.\
1078 */
1079static bool rtZipLZFValidHeader(PCRTZIPLZFHDR pHdr)
1080{
1081 if ( pHdr->u16Magic != RTZIPLZFHDR_MAGIC
1082 || !pHdr->cbData
1083 || pHdr->cbData > RTZIPLZF_MAX_DATA_SIZE
1084 || !pHdr->cbUncompressed
1085 || pHdr->cbUncompressed > RTZIPLZF_MAX_UNCOMPRESSED_DATA_SIZE
1086 )
1087 {
1088 AssertMsgFailed(("Invalid LZF header! %.*%Rhxs\n", sizeof(pHdr), pHdr));
1089 return false;
1090 }
1091 return true;
1092}
1093
1094
1095/**
1096 * @copydoc RTZipDecompress
1097 */
1098static DECLCALLBACK(int) rtZipLZFDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1099{
1100 /*
1101 * Decompression loop.
1102 *
1103 * This a bit ugly because we have to deal with reading block...
1104 * To simplify matters we've put a max block size and will never
1105 * fill the input buffer with more than allows us to complete
1106 * any partially read blocks.
1107 *
1108 * When possible we decompress directly to the user buffer, when
1109 * not possible we'll use the spill buffer.
1110 */
1111# ifdef RTZIP_LZF_BLOCK_BY_BLOCK
1112 size_t cbWritten = 0;
1113 while (cbBuf > 0)
1114 {
1115 /*
1116 * Anything in the spill buffer?
1117 */
1118 if (pZip->u.LZF.cbSpill > 0)
1119 {
1120 unsigned cb = (unsigned)RT_MIN(pZip->u.LZF.cbSpill, cbBuf);
1121 memcpy(pvBuf, pZip->u.LZF.pbSpill, cb);
1122 pZip->u.LZF.pbSpill += cb;
1123 pZip->u.LZF.cbSpill -= cb;
1124 cbWritten += cb;
1125 cbBuf -= cb;
1126 if (!cbBuf)
1127 break;
1128 pvBuf = (uint8_t *)pvBuf + cb;
1129 }
1130
1131 /*
1132 * We always read and work one block at a time.
1133 */
1134 RTZIPLZFHDR Hdr;
1135 int rc = pZip->pfnIn(pZip->pvUser, &Hdr, sizeof(Hdr), NULL);
1136 if (RT_FAILURE(rc))
1137 return rc;
1138 if (!rtZipLZFValidHeader(&Hdr))
1139 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1140 if (Hdr.cbData > 0)
1141 {
1142 rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0], Hdr.cbData, NULL);
1143 if (RT_FAILURE(rc))
1144 return rc;
1145 }
1146
1147 /*
1148 * Does the uncompressed data fit into the supplied buffer?
1149 * If so we uncompress it directly into the user buffer, else we'll have to use the spill buffer.
1150 */
1151 unsigned cbUncompressed = Hdr.cbUncompressed;
1152 if (cbUncompressed <= cbBuf)
1153 {
1154 unsigned cbOutput = lzf_decompress(&pZip->abBuffer[0], Hdr.cbData, pvBuf, cbUncompressed);
1155 if (cbOutput != cbUncompressed)
1156 {
1157 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1158 errno, cbOutput, cbUncompressed));
1159 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1160 }
1161 cbBuf -= cbUncompressed;
1162 pvBuf = (uint8_t *)pvBuf + cbUncompressed;
1163 cbWritten += cbUncompressed;
1164 }
1165 else
1166 {
1167 unsigned cbOutput = lzf_decompress(&pZip->abBuffer[0], Hdr.cbData, pZip->u.LZF.abSpill, cbUncompressed);
1168 if (cbOutput != cbUncompressed)
1169 {
1170 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1171 errno, cbOutput, cbUncompressed));
1172 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1173 }
1174 pZip->u.LZF.pbSpill = &pZip->u.LZF.abSpill[0];
1175 pZip->u.LZF.cbSpill = cbUncompressed;
1176 }
1177 }
1178
1179 if (pcbWritten)
1180 *pcbWritten = cbWritten;
1181# else /* !RTZIP_LZF_BLOCK_BY_BLOCK */
1182 while (cbBuf > 0)
1183 {
1184 /*
1185 * Anything in the spill buffer?
1186 */
1187 if (pZip->u.LZF.cbSpill > 0)
1188 {
1189 unsigned cb = (unsigned)RT_MIN(pZip->u.LZF.cbSpill, cbBuf);
1190 memcpy(pvBuf, pZip->u.LZF.pbSpill, cb);
1191 pZip->u.LZF.pbSpill += cb;
1192 pZip->u.LZF.cbSpill -= cb;
1193 cbBuf -= cb;
1194 if (pcbWritten)
1195 *pcbWritten = cb;
1196 if (!cbBuf)
1197 break;
1198 pvBuf = (uint8_t *)pvBuf + cb;
1199 }
1200
1201 /*
1202 * Incomplete header or nothing at all.
1203 */
1204 PCRTZIPLZFHDR pHdr;
1205 if (pZip->u.LZF.cbInput < sizeof(RTZIPLZFHDR))
1206 {
1207 if (pZip->u.LZF.cbInput <= 0)
1208 {
1209 /* empty, fill the buffer. */
1210 size_t cb = 0;
1211 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[0],
1212 sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE, &cb);
1213 if (RT_FAILURE(rc))
1214 return rc;
1215 pZip->u.LZF.pbInput = &pZip->abBuffer[0];
1216 pZip->u.LZF.cbInput = cb;
1217 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1218 }
1219 else
1220 {
1221 /* move the header up and fill the buffer. */
1222 size_t cbCur = pZip->u.LZF.cbInput;
1223 memmove(&pZip->abBuffer[0], pZip->u.LZF.pbInput, cbCur);
1224 pZip->u.LZF.pbInput = &pZip->abBuffer[0];
1225
1226 size_t cb = 0;
1227 int rc = pZip->pfnIn(pZip->pvUser, &pZip->abBuffer[cbCur],
1228 sizeof(pZip->abBuffer) - RTZIPLZF_MAX_DATA_SIZE - cbCur, &cb);
1229 if (RT_FAILURE(rc))
1230 return rc;
1231 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1232 pZip->u.LZF.cbInput += cb;
1233 }
1234
1235 /*
1236 * Validate the header.
1237 */
1238 if (!rtZipLZFValidHeader(pHdr))
1239 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1240 }
1241 else
1242 {
1243 /*
1244 * Validate the header and check if it's an incomplete block.
1245 */
1246 pHdr = (PCRTZIPLZFHDR)pZip->u.LZF.pbInput;
1247 if (!rtZipLZFValidHeader(pHdr))
1248 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1249
1250 if (pHdr->cbData > pZip->u.LZF.cbInput - sizeof(*pHdr))
1251 {
1252 /* read the remainder of the block. */
1253 size_t cbToRead = pHdr->cbData - (pZip->u.LZF.cbInput - sizeof(*pHdr));
1254 Assert(&pZip->u.LZF.pbInput[pZip->u.LZF.cbInput + cbToRead] <= &pZip->u.LZF.pbInput[sizeof(pZip->abBuffer)]);
1255 int rc = pZip->pfnIn(pZip->pvUser, &pZip->u.LZF.pbInput[pZip->u.LZF.cbInput],
1256 cbToRead, NULL);
1257 if (RT_FAILURE(rc))
1258 return rc;
1259 pZip->u.LZF.cbInput += cbToRead;
1260 }
1261 }
1262 AssertMsgReturn(sizeof(*pHdr) + pHdr->cbData <= pZip->u.LZF.cbInput,
1263 ("cbData=%#x cbInput=%#x\n", pHdr->cbData, pZip->u.LZF.cbInput),
1264 VERR_GENERAL_FAILURE); /** @todo Get better error codes for RTZip! */
1265
1266 /*
1267 * Does the uncompressed data fit into the supplied buffer?
1268 * If so we uncompress it directly into the user buffer, else we'll have to use the spill buffer.
1269 */
1270 unsigned cbUncompressed = pHdr->cbUncompressed;
1271 if (cbUncompressed <= cbBuf)
1272 {
1273 unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pvBuf, cbUncompressed);
1274 if (cbOutput != cbUncompressed)
1275 {
1276 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1277 errno, cbOutput, cbUncompressed));
1278 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1279 }
1280 cbBuf -= cbUncompressed;
1281 pvBuf = (uint8_t *)pvBuf + cbUncompressed;
1282 }
1283 else
1284 {
1285 unsigned cbOutput = lzf_decompress(pHdr + 1, pHdr->cbData, pZip->u.LZF.abSpill, cbUncompressed);
1286 if (cbOutput != cbUncompressed)
1287 {
1288 AssertMsgFailed(("Decompression error, errno=%d. cbOutput=%#x cbUncompressed=%#x\n",
1289 errno, cbOutput, cbUncompressed));
1290 return VERR_GENERAL_FAILURE; /** @todo Get better error codes for RTZip! */
1291 }
1292 pZip->u.LZF.pbSpill = &pZip->u.LZF.abSpill[0];
1293 pZip->u.LZF.cbSpill = cbUncompressed;
1294 }
1295
1296 /* advance the input buffer */
1297 pZip->u.LZF.cbInput -= pHdr->cbData + sizeof(*pHdr);
1298 pZip->u.LZF.pbInput += pHdr->cbData + sizeof(*pHdr);
1299 if (pcbWritten)
1300 *pcbWritten += cbUncompressed;
1301 }
1302# endif /* !RTZIP_LZF_BLOCK_BY_BLOCK */
1303 return VINF_SUCCESS;
1304}
1305
1306
1307/**
1308 * @copydoc RTZipDecompDestroy
1309 */
1310static DECLCALLBACK(int) rtZipLZFDecompDestroy(PRTZIPDECOMP pZip)
1311{
1312 NOREF(pZip);
1313 return VINF_SUCCESS;
1314}
1315
1316
1317/**
1318 * Initialize the decompressor instance.
1319 * @returns iprt status code.
1320 * @param pZip The decompressor instance.
1321 */
1322static DECLCALLBACK(int) rtZipLZFDecompInit(PRTZIPDECOMP pZip)
1323{
1324 pZip->pfnDecompress = rtZipLZFDecompress;
1325 pZip->pfnDestroy = rtZipLZFDecompDestroy;
1326
1327# ifndef RTZIP_LZF_BLOCK_BY_BLOCK
1328 pZip->u.LZF.pbInput = NULL;
1329 pZip->u.LZF.cbInput = 0;
1330# endif
1331 pZip->u.LZF.cbSpill = 0;
1332 pZip->u.LZF.pbSpill = NULL;
1333
1334 return VINF_SUCCESS;
1335}
1336
1337#endif /* RTZIP_USE_LZF */
1338
1339
1340/**
1341 * Create a compressor instance.
1342 *
1343 * @returns iprt status code.
1344 * @param ppZip Where to store the instance handle.
1345 * @param pvUser User argument which will be passed on to pfnOut and pfnIn.
1346 * @param pfnOut Callback for consuming output of compression.
1347 * @param enmType Type of compressor to create.
1348 * @param enmLevel Compression level.
1349 */
1350RTDECL(int) RTZipCompCreate(PRTZIPCOMP *ppZip, void *pvUser, PFNRTZIPOUT pfnOut, RTZIPTYPE enmType, RTZIPLEVEL enmLevel)
1351{
1352 /*
1353 * Validate input.
1354 */
1355 AssertReturn(enmType >= RTZIPTYPE_INVALID && enmType < RTZIPTYPE_END, VERR_INVALID_PARAMETER);
1356 AssertReturn(enmLevel >= RTZIPLEVEL_STORE && enmLevel <= RTZIPLEVEL_MAX, VERR_INVALID_PARAMETER);
1357 AssertPtrReturn(pfnOut, VERR_INVALID_POINTER);
1358 AssertPtrReturn(ppZip, VERR_INVALID_POINTER);
1359
1360 /*
1361 * Allocate memory for the instance data.
1362 */
1363 PRTZIPCOMP pZip = (PRTZIPCOMP)RTMemAlloc(sizeof(RTZIPCOMP));
1364 if (!pZip)
1365 return VERR_NO_MEMORY;
1366
1367 /*
1368 * Determine auto type.
1369 */
1370 if (enmType == RTZIPTYPE_AUTO)
1371 {
1372 if (enmLevel == RTZIPLEVEL_STORE)
1373 enmType = RTZIPTYPE_STORE;
1374 else
1375 {
1376#if defined(RTZIP_USE_ZLIB) && defined(RTZIP_USE_BZLIB)
1377 if (enmLevel == RTZIPLEVEL_MAX)
1378 enmType = RTZIPTYPE_BZLIB;
1379 else
1380 enmType = RTZIPTYPE_ZLIB;
1381#elif defined(RTZIP_USE_ZLIB)
1382 enmType = RTZIPTYPE_ZLIB;
1383#elif defined(RTZIP_USE_BZLIB)
1384 enmType = RTZIPTYPE_BZLIB;
1385#else
1386 enmType = RTZIPTYPE_STORE;
1387#endif
1388 }
1389 }
1390
1391 /*
1392 * Init instance.
1393 */
1394 pZip->pfnOut = pfnOut;
1395 pZip->enmType = enmType;
1396 pZip->pvUser = pvUser;
1397 pZip->abBuffer[0] = enmType; /* first byte is the compression type. */
1398 int rc = VERR_NOT_IMPLEMENTED;
1399 switch (enmType)
1400 {
1401 case RTZIPTYPE_STORE:
1402#ifdef RTZIP_USE_STORE
1403 rc = rtZipStoreCompInit(pZip, enmLevel);
1404#endif
1405 break;
1406
1407 case RTZIPTYPE_ZLIB:
1408#ifdef RTZIP_USE_ZLIB
1409 rc = rtZipZlibCompInit(pZip, enmLevel);
1410#endif
1411 break;
1412
1413 case RTZIPTYPE_BZLIB:
1414#ifdef RTZIP_USE_BZLIB
1415 rc = rtZipBZlibCompInit(pZip, enmLevel);
1416#endif
1417 break;
1418
1419 case RTZIPTYPE_LZF:
1420#ifdef RTZIP_USE_LZF
1421 rc = rtZipLZFCompInit(pZip, enmLevel);
1422#endif
1423 break;
1424
1425 case RTZIPTYPE_LZJB:
1426 case RTZIPTYPE_LZO:
1427 break;
1428
1429 default:
1430 AssertFailedBreak();
1431 }
1432
1433 if (RT_SUCCESS(rc))
1434 *ppZip = pZip;
1435 else
1436 RTMemFree(pZip);
1437 return rc;
1438}
1439RT_EXPORT_SYMBOL(RTZipCompCreate);
1440
1441
1442/**
1443 * Compresses a chunk of memory.
1444 *
1445 * @returns iprt status code.
1446 * @param pZip The compressor instance.
1447 * @param pvBuf Pointer to buffer containing the bits to compress.
1448 * @param cbBuf Number of bytes to compress.
1449 */
1450RTDECL(int) RTZipCompress(PRTZIPCOMP pZip, const void *pvBuf, size_t cbBuf)
1451{
1452 if (!cbBuf)
1453 return VINF_SUCCESS;
1454 return pZip->pfnCompress(pZip, pvBuf, cbBuf);
1455}
1456RT_EXPORT_SYMBOL(RTZipCompress);
1457
1458
1459/**
1460 * Finishes the compression.
1461 * This will flush all data and terminate the compression data stream.
1462 *
1463 * @returns iprt status code.
1464 * @param pZip The compressor instance.
1465 */
1466RTDECL(int) RTZipCompFinish(PRTZIPCOMP pZip)
1467{
1468 return pZip->pfnFinish(pZip);
1469}
1470RT_EXPORT_SYMBOL(RTZipCompFinish);
1471
1472
1473/**
1474 * Destroys the compressor instance.
1475 *
1476 * @returns iprt status code.
1477 * @param pZip The compressor instance.
1478 */
1479RTDECL(int) RTZipCompDestroy(PRTZIPCOMP pZip)
1480{
1481 /*
1482 * Compressor specific destruction attempt first.
1483 */
1484 int rc = pZip->pfnDestroy(pZip);
1485 AssertRCReturn(rc, rc);
1486
1487 /*
1488 * Free the instance memory.
1489 */
1490 pZip->enmType = RTZIPTYPE_INVALID;
1491 RTMemFree(pZip);
1492 return VINF_SUCCESS;
1493}
1494RT_EXPORT_SYMBOL(RTZipCompDestroy);
1495
1496
1497/**
1498 * @copydoc RTZipDecompress
1499 */
1500static DECLCALLBACK(int) rtZipStubDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1501{
1502 NOREF(pZip); NOREF(pvBuf); NOREF(cbBuf); NOREF(pcbWritten);
1503 return VERR_NOT_SUPPORTED;
1504}
1505
1506
1507/**
1508 * @copydoc RTZipDecompDestroy
1509 */
1510static DECLCALLBACK(int) rtZipStubDecompDestroy(PRTZIPDECOMP pZip)
1511{
1512 NOREF(pZip);
1513 return VINF_SUCCESS;
1514}
1515
1516
1517/**
1518 * Create a decompressor instance.
1519 *
1520 * @returns iprt status code.
1521 * @param ppZip Where to store the instance handle.
1522 * @param pvUser User argument which will be passed on to pfnOut and pfnIn.
1523 * @param pfnIn Callback for producing input for decompression.
1524 */
1525RTDECL(int) RTZipDecompCreate(PRTZIPDECOMP *ppZip, void *pvUser, PFNRTZIPIN pfnIn)
1526{
1527 /*
1528 * Validate input.
1529 */
1530 AssertPtrReturn(pfnIn, VERR_INVALID_POINTER);
1531 AssertPtrReturn(ppZip, VERR_INVALID_POINTER);
1532
1533 /*
1534 * Allocate memory for the instance data.
1535 */
1536 PRTZIPDECOMP pZip = (PRTZIPDECOMP)RTMemAlloc(sizeof(RTZIPDECOMP));
1537 if (!pZip)
1538 return VERR_NO_MEMORY;
1539
1540 /*
1541 * Init instance.
1542 */
1543 pZip->pfnIn = pfnIn;
1544 pZip->enmType = RTZIPTYPE_INVALID;
1545 pZip->pvUser = pvUser;
1546 pZip->pfnDecompress = NULL;
1547 pZip->pfnDestroy = rtZipStubDecompDestroy;
1548
1549 *ppZip = pZip;
1550 return VINF_SUCCESS;
1551}
1552RT_EXPORT_SYMBOL(RTZipDecompCreate);
1553
1554
1555/**
1556 * Lazy init of the decompressor.
1557 * @returns iprt status code.
1558 * @param pZip The decompressor instance.
1559 */
1560static int rtzipDecompInit(PRTZIPDECOMP pZip)
1561{
1562 /*
1563 * Read the first byte from the stream so we can determine the type.
1564 */
1565 uint8_t u8Type;
1566 int rc = pZip->pfnIn(pZip->pvUser, &u8Type, sizeof(u8Type), NULL);
1567 if (RT_FAILURE(rc))
1568 return rc;
1569
1570 /*
1571 * Determine type and do type specific init.
1572 */
1573 pZip->enmType = (RTZIPTYPE)u8Type;
1574 rc = VERR_NOT_SUPPORTED;
1575 switch (pZip->enmType)
1576 {
1577 case RTZIPTYPE_STORE:
1578#ifdef RTZIP_USE_STORE
1579 rc = rtZipStoreDecompInit(pZip);
1580#else
1581 AssertMsgFailed(("Store is not include in this build!\n"));
1582#endif
1583 break;
1584
1585 case RTZIPTYPE_ZLIB:
1586#ifdef RTZIP_USE_ZLIB
1587 rc = rtZipZlibDecompInit(pZip);
1588#else
1589 AssertMsgFailed(("Zlib is not include in this build!\n"));
1590#endif
1591 break;
1592
1593 case RTZIPTYPE_BZLIB:
1594#ifdef RTZIP_USE_BZLIB
1595 rc = rtZipBZlibDecompInit(pZip);
1596#else
1597 AssertMsgFailed(("BZlib is not include in this build!\n"));
1598#endif
1599 break;
1600
1601 case RTZIPTYPE_LZF:
1602#ifdef RTZIP_USE_LZF
1603 rc = rtZipLZFDecompInit(pZip);
1604#else
1605 AssertMsgFailed(("LZF is not include in this build!\n"));
1606#endif
1607 break;
1608
1609 case RTZIPTYPE_LZJB:
1610#ifdef RTZIP_USE_LZJB
1611 AssertMsgFailed(("LZJB streaming support is not implemented yet!\n"));
1612#else
1613 AssertMsgFailed(("LZJB is not include in this build!\n"));
1614#endif
1615 break;
1616
1617 case RTZIPTYPE_LZO:
1618#ifdef RTZIP_USE_LZJB
1619 AssertMsgFailed(("LZO streaming support is not implemented yet!\n"));
1620#else
1621 AssertMsgFailed(("LZO is not include in this build!\n"));
1622#endif
1623 break;
1624
1625 default:
1626 AssertMsgFailed(("Invalid compression type %d (%#x)!\n", pZip->enmType, pZip->enmType));
1627 rc = VERR_INVALID_MAGIC;
1628 break;
1629 }
1630 if (RT_FAILURE(rc))
1631 {
1632 pZip->pfnDecompress = rtZipStubDecompress;
1633 pZip->pfnDestroy = rtZipStubDecompDestroy;
1634 }
1635
1636 return rc;
1637}
1638
1639
1640/**
1641 * Decompresses a chunk of memory.
1642 *
1643 * @returns iprt status code.
1644 * @param pZip The decompressor instance.
1645 * @param pvBuf Where to store the decompressed data.
1646 * @param cbBuf Number of bytes to produce. If pcbWritten is set
1647 * any number of bytes up to cbBuf might be returned.
1648 * @param pcbWritten Number of bytes actually written to the buffer. If NULL
1649 * cbBuf number of bytes must be written.
1650 */
1651RTDECL(int) RTZipDecompress(PRTZIPDECOMP pZip, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
1652{
1653 /*
1654 * Skip empty requests.
1655 */
1656 if (!cbBuf)
1657 return VINF_SUCCESS;
1658
1659 /*
1660 * Lazy init.
1661 */
1662 if (!pZip->pfnDecompress)
1663 {
1664 int rc = rtzipDecompInit(pZip);
1665 if (RT_FAILURE(rc))
1666 return rc;
1667 }
1668
1669 /*
1670 * 'Read' the decompressed stream.
1671 */
1672 return pZip->pfnDecompress(pZip, pvBuf, cbBuf, pcbWritten);
1673}
1674RT_EXPORT_SYMBOL(RTZipDecompress);
1675
1676
1677/**
1678 * Destroys the decompressor instance.
1679 *
1680 * @returns iprt status code.
1681 * @param pZip The decompressor instance.
1682 */
1683RTDECL(int) RTZipDecompDestroy(PRTZIPDECOMP pZip)
1684{
1685 /*
1686 * Destroy compressor instance and flush the output buffer.
1687 */
1688 int rc = pZip->pfnDestroy(pZip);
1689 AssertRCReturn(rc, rc);
1690
1691 /*
1692 * Free the instance memory.
1693 */
1694 pZip->enmType = RTZIPTYPE_INVALID;
1695 RTMemFree(pZip);
1696 return rc;
1697}
1698RT_EXPORT_SYMBOL(RTZipDecompDestroy);
1699
1700
1701RTDECL(int) RTZipBlockCompress(RTZIPTYPE enmType, RTZIPLEVEL enmLevel, uint32_t fFlags,
1702 void const *pvSrc, size_t cbSrc,
1703 void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW
1704{
1705 /* input validation - the crash and burn approach as speed is essential here. */
1706 Assert(enmLevel <= RTZIPLEVEL_MAX && enmLevel >= RTZIPLEVEL_STORE);
1707 Assert(!fFlags);
1708
1709 /*
1710 * Deal with flags involving prefixes.
1711 */
1712 /** @todo later: type and/or compressed length prefix. */
1713
1714 /*
1715 * The type specific part.
1716 */
1717 switch (enmType)
1718 {
1719 case RTZIPTYPE_LZF:
1720 {
1721#ifdef RTZIP_USE_LZF
1722# if 0
1723 static const uint8_t s_abZero4K[] =
1724 {
1725 0x01, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff,
1726 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0,
1727 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00,
1728 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff,
1729 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0,
1730 0xff, 0x00, 0xe0, 0xff, 0x00, 0xe0, 0xff, 0x00,
1731 0xe0, 0x7d, 0x00
1732 };
1733 if ( cbSrc == _4K
1734 && !((uintptr_t)pvSrc & 15)
1735 && ASMMemIsZeroPage(pvSrc))
1736 {
1737 if (RT_UNLIKELY(cbDst < sizeof(s_abZero4K)))
1738 return VERR_BUFFER_OVERFLOW;
1739 memcpy(pvDst, s_abZero4K, sizeof(s_abZero4K));
1740 *pcbDstActual = sizeof(s_abZero4K);
1741 break;
1742 }
1743# endif
1744
1745 unsigned cbDstActual = lzf_compress(pvSrc, (unsigned)cbSrc, pvDst, (unsigned)cbDst); /** @todo deal with size type overflows */
1746 if (RT_UNLIKELY(cbDstActual < 1))
1747 return VERR_BUFFER_OVERFLOW;
1748 *pcbDstActual = cbDstActual;
1749 break;
1750#else
1751 return VERR_NOT_SUPPORTED;
1752#endif
1753 }
1754
1755 case RTZIPTYPE_STORE:
1756 {
1757 if (cbDst < cbSrc)
1758 return VERR_BUFFER_OVERFLOW;
1759 memcpy(pvDst, pvSrc, cbSrc);
1760 *pcbDstActual = cbSrc;
1761 break;
1762 }
1763
1764 case RTZIPTYPE_LZJB:
1765 {
1766#ifdef RTZIP_USE_LZJB
1767 AssertReturn(cbDst > cbSrc, VERR_BUFFER_OVERFLOW);
1768 size_t cbDstActual = lzjb_compress((void *)pvSrc, (uint8_t *)pvDst + 1, cbSrc, cbSrc, 0 /*??*/);
1769 if (cbDstActual == cbSrc)
1770 *(uint8_t *)pvDst = 0;
1771 else
1772 *(uint8_t *)pvDst = 1;
1773 *pcbDstActual = cbDstActual + 1;
1774 break;
1775#else
1776 return VERR_NOT_SUPPORTED;
1777#endif
1778 }
1779
1780 case RTZIPTYPE_LZO:
1781 {
1782#ifdef RTZIP_USE_LZO
1783 uint64_t Scratch[RT_ALIGN(LZO1X_1_MEM_COMPRESS, sizeof(uint64_t)) / sizeof(uint64_t)];
1784 int rc = lzo_init();
1785 if (RT_UNLIKELY(rc != LZO_E_OK))
1786 return VERR_INTERNAL_ERROR;
1787
1788 lzo_uint cbDstInOut = cbDst;
1789 rc = lzo1x_1_compress((const lzo_bytep)pvSrc, cbSrc, (lzo_bytep )pvDst, &cbDstInOut, &Scratch[0]);
1790 if (RT_UNLIKELY(rc != LZO_E_OK))
1791 switch (rc)
1792 {
1793 case LZO_E_OUTPUT_OVERRUN: return VERR_BUFFER_OVERFLOW;
1794 default: return VERR_GENERAL_FAILURE;
1795 }
1796 *pcbDstActual = cbDstInOut;
1797 break;
1798#else
1799 return VERR_NOT_SUPPORTED;
1800#endif
1801 }
1802
1803 case RTZIPTYPE_ZLIB:
1804 case RTZIPTYPE_BZLIB:
1805 return VERR_NOT_SUPPORTED;
1806
1807 default:
1808 AssertMsgFailed(("%d\n", enmType));
1809 return VERR_INVALID_PARAMETER;
1810 }
1811
1812 return VINF_SUCCESS;
1813}
1814RT_EXPORT_SYMBOL(RTZipBlockCompress);
1815
1816
1817RTDECL(int) RTZipBlockDecompress(RTZIPTYPE enmType, uint32_t fFlags,
1818 void const *pvSrc, size_t cbSrc, size_t *pcbSrcActual,
1819 void *pvDst, size_t cbDst, size_t *pcbDstActual) RT_NO_THROW
1820{
1821 /* input validation - the crash and burn approach as speed is essential here. */
1822 Assert(!fFlags);
1823
1824 /*
1825 * Deal with flags involving prefixes.
1826 */
1827 /** @todo later: type and/or compressed length prefix. */
1828
1829 /*
1830 * The type specific part.
1831 */
1832 switch (enmType)
1833 {
1834 case RTZIPTYPE_LZF:
1835 {
1836#ifdef RTZIP_USE_LZF
1837 unsigned cbDstActual = lzf_decompress(pvSrc, (unsigned)cbSrc, pvDst, (unsigned)cbDst); /** @todo deal with size type overflows */
1838 if (RT_UNLIKELY(cbDstActual < 1))
1839 {
1840 if (errno == E2BIG)
1841 return VERR_BUFFER_OVERFLOW;
1842 Assert(errno == EINVAL);
1843 return VERR_GENERAL_FAILURE;
1844 }
1845 if (pcbDstActual)
1846 *pcbDstActual = cbDstActual;
1847 if (pcbSrcActual)
1848 *pcbSrcActual = cbSrc;
1849 break;
1850#else
1851 return VERR_NOT_SUPPORTED;
1852#endif
1853 }
1854
1855 case RTZIPTYPE_STORE:
1856 {
1857 if (cbDst < cbSrc)
1858 return VERR_BUFFER_OVERFLOW;
1859 memcpy(pvDst, pvSrc, cbSrc);
1860 if (pcbDstActual)
1861 *pcbDstActual = cbSrc;
1862 if (pcbSrcActual)
1863 *pcbSrcActual = cbSrc;
1864 break;
1865 }
1866
1867 case RTZIPTYPE_LZJB:
1868 {
1869#ifdef RTZIP_USE_LZJB
1870 if (*(uint8_t *)pvSrc == 1)
1871 {
1872 int rc = lzjb_decompress((uint8_t *)pvSrc + 1, pvDst, cbSrc - 1, cbDst, 0 /*??*/);
1873 if (RT_UNLIKELY(rc != 0))
1874 return VERR_GENERAL_FAILURE;
1875 if (pcbDstActual)
1876 *pcbDstActual = cbDst;
1877 }
1878 else
1879 {
1880 AssertReturn(cbDst >= cbSrc - 1, VERR_BUFFER_OVERFLOW);
1881 memcpy(pvDst, (uint8_t *)pvSrc + 1, cbSrc - 1);
1882 if (pcbDstActual)
1883 *pcbDstActual = cbSrc - 1;
1884 }
1885 if (pcbSrcActual)
1886 *pcbSrcActual = cbSrc;
1887 break;
1888#else
1889 return VERR_NOT_SUPPORTED;
1890#endif
1891 }
1892
1893 case RTZIPTYPE_LZO:
1894 {
1895#ifdef RTZIP_USE_LZO
1896 int rc = lzo_init();
1897 if (RT_UNLIKELY(rc != LZO_E_OK))
1898 return VERR_INTERNAL_ERROR;
1899 lzo_uint cbDstInOut = cbDst;
1900 rc = lzo1x_decompress((const lzo_bytep)pvSrc, cbSrc, (lzo_bytep)pvDst, &cbDstInOut, NULL);
1901 if (RT_UNLIKELY(rc != LZO_E_OK))
1902 switch (rc)
1903 {
1904 case LZO_E_OUTPUT_OVERRUN: return VERR_BUFFER_OVERFLOW;
1905 default:
1906 case LZO_E_INPUT_OVERRUN: return VERR_GENERAL_FAILURE;
1907 }
1908 if (pcbSrcActual)
1909 *pcbSrcActual = cbSrc;
1910 if (pcbDstActual)
1911 *pcbDstActual = cbDstInOut;
1912 break;
1913#else
1914 return VERR_NOT_SUPPORTED;
1915#endif
1916 }
1917
1918 case RTZIPTYPE_ZLIB:
1919 case RTZIPTYPE_BZLIB:
1920 return VERR_NOT_SUPPORTED;
1921
1922 default:
1923 AssertMsgFailed(("%d\n", enmType));
1924 return VERR_INVALID_PARAMETER;
1925 }
1926 return VINF_SUCCESS;
1927}
1928RT_EXPORT_SYMBOL(RTZipBlockDecompress);
1929
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