VirtualBox

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

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

zip.cpp: make sure we return VERR_NOT_SUPPORTED for attempts using compression types that aren't enabled in the build.

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