1 /*$
2 Copyright (C) 2016-2020 Azel.
3
4 This file is part of AzPainterB.
5
6 AzPainterB is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainterB is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * mZlib
22 *****************************************/
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <zlib.h>
27
28 #include "mDef.h"
29 #include "mFile.h"
30 #include "mZlib.h"
31
32
33 //-----------------------
34
35 typedef struct _mZlibEncode
36 {
37 z_stream z;
38 FILE *fp;
39 uint8_t *buf;
40 int bufsize;
41 uint32_t writesize;
42 }mZlibEncode;
43
44 typedef struct _mZlibDecode
45 {
46 z_stream z;
47 FILE *fp;
48 uint8_t *buf;
49 int bufsize;
50 uint32_t insize;
51 }mZlibDecode;
52
53 //-----------------------
54
55
56
57 /**
58 @defgroup zlib mZlib
59 @brief zlib ユーティリティ関数
60
61 @ingroup group_lib
62
63 @{
64 @file mZlib.h
65 */
66
67
68 //===========================
69 // sub
70 //===========================
71
72
73 /** 圧縮初期化
74 *
75 * @param memlevel 0 以下で deflateInit() を使う */
76
_init_encode(uint8_t ** ppbuf,int bufsize,z_stream * z,int level,int windowbits,int memlevel,int strategy)77 static mBool _init_encode(uint8_t **ppbuf,int bufsize,z_stream *z,
78 int level,int windowbits,int memlevel,int strategy)
79 {
80 int ret;
81
82 //作業用バッファ
83
84 *ppbuf = (uint8_t *)mMalloc(bufsize, FALSE);
85 if(!(*ppbuf)) return FALSE;
86
87 //zlib 初期化
88
89 memset(z, 0, sizeof(z_stream));
90
91 if(memlevel <= 0)
92 ret = deflateInit(z, level);
93 else
94 ret = deflateInit2(z, level, Z_DEFLATED, windowbits, memlevel, strategy);
95
96 if(ret == Z_OK)
97 return TRUE;
98 else
99 {
100 mFree(*ppbuf);
101 return FALSE;
102 }
103 }
104
105 /** 展開初期化 */
106
_init_decode(uint8_t ** ppbuf,int bufsize,z_stream * z,int windowbits)107 static mBool _init_decode(uint8_t **ppbuf,int bufsize,z_stream *z,int windowbits)
108 {
109 int ret;
110
111 //作業用バッファ
112
113 *ppbuf = (uint8_t *)mMalloc(bufsize, FALSE);
114 if(!(*ppbuf)) return FALSE;
115
116 //zlib 初期化
117
118 memset(z, 0, sizeof(z_stream));
119
120 if(windowbits)
121 ret = inflateInit2(z, windowbits);
122 else
123 ret = inflateInit(z);
124
125 if(ret == Z_OK)
126 return TRUE;
127 else
128 {
129 mFree(*ppbuf);
130 return FALSE;
131 }
132 }
133
134
135 //=================================
136 // mZlibEncode : 圧縮
137 //=================================
138
139
140
141 /** 書き込み処理 */
142
_encode_write(mZlibEncode * p,int size)143 static mBool _encode_write(mZlibEncode *p,int size)
144 {
145 if(p->fp)
146 return (fwrite(p->buf, 1, size, p->fp) == size);
147 else
148 return FALSE;
149 }
150
151 /** 解放 */
152
mZlibEncodeFree(mZlibEncode * p)153 void mZlibEncodeFree(mZlibEncode *p)
154 {
155 if(p)
156 {
157 deflateEnd(&p->z);
158
159 mFree(p->buf);
160 mFree(p);
161 }
162 }
163
164 /** 作成
165 *
166 * @param bufsize 圧縮用バッファのサイズ (0 以下で自動)
167 * @param level 圧縮率 (0-9)
168 * @param windowbits [8-15] zlib 形式 [+16] gzip 形式 [-8...-15] ヘッダなし zlib
169 * @param memlevel 1-9 (default: 8)
170 * @param strategy 圧縮タイプ (default: 0) */
171
mZlibEncodeNew(int bufsize,int level,int windowbits,int memlevel,int strategy)172 mZlibEncode *mZlibEncodeNew(int bufsize,
173 int level,int windowbits,int memlevel,int strategy)
174 {
175 mZlibEncode *p;
176
177 if(bufsize <= 0) bufsize = 8 * 1024;
178
179 p = (mZlibEncode *)mMalloc(sizeof(mZlibEncode), TRUE);
180 if(!p) return NULL;
181
182 if(!_init_encode(&p->buf, bufsize, &p->z, level, windowbits, memlevel, strategy))
183 {
184 mFree(p);
185 return NULL;
186 }
187
188 //
189
190 p->bufsize = bufsize;
191
192 p->z.next_out = p->buf;
193 p->z.avail_out = bufsize;
194
195 return p;
196 }
197
198 /** 作成 (シンプル) */
199
mZlibEncodeNew_simple(int bufsize,int level)200 mZlibEncode *mZlibEncodeNew_simple(int bufsize,int level)
201 {
202 return mZlibEncodeNew(bufsize, level, 0, -1, 0);
203 }
204
205 /** ファイルポインタ (FILE *) をセット */
206
mZlibEncodeSetIO_stdio(mZlibEncode * p,void * fp)207 void mZlibEncodeSetIO_stdio(mZlibEncode *p,void *fp)
208 {
209 p->fp = (FILE *)fp;
210 }
211
212 /** 書き込まれたサイズを取得 */
213
mZlibEncodeGetWriteSize(mZlibEncode * p)214 uint32_t mZlibEncodeGetWriteSize(mZlibEncode *p)
215 {
216 return p->writesize;
217 }
218
219 /** リセットする */
220
mZlibEncodeReset(mZlibEncode * p)221 mBool mZlibEncodeReset(mZlibEncode *p)
222 {
223 p->z.next_out = p->buf;
224 p->z.avail_out = p->bufsize;
225 p->writesize = 0;
226
227 return (deflateReset(&p->z) == Z_OK);
228 }
229
230 /** データを送る */
231
mZlibEncodeSend(mZlibEncode * p,void * buf,int size)232 mBool mZlibEncodeSend(mZlibEncode *p,void *buf,int size)
233 {
234 z_stream *z = &p->z;
235 int ret,bufsize;
236
237 bufsize = p->bufsize;
238
239 z->next_in = (unsigned char *)buf;
240 z->avail_in = size;
241
242 while(z->avail_in)
243 {
244 ret = deflate(z, Z_NO_FLUSH);
245 if(ret != Z_OK && ret != Z_STREAM_END) return FALSE;
246
247 //バッファが一杯なので書き出し
248
249 if(z->avail_out == 0)
250 {
251 if(!_encode_write(p, bufsize)) return FALSE;
252
253 z->next_out = p->buf;
254 z->avail_out = bufsize;
255
256 p->writesize += bufsize;
257 }
258 }
259
260 return TRUE;
261 }
262
263 /** 残りのデータを処理する */
264
mZlibEncodeFlushEnd(mZlibEncode * p)265 mBool mZlibEncodeFlushEnd(mZlibEncode *p)
266 {
267 z_stream *z = &p->z;
268 int ret,bufsize;
269
270 bufsize = p->bufsize;
271
272 //残りデータの圧縮
273
274 while(1)
275 {
276 ret = deflate(z, Z_FINISH);
277
278 if(ret == Z_STREAM_END)
279 break;
280 else if(ret != Z_OK)
281 return FALSE;
282
283 //書き出し
284
285 if(z->avail_out == 0)
286 {
287 if(!_encode_write(p, bufsize))
288 return FALSE;
289
290 z->next_out = p->buf;
291 z->avail_out = bufsize;
292
293 p->writesize += bufsize;
294 }
295 }
296
297 //バッファ残りの書き込み
298
299 ret = bufsize - z->avail_out;
300
301 if(ret)
302 {
303 if(!_encode_write(p, ret)) return FALSE;
304
305 p->writesize += ret;
306 }
307
308 return TRUE;
309 }
310
311
312 //===========================
313 // mZlibDecode : 展開
314 //===========================
315
316
317 /** バッファサイズ分を読み込み */
318
_decode_read(mZlibDecode * p)319 static int _decode_read(mZlibDecode *p)
320 {
321 int size;
322
323 if(p->fp)
324 size = fread(p->buf, 1, (p->insize < p->bufsize)? p->insize: p->bufsize, p->fp);
325 else
326 size = 0;
327
328 if(size > 0)
329 p->insize -= size;
330
331 return size;
332 }
333
334 /** 解放 */
335
mZlibDecodeFree(mZlibDecode * p)336 void mZlibDecodeFree(mZlibDecode *p)
337 {
338 if(p)
339 {
340 inflateEnd(&p->z);
341
342 mFree(p->buf);
343 mFree(p);
344 }
345 }
346
347 /** 作成
348 *
349 * @param windowbits 圧縮時と同じ (default: 15) */
350
mZlibDecodeNew(int bufsize,int windowbits)351 mZlibDecode *mZlibDecodeNew(int bufsize,int windowbits)
352 {
353 mZlibDecode *p;
354
355 if(bufsize <= 0) bufsize = 8 * 1024;
356
357 p = (mZlibDecode *)mMalloc(sizeof(mZlibDecode), TRUE);
358 if(!p) return NULL;
359
360 if(!_init_decode(&p->buf, bufsize, &p->z, windowbits))
361 {
362 mFree(p);
363 return NULL;
364 }
365
366 p->bufsize = bufsize;
367
368 return p;
369 }
370
371 /** ファイルポインタ (FILE *) をセット */
372
mZlibDecodeSetIO_stdio(mZlibDecode * p,void * fp)373 void mZlibDecodeSetIO_stdio(mZlibDecode *p,void *fp)
374 {
375 p->fp = fp;
376 }
377
378 /** 入力データ (圧縮後のサイズ) をセット */
379
mZlibDecodeSetInSize(mZlibDecode * p,uint32_t size)380 void mZlibDecodeSetInSize(mZlibDecode *p,uint32_t size)
381 {
382 p->insize = size;
383 }
384
385 /** リセット */
386
mZlibDecodeReset(mZlibDecode * p)387 void mZlibDecodeReset(mZlibDecode *p)
388 {
389 inflateReset(&p->z);
390
391 p->insize = 0;
392 }
393
394 /** 一回で最後まですべて展開
395 *
396 * @param insize 入力サイズ
397 * @return エラーコード */
398
mZlibDecodeReadOnce(mZlibDecode * p,void * buf,int bufsize,uint32_t insize)399 int mZlibDecodeReadOnce(mZlibDecode *p,void *buf,int bufsize,uint32_t insize)
400 {
401 z_stream *z = &p->z;
402 int n;
403
404 p->insize = insize;
405
406 z->next_out = (unsigned char *)buf;
407 z->avail_out = bufsize;
408
409 while(1)
410 {
411 //ファイルからバッファへ読み込み
412
413 if(z->avail_in == 0)
414 {
415 if(p->insize == 0) return MZLIBDEC_READ_INDATA;
416
417 n = _decode_read(p);
418 if(n <= 0) return MZLIBDEC_READ_INDATA;
419
420 z->next_in = p->buf;
421 z->avail_in = n;
422 }
423
424 //展開
425
426 n = inflate(z, Z_NO_FLUSH);
427
428 if(n == Z_STREAM_END)
429 break;
430 else if(n != Z_OK)
431 return MZLIBDEC_READ_ZLIB;
432 }
433
434 //念の為入力データを最後まで読み込む
435
436 while(p->insize)
437 {
438 if(_decode_read(p) <= 0)
439 return MZLIBDEC_READ_INDATA;
440 }
441
442 return MZLIBDEC_READ_OK;
443 }
444
445 /** 指定サイズ分を読み込み
446 *
447 * @return エラーコード */
448
mZlibDecodeRead(mZlibDecode * p,void * buf,int size)449 int mZlibDecodeRead(mZlibDecode *p,void *buf,int size)
450 {
451 z_stream *z = &p->z;
452 int n;
453
454 z->next_out = (unsigned char *)buf;
455 z->avail_out = size;
456
457 while(z->avail_out)
458 {
459 //ファイルからバッファへ読み込み
460
461 if(z->avail_in == 0)
462 {
463 if(p->insize == 0) return MZLIBDEC_READ_INDATA;
464
465 n = _decode_read(p);
466 if(n <= 0) return MZLIBDEC_READ_INDATA;
467
468 z->next_in = p->buf;
469 z->avail_in = n;
470 }
471
472 //展開
473
474 n = inflate(z, Z_NO_FLUSH);
475
476 if(n == Z_STREAM_END)
477 break;
478 else if(n != Z_OK)
479 return MZLIBDEC_READ_ZLIB;
480 }
481
482 return MZLIBDEC_READ_OK;
483 }
484
485 /** 読み込み終了
486 *
487 * mZlibDecodeRead() で複数回に分けて読み込んだ場合、実行すること。
488 *
489 * @return エラーコード */
490
mZlibDecodeReadEnd(mZlibDecode * p)491 int mZlibDecodeReadEnd(mZlibDecode *p)
492 {
493 //入力データが残っている場合、すべて読み込む
494 /* Z_STREAM_END が来ていない場合、すべてのデータを展開済みでも、
495 * 数バイト残っている場合がある。 */
496
497 while(p->insize)
498 {
499 if(_decode_read(p) <= 0)
500 return MZLIBDEC_READ_INDATA;
501 }
502
503 return MZLIBDEC_READ_OK;
504 }
505
506
507 //===========================
508 // 単体関数
509 //===========================
510
511
512 /** ファイルから展開
513 *
514 * @param compsize 圧縮後のサイズ
515 * @param bufsize 作業用バッファサイズ (0 で自動)
516 * @param windowbits 0 で zlib 形式。-15 で生データ */
517
mZlibDecodeFILE(mFile file,void * dstbuf,uint32_t dstsize,uint32_t compsize,uint32_t bufsize,int windowbits)518 mBool mZlibDecodeFILE(mFile file,void *dstbuf,uint32_t dstsize,
519 uint32_t compsize,uint32_t bufsize,int windowbits)
520 {
521 z_stream z;
522 uint8_t *buf;
523 uint32_t remain;
524 int ret;
525 mBool result = FALSE;
526
527 if(!bufsize) bufsize = 8 * 1024;
528
529 //初期化
530
531 if(!_init_decode(&buf, bufsize, &z, windowbits))
532 return FALSE;
533
534 //
535
536 z.next_out = (uint8_t *)dstbuf;
537 z.avail_out = dstsize;
538
539 remain = compsize;
540
541 while(1)
542 {
543 //ファイルから読み込み
544
545 if(z.avail_in == 0)
546 {
547 ret = mFileRead(file, buf, (remain < bufsize)? remain: bufsize);
548 if(ret == 0) break;
549
550 z.next_in = buf;
551 z.avail_in = ret;
552
553 remain -= ret;
554 }
555
556 //展開
557
558 ret = inflate(&z, Z_NO_FLUSH);
559
560 if(ret == Z_STREAM_END)
561 {
562 result = TRUE;
563 break;
564 }
565 else if(ret != Z_OK)
566 break;
567 }
568
569 //終了
570
571 inflateEnd(&z);
572
573 mFree(buf);
574
575 return result;
576 }
577
578
579 /** @} */
580