Coverage Report

Created: 2026-04-20 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openexr/src/lib/OpenEXR/ImfContext.cpp
Line
Count
Source
1
//
2
// SPDX-License-Identifier: BSD-3-Clause
3
// Copyright (c) Contributors to the OpenEXR Project.
4
//
5
6
#include "ImfContext.h"
7
8
#include "openexr.h"
9
10
#include "Iex.h"
11
12
// TODO: remove these once we've cleared the legacy stream need
13
#include "ImfIO.h"
14
#include "ImfStdIO.h"
15
#include <mutex>
16
17
#include <string.h>
18
19
#include <ImfBoxAttribute.h>
20
#include <ImfBytesAttribute.h>
21
#include <ImfChannelListAttribute.h>
22
#include <ImfChromaticitiesAttribute.h>
23
#include <ImfCompressionAttribute.h>
24
#include <ImfCompressor.h>
25
#include <ImfDeepImageStateAttribute.h>
26
#include <ImfDoubleAttribute.h>
27
#include <ImfDwaCompressor.h>
28
#include <ImfEnvmapAttribute.h>
29
#include <ImfFloatAttribute.h>
30
#include <ImfFloatVectorAttribute.h>
31
#include <ImfIDManifestAttribute.h>
32
#include <ImfIntAttribute.h>
33
#include <ImfKeyCodeAttribute.h>
34
#include <ImfLineOrderAttribute.h>
35
#include <ImfMatrixAttribute.h>
36
#include <ImfOpaqueAttribute.h>
37
#include <ImfPreviewImageAttribute.h>
38
#include <ImfRationalAttribute.h>
39
#include <ImfStringAttribute.h>
40
#include <ImfStringVectorAttribute.h>
41
#include <ImfTileDescriptionAttribute.h>
42
#include <ImfTimeCodeAttribute.h>
43
#include <ImfVecAttribute.h>
44
45
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
46
47
namespace
48
{
49
50
class MemAttrStream : public OPENEXR_IMF_NAMESPACE::IStream
51
{
52
public:
53
    MemAttrStream (const exr_attr_opaquedata_t *opaque)
54
5.75k
        : IStream ("<mem_attr>"),
55
5.75k
          _data (static_cast<char*> (opaque->packed_data)),
56
5.75k
          _sz (static_cast<uint64_t> (opaque->size)),
57
5.75k
          _pos (0)
58
5.75k
    {}
59
60
0
    ~MemAttrStream () override {}
61
62
0
    bool isMemoryMapped () const override { return true; }
63
64
    bool     read (char c[/*n*/], int n) override
65
11.4k
    {
66
11.4k
        if (_pos >= _sz && n != 0)
67
0
            throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
68
69
11.4k
        uint64_t n2     = n;
70
11.4k
        bool     retVal = true;
71
72
11.4k
        if (_sz - _pos <= n2)
73
10.9k
        {
74
10.9k
            n2     = _sz - _pos;
75
10.9k
            retVal = false;
76
10.9k
        }
77
78
11.4k
        memcpy (c, _data + _pos, n2);
79
11.4k
        _pos += n2;
80
11.4k
        return retVal;
81
11.4k
    }
82
83
    char*    readMemoryMapped (int n) override
84
0
    {
85
0
        if (_pos >= _sz)
86
0
            throw IEX_NAMESPACE::InputExc ("Unexpected end of file.");
87
88
0
        if (_pos + n > _sz)
89
0
            throw IEX_NAMESPACE::InputExc ("Reading past end of file.");
90
91
0
        char* retVal = _data + _pos;
92
0
        _pos += n;
93
0
        return retVal;
94
0
    }
95
0
    uint64_t tellg () override { return _pos; }
96
0
    void     seekg (uint64_t pos) override { _pos = pos; }
97
0
    void     clear () override {}
98
99
private:
100
    char*    _data;
101
    uint64_t _sz;
102
    uint64_t _pos;
103
};
104
105
} // namespace
106
107
////////////////////////////////////////
108
109
Context::Context ()
110
201k
    : _ctxt (new exr_context_t(), [] (exr_context_t* todel) {
111
201k
        exr_finish (todel);
112
201k
        delete todel;
113
201k
    })
114
201k
{
115
201k
}
116
117
////////////////////////////////////////
118
119
Context::Context (const char* filename, const ContextInitializer& ctxtinit, read_mode_t)
120
40.0k
    : Context()
