source: thirdparty/blosc/internal-complibs/zstd-0.7.4/decompress/zbuff_decompress.c @ 8ebc79b

Revision 8ebc79b, 13.0 KB checked in by Hal Finkel <hfinkel@…>, 8 years ago (diff)

Add the other internal compression libraries from blocs

  • Property mode set to 100644
Line 
1/*
2    Buffered version of Zstd compression library
3    Copyright (C) 2015-2016, Yann Collet.
4
5    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7    Redistribution and use in source and binary forms, with or without
8    modification, are permitted provided that the following conditions are
9    met:
10    * Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    * Redistributions in binary form must reproduce the above
13    copyright notice, this list of conditions and the following disclaimer
14    in the documentation and/or other materials provided with the
15    distribution.
16    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28    You can contact the author at :
29    - zstd homepage : http://www.zstd.net/
30*/
31
32
33/* *************************************
34*  Dependencies
35***************************************/
36#include <stdlib.h>
37#include "error_private.h"
38#include "zstd_internal.h"  /* MIN, ZSTD_blockHeaderSize, ZSTD_BLOCKSIZE_MAX */
39#define ZBUFF_STATIC_LINKING_ONLY
40#include "zbuff.h"
41
42
43/*-***************************************************************************
44*  Streaming decompression howto
45*
46*  A ZBUFF_DCtx object is required to track streaming operations.
47*  Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources.
48*  Use ZBUFF_decompressInit() to start a new decompression operation,
49*   or ZBUFF_decompressInitDictionary() if decompression requires a dictionary.
50*  Note that ZBUFF_DCtx objects can be re-init multiple times.
51*
52*  Use ZBUFF_decompressContinue() repetitively to consume your input.
53*  *srcSizePtr and *dstCapacityPtr can be any size.
54*  The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr.
55*  Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again.
56*  The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst.
57*  @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency),
58*            or 0 when a frame is completely decoded,
59*            or an error code, which can be tested using ZBUFF_isError().
60*
61*  Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize()
62*  output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded.
63*  input  : ZBUFF_recommendedDInSize == 128KB + 3;
64*           just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 .
65* *******************************************************************************/
66
67typedef enum { ZBUFFds_init, ZBUFFds_loadHeader,
68               ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFF_dStage;
69
70/* *** Resource management *** */
71struct ZBUFF_DCtx_s {
72    ZSTD_DCtx* zd;
73    ZSTD_frameParams fParams;
74    ZBUFF_dStage stage;
75    char*  inBuff;
76    size_t inBuffSize;
77    size_t inPos;
78    char*  outBuff;
79    size_t outBuffSize;
80    size_t outStart;
81    size_t outEnd;
82    size_t blockSize;
83    BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
84    size_t lhSize;
85    ZSTD_customMem customMem;
86};   /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */
87
88
89ZBUFF_DCtx* ZBUFF_createDCtx(void)
90{
91    return ZBUFF_createDCtx_advanced(defaultCustomMem);
92}
93
94ZBUFF_DCtx* ZBUFF_createDCtx_advanced(ZSTD_customMem customMem)
95{
96    ZBUFF_DCtx* zbd;
97
98    if (!customMem.customAlloc && !customMem.customFree)
99        customMem = defaultCustomMem;
100
101    if (!customMem.customAlloc || !customMem.customFree)
102        return NULL;
103
104    zbd = (ZBUFF_DCtx*)customMem.customAlloc(customMem.opaque, sizeof(ZBUFF_DCtx));
105    if (zbd==NULL) return NULL;
106    memset(zbd, 0, sizeof(ZBUFF_DCtx));
107    memcpy(&zbd->customMem, &customMem, sizeof(ZSTD_customMem));
108    zbd->zd = ZSTD_createDCtx_advanced(customMem);
109    if (zbd->zd == NULL) { ZBUFF_freeDCtx(zbd); return NULL; }
110    zbd->stage = ZBUFFds_init;
111    return zbd;
112}
113
114size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbd)
115{
116    if (zbd==NULL) return 0;   /* support free on null */
117    ZSTD_freeDCtx(zbd->zd);
118    if (zbd->inBuff) zbd->customMem.customFree(zbd->customMem.opaque, zbd->inBuff);
119    if (zbd->outBuff) zbd->customMem.customFree(zbd->customMem.opaque, zbd->outBuff);
120    zbd->customMem.customFree(zbd->customMem.opaque, zbd);
121    return 0;
122}
123
124
125/* *** Initialization *** */
126
127size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbd, const void* dict, size_t dictSize)
128{
129    zbd->stage = ZBUFFds_loadHeader;
130    zbd->lhSize = zbd->inPos = zbd->outStart = zbd->outEnd = 0;
131    return ZSTD_decompressBegin_usingDict(zbd->zd, dict, dictSize);
132}
133
134size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbd)
135{
136    return ZBUFF_decompressInitDictionary(zbd, NULL, 0);
137}
138
139
140/* internal util function */
141MEM_STATIC size_t ZBUFF_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
142{
143    size_t const length = MIN(dstCapacity, srcSize);
144    memcpy(dst, src, length);
145    return length;
146}
147
148
149/* *** Decompression *** */
150
151size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbd,
152                                void* dst, size_t* dstCapacityPtr,
153                          const void* src, size_t* srcSizePtr)
154{
155    const char* const istart = (const char*)src;
156    const char* const iend = istart + *srcSizePtr;
157    const char* ip = istart;
158    char* const ostart = (char*)dst;
159    char* const oend = ostart + *dstCapacityPtr;
160    char* op = ostart;
161    U32 notDone = 1;
162
163    while (notDone) {
164        switch(zbd->stage)
165        {
166        case ZBUFFds_init :
167            return ERROR(init_missing);
168
169        case ZBUFFds_loadHeader :
170            {   size_t const hSize = ZSTD_getFrameParams(&(zbd->fParams), zbd->headerBuffer, zbd->lhSize);
171                if (hSize != 0) {
172                    size_t const toLoad = hSize - zbd->lhSize;   /* if hSize!=0, hSize > zbd->lhSize */
173                    if (ZSTD_isError(hSize)) return hSize;
174                    if (toLoad > (size_t)(iend-ip)) {   /* not enough input to load full header */
175                        memcpy(zbd->headerBuffer + zbd->lhSize, ip, iend-ip);
176                        zbd->lhSize += iend-ip;
177                        *dstCapacityPtr = 0;
178                        return (hSize - zbd->lhSize) + ZSTD_blockHeaderSize;   /* remaining header bytes + next block header */
179                    }
180                    memcpy(zbd->headerBuffer + zbd->lhSize, ip, toLoad); zbd->lhSize = hSize; ip += toLoad;
181                    break;
182            }   }
183
184            /* Consume header */
185            {   size_t const h1Size = ZSTD_nextSrcSizeToDecompress(zbd->zd);  /* == ZSTD_frameHeaderSize_min */
186                size_t const h1Result = ZSTD_decompressContinue(zbd->zd, NULL, 0, zbd->headerBuffer, h1Size);
187                if (ZSTD_isError(h1Result)) return h1Result;
188                if (h1Size < zbd->lhSize) {   /* long header */
189                    size_t const h2Size = ZSTD_nextSrcSizeToDecompress(zbd->zd);
190                    size_t const h2Result = ZSTD_decompressContinue(zbd->zd, NULL, 0, zbd->headerBuffer+h1Size, h2Size);
191                    if (ZSTD_isError(h2Result)) return h2Result;
192            }   }
193
194            zbd->fParams.windowSize = MAX(zbd->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
195
196            /* Frame header instruct buffer sizes */
197            {   size_t const blockSize = MIN(zbd->fParams.windowSize, ZSTD_BLOCKSIZE_MAX);
198                zbd->blockSize = blockSize;
199                if (zbd->inBuffSize < blockSize) {
200                    zbd->customMem.customFree(zbd->customMem.opaque, zbd->inBuff);
201                    zbd->inBuffSize = blockSize;
202                    zbd->inBuff = (char*)zbd->customMem.customAlloc(zbd->customMem.opaque, blockSize);
203                    if (zbd->inBuff == NULL) return ERROR(memory_allocation);
204                }
205                {   size_t const neededOutSize = zbd->fParams.windowSize + blockSize;
206                    if (zbd->outBuffSize < neededOutSize) {
207                        zbd->customMem.customFree(zbd->customMem.opaque, zbd->outBuff);
208                        zbd->outBuffSize = neededOutSize;
209                        zbd->outBuff = (char*)zbd->customMem.customAlloc(zbd->customMem.opaque, neededOutSize);
210                        if (zbd->outBuff == NULL) return ERROR(memory_allocation);
211            }   }   }
212            zbd->stage = ZBUFFds_read;
213
214        case ZBUFFds_read:
215            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbd->zd);
216                if (neededInSize==0) {  /* end of frame */
217                    zbd->stage = ZBUFFds_init;
218                    notDone = 0;
219                    break;
220                }
221                if ((size_t)(iend-ip) >= neededInSize) {  /* decode directly from src */
222                    const int isSkipFrame = ZSTD_isSkipFrame(zbd->zd);
223                    size_t const decodedSize = ZSTD_decompressContinue(zbd->zd,
224                        zbd->outBuff + zbd->outStart, (isSkipFrame ? 0 : zbd->outBuffSize - zbd->outStart),
225                        ip, neededInSize);
226                    if (ZSTD_isError(decodedSize)) return decodedSize;
227                    ip += neededInSize;
228                    if (!decodedSize && !isSkipFrame) break;   /* this was just a header */
229                    zbd->outEnd = zbd->outStart +  decodedSize;
230                    zbd->stage = ZBUFFds_flush;
231                    break;
232                }
233                if (ip==iend) { notDone = 0; break; }   /* no more input */
234                zbd->stage = ZBUFFds_load;
235            }
236
237        case ZBUFFds_load:
238            {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbd->zd);
239                size_t const toLoad = neededInSize - zbd->inPos;   /* should always be <= remaining space within inBuff */
240                size_t loadedSize;
241                if (toLoad > zbd->inBuffSize - zbd->inPos) return ERROR(corruption_detected);   /* should never happen */
242                loadedSize = ZBUFF_limitCopy(zbd->inBuff + zbd->inPos, toLoad, ip, iend-ip);
243                ip += loadedSize;
244                zbd->inPos += loadedSize;
245                if (loadedSize < toLoad) { notDone = 0; break; }   /* not enough input, wait for more */
246
247                /* decode loaded input */
248                {  const int isSkipFrame = ZSTD_isSkipFrame(zbd->zd);
249                   size_t const decodedSize = ZSTD_decompressContinue(zbd->zd,
250                        zbd->outBuff + zbd->outStart, zbd->outBuffSize - zbd->outStart,
251                        zbd->inBuff, neededInSize);
252                    if (ZSTD_isError(decodedSize)) return decodedSize;
253                    zbd->inPos = 0;   /* input is consumed */
254                    if (!decodedSize && !isSkipFrame) { zbd->stage = ZBUFFds_read; break; }   /* this was just a header */
255                    zbd->outEnd = zbd->outStart +  decodedSize;
256                    zbd->stage = ZBUFFds_flush;
257                    // break; /* ZBUFFds_flush follows */
258            }   }
259
260        case ZBUFFds_flush:
261            {   size_t const toFlushSize = zbd->outEnd - zbd->outStart;
262                size_t const flushedSize = ZBUFF_limitCopy(op, oend-op, zbd->outBuff + zbd->outStart, toFlushSize);
263                op += flushedSize;
264                zbd->outStart += flushedSize;
265                if (flushedSize == toFlushSize) {
266                    zbd->stage = ZBUFFds_read;
267                    if (zbd->outStart + zbd->blockSize > zbd->outBuffSize)
268                        zbd->outStart = zbd->outEnd = 0;
269                    break;
270                }
271                /* cannot flush everything */
272                notDone = 0;
273                break;
274            }
275        default: return ERROR(GENERIC);   /* impossible */
276    }   }
277
278    /* result */
279    *srcSizePtr = ip-istart;
280    *dstCapacityPtr = op-ostart;
281    {   size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbd->zd);
282//        if (nextSrcSizeHint > ZSTD_blockHeaderSize) nextSrcSizeHint+= ZSTD_blockHeaderSize;   /* get following block header too */
283        nextSrcSizeHint -= zbd->inPos;   /* already loaded*/
284        return nextSrcSizeHint;
285    }
286}
287
288
289
290/* *************************************
291*  Tool functions
292***************************************/
293size_t ZBUFF_recommendedDInSize(void)  { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize /* block header size*/ ; }
294size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Note: See TracBrowser for help on using the repository browser.