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