1 /*
2 Copyright (C) 2016-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dk4strmco.ctr
12 */
13 
14 /**	@file dk4strmco.c The dk4strmco module.
15 */
16 
17 
18 #include "dk4conf.h"
19 
20 #if	DK4_HAVE_ZLIB_H
21 #ifndef	ZLIB_H_INCLUDED
22 #include <zlib.h>
23 #define	ZLIB_H_INCLUDED 1
24 #endif
25 #endif
26 
27 #if	DK4_HAVE_LIMITS_H
28 #ifndef	LIMITS_H_INCLUDED
29 #include <limits.h>
30 #define	LIMITS_H_INCLUDED 1
31 #endif
32 #endif
33 
34 #include <libdk4c/dk4rle.h>
35 #include <libdk4c/dk4a85e.h>
36 #include <libdk4c/dk4strmco.h>
37 #include <libdk4base/dk4mem.h>
38 #include <libdk4base/dk4memrs.h>
39 #include <libdk4c/dk4lzwe.h>
40 
41 #if DK4_HAVE_ASSERT_H
42 #ifndef	ASSERT_H_INCLUDED
43 #include <assert.h>
44 #define	ASSERT_H_INCLUDED 1
45 #endif
46 #endif
47 
48 
49 
50 
51 
52 #ifndef	DK4_STRMCO_ZBUF_SIZE
53 #define	DK4_STRMCO_ZBUF_SIZE	4096
54 #endif
55 
56 
57 
58 /**	Compressor data structure.
59 */
60 typedef struct {
61 	char				 zbuf[DK4_STRMCO_ZBUF_SIZE];	/**< Output buffer. */
62 	union {
63 #if DK4_HAVE_ZLIB_H
64 		z_stream		 zs;		/**< Flate compression structure. */
65 #endif
66 		dk4_lzwe_t		 lzw;		/**< LZW compression structure. */
67 	}					 u_co;		/**< Compression structures. */
68 	union {
69 		dk4_rl_enc_t	 rle;		/**< Run-length encoder. */
70 	}					 u_pp;		/**< Preprocessing structures. */
71 	union {
72 		dk4_a85_enc_t	 a85;		/**< ASCII-85 encoder. */
73 	}					 u_oe;		/**< Output encoding structures. */
74 	dk4_stream_t		*dststrm;	/**< Destination stream. */
75 	size_t				 ll;		/**< Line length. */
76 	int					 pp;		/**< Preprocessing. */
77 	int					 co;		/**< Compression. */
78 	int					 oe;		/**< Output encoding. */
79 	int					 fl;		/**< Flags. */
80 } compressor_t;
81 
82 
83 
84 /**	Newline.
85 */
86 static char nl[] = {
87 	'\n', '\0'
88 };
89 
90 
91 
92 /**	Carriage return and newline.
93 */
94 static char crnl[] = {
95 	'\r', '\n', '\0'
96 };
97 
98 
99 
100 /**	Finalizer for ASCII-Hex encoding.
101 */
102 static char ahfin[] = {
103 	'>', '\0'
104 };
105 
106 
107 
108 /**	Finalizer for ASCII-85 encoding.
109 */
110 static char a85fin[] = {
111 	'~', '>', '\0'
112 };
113 
114 
115 
116 /**	Hexadecimal digits using lower case characters.
117 */
118 static char lower[] = {
119 	'0', '1', '2', '3', '4', '5', '6', '7',
120 	'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '\0'
121 };
122 
123 
124 
125 /**	Hexadecimal digits using upper case characters.
126 */
127 static char upper[] = {
128 	'0', '1', '2', '3', '4', '5', '6', '7',
129 	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '\0'
130 };
131 
132 
133 
134 /**	Write newline to destination stream.
135 	@param	co	Compressor structure.
136 	@return	1 on success, 0 on error.
137 */
138 static
139 int
dk4strmco_nl(compressor_t * co)140 dk4strmco_nl(compressor_t *co)
141 {
142 	int		back	= 0;
143 
144 #if	DK4_USE_ASSERT
145 	assert(NULL != co);
146 #endif
147 	if (0 != (DK4_STRMCO_FL_CR_NL & (co->fl))) {
148 		back = dk4stream_write(co->dststrm, crnl, 2, NULL);
149 	}
150 	else {
151 		back = dk4stream_write(co->dststrm, nl, 1, NULL);
152 	}
153 
154 	return back;
155 }
156 
157 
158 
159 
160 /**	Write bytes to compressor at output encoding level.
161 	@param	co	Compressor to write to.
162 	@param	b	Buffer start address.
163 	@param	sz	Number of bytes to write.
164 	@param	szo	Address of variable for number of bytes written, may be NULL.
165 	@return	1 on success, 0 on error.
166 */
167 static
168 int
dk4strmco_co_oe(compressor_t * co,const char * b,size_t sz,size_t * szo)169 dk4strmco_co_oe(
170 	compressor_t	*co,
171 	const char		*b,
172 	size_t			 sz,
173 	size_t			*szo
174 )
175 {
176 	char			 buf[8];		/* Buffer for hexadecimal digits. */
177 	const char		*dptr;			/* Pointer to A85 encoding result. */
178 	size_t			 osz	= 0;	/* Number of bytes processed. */
179 	size_t			 szd	= 0;	/* A85 encoding result length. */
180 	size_t			 i		= 0;	/* Index of current byte to process. */
181 	size_t			 j		= 0;	/* Index of cur out char. */
182 	int				 back	= 0;	/* Function result. */
183 	int				 res;			/* Result from various operations. */
184 	unsigned		 us;			/* Index in hex digits array. */
185 	unsigned char	 uc;			/* UC version of current character */
186 
187 #if	DK4_USE_ASSERT
188 	assert(NULL != co);
189 	assert(NULL != b);
190 	assert(0 < sz);
191 #endif
192 	switch (co->oe) {
193 		case DK4_STRMCO_OE_ASCII85 : {
194 
195 			back = 1;
196 			for (i = 0; ((i < sz) && (1 == back)); i++) {
197 				switch (
198 					dk4a85_enc_add(
199 						&(co->u_oe.a85), (unsigned char)(b[i]), NULL
200 					)
201 				) {
202 					case DK4_EDSTM_ACCEPT : {
203 						osz++;
204 					} break;
205 					case DK4_EDSTM_FINISHED : {
206 						dptr = NULL;
207 						szd   = 0;
208 						res = dk4a85_enc_output(
209 							&dptr, &szd, &(co->u_oe.a85), NULL
210 						);
211 						if (0 < res) {
212 							if (0 < szd) {
213 #if	VERSION_BEFORE_20161019
214 								res = dk4stream_write(
215 									co->dststrm, dptr, szd, NULL
216 								);
217 								if (0 < res) {
218 									osz++;
219 									co->ll += szd;
220 									if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) {
221 										if (74 <= co->ll) {
222 											res = dk4strmco_nl(co);
223 											if (0 < res) {
224 												co->ll = 0;
225 											}
226 											else {
227 												back = 0;
228 											}
229 										}
230 									}
231 								}
232 								else {
233 									back = 0;
234 								}
235 #else
236 								back = 1;
237 								for (j = 0; ((j < szd) && (1 == back)); j++) {
238 									res = dk4stream_write_byte(
239 										co->dststrm, dptr[j], NULL
240 									);
241 									if (0 < res) {
242 										osz++;
243 										co->ll += 1;
244 										if (75 <= co->ll) {
245 											res = dk4strmco_nl(co);
246 											if (0 < res) {
247 												co->ll = 0;
248 											}
249 											else {
250 												back = 0;
251 											}
252 										}
253 									}
254 									else {
255 										back = 0;
256 									}
257 								}
258 #endif
259 							}
260 							else {
261 								osz++;
262 							}
263 						}
264 						else {
265 							back = 0;
266 						}
267 					} break;
268 					default : {
269 						back = 0;
270 					} break;
271 				}
272 			}
273 		} break;
274 		case DK4_STRMCO_OE_HEX : {
275 
276 			back = 1;
277 			buf[2] = '\0';
278 			for (i = 0; ((i < sz) && (1 == back)); i++) {
279 				uc = (unsigned char)(b[i]);
280 				us = 0x000FU & ((unsigned char)uc);
281 				if (0 != (DK4_STRMCO_FL_UPPER_OE & (co->fl))) {
282 					buf[1] = upper[us];
283 				}
284 				else {
285 					buf[1] = lower[us];
286 				}
287 				us = 0x000FU & (((unsigned char)uc) >> 4);
288 				if (0 != (DK4_STRMCO_FL_UPPER_OE & (co->fl))) {
289 					buf[0] = upper[us];
290 				}
291 				else {
292 					buf[0] = lower[us];
293 				}
294 				res = dk4stream_write(co->dststrm, buf, 2, NULL);
295 				co->ll += 2;
296 				if (0 < res) {
297 					osz++;
298 					if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) {
299 						if (78 <= co->ll) {
300 							res = dk4strmco_nl(co);
301 							if (0 < res) {
302 								co->ll = 0;
303 							}
304 							else {
305 								back = 0;
306 							}
307 						}
308 					}
309 				}
310 				else {
311 					back = 0;
312 				}
313 			}
314 		} break;
315 		default : {
316 
317 			back = dk4stream_write(co->dststrm, b, sz, NULL);
318 			if (0 != back) {
319 				osz = sz;
320 			}
321 		} break;
322 	}
323 	if (NULL != szo) { *szo = osz; }
324 
325 	return back;
326 }
327 
328 
329 
330 /**	Write bytes to compressor at compression level.
331 	@param	co	Compressor to write to.
332 	@param	b	Buffer start address.
333 	@param	sz	Number of bytes to write.
334 	@param	szo	Address of variable for number of bytes written, may be NULL.
335 	@return	1 on success, 0 on error.
336 */
337 static
338 int
dk4strmco_co_co(compressor_t * co,const char * b,size_t sz,size_t * szo)339 dk4strmco_co_co(
340 	compressor_t	*co,
341 	const char		*b,
342 	size_t			 sz,
343 	size_t			*szo
344 )
345 {
346 	const unsigned char	*cptr;
347 	size_t	osz		= 0;	/* Number of bytes processed successfully. */
348 	size_t	used	= 0;	/* Used bytes in output buffer. */
349 	size_t	i		= 0;	/* Index of current LZW byte to process. */
350 	size_t	lzwsz	= 0;	/* Bytes from LZW compression. */
351 	int		back	= 0;	/* Function result. */
352 	int		res		= 0;	/* Result from various operations. */
353 
354 #if	DK4_USE_ASSERT
355 	assert(NULL != co);
356 	assert(NULL != b);
357 	assert(0 < sz);
358 #endif
359 	switch (co->co) {
360 		case DK4_STRMCO_CO_FLATE : {
361 
362 			if (((dk4_um_t)(UINT_MAX)) >= ((dk4_um_t)sz)) {
363 				back = 1;
364 				co->u_co.zs.next_in		= (unsigned char *)b;
365 				co->u_co.zs.avail_in	= (unsigned int)sz;
366 				do {
367 					co->u_co.zs.next_out =	(unsigned char *)(&(co->zbuf[0]));
368 					co->u_co.zs.avail_out =	DK4_STRMCO_ZBUF_SIZE;
369 					res = deflate(&(co->u_co.zs), Z_NO_FLUSH);
370 					switch (res) {
371 						case Z_OK : {
372 							used = DK4_STRMCO_ZBUF_SIZE - co->u_co.zs.avail_out;
373 							if (0 < used) {
374 								res = dk4strmco_co_oe(
375 									co, &(co->zbuf[0]), used, NULL
376 								);
377 								if (0 < res) {
378 									osz = sz - co->u_co.zs.avail_in;
379 								}
380 								else {
381 									back = 0;
382 								}
383 							}
384 							else {
385 								osz = sz - co->u_co.zs.avail_in;
386 							}
387 						} break;
388 						default : {
389 							back = 0;
390 						} break;
391 					}
392 				} while ((0 < co->u_co.zs.avail_in) && (1 == back));
393 				if (NULL != szo) { *szo = osz; }
394 			} else {
395 			}
396 		} break;
397 		case DK4_STRMCO_CO_LZW : {
398 			back = 1;
399 			for (i = 0; ((1 == back) && (i < sz)); i++) {
400 				res = dk4lzwe_add(&(co->u_co.lzw), (unsigned char)(b[i]), NULL);
401 				switch (res) {
402 					case DK4_EDSTM_ACCEPT : {
403 						osz++;
404 					} break;
405 					case DK4_EDSTM_FINISHED : {
406 						cptr	= NULL;
407 						lzwsz	= 0;
408 						res		= dk4lzwe_output(
409 							&cptr, &lzwsz, &(co->u_co.lzw), NULL
410 						);
411 						if ((0 != res) && (NULL != cptr) && (0 < lzwsz)) {
412 							back = dk4strmco_co_oe(
413 								co, (const char *)cptr, lzwsz, NULL
414 							);
415 							if (0 != back) {
416 								osz++;
417 							}
418 						}
419 						else {
420 							back = 0;
421 						}
422 					} break;
423 					case DK4_EDSTM_ERROR : {
424 						back = 0;
425 					} break;
426 				}
427 			}
428 			if (NULL != szo) { *szo = osz; }
429 		} break;
430 		default : {
431 
432 			back = dk4strmco_co_oe(co, b, sz, szo);
433 		} break;
434 	}
435 
436 	return back;
437 }
438 
439 
440 
441 /**	Write bytes to compressor at preprocessor level.
442 	@param	co	Compressor to write to.
443 	@param	b	Buffer start address.
444 	@param	sz	Number of bytes to write.
445 	@param	szo	Address of variable for number of bytes written, may be NULL.
446 	@return	1 on success, 0 on error.
447 */
448 static
449 int
dk4strmco_co_write(compressor_t * co,const char * b,size_t sz,size_t * szo)450 dk4strmco_co_write(
451 	compressor_t	*co,
452 	const char		*b,
453 	size_t			 sz,
454 	size_t			*szo
455 )
456 {
457 	const unsigned char		*rleptr;		/* RL encoding result */
458 	size_t					 osz	= 0;	/* Bytes processed successfully */
459 	size_t					 i;				/* Running index of current byte */
460 	size_t					 rlesz;			/* Size of RL encoding result */
461 	int						 back	= 0;	/* Function result */
462 	int						 res;			/* Result from various operations */
463 
464 #if	DK4_USE_ASSERT
465 	assert(NULL != co);
466 #endif
467 	switch (co->pp) {
468 		case DK4_STRMCO_PP_RUNLENGTH : {
469 
470 			back = 1;
471 			for (i = 0; ((i < sz) && (0 != back)); i++) {
472 				switch (dk4rle_add(&(co->u_pp.rle),(unsigned char)(b[i]),NULL))
473 				{
474 					case DK4_EDSTM_FINISHED : {
475 						rleptr = NULL;
476 						rlesz  = 0;
477 						res = dk4rle_output(
478 							&rleptr, &rlesz, &(co->u_pp.rle), NULL
479 						);
480 						if (0 != res) {
481 							res = dk4strmco_co_co(
482 								co, (const char *)rleptr, rlesz, NULL
483 							);
484 							if (0 != res) {
485 								osz++;
486 							}
487 							else {
488 								back = 0;
489 							}
490 						}
491 						else {
492 							back = 0;
493 						}
494 					} break;
495 					case DK4_EDSTM_ERROR : {
496 						back = 0;
497 					} break;
498 					default : {
499 						osz++;
500 					} break;
501 				}
502 			}
503 			if (NULL != szo) { *szo = osz; }
504 		} break;
505 		default : {
506 
507 			back = dk4strmco_co_co(co, b, sz, szo);
508 		} break;
509 	}
510 
511 	return back;
512 }
513 
514 
515 
516 /**	Flush data in output encoders if used.
517 	@param	co	Compressor structure.
518 	@return	1 on success, 0 on error.
519 */
520 static
521 int
dk4strmco_co_oe_close(compressor_t * co)522 dk4strmco_co_oe_close(compressor_t *co)
523 {
524 	const char	*dptr	= NULL;
525 	size_t		 sz		= 0;
526 	size_t		 j		= 0;
527 	int			 back	= 1;
528 	int			 res	= 0;
529 
530 #if	DK4_USE_ASSERT
531 	assert(NULL != co);
532 #endif
533 	switch (co->oe) {
534 		case DK4_STRMCO_OE_ASCII85 : {
535 
536 			switch (dk4a85_enc_finish(&(co->u_oe.a85), NULL)) {
537 				case DK4_EDSTM_FINISHED : {
538 					if (0 < dk4a85_enc_output(&dptr,&sz,&(co->u_oe.a85),NULL)) {
539 						if (0 < sz) {
540 #if	VERSION_BEFORE_20161019
541 							back = dk4stream_write(co->dststrm, dptr, sz, NULL);
542 #else
543 							back = 1;
544 							for (j = 0; ((j < sz) && (1 == back)); j++) {
545 								res = dk4stream_write_byte(
546 									co->dststrm, dptr[j], NULL
547 								);
548 								if (0 < res) {
549 									co->ll += 1;
550 									if (75 <= co->ll) {
551 										res = dk4strmco_nl(co);
552 										if (0 < res) {
553 											co->ll = 0;
554 										}
555 										else {
556 											back = 0;
557 										}
558 									}
559 								}
560 								else {
561 									back = 0;
562 								}
563 							}
564 #endif
565 						}
566 					}
567 					else {
568 						back = 0;
569 					}
570 				} break;
571 			}
572 			if (0 != (DK4_STRMCO_FL_EOD_OE & (co->fl))) {
573 
574 				res = dk4stream_write(co->dststrm, a85fin, 2, NULL);
575 				if (0 == res) {
576 					back = 0;
577 				}
578 			}
579 			if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) {
580 
581 				if (0 == dk4strmco_nl(co)) {
582 					back = 0;
583 				}
584 			}
585 		} break;
586 		case DK4_STRMCO_OE_HEX : {
587 			if (0 != (DK4_STRMCO_FL_EOD_OE & (co->fl))) {
588 
589 				back = dk4stream_write(co->dststrm, ahfin, 1, NULL);
590 			}
591 			if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) {
592 
593 				if (0 == dk4strmco_nl(co)) {
594 					back = 0;
595 				}
596 			}
597 		} break;
598 	}
599 
600 	return back;
601 }
602 
603 
604 
605 /**	Flush data from flate compressor if used.
606 	@param	co	Compressor structure.
607 	@return	1 on success, 0 on error.
608 */
609 static
610 int
dk4strmco_co_co_close(compressor_t * co)611 dk4strmco_co_co_close(compressor_t *co)
612 {
613 	const unsigned char	*cptr;
614 	size_t	 used	= 0;
615 	int		 back	= 1;
616 	int		 zres	= Z_OK;
617 	int		 res	= 0;
618 
619 #if	DK4_USE_ASSERT
620 	assert(NULL != co);
621 #endif
622 	switch (co->co) {
623 		case DK4_STRMCO_CO_FLATE : {
624 
625 			co->u_co.zs.next_in		= (unsigned char *)nl;
626 			co->u_co.zs.avail_in	= 0;
627 			do {
628 				co->u_co.zs.next_out	=	(unsigned char *)(&(co->zbuf[0]));
629 				co->u_co.zs.avail_out	=	DK4_STRMCO_ZBUF_SIZE;
630 				zres = deflate(&(co->u_co.zs), Z_FINISH);
631 
632 				switch (zres) {
633 					case Z_OK : case Z_STREAM_END : {
634 						used = DK4_STRMCO_ZBUF_SIZE - co->u_co.zs.avail_out;
635 
636 						if (0 < used) {
637 							res = dk4strmco_co_oe(co,&(co->zbuf[0]),used,NULL);
638 							if (0 == res) {
639 								back = 0;
640 							}
641 						}
642 					} break;
643 					default : {
644 						back = 0;
645 					} break;
646 				}
647 			} while ((Z_OK == zres) && (1 == back));
648 
649 			if (Z_OK != deflateEnd(&(co->u_co.zs))) {
650 				back = 0;
651 			}
652 		} break;
653 		case DK4_STRMCO_CO_LZW : {
654 			res = dk4lzwe_finish(&(co->u_co.lzw), NULL);
655 			switch (res) {
656 				case DK4_EDSTM_FINISHED : {
657 					cptr = NULL;
658 					used = 0;
659 					res = dk4lzwe_output(
660 						&cptr, &used, &(co->u_co.lzw), NULL
661 					);
662 					if ((0 != res) && (NULL != cptr) && (0 < used)) {
663 						back = dk4strmco_co_oe(
664 							co, (const char *)cptr, used, NULL
665 						);
666 					}
667 					else {
668 						back = 0;
669 					}
670 				} break;
671 				case DK4_EDSTM_ERROR : {
672 					back = 0;
673 				} break;
674 			}
675 		} break;
676 	}
677 
678 	return back;
679 }
680 
681 
682 
683 /**	Flush data from run-length encoder if used.
684 	@param	co	Compressor structure.
685 	@return	1 on success, 0 on error.
686 */
687 static
688 int
dk4strmco_co_pp_close(compressor_t * co)689 dk4strmco_co_pp_close(compressor_t *co)
690 {
691 	const unsigned char	*dptr	= NULL;
692 	size_t				 szd	= 0;
693 	int					 back	= 1;
694 	int					 res;
695 
696 #if	DK4_USE_ASSERT
697 	assert(NULL != co);
698 #endif
699 	switch (co->pp) {
700 		case DK4_STRMCO_PP_RUNLENGTH : {
701 
702 			switch (dk4rle_finish(&(co->u_pp.rle), NULL)) {
703 				case DK4_EDSTM_ACCEPT : {
704 				} break;
705 				case DK4_EDSTM_FINISHED : {
706 
707 					if (0 < dk4rle_output(&dptr, &szd, &(co->u_pp.rle), NULL)) {
708 						res = dk4strmco_co_write(
709 							co, (const char *)dptr, szd, NULL
710 						);
711 						if (0 == res) {
712 							back = 0;
713 						}
714 					}
715 					else {
716 						back = 0;
717 					}
718 				} break;
719 				default : {
720 				} break;
721 			}
722 		} break;
723 	}
724 
725 	return back;
726 }
727 
728 
729 
730 /**	Finish output (flush data stored in the encoders).
731 	@param	co	Compressor structure.
732 	@return	1 on success, 0 on error.
733 */
734 static
735 int
dk4strmco_co_close(compressor_t * co)736 dk4strmco_co_close(compressor_t *co)
737 {
738 	int					 back	= 1;
739 
740 #if	DK4_USE_ASSERT
741 	assert(NULL != co);
742 #endif
743 	/*	Flush preprocessor (run-length encoder).
744 	*/
745 	if (0 == dk4strmco_co_pp_close(co)) {
746 		back = 0;
747 	}
748 	/*	Flush compressor (flate stream).
749 	*/
750 	if (0 == dk4strmco_co_co_close(co)) {
751 		back = 0;
752 	}
753 	/*	Flush output encoder (ASCII-Hex or ASCII-85 encoder).
754 	*/
755 	if (0 == dk4strmco_co_oe_close(co)) {
756 		back = 0;
757 	}
758 	/*	Release memory.
759 	*/
760 
761 	if (0 == dk4mem_reset_secure(co, sizeof(compressor_t), NULL)) {
762 		back = 0;
763 	}
764 
765 	dk4mem_free(co);
766 
767 	return back;
768 }
769 
770 
771 
772 static
773 void
dk4strmco_handler(dk4_stream_api_t * api)774 dk4strmco_handler(dk4_stream_api_t *api)
775 {
776 	compressor_t	*co	= NULL;
777 
778 #if	DK4_USE_ASSERT
779 	assert(NULL != api);
780 #endif
781 	if (NULL != api) {
782 		api->res = 0;
783 		api->sz_out = 0;
784 		co = (compressor_t *)(api->d);
785 		switch (api->cmd) {
786 			case DK4_STREAM_API_WRITE : {
787 				if (0 < api->sz_in) {
788 					api->res = dk4strmco_co_write(
789 						co, api->b, api->sz_in, &(api->sz_out)
790 					);
791 				}
792 				else {
793 					api->res = 1;
794 				}
795 			} break;
796 			case DK4_STREAM_API_FLUSH : {
797 				/*
798 					Do nothing but indicate success.
799 					Otherwise closing a stream will return an error.
800 				*/
801 				api->res = 1;
802 			} break;
803 			case DK4_STREAM_API_CLOSE : {
804 				api->res = dk4strmco_co_close(co);
805 			} break;
806 			case DK4_STREAM_API_ZERO_READ_IS_EOF : {
807 				api->res = 0;
808 			} break;
809 			default : {
810 				/* Error: Functions not available */
811 			} break;
812 		}
813 	}
814 
815 }
816 
817 
818 
819 dk4_stream_t *
dk4strmco_open(dk4_stream_t * strm,enum dk4_strmco_pp pp,enum dk4_strmco_co co,enum dk4_strmco_oe oe,int fl,dk4_er_t * erp)820 dk4strmco_open(
821 	dk4_stream_t		*strm,
822 	enum dk4_strmco_pp	 pp,
823 	enum dk4_strmco_co	 co,
824 	enum dk4_strmco_oe	 oe,
825 	int					 fl,
826 	dk4_er_t			*erp
827 )
828 {
829 	dk4_stream_t	*back	= NULL;
830 	compressor_t	*cc		= NULL;
831 
832 #if	DK4_USE_ASSERT
833 	assert(NULL != strm);
834 #endif
835 	if (NULL != strm) {
836 		/*	Allocate compressor and set up.
837 		*/
838 
839 		cc = dk4mem_new(compressor_t,1,erp);
840 		if (NULL != cc) {
841 			cc->dststrm = strm;
842 			cc->pp = pp;
843 			cc->co = co;
844 			cc->oe = oe;
845 			cc->fl = fl;
846 			cc->ll = 0;
847 			switch (pp) {
848 				case DK4_STRMCO_PP_RUNLENGTH : {
849 
850 					dk4rle_init(
851 						&(cc->u_pp.rle),
852 						((0 != (DK4_STRMCO_FL_EOD_PP & fl)) ? 1 : 0),
853 						NULL
854 					);
855 				} break;
856 				default : {
857 				} break;
858 			}
859 			switch (co) {
860 				case DK4_STRMCO_CO_FLATE : {
861 
862 					cc->u_co.zs.zalloc = Z_NULL;
863 					cc->u_co.zs.zfree  = Z_NULL;
864 					cc->u_co.zs.opaque = Z_NULL;
865 
866 					if (Z_OK != deflateInit(&(cc->u_co.zs), 9)) {
867 
868 						dk4mem_free(cc);
869 						cc = NULL;
870 
871 					}
872 				} break;
873 				case DK4_STRMCO_CO_LZW : {
874 
875 					if (0 == dk4lzwe_init(&(cc->u_co.lzw), NULL)) {
876 
877 						dk4mem_free(cc);
878 						cc = NULL;
879 
880 					}
881 				} break;
882 				default : {
883 				} break;
884 			}
885 			switch (oe) {
886 				case DK4_STRMCO_OE_ASCII85 : {
887 
888 					dk4a85_enc_init(&(cc->u_oe.a85), 1, NULL);
889 				} break;
890 				default : {
891 				} break;
892 			}
893 		}
894 #if TRACE_DEBUG
895 		else {
896 		}
897 #endif
898 		/*	If the compressor was set up successfully, create stream.
899 		*/
900 		if (NULL != cc) {
901 
902 			back = dk4stream_open(
903 				cc, dk4strmco_handler, DK4_STREAM_WRITE, 0, 4096, erp
904 			);
905 			/*
906 				When failed to create stream, we must release the compressor.
907 			*/
908 			if (NULL == back) {
909 				/*
910 					Release dynamic resources assigned to components.
911 				*/
912 
913 				switch (co) {
914 					case DK4_STRMCO_CO_FLATE : {
915 
916 						(void)deflateEnd(&(cc->u_co.zs));
917 					} break;
918 					case DK4_STRMCO_CO_LZW : {
919 
920 						(void)dk4lzwe_finish(&(cc->u_co.lzw), NULL);
921 					} break;
922 					default : {
923 					} break;
924 				}
925 
926 				dk4mem_free(cc);
927 			}
928 #if TRACE_DEBUG
929 			else {
930 			}
931 #endif
932 		}
933 	}
934 	else {
935 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
936 	}
937 
938 	return back;
939 }
940 
941 
942 
943 /* vim: set ai sw=4 ts=4 : */
944 
945