VirtualBox

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

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

IPRT: Fixed -Wshadow warnings, found two bugs in error paths.

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