1 /*
2 Copyright (C) 2017-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: dk4bifn.ctr
12 */
13 
14 /**	@file dk4bifn.c The dk4bifn module.
15 */
16 
17 #include "dk4conf.h"
18 
19 #if	DK4_HAVE_SYS_TYPES_H
20 #ifndef	SYS_TYPES_H_INCLUDED
21 #include <sys/types.h>
22 #define	SYS_TYPES_H_INCLUDED1
23 #endif
24 #endif
25 #if	DK4_HAVE_STDINT_H
26 #ifndef	STDINT_H_INCLUDED
27 #include <stdint.h>
28 #define	STDINT_H_INCLUDED 1
29 #endif
30 #endif
31 #if	DK4_HAVE_LIMITS_H
32 #ifndef	LIMITS_H_INCLUDED
33 #include <limits.h>
34 #define	LIMITS_H_INCLUDED 1
35 #endif
36 #endif
37 
38 #ifndef	DK4TYPES_H_INCLUDED
39 #include <libdk4base/dk4types.h>
40 #endif
41 
42 #ifndef	DK4MEM_H_INCLUDED
43 #include <libdk4base/dk4mem.h>
44 #endif
45 
46 #ifndef	DK4MAASZ_H_INCLUDED
47 #include <libdk4ma/dk4maasz.h>
48 #endif
49 
50 #ifndef	DK4STR8_H_INCLUDED
51 #include <libdk4base/dk4str8.h>
52 #endif
53 
54 #ifndef	DK4BIFTY_H_INCLUDED
55 #include <libdk4bif/dk4bifty.h>
56 #endif
57 
58 #ifndef	DK4BIF_H_INCLUDED
59 #include <libdk4bif/dk4bif.h>
60 #endif
61 
62 #ifndef	BIF_H_INCLUDED
63 #include <libdk4bif/bif.h>
64 #endif
65 
66 #ifndef	DK4MAI8DSZ_H_INCLUDED
67 #include <libdk4maio8d/dk4mai8dsz.h>
68 #endif
69 
70 #if DK4_HAVE_ASSERT_H
71 #ifndef	ASSERT_H_INCLUDED
72 #include <assert.h>
73 #define	ASSERT_H_INCLUDED 1
74 #endif
75 #endif
76 
77 
78 
79 
80 
81 
82 /**	Data to save between applying bytes.
83 */
84 typedef struct {
85 	dk4_bif_t		*bif;		/**< The result. */
86 	size_t			 nums[4];	/**< Width, height, maxval. */
87 	int				 magnum;	/**< Magic number. */
88 	int				 tupt;		/**< Tuple type for DK4_NETPBM_P7. */
89 } dk4_bif_netpbm_builder_t;
90 
91 
92 
93 /**	Pointer to unsigned character.
94 */
95 typedef unsigned char	*dk4_puchar_t;
96 
97 
98 
99 static const char * const	dk4netpbm_p7_kw[] = {
100 /* 0 */
101 "WIDTH",
102 
103 /* 1 */
104 "HEIGHT",
105 
106 /* 2 */
107 "DEPTH",
108 
109 /* 3 */
110 "MAXVAL",
111 
112 /* 4 */
113 "TUPLTYPE",
114 
115 /* 5 */
116 "ENDHDR",
117 
118 NULL
119 
120 };
121 
122 
123 
124 /**	Tuple types.
125 */
126 static const char * const	dk4netpbm_p7_tut[] = {
127 /* 0 */
128 "BLACKANDWHITE",
129 
130 /* 1 */
131 "GRAYSCALE",
132 
133 /* 2 */
134 "RGB",
135 
136 /* 3 */
137 "BLACKANDWHITE_ALPHA",
138 
139 /* 4 */
140 "GRAYSCALE_ALPHA",
141 
142 /* 5 */
143 "RGB_ALPHA",
144 
145 NULL
146 
147 };
148 
149 
150 
151 void
dk4bifnetpbm_nc_release_per_frame_data(void * tsdata)152 dk4bifnetpbm_nc_release_per_frame_data(
153 	void			*tsdata
154 )
155 {
156 	dk4_bif_netpbm_per_frame_t	*pfd;	/* Per-frame data */
157 	size_t						 i;		/* Traverse all rows */
158 
159 #if	DK4_USE_ASSERT
160 	assert(NULL != tsdata);
161 #endif
162 	if (NULL != tsdata) {
163 		pfd = (dk4_bif_netpbm_per_frame_t *)tsdata;
164 		if (NULL != pfd->rows) {
165 			for (i = 0; i < (size_t)(pfd->h); i++) {
166 
167 				dk4mem_release((pfd->rows)[i]);
168 			}
169 			dk4mem_free(pfd->rows);
170 		}
171 		pfd->rows = NULL;
172 		pfd->w = 0;
173 		pfd->h = 0;
174 		pfd->ch = 0;
175 		pfd->bpr = 0;
176 		pfd->tupt = 0;
177 		pfd->maxval = 0;
178 		pfd->bpc = 0;
179 		pfd->magnum = 0;
180 		dk4mem_free(tsdata);
181 	}
182 
183 }
184 
185 
186 
187 static
188 int
dk4_bif_netpbm_check_input(size_t w,size_t h,size_t maxval,dk4_er_t * erp)189 dk4_bif_netpbm_check_input(
190 	size_t				 w,
191 	size_t				 h,
192 	size_t				 maxval,
193 	dk4_er_t			*erp
194 )
195 {
196 	int			 back	= 0;
197 
198 
199 
200 
201 	if ((0 < w) && (0 < h) && (0 < maxval)) {
202 		if ((dk4_um_t)(LONG_MAX) >= (dk4_um_t)w) {
203 			if ((dk4_um_t)(LONG_MAX) >= (dk4_um_t)h) {
204 				if ((dk4_um_t)(DK4_U16_MAX) >= (dk4_um_t)maxval) {
205 					back = 1;
206 				}
207 			}
208 		}
209 	}
210 	if (0 == back) {
211 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
212 	}
213 
214 	return back;
215 }
216 
217 
218 
219 static
220 dk4_bif_netpbm_per_frame_t *
dk4bifnetpbm_tsdata_new(int magnum,int tupt,size_t ch,size_t w,size_t h,size_t maxval,dk4_er_t * erp)221 dk4bifnetpbm_tsdata_new(
222 	int					 magnum,
223 	int					 tupt,
224 	size_t				 ch,
225 	size_t				 w,
226 	size_t				 h,
227 	size_t				 maxval,
228 	dk4_er_t			*erp
229 )
230 {
231 	dk4_er_t					 er;			/* Error report for math op */
232 	dk4_bif_netpbm_per_frame_t	*back	= NULL;
233 	size_t						 i		= 0;	/* Traverse all rows */
234 	int							 ok		= 0;	/* Flag: Success, no errors */
235 
236 	if (0 != dk4_bif_netpbm_check_input(w, h, maxval, erp)) {
237 		back = dk4mem_new(dk4_bif_netpbm_per_frame_t,1,erp);
238 		if (NULL != back) {
239 			dk4error_init(&er);
240 			back->rows = NULL;
241 			back->w = (dk4_bif_dim_t)w;
242 			back->h = (dk4_bif_dim_t)h;
243 			back->ch = 0;						/* Number of channels */
244 			back->vpr = 0;						/* Values per row */
245 			back->bpr = 0;						/* Bytes per row */
246 			back->magnum = magnum;
247 			back->tupt = tupt;
248 			back->maxval = (dk4_px_t)maxval;
249 			back->bpc = (dk4_px_bit_depth_t)dk4pxbit_get_bitno((dk4_px_t)maxval);
250 
251 			switch (magnum) {
252 				case DK4_NETPBM_P1 : case DK4_NETPBM_P4 : {
253 					back->ch = 1;
254 					back->vpr = w;
255 					back->bpr = w / 8;
256 					if (0 != (w % 8)) { back->bpr += 1; }
257 				} break;
258 				case DK4_NETPBM_P2 : case DK4_NETPBM_P5 : {
259 					back->ch = 1;
260 					back->vpr = w;
261 					back->bpr = back->vpr;
262 					if (255 < maxval) {
263 						back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
264 					}
265 				} break;
266 				case DK4_NETPBM_P3 : case DK4_NETPBM_P6 : {
267 					back->ch = 3;
268 					back->vpr = dk4ma_size_t_mul(3, w, &er);
269 					back->bpr = back->vpr;
270 					if (255 < maxval) {
271 						back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
272 					}
273 				} break;
274 				case DK4_NETPBM_P7 : {
275 					switch (tupt) {
276 						case DK4_NETPBM_TT_BLACKANDWHITE : {
277 							back->ch = 1;
278 							back->vpr = w;
279 							back->bpr = w;
280 						} break;
281 						case DK4_NETPBM_TT_GRAYSCALE : {
282 							back->ch = 1;
283 							back->vpr = w;
284 							back->bpr = back->vpr;
285 							if (255 < maxval) {
286 								back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
287 							}
288 						} break;
289 						case DK4_NETPBM_TT_RGB : {
290 							back->ch = 3;
291 							back->vpr = dk4ma_size_t_mul(3, w, &er);
292 							back->bpr = back->vpr;
293 							if (255 < maxval) {
294 								back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
295 							}
296 						} break;
297 						case DK4_NETPBM_TT_BLACKANDWHITE_ALPHA : {
298 							back->ch = 2;
299 							back->vpr = dk4ma_size_t_mul(2, w, &er);
300 							back->bpr = back->vpr;
301 						} break;
302 						case DK4_NETPBM_TT_GRAYSCALE_ALPHA : {
303 							back->ch = 2;
304 							back->vpr = dk4ma_size_t_mul(2, w, &er);
305 							back->bpr = back->vpr;
306 							if (255 < maxval) {
307 								back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
308 							}
309 						} break;
310 						case DK4_NETPBM_TT_RGB_ALPHA : {
311 							back->ch = 4;
312 							back->vpr = dk4ma_size_t_mul(4, w, &er);
313 							back->bpr = back->vpr;
314 							if (255 < maxval) {
315 								back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
316 							}
317 						} break;
318 						default : {
319 							back->ch = ch;
320 							back->vpr = dk4ma_size_t_mul(ch, w, &er);
321 							back->bpr = back->vpr;
322 							if (255 < maxval) {
323 								back->bpr = dk4ma_size_t_mul(2, back->vpr, &er);
324 							}
325 						} break;
326 					}
327 				} break;
328 			}
329 			(void)dk4ma_size_t_mul(h,sizeof(dk4_puchar_t),&er);
330 			if (DK4_E_NONE == er.ec) {
331 				if (0 < back->bpr) {
332 					back->rows = dk4mem_new(dk4_puchar_t,h,erp);
333 					if (NULL != back->rows) {
334 						for (i = 0; i < h; i++) { (back->rows)[i] = NULL; }
335 						ok = 1;
336 						for (i = 0; i < h; i++) {
337 							(back->rows)[i] =
338 							dk4mem_new(unsigned char,back->bpr,erp);
339 							if (NULL != (back->rows)[i]) {
340 								DK4_MEMRES((back->rows)[i],back->bpr);
341 
342 							}
343 							else {
344 								ok = 0;
345 							}
346 						}
347 					}
348 				}
349 			}
350 			else {
351 				dk4error_copy(erp, &er);
352 			}
353 			if (0 == ok) {
354 				dk4bifnetpbm_nc_release_per_frame_data(back);
355 				back = NULL;
356 			}
357 #if TRACE_DEBUG
358 			else {
359 
360 
361 
362 
363 
364 
365 
366 
367 
368 
369 			}
370 #endif
371 		}
372 #if TRACE_DEBUG
373 		else {
374 		}
375 #endif
376 	}
377 #if	TRACE_DEBUG
378 	else {
379 	}
380 #endif
381 
382 	return back;
383 }
384 
385 
386 
387 /**	Copy original data to frame information.
388 	@param	cf	Frame data to fill.
389 	@param	pfd	Original per frame data.
390 */
391 static
392 void
dk4bifnetpbm_fill_frame(dk4_bif_frame_t * cf,void const * voptr)393 dk4bifnetpbm_fill_frame(
394 	dk4_bif_frame_t			*cf,
395 	void			const	*voptr
396 )
397 {
398 	dk4_bif_netpbm_per_frame_t	const	*pfd;
399 
400 #if	DK4_USE_ASSERT
401 	assert(NULL != cf);
402 #endif
403 	pfd = (dk4_bif_netpbm_per_frame_t *)voptr;
404 	cf->n_comp = pfd->ch;	/* 2021-07-29: Bugfix, right side was missing. */
405 	cf->dim_x = pfd->w;
406 	cf->dim_y = pfd->h;
407 	switch (pfd->magnum) {
408 		case DK4_NETPBM_P1 : {
409 			cf->l_cs = cf->f_cs =			DK4_CS_GRAY;
410 			cf->l_bdepth = cf->r_bdepth =	1;
411 		} break;
412 		case DK4_NETPBM_P2 : {
413 			cf->l_cs = cf->f_cs =			DK4_CS_GRAY;
414 			cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
415 		} break;
416 		case DK4_NETPBM_P3 : {
417 			cf->l_cs = cf->f_cs =			DK4_CS_RGB;
418 			cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
419 		} break;
420 		case DK4_NETPBM_P4 : {
421 			cf->l_cs = cf->f_cs =			DK4_CS_GRAY;
422 			cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
423 		} break;
424 		case DK4_NETPBM_P5 : {
425 			cf->l_cs = cf->f_cs =			DK4_CS_GRAY;
426 			cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
427 		} break;
428 		case DK4_NETPBM_P6 : {
429 			cf->l_cs = cf->f_cs =			DK4_CS_RGB;
430 			cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
431 		} break;
432 		case DK4_NETPBM_P7 : {
433 			switch (pfd->tupt) {
434 				case DK4_NETPBM_TT_BLACKANDWHITE : {
435 					cf->l_cs = cf->f_cs =	  		DK4_CS_GRAY;
436 					cf->l_bdepth = cf->r_bdepth =	1;
437 				} break;
438 				case DK4_NETPBM_TT_GRAYSCALE : {
439 					cf->l_cs = cf->f_cs =			DK4_CS_GRAY;
440 					cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
441 				} break;
442 				case DK4_NETPBM_TT_RGB : {
443 					cf->l_cs = cf->f_cs =			DK4_CS_RGB;
444 					cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
445 				} break;
446 				case DK4_NETPBM_TT_BLACKANDWHITE_ALPHA : {
447 					cf->l_cs = cf->f_cs =			DK4_CS_GRAY_ALPHA;
448 					cf->l_bdepth = cf->r_bdepth =	1;
449 				} break;
450 				case DK4_NETPBM_TT_GRAYSCALE_ALPHA : {
451 					cf->l_cs = cf->f_cs =			DK4_CS_GRAY_ALPHA;
452 					cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
453 				} break;
454 				case DK4_NETPBM_TT_RGB_ALPHA : {
455 					cf->l_cs = cf->f_cs =			DK4_CS_RGB_ALPHA;
456 					cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
457 				} break;
458 				default : {
459 
460 					switch (pfd->ch) {
461 						case 1: {
462 							cf->l_cs = cf->f_cs =			DK4_CS_GRAY;
463 							cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
464 						} break;
465 						case 2: {
466 							cf->l_cs = cf->f_cs =			DK4_CS_GRAY_ALPHA;
467 							cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
468 						} break;
469 						case 3: {
470 							cf->l_cs = cf->f_cs =			DK4_CS_RGB;
471 							cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
472 						} break;
473 						case 4: {
474 							cf->l_cs = cf->f_cs =			DK4_CS_RGB_ALPHA;
475 							cf->l_bdepth = cf->r_bdepth =	pfd->bpc;
476 						} break;
477 					}
478 				} break;
479 			}
480 		} break;
481 	}
482 	cf->bglbd[0] = pfd->maxval;
483 	cf->bglbd[1] = pfd->maxval;
484 	cf->bglbd[2] = pfd->maxval;
485 	cf->bglbd[3] = pfd->maxval;
486 	if (pfd->maxval != dk4pxbit_get_max(pfd->bpc)) {
487 		cf->fmres = 1;
488 		cf->fmrmv = pfd->maxval;
489 		dk4pxres_setup_from_maxval(&(cf->resampler), pfd->maxval, pfd->bpc);
490 		cf->bg[0] = dk4pxbit_get_max(pfd->bpc);
491 		cf->bg[1] = cf->bg[2] =  cf->bg[3] = cf->bg[0];
492 	}
493 	else {
494 		dk4pxres_setup(&(cf->resampler), cf->l_bdepth, cf->l_bdepth);
495 		cf->bg[0] = pfd->maxval;
496 		cf->bg[1] = pfd->maxval;
497 		cf->bg[2] = pfd->maxval;
498 		cf->bg[3] = pfd->maxval;
499 	}
500 #if	TRACE_DEBUG
501 
502 
503 
504 
505 
506 
507 
508 
509 
510 
511 
512 
513 
514 
515 
516 
517 
518 
519 
520 
521 
522 
523 #endif
524 
525 }
526 
527 
528 
529 /**	Initialize builder before applying any data.
530 	@param	pbuilder	Builder to initialize.
531 	@return	1 on success, 0 on error (memory).
532 */
533 static
534 int
dk4_bif_netpbm_builder_initialize(dk4_bif_netpbm_builder_t * pbuilder,const dkChar * fn,int honly,dk4_cs_conv_ctx_t const * pcsctx,dk4_er_t * erp)535 dk4_bif_netpbm_builder_initialize(
536 	dk4_bif_netpbm_builder_t	*pbuilder,
537 	const dkChar				*fn,
538 	int							 honly,
539 	dk4_cs_conv_ctx_t	const	*pcsctx,
540 	dk4_er_t					*erp
541 )
542 {
543 	int		 back	= 0;
544 
545 #if	DK4_USE_ASSERT
546 	assert(NULL != pbuilder);
547 #endif
548 	pbuilder->bif = NULL;
549 	pbuilder->magnum = 0;
550 
551 	pbuilder->bif = dk4biftool_nc_new_for_one_frame(
552 		fn, DK4_BIF_TYPE_NETPBM, honly, pcsctx, erp
553 	);
554 	if (NULL != pbuilder->bif) {
555 		back = 1;
556 	}
557 
558 	return back;
559 }
560 
561 
562 
563 /**	Clean up builder.
564 	@param	pbuilder	Builder to clean up.
565 */
566 static
567 void
dk4_bif_netpbm_builder_cleanup(dk4_bif_netpbm_builder_t * pbuilder)568 dk4_bif_netpbm_builder_cleanup(dk4_bif_netpbm_builder_t *pbuilder)
569 {
570 
571 #if	DK4_USE_ASSERT
572 	assert(NULL != pbuilder);
573 #endif
574 	if (NULL != pbuilder->bif) {
575 		dk4bif_close(pbuilder->bif);
576 		pbuilder->bif = NULL;
577 	}
578 
579 }
580 
581 
582 
583 /**	Attempt to read magic number and one whitespace from file.
584 	For a sequence of frames (sequence of NetPBM images) we might
585 	have white spaces between frame data and the magic number of the
586 	following frame, so we ignore leading white spaces if the
587 	havefr flag is set.
588 	@param	pbuilder	Image builder structure.
589 	@param	fipo		Input file, opened for binary reading.
590 	@param	havefr		Flag: Already have previous frame.
591 	@param	erp			Error report, may be NULL.
592 	@return	1 on success, 0 on end of file, -1 on error.
593 */
594 static
595 int
dk4bifnetpbm_read_magic_number(dk4_bif_netpbm_builder_t * pbuilder,FILE * fipo,int havefr,dk4_er_t * erp)596 dk4bifnetpbm_read_magic_number(
597 	dk4_bif_netpbm_builder_t	*pbuilder,
598 	FILE						*fipo,
599 	int							 havefr,
600 	dk4_er_t					*erp
601 )
602 {
603 	int			 cc		=	 1;		/* Flag: Can continue */
604 	int			 c		=	 0;		/* Input character */
605 	int			 inco	=	 0;		/* Flag: In comment */
606 	int			 back	=	-1;
607 
608 
609 #if	DK4_USE_ASSERT
610 	assert(NULL != pbuilder);
611 	assert(NULL != fipo);
612 #endif
613 	do {
614 		c = fgetc(fipo);
615 		switch (c) {
616 			case EOF : {
617 				cc = -1;
618 				back = 0;
619 			} break;
620 			case 'P' : {
621 				cc = 0;
622 			} break;
623 			case '#' : {
624 				inco = 1;
625 				do {
626 					c = fgetc(fipo);
627 					switch (c) {
628 						case EOF : {
629 							inco = 0;
630 							cc = -1;
631 							back = 0;
632 						} break;
633 						case '\n' : {
634 							inco = 0;
635 						} break;
636 					}
637 				} while (1 == inco);
638 			} break;
639 			case ' '  :
640 			case '\t' :
641 			case '\r' :
642 			case '\n' :
643 			case '\v' :
644 			case '\f' : {
645 				if (0 == havefr) {
646 					cc = -1;
647 					dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
648 				}
649 			} break;
650 			default : {
651 				cc = -1;
652 				dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
653 			} break;
654 		}
655 	} while (1 == cc);
656 	switch (cc) {
657 		case 0 : {		/* P was read */
658 			back = 1;
659 			c = fgetc(fipo);
660 			switch (c) {
661 				case '1' : {
662 					pbuilder->magnum = DK4_NETPBM_P1;
663 				} break;
664 				case '2' : {
665 					pbuilder->magnum = DK4_NETPBM_P2;
666 				} break;
667 				case '3' : {
668 					pbuilder->magnum = DK4_NETPBM_P3;
669 				} break;
670 				case '4' : {
671 					pbuilder->magnum = DK4_NETPBM_P4;
672 				} break;
673 				case '5' : {
674 					pbuilder->magnum = DK4_NETPBM_P5;
675 				} break;
676 				case '6' : {
677 					pbuilder->magnum = DK4_NETPBM_P6;
678 				} break;
679 				case '7' : {
680 					pbuilder->magnum = DK4_NETPBM_P7;
681 				} break;
682 				default : {
683 					back = -1;
684 					dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
685 				} break;
686 			}
687 			if (1 == back) {
688 				c = fgetc(fipo);
689 				back = -1;
690 				switch (c) {
691 					case ' '  :
692 					case '\t' :
693 					case '\r' :
694 					case '\n' :
695 					case '\v' :
696 					case '\f' : {
697 						back = 1;
698 					} break;
699 				}
700 			}
701 		} break;
702 		default : {		/* Failed */
703 			/* Empty by intent. */
704 		} break;
705 	}
706 
707 	return back;
708 }
709 
710 
711 
712 static
713 size_t
dk4bifnetpbm_digit(char c)714 dk4bifnetpbm_digit(char c)
715 {
716 	size_t	back = 0;
717 
718 	switch (c) {
719 		case '1' : { back = 1; } break;
720 		case '2' : { back = 2; } break;
721 		case '3' : { back = 3; } break;
722 		case '4' : { back = 4; } break;
723 		case '5' : { back = 5; } break;
724 		case '6' : { back = 6; } break;
725 		case '7' : { back = 7; } break;
726 		case '8' : { back = 8; } break;
727 		case '9' : { back = 9; } break;
728 	}
729 
730 	return back;
731 }
732 
733 
734 
735 /**	Read NetPBM header (2 or 3 decimal numbers), optionally containing
736 	a comment.
737 	We must have
738 	- white space(s),
739 	- 2 or 3 decimal numbers separated by white space(s),
740 	- one white space at end as separator between header and data.
741 	@param	fipo		Input file, opened for binary reading.
742 	@param	numbuf		Destination buffer for decimal numbers.
743 	@param	sznb		Buffer size (number of numbers).
744 	@param	erp			Error report, may be NULL.
745 	@return	1 on success, 0 on error.
746 */
747 static
748 int
dk4bifnetpbm_read_header_16(FILE * fipo,size_t * numbuf,size_t sznb,dk4_er_t * erp)749 dk4bifnetpbm_read_header_16(
750 	FILE						*fipo,
751 	size_t						*numbuf,
752 	size_t						 sznb,
753 	dk4_er_t					*erp
754 )
755 {
756 	dk4_er_t	 er;			/* Error report */
757 	size_t		 i;				/* Traverse all numbers */
758 	size_t		 val	= 0;	/* Value to store in current number */
759 	size_t		 found	= 0;	/* Number of completed numbers */
760 	int			 back	= 0;
761 	int			 inco	= 0;	/* Flag: In comment */
762 	int			 st		= 0;	/* State: 0=in space, 1=in number */
763 	int			 c		= 0;	/* Current character to process */
764 	int			 cc		= 1;	/* Flag: 1=can continue, 0=finished, -1=error */
765 
766 #if	DK4_USE_ASSERT
767 	assert(NULL != fipo);
768 	assert(NULL != numbuf);
769 	assert(0 < sznb);
770 #endif
771 	for (i = 0; i < sznb; i++) { numbuf[i] = 0; }
772 	dk4error_init(&er);
773 	do {
774 		c = fgetc(fipo);
775 		switch (c) {
776 			case EOF : {
777 				cc = -1;
778 				if (0 != st) {
779 					numbuf[found++] = val;
780 					val = 0;
781 				}
782 			} break;
783 			case '#' : {
784 				if (0 != st) {
785 					numbuf[found++] = val;
786 					val = 0;
787 					st = 0;
788 				}
789 				inco = 1;
790 				do {
791 					c = fgetc(fipo);
792 					switch (c) {
793 						case EOF : {
794 							inco = 0; cc = -1;
795 						} break;
796 						case '\n' : {
797 							inco = 0;
798 						} break;
799 					}
800 				} while (1 == inco);
801 			} break;
802 			case '0' : case '1' : case '2' : case '3' : case '4' :
803 			case '5' : case '6' : case '7' : case '8' : case '9' : {
804 				if (0 != st) {
805 					val = dk4ma_size_t_add(
806 						dk4ma_size_t_mul(val, 10, &er),
807 						dk4bifnetpbm_digit((char)c), &er
808 					);
809 				}
810 				else {
811 					val = dk4bifnetpbm_digit((char)c);
812 					st = 1;
813 				}
814 			} break;
815 			case ' ': case '\t': case '\r': case '\n': case '\v': case '\f': {
816 				if (0 != st) {
817 					numbuf[found++] = val;
818 					val = 0;
819 					if (found == sznb) {
820 						cc = 0;
821 						back = 1;
822 					}
823 				}
824 				else {
825 					if (found == sznb) {
826 						cc = 0;
827 						back = 1;
828 					}
829 				}
830 				st = 0;
831 			} break;
832 			default : {
833 				cc = -1;
834 			} break;
835 		}
836 	} while (1 == cc);
837 	if (DK4_E_NONE != er.ec) {
838 		back = 0;
839 	}
840 #if TRACE_DEBUG
841 	for (i = 0; i < found; i++) {
842 
843 	}
844 #endif
845 	if (1 == back) {
846 		for (i = 0; i < found; i++) {
847 			if (0 == numbuf[i]) {
848 				back = 0;
849 			}
850 		}
851 	}
852 	else {
853 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
854 	}
855 
856 	return back;
857 }
858 
859 
860 
861 /**	Check configuration data from P7 lines.
862 	@param	w		Image width.
863 	@param	h		Image height.
864 	@param	ch		Number of channels in image.
865 	@param	maxval	Maximum component value.
866 	@param	tuptp	Address of tuple type variable.
867 	@param	erp		Error report, may be NULL.
868 	@return	1 on success, 0 on error.
869 */
870 static
871 int
dk4bifnetpbm_check_p7(size_t w,size_t h,size_t ch,size_t maxval,int * tuptp,dk4_er_t * erp)872 dk4bifnetpbm_check_p7(
873 	size_t		 w,
874 	size_t		 h,
875 	size_t		 ch,
876 	size_t		 maxval,
877 	int			*tuptp,
878 	dk4_er_t	*erp
879 )
880 {
881 	int			 back	= 0;
882 
883 
884 
885 
886 
887 
888 	if ((0 == ch) && (0 <= *tuptp)) {
889 		switch (*tuptp) {
890 			case DK4_NETPBM_TT_BLACKANDWHITE : {
891 				ch = 1;
892 			} break;
893 			case DK4_NETPBM_TT_GRAYSCALE : {
894 				ch = 1;
895 			} break;
896 			case DK4_NETPBM_TT_RGB : {
897 				ch = 3;
898 			} break;
899 			case DK4_NETPBM_TT_BLACKANDWHITE_ALPHA : {
900 				ch = 2;
901 			} break;
902 			case DK4_NETPBM_TT_GRAYSCALE_ALPHA : {
903 				ch = 2;
904 			} break;
905 			case DK4_NETPBM_TT_RGB_ALPHA : {
906 				ch = 4;
907 			} break;
908 #if TRACE_DEBUG
909 			default : {
910 
911 			} break;
912 #endif
913 		}
914 	}
915 	else {
916 		if ((0 < ch) && (0 > *tuptp)) {
917 			switch (ch) {
918 				case 1 : {
919 					*tuptp = DK4_NETPBM_TT_GRAYSCALE;
920 				} break;
921 				case 2 : {
922 					*tuptp = DK4_NETPBM_TT_GRAYSCALE_ALPHA;
923 				} break;
924 				case 3 : {
925 					*tuptp = DK4_NETPBM_TT_RGB;
926 				} break;
927 				case 4 : {
928 					*tuptp = DK4_NETPBM_TT_RGB_ALPHA;
929 				} break;
930 			}
931 		}
932 	}
933 	if (0 != dk4_bif_netpbm_check_input(w, h, maxval, erp)) {
934 		if ((0 != ch) && (0 <= *tuptp)) {
935 			switch (*tuptp) {
936 				case DK4_NETPBM_TT_BLACKANDWHITE : {
937 					if (1 == ch) { back = 1; }
938 				} break;
939 				case DK4_NETPBM_TT_GRAYSCALE : {
940 					if (1 == ch) { back = 1; }
941 				} break;
942 				case DK4_NETPBM_TT_RGB : {
943 					if (3 == ch) { back = 1; }
944 				} break;
945 				case DK4_NETPBM_TT_BLACKANDWHITE_ALPHA : {
946 					if (2 == ch) { back = 1; }
947 				} break;
948 				case DK4_NETPBM_TT_GRAYSCALE_ALPHA : {
949 					if (2 == ch) { back = 1; }
950 				} break;
951 				case DK4_NETPBM_TT_RGB_ALPHA : {
952 					if (4 == ch) { back = 1; }
953 				} break;
954 #if	TRACE_DEBUG
955 				default : {
956 
957 				} break;
958 #endif
959 			}
960 		}
961 	}
962 
963 	return back;
964 }
965 
966 
967 
968 /**	Read binary data for one row.
969 	@param	row		Address of row buffer to fill.
970 	@param	fipo	Input file, opened for binary reading.
971 	@param	nbytes	Number of bytes for row.
972 	@param	erp		Error report, may be NULL.
973 	@return	1 on success, 0 on error.
974 */
975 static
976 int
dk4bifnetpbm_read_row(unsigned char * row,FILE * fipo,size_t nbytes,dk4_er_t * erp)977 dk4bifnetpbm_read_row(
978 	unsigned char	*row,
979 	FILE			*fipo,
980 	size_t			 nbytes,
981 	dk4_er_t		*erp
982 )
983 {
984 	size_t		 rdbytes	=	0;	/* Number of bytes read */
985 	int			 back		= 1;
986 
987 #if	DK4_USE_ASSERT
988 	assert(NULL != row);
989 	assert(NULL != fipo);
990 #endif
991 	/*
992 		Normally one fread attempt should be sufficient.
993 		But sometimes multiple attempts are needed if
994 		an fread returns a small portion of data only.
995 		Reading 0 bytes means either end of file or read error.
996 	*/
997 	do {
998 		rdbytes = fread(row, 1, nbytes, fipo);
999 		if (0 < rdbytes) {
1000 			if (rdbytes >= nbytes) {
1001 				nbytes = 0;
1002 			}
1003 			else {
1004 				nbytes -= rdbytes;
1005 				row = &(row[rdbytes]);
1006 			}
1007 		}
1008 		else {
1009 			back = 0;
1010 		}
1011 	} while ((0 < nbytes) && (1 == back));
1012 	if (0 == back) {
1013 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1014 	}
1015 
1016 	return back;
1017 }
1018 
1019 
1020 
1021 /**	Read binary raster data.
1022 	@param	tsdata	Per-frame NetPBM data.
1023 	@param	fipo	Input file, opened for binary reading.
1024 	@param	erp		Error report, may be NULL.
1025 	@return	1 on success, 0 on error.
1026 */
1027 static
1028 int
dk4bifnetpbm_read_binary(void * tsdata,FILE * fipo,dk4_er_t * erp)1029 dk4bifnetpbm_read_binary(
1030 	void			*tsdata,
1031 	FILE			*fipo,
1032 	dk4_er_t		*erp
1033 )
1034 {
1035 	dk4_bif_netpbm_per_frame_t		 *pfd	= NULL;	/* Per-frame data */
1036 	unsigned char					**row	= NULL;	/* Array of row pointers */
1037 	size_t							  i;			/* Traverse all rows */
1038 	int								  back	= 0;
1039 
1040 #if	DK4_USE_ASSERT
1041 	assert(NULL != tsdata);
1042 	assert(NULL != fipo);
1043 #endif
1044 	pfd = (dk4_bif_netpbm_per_frame_t *)tsdata;
1045 	row = pfd->rows;
1046 	back = 1;
1047 	for (i = 0; i < (size_t)(pfd->h); i++) {
1048 		if (0 == dk4bifnetpbm_read_row(*(row++), fipo, pfd->bpr, erp)) {
1049 			back = 0; i = (size_t)(pfd->h);
1050 		}
1051 	}
1052 
1053 	return back;
1054 }
1055 
1056 
1057 
1058 
1059 /**	Read frame contents (NetPBM image) after magic number P7.
1060 	@param	pbuilder	Image builder structure.
1061 	@param	fipo		Input file, opened for binary reading.
1062 	@param	havefr		Flag: Already have frame.
1063 	@param	erp			Error report, may be NULL.
1064 	@return	1 on success, 0 on error.
1065 */
1066 static
1067 int
dk4bifnetpbm_read_p7(dk4_bif_netpbm_builder_t * pbuilder,FILE * fipo,int havefr,dk4_er_t * erp)1068 dk4bifnetpbm_read_p7(
1069 	dk4_bif_netpbm_builder_t	*pbuilder,
1070 	FILE						*fipo,
1071 	int							 havefr,
1072 	dk4_er_t					*erp
1073 )
1074 {
1075 	dk4_er_t	 er;				/* Error report */
1076 	char		*tok[256];			/* Tokens in input line */
1077 	char		 il[256];			/* Input line */
1078 	const char	*ep		= NULL;		/* End pointer */
1079 	size_t		 ilp		= 0;	/* Current position in input line */
1080 	size_t		 ntok		= 0;	/* Number of tokens in line */
1081 	size_t		 w			= 0;	/* Image width */
1082 	size_t		 h			= 0;	/* Image height */
1083 	size_t		 ch			= 0;	/* Number of channels */
1084 	size_t		 maxval		= 0;	/* Maximum component value */
1085 	int			 back		= 0;	/* Function result */
1086 	int			 cc			= 1;	/* Can continue (1=yes, 0=no, -1=error) */
1087 	int			 hdt		= 0;	/* Header line type */
1088 	int			 res		= 0;	/* Operation result */
1089 	int			 tupt		= -1;	/* Tuple type */
1090 	int			 c;
1091 
1092 #if	DK4_USE_ASSERT
1093 	assert(NULL != pbuilder);
1094 	assert(NULL != fipo);
1095 #endif
1096 	DK4_MEMRES(il,sizeof(il));
1097 	dk4error_init(&er);
1098 	do {
1099 		c = fgetc(fipo);
1100 		switch (c) {
1101 			case EOF : {
1102 				cc = -1;
1103 			} break;
1104 			case '\n' : {
1105 				il[ilp] = '\0';
1106 				ntok = dk4str8_tokenize(tok, 256, il, NULL, erp);
1107 
1108 				if (0 < ntok) {
1109 					hdt = dk4str8_array_index(dk4netpbm_p7_kw, tok[0], 0);
1110 
1111 					switch (hdt) {
1112 						case 0: {		/* WIDTH */
1113 							if (1 < ntok) {
1114 								ep = NULL;
1115 								res = dk4ma_input_c8_dec_size_t_simple(
1116 									&w, tok[1], &ep, 1, erp
1117 								);
1118 								if (0 == res) {
1119 									cc = -1;
1120 								}
1121 							}
1122 							else {
1123 								cc = -1;
1124 							}
1125 						} break;
1126 						case 1: {		/* HEIGHT */
1127 							if (1 < ntok) {
1128 								ep = NULL;
1129 								res = dk4ma_input_c8_dec_size_t_simple(
1130 									&h, tok[1], &ep, 1, erp
1131 								);
1132 								if (0 == res) {
1133 									cc = -1;
1134 								}
1135 							}
1136 							else {
1137 								cc = -1;
1138 							}
1139 						} break;
1140 						case 2: {		/* DEPTH */
1141 							if (1 < ntok) {
1142 								ep = NULL;
1143 								res = dk4ma_input_c8_dec_size_t_simple(
1144 									&ch, tok[1], &ep, 1, erp
1145 								);
1146 								if (0 == res) {
1147 									cc = -1;
1148 								}
1149 							}
1150 							else {
1151 								cc = -1;
1152 							}
1153 						} break;
1154 						case 3: {		/* MAXVAL */
1155 							if (1 < ntok) {
1156 								ep = NULL;
1157 								res = dk4ma_input_c8_dec_size_t_simple(
1158 									&maxval, tok[1], &ep, 1, erp
1159 								);
1160 								if (0 == res) {
1161 									cc = -1;
1162 								}
1163 							}
1164 							else {
1165 								cc = -1;
1166 							}
1167 						} break;
1168 						case 4: {		/* TUPLTYPE */
1169 							if (1 < ntok) {
1170 								tupt = dk4str8_array_index(
1171 									dk4netpbm_p7_tut, tok[1], 0
1172 								);
1173 								if (0 > tupt) {
1174 
1175 
1176 									/*	2018-03-14
1177 										Simply ignore unkown tuple types.
1178 									*/
1179 								}
1180 							}
1181 							else {
1182 								cc = -1;
1183 							}
1184 						} break;
1185 						case 5: {		/* ENDHDR */
1186 							cc = -1;
1187 							res = dk4bifnetpbm_check_p7(
1188 								w, h, ch, maxval, &tupt, erp
1189 							);
1190 							if (0 != res) {
1191 								back = 1;
1192 								if (0 != havefr) {
1193 									back = dk4biftool_nc_add_frame(
1194 										pbuilder->bif, erp
1195 									);
1196 								}
1197 								if (1 == back) {
1198 									back = 0;
1199 									pbuilder->bif->cf->tsdata =
1200 									dk4bifnetpbm_tsdata_new(
1201 										DK4_NETPBM_P7,tupt,ch,w,h,maxval,erp
1202 									);
1203 									if (NULL != pbuilder->bif->cf->tsdata) {
1204 										cc = 0;
1205 										dk4bifnetpbm_fill_frame(
1206 											pbuilder->bif->cf,
1207 											pbuilder->bif->cf->tsdata
1208 										);
1209 									}
1210 								}
1211 							}
1212 						} break;
1213 						default : {
1214 							cc = -1;
1215 						} break;
1216 					}
1217 				}
1218 				else {
1219 					/* Empty line is ok */
1220 				}
1221 				DK4_MEMRES(il,sizeof(il));
1222 				ilp = 0;
1223 			} break;
1224 			default : {
1225 				il[ilp++] = (char)c;
1226 				if (sizeof(il) <= ilp) {
1227 					cc = -1;
1228 				}
1229 			} break;
1230 		}
1231 	} while (1 == cc);
1232 
1233 
1234 
1235 
1236 
1237 	if (0 == cc) {
1238 		/*
1239 			Read raster data
1240 		*/
1241 		back = dk4bifnetpbm_read_binary(
1242 			pbuilder->bif->cf->tsdata, fipo, erp
1243 		);
1244 	}
1245 
1246 	return back;
1247 }
1248 
1249 
1250 
1251 /**	Read bit values as text.
1252 	@param	tsdata	Per-frame NetPBM data.
1253 	@param	fipo	Input file, opened for binary reading.
1254 	@param	erp		Error report, may be NULL.
1255 	@return	1 on success, 0 on error.
1256 */
1257 static
1258 int
dk4bifnetpbm_read_bits_text(void * tsdata,FILE * fipo,dk4_er_t * erp)1259 dk4bifnetpbm_read_bits_text(
1260 	void			*tsdata,
1261 	FILE			*fipo,
1262 	dk4_er_t		*erp
1263 )
1264 {
1265 	dk4_bif_netpbm_per_frame_t	*pfd;			/* Per-frame data */
1266 	size_t						 rowno	=	0;	/* Current row number */
1267 	size_t						 valno	=	0;	/* Current value number */
1268 	size_t						 byteno	=	0;	/* Byte number within row */
1269 	size_t						 bitno	=	0;	/* Bit number within byte */
1270 	int							 back	=	1;
1271 	int							 cc		=	1;	/* Flag: Can continue */
1272 	int							 c;				/* Current input character */
1273 	unsigned char				 uc;			/* Byte to save */
1274 
1275 #if	DK4_USE_ASSERT
1276 	assert(NULL != tsdata);
1277 	assert(NULL != fipo);
1278 #endif
1279 	pfd = (dk4_bif_netpbm_per_frame_t *)tsdata;
1280 	do {
1281 		c = fgetc(fipo);
1282 		switch (c) {
1283 			case EOF : {
1284 				cc		= -1;
1285 				back	=  0;
1286 			} break;
1287 			case '0' : case '1' : {
1288 				if ('1' == c) {
1289 					byteno	=	valno / 8;
1290 					bitno	=	valno % 8;
1291 					uc		=	(unsigned char)dk4pxbit_get_bit(7 - bitno);
1292 					((pfd->rows)[rowno])[byteno] |= uc;
1293 				}
1294 				valno++;
1295 				if (valno >= pfd->vpr) {
1296 					valno = 0;
1297 					rowno++;
1298 					if (rowno >= (size_t)(pfd->h)) {
1299 						cc = 0;
1300 					}
1301 				}
1302 			} break;
1303 			case ' '  :
1304 			case '\t' :
1305 			case '\r' :
1306 			case '\n' :
1307 			case '\v' :
1308 			case '\f' : {
1309 			} break;
1310 			default : {
1311 				cc = -1;
1312 			} break;
1313 		}
1314 	} while (1 == cc);
1315 	if (0 == cc) {
1316 		do {
1317 			c = fgetc(fipo);
1318 		} while ((EOF != c) && (0 == feof(fipo)) && (0 == ferror(fipo)));
1319 	}
1320 	if (0 == back) {
1321 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1322 	}
1323 
1324 	return back;
1325 }
1326 
1327 
1328 
1329 /**	Read pixel component values as text.
1330 	@param	tsdata	Per-frame NetPBM data.
1331 	@param	fipo	Input file, opened for binary reading.
1332 	@param	erp		Error report, may be NULL.
1333 	@return	1 on success, 0 on error.
1334 */
1335 static
1336 int
dk4bifnetpbm_read_values_from_text(void * tsdata,FILE * fipo,dk4_er_t * erp)1337 dk4bifnetpbm_read_values_from_text(
1338 	void			*tsdata,
1339 	FILE			*fipo,
1340 	dk4_er_t		*erp
1341 )
1342 {
1343 	dk4_er_t					 er;				/* Error report for math */
1344 	dk4_bif_netpbm_per_frame_t	*pfd	=	NULL;	/* Per-frame data */
1345 	size_t						 rowno	=	0;		/* Current row number */
1346 	size_t						 valno	=	0;		/* Current value number */
1347 	size_t						 value	=	0;		/* Sample value */
1348 	int							 back	=	1;
1349 	int							 st		=	0;		/* State: 1=in number */
1350 	int							 cc		=	1;		/* Flag: Can continue */
1351 	int							 c;					/* Current character */
1352 	unsigned char				 uc;				/* Byte to save */
1353 
1354 #if	DK4_USE_ASSERT
1355 	assert(NULL != tsdata);
1356 	assert(NULL != fipo);
1357 #endif
1358 	pfd = (dk4_bif_netpbm_per_frame_t *)tsdata;
1359 	dk4error_init(&er);
1360 	do {
1361 		c = fgetc(fipo);
1362 		switch (c) {
1363 			case EOF : {
1364 				if (0 != st) {
1365 					cc = -1;
1366 					back = 0;
1367 					if (value <= pfd->maxval) {
1368 						if (256 > pfd->maxval) {
1369 							uc = (unsigned char)value;
1370 							((pfd->rows)[rowno])[valno]	= uc;
1371 						}
1372 						else {
1373 							uc = (value >> 8) & 0x00FFU;
1374 							((pfd->rows)[rowno])[2 * valno] = uc;
1375 							uc = value & 0x00FFU;
1376 							((pfd->rows)[rowno])[2 * valno + 1] = uc;
1377 						}
1378 						valno++;
1379 						if (valno >= pfd->vpr) {
1380 							valno = 0;
1381 							rowno++;
1382 							if (rowno >= (size_t)(pfd->h)) {
1383 								back = 1;
1384 							}
1385 						}
1386 					}
1387 				}
1388 				else {
1389 					cc = -1;
1390 					back = 0;
1391 				}
1392 			} break;
1393 			case '0' : case '1' : case '2' : case '3' : case '4' :
1394 			case '5' : case '6' : case '7' : case '8' : case '9' : {
1395 				if (0 != st) {
1396 					value = dk4ma_size_t_add(
1397 						dk4ma_size_t_mul(value, 10, &er),
1398 						dk4bifnetpbm_digit((char)c), &er
1399 					);
1400 				}
1401 				else {
1402 					value = dk4bifnetpbm_digit((char)c);
1403 				}
1404 				st = 1;
1405 			} break;
1406 			case ' '  :
1407 			case '\t' :
1408 			case '\r' :
1409 			case '\n' :
1410 			case '\v' :
1411 			case '\f' : {
1412 				if (0 != st) {
1413 					if (value <= pfd->maxval) {
1414 						if (256 > pfd->maxval) {
1415 							uc = (unsigned char)value;
1416 							((pfd->rows)[rowno])[valno] = uc;
1417 						}
1418 						else {
1419 							uc = (value >> 8) & 0x00FFU;
1420 							((pfd->rows)[rowno])[2 * valno] = uc;
1421 							uc = value & 0x00FFU;
1422 							((pfd->rows)[rowno])[2 * valno + 1] = uc;
1423 						}
1424 						valno++;
1425 						if (valno >= pfd->vpr) {
1426 							valno = 0;
1427 							rowno++;
1428 							if (rowno >= (size_t)(pfd->h)) {
1429 								back = 1;
1430 								cc = 0;
1431 							}
1432 						}
1433 					}
1434 					else {
1435 						cc = -1;
1436 						back = 0;
1437 					}
1438 				}
1439 				st = 0;
1440 			} break;
1441 			default : {
1442 				cc = -1;
1443 				back = 0;
1444 			} break;
1445 		}
1446 	} while (1 == cc);
1447 	if (0 == cc) {
1448 		do {
1449 			c = fgetc(fipo);
1450 		} while ((EOF != c) && (0 == feof(fipo)) && (0 == ferror(fipo)));
1451 	}
1452 	if (DK4_E_NONE != er.ec) {
1453 		back = 0;
1454 	}
1455 	if (0 == back) {
1456 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1457 	}
1458 
1459 	return back;
1460 }
1461 
1462 
1463 
1464 /**	Read frame contents (NetPBM image) after magic number.
1465 	@param	pbuilder	Image builder structure.
1466 	@param	fipo		Input file, opened for binary reading.
1467 	@param	havefr		Flag: Already have a frame.
1468 	@param	erp			Error report, may be NULL.
1469 	@return	1 on success, 0 on error.
1470 */
1471 static
1472 int
dk4bifnetpbm_read_frame_contents(dk4_bif_netpbm_builder_t * pbuilder,FILE * fipo,int havefr,dk4_er_t * erp)1473 dk4bifnetpbm_read_frame_contents(
1474 	dk4_bif_netpbm_builder_t	*pbuilder,
1475 	FILE						*fipo,
1476 	int							 havefr,
1477 	dk4_er_t					*erp
1478 )
1479 {
1480 	int			 back	= 0;
1481 
1482 #if	DK4_USE_ASSERT
1483 	assert(NULL != pbuilder);
1484 	assert(NULL != fipo);
1485 #endif
1486 	switch (pbuilder->magnum) {
1487 		case DK4_NETPBM_P1 :
1488 		case DK4_NETPBM_P4 :
1489 		{
1490 			back = dk4bifnetpbm_read_header_16(
1491 				fipo, &(pbuilder->nums[0]), 2, erp
1492 			);
1493 			if (1 == back) {
1494 				back = 0;
1495 				if (0 != havefr) {
1496 					if (0 != dk4biftool_nc_add_frame(pbuilder->bif, erp)) {
1497 						back = 1;
1498 					}
1499 				}
1500 				else {
1501 					back = 1;
1502 				}
1503 				if (0 != back) {
1504 					back = 0;
1505 					pbuilder->bif->cf->tsdata = dk4bifnetpbm_tsdata_new(
1506 						pbuilder->magnum, pbuilder->tupt, 1,
1507 						pbuilder->nums[0], pbuilder->nums[1], 1,
1508 						erp
1509 					);
1510 					if (NULL != pbuilder->bif->cf->tsdata) {
1511 						dk4bifnetpbm_fill_frame(
1512 							pbuilder->bif->cf,
1513 							pbuilder->bif->cf->tsdata
1514 						);
1515 						if (DK4_NETPBM_P4 == pbuilder->magnum) {
1516 							back = dk4bifnetpbm_read_binary(
1517 								pbuilder->bif->cf->tsdata, fipo, erp
1518 							);
1519 						}
1520 						else {
1521 							back = dk4bifnetpbm_read_bits_text(
1522 								pbuilder->bif->cf->tsdata, fipo, erp
1523 							);
1524 						}
1525 					}
1526 				}
1527 			}
1528 		} break;
1529 		case DK4_NETPBM_P2 :
1530 		case DK4_NETPBM_P3 :
1531 		case DK4_NETPBM_P5 :
1532 		case DK4_NETPBM_P6 :
1533 		{
1534 			back = dk4bifnetpbm_read_header_16(
1535 				fipo, &(pbuilder->nums[0]), 3, erp
1536 			);
1537 			if (1 == back) {
1538 				back = 0;
1539 				if (0 != havefr) {
1540 					if (0 != dk4biftool_nc_add_frame(pbuilder->bif, erp)) {
1541 						back = 1;
1542 					}
1543 				}
1544 				else {
1545 					back = 1;
1546 				}
1547 				if (0 != back) {
1548 					back = 0;
1549 					switch (pbuilder->magnum) {
1550 						case DK4_NETPBM_P2 : case DK4_NETPBM_P5 : {
1551 							pbuilder->bif->cf->tsdata = dk4bifnetpbm_tsdata_new(
1552 								pbuilder->magnum, pbuilder->tupt, 1,
1553 								pbuilder->nums[0], pbuilder->nums[1],
1554 								pbuilder->nums[2], erp
1555 							);
1556 						} break;
1557 						default : {
1558 							pbuilder->bif->cf->tsdata = dk4bifnetpbm_tsdata_new(
1559 								pbuilder->magnum, pbuilder->tupt, 3,
1560 								pbuilder->nums[0], pbuilder->nums[1],
1561 								pbuilder->nums[2], erp
1562 							);
1563 						} break;
1564 					}
1565 					if (NULL != pbuilder->bif->cf->tsdata) {
1566 						dk4bifnetpbm_fill_frame(
1567 							pbuilder->bif->cf,
1568 							pbuilder->bif->cf->tsdata
1569 						);
1570 						switch (pbuilder->magnum) {
1571 							case DK4_NETPBM_P5 : case DK4_NETPBM_P6 : {
1572 								back = dk4bifnetpbm_read_binary(
1573 									pbuilder->bif->cf->tsdata, fipo, erp
1574 								);
1575 							} break;
1576 							default : {
1577 								back = dk4bifnetpbm_read_values_from_text(
1578 									pbuilder->bif->cf->tsdata, fipo, erp
1579 								);
1580 							} break;
1581 						}
1582 					}
1583 				}
1584 			}
1585 		} break;
1586 		case DK4_NETPBM_P7 :
1587 		{
1588 			back = dk4bifnetpbm_read_p7(pbuilder, fipo, havefr, erp);
1589 		} break;
1590 		default : {
1591 			dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1592 		} break;
1593 	}
1594 
1595 	return back;
1596 }
1597 
1598 
1599 
1600 /**	Read one frame (one image) from the input file and add it to builder.
1601 	@param	pbuilder	Image builder structure.
1602 	@param	fipo		Input file, opened for binary reading.
1603 	@param	havefr		Flag: Already have previous frame.
1604 	@param	erp			Error report, may be NULL.
1605 	@return	1 on success, 0 on end of file, -1 on error.
1606 */
1607 static
1608 int
dk4bifnetpbm_read_frame(dk4_bif_netpbm_builder_t * pbuilder,FILE * fipo,int havefr,dk4_er_t * erp)1609 dk4bifnetpbm_read_frame(
1610 	dk4_bif_netpbm_builder_t	*pbuilder,
1611 	FILE						*fipo,
1612 	int							 havefr,
1613 	dk4_er_t					*erp
1614 )
1615 {
1616 	int		 back	= -1;
1617 
1618 #if	DK4_USE_ASSERT
1619 	assert(NULL != pbuilder);
1620 	assert(NULL != fipo);
1621 #endif
1622 	back = dk4bifnetpbm_read_magic_number(pbuilder, fipo, havefr, erp);
1623 	if (1 == back) {
1624 		back = dk4bifnetpbm_read_frame_contents(pbuilder, fipo, havefr, erp);
1625 		if (1 != back) {
1626 			back = -1;
1627 		}
1628 	}
1629 
1630 	return back;
1631 }
1632 
1633 
1634 
1635 dk4_bif_t *
dk4bifnetpbm_nc_open_file(FILE * fipo,dkChar const * fn,int honly,dk4_cs_conv_ctx_t const * pcsctx,dk4_er_t * erp)1636 dk4bifnetpbm_nc_open_file(
1637 	FILE						*fipo,
1638 	dkChar	const				*fn,
1639 	int							 honly,
1640 	dk4_cs_conv_ctx_t	const	*pcsctx,
1641 	dk4_er_t					*erp
1642 )
1643 {
1644 	dk4_bif_t					*back	= NULL;
1645 	int							 res	= 0;		/* Operation result */
1646 	int							 havefr	= 0;		/* Flag: frames found */
1647 	dk4_bif_netpbm_builder_t	 builder;			/* Builder structure */
1648 
1649 #if	DK4_USE_ASSERT
1650 	assert(NULL != fipo);
1651 #endif
1652 	/*	Initialize the builder
1653 	*/
1654 	if (0 != dk4_bif_netpbm_builder_initialize(&builder,fn,honly,pcsctx,erp)) {
1655 
1656 		/*	Attempt to read all frames from input
1657 		*/
1658 		do {
1659 			res = dk4bifnetpbm_read_frame(&builder, fipo, havefr, erp);
1660 			switch (res) {
1661 				case 1: {
1662 					havefr = 1;
1663 				} break;
1664 			}
1665 		} while (0 < res);
1666 
1667 		/*	On success (at least one frame was read, end of file
1668 			was found after last frame) return the builders collected data
1669 		*/
1670 		if ((-1 != res) && (0 != havefr)) {
1671 			back = builder.bif;
1672 			builder.bif = NULL;
1673 		}
1674 
1675 		/*	Finally clean up the builder
1676 		*/
1677 		dk4_bif_netpbm_builder_cleanup(&builder);
1678 
1679 	}
1680 
1681 	return back;
1682 }
1683 
1684 
1685 
1686 /**	Shift and mask a value.
1687 	@param	u	Original value.
1688 	@param	w	Shift width, 0 allowed.
1689 	@param	m	Mask value.
1690 	@return	Operation result.
1691 */
1692 static
1693 dk4_px_t
dk4bifnetpbm_shift_mask(unsigned u,unsigned w,unsigned m)1694 dk4bifnetpbm_shift_mask(unsigned u, unsigned w, unsigned m)
1695 {
1696 	if (0 < w) {
1697 		u = u << w;
1698 	}
1699 	return ((dk4_px_t)(u & m));
1700 }
1701 
1702 
1703 
1704 /**	Combine two bytes into one 16 bit unsigned integer for pixel component.
1705 	@param	msb	Most significant byte.
1706 	@param	lsb	Least significant byte.
1707 	@return	Pixel component value.
1708 */
1709 static
1710 dk4_px_t
dk4bifnetpbm_combine_bytes(unsigned char msb,unsigned char lsb)1711 dk4bifnetpbm_combine_bytes(unsigned char msb, unsigned char lsb)
1712 {
1713 	dk4_px_t	back;
1714 
1715 #if	VERSION_BEFORE_20210729
1716 	back =	((((dk4_px_t)msb) << 8) & ((dk4_px_t)0xFF00U))
1717 			| (((dk4_px_t)lsb) & ((dk4_px_t)0x00FFU));
1718 #endif
1719 	back =	dk4bifnetpbm_shift_mask(msb, 8, 0xFF00U)
1720 			| dk4bifnetpbm_shift_mask(lsb, 0, 0x00FFU);
1721 
1722 	return back;
1723 }
1724 
1725 
1726 int
dk4bifnetpbm_nc_get_original_pixel(dk4_px_t * dptr,dk4_bif_t const * bif,dk4_bif_dim_t rowno,dk4_bif_dim_t colno)1727 dk4bifnetpbm_nc_get_original_pixel(
1728 	dk4_px_t				*dptr,
1729 	dk4_bif_t		const	*bif,
1730 	dk4_bif_dim_t			 rowno,
1731 	dk4_bif_dim_t			 colno
1732 )
1733 {
1734 	dk4_bif_netpbm_per_frame_t	*pfd	= NULL;	/* Per-frame data */
1735 	unsigned char				*ucptr	= NULL;	/* Row data */
1736 	size_t						 byteno;		/* Byte number to retrieve */
1737 	size_t						 bitno;			/* Bit number within byte */
1738 	size_t						 i;				/* Traverse components */
1739 	int							 back	= 0;
1740 	unsigned char				 uc;			/* Byte read from buffer */
1741 
1742 #if	DK4_USE_ASSERT
1743 	assert(NULL != dptr);
1744 	assert(NULL != bif);
1745 #endif
1746 	if (NULL == bif->cf) {
1747 		goto finished;
1748 	}
1749 	if (NULL == bif->cf->tsdata) {
1750 		goto finished;
1751 	}
1752 	pfd = (dk4_bif_netpbm_per_frame_t *)(bif->cf->tsdata);
1753 	if (NULL == pfd->rows) {
1754 		goto finished;
1755 	}
1756 	switch (pfd->magnum) {
1757 		case DK4_NETPBM_P1 : case DK4_NETPBM_P4 : {
1758 			byteno = (size_t)colno / 8;
1759 			bitno  = (size_t)colno % 8;
1760 			uc = ((pfd->rows)[rowno])[byteno];
1761 			if (0 != (dk4pxbit_get_bit(7 - bitno) & uc)) {
1762 				*dptr = 0;
1763 			}
1764 			else {
1765 				*dptr = 1;
1766 			}
1767 			back = 1;
1768 		} break;
1769 		case DK4_NETPBM_P2 : case DK4_NETPBM_P5 : {
1770 			if (256 > pfd->maxval) {
1771 				*dptr = (dk4_px_t)(((pfd->rows)[rowno])[colno]);
1772 			}
1773 			else {
1774 				*dptr = dk4bifnetpbm_combine_bytes(
1775 					((pfd->rows)[rowno])[2 * colno],
1776 					((pfd->rows)[rowno])[2 * colno + 1]
1777 				);
1778 			}
1779 			back = 1;
1780 		} break;
1781 		case DK4_NETPBM_P3 : case DK4_NETPBM_P6 : {
1782 			if (256 > pfd->maxval) {
1783 				dptr[0] = (dk4_px_t)(((pfd->rows)[rowno])[3 * colno]);
1784 				dptr[1] = (dk4_px_t)(((pfd->rows)[rowno])[3 * colno + 1]);
1785 				dptr[2] = (dk4_px_t)(((pfd->rows)[rowno])[3 * colno + 2]);
1786 			}
1787 			else {
1788 				dptr[0] = dk4bifnetpbm_combine_bytes(
1789 					((pfd->rows)[rowno])[6 * colno],
1790 					((pfd->rows)[rowno])[6 * colno + 1]
1791 				);
1792 				dptr[1] = dk4bifnetpbm_combine_bytes(
1793 					((pfd->rows)[rowno])[6 * colno + 2],
1794 					((pfd->rows)[rowno])[6 * colno + 3]
1795 				);
1796 				dptr[2] = dk4bifnetpbm_combine_bytes(
1797 					((pfd->rows)[rowno])[6 * colno + 4],
1798 					((pfd->rows)[rowno])[6 * colno + 5]
1799 				);
1800 			}
1801 			back = 1;
1802 		} break;
1803 		case DK4_NETPBM_P7 : {
1804 			switch (pfd->tupt) {
1805 				case DK4_NETPBM_TT_BLACKANDWHITE : {
1806 					if (0 != ((pfd->rows)[rowno])[colno]) {
1807 						*dptr = 1;
1808 					}
1809 					else {
1810 						*dptr = 0;
1811 					}
1812 					back = 1;
1813 				} break;
1814 				case DK4_NETPBM_TT_GRAYSCALE : {
1815 					if (256 > pfd->maxval) {
1816 						*dptr = (dk4_px_t)(((pfd->rows)[rowno])[colno]);
1817 					}
1818 					else {
1819 						*dptr = dk4bifnetpbm_combine_bytes(
1820 							((pfd->rows)[rowno])[2 * colno],
1821 							((pfd->rows)[rowno])[2 * colno + 1]
1822 						);
1823 					}
1824 					back = 1;
1825 				} break;
1826 				case DK4_NETPBM_TT_RGB : {
1827 					if (256 > pfd->maxval) {
1828 						dptr[0] = (dk4_px_t)(((pfd->rows)[rowno])[3*colno]);
1829 						dptr[1] = (dk4_px_t)(((pfd->rows)[rowno])[3*colno+1]);
1830 						dptr[2] = (dk4_px_t)(((pfd->rows)[rowno])[3*colno+2]);
1831 					}
1832 					else {
1833 						dptr[0] = dk4bifnetpbm_combine_bytes(
1834 							((pfd->rows)[rowno])[6 * colno],
1835 							((pfd->rows)[rowno])[6 * colno + 1]
1836 						);
1837 						dptr[1] = dk4bifnetpbm_combine_bytes(
1838 							((pfd->rows)[rowno])[6 * colno + 2],
1839 							((pfd->rows)[rowno])[6 * colno + 3]
1840 						);
1841 						dptr[2] = dk4bifnetpbm_combine_bytes(
1842 							((pfd->rows)[rowno])[6 * colno + 4],
1843 							((pfd->rows)[rowno])[6 * colno + 5]
1844 						);
1845 					}
1846 					back = 1;
1847 				} break;
1848 				case DK4_NETPBM_TT_BLACKANDWHITE_ALPHA : {
1849 					if (0 != ((pfd->rows)[rowno])[2 * colno]) {
1850 						dptr[0] = 1;
1851 					}
1852 					else {
1853 						dptr[0] = 0;
1854 					}
1855 					if (0 != ((pfd->rows)[rowno])[2 * colno + 1]) {
1856 						dptr[1] = 1;
1857 					}
1858 					else {
1859 						dptr[1] = 0;
1860 					}
1861 					back = 1;
1862 				} break;
1863 				case DK4_NETPBM_TT_GRAYSCALE_ALPHA : {
1864 					if (256 > pfd->maxval) {
1865 						dptr[0] = (dk4_px_t)(((pfd->rows)[rowno])[2*colno]);
1866 						dptr[1] = (dk4_px_t)(((pfd->rows)[rowno])[2*colno+1]);
1867 					}
1868 					else {
1869 						dptr[0] = dk4bifnetpbm_combine_bytes(
1870 							((pfd->rows)[rowno])[4 * colno],
1871 							((pfd->rows)[rowno])[4 * colno + 1]
1872 						);
1873 						dptr[1] = dk4bifnetpbm_combine_bytes(
1874 							((pfd->rows)[rowno])[4 * colno + 2],
1875 							((pfd->rows)[rowno])[4 * colno + 3]
1876 						);
1877 					}
1878 					back = 1;
1879 				} break;
1880 				case DK4_NETPBM_TT_RGB_ALPHA : {
1881 					if (256 > pfd->maxval) {
1882 						dptr[0] = (dk4_px_t)(((pfd->rows)[rowno])[4*colno]);
1883 						dptr[1] = (dk4_px_t)(((pfd->rows)[rowno])[4*colno+1]);
1884 						dptr[2] = (dk4_px_t)(((pfd->rows)[rowno])[4*colno+2]);
1885 						dptr[3] = (dk4_px_t)(((pfd->rows)[rowno])[4*colno+3]);
1886 					}
1887 					else {
1888 						dptr[0] = dk4bifnetpbm_combine_bytes(
1889 							((pfd->rows)[rowno])[8 * colno],
1890 							((pfd->rows)[rowno])[8 * colno + 1]
1891 						);
1892 						dptr[1] = dk4bifnetpbm_combine_bytes(
1893 							((pfd->rows)[rowno])[8 * colno + 2],
1894 							((pfd->rows)[rowno])[8 * colno + 3]
1895 						);
1896 						dptr[2] = dk4bifnetpbm_combine_bytes(
1897 							((pfd->rows)[rowno])[8 * colno + 4],
1898 							((pfd->rows)[rowno])[8 * colno + 5]
1899 						);
1900 						dptr[3] = dk4bifnetpbm_combine_bytes(
1901 							((pfd->rows)[rowno])[8 * colno + 6],
1902 							((pfd->rows)[rowno])[8 * colno + 7]
1903 						);
1904 					}
1905 					back = 1;
1906 				} break;
1907 				default : {
1908 
1909 					if (256 > pfd->maxval) {
1910 						ucptr = (pfd->rows)[(size_t)rowno];
1911 						for (i = 0; i < pfd->ch; i++) {
1912 							dptr[i] =
1913 							(dk4_px_t)(ucptr[pfd->ch * (size_t)colno + i]);
1914 						}
1915 					}
1916 					else {
1917 						ucptr = (pfd->rows)[(size_t)rowno];
1918 						for (i = 0; i < pfd->ch; i++) {
1919 							dptr[i] = dk4bifnetpbm_combine_bytes(
1920 								ucptr[2*(pfd->ch * (size_t)colno + i)],
1921 								ucptr[2*(pfd->ch * (size_t)colno + i)+1]
1922 							);
1923 						}
1924 					}
1925 					back = 1;
1926 				} break;
1927 			}
1928 		} break;
1929 	}
1930 
1931 	finished:
1932 
1933 	return back;
1934 }
1935 
1936 
1937 
1938 
1939 /* vim: set ai sw=4 ts=4 : */
1940 
1941