121
40.0k
{
122
40.0k
    exr_result_t rv;
123
124
40.0k
    rv = exr_start_read (_ctxt.get (), filename, &(ctxtinit._initializer));
125
40.0k
    if (EXR_ERR_SUCCESS != rv)
126
4.97k
    {
127
4.97k
        if (rv == EXR_ERR_MISSING_REQ_ATTR)
128
898
        {
129
898
            THROW (
130
898
                IEX_NAMESPACE::ArgExc,
131
898
                "Invalid or missing attribute when attempting to open '"
132
898
                << filename << "' for read");
133
898
        }
134
4.07k
        else
135
4.07k
        {
136
4.07k
            THROW (
137
4.07k
                IEX_NAMESPACE::InputExc,
138
4.07k
                "Unable to open '" << filename << "' for read");
139
4.07k
        }
140
4.97k
    }
141
40.0k
}
142
143
////////////////////////////////////////
144
145
Context::Context (const char* filename, const ContextInitializer& ctxtinit, temp_mode_t)
146
0
    : Context()
147
0
{
148
0
    if (EXR_ERR_SUCCESS != exr_start_temporary_context (
149
0
                               _ctxt.get (),
150
0
                               filename,
151
0
                               &(ctxtinit._initializer)))
152
0
    {
153
0
        THROW (
154
0
            IEX_NAMESPACE::InputExc,
155
0
            "Unable to create a temporary context");
156
0
    }
157
0
}
158
159
////////////////////////////////////////
160
161
Context::Context (const char* filename, const ContextInitializer& ctxtinit, write_mode_t)
162
0
    : Context()
