VirtualBox

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

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

iprt/zip.cpp: notes from zero page optimizations.

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