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