163
0
{
164
0
    if (EXR_ERR_SUCCESS != exr_start_write (
165
0
                               _ctxt.get (),
166
0
                               filename,
167
0
                               EXR_WRITE_FILE_DIRECTLY,
168
0
                               &(ctxtinit._initializer)))
169
0
    {
170
0
        THROW (
171
0
            IEX_NAMESPACE::InputExc,
172
0
            "Unable to open '" << filename << "' for write");
173
0
    }
174
0
}
175
176
////////////////////////////////////////
177
178
void
179
Context::setLongNameSupport (bool onoff)
180
0
{
181
0
    if (EXR_ERR_SUCCESS != exr_set_longname_support (*_ctxt, onoff ? 1 : 0))
182
0
    {
183
0
        THROW (IEX_NAMESPACE::ArgExc, "Unable to set long name support flag");
184
0
    }
185
0
}
186
187
////////////////////////////////////////
188
189
const char*
190
Context::fileName () const
191
149k
{
192
149k
    const char* filename = nullptr;
193
194
149k
    if (EXR_ERR_SUCCESS != exr_get_file_name (*_ctxt, &filename))
195
0
    {
196
0
        THROW (IEX_NAMESPACE::ArgExc, "Unable to get filename from context");
197
0
    }
198
199
149k
    return filename;
200
149k
}
201
202
////////////////////////////////////////
203
204
int
205
Context::version () const
206
53.7k
{
207
53.7k
    uint32_t ver = 0;
208
209
53.7k
    if (EXR_ERR_SUCCESS != exr_get_file_version_and_flags (*_ctxt, &ver))
210
0
    {
211
0
        THROW (
212
0
            IEX_NAMESPACE::ArgExc, "Unable to get file version from context");
213
0
    }
214
215
53.7k
    return static_cast<int> (ver);
216
53.7k
}
217
218
////////////////////////////////////////
219
220
int
221
Context::partCount () const
222
12.2k
{
223
12.2k
    int count = 0;
224
225
12.2k
    if (EXR_ERR_SUCCESS != exr_get_count (*_ctxt, &count))
226
0
    {
227
0
        THROW (
228
0
            IEX_NAMESPACE::ArgExc,
229
0
            "Unable to get part count for file '" << fileName () << "'");
230
0
    }
231
232
12.2k
    return count;
233
12.2k
}
234
235
////////////////////////////////////////
236
237
exr_storage_t
238
Context::storage (int partidx) const
239
714k
{
240
714k
    exr_storage_t storage = EXR_STORAGE_LAST_TYPE;
241
242
714k
    if (EXR_ERR_SUCCESS != exr_get_storage (*_ctxt, partidx, &storage))
243
0
    {
244
0
        THROW (
245
0
            IEX_NAMESPACE::ArgExc,
246
0
            "Unable to get storage type for part " << partidx << " in file '"
247
0
                                                   << fileName () << "'");
248
0
    }
249
250
714k
    return storage;
251
714k
}
252
253
////////////////////////////////////////
254
255
exr_attr_box2i_t
256
Context::dataWindow (int partidx) const
257
163k
{
258
163k
    exr_attr_box2i_t dw;
259
260
163k
    if (EXR_ERR_SUCCESS != exr_get_data_window (*_ctxt, partidx, &dw))
261
0
    {
262
0
        THROW (
263
0
            IEX_NAMESPACE::ArgExc,
264
0
            "Unable to get the data window for part " << partidx << " in file '"
265
0
                                                      << fileName () << "'");
266
0
    }
267
268
163k
    return dw;
269
163k
}
270
271
////////////////////////////////////////
272
273
const exr_attr_chlist_t*
274
Context::channels (int partidx) const
275
226k
{
276
226k
    const exr_attr_chlist_t* cl;
277
278
226k
    if (EXR_ERR_SUCCESS != exr_get_channels (*_ctxt, partidx, &cl))
279
0
    {
280
0
        THROW (
281
0
            IEX_NAMESPACE::ArgExc,
282
0
            "Unable to get the channel list for part "
283
0
                << partidx << " in file '" << fileName () << "'");
284
0
    }
285
286
226k
    return cl;
287
226k
}
288
289
////////////////////////////////////////
290
291
bool
292
Context::hasChannel (int partidx, const char* name) const
293
6.30k
{
294
6.30k
    return findChannel (partidx, name) != nullptr;
295
6.30k
}
296
297
const exr_attr_chlist_entry_t* Context::findChannel (int partidx, const char* name) const
298
226k
{
299
226k
    const exr_attr_chlist_t* cl  = channels (partidx);
300
226k
    int32_t                  len = strlen (name);
301
302
740k
    for (int i = 0; i < cl->num_channels; ++i)
303
688k
    {
304
688k
        const exr_attr_chlist_entry_t* curc = cl->entries + i;
305
688k
        if (curc->name.length == len && 0 == memcmp (name, curc->name.str, len))
306
173k
        {
307
173k
            return curc;
308
173k
        }
309
688k
    }
310
52.4k
    return nullptr;
311
226k
}
312
313
////////////////////////////////////////
314
315
exr_lineorder_t
316
Context::lineOrder (int partidx) const
317
0
{
318
0
    exr_lineorder_t lo;
319
320
0
    if (EXR_ERR_SUCCESS != exr_get_lineorder (*_ctxt, partidx, &lo))
321
0
    {
322
0
        THROW (
323
0
            IEX_NAMESPACE::ArgExc,
324
0
            "Unable to get the line order for part " << partidx << " in file '"
325
0
                                                     << fileName () << "'");
326
0
    }
327
328
0
    return lo;
329
0
}
330
331
////////////////////////////////////////
332
333
int
334
Context::attrCount (int partidx) const
335
0
{
336
0
    int32_t attrcnt = 0;
337
338
0
    if (EXR_ERR_SUCCESS != exr_get_attribute_count (*_ctxt, partidx, &attrcnt))
339
0
    {
340
0
        THROW (
341
0
            IEX_NAMESPACE::ArgExc,
342
0
            "Unable to get attribute for part " << partidx << " in file '"
343
0
                                                << fileName () << "'");
344
0
    }
345
346
0
    return 0;
347
0
}
348
349
////////////////////////////////////////
350
351
const exr_attribute_t*
352
Context::getAttr (int partidx, int attridx) const
353
0
{
354
0
    const exr_attribute_t* attr = nullptr;
355
356
0
    if (EXR_ERR_SUCCESS !=
357
0
        exr_get_attribute_by_index (
358
0
            *_ctxt, partidx, EXR_ATTR_LIST_FILE_ORDER, attridx, &attr))
359
0
    {
360
0
        THROW (
361
0
            IEX_NAMESPACE::ArgExc,
362
0
            "Unable to get attribute index " << attridx << " for part "
363
0
                                             << partidx << " in file '"
364
0
                                             << fileName () << "'");
365
0
    }
366
367
0
    return attr;
368
0
}
369
370
////////////////////////////////////////
371
372
const exr_attribute_t*
373
Context::getAttr (int partidx, const char* name) const
374
0
{
375
0
    const exr_attribute_t* attr = nullptr;
376
0
    exr_result_t           res;
377
378
0
    res = exr_get_attribute_by_name (*_ctxt, partidx, name, &attr);
379
380
0
    if (res == EXR_ERR_SUCCESS || res == EXR_ERR_NO_ATTR_BY_NAME) return attr;
381
382
0
    THROW (
383
0
        IEX_NAMESPACE::ArgExc,
384
0
        "Unable to find attribute '" << name << "' for part " << partidx
385
0
                                     << " in file '" << fileName () << "'");
386
0
}
387
388
////////////////////////////////////////
389
390
Header
391
Context::header (int partidx) const
392
225k
{
393
225k
    Header                 hdr;
394
225k
    int32_t                attrcnt = 0;
395
225k
    const exr_attribute_t* cur     = nullptr;
396
397
225k
    if (EXR_ERR_SUCCESS != exr_get_attribute_count (*_ctxt, partidx, &attrcnt))
398
0
    {
399
0
        THROW (
400
0
            IEX_NAMESPACE::ArgExc,
401
0
            "Unable to get attribute for part " << partidx << " in file '"
402
0
                                                << fileName () << "'");
403
0
    }
404
405
3.02M
    for (int32_t idx = 0; idx < attrcnt; ++idx)
406
2.79M
    {
407
2.79M
        if (EXR_ERR_SUCCESS !=
408
2.79M
            exr_get_attribute_by_index (
409
2.79M
                *_ctxt, partidx, EXR_ATTR_LIST_FILE_ORDER, idx, &cur))
410
0
        {
411
0
            THROW (
412
0
                IEX_NAMESPACE::ArgExc,
413
0
                "Unable to get attribute index " << idx << " for part "
414
0
                                                 << partidx << " in file '"
415
0
                                                 << fileName () << "'");
416
0
        }
417
418
2.79M
        switch (cur->type)
419
2.79M
        {
420
142k
            case EXR_ATTR_INT:
421
142k
                hdr.insert (cur->name, IntAttribute (cur->i));
422
142k
                break;
423
2.88k
            case EXR_ATTR_DOUBLE:
424
2.88k
                hdr.insert (cur->name, DoubleAttribute (cur->d));
425
2.88k
                break;
426
518k
            case EXR_ATTR_FLOAT:
427
518k
                hdr.insert (cur->name, FloatAttribute (cur->f));
428
518k
                break;
429
430
453k
            case EXR_ATTR_BOX2I:
431
453k
                hdr.insert (
432
453k
                    cur->name,
433
453k
                    Box2iAttribute (IMATH_NAMESPACE::Box2i (
434
453k
                        IMATH_NAMESPACE::V2i (cur->box2i->min),
435
453k
                        IMATH_NAMESPACE::V2i (cur->box2i->max))));
436
453k
                break;
437
2.77k
            case EXR_ATTR_BOX2F:
438
2.77k
                hdr.insert (
439
2.77k
                    cur->name,
440
2.77k
                    Box2fAttribute (IMATH_NAMESPACE::Box2f (
441
2.77k
                        IMATH_NAMESPACE::V2f (cur->box2f->min),
442
2.77k
                        IMATH_NAMESPACE::V2f (cur->box2f->max))));
443
2.77k
                break;
444
5.83k
            case EXR_ATTR_BYTES:
445
5.83k
                hdr.insert (
446
5.83k
                    cur->name, BytesAttribute (
447
5.83k
                        cur->bytes->size,
448
5.83k
                        cur->bytes->data,
449
5.83k
                        std::string (cur->bytes->type_hint, cur->bytes->hint_length)));
450
5.83k
                break;
451
2.04k
            case EXR_ATTR_V2I:
452
2.04k
                hdr.insert (
453
2.04k
                    cur->name,
454
2.04k
                    V2iAttribute (IMATH_NAMESPACE::V2i (*(cur->v2i))));
455
2.04k
                break;
456
227k
            case EXR_ATTR_V2F:
457
227k
                hdr.insert (
458
227k
                    cur->name,
459
227k
                    V2fAttribute (IMATH_NAMESPACE::V2f (*(cur->v2f))));
460
227k
                break;
461
3.93k
            case EXR_ATTR_V2D:
462
3.93k
                hdr.insert (
463
3.93k
                    cur->name,
464
3.93k
                    V2dAttribute (IMATH_NAMESPACE::V2d (*(cur->v2d))));
465
3.93k
                break;
466
1.62k
            case EXR_ATTR_V3I:
467
1.62k
                hdr.insert (
468
1.62k
                    cur->name,
469
1.62k
                    V3iAttribute (IMATH_NAMESPACE::V3i (*(cur->v3i))));
470
1.62k
                break;
471
1.25k
            case EXR_ATTR_V3F:
472
1.25k
                hdr.insert (
473
1.25k
                    cur->name,
474
1.25k
                    V3fAttribute (IMATH_NAMESPACE::V3f (*(cur->v3f))));
475
1.25k
                break;
476
2.49k
            case EXR_ATTR_V3D:
477
2.49k
                hdr.insert (
478
2.49k
                    cur->name,
479
2.49k
                    V3dAttribute (IMATH_NAMESPACE::V3d (*(cur->v3d))));
480
2.49k
                break;
481
482
445k
            case EXR_ATTR_STRING:
483
445k
                hdr.insert (
484
445k
                    cur->name,
485
445k
                    StringAttribute (
486
445k
                        std::string (cur->string->str, cur->string->length)));
487
445k
                break;
488
489
237k
            case EXR_ATTR_COMPRESSION:
490
237k
                hdr.insert (
491
237k
                    cur->name, CompressionAttribute (Compression (cur->uc)));
492
237k
                break;
493
3.21k
            case EXR_ATTR_ENVMAP:
494
3.21k
                hdr.insert (cur->name, EnvmapAttribute (Envmap (cur->uc)));
495
3.21k
                break;
496
225k
            case EXR_ATTR_LINEORDER:
497
225k
                hdr.insert (
498
225k
                    cur->name, LineOrderAttribute (LineOrder (cur->uc)));
499
225k
                break;
500
501
277k
            case EXR_ATTR_CHLIST: {
502
277k
                ChannelList& chans = hdr.channels ();
503
504
659k
                for (int c = 0; c < cur->chlist->num_channels; ++c)
505
381k
                {
506
381k
                    const exr_attr_chlist_entry_t& curc =
507
381k
                        cur->chlist->entries[c];
508
381k
                    chans.insert (
509
381k
                        curc.name.str,
510
381k
                        Channel (
511
381k
                            PixelType (curc.pixel_type),
512
381k
                            curc.x_sampling,
513
381k
                            curc.y_sampling,
514
381k
                            curc.p_linear != 0));
515
381k
                }
516
277k
                break;
517
0
            }
518
519
63.2k
            case EXR_ATTR_TILEDESC:
520
63.2k
                hdr.insert (
521
63.2k
                    cur->name, TileDescriptionAttribute (
522
63.2k
                        TileDescription (
523
63.2k
                            cur->tiledesc->x_size,
524
63.2k
                            cur->tiledesc->y_size,
525
63.2k
                            (LevelMode)(EXR_GET_TILE_LEVEL_MODE (*cur->tiledesc)),
526
63.2k
                            (LevelRoundingMode)(EXR_GET_TILE_ROUND_MODE (*cur->tiledesc)))));
527
63.2k
                break;
528
529
3.98k
            case EXR_ATTR_FLOAT_VECTOR:
530
3.98k
                hdr.insert (
531
3.98k
                    cur->name, FloatVectorAttribute (
532
3.98k
                        FloatVector (
533
3.98k
                            cur->floatvector->arr,
534
3.98k
                            cur->floatvector->arr + cur->floatvector->length)));
535
3.98k
                break;
536
537
2.23k
            case EXR_ATTR_M33F:
538
2.23k
                hdr.insert (
539
2.23k
                    cur->name, M33fAttribute (
540
2.23k
                        IMATH_NAMESPACE::M33f (
541
2.23k
                            *reinterpret_cast<float (*)[3][3]> (cur->m33f->m))));
542
2.23k
                break;
543
1.75k
            case EXR_ATTR_M33D:
544
1.75k
                hdr.insert (
545
1.75k
                    cur->name, M33dAttribute (
546
1.75k
                        IMATH_NAMESPACE::M33d (
547
1.75k
                            *reinterpret_cast<double (*)[3][3]> (cur->m33d->m))));
548
1.75k
                break;
549
1.22k
            case EXR_ATTR_M44F:
550
1.22k
                hdr.insert (
551
1.22k
                    cur->name, M44fAttribute (
552
1.22k
                        IMATH_NAMESPACE::M44f (
553
1.22k
                            *reinterpret_cast<float (*)[4][4]> (cur->m44f->m))));
554
1.22k
                break;
555
617
            case EXR_ATTR_M44D:
556
617
                hdr.insert (
557
617
                    cur->name, M44dAttribute (
558
617
                        IMATH_NAMESPACE::M44d (
559
617
                            *reinterpret_cast<double (*)[4][4]> (cur->m44d->m))));
560
617
                break;
561
562
1.95k
            case EXR_ATTR_CHROMATICITIES:
563
1.95k
                hdr.insert (
564
1.95k
                    cur->name, ChromaticitiesAttribute (
565
1.95k
                        Chromaticities (
566
1.95k
                            IMATH_NAMESPACE::V2f (
567
1.95k
                                cur->chromaticities->red_x,
568
1.95k
                                cur->chromaticities->red_y),
569
1.95k
                            IMATH_NAMESPACE::V2f (
570
1.95k
                                cur->chromaticities->green_x,
571
1.95k
                                cur->chromaticities->green_y),
572
1.95k
                            IMATH_NAMESPACE::V2f (
573
1.95k
                                cur->chromaticities->blue_x,
574
1.95k
                                cur->chromaticities->blue_y),
575
1.95k
                            IMATH_NAMESPACE::V2f (
576
1.95k
                                cur->chromaticities->white_x,
577
1.95k
                                cur->chromaticities->white_y))));
578
1.95k
                break;
579
1.01k
            case EXR_ATTR_KEYCODE:
580
1.01k
                hdr.insert (
581
1.01k
                    cur->name, KeyCodeAttribute (
582
1.01k
                        KeyCode (
583
1.01k
                            cur->keycode->film_mfc_code,
584
1.01k
                            cur->keycode->film_type,
585
1.01k
                            cur->keycode->prefix,
586
1.01k
                            cur->keycode->count,
587
1.01k
                            cur->keycode->perf_offset,
588
1.01k
                            cur->keycode->perfs_per_frame,
589
1.01k
                            cur->keycode->perfs_per_count)));
590
1.01k
                break;
591
5.69k
            case EXR_ATTR_RATIONAL:
592
5.69k
                hdr.insert (
593
5.69k
                    cur->name, RationalAttribute (
594
5.69k
                        Rational (
595
5.69k
                            cur->rational->num,
596
5.69k
                            cur->rational->denom)));
597
5.69k
                break;
598
1.56k
            case EXR_ATTR_TIMECODE:
599
1.56k
                hdr.insert (
600
1.56k
                    cur->name, TimeCodeAttribute (
601
1.56k
                        TimeCode (
602
1.56k
                            cur->timecode->time_and_flags,
603
1.56k
                            cur->timecode->user_data)));
604
1.56k
                break;
605
3.62k
            case EXR_ATTR_PREVIEW:
606
3.62k
                hdr.insert (
607
3.62k
                    cur->name, PreviewImageAttribute (
608
3.62k
                        PreviewImage (
609
3.62k
                            cur->preview->width,
610
3.62k
                            cur->preview->height,
611
3.62k
                            reinterpret_cast<const PreviewRgba*> (cur->preview->rgba))));
612
3.62k
                break;
613
2.78k
            case EXR_ATTR_STRING_VECTOR:
614
2.78k
            {
615
2.78k
                std::vector<std::string> svec;
616
2.78k
                svec.resize (cur->stringvector->n_strings);
617
78.2k
                for (int s = 0; s < cur->stringvector->n_strings; ++s)
618
75.4k
                {
619
75.4k
                    svec[s] = std::string (
620
75.4k
                        cur->stringvector->strings[s].str,
621
75.4k
                        cur->stringvector->strings[s].length);
622
75.4k
                }
623
2.78k
                hdr.insert (
624
2.78k
                    cur->name, StringVectorAttribute (svec));
625
2.78k
                break;
626
0
            }
627
628
4.37k
            case EXR_ATTR_DEEP_IMAGE_STATE:
629
4.37k
                hdr.insert (
630
4.37k
                    cur->name, DeepImageStateAttribute (DeepImageState (cur->uc)));
631
4.37k
                break;
632
633
150k
            case EXR_ATTR_OPAQUE:
634
150k
                if (Attribute::knownType (cur->type_name))
635
5.75k
                {
636
5.75k
                    MemAttrStream mas {cur->opaque};
637
638
5.75k
                    std::unique_ptr<Attribute> attr;
639
5.75k
                    attr.reset (Attribute::newAttribute (cur->type_name));
640
641
5.75k
                    attr->readValueFrom (mas, cur->opaque->size, version ());
642
                    // TODO: can we avoid a double copy?
643
5.75k
                    hdr.insert (cur->name, *attr);
644
5.75k
                }
645
145k
                else
646
145k
                {
647
145k
                    hdr.insert (
648
145k
                        cur->name, OpaqueAttribute (
649
145k
                            cur->type_name,
650
145k
                            cur->opaque->size,
651
145k
                            cur->opaque->packed_data));
652
145k
                }
653
150k
                break;
654
655
0
            case EXR_ATTR_UNKNOWN:
656
0
            case EXR_ATTR_LAST_KNOWN_TYPE:
657
0
            default: {
658
0
                THROW (IEX_NAMESPACE::LogicExc,
659
0
                       "Unknown attribute '"
660
0
                       << cur->name
661
0
                       << "' of type '"
662
0
                       << cur->type << "', conversion to legacy header not yet implemented");
663
0
            }
664
2.79M
        }
665
2.79M
    }
666
667
225k
    return hdr;
668
225k
}
669
670
////////////////////////////////////////
671
672
673
#define EXR_SET_ATTR(type, cpptype, attrval)                            \
674
0
    if (!strcmp (attrT, #type))                                         \
675
0
    {                                                                   \
676
0
        const cpptype *attr = dynamic_cast<const cpptype*> (&a);        \
677
0
        if (!attr)                                                      \
678
0
            throw IEX_NAMESPACE::ArgExc ("unexpected type mismatch");   \
679
0
        rv = exr_attr_set_##type (*_ctxt, partnum, i.name (), attrval); \
680
0
        if (rv != EXR_ERR_SUCCESS)                                      \
681
0
            throw IEX_NAMESPACE::ArgExc ("Unable to copy attribute");   \
682
0
        continue;                                                       \
683
0
    }
684
685
686
void Context::addHeader (int partnum, const Header &h)
687
0
{
688
0
    exr_result_t rv;
689
    // TODO: ImfHeader iterator types should support operator* so they can
690
    // use ranged-based for
691
0
    for (auto i = h.begin (); i != h.end (); ++i)
692
0
    {
693
0
        const Attribute& a = i.attribute ();
694
0
        const char* attrT = a.typeName ();
695
696
0
        if (!strcmp (i.name (), "channels"))
697
0
        {
698
0
            const ChannelList& chans = h.channels ();
699
700
0
            for (auto c = chans.begin (); c != chans.end (); ++c)
701
0
            {
702
0
                const Channel &cdef = c.channel ();
703
0
                rv = exr_add_channel (
704
0
                    *_ctxt, partnum, c.name (),
705
0
                    (exr_pixel_type_t)cdef.type,
706
0
                    cdef.pLinear ? EXR_PERCEPTUALLY_LINEAR : EXR_PERCEPTUALLY_LOGARITHMIC,
707
0
                    cdef.xSampling,
708
0
                    cdef.ySampling);
709
0
                if (rv != EXR_ERR_SUCCESS)
710
0
                    throw IEX_NAMESPACE::ArgExc ("Unable to copy channel information");
711
0
            }
712
0
            continue;
713
0
        }
714
715
0
        if (!strcmp (i.name (), "lineOrder"))
716
0
        {
717
0
            const LineOrderAttribute *attr =
718
0
                dynamic_cast<const LineOrderAttribute*> (&a);
719
0
            if (!attr)
720
0
                throw IEX_NAMESPACE::ArgExc ("unexpected type mismatch");
721
0
            rv = exr_set_lineorder (
722
0
                *_ctxt, partnum, (exr_lineorder_t)attr->value ());
723
0
            if (rv != EXR_ERR_SUCCESS)
724
0
                throw IEX_NAMESPACE::ArgExc ("Unable to copy attribute");
725
0
            continue;
726
0
        }
727
728
0
        if (!strcmp (attrT, "tiledesc"))
729
0
        {
730
0
            const TileDescriptionAttribute *attr =
731
0
                dynamic_cast<const TileDescriptionAttribute*> (&a);
732
0
            if (!attr)
733
0
                throw IEX_NAMESPACE::ArgExc ("unexpected type mismatch");
734
0
            TileDescription td = attr->value ();
735
736
0
            rv = exr_set_tile_descriptor (
737
0
                *_ctxt, partnum,
738
0
                td.xSize,
739
0
                td.ySize,
740
0
                (exr_tile_level_mode_t)td.mode,
741
0
                (exr_tile_round_mode_t)td.roundingMode);
742
743
0
            if (rv != EXR_ERR_SUCCESS)
744
0
                throw IEX_NAMESPACE::ArgExc ("Unable to copy attribute");
745
0
            continue;
746
0
        }
747
748
0
        EXR_SET_ATTR(string, StringAttribute, attr->value ().c_str ());
749
0
        EXR_SET_ATTR(int, IntAttribute, attr->value ());
750
0
        EXR_SET_ATTR(float, FloatAttribute, attr->value ());
751
0
        EXR_SET_ATTR(double, DoubleAttribute, attr->value ());
752
0
        EXR_SET_ATTR(compression, CompressionAttribute, (exr_compression_t)attr->value ());
753
0
        EXR_SET_ATTR(envmap, EnvmapAttribute, (exr_envmap_t)attr->value ());
754
0
        EXR_SET_ATTR(v2i, V2iAttribute,
755
0
                     reinterpret_cast<const exr_attr_v2i_t*>(&(attr->value ())));
756
0
        EXR_SET_ATTR(v2f, V2fAttribute,
757
0
                     reinterpret_cast<const exr_attr_v2f_t*>(&(attr->value ())));
758
0
        EXR_SET_ATTR(v2d, V2dAttribute,
759
0
                     reinterpret_cast<const exr_attr_v2d_t*>(&(attr->value ())));
760
0
        EXR_SET_ATTR(v3i, V3iAttribute,
761
0
                     reinterpret_cast<const exr_attr_v3i_t*>(&(attr->value ())));
762
0
        EXR_SET_ATTR(v3f, V3fAttribute,
763
0
                     reinterpret_cast<const exr_attr_v3f_t*>(&(attr->value ())));
764
0
        EXR_SET_ATTR(v3d, V3dAttribute,
765
0
                     reinterpret_cast<const exr_attr_v3d_t*>(&(attr->value ())));
766
0
        EXR_SET_ATTR(m33f, M33fAttribute,
767
0
                     reinterpret_cast<const exr_attr_m33f_t*>(&(attr->value ())));
768
0
        EXR_SET_ATTR(m33d, M33dAttribute,
769
0
                     reinterpret_cast<const exr_attr_m33d_t*>(&(attr->value ())));
770
0
        EXR_SET_ATTR(m44f, M44fAttribute,
771
0
                     reinterpret_cast<const exr_attr_m44f_t*>(&(attr->value ())));
772
0
        EXR_SET_ATTR(m44d, M44dAttribute,
773
0
                     reinterpret_cast<const exr_attr_m44d_t*>(&(attr->value ())));
774
0
        EXR_SET_ATTR(box2i, Box2iAttribute,
775
0
                     reinterpret_cast<const exr_attr_box2i_t*>(&(attr->value ())));
776
0
        EXR_SET_ATTR(box2f, Box2fAttribute,
777
0
                     reinterpret_cast<const exr_attr_box2f_t*>(&(attr->value ())));
778
779
0
        if (!strcmp (attrT, "chromaticities"))
780
0
        {
781
0
            const ChromaticitiesAttribute *attr =
782
0
                dynamic_cast<const ChromaticitiesAttribute*> (&a);
783
0
            if (!attr)
784
0
                throw IEX_NAMESPACE::ArgExc ("unexpected type mismatch");
785
0
            Chromaticities ac = attr->value ();
786
0
            exr_attr_chromaticities_t cac;
787
788
0
            cac.red_x = ac.red.x;
789
0
            cac.red_y = ac.red.y;
790
0
            cac.green_x = ac.green.x;
791
0
            cac.green_y = ac.green.y;
792
0
            cac.blue_x = ac.blue.x;
793
0
            cac.blue_y = ac.blue.y;
794
0
            cac.white_x = ac.white.x;
795
0
            cac.white_y = ac.white.y;
796
797
0
            rv = exr_attr_set_chromaticities (
798
0
                *_ctxt, partnum, i.name (), &cac);
799
800
0
            if (rv != EXR_ERR_SUCCESS)
801
0
                throw IEX_NAMESPACE::ArgExc ("Unable to copy attribute");
802
0
            continue;
803
0
        }
804
805
0
        if (!strcmp (attrT, "stringvector"))
806
0
        {
807
0
            continue;
808
0
        }
809
810
0
        if (!strcmp (attrT, "floatvector"))
811
0
        {
812
0
            continue;
813
0
        }
814
815
0
        if (!strcmp (attrT, "preview"))
816
0
        {
817
0
            continue;
818
0
        }
819
820
0
        if (!strcmp (attrT, "rational"))
821
0
        {
822
0
            continue;
823
0
        }
824
825
0
        if (!strcmp (attrT, "timecode"))
826
0
        {
827
0
            continue;
828
0
        }
829
830
0
        if (!strcmp (attrT, "keycode"))
831
0
        {
832
0
            continue;
833
0
        }
834
835
0
        if (!strcmp (attrT, "deepImageState"))
836
0
        {
837
0
            continue;
838
0
        }
839
840
        //THROW (
841
        //    IEX_NAMESPACE::LogicExc,
842
        //    "Conversion of attribute '" << i.name () << "' of type '" << attrT
843
        //    << "' to core value not yet implemented");
844
0
    }
845
0
}
846
847
////////////////////////////////////////
848
849
bool
850
Context::chunkTableValid (int partidx) const
851
13.3k
{
852
13.3k
    return exr_validate_chunk_table (*_ctxt, partidx) == EXR_ERR_SUCCESS;
853
13.3k
}
854
855
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT