1 /*
2 ** SPDX-License-Identifier: BSD-3-Clause
3 ** Copyright Contributors to the OpenEXR Project.
4 */
5
6 #include "internal_file.h"
7
8 #include "internal_attr.h"
9 #include "internal_constants.h"
10 #include "internal_structs.h"
11 #include "internal_xdr.h"
12
13 #include <limits.h>
14 #include <math.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include <stdio.h>
19
20 /**************************************/
21
22 struct _internal_exr_seq_scratch
23 {
24 uint8_t* scratch;
25 uint64_t curpos;
26 int64_t navail;
27 uint64_t fileoff;
28
29 exr_result_t (*sequential_read) (
30 struct _internal_exr_seq_scratch*, void*, uint64_t);
31
32 struct _internal_exr_context* ctxt;
33 };
34
35 static inline int
scratch_attr_too_big(struct _internal_exr_seq_scratch * scr,int32_t attrsz,int64_t fsize)36 scratch_attr_too_big (
37 struct _internal_exr_seq_scratch* scr, int32_t attrsz, int64_t fsize)
38 {
39 int64_t acmp = (int64_t) attrsz;
40 if (fsize > 0 && (acmp > scr->navail))
41 {
42 int64_t test = acmp - scr->navail;
43 int64_t foff = (int64_t) scr->fileoff;
44 if ((foff + test) > fsize) return 1;
45 }
46 return 0;
47 }
48
49 #define SCRATCH_BUFFER_SIZE 4096
50
51 static exr_result_t
scratch_seq_read(struct _internal_exr_seq_scratch * scr,void * buf,uint64_t sz)52 scratch_seq_read (struct _internal_exr_seq_scratch* scr, void* buf, uint64_t sz)
53 {
54 uint8_t* outbuf = buf;
55 uint64_t nCopied = 0;
56 uint64_t notdone = sz;
57 exr_result_t rv = -1;
58
59 while (notdone > 0)
60 {
61 if (scr->navail > 0)
62 {
63 uint64_t nLeft = (uint64_t) scr->navail;
64 uint64_t nCopy = notdone;
65 if (nCopy > nLeft) nCopy = nLeft;
66 memcpy (outbuf, scr->scratch + scr->curpos, nCopy);
67 scr->curpos += nCopy;
68 scr->navail -= (int64_t) nCopy;
69 notdone -= nCopy;
70 outbuf += nCopy;
71 nCopied += nCopy;
72 }
73 else if (notdone > SCRATCH_BUFFER_SIZE)
74 {
75 uint64_t nPages = notdone / SCRATCH_BUFFER_SIZE;
76 int64_t nread = 0;
77 uint64_t nToRead = nPages * SCRATCH_BUFFER_SIZE;
78 rv = scr->ctxt->do_read (
79 scr->ctxt,
80 outbuf,
81 nToRead,
82 &(scr->fileoff),
83 &nread,
84 EXR_MUST_READ_ALL);
85 if (nread > 0)
86 {
87 notdone -= (uint64_t) nread;
88 outbuf += nread;
89 nCopied += (uint64_t) nread;
90 }
91 else
92 {
93 break;
94 }
95 }
96 else
97 {
98 int64_t nread = 0;
99 rv = scr->ctxt->do_read (
100 scr->ctxt,
101 scr->scratch,
102 SCRATCH_BUFFER_SIZE,
103 &(scr->fileoff),
104 &nread,
105 EXR_ALLOW_SHORT_READ);
106 if (nread > 0)
107 {
108 scr->navail = nread;
109 scr->curpos = 0;
110 }
111 else
112 {
113 if (nread == 0)
114 rv = scr->ctxt->report_error (
115 scr->ctxt,
116 EXR_ERR_READ_IO,
117 "End of file attempting to read header");
118 break;
119 }
120 }
121 }
122 if (rv == -1)
123 {
124 if (nCopied == sz)
125 rv = EXR_ERR_SUCCESS;
126 else
127 rv = EXR_ERR_READ_IO;
128 }
129 return rv;
130 }
131
132 /**************************************/
133
134 static exr_result_t
priv_init_scratch(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scr,uint64_t offset)135 priv_init_scratch (
136 struct _internal_exr_context* ctxt,
137 struct _internal_exr_seq_scratch* scr,
138 uint64_t offset)
139 {
140 scr->curpos = 0;
141 scr->navail = 0;
142 scr->fileoff = offset;
143 scr->sequential_read = &scratch_seq_read;
144 scr->ctxt = ctxt;
145 scr->scratch = ctxt->alloc_fn (SCRATCH_BUFFER_SIZE);
146 if (scr->scratch == NULL)
147 return ctxt->standard_error (ctxt, EXR_ERR_OUT_OF_MEMORY);
148 return EXR_ERR_SUCCESS;
149 }
150
151 /**************************************/
152
153 static void
priv_destroy_scratch(struct _internal_exr_seq_scratch * scr)154 priv_destroy_scratch (struct _internal_exr_seq_scratch* scr)
155 {
156 struct _internal_exr_context* pctxt = scr->ctxt;
157 if (scr->scratch) pctxt->free_fn (scr->scratch);
158 }
159
160 /**************************************/
161
162 static exr_result_t
check_bad_attrsz(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,int32_t attrsz,int32_t eltsize,const char * aname,const char * tname,int32_t * outsz)163 check_bad_attrsz (
164 struct _internal_exr_context* ctxt,
165 struct _internal_exr_seq_scratch* scratch,
166 int32_t attrsz,
167 int32_t eltsize,
168 const char* aname,
169 const char* tname,
170 int32_t* outsz)
171 {
172 int32_t n = attrsz;
173
174 *outsz = n;
175 if (attrsz < 0)
176 return ctxt->print_error (
177 ctxt,
178 EXR_ERR_ATTR_SIZE_MISMATCH,
179 "Attribute '%s', type '%s': Invalid negative size %d",
180 aname,
181 tname,
182 attrsz);
183
184 if (scratch_attr_too_big (scratch, attrsz, ctxt->file_size))
185 return ctxt->print_error (
186 ctxt,
187 EXR_ERR_ATTR_SIZE_MISMATCH,
188 "Attribute '%s', type '%s': Invalid size %d",
189 aname,
190 tname,
191 attrsz);
192
193 if (eltsize > 1)
194 {
195 n = attrsz / eltsize;
196 if (attrsz != (int32_t) (n * eltsize))
197 return ctxt->print_error (
198 ctxt,
199 EXR_ERR_ATTR_SIZE_MISMATCH,
200 "Attribute '%s': Invalid size %d (exp '%s' size 4 * n, found odd bytes %d)",
201 aname,
202 attrsz,
203 tname,
204 (attrsz % eltsize));
205 *outsz = n;
206 }
207
208 return EXR_ERR_SUCCESS;
209 }
210
211 /**************************************/
212
213 static exr_result_t
read_text(struct _internal_exr_context * ctxt,char text[256],int32_t * outlen,int32_t maxlen,struct _internal_exr_seq_scratch * scratch,const char * type)214 read_text (
215 struct _internal_exr_context* ctxt,
216 char text[256],
217 int32_t* outlen,
218 int32_t maxlen,
219 struct _internal_exr_seq_scratch* scratch,
220 const char* type)
221 {
222 char b;
223 exr_result_t rv = EXR_ERR_SUCCESS;
224 int32_t namelen = *outlen;
225
226 while (namelen <= maxlen)
227 {
228 rv = scratch->sequential_read (scratch, &b, 1);
229 if (rv != EXR_ERR_SUCCESS) return rv;
230 text[namelen] = b;
231 if (b == '\0') break;
232 ++namelen;
233 }
234 *outlen = namelen;
235 if (namelen > maxlen)
236 {
237 text[maxlen - 1] = '\0';
238 return ctxt->print_error (
239 ctxt,
240 EXR_ERR_NAME_TOO_LONG,
241 "Invalid %s encountered: start '%s' (max %d)",
242 type,
243 text,
244 maxlen);
245 }
246 return EXR_ERR_SUCCESS;
247 }
248
249 /**************************************/
250
251 static exr_result_t
extract_attr_chlist(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_chlist_t * attrdata,const char * aname,const char * tname,int32_t attrsz)252 extract_attr_chlist (
253 struct _internal_exr_context* ctxt,
254 struct _internal_exr_seq_scratch* scratch,
255 exr_attr_chlist_t* attrdata,
256 const char* aname,
257 const char* tname,
258 int32_t attrsz)
259 {
260 char chname[256];
261 int32_t chlen;
262 int32_t ptype, xsamp, ysamp;
263 uint8_t flags[4];
264 int32_t maxlen = ctxt->max_name_length;
265 exr_result_t rv;
266
267 rv = check_bad_attrsz (ctxt, scratch, attrsz, 1, aname, tname, &chlen);
268
269 while (rv == EXR_ERR_SUCCESS && attrsz > 0)
270 {
271 chlen = 0;
272 rv = read_text (ctxt, chname, &chlen, maxlen, scratch, aname);
273 if (rv != EXR_ERR_SUCCESS) break;
274 attrsz -= chlen + 1;
275
276 if (chlen == 0) break;
277
278 if (attrsz < 16)
279 {
280 return ctxt->print_error (
281 ctxt,
282 EXR_ERR_ATTR_SIZE_MISMATCH,
283 "Out of data parsing '%s', last channel '%s'",
284 aname,
285 chname);
286 }
287
288 rv = scratch->sequential_read (scratch, &ptype, 4);
289 if (rv != EXR_ERR_SUCCESS) break;
290 rv = scratch->sequential_read (scratch, &flags, 4);
291 if (rv != EXR_ERR_SUCCESS) break;
292 rv = scratch->sequential_read (scratch, &xsamp, 4);
293 if (rv != EXR_ERR_SUCCESS) break;
294 rv = scratch->sequential_read (scratch, &ysamp, 4);
295 if (rv != EXR_ERR_SUCCESS) break;
296
297 attrsz -= 16;
298 ptype = (int32_t) one_to_native32 ((uint32_t) ptype);
299 xsamp = (int32_t) one_to_native32 ((uint32_t) xsamp);
300 ysamp = (int32_t) one_to_native32 ((uint32_t) ysamp);
301
302 rv = exr_attr_chlist_add_with_length (
303 (exr_context_t) ctxt,
304 attrdata,
305 chname,
306 chlen,
307 (exr_pixel_type_t) ptype,
308 flags[0],
309 xsamp,
310 ysamp);
311 }
312 return rv;
313 }
314
315 /**************************************/
316
317 static exr_result_t
extract_attr_uint8(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,uint8_t * attrdata,const char * aname,const char * tname,int32_t attrsz,uint8_t maxval)318 extract_attr_uint8 (
319 struct _internal_exr_context* ctxt,
320 struct _internal_exr_seq_scratch* scratch,
321 uint8_t* attrdata,
322 const char* aname,
323 const char* tname,
324 int32_t attrsz,
325 uint8_t maxval)
326 {
327 if (attrsz != 1)
328 return ctxt->print_error (
329 ctxt,
330 EXR_ERR_ATTR_SIZE_MISMATCH,
331 "Attribute '%s': Invalid size %d (exp '%s' size 1)",
332 aname,
333 attrsz,
334 tname);
335
336 if (scratch->sequential_read (scratch, attrdata, sizeof (uint8_t)))
337 return ctxt->print_error (
338 ctxt, EXR_ERR_READ_IO, "Unable to read '%s' %s data", aname, tname);
339
340 if (*attrdata >= maxval)
341 return ctxt->print_error (
342 ctxt,
343 EXR_ERR_INVALID_ATTR,
344 "Attribute '%s' (type '%s'): Invalid value %d (max allowed %d)",
345 aname,
346 tname,
347 (int) *attrdata,
348 (int) maxval);
349
350 return EXR_ERR_SUCCESS;
351 }
352
353 /**************************************/
354
355 static exr_result_t
extract_attr_64bit(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,void * attrdata,const char * aname,const char * tname,int32_t attrsz,int32_t num)356 extract_attr_64bit (
357 struct _internal_exr_context* ctxt,
358 struct _internal_exr_seq_scratch* scratch,
359 void* attrdata,
360 const char* aname,
361 const char* tname,
362 int32_t attrsz,
363 int32_t num)
364 {
365 exr_result_t rv;
366 if (attrsz != 8 * num)
367 return ctxt->print_error (
368 ctxt,
369 EXR_ERR_ATTR_SIZE_MISMATCH,
370 "Attribute '%s': Invalid size %d (exp '%s' size 8 * %d (%d))",
371 aname,
372 attrsz,
373 tname,
374 num,
375 8 * num);
376
377 rv = scratch->sequential_read (scratch, attrdata, 8 * (uint64_t) num);
378 if (rv != EXR_ERR_SUCCESS)
379 return ctxt->print_error (
380 ctxt, rv, "Unable to read '%s' %s data", aname, tname);
381
382 priv_to_native64 (attrdata, num);
383 return rv;
384 }
385
386 /**************************************/
387
388 static exr_result_t
extract_attr_32bit(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,void * attrdata,const char * aname,const char * tname,int32_t attrsz,int32_t num)389 extract_attr_32bit (
390 struct _internal_exr_context* ctxt,
391 struct _internal_exr_seq_scratch* scratch,
392 void* attrdata,
393 const char* aname,
394 const char* tname,
395 int32_t attrsz,
396 int32_t num)
397 {
398 exr_result_t rv;
399 if (attrsz != 4 * num)
400 return ctxt->print_error (
401 ctxt,
402 EXR_ERR_ATTR_SIZE_MISMATCH,
403 "Attribute '%s': Invalid size %d (exp '%s' size 4 * %d (%d))",
404 aname,
405 attrsz,
406 tname,
407 num,
408 4 * num);
409
410 rv = scratch->sequential_read (scratch, attrdata, 4 * (uint64_t) num);
411 if (rv != EXR_ERR_SUCCESS)
412 return ctxt->print_error (
413 ctxt, rv, "Unable to read '%s' %s data", aname, tname);
414
415 priv_to_native32 (attrdata, num);
416 return rv;
417 }
418
419 /**************************************/
420
421 static exr_result_t
extract_attr_float_vector(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_float_vector_t * attrdata,const char * aname,const char * tname,int32_t attrsz)422 extract_attr_float_vector (
423 struct _internal_exr_context* ctxt,
424 struct _internal_exr_seq_scratch* scratch,
425 exr_attr_float_vector_t* attrdata,
426 const char* aname,
427 const char* tname,
428 int32_t attrsz)
429 {
430 int32_t n = 0;
431 exr_result_t rv = check_bad_attrsz (
432 ctxt, scratch, attrsz, (int) sizeof (float), aname, tname, &n);
433
434 /* in case of duplicate attr name in header (mostly fuzz testing) */
435 exr_attr_float_vector_destroy ((exr_context_t) ctxt, attrdata);
436
437 if (rv == EXR_ERR_SUCCESS && n > 0)
438 {
439 rv = exr_attr_float_vector_init ((exr_context_t) ctxt, attrdata, n);
440 if (rv != EXR_ERR_SUCCESS) return rv;
441
442 rv = scratch->sequential_read (
443 scratch, EXR_CONST_CAST (void*, attrdata->arr), (uint64_t) attrsz);
444 if (rv != EXR_ERR_SUCCESS)
445 {
446 exr_attr_float_vector_destroy ((exr_context_t) ctxt, attrdata);
447 return ctxt->print_error (
448 ctxt,
449 EXR_ERR_READ_IO,
450 "Unable to read '%s' %s data",
451 aname,
452 tname);
453 }
454
455 priv_to_native32 (attrdata, n);
456 }
457
458 return rv;
459 }
460
461 /**************************************/
462
463 static exr_result_t
extract_attr_string(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_string_t * attrdata,const char * aname,const char * tname,int32_t attrsz,char * strptr)464 extract_attr_string (
465 struct _internal_exr_context* ctxt,
466 struct _internal_exr_seq_scratch* scratch,
467 exr_attr_string_t* attrdata,
468 const char* aname,
469 const char* tname,
470 int32_t attrsz,
471 char* strptr)
472 {
473 exr_result_t rv =
474 scratch->sequential_read (scratch, (void*) strptr, (uint64_t) attrsz);
475
476 if (rv != EXR_ERR_SUCCESS)
477 return ctxt->print_error (
478 ctxt, rv, "Unable to read '%s' %s data", aname, tname);
479
480 strptr[attrsz] = '\0';
481
482 return exr_attr_string_init_static_with_length (
483 (exr_context_t) ctxt, attrdata, strptr, attrsz);
484 }
485
486 /**************************************/
487
488 static exr_result_t
extract_attr_string_vector(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_string_vector_t * attrdata,const char * aname,const char * tname,int32_t attrsz)489 extract_attr_string_vector (
490 struct _internal_exr_context* ctxt,
491 struct _internal_exr_seq_scratch* scratch,
492 exr_attr_string_vector_t* attrdata,
493 const char* aname,
494 const char* tname,
495 int32_t attrsz)
496 {
497 exr_result_t rv;
498 int32_t n, nstr, nalloced, nlen, pulled = 0;
499 exr_attr_string_t *nlist, *clist, nil = { 0 };
500
501 rv = check_bad_attrsz (ctxt, scratch, attrsz, 1, aname, tname, &n);
502 if (rv != EXR_ERR_SUCCESS) return rv;
503
504 nstr = 0;
505 nalloced = 0;
506 clist = NULL;
507 while (pulled < attrsz)
508 {
509 nlen = 0;
510 rv = scratch->sequential_read (scratch, &nlen, sizeof (int32_t));
511 if (rv != EXR_ERR_SUCCESS)
512 {
513 rv = ctxt->print_error (
514 ctxt,
515 rv,
516 "Attribute '%s': Unable to read string length",
517 aname);
518 goto extract_string_vector_fail;
519 }
520
521 pulled += sizeof (int32_t);
522 nlen = (int32_t) one_to_native32 ((uint32_t) nlen);
523 if (nlen < 0 || (ctxt->file_size > 0 && nlen > ctxt->file_size))
524 {
525 rv = ctxt->print_error (
526 ctxt,
527 EXR_ERR_INVALID_ATTR,
528 "Attribute '%s': Invalid size (%d) encountered parsing string vector",
529 aname,
530 nlen);
531 goto extract_string_vector_fail;
532 }
533
534 if (nalloced == 0)
535 {
536 clist = ctxt->alloc_fn (4 * sizeof (exr_attr_string_t));
537 if (clist == NULL)
538 {
539 rv = ctxt->standard_error (ctxt, EXR_ERR_OUT_OF_MEMORY);
540 goto extract_string_vector_fail;
541 }
542 nalloced = 4;
543 }
544 if ((nstr + 1) >= nalloced)
545 {
546 nalloced *= 2;
547 nlist = ctxt->alloc_fn (
548 (size_t) (nalloced) * sizeof (exr_attr_string_t));
549 if (nlist == NULL)
550 {
551 rv = ctxt->standard_error (ctxt, EXR_ERR_OUT_OF_MEMORY);
552 goto extract_string_vector_fail;
553 }
554 for (int32_t i = 0; i < nstr; ++i)
555 *(nlist + i) = clist[i];
556 ctxt->free_fn (clist);
557 clist = nlist;
558 }
559 nlist = clist + nstr;
560 *nlist = nil;
561 nstr += 1;
562 rv = exr_attr_string_init ((exr_context_t) ctxt, nlist, nlen);
563 if (rv != EXR_ERR_SUCCESS) goto extract_string_vector_fail;
564
565 rv = scratch->sequential_read (
566 scratch, EXR_CONST_CAST (void*, nlist->str), (uint64_t) nlen);
567 if (rv != EXR_ERR_SUCCESS)
568 {
569 rv = ctxt->print_error (
570 ctxt,
571 rv,
572 "Attribute '%s': Unable to read string of length (%d)",
573 aname,
574 nlen);
575 goto extract_string_vector_fail;
576 }
577 *((EXR_CONST_CAST (char*, nlist->str)) + nlen) = '\0';
578 pulled += nlen;
579 }
580
581 // just in case someone injected a duplicate attribute name into the header
582 exr_attr_string_vector_destroy ((exr_context_t) ctxt, attrdata);
583 attrdata->n_strings = nstr;
584 attrdata->alloc_size = nalloced;
585 attrdata->strings = clist;
586 return EXR_ERR_SUCCESS;
587 extract_string_vector_fail:
588 for (int32_t i = 0; i < nstr; ++i)
589 exr_attr_string_destroy ((exr_context_t) ctxt, clist + i);
590 if (clist) ctxt->free_fn (clist);
591
592 return rv;
593 }
594
595 /**************************************/
596
597 static exr_result_t
extract_attr_tiledesc(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_tiledesc_t * attrdata,const char * aname,const char * tname,int32_t attrsz)598 extract_attr_tiledesc (
599 struct _internal_exr_context* ctxt,
600 struct _internal_exr_seq_scratch* scratch,
601 exr_attr_tiledesc_t* attrdata,
602 const char* aname,
603 const char* tname,
604 int32_t attrsz)
605 {
606 exr_result_t rv;
607 if (attrsz != (int32_t) sizeof (*attrdata))
608 return ctxt->print_error (
609 ctxt,
610 EXR_ERR_ATTR_SIZE_MISMATCH,
611 "Attribute '%s': Invalid size %d (exp '%s' size %d)",
612 aname,
613 attrsz,
614 tname,
615 (int32_t) sizeof (*attrdata));
616
617 rv = scratch->sequential_read (scratch, attrdata, sizeof (*attrdata));
618 if (rv != EXR_ERR_SUCCESS)
619 return ctxt->print_error (
620 ctxt, rv, "Unable to read '%s' %s data", aname, tname);
621
622 attrdata->x_size = one_to_native32 (attrdata->x_size);
623 attrdata->y_size = one_to_native32 (attrdata->y_size);
624
625 if ((int) EXR_GET_TILE_LEVEL_MODE (*attrdata) >= (int) EXR_TILE_LAST_TYPE)
626 return ctxt->print_error (
627 ctxt,
628 EXR_ERR_INVALID_ATTR,
629 "Attribute '%s': Invalid tile level specification encountered: found enum %d",
630 aname,
631 (int) EXR_GET_TILE_LEVEL_MODE (*attrdata));
632
633 if ((int) EXR_GET_TILE_ROUND_MODE (*attrdata) >=
634 (int) EXR_TILE_ROUND_LAST_TYPE)
635 return ctxt->print_error (
636 ctxt,
637 EXR_ERR_INVALID_ATTR,
638 "Attribute '%s': Invalid tile rounding specification encountered: found enum %d",
639 aname,
640 (int) EXR_GET_TILE_ROUND_MODE (*attrdata));
641
642 return rv;
643 }
644
645 /**************************************/
646
647 static exr_result_t
extract_attr_opaque(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_opaquedata_t * attrdata,const char * aname,const char * tname,int32_t attrsz)648 extract_attr_opaque (
649 struct _internal_exr_context* ctxt,
650 struct _internal_exr_seq_scratch* scratch,
651 exr_attr_opaquedata_t* attrdata,
652 const char* aname,
653 const char* tname,
654 int32_t attrsz)
655 {
656 int32_t n;
657 exr_result_t rv;
658
659 rv = check_bad_attrsz (ctxt, scratch, attrsz, 1, aname, tname, &n);
660 if (rv != EXR_ERR_SUCCESS) return rv;
661
662 exr_attr_opaquedata_destroy ((exr_context_t) ctxt, attrdata);
663 rv = exr_attr_opaquedata_init (
664 (exr_context_t) ctxt, attrdata, (uint64_t) attrsz);
665 if (rv != EXR_ERR_SUCCESS) return rv;
666
667 rv = scratch->sequential_read (
668 scratch, (void*) attrdata->packed_data, (uint64_t) attrsz);
669 if (rv != EXR_ERR_SUCCESS)
670 {
671 exr_attr_opaquedata_destroy ((exr_context_t) ctxt, attrdata);
672 return ctxt->print_error (
673 ctxt,
674 EXR_ERR_READ_IO,
675 "Attribute '%s': Unable to read opaque %s data (%d bytes)",
676 aname,
677 tname,
678 attrsz);
679 }
680 return rv;
681 }
682
683 /**************************************/
684
685 static exr_result_t
extract_attr_preview(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch,exr_attr_preview_t * attrdata,const char * aname,const char * tname,int32_t attrsz)686 extract_attr_preview (
687 struct _internal_exr_context* ctxt,
688 struct _internal_exr_seq_scratch* scratch,
689 exr_attr_preview_t* attrdata,
690 const char* aname,
691 const char* tname,
692 int32_t attrsz)
693 {
694 uint64_t bytes;
695 uint32_t sz[2];
696 exr_result_t rv;
697 int64_t fsize = ctxt->file_size;
698
699 /* mostly for fuzzing, but just in case there's a duplicate name */
700 exr_attr_preview_destroy ((exr_context_t) ctxt, attrdata);
701
702 if (attrsz < 8)
703 return ctxt->print_error (
704 ctxt,
705 EXR_ERR_ATTR_SIZE_MISMATCH,
706 "Attribute '%s': Invalid size %d (exp '%s' size >= 8)",
707 aname,
708 attrsz,
709 tname);
710
711 rv = scratch->sequential_read (scratch, sz, sizeof (uint32_t) * 2);
712 if (rv != EXR_ERR_SUCCESS)
713 return ctxt->print_error (
714 ctxt, rv, "Attribute '%s': Unable to read preview sizes", aname);
715
716 sz[0] = one_to_native32 (sz[0]);
717 sz[1] = one_to_native32 (sz[1]);
718 bytes = 4 * sz[0] * sz[1];
719 if ((uint64_t) attrsz != (8 + bytes))
720 return ctxt->print_error (
721 ctxt,
722 EXR_ERR_INVALID_ATTR,
723 "Attribute '%s': Invalid size %d (exp '%s' %u x %u * 4 + sizevals)",
724 aname,
725 attrsz,
726 tname,
727 sz[0],
728 sz[1]);
729
730 if (bytes == 0 || (fsize > 0 && bytes >= (uint64_t) fsize))
731 {
732 return ctxt->print_error (
733 ctxt,
734 EXR_ERR_ATTR_SIZE_MISMATCH,
735 "Attribute '%s', type '%s': Invalid size for preview %u x %u",
736 aname,
737 tname,
738 sz[0],
739 sz[1]);
740 }
741
742 rv = exr_attr_preview_init ((exr_context_t) ctxt, attrdata, sz[0], sz[1]);
743 if (rv != EXR_ERR_SUCCESS) return rv;
744
745 if (bytes > 0)
746 {
747 rv = scratch->sequential_read (
748 scratch, EXR_CONST_CAST (void*, attrdata->rgba), sz[0] * sz[1] * 4);
749 if (rv != EXR_ERR_SUCCESS)
750 {
751 exr_attr_preview_destroy ((exr_context_t) ctxt, attrdata);
752 return ctxt->print_error (
753 ctxt,
754 rv,
755 "Attribute '%s': Unable to read preview data (%d bytes)",
756 aname,
757 attrsz);
758 }
759 }
760
761 return rv;
762 }
763
764 /**************************************/
765
766 static exr_result_t
check_populate_channels(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)767 check_populate_channels (
768 struct _internal_exr_context* ctxt,
769 struct _internal_exr_part* curpart,
770 struct _internal_exr_seq_scratch* scratch,
771 const char* tname,
772 int32_t attrsz)
773 {
774 exr_attr_chlist_t tmpchans = { 0 };
775 exr_result_t rv;
776
777 if (curpart->channels)
778 return ctxt->print_error (
779 ctxt,
780 EXR_ERR_INVALID_ATTR,
781 "Duplicate copy of required attribute 'channels' encountered");
782
783 if (0 != strcmp (tname, "chlist"))
784 return ctxt->print_error (
785 ctxt,
786 EXR_ERR_ATTR_TYPE_MISMATCH,
787 "Required attribute 'channels': Invalid type '%s'",
788 tname);
789
790 rv = extract_attr_chlist (
791 ctxt, scratch, &(tmpchans), EXR_REQ_CHANNELS_STR, tname, attrsz);
792 if (rv != EXR_ERR_SUCCESS)
793 {
794 exr_attr_chlist_destroy ((exr_context_t) ctxt, &(tmpchans));
795 return rv;
796 }
797
798 rv = exr_attr_list_add_static_name (
799 (exr_context_t) ctxt,
800 &(curpart->attributes),
801 EXR_REQ_CHANNELS_STR,
802 EXR_ATTR_CHLIST,
803 0,
804 NULL,
805 &(curpart->channels));
806
807 if (rv != EXR_ERR_SUCCESS)
808 {
809 exr_attr_chlist_destroy ((exr_context_t) ctxt, &tmpchans);
810 return ctxt->print_error (
811 ctxt,
812 rv,
813 "Unable to initialize attribute '%s', type 'chlist'",
814 EXR_REQ_CHANNELS_STR);
815 }
816
817 exr_attr_chlist_destroy ((exr_context_t) ctxt, curpart->channels->chlist);
818 *(curpart->channels->chlist) = tmpchans;
819 return rv;
820 }
821
822 /**************************************/
823
824 static exr_result_t
check_populate_compression(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)825 check_populate_compression (
826 struct _internal_exr_context* ctxt,
827 struct _internal_exr_part* curpart,
828 struct _internal_exr_seq_scratch* scratch,
829 const char* tname,
830 int32_t attrsz)
831 {
832 uint8_t data;
833 exr_result_t rv;
834
835 if (curpart->compression)
836 return ctxt->print_error (
837 ctxt,
838 EXR_ERR_INVALID_ATTR,
839 "Duplicate copy of required attribute '%s' encountered",
840 EXR_REQ_COMP_STR);
841
842 if (0 != strcmp (tname, EXR_REQ_COMP_STR))
843 return ctxt->print_error (
844 ctxt,
845 EXR_ERR_ATTR_TYPE_MISMATCH,
846 "Required attribute '%s': Invalid type '%s'",
847 EXR_REQ_COMP_STR,
848 tname);
849
850 rv = extract_attr_uint8 (
851 ctxt,
852 scratch,
853 &data,
854 EXR_REQ_COMP_STR,
855 tname,
856 attrsz,
857 (uint8_t) EXR_COMPRESSION_LAST_TYPE);
858 if (rv != EXR_ERR_SUCCESS) return rv;
859
860 rv = exr_attr_list_add_static_name (
861 (exr_context_t) ctxt,
862 &(curpart->attributes),
863 EXR_REQ_COMP_STR,
864 EXR_ATTR_COMPRESSION,
865 0,
866 NULL,
867 &(curpart->compression));
868 if (rv != EXR_ERR_SUCCESS)
869 return ctxt->print_error (
870 ctxt,
871 rv,
872 "Unable to initialize attribute '%s', type 'compression'",
873 EXR_REQ_COMP_STR);
874
875 curpart->compression->uc = data;
876 curpart->comp_type = (exr_compression_t) data;
877 return rv;
878 }
879
880 /**************************************/
881
882 static exr_result_t
check_populate_dataWindow(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)883 check_populate_dataWindow (
884 struct _internal_exr_context* ctxt,
885 struct _internal_exr_part* curpart,
886 struct _internal_exr_seq_scratch* scratch,
887 const char* tname,
888 int32_t attrsz)
889 {
890 exr_attr_box2i_t tmpdata = { 0 };
891 exr_result_t rv;
892
893 if (curpart->dataWindow)
894 return ctxt->print_error (
895 ctxt,
896 EXR_ERR_INVALID_ATTR,
897 "Duplicate copy of required attribute '%s' encountered",
898 EXR_REQ_DATA_STR);
899
900 if (0 != strcmp (tname, "box2i"))
901 return ctxt->print_error (
902 ctxt,
903 EXR_ERR_ATTR_TYPE_MISMATCH,
904 "Required attribute '%s': Invalid type '%s'",
905 EXR_REQ_DATA_STR,
906 tname);
907
908 rv = extract_attr_32bit (
909 ctxt, scratch, &(tmpdata), EXR_REQ_DATA_STR, tname, attrsz, 4);
910 if (rv != EXR_ERR_SUCCESS) return rv;
911
912 rv = exr_attr_list_add_static_name (
913 (exr_context_t) ctxt,
914 &(curpart->attributes),
915 EXR_REQ_DATA_STR,
916 EXR_ATTR_BOX2I,
917 0,
918 NULL,
919 &(curpart->dataWindow));
920 if (rv != EXR_ERR_SUCCESS)
921 return ctxt->print_error (
922 ctxt,
923 rv,
924 "Unable to initialize attribute '%s', type 'box2i'",
925 EXR_REQ_DATA_STR);
926
927 *(curpart->dataWindow->box2i) = tmpdata;
928 curpart->data_window = tmpdata;
929 return rv;
930 }
931
932 /**************************************/
933
934 static exr_result_t
check_populate_displayWindow(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)935 check_populate_displayWindow (
936 struct _internal_exr_context* ctxt,
937 struct _internal_exr_part* curpart,
938 struct _internal_exr_seq_scratch* scratch,
939 const char* tname,
940 int32_t attrsz)
941 {
942 exr_attr_box2i_t tmpdata = { 0 };
943 exr_result_t rv;
944
945 if (curpart->displayWindow)
946 return ctxt->print_error (
947 ctxt,
948 EXR_ERR_INVALID_ATTR,
949 "Duplicate copy of required attribute '%s' encountered",
950 EXR_REQ_DISP_STR);
951
952 if (0 != strcmp (tname, "box2i"))
953 return ctxt->print_error (
954 ctxt,
955 EXR_ERR_ATTR_TYPE_MISMATCH,
956 "Required attribute '%s': Invalid type '%s'",
957 EXR_REQ_DISP_STR,
958 tname);
959
960 rv = extract_attr_32bit (
961 ctxt, scratch, &(tmpdata), EXR_REQ_DISP_STR, tname, attrsz, 4);
962 if (rv != EXR_ERR_SUCCESS) return rv;
963
964 rv = exr_attr_list_add_static_name (
965 (exr_context_t) ctxt,
966 &(curpart->attributes),
967 EXR_REQ_DISP_STR,
968 EXR_ATTR_BOX2I,
969 0,
970 NULL,
971 &(curpart->displayWindow));
972 if (rv != EXR_ERR_SUCCESS)
973 return ctxt->print_error (
974 ctxt,
975 rv,
976 "Unable to initialize attribute '%s', type 'box2i'",
977 EXR_REQ_DISP_STR);
978
979 *(curpart->displayWindow->box2i) = tmpdata;
980 curpart->display_window = tmpdata;
981 return rv;
982 }
983
984 /**************************************/
985
986 static exr_result_t
check_populate_lineOrder(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)987 check_populate_lineOrder (
988 struct _internal_exr_context* ctxt,
989 struct _internal_exr_part* curpart,
990 struct _internal_exr_seq_scratch* scratch,
991 const char* tname,
992 int32_t attrsz)
993 {
994 uint8_t data;
995 exr_result_t rv;
996
997 if (curpart->lineOrder)
998 return ctxt->print_error (
999 ctxt,
1000 EXR_ERR_INVALID_ATTR,
1001 "Duplicate copy of required attribute '%s' encountered",
1002 EXR_REQ_LO_STR);
1003
1004 if (0 != strcmp (tname, EXR_REQ_LO_STR))
1005 return ctxt->print_error (
1006 ctxt,
1007 EXR_ERR_ATTR_TYPE_MISMATCH,
1008 "Required attribute '%s': Invalid type '%s'",
1009 EXR_REQ_LO_STR,
1010 tname);
1011
1012 rv = extract_attr_uint8 (
1013 ctxt,
1014 scratch,
1015 &data,
1016 EXR_REQ_LO_STR,
1017 tname,
1018 attrsz,
1019 (uint8_t) EXR_LINEORDER_LAST_TYPE);
1020 if (rv != EXR_ERR_SUCCESS) return rv;
1021
1022 rv = exr_attr_list_add_static_name (
1023 (exr_context_t) ctxt,
1024 &(curpart->attributes),
1025 EXR_REQ_LO_STR,
1026 EXR_ATTR_LINEORDER,
1027 0,
1028 NULL,
1029 &(curpart->lineOrder));
1030 if (rv != EXR_ERR_SUCCESS)
1031 return ctxt->print_error (
1032 ctxt,
1033 rv,
1034 "Unable to initialize attribute '%s', type 'lineOrder'",
1035 EXR_REQ_LO_STR);
1036
1037 curpart->lineOrder->uc = data;
1038 curpart->lineorder = data;
1039 return rv;
1040 }
1041
1042 /**************************************/
1043
1044 static exr_result_t
check_populate_pixelAspectRatio(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1045 check_populate_pixelAspectRatio (
1046 struct _internal_exr_context* ctxt,
1047 struct _internal_exr_part* curpart,
1048 struct _internal_exr_seq_scratch* scratch,
1049 const char* tname,
1050 int32_t attrsz)
1051 {
1052 exr_result_t rv;
1053 union
1054 {
1055 uint32_t ival;
1056 float fval;
1057 } tpun;
1058
1059 if (curpart->pixelAspectRatio)
1060 return ctxt->print_error (
1061 ctxt,
1062 EXR_ERR_INVALID_ATTR,
1063 "Duplicate copy of required attribute '%s' encountered",
1064 EXR_REQ_PAR_STR);
1065
1066 if (0 != strcmp (tname, "float"))
1067 return ctxt->print_error (
1068 ctxt,
1069 EXR_ERR_ATTR_TYPE_MISMATCH,
1070 "Required attribute '%s': Invalid type '%s'",
1071 EXR_REQ_PAR_STR,
1072 tname);
1073
1074 if (attrsz != sizeof (float))
1075 return ctxt->print_error (
1076 ctxt,
1077 EXR_ERR_ATTR_SIZE_MISMATCH,
1078 "Required attribute '%s': Invalid size %d (exp 4)",
1079 EXR_REQ_PAR_STR,
1080 attrsz);
1081
1082 rv = scratch->sequential_read (scratch, &(tpun.ival), sizeof (uint32_t));
1083 if (rv != EXR_ERR_SUCCESS)
1084 return ctxt->print_error (
1085 ctxt,
1086 rv,
1087 "Attribute '%s': Unable to read data (%d bytes)",
1088 EXR_REQ_PAR_STR,
1089 attrsz);
1090
1091 tpun.ival = one_to_native32 (tpun.ival);
1092
1093 rv = exr_attr_list_add_static_name (
1094 (exr_context_t) ctxt,
1095 &(curpart->attributes),
1096 EXR_REQ_PAR_STR,
1097 EXR_ATTR_FLOAT,
1098 0,
1099 NULL,
1100 &(curpart->pixelAspectRatio));
1101 if (rv != EXR_ERR_SUCCESS)
1102 return ctxt->print_error (
1103 ctxt,
1104 rv,
1105 "Unable to initialize attribute '%s', type 'float'",
1106 EXR_REQ_PAR_STR);
1107
1108 curpart->pixelAspectRatio->f = tpun.fval;
1109 return rv;
1110 }
1111
1112 /**************************************/
1113
1114 static exr_result_t
check_populate_screenWindowCenter(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1115 check_populate_screenWindowCenter (
1116 struct _internal_exr_context* ctxt,
1117 struct _internal_exr_part* curpart,
1118 struct _internal_exr_seq_scratch* scratch,
1119 const char* tname,
1120 int32_t attrsz)
1121 {
1122 exr_result_t rv;
1123 exr_attr_v2f_t tmpdata;
1124
1125 if (curpart->screenWindowCenter)
1126 return ctxt->print_error (
1127 ctxt,
1128 EXR_ERR_INVALID_ATTR,
1129 "Duplicate copy of required attribute '%s' encountered",
1130 EXR_REQ_SCR_WC_STR);
1131
1132 if (0 != strcmp (tname, "v2f"))
1133 return ctxt->print_error (
1134 ctxt,
1135 EXR_ERR_ATTR_TYPE_MISMATCH,
1136 "Required attribute '%s': Invalid type '%s'",
1137 EXR_REQ_SCR_WC_STR,
1138 tname);
1139
1140 if (attrsz != sizeof (exr_attr_v2f_t))
1141 return ctxt->print_error (
1142 ctxt,
1143 EXR_ERR_ATTR_SIZE_MISMATCH,
1144 "Required attribute '%s': Invalid size %d (exp %" PRIu64 ")",
1145 EXR_REQ_SCR_WC_STR,
1146 attrsz,
1147 (uint64_t) sizeof (exr_attr_v2f_t));
1148
1149 rv = scratch->sequential_read (scratch, &tmpdata, sizeof (exr_attr_v2f_t));
1150 if (rv != EXR_ERR_SUCCESS)
1151 return ctxt->print_error (
1152 ctxt,
1153 rv,
1154 "Attribute '%s': Unable to read data (%d bytes)",
1155 EXR_REQ_SCR_WC_STR,
1156 attrsz);
1157
1158 priv_to_native32 (&tmpdata, 2);
1159
1160 rv = exr_attr_list_add_static_name (
1161 (exr_context_t) ctxt,
1162 &(curpart->attributes),
1163 EXR_REQ_SCR_WC_STR,
1164 EXR_ATTR_V2F,
1165 0,
1166 NULL,
1167 &(curpart->screenWindowCenter));
1168 if (rv != EXR_ERR_SUCCESS)
1169 return ctxt->print_error (
1170 ctxt,
1171 rv,
1172 "Unable to initialize attribute '%s', type 'v2f'",
1173 EXR_REQ_SCR_WC_STR);
1174
1175 *(curpart->screenWindowCenter->v2f) = tmpdata;
1176 return rv;
1177 }
1178
1179 /**************************************/
1180
1181 static exr_result_t
check_populate_screenWindowWidth(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1182 check_populate_screenWindowWidth (
1183 struct _internal_exr_context* ctxt,
1184 struct _internal_exr_part* curpart,
1185 struct _internal_exr_seq_scratch* scratch,
1186 const char* tname,
1187 int32_t attrsz)
1188 {
1189 exr_result_t rv;
1190 union
1191 {
1192 uint32_t ival;
1193 float fval;
1194 } tpun;
1195
1196 if (curpart->screenWindowWidth)
1197 return ctxt->print_error (
1198 ctxt,
1199 EXR_ERR_INVALID_ATTR,
1200 "Duplicate copy of required attribute '%s' encountered",
1201 EXR_REQ_SCR_WW_STR);
1202
1203 if (0 != strcmp (tname, "float"))
1204 return ctxt->print_error (
1205 ctxt,
1206 EXR_ERR_ATTR_TYPE_MISMATCH,
1207 "Required attribute '%s': Invalid type '%s'",
1208 EXR_REQ_SCR_WW_STR,
1209 tname);
1210
1211 if (attrsz != sizeof (float))
1212 return ctxt->print_error (
1213 ctxt,
1214 EXR_ERR_ATTR_SIZE_MISMATCH,
1215 "Required attribute '%s': Invalid size %d (exp 4)",
1216 EXR_REQ_SCR_WW_STR,
1217 attrsz);
1218
1219 rv = scratch->sequential_read (scratch, &(tpun.ival), sizeof (uint32_t));
1220 if (rv != EXR_ERR_SUCCESS)
1221 return ctxt->print_error (
1222 ctxt,
1223 rv,
1224 "Attribute '%s': Unable to read data (%d bytes)",
1225 EXR_REQ_SCR_WW_STR,
1226 attrsz);
1227
1228 tpun.ival = one_to_native32 (tpun.ival);
1229
1230 rv = exr_attr_list_add_static_name (
1231 (exr_context_t) ctxt,
1232 &(curpart->attributes),
1233 EXR_REQ_SCR_WW_STR,
1234 EXR_ATTR_FLOAT,
1235 0,
1236 NULL,
1237 &(curpart->screenWindowWidth));
1238 if (rv != EXR_ERR_SUCCESS)
1239 return ctxt->print_error (
1240 ctxt,
1241 rv,
1242 "Unable to initialize attribute '%s', type 'float'",
1243 EXR_REQ_SCR_WW_STR);
1244
1245 curpart->screenWindowWidth->f = tpun.fval;
1246 return rv;
1247 }
1248
1249 /**************************************/
1250
1251 static exr_result_t
check_populate_tiles(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1252 check_populate_tiles (
1253 struct _internal_exr_context* ctxt,
1254 struct _internal_exr_part* curpart,
1255 struct _internal_exr_seq_scratch* scratch,
1256 const char* tname,
1257 int32_t attrsz)
1258 {
1259 exr_result_t rv;
1260 exr_attr_tiledesc_t tmpdata = { 0 };
1261
1262 if (curpart->tiles)
1263 return ctxt->print_error (
1264 ctxt,
1265 EXR_ERR_INVALID_ATTR,
1266 "Duplicate copy of required attribute 'tiles' encountered");
1267
1268 if (0 != strcmp (tname, "tiledesc"))
1269 return ctxt->print_error (
1270 ctxt,
1271 EXR_ERR_ATTR_TYPE_MISMATCH,
1272 "Required attribute 'tiles': Invalid type '%s'",
1273 tname);
1274
1275 if (attrsz != sizeof (exr_attr_tiledesc_t))
1276 return ctxt->print_error (
1277 ctxt,
1278 EXR_ERR_ATTR_TYPE_MISMATCH,
1279 "Required attribute 'tiles': Invalid size %d (exp %" PRIu64 ")",
1280 attrsz,
1281 (uint64_t) sizeof (exr_attr_tiledesc_t));
1282
1283 rv = scratch->sequential_read (scratch, &tmpdata, sizeof (tmpdata));
1284 if (rv != EXR_ERR_SUCCESS)
1285 return ctxt->report_error (ctxt, rv, "Unable to read 'tiles' data");
1286
1287 tmpdata.x_size = one_to_native32 (tmpdata.x_size);
1288 tmpdata.y_size = one_to_native32 (tmpdata.y_size);
1289
1290 rv = exr_attr_list_add_static_name (
1291 (exr_context_t) ctxt,
1292 &(curpart->attributes),
1293 EXR_REQ_TILES_STR,
1294 EXR_ATTR_TILEDESC,
1295 0,
1296 NULL,
1297 &(curpart->tiles));
1298 if (rv != EXR_ERR_SUCCESS)
1299 return ctxt->print_error (
1300 ctxt,
1301 rv,
1302 "Unable to initialize attribute '%s', type 'tiledesc'",
1303 EXR_REQ_TILES_STR);
1304
1305 *(curpart->tiles->tiledesc) = tmpdata;
1306 return rv;
1307 }
1308
1309 /**************************************/
1310
1311 static exr_result_t
check_populate_name(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1312 check_populate_name (
1313 struct _internal_exr_context* ctxt,
1314 struct _internal_exr_part* curpart,
1315 struct _internal_exr_seq_scratch* scratch,
1316 const char* tname,
1317 int32_t attrsz)
1318 {
1319 exr_result_t rv;
1320 uint8_t* outstr;
1321 int32_t n;
1322
1323 rv = check_bad_attrsz (
1324 ctxt, scratch, attrsz, 1, EXR_REQ_NAME_STR, tname, &n);
1325 if (rv != EXR_ERR_SUCCESS) return rv;
1326
1327 if (curpart->name)
1328 return ctxt->print_error (
1329 ctxt,
1330 EXR_ERR_INVALID_ATTR,
1331 "Duplicate copy of required attribute 'name' encountered");
1332
1333 if (0 != strcmp (tname, "string"))
1334 return ctxt->print_error (
1335 ctxt,
1336 EXR_ERR_ATTR_TYPE_MISMATCH,
1337 "attribute 'name': Invalid type '%s'",
1338 tname);
1339
1340 rv = exr_attr_list_add_static_name (
1341 (exr_context_t) ctxt,
1342 &(curpart->attributes),
1343 EXR_REQ_NAME_STR,
1344 EXR_ATTR_STRING,
1345 attrsz + 1,
1346 &outstr,
1347 &(curpart->name));
1348 if (rv != EXR_ERR_SUCCESS)
1349 {
1350 return ctxt->print_error (
1351 ctxt,
1352 rv,
1353 "Unable to initialize attribute '%s', type 'string'",
1354 EXR_REQ_NAME_STR);
1355 }
1356
1357 rv = scratch->sequential_read (scratch, outstr, (uint64_t) attrsz);
1358 if (rv != EXR_ERR_SUCCESS)
1359 {
1360 exr_attr_list_remove (
1361 (exr_context_t) ctxt, &(curpart->attributes), curpart->name);
1362 curpart->name = NULL;
1363 return ctxt->report_error (ctxt, rv, "Unable to read 'name' data");
1364 }
1365 outstr[attrsz] = '\0';
1366
1367 rv = exr_attr_string_init_static_with_length (
1368 (exr_context_t) ctxt,
1369 curpart->name->string,
1370 (const char*) outstr,
1371 attrsz);
1372 if (rv != EXR_ERR_SUCCESS)
1373 {
1374 exr_attr_list_remove (
1375 (exr_context_t) ctxt, &(curpart->attributes), curpart->name);
1376 curpart->name = NULL;
1377 return ctxt->report_error (ctxt, rv, "Unable to read 'name' data");
1378 }
1379
1380 return rv;
1381 }
1382
1383 /**************************************/
1384
1385 static exr_result_t
check_populate_type(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1386 check_populate_type (
1387 struct _internal_exr_context* ctxt,
1388 struct _internal_exr_part* curpart,
1389 struct _internal_exr_seq_scratch* scratch,
1390 const char* tname,
1391 int32_t attrsz)
1392 {
1393 exr_result_t rv;
1394 uint8_t* outstr;
1395 int32_t n;
1396
1397 rv = check_bad_attrsz (
1398 ctxt, scratch, attrsz, 1, EXR_REQ_TYPE_STR, tname, &n);
1399 if (rv != EXR_ERR_SUCCESS) return rv;
1400
1401 if (curpart->type)
1402 return ctxt->print_error (
1403 ctxt,
1404 EXR_ERR_INVALID_ATTR,
1405 "Duplicate copy of required attribute 'type' encountered");
1406
1407 if (0 != strcmp (tname, "string"))
1408 return ctxt->print_error (
1409 ctxt,
1410 EXR_ERR_ATTR_TYPE_MISMATCH,
1411 "Required attribute 'type': Invalid type '%s'",
1412 tname);
1413
1414 rv = exr_attr_list_add_static_name (
1415 (exr_context_t) ctxt,
1416 &(curpart->attributes),
1417 EXR_REQ_TYPE_STR,
1418 EXR_ATTR_STRING,
1419 attrsz + 1,
1420 &outstr,
1421 &(curpart->type));
1422 if (rv != EXR_ERR_SUCCESS)
1423 {
1424 return ctxt->print_error (
1425 ctxt,
1426 rv,
1427 "Unable to initialize attribute '%s', type 'string'",
1428 EXR_REQ_TYPE_STR);
1429 }
1430
1431 rv = scratch->sequential_read (scratch, outstr, (uint64_t) attrsz);
1432 if (rv != EXR_ERR_SUCCESS)
1433 {
1434 exr_attr_list_remove (
1435 (exr_context_t) ctxt, &(curpart->attributes), curpart->type);
1436 curpart->type = NULL;
1437 return ctxt->report_error (ctxt, rv, "Unable to read 'name' data");
1438 }
1439 outstr[attrsz] = '\0';
1440
1441 rv = exr_attr_string_init_static_with_length (
1442 (exr_context_t) ctxt,
1443 curpart->type->string,
1444 (const char*) outstr,
1445 attrsz);
1446 if (rv != EXR_ERR_SUCCESS)
1447 {
1448 exr_attr_list_remove (
1449 (exr_context_t) ctxt, &(curpart->attributes), curpart->type);
1450 curpart->type = NULL;
1451 return ctxt->report_error (ctxt, rv, "Unable to read 'name' data");
1452 }
1453
1454 if (strcmp ((const char*) outstr, "scanlineimage") == 0)
1455 curpart->storage_mode = EXR_STORAGE_SCANLINE;
1456 else if (strcmp ((const char*) outstr, "tiledimage") == 0)
1457 curpart->storage_mode = EXR_STORAGE_TILED;
1458 else if (strcmp ((const char*) outstr, "deepscanline") == 0)
1459 curpart->storage_mode = EXR_STORAGE_DEEP_SCANLINE;
1460 else if (strcmp ((const char*) outstr, "deeptile") == 0)
1461 curpart->storage_mode = EXR_STORAGE_DEEP_TILED;
1462 else
1463 {
1464 rv = ctxt->print_error (
1465 ctxt,
1466 EXR_ERR_INVALID_ATTR,
1467 "attribute 'type': Invalid type string '%s'",
1468 outstr);
1469 exr_attr_list_remove (
1470 (exr_context_t) ctxt, &(curpart->attributes), curpart->type);
1471 curpart->type = NULL;
1472 }
1473
1474 return rv;
1475 }
1476
1477 /**************************************/
1478
1479 static exr_result_t
check_populate_version(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1480 check_populate_version (
1481 struct _internal_exr_context* ctxt,
1482 struct _internal_exr_part* curpart,
1483 struct _internal_exr_seq_scratch* scratch,
1484 const char* tname,
1485 int32_t attrsz)
1486 {
1487 exr_result_t rv;
1488
1489 if (curpart->version)
1490 return ctxt->print_error (
1491 ctxt,
1492 EXR_ERR_INVALID_ATTR,
1493 "Duplicate copy of required attribute 'version' encountered");
1494
1495 if (0 != strcmp (tname, "int"))
1496 return ctxt->print_error (
1497 ctxt,
1498 EXR_ERR_ATTR_TYPE_MISMATCH,
1499 "attribute 'version': Invalid type '%s'",
1500 tname);
1501
1502 if (attrsz != sizeof (int32_t))
1503 return ctxt->print_error (
1504 ctxt,
1505 EXR_ERR_INVALID_ATTR,
1506 "attribute 'version': Invalid size %d (exp 4)",
1507 attrsz);
1508
1509 rv = scratch->sequential_read (scratch, &attrsz, sizeof (int32_t));
1510 if (rv != EXR_ERR_SUCCESS)
1511 return ctxt->report_error (ctxt, rv, "Unable to read version data");
1512
1513 attrsz = (int32_t) one_to_native32 ((uint32_t) attrsz);
1514 if (attrsz != 1)
1515 return ctxt->print_error (
1516 ctxt, EXR_ERR_INVALID_ATTR, "Invalid version %d: expect 1", attrsz);
1517
1518 rv = exr_attr_list_add_static_name (
1519 (exr_context_t) ctxt,
1520 &(curpart->attributes),
1521 EXR_REQ_VERSION_STR,
1522 EXR_ATTR_INT,
1523 0,
1524 NULL,
1525 &(curpart->version));
1526 if (rv != EXR_ERR_SUCCESS)
1527 return ctxt->print_error (
1528 ctxt,
1529 rv,
1530 "Unable to initialize attribute '%s', type 'int'",
1531 EXR_REQ_VERSION_STR);
1532 curpart->version->i = attrsz;
1533 return rv;
1534 }
1535
1536 /**************************************/
1537
1538 static exr_result_t
check_populate_chunk_count(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * tname,int32_t attrsz)1539 check_populate_chunk_count (
1540 struct _internal_exr_context* ctxt,
1541 struct _internal_exr_part* curpart,
1542 struct _internal_exr_seq_scratch* scratch,
1543 const char* tname,
1544 int32_t attrsz)
1545 {
1546 exr_result_t rv;
1547
1548 if (curpart->chunkCount)
1549 return ctxt->print_error (
1550 ctxt,
1551 EXR_ERR_INVALID_ATTR,
1552 "Duplicate copy of required attribute 'chunkCount' encountered");
1553
1554 if (0 != strcmp (tname, "int"))
1555 return ctxt->print_error (
1556 ctxt,
1557 EXR_ERR_ATTR_TYPE_MISMATCH,
1558 "attribute 'chunkCount': Invalid type '%s'",
1559 tname);
1560
1561 if (attrsz != sizeof (int32_t))
1562 return ctxt->print_error (
1563 ctxt,
1564 EXR_ERR_INVALID_ATTR,
1565 "Required attribute 'chunkCount': Invalid size %d (exp 4)",
1566 attrsz);
1567
1568 rv = scratch->sequential_read (scratch, &attrsz, sizeof (int32_t));
1569 if (rv != EXR_ERR_SUCCESS)
1570 return ctxt->report_error (ctxt, rv, "Unable to read chunkCount data");
1571
1572 rv = exr_attr_list_add_static_name (
1573 (exr_context_t) ctxt,
1574 &(curpart->attributes),
1575 EXR_REQ_CHUNK_COUNT_STR,
1576 EXR_ATTR_INT,
1577 0,
1578 NULL,
1579 &(curpart->chunkCount));
1580 if (rv != EXR_ERR_SUCCESS)
1581 return ctxt->print_error (
1582 ctxt,
1583 rv,
1584 "Unable to initialize attribute '%s', type 'int'",
1585 EXR_REQ_CHUNK_COUNT_STR);
1586
1587 attrsz = (int32_t) one_to_native32 ((uint32_t) attrsz);
1588 curpart->chunkCount->i = attrsz;
1589 curpart->chunk_count = attrsz;
1590 return rv;
1591 }
1592
1593 /**************************************/
1594
1595 static exr_result_t
check_req_attr(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,struct _internal_exr_seq_scratch * scratch,const char * aname,const char * tname,int32_t attrsz)1596 check_req_attr (
1597 struct _internal_exr_context* ctxt,
1598 struct _internal_exr_part* curpart,
1599 struct _internal_exr_seq_scratch* scratch,
1600 const char* aname,
1601 const char* tname,
1602 int32_t attrsz)
1603 {
1604 switch (aname[0])
1605 {
1606 case 'c':
1607 if (0 == strcmp (aname, EXR_REQ_CHANNELS_STR))
1608 return check_populate_channels (
1609 ctxt, curpart, scratch, tname, attrsz);
1610 if (0 == strcmp (aname, EXR_REQ_COMP_STR))
1611 return check_populate_compression (
1612 ctxt, curpart, scratch, tname, attrsz);
1613 if (0 == strcmp (aname, EXR_REQ_CHUNK_COUNT_STR))
1614 return check_populate_chunk_count (
1615 ctxt, curpart, scratch, tname, attrsz);
1616 break;
1617 case 'd':
1618 if (0 == strcmp (aname, EXR_REQ_DATA_STR))
1619 return check_populate_dataWindow (
1620 ctxt, curpart, scratch, tname, attrsz);
1621 if (0 == strcmp (aname, EXR_REQ_DISP_STR))
1622 return check_populate_displayWindow (
1623 ctxt, curpart, scratch, tname, attrsz);
1624 break;
1625 case 'l':
1626 if (0 == strcmp (aname, EXR_REQ_LO_STR))
1627 return check_populate_lineOrder (
1628 ctxt, curpart, scratch, tname, attrsz);
1629 break;
1630 case 'n':
1631 if (0 == strcmp (aname, EXR_REQ_NAME_STR))
1632 return check_populate_name (
1633 ctxt, curpart, scratch, tname, attrsz);
1634 break;
1635 case 'p':
1636 if (0 == strcmp (aname, EXR_REQ_PAR_STR))
1637 return check_populate_pixelAspectRatio (
1638 ctxt, curpart, scratch, tname, attrsz);
1639 break;
1640 case 's':
1641 if (0 == strcmp (aname, EXR_REQ_SCR_WC_STR))
1642 return check_populate_screenWindowCenter (
1643 ctxt, curpart, scratch, tname, attrsz);
1644 if (0 == strcmp (aname, EXR_REQ_SCR_WW_STR))
1645 return check_populate_screenWindowWidth (
1646 ctxt, curpart, scratch, tname, attrsz);
1647 break;
1648 case 't':
1649 if (0 == strcmp (aname, EXR_REQ_TILES_STR))
1650 return check_populate_tiles (
1651 ctxt, curpart, scratch, tname, attrsz);
1652 if (0 == strcmp (aname, EXR_REQ_TYPE_STR))
1653 return check_populate_type (
1654 ctxt, curpart, scratch, tname, attrsz);
1655 break;
1656 case 'v':
1657 if (0 == strcmp (aname, EXR_REQ_VERSION_STR))
1658 return check_populate_version (
1659 ctxt, curpart, scratch, tname, attrsz);
1660 break;
1661 default: break;
1662 }
1663
1664 return EXR_ERR_UNKNOWN;
1665 }
1666
1667 /**************************************/
1668
1669 static exr_result_t
pull_attr(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,uint8_t init_byte,struct _internal_exr_seq_scratch * scratch)1670 pull_attr (
1671 struct _internal_exr_context* ctxt,
1672 struct _internal_exr_part* curpart,
1673 uint8_t init_byte,
1674 struct _internal_exr_seq_scratch* scratch)
1675 {
1676 char name[256], type[256];
1677 exr_result_t rv;
1678 int32_t namelen = 0, typelen = 0;
1679 int32_t attrsz = 0;
1680 exr_attribute_t* nattr = NULL;
1681 uint8_t* strptr = NULL;
1682 const int32_t maxlen = ctxt->max_name_length;
1683
1684 name[0] = (char) init_byte;
1685 namelen = 1;
1686
1687 rv = read_text (ctxt, name, &namelen, maxlen, scratch, "attribute name");
1688 if (rv != EXR_ERR_SUCCESS) return rv;
1689 rv = read_text (ctxt, type, &typelen, maxlen, scratch, "attribute type");
1690 if (rv != EXR_ERR_SUCCESS) return rv;
1691
1692 if (namelen == 0)
1693 return ctxt->report_error (
1694 ctxt,
1695 EXR_ERR_FILE_BAD_HEADER,
1696 "Invalid empty string encountered parsing attribute name");
1697
1698 if (typelen == 0)
1699 return ctxt->print_error (
1700 ctxt,
1701 EXR_ERR_FILE_BAD_HEADER,
1702 "Invalid empty string encountered parsing attribute type for attribute '%s'",
1703 name);
1704
1705 rv = scratch->sequential_read (scratch, &attrsz, sizeof (int32_t));
1706 if (rv != EXR_ERR_SUCCESS)
1707 return ctxt->print_error (
1708 ctxt,
1709 rv,
1710 "Unable to read attribute size for attribute '%s', type '%s'",
1711 name,
1712 type);
1713 attrsz = (int32_t) one_to_native32 ((uint32_t) attrsz);
1714
1715 rv = check_req_attr (ctxt, curpart, scratch, name, type, attrsz);
1716 if (rv != EXR_ERR_UNKNOWN) return rv;
1717
1718 /* not a required attr, just a normal one, optimize for string type to avoid double malloc */
1719 if (!strcmp (type, "string"))
1720 {
1721 int32_t n;
1722 rv = check_bad_attrsz (ctxt, scratch, attrsz, 1, name, type, &n);
1723 if (rv != EXR_ERR_SUCCESS) return rv;
1724
1725 rv = exr_attr_list_add (
1726 (exr_context_t) ctxt,
1727 &(curpart->attributes),
1728 name,
1729 EXR_ATTR_STRING,
1730 n + 1,
1731 &strptr,
1732 &nattr);
1733 }
1734 else
1735 {
1736 rv = exr_attr_list_add_by_type (
1737 (exr_context_t) ctxt,
1738 &(curpart->attributes),
1739 name,
1740 type,
1741 0,
1742 NULL,
1743 &nattr);
1744 }
1745
1746 if (rv != EXR_ERR_SUCCESS)
1747 return ctxt->print_error (
1748 ctxt,
1749 rv,
1750 "Unable to initialize attribute '%s', type '%s'",
1751 name,
1752 type);
1753
1754 switch (nattr->type)
1755 {
1756 case EXR_ATTR_BOX2I:
1757 rv = extract_attr_32bit (
1758 ctxt, scratch, nattr->box2i, name, type, attrsz, 4);
1759 break;
1760 case EXR_ATTR_BOX2F:
1761 rv = extract_attr_32bit (
1762 ctxt, scratch, nattr->box2f, name, type, attrsz, 4);
1763 break;
1764 case EXR_ATTR_CHLIST:
1765 rv = extract_attr_chlist (
1766 ctxt, scratch, nattr->chlist, name, type, attrsz);
1767 break;
1768 case EXR_ATTR_CHROMATICITIES:
1769 rv = extract_attr_32bit (
1770 ctxt, scratch, nattr->chromaticities, name, type, attrsz, 8);
1771 break;
1772 case EXR_ATTR_COMPRESSION:
1773 rv = extract_attr_uint8 (
1774 ctxt,
1775 scratch,
1776 &(nattr->uc),
1777 name,
1778 type,
1779 attrsz,
1780 (uint8_t) EXR_COMPRESSION_LAST_TYPE);
1781 break;
1782 case EXR_ATTR_ENVMAP:
1783 rv = extract_attr_uint8 (
1784 ctxt,
1785 scratch,
1786 &(nattr->uc),
1787 name,
1788 type,
1789 attrsz,
1790 (uint8_t) EXR_ENVMAP_LAST_TYPE);
1791 break;
1792 case EXR_ATTR_LINEORDER:
1793 rv = extract_attr_uint8 (
1794 ctxt,
1795 scratch,
1796 &(nattr->uc),
1797 name,
1798 type,
1799 attrsz,
1800 (uint8_t) EXR_LINEORDER_LAST_TYPE);
1801 break;
1802 case EXR_ATTR_DOUBLE:
1803 rv = extract_attr_64bit (
1804 ctxt, scratch, &(nattr->d), name, type, attrsz, 1);
1805 break;
1806 case EXR_ATTR_FLOAT:
1807 rv = extract_attr_32bit (
1808 ctxt, scratch, &(nattr->f), name, type, attrsz, 1);
1809 break;
1810 case EXR_ATTR_FLOAT_VECTOR:
1811 rv = extract_attr_float_vector (
1812 ctxt, scratch, nattr->floatvector, name, type, attrsz);
1813 break;
1814 case EXR_ATTR_INT:
1815 rv = extract_attr_32bit (
1816 ctxt, scratch, &(nattr->i), name, type, attrsz, 1);
1817 break;
1818 case EXR_ATTR_KEYCODE:
1819 rv = extract_attr_32bit (
1820 ctxt, scratch, nattr->keycode, name, type, attrsz, 7);
1821 break;
1822 case EXR_ATTR_M33F:
1823 rv = extract_attr_32bit (
1824 ctxt, scratch, nattr->m33f->m, name, type, attrsz, 9);
1825 break;
1826 case EXR_ATTR_M33D:
1827 rv = extract_attr_64bit (
1828 ctxt, scratch, nattr->m33d->m, name, type, attrsz, 9);
1829 break;
1830 case EXR_ATTR_M44F:
1831 rv = extract_attr_32bit (
1832 ctxt, scratch, nattr->m44f->m, name, type, attrsz, 16);
1833 break;
1834 case EXR_ATTR_M44D:
1835 rv = extract_attr_64bit (
1836 ctxt, scratch, nattr->m44d->m, name, type, attrsz, 16);
1837 break;
1838 case EXR_ATTR_PREVIEW:
1839 rv = extract_attr_preview (
1840 ctxt, scratch, nattr->preview, name, type, attrsz);
1841 break;
1842 case EXR_ATTR_RATIONAL:
1843 rv = extract_attr_32bit (
1844 ctxt, scratch, nattr->rational, name, type, attrsz, 2);
1845 break;
1846 case EXR_ATTR_STRING:
1847 rv = extract_attr_string (
1848 ctxt,
1849 scratch,
1850 nattr->string,
1851 name,
1852 type,
1853 attrsz,
1854 (char*) strptr);
1855 break;
1856 case EXR_ATTR_STRING_VECTOR:
1857 rv = extract_attr_string_vector (
1858 ctxt, scratch, nattr->stringvector, name, type, attrsz);
1859 break;
1860 case EXR_ATTR_TILEDESC:
1861 rv = extract_attr_tiledesc (
1862 ctxt, scratch, nattr->tiledesc, name, type, attrsz);
1863 break;
1864 case EXR_ATTR_TIMECODE:
1865 rv = extract_attr_32bit (
1866 ctxt, scratch, nattr->timecode, name, type, attrsz, 2);
1867 break;
1868 case EXR_ATTR_V2I:
1869 rv = extract_attr_32bit (
1870 ctxt, scratch, nattr->v2i->arr, name, type, attrsz, 2);
1871 break;
1872 case EXR_ATTR_V2F:
1873 rv = extract_attr_32bit (
1874 ctxt, scratch, nattr->v2f->arr, name, type, attrsz, 2);
1875 break;
1876 case EXR_ATTR_V2D:
1877 rv = extract_attr_64bit (
1878 ctxt, scratch, nattr->v2d->arr, name, type, attrsz, 2);
1879 break;
1880 case EXR_ATTR_V3I:
1881 rv = extract_attr_32bit (
1882 ctxt, scratch, nattr->v3i->arr, name, type, attrsz, 3);
1883 break;
1884 case EXR_ATTR_V3F:
1885 rv = extract_attr_32bit (
1886 ctxt, scratch, nattr->v3f->arr, name, type, attrsz, 3);
1887 break;
1888 case EXR_ATTR_V3D:
1889 rv = extract_attr_64bit (
1890 ctxt, scratch, nattr->v3d->arr, name, type, attrsz, 3);
1891 break;
1892 case EXR_ATTR_OPAQUE:
1893 rv = extract_attr_opaque (
1894 ctxt, scratch, nattr->opaque, name, type, attrsz);
1895 break;
1896 case EXR_ATTR_UNKNOWN:
1897 case EXR_ATTR_LAST_KNOWN_TYPE:
1898 default:
1899 rv = ctxt->print_error (
1900 ctxt,
1901 EXR_ERR_INVALID_ARGUMENT,
1902 "Invalid type '%s' for attribute '%s'",
1903 type,
1904 name);
1905 break;
1906 }
1907 if (rv != EXR_ERR_SUCCESS)
1908 {
1909 exr_attr_list_remove (
1910 (exr_context_t) ctxt, &(curpart->attributes), nattr);
1911 }
1912
1913 return rv;
1914 }
1915
1916 /**************************************/
1917
1918 /* floor( log(x) / log(2) ) */
1919 static int32_t
floor_log2(int64_t x)1920 floor_log2 (int64_t x)
1921 {
1922 int32_t y = 0;
1923 while (x > 1)
1924 {
1925 y += 1;
1926 x >>= 1;
1927 }
1928 return y;
1929 }
1930
1931 /**************************************/
1932
1933 /* ceil( log(x) / log(2) ) */
1934 static int32_t
ceil_log2(int64_t x)1935 ceil_log2 (int64_t x)
1936 {
1937 int32_t y = 0, r = 0;
1938 while (x > 1)
1939 {
1940 if (x & 1) r = 1;
1941 y += 1;
1942 x >>= 1;
1943 }
1944 return y + r;
1945 }
1946
1947 /**************************************/
1948
1949 static int64_t
calc_level_size(int64_t mind,int64_t maxd,int level,exr_tile_round_mode_t rounding)1950 calc_level_size (
1951 int64_t mind, int64_t maxd, int level, exr_tile_round_mode_t rounding)
1952 {
1953 int64_t dsize = (int64_t) maxd - (int64_t) mind + 1;
1954 int64_t b = ((int64_t) 1) << level;
1955 int64_t retsize = dsize / b;
1956
1957 if (rounding == EXR_TILE_ROUND_UP && retsize * b < dsize) retsize += 1;
1958
1959 if (retsize < 1) retsize = 1;
1960 return retsize;
1961 }
1962
1963 /**************************************/
1964
1965 exr_result_t
internal_exr_compute_tile_information(struct _internal_exr_context * ctxt,struct _internal_exr_part * curpart,int rebuild)1966 internal_exr_compute_tile_information (
1967 struct _internal_exr_context* ctxt,
1968 struct _internal_exr_part* curpart,
1969 int rebuild)
1970 {
1971 exr_result_t rv = EXR_ERR_SUCCESS;
1972 if (curpart->storage_mode == EXR_STORAGE_SCANLINE ||
1973 curpart->storage_mode == EXR_STORAGE_DEEP_SCANLINE)
1974 return EXR_ERR_SUCCESS;
1975
1976 if (rebuild && (!curpart->dataWindow || !curpart->tiles))
1977 return EXR_ERR_SUCCESS;
1978
1979 if (!curpart->tiles)
1980 return ctxt->standard_error (ctxt, EXR_ERR_MISSING_REQ_ATTR);
1981
1982 if (rebuild)
1983 {
1984 if (curpart->tile_level_tile_count_x)
1985 {
1986 ctxt->free_fn (curpart->tile_level_tile_count_x);
1987 curpart->tile_level_tile_count_x = NULL;
1988 }
1989 }
1990
1991 if (curpart->tile_level_tile_count_x == NULL)
1992 {
1993 const exr_attr_box2i_t dw = curpart->data_window;
1994 const exr_attr_tiledesc_t* tiledesc = curpart->tiles->tiledesc;
1995 int64_t w, h;
1996 int32_t numX, numY;
1997 int32_t* levcntX = NULL;
1998 int32_t* levcntY = NULL;
1999 int32_t* levszX = NULL;
2000 int32_t* levszY = NULL;
2001
2002 w = ((int64_t) dw.max.x) - ((int64_t) dw.min.x) + 1;
2003 h = ((int64_t) dw.max.y) - ((int64_t) dw.min.y) + 1;
2004
2005 if (tiledesc->x_size == 0 || tiledesc->y_size == 0)
2006 return ctxt->standard_error (ctxt, EXR_ERR_INVALID_ATTR);
2007 switch (EXR_GET_TILE_LEVEL_MODE ((*tiledesc)))
2008 {
2009 case EXR_TILE_ONE_LEVEL: numX = numY = 1; break;
2010 case EXR_TILE_MIPMAP_LEVELS:
2011 if (EXR_GET_TILE_ROUND_MODE ((*tiledesc)) ==
2012 EXR_TILE_ROUND_DOWN)
2013 {
2014 numX = floor_log2 (w > h ? w : h) + 1;
2015 numY = numX;
2016 }
2017 else
2018 {
2019 numX = ceil_log2 (w > h ? w : h) + 1;
2020 numY = numX;
2021 }
2022 break;
2023 case EXR_TILE_RIPMAP_LEVELS:
2024 if (EXR_GET_TILE_ROUND_MODE ((*tiledesc)) ==
2025 EXR_TILE_ROUND_DOWN)
2026 {
2027 numX = floor_log2 (w) + 1;
2028 numY = floor_log2 (h) + 1;
2029 }
2030 else
2031 {
2032 numX = ceil_log2 (w) + 1;
2033 numY = ceil_log2 (h) + 1;
2034 }
2035 break;
2036 case EXR_TILE_LAST_TYPE:
2037 default:
2038 return ctxt->standard_error (
2039 ctxt, EXR_ERR_INVALID_ATTR);
2040 }
2041
2042 curpart->num_tile_levels_x = numX;
2043 curpart->num_tile_levels_y = numY;
2044 levcntX = (int32_t*) ctxt->alloc_fn (
2045 2 * (size_t) (numX + numY) * sizeof (int32_t));
2046 if (levcntX == NULL)
2047 return ctxt->standard_error (ctxt, EXR_ERR_OUT_OF_MEMORY);
2048 levszX = levcntX + numX;
2049 levcntY = levszX + numX;
2050 levszY = levcntY + numY;
2051
2052 for (int32_t l = 0; l < numX; ++l)
2053 {
2054 int64_t sx = calc_level_size (
2055 dw.min.x, dw.max.x, l, EXR_GET_TILE_ROUND_MODE ((*tiledesc)));
2056 if (sx < 0 || sx > (int64_t) INT32_MAX)
2057 return ctxt->print_error (
2058 ctxt,
2059 EXR_ERR_INVALID_ATTR,
2060 "Invalid data window x dims (%d, %d) resulting in invalid tile level size (%" PRId64
2061 ") for level %d",
2062 dw.min.x,
2063 dw.max.x,
2064 sx,
2065 l);
2066 levcntX[l] =
2067 (int32_t) (((uint64_t) sx + tiledesc->x_size - 1) / tiledesc->x_size);
2068 levszX[l] = (int32_t) sx;
2069 }
2070
2071 for (int32_t l = 0; l < numY; ++l)
2072 {
2073 int64_t sy = calc_level_size (
2074 dw.min.y, dw.max.y, l, EXR_GET_TILE_ROUND_MODE ((*tiledesc)));
2075 if (sy < 0 || sy > (int64_t) INT32_MAX)
2076 return ctxt->print_error (
2077 ctxt,
2078 EXR_ERR_INVALID_ATTR,
2079 "Invalid data window y dims (%d, %d) resulting in invalid tile level size (%" PRId64
2080 ") for level %d",
2081 dw.min.y,
2082 dw.max.y,
2083 sy,
2084 l);
2085 levcntY[l] =
2086 (int32_t) (((uint64_t) sy + tiledesc->y_size - 1) / tiledesc->y_size);
2087 levszY[l] = (int32_t) sy;
2088 }
2089
2090 curpart->tile_level_tile_count_x = levcntX;
2091 curpart->tile_level_tile_count_y = levcntY;
2092 curpart->tile_level_tile_size_x = levszX;
2093 curpart->tile_level_tile_size_y = levszY;
2094 }
2095 return rv;
2096 }
2097
2098 /**************************************/
2099
2100 int32_t
internal_exr_compute_chunk_offset_size(struct _internal_exr_part * curpart)2101 internal_exr_compute_chunk_offset_size (struct _internal_exr_part* curpart)
2102 {
2103 int32_t retval = 0;
2104 const exr_attr_box2i_t dw = curpart->data_window;
2105 const exr_attr_chlist_t* channels = curpart->channels->chlist;
2106 uint64_t unpackedsize = 0;
2107 uint64_t w;
2108 int hasLineSample = 0;
2109
2110 w = (uint64_t) (((int64_t) dw.max.x) - ((int64_t) dw.min.x) + 1);
2111
2112 if (curpart->tiles)
2113 {
2114 const exr_attr_tiledesc_t* tiledesc = curpart->tiles->tiledesc;
2115 int64_t tilecount = 0;
2116
2117 switch (EXR_GET_TILE_LEVEL_MODE ((*tiledesc)))
2118 {
2119 case EXR_TILE_ONE_LEVEL:
2120 case EXR_TILE_MIPMAP_LEVELS:
2121 for (int32_t l = 0; l < curpart->num_tile_levels_x; ++l)
2122 tilecount +=
2123 ((int64_t) curpart->tile_level_tile_count_x[l] *
2124 (int64_t) curpart->tile_level_tile_count_y[l]);
2125 if (tilecount > (int64_t) INT_MAX) return -1;
2126 retval = (int32_t) tilecount;
2127 break;
2128 case EXR_TILE_RIPMAP_LEVELS:
2129 for (int32_t lx = 0; lx < curpart->num_tile_levels_x; ++lx)
2130 {
2131 for (int32_t ly = 0; ly < curpart->num_tile_levels_y; ++ly)
2132 {
2133 tilecount +=
2134 ((int64_t) curpart->tile_level_tile_count_x[lx] *
2135 (int64_t) curpart->tile_level_tile_count_y[ly]);
2136 }
2137 }
2138 if (tilecount > (int64_t) INT_MAX) return -1;
2139 retval = (int32_t) tilecount;
2140 break;
2141 case EXR_TILE_LAST_TYPE:
2142 default: return -1;
2143 }
2144
2145 for (int c = 0; c < channels->num_channels; ++c)
2146 {
2147 uint64_t xsamp = (uint64_t) channels->entries[c].x_sampling;
2148 uint64_t ysamp = (uint64_t) channels->entries[c].y_sampling;
2149 uint64_t cunpsz = 0;
2150 if (channels->entries[c].pixel_type == EXR_PIXEL_HALF)
2151 cunpsz = 2;
2152 else
2153 cunpsz = 4;
2154 cunpsz *= (((uint64_t) tiledesc->x_size + xsamp - 1) / xsamp);
2155 if (ysamp > 1)
2156 {
2157 hasLineSample = 1;
2158 cunpsz *= (((uint64_t) tiledesc->y_size + ysamp - 1) / ysamp);
2159 }
2160 else
2161 cunpsz *= (uint64_t) tiledesc->y_size;
2162 unpackedsize += cunpsz;
2163 }
2164 curpart->unpacked_size_per_chunk = unpackedsize;
2165 curpart->chan_has_line_sampling = ((int16_t) hasLineSample);
2166 }
2167 else
2168 {
2169 uint64_t linePerChunk, h;
2170 switch (curpart->comp_type)
2171 {
2172 case EXR_COMPRESSION_NONE:
2173 case EXR_COMPRESSION_RLE:
2174 case EXR_COMPRESSION_ZIPS: linePerChunk = 1; break;
2175 case EXR_COMPRESSION_ZIP:
2176 case EXR_COMPRESSION_PXR24: linePerChunk = 16; break;
2177 case EXR_COMPRESSION_PIZ:
2178 case EXR_COMPRESSION_B44:
2179 case EXR_COMPRESSION_B44A:
2180 case EXR_COMPRESSION_DWAA: linePerChunk = 32; break;
2181 case EXR_COMPRESSION_DWAB: linePerChunk = 256; break;
2182 case EXR_COMPRESSION_LAST_TYPE:
2183 default:
2184 /* ERROR CONDITION */
2185 return -1;
2186 }
2187
2188 for (int c = 0; c < channels->num_channels; ++c)
2189 {
2190 uint64_t xsamp = (uint64_t) channels->entries[c].x_sampling;
2191 uint64_t ysamp = (uint64_t) channels->entries[c].y_sampling;
2192 uint64_t cunpsz = 0;
2193 if (channels->entries[c].pixel_type == EXR_PIXEL_HALF)
2194 cunpsz = 2;
2195 else
2196 cunpsz = 4;
2197 cunpsz *= w / xsamp;
2198 cunpsz *= linePerChunk;
2199 if (ysamp > 1)
2200 {
2201 hasLineSample = 1;
2202 if (linePerChunk > 1) cunpsz *= linePerChunk / ysamp;
2203 }
2204 unpackedsize += cunpsz;
2205 }
2206
2207 curpart->unpacked_size_per_chunk = unpackedsize;
2208 curpart->lines_per_chunk = ((int16_t) linePerChunk);
2209 curpart->chan_has_line_sampling = ((int16_t) hasLineSample);
2210
2211 h = (uint64_t) ((int64_t) dw.max.y - (int64_t) dw.min.y + 1);
2212 retval = (int32_t) ((h + linePerChunk - 1) / linePerChunk);
2213 }
2214 return retval;
2215 }
2216
2217 /**************************************/
2218
2219 static exr_result_t
update_chunk_offsets(struct _internal_exr_context * ctxt,struct _internal_exr_seq_scratch * scratch)2220 update_chunk_offsets (
2221 struct _internal_exr_context* ctxt,
2222 struct _internal_exr_seq_scratch* scratch)
2223 {
2224 struct _internal_exr_part *curpart, *prevpart;
2225
2226 exr_result_t rv = EXR_ERR_SUCCESS;
2227
2228 if (!ctxt->parts) return EXR_ERR_INVALID_ARGUMENT;
2229
2230 ctxt->parts[0]->chunk_table_offset =
2231 scratch->fileoff - (uint64_t) scratch->navail;
2232 prevpart = ctxt->parts[0];
2233 for (int p = 0; p < ctxt->num_parts; ++p)
2234 {
2235 curpart = ctxt->parts[p];
2236
2237 rv = internal_exr_compute_tile_information (ctxt, curpart, 0);
2238 if (rv != EXR_ERR_SUCCESS) break;
2239
2240 int32_t ccount = internal_exr_compute_chunk_offset_size (curpart);
2241 if (ccount < 0)
2242 {
2243 rv = ctxt->print_error (
2244 ctxt,
2245 EXR_ERR_INVALID_ATTR,
2246 "Invalid chunk count (%d) for part '%s'",
2247 ccount,
2248 (curpart->name ? curpart->name->string->str : "<first>"));
2249 break;
2250 }
2251
2252 if (curpart->chunk_count < 0)
2253 curpart->chunk_count = ccount;
2254 else if (curpart->chunk_count != ccount)
2255 {
2256 /* fatal error or just ignore it? c++ seemed to just ignore it entirely, we can at least warn */
2257 /* rv = */
2258 ctxt->print_error (
2259 ctxt,
2260 EXR_ERR_INVALID_ATTR,
2261 "Invalid chunk count (%d) for part '%s', expect (%d)",
2262 curpart->chunk_count,
2263 (curpart->name ? curpart->name->string->str : "<first>"),
2264 ccount);
2265 curpart->chunk_count = ccount;
2266 }
2267 if (prevpart != curpart)
2268 curpart->chunk_table_offset =
2269 prevpart->chunk_table_offset +
2270 sizeof (uint64_t) * (size_t) (prevpart->chunk_count);
2271 prevpart = curpart;
2272 }
2273 return rv;
2274 }
2275
2276 /**************************************/
2277
2278 static exr_result_t
read_magic_and_flags(struct _internal_exr_context * ctxt,uint32_t * outflags,uint64_t * initpos)2279 read_magic_and_flags (
2280 struct _internal_exr_context* ctxt, uint32_t* outflags, uint64_t* initpos)
2281 {
2282 uint32_t magic_and_version[2];
2283 uint32_t flags;
2284 exr_result_t rv = EXR_ERR_UNKNOWN;
2285 uint64_t fileoff = 0;
2286 int64_t nread = 0;
2287
2288 rv = ctxt->do_read (
2289 ctxt,
2290 magic_and_version,
2291 sizeof (uint32_t) * 2,
2292 &fileoff,
2293 &nread,
2294 EXR_MUST_READ_ALL);
2295 if (rv != EXR_ERR_SUCCESS)
2296 {
2297 ctxt->report_error (
2298 ctxt, EXR_ERR_READ_IO, "Unable to read magic and version flags");
2299 return rv;
2300 }
2301
2302 *initpos = sizeof (uint32_t) * 2;
2303
2304 priv_to_native32 (magic_and_version, 2);
2305 if (magic_and_version[0] != 20000630)
2306 {
2307 rv = ctxt->print_error (
2308 ctxt,
2309 EXR_ERR_FILE_BAD_HEADER,
2310 "File is not an OpenEXR file: magic 0x%08X (%d) flags 0x%08X",
2311 magic_and_version[0],
2312 (int) magic_and_version[0],
2313 magic_and_version[1]);
2314 return rv;
2315 }
2316
2317 flags = magic_and_version[1];
2318
2319 ctxt->version = flags & EXR_FILE_VERSION_MASK;
2320 if (ctxt->version != 2)
2321 {
2322 rv = ctxt->print_error (
2323 ctxt,
2324 EXR_ERR_FILE_BAD_HEADER,
2325 "File is of an unsupported version: %d, magic 0x%08X flags 0x%08X",
2326 (int) ctxt->version,
2327 magic_and_version[0],
2328 magic_and_version[1]);
2329 return rv;
2330 }
2331
2332 flags = flags & ~((uint32_t) EXR_FILE_VERSION_MASK);
2333 if ((flags & ~((uint32_t) EXR_VALID_FLAGS)) != 0)
2334 {
2335 rv = ctxt->print_error (
2336 ctxt,
2337 EXR_ERR_FILE_BAD_HEADER,
2338 "File has an unsupported flags: magic 0x%08X flags 0x%08X",
2339 magic_and_version[0],
2340 magic_and_version[1]);
2341 return rv;
2342 }
2343 *outflags = flags;
2344 return EXR_ERR_SUCCESS;
2345 }
2346
2347 /**************************************/
2348
2349 exr_result_t
internal_exr_check_magic(struct _internal_exr_context * ctxt)2350 internal_exr_check_magic (struct _internal_exr_context* ctxt)
2351 {
2352 uint32_t flags;
2353 uint64_t initpos;
2354 exr_result_t rv = EXR_ERR_UNKNOWN;
2355
2356 rv = read_magic_and_flags (ctxt, &flags, &initpos);
2357 return rv;
2358 }
2359
2360 /**************************************/
2361
2362 exr_result_t
internal_exr_parse_header(struct _internal_exr_context * ctxt)2363 internal_exr_parse_header (struct _internal_exr_context* ctxt)
2364 {
2365 struct _internal_exr_seq_scratch scratch;
2366 struct _internal_exr_part* curpart;
2367 uint32_t flags;
2368 uint64_t initpos;
2369 uint8_t next_byte;
2370 exr_result_t rv = EXR_ERR_UNKNOWN;
2371
2372 rv = read_magic_and_flags (ctxt, &flags, &initpos);
2373 if (rv != EXR_ERR_SUCCESS) return rv;
2374
2375 rv = priv_init_scratch (ctxt, &scratch, initpos);
2376 if (rv != EXR_ERR_SUCCESS)
2377 {
2378 priv_destroy_scratch (&scratch);
2379 return rv;
2380 }
2381
2382 curpart = ctxt->parts[0];
2383 if (!curpart)
2384 {
2385 rv = ctxt->report_error (
2386 ctxt, EXR_ERR_INVALID_ARGUMENT, "Error during file initialization");
2387 priv_destroy_scratch (&scratch);
2388 return rv;
2389 }
2390
2391 ctxt->is_singlepart_tiled = (flags & EXR_TILED_FLAG) ? 1 : 0;
2392 ctxt->max_name_length = (flags & EXR_LONG_NAMES_FLAG)
2393 ? EXR_LONGNAME_MAXLEN
2394 : EXR_SHORTNAME_MAXLEN;
2395 ctxt->has_nonimage_data = (flags & EXR_NON_IMAGE_FLAG) ? 1 : 0;
2396 ctxt->is_multipart = (flags & EXR_MULTI_PART_FLAG) ? 1 : 0;
2397 if (ctxt->is_singlepart_tiled)
2398 {
2399 if (ctxt->has_nonimage_data || ctxt->is_multipart)
2400 {
2401 rv = ctxt->print_error (
2402 ctxt,
2403 EXR_ERR_FILE_BAD_HEADER,
2404 "Invalid combination of version flags: single part found, but also marked as deep (%d) or multipart (%d)",
2405 (int) ctxt->has_nonimage_data,
2406 (int) ctxt->is_multipart);
2407 priv_destroy_scratch (&scratch);
2408 return rv;
2409 }
2410 curpart->storage_mode = EXR_STORAGE_TILED;
2411 }
2412 else
2413 curpart->storage_mode = EXR_STORAGE_SCANLINE;
2414
2415 do
2416 {
2417 rv = scratch.sequential_read (&scratch, &next_byte, 1);
2418 if (rv != EXR_ERR_SUCCESS)
2419 {
2420 rv = ctxt->report_error (
2421 ctxt, EXR_ERR_FILE_BAD_HEADER, "Unable to extract header byte");
2422 priv_destroy_scratch (&scratch);
2423 return rv;
2424 }
2425
2426 if (next_byte == '\0')
2427 {
2428 rv = internal_exr_validate_read_part (ctxt, curpart);
2429 if (rv != EXR_ERR_SUCCESS)
2430 {
2431 priv_destroy_scratch (&scratch);
2432 return rv;
2433 }
2434
2435 if (!ctxt->is_multipart)
2436 {
2437 /* got a terminal mark, not multipart, so finished */
2438 break;
2439 }
2440
2441 rv = scratch.sequential_read (&scratch, &next_byte, 1);
2442 if (rv != EXR_ERR_SUCCESS)
2443 {
2444 rv = ctxt->report_error (
2445 ctxt,
2446 EXR_ERR_FILE_BAD_HEADER,
2447 "Unable to go to next part definition");
2448 priv_destroy_scratch (&scratch);
2449 return rv;
2450 }
2451
2452 if (next_byte == '\0')
2453 {
2454 /* got a second terminator, finished with the
2455 * headers, can read chunk offsets next */
2456 break;
2457 }
2458
2459 rv = internal_exr_add_part (ctxt, &curpart, NULL);
2460 }
2461
2462 if (rv == EXR_ERR_SUCCESS)
2463 rv = pull_attr (ctxt, curpart, next_byte, &scratch);
2464 if (rv != EXR_ERR_SUCCESS) break;
2465 } while (1);
2466
2467 if (rv == EXR_ERR_SUCCESS) rv = update_chunk_offsets (ctxt, &scratch);
2468
2469 priv_destroy_scratch (&scratch);
2470 return rv;
2471 }
2472