VirtualBox

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

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

IPRT/RTZip: Fixed LZJB support and added LZO.

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