1 /** @file block.c  Byte array with copy-on-write semantics.
2 
3 @authors Copyright (c) 2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4 
5 @par License
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice, this
11    list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13    this list of conditions and the following disclaimer in the documentation
14    and/or other materials provided with the distribution.
15 
16 <small>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</small>
26 */
27 
28 #include "the_Foundation/block.h"
29 #include "the_Foundation/atomic.h"
30 #include "the_Foundation/garbage.h"
31 #include "the_Foundation/string.h"
32 #include "the_Foundation/stream.h"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <strings.h>
38 #include <uniconv.h>
39 #if defined (iHaveZlib)
40 #   include <zlib.h>
41 #endif
42 
43 /// @todo Needs a ref-counting mutex.
44 static iBlockData emptyBlockData = {
45     .refCount = 1,
46     .data = "",
47     .size = 0,
48     .allocSize = 1,
49 };
50 
new_BlockData_(size_t size,size_t allocSize)51 static iBlockData *new_BlockData_(size_t size, size_t allocSize) {
52     iBlockData *d = iMalloc(BlockData);
53     set_Atomic(&d->refCount, 1);
54     d->size = size;
55     d->allocSize = iMax(size + 1, allocSize);
56     d->data = malloc(d->allocSize);
57     return d;
58 }
59 
newPrealloc_BlockData_(void * data,size_t size,size_t allocSize)60 static iBlockData *newPrealloc_BlockData_(void *data, size_t size, size_t allocSize) {
61     iBlockData *d = iMalloc(BlockData);
62     set_Atomic(&d->refCount, 1);
63     d->size = size;
64     d->allocSize = allocSize;
65     d->data = data;
66     return d;
67 }
68 
duplicate_BlockData_(const iBlockData * d,size_t allocSize)69 static iBlockData *duplicate_BlockData_(const iBlockData *d, size_t allocSize) {
70     iBlockData *dupl = new_BlockData_(d->size, allocSize);
71     memcpy(dupl->data, d->data, iMin(d->allocSize, dupl->size + 1));
72     return dupl;
73 }
74 
deref_BlockData_(iBlockData * d)75 static void deref_BlockData_(iBlockData *d) {
76     const int refWas = addRelaxed_Atomic(&d->refCount, -1);
77     if (refWas == 1) {
78         iAssert(d != &emptyBlockData);
79         free(d->data);
80         free(d);
81     }
82 }
83 
reserve_BlockData_(iBlockData * d,size_t size)84 static void reserve_BlockData_(iBlockData *d, size_t size) {
85     size++;
86     if (d->allocSize >= size) return;
87     iAssert(value_Atomic(&d->refCount) == 1);
88     iAssert(d->allocSize > 0);
89     /* Reserve increased amount of memory in powers-of-two. */
90     for (d->allocSize = 8; d->allocSize < size; d->allocSize <<= 1) {}
91     d->data = realloc(d->data, d->allocSize);
92 }
93 
memcpyFrom_Block_(iBlock * d,const void * data,size_t size)94 static void memcpyFrom_Block_(iBlock *d, const void *data, size_t size) {
95     if (size) {
96         memcpy(d->i->data, data, size);
97         d->i->data[size] = 0;
98         d->i->size = size;
99     }
100 }
101 
detach_Block_(iBlock * d,size_t allocSize)102 static void detach_Block_(iBlock *d, size_t allocSize) {
103     if (value_Atomic(&d->i->refCount) > 1) {
104         iBlockData *detached = duplicate_BlockData_(d->i, allocSize);
105         deref_BlockData_(d->i);
106         d->i = detached;
107     }
108     iAssert(value_Atomic(&d->i->refCount) == 1);
109 }
110 
111 /*-------------------------------------------------------------------------------------*/
112 
113 iDefineTypeConstructionArgs(Block, (size_t size), size)
114 
newCStr_Block(const char * cstr)115 iBlock *newCStr_Block(const char *cstr) {
116     iBlock *d = new_Block(strlen(cstr));
117     memcpyFrom_Block_(d, cstr, d->i->size);
118     return d;
119 }
120 
newData_Block(const void * data,size_t size)121 iBlock *newData_Block(const void *data, size_t size) {
122     iBlock *d = new_Block(size);
123     memcpyFrom_Block_(d, data, size);
124     return d;
125 }
126 
newPrealloc_Block(void * data,size_t size,size_t allocSize)127 iBlock *newPrealloc_Block(void *data, size_t size, size_t allocSize) {
128     iBlock *d = iMalloc(Block);
129     initPrealloc_Block(d, data, size, allocSize);
130     return d;
131 }
132 
copy_Block(const iBlock * d)133 iBlock *copy_Block(const iBlock *d) {
134     if (d) {
135         iBlock *dupl = malloc(sizeof(iBlock));
136         initCopy_Block(dupl, d);
137         return dupl;
138     }
139     return NULL;
140 }
141 
init_Block(iBlock * d,size_t size)142 void init_Block(iBlock *d, size_t size) {
143     if (size == 0) {
144         d->i = &emptyBlockData;
145         addRelaxed_Atomic(&emptyBlockData.refCount, 1);
146     }
147     else {
148         d->i = new_BlockData_(size, 0);
149     }
150 }
151 
initData_Block(iBlock * d,const void * data,size_t size)152 void initData_Block(iBlock *d, const void *data, size_t size) {
153     if (size > 0) {
154         d->i = new_BlockData_(size, 0);
155         memcpyFrom_Block_(d, data, size);
156     }
157     else {
158         init_Block(d, size);
159     }
160 }
161 
initCStr_Block(iBlock * d,const char * cstr)162 void initCStr_Block(iBlock *d, const char *cstr) {
163     initData_Block(d, cstr, cstr ? strlen(cstr) : 0);
164 }
165 
initPrealloc_Block(iBlock * d,void * data,size_t size,size_t allocSize)166 void initPrealloc_Block(iBlock *d, void *data, size_t size, size_t allocSize) {
167     d->i = newPrealloc_BlockData_(data, size, allocSize);
168 }
169 
initCopy_Block(iBlock * d,const iBlock * other)170 void initCopy_Block(iBlock *d, const iBlock *other) {
171     if (other) {
172         addRelaxed_Atomic(&other->i->refCount, 1);
173         d->i = other->i;
174     }
175     else {
176         init_Block(d, 0);
177     }
178 }
179 
deinit_Block(iBlock * d)180 void deinit_Block(iBlock *d) {
181     deref_BlockData_(d->i);
182 }
183 
serialize_Block(const iBlock * d,iStream * outs)184 void serialize_Block(const iBlock *d, iStream *outs) {
185     writeU32_Stream(outs, (uint32_t) d->i->size);
186     if (d->i->size) {
187         writeData_Stream(outs, d->i->data, d->i->size);
188     }
189 }
190 
deserialize_Block(iBlock * d,iStream * ins)191 void deserialize_Block(iBlock *d, iStream *ins) {
192     clear_Block(d);
193     const size_t len = readU32_Stream(ins);
194     if (len) {
195         resize_Block(d, len);
196         readData_Stream(ins, len, d->i->data);
197     }
198 }
199 
size_Block(const iBlock * d)200 size_t size_Block(const iBlock *d) {
201     return d->i->size;
202 }
203 
at_Block(const iBlock * d,size_t pos)204 char at_Block(const iBlock *d, size_t pos) {
205     iAssert(pos < d->i->size);
206     return d->i->data[pos];
207 }
208 
front_Block(const iBlock * d)209 char front_Block(const iBlock *d) {
210     return d->i->data[0];
211 }
212 
back_Block(const iBlock * d)213 char back_Block(const iBlock *d) {
214     return d->i->data[d->i->size - 1];
215 }
216 
constData_Block(const iBlock * d)217 const void *constData_Block(const iBlock *d) {
218     return d->i->data;
219 }
220 
constBegin_Block(const iBlock * d)221 const char *constBegin_Block(const iBlock *d) {
222     return d->i->data;
223 }
224 
constEnd_Block(const iBlock * d)225 const char *constEnd_Block(const iBlock *d) {
226     return d->i->data + d->i->size;
227 }
228 
mid_Block(const iBlock * d,size_t start,size_t count)229 iBlock *mid_Block(const iBlock *d, size_t start, size_t count) {
230     if (start >= d->i->size) {
231         return new_Block(0);
232     }
233     const size_t midSize = iMin(count, d->i->size - start);
234     iBlock *mid = new_Block(midSize);
235     memcpyFrom_Block_(mid, d->i->data + start, midSize);
236     return mid;
237 }
238 
data_Block(iBlock * d)239 void *data_Block(iBlock *d) {
240     detach_Block_(d, 0);
241     return d->i->data;
242 }
243 
clear_Block(iBlock * d)244 void clear_Block(iBlock *d) {
245     deref_BlockData_(d->i);
246     d->i = &emptyBlockData;
247     addRelaxed_Atomic(&emptyBlockData.refCount, 1);
248 }
249 
reserve_Block(iBlock * d,size_t reservedSize)250 void reserve_Block(iBlock *d, size_t reservedSize) {
251     detach_Block_(d, reservedSize + 1);
252     reserve_BlockData_(d->i, reservedSize);
253 }
254 
resize_Block(iBlock * d,size_t size)255 void resize_Block(iBlock *d, size_t size) {
256     if (size < size_Block(d)) {
257         truncate_Block(d, size);
258         return;
259     }
260     reserve_Block(d, size);
261     const size_t oldSize = d->i->size;
262     d->i->size = size;
263     memset(d->i->data + oldSize, 0, d->i->size - oldSize + 1);
264 }
265 
truncate_Block(iBlock * d,size_t size)266 void truncate_Block(iBlock *d, size_t size) {
267     if (size < size_Block(d)) {
268         detach_Block_(d, 0);
269         d->i->size = iMin(d->i->size, size); // note: allocated size does not change
270         d->i->data[d->i->size] = 0;
271     }
272 }
273 
remove_Block(iBlock * d,size_t start,size_t count)274 void remove_Block(iBlock *d, size_t start, size_t count) {
275     detach_Block_(d, 0);
276     iAssert(start <= d->i->size);
277     if (count == iInvalidSize || start + count > d->i->size) {
278         count = d->i->size - start;
279     }
280     const size_t remainder = d->i->size - start - count;
281     if (remainder > 0) {
282         memmove(d->i->data + start, d->i->data + start + count, remainder);
283     }
284     d->i->size -= count;
285     d->i->data[d->i->size] = 0;
286 }
287 
printf_Block(iBlock * d,const char * format,...)288 void printf_Block(iBlock *d, const char *format, ...) {
289     va_list args;
290     va_start(args, format);
291     vprintf_Block(d, format, args);
292     va_end(args);
293 }
294 
vprintf_Block(iBlock * d,const char * format,va_list args)295 void vprintf_Block(iBlock *d, const char *format, va_list args) {
296     va_list args2;
297     va_copy(args2, args);
298     const int len = vsnprintf(NULL, 0, format, args);
299     reserve_Block(d, len);
300     vsprintf(d->i->data, format, args2);
301     d->i->size = len;
302     va_end(args2);
303 }
304 
fill_Block(iBlock * d,char value)305 void fill_Block(iBlock *d, char value) {
306     detach_Block_(d, 0);
307     memset(d->i->data, value, d->i->size);
308     d->i->data[d->i->size] = 0;
309 }
310 
pushBack_Block(iBlock * d,char value)311 void pushBack_Block(iBlock *d, char value) {
312     reserve_Block(d, d->i->size + 1);
313     d->i->data[d->i->size++] = value;
314     d->i->data[d->i->size] = 0;
315 }
316 
popBack_Block(iBlock * d)317 void popBack_Block(iBlock *d) {
318     detach_Block_(d, 0);
319     if (d->i->size > 0) {
320         d->i->data[--d->i->size] = 0;
321     }
322 }
323 
set_Block(iBlock * d,const iBlock * other)324 void set_Block(iBlock *d, const iBlock *other) {
325     if (d != other) {
326         addRelaxed_Atomic(&other->i->refCount, 1);
327         deref_BlockData_(d->i);
328         d->i = other->i;
329     }
330 }
331 
setByte_Block(iBlock * d,size_t pos,char value)332 void setByte_Block(iBlock *d, size_t pos, char value) {
333     detach_Block_(d, 0);
334     iAssert(pos < d->i->size);
335     d->i->data[pos] = value;
336 }
337 
setData_Block(iBlock * d,const void * data,size_t size)338 void setData_Block(iBlock *d, const void *data, size_t size) {
339     if (size) {
340         reserve_Block(d, size);
341         memcpyFrom_Block_(d, data, size);
342     }
343     else {
344         clear_Block(d);
345     }
346 }
347 
setSubData_Block(iBlock * d,size_t pos,const void * data,size_t size)348 void setSubData_Block(iBlock *d, size_t pos, const void *data, size_t size) {
349     reserve_Block(d, pos + size);
350     iAssert(pos <= d->i->size);
351     memcpy(d->i->data + pos, data, size);
352     d->i->size = iMax(d->i->size, pos + size);
353     if (d->i->size == pos + size) {
354         d->i->data[d->i->size] = 0;
355     }
356 }
357 
setCStr_Block(iBlock * d,const char * cstr)358 void setCStr_Block(iBlock *d, const char *cstr) {
359     setData_Block(d, cstr, strlen(cstr));
360 }
361 
append_Block(iBlock * d,const iBlock * other)362 void append_Block(iBlock *d, const iBlock *other) {
363     appendData_Block(d, other->i->data, other->i->size);
364 }
365 
appendData_Block(iBlock * d,const void * data,size_t size)366 void appendData_Block(iBlock *d, const void *data, size_t size) {
367     reserve_Block(d, d->i->size + size);
368     memcpy(d->i->data + d->i->size, data, size);
369     d->i->size += size;
370     d->i->data[d->i->size] = 0;
371 }
372 
appendCStr_Block(iBlock * d,const char * cstr)373 void appendCStr_Block(iBlock *d, const char *cstr) {
374     appendData_Block(d, cstr, strlen(cstr));
375 }
376 
insertData_Block(iBlock * d,size_t insertAt,const void * data,size_t size)377 void insertData_Block(iBlock *d, size_t insertAt, const void *data, size_t size) {
378     reserve_Block(d, d->i->size + size);
379     char *start = d->i->data + insertAt;
380     memmove(start + size, start, d->i->size - insertAt);
381     memcpy (start,        data,  size);
382     d->i->size += size;
383     d->i->data[d->i->size] = 0;
384 }
385 
concat_Block(const iBlock * d,const iBlock * other)386 iBlock *concat_Block(const iBlock *d, const iBlock *other) {
387     iBlock *cat = new_Block(d->i->size + other->i->size);
388     memcpy(cat->i->data,                  d->i->data,     d->i->size);
389     memcpy(cat->i->data + d->i->size, other->i->data, other->i->size);
390     cat->i->data[cat->i->size] = 0;
391     return cat;
392 }
393 
cmp_Block(const iBlock * d,const iBlock * other)394 int cmp_Block(const iBlock *d, const iBlock *other) {
395     return cmpData_Block(d, other->i->data, other->i->size);
396 }
397 
cmpCase_Block(const iBlock * d,const iBlock * other)398 int cmpCase_Block(const iBlock *d, const iBlock *other) {
399     return iCmpStrCase(d->i->data, other->i->data);
400 }
401 
cmpCaseN_Block(const iBlock * d,const iBlock * other,size_t size)402 int cmpCaseN_Block(const iBlock *d, const iBlock *other, size_t size) {
403     return iCmpStrNCase(d->i->data, other->i->data, size);
404 }
405 
cmpData_Block(const iBlock * d,const char * data,size_t size)406 int cmpData_Block(const iBlock *d, const char *data, size_t size) {
407     return memcmp(d->i->data, data, iMin(size, d->i->size));
408 }
409 
cmpCStr_Block(const iBlock * d,const char * cstr)410 int cmpCStr_Block(const iBlock *d, const char *cstr) {
411     return iCmpStr(d->i->data, cstr);
412 }
413 
cmpCStrN_Block(const iBlock * d,const char * cstr,size_t len)414 int cmpCStrN_Block(const iBlock *d, const char *cstr, size_t len) {
415     return iCmpStrN(d->i->data, cstr, len);
416 }
417 
cmpCaseCStr_Block(const iBlock * d,const char * cstr)418 int cmpCaseCStr_Block(const iBlock *d, const char *cstr) {
419     return iCmpStrCase(d->i->data, cstr);
420 }
421 
cmpCaseCStrN_Block(const iBlock * d,const char * cstr,size_t len)422 int cmpCaseCStrN_Block(const iBlock *d, const char *cstr, size_t len) {
423     return iCmpStrNCase(d->i->data, cstr, len);
424 }
425 
crc32_Block(const iBlock * d)426 uint32_t crc32_Block(const iBlock *d) {
427     return iCrc32(d->i->data, d->i->size);
428 }
429 
md5_Block(const iBlock * d,uint8_t md5_out[16])430 void md5_Block(const iBlock *d, uint8_t md5_out[16]) {
431     iMd5Hash(d->i->data, d->i->size, md5_out);
432 }
433 
decode_Block(const iBlock * d,const char * textEncoding)434 iString *decode_Block(const iBlock *d, const char *textEncoding) {
435     size_t len = 0;
436     uint8_t *data = u8_conv_from_encoding(textEncoding,
437                                           iconveh_question_mark,
438                                           constData_Block(d),
439                                           size_Block(d),
440                                           NULL,
441                                           NULL,
442                                           &len);
443     data = realloc(data, len + 1);
444     data[len] = 0;
445     iString *str = iMalloc(String);
446     initPrealloc_Block(&str->chars, data, len, len + 1);
447     return str;
448 }
449 
hexEncode_Block(const iBlock * d)450 iString *hexEncode_Block(const iBlock *d) {
451     static const char hexValues[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
452                                         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
453     iString *hex = new_String();
454     for (const char *i = constBegin_Block(d), *end = constEnd_Block(d); i != end; i++) {
455         const uint8_t val = *i;
456         appendChar_String(hex, hexValues[val >> 4]);
457         appendChar_String(hex, hexValues[val & 15]);
458     }
459     return hex;
460 }
461 
fromHex_(char ch)462 static int fromHex_(char ch) {
463     if (ch >= 'a') return ch - 'a' + 10;
464     if (ch >= 'A') return ch - 'A' + 10;
465     return ch - '0';
466 }
467 
hexDecode_Rangecc(iRangecc range)468 iBlock *hexDecode_Rangecc(iRangecc range) {
469     iBlock *d = new_Block(size_Range(&range) / 2);
470     size_t pos = 0;
471     for (const char *i = range.start; i < range.end; i += 2) {
472         const uint8_t val = (fromHex_(i[0]) << 4) | fromHex_(i[1]);
473         setByte_Block(d, pos++, val);
474     }
475     return d;
476 }
477 
base64Index_(char ch)478 iLocalDef uint8_t base64Index_(char ch) {
479     /* TODO: Replace this with a lookup table. */
480     if (ch == '=') return 0; /* padding */
481     if (ch == '/') return 63;
482     if (ch == '+') return 62;
483     if (ch >= 'a') return ch - 'a' + 26;
484     if (ch >= 'A') return ch - 'A';
485     return ch - '0' + 52;
486 }
487 
base64Decode_Block(const iBlock * d)488 iBlock *base64Decode_Block(const iBlock *d) {
489     const size_t outSize = 6 * size_Block(d) / 8;
490     iBlock *     decoded = new_Block(outSize);
491     uint16_t     comp    = 0;
492     int          shift   = 10;
493     // |-------|-------| comp
494     //  7654321076543210
495     //       ^10         shift
496     //  aaaaaa
497     //             ^4    shift
498     //  aaaaaabbbbbb
499     uint8_t *out = data_Block(decoded);
500     for (const char *pos = constBegin_Block(d), *end = constEnd_Block(d); pos != end; pos++) {
501         comp |= base64Index_(*pos) << shift;
502         if (shift <= 8) {
503             *out++ = comp >> 8;
504             comp <<= 8;
505             shift += 8;
506         }
507         shift -= 6;
508     }
509     iAssert((size_t) (out - (uint8_t *) data_Block(decoded)) == outSize); /* all written */
510     return decoded;
511 }
512 
replace_Block(iBlock * d,char oldValue,char newValue)513 size_t replace_Block(iBlock *d, char oldValue, char newValue) {
514     size_t count = 0;
515     detach_Block_(d, 0);
516     for (char *i = d->i->data, *end = d->i->data + d->i->size; i != end; ++i) {
517         if (*i == oldValue) {
518             *i = newValue;
519             count++;
520         }
521     }
522     return count;
523 }
524 
525 /*-------------------------------------------------------------------------------------*/
526 #if defined (iHaveZlib)
527 
528 iDeclareType(ZStream)
529 
530 struct Impl_ZStream {
531     z_stream stream;
532     iBlock *out;
533 };
534 
init_ZStream_(iZStream * d,const iBlock * in,iBlock * out)535 static void init_ZStream_(iZStream *d, const iBlock *in, iBlock *out) {
536     d->out = out;
537     iZap(d->stream);
538     d->stream.avail_in  = (uInt) in->i->size;
539     d->stream.next_in   = (Bytef *) in->i->data;
540     d->stream.avail_out = (uInt) out->i->size;
541     d->stream.next_out  = (Bytef *) out->i->data;
542 }
543 
process_ZStream_(iZStream * d,int (* process)(z_streamp,int))544 static iBool process_ZStream_(iZStream *d, int (*process)(z_streamp, int)) {
545     int opts = Z_NO_FLUSH;
546     for (;;) {
547         int rc = process(&d->stream, opts);
548         if (rc == Z_STREAM_END) {
549             break;
550         }
551         else if (rc != Z_OK && rc != Z_BUF_ERROR) {
552             /* Something went wrong. */
553             return iFalse;
554         }
555         if (d->stream.avail_out == 0) {
556             /* Allocate more room. */
557             const size_t oldSize = size_Block(d->out);
558             resize_Block(d->out, oldSize * 2);
559             d->stream.next_out = (Bytef *) d->out->i->data + oldSize;
560             d->stream.avail_out = (uInt) (size_Block(d->out) - oldSize);
561         }
562         if (d->stream.avail_in == 0) {
563             opts = Z_FINISH;
564         }
565     }
566     truncate_Block(d->out, size_Block(d->out) - d->stream.avail_out);
567     return iTrue;
568 }
569 
compressLevel_Block(const iBlock * d,int level)570 iBlock *compressLevel_Block(const iBlock *d, int level) {
571     iBlock *out = new_Block(1024);
572     iZStream z;
573     init_ZStream_(&z, d, out);
574     /*
575      * The deflation is done in raw mode. From zlib documentation:
576      *
577      * "windowBits can also be –8..–15 for raw deflate. In this case, -windowBits
578      * determines the window size. deflate() will then generate raw deflate data with no
579      * zlib header or trailer, and will not compute an adler32 check value."
580      */
581     if (deflateInit2(&z.stream, level, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
582         if (!process_ZStream_(&z, deflate)) {
583             clear_Block(out);
584         }
585     }
586     deflateEnd(&z.stream);
587     return out;
588 }
589 
decompress_Block(const iBlock * d)590 iBlock *decompress_Block(const iBlock *d) {
591     iBlock *out = new_Block(1024);
592     iZStream z;
593     init_ZStream_(&z, d, out);
594     if (inflateInit2(&z.stream, -MAX_WBITS) == Z_OK) {
595         if (!process_ZStream_(&z, inflate)) {
596             clear_Block(out);
597         }
598     }
599     inflateEnd(&z.stream);
600     return out;
601 }
602 
603 #endif // HaveZlib
604