VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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