VirtualBox

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

Last change on this file since 39050 was 39050, checked in by vboxsync, 13 years ago

copyright year.

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