summaryrefslogtreecommitdiff
path: root/gpr/source/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gpr/source/lib')
-rw-r--r--gpr/source/lib/common/CMakeLists.txt18
-rw-r--r--gpr/source/lib/common/private/gpr_allocator.c44
-rwxr-xr-xgpr/source/lib/common/private/gpr_buffer.c99
-rwxr-xr-xgpr/source/lib/common/private/gpr_buffer_auto.cpp45
-rwxr-xr-xgpr/source/lib/common/private/gpr_buffer_auto.h148
-rwxr-xr-xgpr/source/lib/common/private/log.c60
-rwxr-xr-xgpr/source/lib/common/private/log.h60
-rwxr-xr-xgpr/source/lib/common/private/macros.h84
-rwxr-xr-xgpr/source/lib/common/private/stdc_includes.h33
-rwxr-xr-xgpr/source/lib/common/private/stdcpp_includes.h22
-rwxr-xr-xgpr/source/lib/common/private/timer.c54
-rwxr-xr-xgpr/source/lib/common/private/timer.h51
-rwxr-xr-xgpr/source/lib/common/public/gpr_allocator.h50
-rwxr-xr-xgpr/source/lib/common/public/gpr_buffer.h47
-rwxr-xr-xgpr/source/lib/common/public/gpr_platform.h162
-rwxr-xr-xgpr/source/lib/common/public/gpr_rgb_buffer.h77
-rw-r--r--gpr/source/lib/dng_sdk/BSD-License.txt32
-rw-r--r--gpr/source/lib/dng_sdk/CMakeLists.txt21
-rw-r--r--gpr/source/lib/dng_sdk/RawEnvironment.h12
-rw-r--r--gpr/source/lib/dng_sdk/dng_1d_function.cpp195
-rw-r--r--gpr/source/lib/dng_sdk/dng_1d_function.h159
-rw-r--r--gpr/source/lib/dng_sdk/dng_1d_table.cpp195
-rw-r--r--gpr/source/lib/dng_sdk/dng_1d_table.h122
-rw-r--r--gpr/source/lib/dng_sdk/dng_abort_sniffer.cpp242
-rw-r--r--gpr/source/lib/dng_sdk/dng_abort_sniffer.h244
-rw-r--r--gpr/source/lib/dng_sdk/dng_area_task.cpp270
-rw-r--r--gpr/source/lib/dng_sdk/dng_area_task.h198
-rw-r--r--gpr/source/lib/dng_sdk/dng_assertions.h133
-rw-r--r--gpr/source/lib/dng_sdk/dng_auto_ptr.h259
-rw-r--r--gpr/source/lib/dng_sdk/dng_bad_pixels.cpp1856
-rw-r--r--gpr/source/lib/dng_sdk/dng_bad_pixels.h307
-rw-r--r--gpr/source/lib/dng_sdk/dng_bottlenecks.cpp72
-rw-r--r--gpr/source/lib/dng_sdk/dng_bottlenecks.h1715
-rw-r--r--gpr/source/lib/dng_sdk/dng_camera_profile.cpp1381
-rw-r--r--gpr/source/lib/dng_sdk/dng_camera_profile.h878
-rw-r--r--gpr/source/lib/dng_sdk/dng_classes.h100
-rw-r--r--gpr/source/lib/dng_sdk/dng_color_space.cpp1072
-rw-r--r--gpr/source/lib/dng_sdk/dng_color_space.h351
-rw-r--r--gpr/source/lib/dng_sdk/dng_color_spec.cpp559
-rw-r--r--gpr/source/lib/dng_sdk/dng_color_spec.h146
-rw-r--r--gpr/source/lib/dng_sdk/dng_date_time.cpp961
-rw-r--r--gpr/source/lib/dng_sdk/dng_date_time.h385
-rw-r--r--gpr/source/lib/dng_sdk/dng_errors.h58
-rw-r--r--gpr/source/lib/dng_sdk/dng_exceptions.cpp205
-rw-r--r--gpr/source/lib/dng_sdk/dng_exceptions.h301
-rw-r--r--gpr/source/lib/dng_sdk/dng_exif.cpp4381
-rw-r--r--gpr/source/lib/dng_sdk/dng_exif.h351
-rw-r--r--gpr/source/lib/dng_sdk/dng_fast_module.h31
-rw-r--r--gpr/source/lib/dng_sdk/dng_file_stream.cpp135
-rw-r--r--gpr/source/lib/dng_sdk/dng_file_stream.h78
-rw-r--r--gpr/source/lib/dng_sdk/dng_filter_task.cpp167
-rw-r--r--gpr/source/lib/dng_sdk/dng_filter_task.h157
-rw-r--r--gpr/source/lib/dng_sdk/dng_fingerprint.cpp589
-rw-r--r--gpr/source/lib/dng_sdk/dng_fingerprint.h377
-rw-r--r--gpr/source/lib/dng_sdk/dng_flags.h267
-rw-r--r--gpr/source/lib/dng_sdk/dng_gain_map.cpp582
-rw-r--r--gpr/source/lib/dng_sdk/dng_gain_map.h218
-rw-r--r--gpr/source/lib/dng_sdk/dng_globals.cpp28
-rw-r--r--gpr/source/lib/dng_sdk/dng_globals.h46
-rw-r--r--gpr/source/lib/dng_sdk/dng_host.cpp539
-rw-r--r--gpr/source/lib/dng_sdk/dng_host.h411
-rw-r--r--gpr/source/lib/dng_sdk/dng_hue_sat_map.cpp367
-rw-r--r--gpr/source/lib/dng_sdk/dng_hue_sat_map.h229
-rw-r--r--gpr/source/lib/dng_sdk/dng_ifd.cpp4266
-rw-r--r--gpr/source/lib/dng_sdk/dng_ifd.h305
-rw-r--r--gpr/source/lib/dng_sdk/dng_image.cpp848
-rw-r--r--gpr/source/lib/dng_sdk/dng_image.h433
l---------gpr/source/lib/dng_sdk/dng_image_writer.cpp1
-rw-r--r--gpr/source/lib/dng_sdk/dng_image_writer.h1253
-rw-r--r--gpr/source/lib/dng_sdk/dng_info.cpp2529
-rw-r--r--gpr/source/lib/dng_sdk/dng_info.h163
-rw-r--r--gpr/source/lib/dng_sdk/dng_iptc.cpp987
-rw-r--r--gpr/source/lib/dng_sdk/dng_iptc.h172
-rw-r--r--gpr/source/lib/dng_sdk/dng_jpeg_image.cpp385
-rw-r--r--gpr/source/lib/dng_sdk/dng_jpeg_image.h92
-rw-r--r--gpr/source/lib/dng_sdk/dng_lens_correction.cpp2373
-rw-r--r--gpr/source/lib/dng_sdk/dng_lens_correction.h638
-rw-r--r--gpr/source/lib/dng_sdk/dng_linearization_info.cpp1517
-rw-r--r--gpr/source/lib/dng_sdk/dng_linearization_info.h164
-rw-r--r--gpr/source/lib/dng_sdk/dng_lossless_jpeg.cpp3765
-rw-r--r--gpr/source/lib/dng_sdk/dng_lossless_jpeg.h69
-rw-r--r--gpr/source/lib/dng_sdk/dng_matrix.cpp1080
-rw-r--r--gpr/source/lib/dng_sdk/dng_matrix.h326
-rw-r--r--gpr/source/lib/dng_sdk/dng_memory.cpp204
-rw-r--r--gpr/source/lib/dng_sdk/dng_memory.h515
-rw-r--r--gpr/source/lib/dng_sdk/dng_memory_stream.cpp253
-rw-r--r--gpr/source/lib/dng_sdk/dng_memory_stream.h97
-rw-r--r--gpr/source/lib/dng_sdk/dng_misc_opcodes.cpp1578
-rw-r--r--gpr/source/lib/dng_sdk/dng_misc_opcodes.h417
-rw-r--r--gpr/source/lib/dng_sdk/dng_mosaic_info.cpp1991
-rw-r--r--gpr/source/lib/dng_sdk/dng_mosaic_info.h200
-rw-r--r--gpr/source/lib/dng_sdk/dng_mutex.cpp394
-rw-r--r--gpr/source/lib/dng_sdk/dng_mutex.h177
l---------gpr/source/lib/dng_sdk/dng_negative.cpp1
-rw-r--r--gpr/source/lib/dng_sdk/dng_negative.h2397
-rw-r--r--gpr/source/lib/dng_sdk/dng_opcode_list.cpp274
-rw-r--r--gpr/source/lib/dng_sdk/dng_opcode_list.h165
-rw-r--r--gpr/source/lib/dng_sdk/dng_opcodes.cpp572
-rw-r--r--gpr/source/lib/dng_sdk/dng_opcodes.h507
-rw-r--r--gpr/source/lib/dng_sdk/dng_orientation.cpp233
-rw-r--r--gpr/source/lib/dng_sdk/dng_orientation.h189
-rw-r--r--gpr/source/lib/dng_sdk/dng_parse_utils.cpp3326
-rw-r--r--gpr/source/lib/dng_sdk/dng_parse_utils.h232
-rw-r--r--gpr/source/lib/dng_sdk/dng_pixel_buffer.cpp1819
-rw-r--r--gpr/source/lib/dng_sdk/dng_pixel_buffer.h680
-rw-r--r--gpr/source/lib/dng_sdk/dng_point.cpp22
-rw-r--r--gpr/source/lib/dng_sdk/dng_point.h198
-rw-r--r--gpr/source/lib/dng_sdk/dng_preview.cpp709
-rw-r--r--gpr/source/lib/dng_sdk/dng_preview.h245
-rw-r--r--gpr/source/lib/dng_sdk/dng_pthread.cpp1141
-rw-r--r--gpr/source/lib/dng_sdk/dng_pthread.h267
-rw-r--r--gpr/source/lib/dng_sdk/dng_rational.cpp150
-rw-r--r--gpr/source/lib/dng_sdk/dng_rational.h149
-rw-r--r--gpr/source/lib/dng_sdk/dng_read_image.cpp3194
-rw-r--r--gpr/source/lib/dng_sdk/dng_read_image.h182
-rw-r--r--gpr/source/lib/dng_sdk/dng_rect.cpp168
-rw-r--r--gpr/source/lib/dng_sdk/dng_rect.h494
-rw-r--r--gpr/source/lib/dng_sdk/dng_ref_counted_block.cpp190
-rw-r--r--gpr/source/lib/dng_sdk/dng_ref_counted_block.h291
-rw-r--r--gpr/source/lib/dng_sdk/dng_reference.cpp2783
-rw-r--r--gpr/source/lib/dng_sdk/dng_reference.h521
-rw-r--r--gpr/source/lib/dng_sdk/dng_render.cpp1328
-rw-r--r--gpr/source/lib/dng_sdk/dng_render.h312
-rw-r--r--gpr/source/lib/dng_sdk/dng_resample.cpp781
-rw-r--r--gpr/source/lib/dng_sdk/dng_resample.h261
-rwxr-xr-xgpr/source/lib/dng_sdk/dng_sdk.py192
-rw-r--r--gpr/source/lib/dng_sdk/dng_sdk_limits.h78
-rw-r--r--gpr/source/lib/dng_sdk/dng_shared.cpp3289
-rw-r--r--gpr/source/lib/dng_sdk/dng_shared.h248
-rw-r--r--gpr/source/lib/dng_sdk/dng_simple_image.cpp197
-rw-r--r--gpr/source/lib/dng_sdk/dng_simple_image.h82
-rw-r--r--gpr/source/lib/dng_sdk/dng_spline.cpp233
-rw-r--r--gpr/source/lib/dng_sdk/dng_spline.h83
-rw-r--r--gpr/source/lib/dng_sdk/dng_stream.cpp1221
-rw-r--r--gpr/source/lib/dng_sdk/dng_stream.h698
-rw-r--r--gpr/source/lib/dng_sdk/dng_string.cpp2242
-rw-r--r--gpr/source/lib/dng_sdk/dng_string.h165
-rw-r--r--gpr/source/lib/dng_sdk/dng_string_list.cpp162
-rw-r--r--gpr/source/lib/dng_sdk/dng_string_list.h86
-rw-r--r--gpr/source/lib/dng_sdk/dng_tag_codes.h543
-rw-r--r--gpr/source/lib/dng_sdk/dng_tag_types.cpp66
-rw-r--r--gpr/source/lib/dng_sdk/dng_tag_types.h52
-rw-r--r--gpr/source/lib/dng_sdk/dng_tag_values.h485
-rw-r--r--gpr/source/lib/dng_sdk/dng_temperature.cpp259
-rw-r--r--gpr/source/lib/dng_sdk/dng_temperature.h97
-rw-r--r--gpr/source/lib/dng_sdk/dng_tile_iterator.cpp199
-rw-r--r--gpr/source/lib/dng_sdk/dng_tile_iterator.h76
-rw-r--r--gpr/source/lib/dng_sdk/dng_tone_curve.cpp138
-rw-r--r--gpr/source/lib/dng_sdk/dng_tone_curve.h66
-rw-r--r--gpr/source/lib/dng_sdk/dng_types.h112
-rw-r--r--gpr/source/lib/dng_sdk/dng_uncopyable.h48
-rw-r--r--gpr/source/lib/dng_sdk/dng_utils.cpp706
-rw-r--r--gpr/source/lib/dng_sdk/dng_utils.h1237
-rw-r--r--gpr/source/lib/dng_sdk/dng_validate.cpp879
-rw-r--r--gpr/source/lib/dng_sdk/dng_xmp.cpp4417
-rw-r--r--gpr/source/lib/dng_sdk/dng_xmp.h405
-rw-r--r--gpr/source/lib/dng_sdk/dng_xmp_sdk.cpp1670
-rw-r--r--gpr/source/lib/dng_sdk/dng_xmp_sdk.h238
-rw-r--r--gpr/source/lib/dng_sdk/dng_xy_coord.cpp89
-rw-r--r--gpr/source/lib/dng_sdk/dng_xy_coord.h187
-rw-r--r--gpr/source/lib/expat_lib/CMakeLists.txt21
-rw-r--r--gpr/source/lib/expat_lib/amigaconfig.h29
-rw-r--r--gpr/source/lib/expat_lib/ascii.h92
-rw-r--r--gpr/source/lib/expat_lib/asciitab.h36
-rw-r--r--gpr/source/lib/expat_lib/expat.h1047
-rw-r--r--gpr/source/lib/expat_lib/expat_external.h115
-rw-r--r--gpr/source/lib/expat_lib/iasciitab.h37
-rw-r--r--gpr/source/lib/expat_lib/internal.h79
-rw-r--r--gpr/source/lib/expat_lib/latin1tab.h36
-rw-r--r--gpr/source/lib/expat_lib/macconfig.h50
-rw-r--r--gpr/source/lib/expat_lib/nametab.h150
-rw-r--r--gpr/source/lib/expat_lib/utf8tab.h37
-rw-r--r--gpr/source/lib/expat_lib/winconfig.h27
l---------gpr/source/lib/expat_lib/xmlparse.c1
-rw-r--r--gpr/source/lib/expat_lib/xmlrole.c1336
-rw-r--r--gpr/source/lib/expat_lib/xmlrole.h114
-rw-r--r--gpr/source/lib/expat_lib/xmltok.c1664
-rw-r--r--gpr/source/lib/expat_lib/xmltok.h316
-rw-r--r--gpr/source/lib/expat_lib/xmltok_impl.c1797
-rw-r--r--gpr/source/lib/expat_lib/xmltok_impl.h46
-rw-r--r--gpr/source/lib/expat_lib/xmltok_ns.c115
-rw-r--r--gpr/source/lib/gpr_sdk/CMakeLists.txt44
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr.cpp1849
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_exif_info.cpp105
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_image_writer.cpp129
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_image_writer.h87
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_profile_info.cpp57
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_read_image.cpp129
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_read_image.h64
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_tuning_info.cpp84
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_utils.cpp73
-rwxr-xr-xgpr/source/lib/gpr_sdk/private/gpr_utils.h40
-rwxr-xr-xgpr/source/lib/gpr_sdk/public/gpr.h169
-rwxr-xr-xgpr/source/lib/gpr_sdk/public/gpr_exif_info.h352
-rwxr-xr-xgpr/source/lib/gpr_sdk/public/gpr_profile_info.h60
-rwxr-xr-xgpr/source/lib/gpr_sdk/public/gpr_tuning_info.h149
-rw-r--r--gpr/source/lib/md5_lib/CMakeLists.txt23
-rwxr-xr-xgpr/source/lib/md5_lib/md5.c257
-rwxr-xr-xgpr/source/lib/md5_lib/md5.h60
-rw-r--r--gpr/source/lib/tiny_jpeg/CMakeLists.txt23
-rw-r--r--gpr/source/lib/tiny_jpeg/jpeg.c3
-rw-r--r--gpr/source/lib/tiny_jpeg/jpeg.h27
-rw-r--r--gpr/source/lib/tiny_jpeg/tiny_jpeg.h1308
-rw-r--r--gpr/source/lib/vc5_common/CMakeLists.txt20
-rwxr-xr-xgpr/source/lib/vc5_common/bitstream.c445
-rwxr-xr-xgpr/source/lib/vc5_common/bitstream.h135
-rwxr-xr-xgpr/source/lib/vc5_common/codec.c201
-rwxr-xr-xgpr/source/lib/vc5_common/codec.h315
-rwxr-xr-xgpr/source/lib/vc5_common/codeset.h44
-rwxr-xr-xgpr/source/lib/vc5_common/common.h53
-rwxr-xr-xgpr/source/lib/vc5_common/companding.c259
-rwxr-xr-xgpr/source/lib/vc5_common/companding.h46
-rwxr-xr-xgpr/source/lib/vc5_common/config.h87
-rwxr-xr-xgpr/source/lib/vc5_common/error.h88
-rwxr-xr-xgpr/source/lib/vc5_common/image.c321
-rwxr-xr-xgpr/source/lib/vc5_common/image.h165
-rwxr-xr-xgpr/source/lib/vc5_common/logcurve.c58
-rwxr-xr-xgpr/source/lib/vc5_common/logcurve.h42
-rwxr-xr-xgpr/source/lib/vc5_common/pixel.h100
-rwxr-xr-xgpr/source/lib/vc5_common/stream.c524
-rwxr-xr-xgpr/source/lib/vc5_common/stream.h133
-rwxr-xr-xgpr/source/lib/vc5_common/syntax.c150
-rwxr-xr-xgpr/source/lib/vc5_common/syntax.h129
-rwxr-xr-xgpr/source/lib/vc5_common/table17.inc290
-rwxr-xr-xgpr/source/lib/vc5_common/types.h94
-rwxr-xr-xgpr/source/lib/vc5_common/unique.h42
-rwxr-xr-xgpr/source/lib/vc5_common/utilities.c82
-rwxr-xr-xgpr/source/lib/vc5_common/utilities.h36
-rw-r--r--gpr/source/lib/vc5_common/vc5_common.h34
-rwxr-xr-xgpr/source/lib/vc5_common/wavelet.c519
-rwxr-xr-xgpr/source/lib/vc5_common/wavelet.h126
-rw-r--r--gpr/source/lib/vc5_decoder/CMakeLists.txt22
-rwxr-xr-xgpr/source/lib/vc5_decoder/codebooks.c36
-rwxr-xr-xgpr/source/lib/vc5_decoder/codebooks.h50
-rwxr-xr-xgpr/source/lib/vc5_decoder/component.c111
-rwxr-xr-xgpr/source/lib/vc5_decoder/component.h36
-rwxr-xr-xgpr/source/lib/vc5_decoder/decoder.c2310
-rwxr-xr-xgpr/source/lib/vc5_decoder/decoder.h336
-rwxr-xr-xgpr/source/lib/vc5_decoder/dequantize.c88
-rwxr-xr-xgpr/source/lib/vc5_decoder/dequantize.h36
-rwxr-xr-xgpr/source/lib/vc5_decoder/headers.h49
-rwxr-xr-xgpr/source/lib/vc5_decoder/inverse.c1188
-rwxr-xr-xgpr/source/lib/vc5_decoder/inverse.h51
-rwxr-xr-xgpr/source/lib/vc5_decoder/parameters.c47
-rwxr-xr-xgpr/source/lib/vc5_decoder/parameters.h119
-rwxr-xr-xgpr/source/lib/vc5_decoder/raw.c135
-rwxr-xr-xgpr/source/lib/vc5_decoder/raw.h35
-rwxr-xr-xgpr/source/lib/vc5_decoder/syntax.c116
-rwxr-xr-xgpr/source/lib/vc5_decoder/syntax.h44
-rwxr-xr-xgpr/source/lib/vc5_decoder/vc5_decoder.c132
-rwxr-xr-xgpr/source/lib/vc5_decoder/vc5_decoder.h84
-rwxr-xr-xgpr/source/lib/vc5_decoder/vlc.c109
-rwxr-xr-xgpr/source/lib/vc5_decoder/vlc.h103
-rwxr-xr-xgpr/source/lib/vc5_decoder/wavelet.c173
-rwxr-xr-xgpr/source/lib/vc5_decoder/wavelet.h42
-rw-r--r--gpr/source/lib/vc5_encoder/CMakeLists.txt21
-rwxr-xr-xgpr/source/lib/vc5_encoder/codebooks.c425
-rwxr-xr-xgpr/source/lib/vc5_encoder/codebooks.h71
-rwxr-xr-xgpr/source/lib/vc5_encoder/component.c403
-rwxr-xr-xgpr/source/lib/vc5_encoder/component.h100
-rwxr-xr-xgpr/source/lib/vc5_encoder/encoder.c2555
-rwxr-xr-xgpr/source/lib/vc5_encoder/encoder.h333
-rwxr-xr-xgpr/source/lib/vc5_encoder/forward.c851
-rwxr-xr-xgpr/source/lib/vc5_encoder/forward.h38
-rwxr-xr-xgpr/source/lib/vc5_encoder/headers.h50
-rwxr-xr-xgpr/source/lib/vc5_encoder/parameters.c86
-rwxr-xr-xgpr/source/lib/vc5_encoder/parameters.h139
-rwxr-xr-xgpr/source/lib/vc5_encoder/raw.c621
-rwxr-xr-xgpr/source/lib/vc5_encoder/raw.h36
-rwxr-xr-xgpr/source/lib/vc5_encoder/sections.c293
-rwxr-xr-xgpr/source/lib/vc5_encoder/sections.h91
-rwxr-xr-xgpr/source/lib/vc5_encoder/syntax.c276
-rwxr-xr-xgpr/source/lib/vc5_encoder/syntax.h44
-rwxr-xr-xgpr/source/lib/vc5_encoder/vc5_encoder.c164
-rwxr-xr-xgpr/source/lib/vc5_encoder/vc5_encoder.h103
-rwxr-xr-xgpr/source/lib/vc5_encoder/vlc.c94
-rwxr-xr-xgpr/source/lib/vc5_encoder/vlc.h138
-rw-r--r--gpr/source/lib/xmp_core/BSD-License.txt32
-rw-r--r--gpr/source/lib/xmp_core/CMakeLists.txt32
-rw-r--r--gpr/source/lib/xmp_core/ExpatAdapter.cpp522
-rw-r--r--gpr/source/lib/xmp_core/ExpatAdapter.hpp59
-rw-r--r--gpr/source/lib/xmp_core/ParseRDF.cpp1459
-rw-r--r--gpr/source/lib/xmp_core/UnicodeConversions.cpp1654
-rw-r--r--gpr/source/lib/xmp_core/UnicodeConversions.hpp115
-rw-r--r--gpr/source/lib/xmp_core/UnicodeInlines.incl_cpp129
-rw-r--r--gpr/source/lib/xmp_core/WXMPIterator.cpp170
-rw-r--r--gpr/source/lib/xmp_core/WXMPMeta.cpp1191
-rw-r--r--gpr/source/lib/xmp_core/WXMPUtils.cpp634
-rw-r--r--gpr/source/lib/xmp_core/XMLParserAdapter.hpp155
-rw-r--r--gpr/source/lib/xmp_core/XML_Node.cpp473
-rw-r--r--gpr/source/lib/xmp_core/XMPCore_Impl.cpp1390
-rw-r--r--gpr/source/lib/xmp_core/XMPCore_Impl.hpp392
-rw-r--r--gpr/source/lib/xmp_core/XMPIterator.cpp637
-rw-r--r--gpr/source/lib/xmp_core/XMPIterator.hpp144
-rw-r--r--gpr/source/lib/xmp_core/XMPMeta-GetSet.cpp1309
-rw-r--r--gpr/source/lib/xmp_core/XMPMeta-Parse.cpp1277
-rw-r--r--gpr/source/lib/xmp_core/XMPMeta-Serialize.cpp1396
-rw-r--r--gpr/source/lib/xmp_core/XMPMeta.cpp1381
-rw-r--r--gpr/source/lib/xmp_core/XMPMeta.hpp428
-rw-r--r--gpr/source/lib/xmp_core/XMPUtils-FileInfo.cpp1493
-rw-r--r--gpr/source/lib/xmp_core/XMPUtils.cpp2000
-rw-r--r--gpr/source/lib/xmp_core/XMPUtils.hpp198
-rw-r--r--gpr/source/lib/xmp_core/XMP_BuildInfo.h17
-rw-r--r--gpr/source/lib/xmp_core/XMP_LibUtils.cpp705
-rw-r--r--gpr/source/lib/xmp_core/XMP_LibUtils.hpp619
-rw-r--r--gpr/source/lib/xmp_core/public/include/TXMPFiles.hpp855
-rw-r--r--gpr/source/lib/xmp_core/public/include/TXMPIterator.hpp235
-rw-r--r--gpr/source/lib/xmp_core/public/include/TXMPMeta.hpp1751
-rw-r--r--gpr/source/lib/xmp_core/public/include/TXMPUtils.hpp967
-rw-r--r--gpr/source/lib/xmp_core/public/include/XMP.hpp98
-rw-r--r--gpr/source/lib/xmp_core/public/include/XMP.incl_cpp69
-rw-r--r--gpr/source/lib/xmp_core/public/include/XMP_Const.h1560
-rw-r--r--gpr/source/lib/xmp_core/public/include/XMP_Environment.h165
-rw-r--r--gpr/source/lib/xmp_core/public/include/XMP_IO.hpp171
-rw-r--r--gpr/source/lib/xmp_core/public/include/XMP_Version.h52
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/TXMPFiles.incl_cpp484
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/TXMPIterator.incl_cpp223
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/TXMPMeta.incl_cpp914
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/TXMPUtils.incl_cpp445
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/WXMPFiles.hpp281
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/WXMPIterator.hpp74
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/WXMPMeta.hpp621
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/WXMPUtils.hpp315
-rw-r--r--gpr/source/lib/xmp_core/public/include/client-glue/WXMP_Common.hpp128
324 files changed, 152932 insertions, 0 deletions
diff --git a/gpr/source/lib/common/CMakeLists.txt b/gpr/source/lib/common/CMakeLists.txt
new file mode 100644
index 0000000..103b6c2
--- /dev/null
+++ b/gpr/source/lib/common/CMakeLists.txt
@@ -0,0 +1,18 @@
+# library
+set( LIB_NAME common )
+
+# get source files
+file( GLOB SRC_FILES "private/*.cpp" "private/*.c" )
+
+# get include files
+file( GLOB INC_FILES "private/*.h" "public/*.h" )
+
+include_directories( "./public" )
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/common/private/gpr_allocator.c b/gpr/source/lib/common/private/gpr_allocator.c
new file mode 100644
index 0000000..366bdf8
--- /dev/null
+++ b/gpr/source/lib/common/private/gpr_allocator.c
@@ -0,0 +1,44 @@
+/*! @file gpr_allocator.c
+ *
+ * @brief Implementation of the global memory allocation functions.
+ * In order to customize memory allocation and deallocation, applications
+ * can implement these functions in additional files and include in
+ * build process
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gpr_allocator.h"
+
+/*!
+ @brief Allocate a block with the specified size
+ */
+void* gpr_global_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+/*!
+ @brief Free a block that was allocated by the specified allocator
+
+ It is an error to free a block allocated by one allocator using a
+ different allocator.
+ */
+void gpr_global_free(void *block)
+{
+ free(block);
+}
+
diff --git a/gpr/source/lib/common/private/gpr_buffer.c b/gpr/source/lib/common/private/gpr_buffer.c
new file mode 100755
index 0000000..083bc0d
--- /dev/null
+++ b/gpr/source/lib/common/private/gpr_buffer.c
@@ -0,0 +1,99 @@
+/*! @file gpr_buffer.c
+ *
+ * @brief Implementation of gpr_buffer object and functions that work on buffer
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gpr_buffer.h"
+#include "macros.h"
+#include "stdc_includes.h"
+
+int read_from_file(gpr_buffer* buffer, const char* file_path, gpr_malloc malloc_function, gpr_free free_function)
+{
+ assert( buffer != NULL );
+
+ FILE *fIN = fopen(file_path, "rb");
+ if (fIN == NULL)
+ {
+ fprintf (stderr, "Error while reading file: %s", file_path);
+ return -1;
+ }
+
+ fseek (fIN, 0, SEEK_END);
+ buffer->size = (size_t) ftell(fIN);
+ rewind (fIN);
+
+ buffer->buffer = malloc_function(buffer->size);
+
+ if ( buffer->buffer == NULL)
+ {
+ fputs ("Memory error", stderr);
+ fclose(fIN);
+ return -1;
+ }
+
+ if (fread(buffer->buffer, 1, buffer->size, fIN) != buffer->size)
+ {
+ free_function(buffer->buffer);
+ fputs ("Reading error", stderr);
+ fclose(fIN);
+ return -1;
+ }
+
+ fclose(fIN);
+
+ return 0;
+}
+
+int write_to_file(const gpr_buffer* buffer, const char* file_path)
+{
+ unsigned int bytes_written;
+
+ FILE *fOUT = fopen(file_path, "wb");
+ if (fOUT == NULL)
+ {
+ fprintf (stderr, "Error while writing file: %s", file_path);
+ return -1;
+ }
+
+ bytes_written = fwrite(buffer->buffer, 1, buffer->size, fOUT);
+ if( bytes_written != buffer->size ) {
+ fputs("Could not write bytes \n", stderr);
+ perror("fwrite()");
+ fclose(fOUT);
+ return -2;
+ }
+
+ fclose(fOUT);
+
+ return 0;
+}
+
+#include "gpr_rgb_buffer.h"
+
+void gpr_rgb_gain_set_defaults(gpr_rgb_gain* x)
+{
+ x->r_gain_num = 30;
+ x->r_gain_pow2_den = 4;
+
+ x->g_gain_num = 1;
+ x->g_gain_pow2_den = 0;
+
+ x->b_gain_num = 7;
+ x->b_gain_pow2_den = 2;
+}
+
diff --git a/gpr/source/lib/common/private/gpr_buffer_auto.cpp b/gpr/source/lib/common/private/gpr_buffer_auto.cpp
new file mode 100755
index 0000000..736c139
--- /dev/null
+++ b/gpr/source/lib/common/private/gpr_buffer_auto.cpp
@@ -0,0 +1,45 @@
+/*! @file gpr_buffer_auto.cpp
+ *
+ * @brief Implementation of gpr_buffer_auto object.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gpr_buffer.h"
+#include "gpr_buffer_auto.h"
+
+#include <stdlib.h>
+
+int gpr_buffer_auto::read_from_file(const char* file_path)
+{
+ assert( is_valid() == false );
+
+ int return_code = ::read_from_file(&buffer, file_path, mem_alloc, mem_free );
+
+ if( return_code == 0 )
+ {
+ free_in_destructor = true;
+ }
+
+ return return_code;
+}
+
+int gpr_buffer_auto::write_to_file(const char* file_path)
+{
+ assert( is_valid() );
+
+ return ::write_to_file(&buffer, file_path);
+}
diff --git a/gpr/source/lib/common/private/gpr_buffer_auto.h b/gpr/source/lib/common/private/gpr_buffer_auto.h
new file mode 100755
index 0000000..e4a2eee
--- /dev/null
+++ b/gpr/source/lib/common/private/gpr_buffer_auto.h
@@ -0,0 +1,148 @@
+/*! @file gpr_internal_buffer
+ *
+ * @brief Declaration of gpr_buffer_auto object. This object
+ * implements a buffer that carries size information. gpr_buffer_auto can
+ * deallocate itself in destructor (depending on free_in_destructor member)
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_INTERNAL_BUFFER_H
+#define GPR_INTERNAL_BUFFER_H
+
+#include "gpr_allocator.h"
+#include "gpr_buffer.h"
+#include "gpr_platform.h"
+#include "stdc_includes.h"
+
+class gpr_buffer_auto
+{
+private:
+ gpr_buffer buffer;
+
+ bool free_in_destructor;
+
+ gpr_malloc mem_alloc;
+
+ gpr_free mem_free;
+
+public:
+ void reset()
+ {
+ buffer.buffer = NULL;
+ buffer.size = 0;
+ free_in_destructor = false;
+ }
+
+ gpr_buffer_auto(gpr_malloc malloc_function, gpr_free free_function)
+ {
+ reset();
+
+ mem_alloc = malloc_function;
+ mem_free = free_function;
+ }
+
+ ~gpr_buffer_auto()
+ {
+ deallocate();
+ }
+
+ void allocate(size_t size_of_memory)
+ {
+ assert(buffer.buffer == NULL);
+ assert(buffer.size == 0);
+
+ buffer.size = size_of_memory;
+
+ if(buffer.size > 0)
+ {
+ buffer.buffer = mem_alloc(buffer.size);
+ assert(buffer.buffer);
+
+ free_in_destructor = true;
+ }
+ }
+
+ void deallocate()
+ {
+ if(buffer.buffer && free_in_destructor)
+ mem_free( (char*)buffer.buffer );
+
+ reset();
+ }
+
+ void resize( size_t new_size )
+ {
+ buffer.size = new_size;
+
+ assert(buffer.buffer);
+ assert(buffer.size);
+ }
+
+ void set(void* _buffer, size_t _size, bool _free_in_destructor = false )
+ {
+ assert(buffer.buffer == NULL);
+ assert(buffer.size == 0);
+
+ buffer.buffer = _buffer;
+ buffer.size = _size;
+ free_in_destructor = _free_in_destructor;
+
+ assert(buffer.buffer);
+ assert(buffer.size);
+ }
+
+ void zero()
+ {
+ // Cant call zero for the case when buffer has been preallocated
+ // Call deallocate()
+ assert( free_in_destructor == false );
+
+ buffer.buffer = NULL;
+ buffer.size = 0;
+ }
+
+ bool is_valid() const
+ {
+ return ( buffer.buffer != NULL ) && buffer.size > 0;
+ }
+
+// Accessors
+ void* get_buffer() const { return buffer.buffer; }
+
+ char* to_char() const { return (char*)buffer.buffer; }
+
+ unsigned char* to_uchar() const { return (unsigned char*)buffer.buffer; }
+
+ unsigned short* to_ushort() const { return (unsigned short*)buffer.buffer; }
+
+ uint16_t* to_uint16_t() const { return (uint16_t*)buffer.buffer; }
+
+ size_t get_size() const { return buffer.size; }
+
+ gpr_malloc get_malloc() const { return mem_alloc; }
+
+ gpr_free get_free() const { return mem_free; }
+
+// Operations
+ int read_from_file(const char* file_path);
+
+ int write_to_file(const char* file_path);
+
+ const gpr_buffer& get_gpr_buffer() { return buffer; }
+};
+
+#endif // GPR_INTERNAL_BUFFER_H
diff --git a/gpr/source/lib/common/private/log.c b/gpr/source/lib/common/private/log.c
new file mode 100755
index 0000000..751ff6d
--- /dev/null
+++ b/gpr/source/lib/common/private/log.c
@@ -0,0 +1,60 @@
+/*! @file gpr_log.c
+ *
+ * @brief Implementation of functions used for logging
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "timer.h"
+#include "stdc_includes.h"
+
+TIMER LogTimer;
+
+bool LogInit(void)
+{
+ InitTimer(&LogTimer);
+
+ return true;
+}
+
+#ifndef LogPrint
+int LogPrint(const char* format, ... )
+{
+ StopTimer(&LogTimer);
+
+ printf("[%5d-ms] ", (unsigned int)TimeMSecs(&LogTimer));
+
+ {
+ va_list argptr;
+ va_start(argptr, format);
+
+ vfprintf(stdout, format, argptr);
+
+ va_end(argptr);
+ }
+
+ printf( "%c", '\n' );
+
+ StartTimer(&LogTimer);
+
+ return 0;
+}
+#endif // LogPrint
+
+bool LogUninit(void)
+{
+ return true;
+}
diff --git a/gpr/source/lib/common/private/log.h b/gpr/source/lib/common/private/log.h
new file mode 100755
index 0000000..76e8879
--- /dev/null
+++ b/gpr/source/lib/common/private/log.h
@@ -0,0 +1,60 @@
+/*! @file gpr_log.h
+ *
+ * @brief Declatation of functions used for logging
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_LOG_H
+#define GPR_LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ bool LogInit(void);
+
+ #ifndef LogPrint
+ int LogPrint(const char* format, ... );
+ #endif
+
+ bool LogUninit(void);
+
+ #define TIMESTAMP(x, y) TIMESTAMP_##y(x)
+
+ #if GPR_TIMING == 0
+ #define TIMESTAMP_3(x)
+ #define TIMESTAMP_2(x)
+ #define TIMESTAMP_1(x)
+ #elif GPR_TIMING == 1
+ #define TIMESTAMP_3(x)
+ #define TIMESTAMP_2(x)
+ #define TIMESTAMP_1(x) LogPrint("%s %s() %s (line %d)", x, __FUNCTION__, __FILE__, __LINE__);
+ #elif GPR_TIMING == 2
+ #define TIMESTAMP_3(x)
+ #define TIMESTAMP_2(x) LogPrint("%s %s() %s (line %d)", x, __FUNCTION__, __FILE__, __LINE__);
+ #define TIMESTAMP_1(x) LogPrint("%s %s() %s (line %d)", x, __FUNCTION__, __FILE__, __LINE__);
+ #elif GPR_TIMING == 3
+ #define TIMESTAMP_3(x) LogPrint("%s %s() %s (line %d)", x, __FUNCTION__, __FILE__, __LINE__);
+ #define TIMESTAMP_2(x) LogPrint("%s %s() %s (line %d)", x, __FUNCTION__, __FILE__, __LINE__);
+ #define TIMESTAMP_1(x) LogPrint("%s %s() %s (line %d)", x, __FUNCTION__, __FILE__, __LINE__);
+ #endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPR_LOG_H
diff --git a/gpr/source/lib/common/private/macros.h b/gpr/source/lib/common/private/macros.h
new file mode 100755
index 0000000..5f3e9b5
--- /dev/null
+++ b/gpr/source/lib/common/private/macros.h
@@ -0,0 +1,84 @@
+/*! @file gpr_macros.h
+ *
+ * @brief Definitions of useful inline functions that are used everywhere in code.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_MACROS_H
+#define GPR_MACROS_H
+
+#ifndef neg
+ #define neg(x) (-(x))
+#endif
+
+#define DivideByShift(x, s) ((x) >> (s))
+
+STATIC_INLINE uint16_t clamp_uint(int32_t value, uint32_t precision)
+{
+ const int32_t limit = ((1 << precision) - 1);
+
+ if (value < 0)
+ value = 0;
+ else if (value > limit)
+ value = limit;
+
+ return (uint16_t)value;
+}
+
+STATIC_INLINE uint16_t clamp_uint16(int32_t value)
+{
+ return (uint16_t)clamp_uint( value, 16);
+}
+
+STATIC_INLINE uint16_t clamp_uint14(int32_t value)
+{
+ return (uint16_t)clamp_uint( value, 14);
+}
+
+STATIC_INLINE uint16_t clamp_uint12(int32_t value)
+{
+ return (uint16_t)clamp_uint( value, 12);
+}
+
+STATIC_INLINE uint8_t clamp_uint8(int32_t value)
+{
+ return (uint8_t)clamp_uint( value, 8);
+}
+
+STATIC_INLINE int minimum(int a, int b)
+{
+ return (a < b) ? a : b;
+}
+
+STATIC_INLINE int maximum(int a, int b)
+{
+ return (a < b) ? b : a;
+}
+
+STATIC_INLINE int absolute(int a)
+{
+ return (a < 0) ? -a : a;
+}
+
+STATIC_INLINE uint32_t Swap32(uint32_t value)
+{
+ value = (value & 0x0000FFFF) << 16 | (value & 0xFFFF0000) >> 16;
+ value = (value & 0x00FF00FF) << 8 | (value & 0xFF00FF00) >> 8;
+ return value;
+}
+
+#endif // GPR_MACROS_H
diff --git a/gpr/source/lib/common/private/stdc_includes.h b/gpr/source/lib/common/private/stdc_includes.h
new file mode 100755
index 0000000..dff18de
--- /dev/null
+++ b/gpr/source/lib/common/private/stdc_includes.h
@@ -0,0 +1,33 @@
+/*! @file stdc_includes.h
+ *
+ * @brief Standard C include files used by package
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <assert.h>
+#include <limits.h>
+#include <math.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <string.h>
+#include <time.h> \ No newline at end of file
diff --git a/gpr/source/lib/common/private/stdcpp_includes.h b/gpr/source/lib/common/private/stdcpp_includes.h
new file mode 100755
index 0000000..3da3a27
--- /dev/null
+++ b/gpr/source/lib/common/private/stdcpp_includes.h
@@ -0,0 +1,22 @@
+/*! @file stdcpp_includes.h
+ *
+ * @brief Standard C++ include files used by package
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fstream>
+
diff --git a/gpr/source/lib/common/private/timer.c b/gpr/source/lib/common/private/timer.c
new file mode 100755
index 0000000..4db60e7
--- /dev/null
+++ b/gpr/source/lib/common/private/timer.c
@@ -0,0 +1,54 @@
+/*! @file gpr_timer.c
+ *
+ * @brief Implementation of a high-resolution performance timer.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "timer.h"
+
+/*!
+ @brief Initialize a timer
+
+ The frequency of the performance timer is determined if it has not
+ already been obtained.
+ */
+void InitTimer(TIMER *timer)
+{
+ timer->begin = 0;
+ timer->elapsed = 0;
+}
+
+void StartTimer(TIMER *timer)
+{
+ timer->begin = clock();
+}
+
+void StopTimer(TIMER *timer)
+{
+ timer->elapsed += (clock() - timer->begin);
+}
+
+float TimeSecs(TIMER *timer)
+{
+ return (float)(timer->elapsed) / CLOCKS_PER_SEC;
+}
+
+float TimeMSecs(TIMER *timer)
+{
+ return (float)(TimeSecs(timer) * 1000);
+}
+
diff --git a/gpr/source/lib/common/private/timer.h b/gpr/source/lib/common/private/timer.h
new file mode 100755
index 0000000..9e05869
--- /dev/null
+++ b/gpr/source/lib/common/private/timer.h
@@ -0,0 +1,51 @@
+/*! @file gpr_timer.h
+ *
+ * @brief Declaration of a high-resolution performance timer.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_TIMER_H
+#define GPR_TIMER_H
+
+#include <time.h>
+
+typedef struct timer
+{
+ clock_t begin;
+ clock_t elapsed;
+
+} TIMER;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void InitTimer(TIMER *timer);
+
+ void StartTimer(TIMER *timer);
+
+ void StopTimer(TIMER *timer);
+
+ float TimeSecs(TIMER *timer);
+
+ float TimeMSecs(TIMER *timer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPR_TIMER_H
diff --git a/gpr/source/lib/common/public/gpr_allocator.h b/gpr/source/lib/common/public/gpr_allocator.h
new file mode 100755
index 0000000..0f002a0
--- /dev/null
+++ b/gpr/source/lib/common/public/gpr_allocator.h
@@ -0,0 +1,50 @@
+/*! @file gpr_allocator.h
+ *
+ * @brief The API for memory allocation and deallocation functions.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_ALLOCATOR_H
+#define GPR_ALLOCATOR_H
+
+#include "gpr_platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void* gpr_global_malloc(size_t size);
+
+ extern void gpr_global_free(void *block);
+
+ typedef void* (*gpr_malloc)(size_t size); /* Malloc callback function typedef */
+
+ typedef void (*gpr_free)(void* p); /* Free callback function typedef */
+
+ typedef struct
+ {
+ gpr_malloc Alloc; // Callback function to allocate memory
+
+ gpr_free Free; // Callback function to free memory
+
+ } gpr_allocator;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPR_ALLOCATOR_H
diff --git a/gpr/source/lib/common/public/gpr_buffer.h b/gpr/source/lib/common/public/gpr_buffer.h
new file mode 100755
index 0000000..beefb23
--- /dev/null
+++ b/gpr/source/lib/common/public/gpr_buffer.h
@@ -0,0 +1,47 @@
+/*! @file gpr_buffer.h
+ *
+ * @brief Declaration of gpr_buffer object and functions that work on buffer
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_BUFFER_H
+#define GPR_BUFFER_H
+
+#include "gpr_allocator.h"
+#include "gpr_platform.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef struct
+ {
+ void* buffer; /* Address to the memory location that this buffer points to */
+
+ size_t size; /* Size of the memory block */
+
+ } gpr_buffer;
+
+ int read_from_file(gpr_buffer* buffer, const char* file_path, gpr_malloc malloc_function, gpr_free free_function);
+
+ int write_to_file(const gpr_buffer* buffer, const char* file_path);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // GPR_BUFFER_H
diff --git a/gpr/source/lib/common/public/gpr_platform.h b/gpr/source/lib/common/public/gpr_platform.h
new file mode 100755
index 0000000..14ffcc5
--- /dev/null
+++ b/gpr/source/lib/common/public/gpr_platform.h
@@ -0,0 +1,162 @@
+/*! @file gpr_platform.h
+ *
+ * @brief Definitions of platform related settings
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_PLATFORM_H
+#define GPR_PLATFORM_H
+
+// =================================================================================================
+// Timing output. Define to:
+// 0 for applications (disabled all timing code)
+// 1 to enable top level timing
+// 2 to enable low level timing
+// =================================================================================================
+
+#ifndef GPR_TIMING
+ #define GPR_TIMING 1
+#endif
+
+// =================================================================================================
+// Defines to enable encoder and decoder API in GPR-SDK
+// =================================================================================================
+
+#ifndef GPR_WRITING
+ #define GPR_WRITING 1
+#endif
+
+#ifndef GPR_READING
+ #define GPR_READING 1
+#endif
+
+#ifndef GPR_JPEG_AVAILABLE
+ #define GPR_JPEG_AVAILABLE 1
+#endif
+
+// =================================================================================================
+// Flags to enable/disable SIMD code
+// =================================================================================================
+
+// Neon code is implemented for encoder
+#ifndef NEON
+ #define NEON 0
+#endif
+
+// SSE code is not implemented yet
+#ifndef SSE
+ #define SSE 0
+#endif
+
+// =================================================================================================
+// Do not change lines below
+// =================================================================================================
+
+// =================================================================================================
+// Common header files needed by GPR-SDK
+// =================================================================================================
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifndef float_t
+typedef float float_t;
+#endif
+
+#ifdef _WIN32
+
+// Turn off warnings about deprecated functions
+#pragma warning(disable: 4996)
+
+#define INLINE __inline
+
+#else
+
+#define INLINE inline
+
+#endif // _WIN32
+
+#define STATIC static
+
+#define STATIC_INLINE STATIC INLINE
+
+#define ENABLED(x) (x)
+
+// =================================================================================================
+// Determine the Platform
+// =================================================================================================
+
+#ifdef _WIN32
+
+ #define qWinOS 1
+ #define qMacOS 0
+ #define qLinux 0
+ #define qiPhone 0
+ #define qAndroid 0
+
+#elif __APPLE__
+
+ #include "TargetConditionals.h"
+
+ #define qEnableCarbon 0 // Disable Carbon API because it is old and deprecated by Apple
+
+ #if TARGET_OS_IPHONE
+
+ #define qWinOS 0
+ #define qMacOS 0
+ #define qLinux 0
+ #define qiPhone 1
+ #define qAndroid 0
+
+ #else
+
+ #define qWinOS 0
+ #define qMacOS 1
+ #define qLinux 0
+ #define qiPhone 0
+ #define qAndroid 0
+
+ #endif
+
+#elif __ANDROID__
+
+ #define qWinOS 0
+ #define qMacOS 0
+ #define qLinux 0
+ #define qiPhone 0
+ #define qAndroid 1
+
+#elif __linux__ || __unix__
+
+ #define qWinOS 0
+ #define qMacOS 0
+ #define qLinux 1
+ #define qiPhone 0
+ #define qAndroid 0
+
+#else
+ #error "XMP environment error - Unknown compiler"
+#endif
+
+// =================================================================================================
+// GPR version numbering
+// =================================================================================================
+
+#define GPR_VERSION_MAJOR 1
+#define GPR_VERSION_MINOR 0
+#define GPR_VERSION_REVISION 0
+
+#endif // GPR_PLATFORM_H
diff --git a/gpr/source/lib/common/public/gpr_rgb_buffer.h b/gpr/source/lib/common/public/gpr_rgb_buffer.h
new file mode 100755
index 0000000..6fcbb8d
--- /dev/null
+++ b/gpr/source/lib/common/public/gpr_rgb_buffer.h
@@ -0,0 +1,77 @@
+/*! @file gpr_buffer.h
+ *
+ * @brief Declaration of gpr_rgb_buffer object and enums/functions that work on it
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_RGB_BUFFER_H
+#define GPR_RGB_BUFFER_H
+
+#include "gpr_allocator.h"
+#include "gpr_platform.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef enum
+ {
+ GPR_RGB_RESOLUTION_SIXTEENTH = 1,
+ GPR_RGB_RESOLUTION_EIGHTH = 2,
+ GPR_RGB_RESOLUTION_QUARTER = 3,
+ GPR_RGB_RESOLUTION_HALF = 4,
+ GPR_RGB_RESOLUTION_FULL = 5,
+
+ GPR_RGB_RESOLUTION_NONE = 6,
+
+ GPR_RGB_RESOLUTION_DEFAULT = GPR_RGB_RESOLUTION_QUARTER,
+
+ } GPR_RGB_RESOLUTION;
+
+
+ typedef struct
+ {
+ int r_gain_num;
+ int r_gain_pow2_den;
+
+ int g_gain_num;
+ int g_gain_pow2_den;
+
+ int b_gain_num;
+ int b_gain_pow2_den;
+
+ } gpr_rgb_gain;
+
+ void gpr_rgb_gain_set_defaults(gpr_rgb_gain* x);
+
+ typedef struct
+ {
+ void* buffer; /* Address to the memory location that this buffer points to */
+
+ size_t size; /* Size of the memory block */
+
+ size_t width;
+
+ size_t height;
+
+ } gpr_rgb_buffer;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // GPR_RGB_BUFFER_H
diff --git a/gpr/source/lib/dng_sdk/BSD-License.txt b/gpr/source/lib/dng_sdk/BSD-License.txt
new file mode 100644
index 0000000..07b967c
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/BSD-License.txt
@@ -0,0 +1,32 @@
+The BSD License
+
+Copyright (c) 1999 - 2014, Adobe Systems Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems Incorporated, nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/gpr/source/lib/dng_sdk/CMakeLists.txt b/gpr/source/lib/dng_sdk/CMakeLists.txt
new file mode 100644
index 0000000..40f9a92
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/CMakeLists.txt
@@ -0,0 +1,21 @@
+# library
+set( LIB_NAME dng_sdk )
+
+# get source files
+file( GLOB SRC_FILES "*.cpp" )
+
+# get include files
+file( GLOB INC_FILES "*.h" )
+
+# add include files from other folders
+include_directories( "../common/private" )
+include_directories( "../common/public" )
+include_directories( "../xmp_core/public/include" )
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/dng_sdk/RawEnvironment.h b/gpr/source/lib/dng_sdk/RawEnvironment.h
new file mode 100644
index 0000000..7b9a3f3
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/RawEnvironment.h
@@ -0,0 +1,12 @@
+/*
+ *
+ * ARM Cortex Environment
+ *
+ *
+ */
+
+#ifndef __RawEnvironment_
+
+#define qDNGLittleEndian 1
+
+#endif // __RawEnvironment
diff --git a/gpr/source/lib/dng_sdk/dng_1d_function.cpp b/gpr/source/lib/dng_sdk/dng_1d_function.cpp
new file mode 100644
index 0000000..3ff79f4
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_1d_function.cpp
@@ -0,0 +1,195 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_1d_function.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_1d_function.h"
+
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_1d_function::~dng_1d_function ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_1d_function::IsIdentity () const
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_function::EvaluateInverse (real64 y) const
+ {
+
+ const uint32 kMaxIterations = 30;
+ const real64 kNearZero = 1.0e-10;
+
+ real64 x0 = 0.0;
+ real64 y0 = Evaluate (x0);
+
+ real64 x1 = 1.0;
+ real64 y1 = Evaluate (x1);
+
+ for (uint32 iteration = 0; iteration < kMaxIterations; iteration++)
+ {
+
+ if (Abs_real64 (y1 - y0) < kNearZero)
+ {
+ break;
+ }
+
+ real64 x2 = Pin_real64 (0.0,
+ x1 + (y - y1) * (x1 - x0) / (y1 - y0),
+ 1.0);
+
+ real64 y2 = Evaluate (x2);
+
+ x0 = x1;
+ y0 = y1;
+
+ x1 = x2;
+ y1 = y2;
+
+ }
+
+ return x1;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_1d_identity::IsIdentity () const
+ {
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_identity::Evaluate (real64 x) const
+ {
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_identity::EvaluateInverse (real64 x) const
+ {
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_1d_identity::Get ()
+ {
+
+ static dng_1d_identity static_function;
+
+ return static_function;
+
+ }
+
+/*****************************************************************************/
+
+dng_1d_concatenate::dng_1d_concatenate (const dng_1d_function &function1,
+ const dng_1d_function &function2)
+
+ : fFunction1 (function1)
+ , fFunction2 (function2)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_1d_concatenate::IsIdentity () const
+ {
+
+ return fFunction1.IsIdentity () &&
+ fFunction2.IsIdentity ();
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_concatenate::Evaluate (real64 x) const
+ {
+
+ real64 y = Pin_real64 (0.0, fFunction1.Evaluate (x), 1.0);
+
+ return fFunction2.Evaluate (y);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_concatenate::EvaluateInverse (real64 x) const
+ {
+
+ real64 y = fFunction2.EvaluateInverse (x);
+
+ return fFunction1.EvaluateInverse (y);
+
+ }
+
+/*****************************************************************************/
+
+dng_1d_inverse::dng_1d_inverse (const dng_1d_function &f)
+
+ : fFunction (f)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_1d_inverse::IsIdentity () const
+ {
+
+ return fFunction.IsIdentity ();
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_inverse::Evaluate (real64 x) const
+ {
+
+ return fFunction.EvaluateInverse (x);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_1d_inverse::EvaluateInverse (real64 y) const
+ {
+
+ return fFunction.Evaluate (y);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_1d_function.h b/gpr/source/lib/dng_sdk/dng_1d_function.h
new file mode 100644
index 0000000..aee59ca
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_1d_function.h
@@ -0,0 +1,159 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_1d_function.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Classes for a 1D floating-point to floating-point function abstraction.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_1d_function__
+#define __dng_1d_function__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief A 1D floating-point function.
+///
+/// The domain (input) is always from 0.0 to 1.0, while the range (output) can be an arbitrary interval.
+
+class dng_1d_function
+ {
+
+ public:
+
+ virtual ~dng_1d_function ();
+
+ /// Returns true if this function is the map x -> y such that x == y for all x . That is if Evaluate(x) == x for all x.
+
+ virtual bool IsIdentity () const;
+
+ /// Return the mapping for value x.
+ /// This method must be implemented by a derived class of dng_1d_function and the derived class determines the
+ /// lookup method and function used.
+ /// \param x A value between 0.0 and 1.0 (inclusive).
+ /// \retval Mapped value for x
+
+ virtual real64 Evaluate (real64 x) const = 0;
+
+ /// Return the reverse mapped value for y.
+ /// This method can be implemented by derived classes. The default implementation uses Newton's method to solve
+ /// for x such that Evaluate(x) == y.
+ /// \param y A value to reverse map. Should be within the range of the function implemented by this dng_1d_function .
+ /// \retval A value x such that Evaluate(x) == y (to very close approximation).
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ };
+
+/*****************************************************************************/
+
+/// An identity (x -> y such that x == y for all x) mapping function.
+
+class dng_1d_identity: public dng_1d_function
+ {
+
+ public:
+ /// Always returns true for this class.
+
+ virtual bool IsIdentity () const;
+
+ /// Always returns x for this class.
+
+ virtual real64 Evaluate (real64 x) const;
+
+ /// Always returns y for this class.
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ /// This class is a singleton, and is entirely threadsafe. Use this method to get an instance of the class.
+
+ static const dng_1d_function & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// A dng_1d_function that represents the composition (curry) of two other dng_1d_functions.
+
+class dng_1d_concatenate: public dng_1d_function
+ {
+
+ protected:
+
+ const dng_1d_function &fFunction1;
+
+ const dng_1d_function &fFunction2;
+
+ public:
+
+ /// Create a dng_1d_function which computes y = function2.Evaluate(function1.Evaluate(x)).
+ /// Compose function1 and function2 to compute y = function2.Evaluate(function1.Evaluate(x)). The range of function1.Evaluate must be a subset of 0.0 to 1.0 inclusive,
+ /// otherwise the result of function1(x) will be pinned (clipped) to 0.0 if <0.0 and to 1.0 if > 1.0 .
+ /// \param function1 Inner function of composition.
+ /// \param function2 Outer function of composition.
+
+ dng_1d_concatenate (const dng_1d_function &function1,
+ const dng_1d_function &function2);
+
+ /// Only true if both function1 and function2 have IsIdentity equal to true.
+
+ virtual bool IsIdentity () const;
+
+ /// Return the composed mapping for value x.
+ /// \param x A value between 0.0 and 1.0 (inclusive).
+ /// \retval function2.Evaluate(function1.Evaluate(x)).
+
+ virtual real64 Evaluate (real64 x) const;
+
+ /// Return the reverse mapped value for y.
+ /// Be careful using this method with compositions where the inner function does not have a range 0.0 to 1.0 . (Or better yet, do not use such functions.)
+ /// \param y A value to reverse map. Should be within the range of function2.Evaluate.
+ /// \retval A value x such that function2.Evaluate(function1.Evaluate(x)) == y (to very close approximation).
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ };
+
+/*****************************************************************************/
+
+/// A dng_1d_function that represents the inverse of another dng_1d_function.
+
+class dng_1d_inverse: public dng_1d_function
+ {
+
+ protected:
+
+ const dng_1d_function &fFunction;
+
+ public:
+
+ dng_1d_inverse (const dng_1d_function &f);
+
+ virtual bool IsIdentity () const;
+
+ virtual real64 Evaluate (real64 x) const;
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_1d_table.cpp b/gpr/source/lib/dng_sdk/dng_1d_table.cpp
new file mode 100644
index 0000000..267078e
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_1d_table.cpp
@@ -0,0 +1,195 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_1d_table.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_1d_table.h"
+
+#include "dng_1d_function.h"
+#include "dng_memory.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_1d_table::dng_1d_table ()
+
+ : fBuffer ()
+ , fTable (NULL)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_1d_table::~dng_1d_table ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_1d_table::SubDivide (const dng_1d_function &function,
+ uint32 lower,
+ uint32 upper,
+ real32 maxDelta)
+ {
+
+ uint32 range = upper - lower;
+
+ bool subDivide = (range > (kTableSize >> 8));
+
+ if (!subDivide)
+ {
+
+ real32 delta = Abs_real32 (fTable [upper] -
+ fTable [lower]);
+
+ if (delta > maxDelta)
+ {
+
+ subDivide = true;
+
+ }
+
+ }
+
+ if (subDivide)
+ {
+
+ uint32 middle = (lower + upper) >> 1;
+
+ fTable [middle] = (real32) function.Evaluate (middle * (1.0 / (real64) kTableSize));
+
+ if (range > 2)
+ {
+
+ SubDivide (function, lower, middle, maxDelta);
+
+ SubDivide (function, middle, upper, maxDelta);
+
+ }
+
+ }
+
+ else
+ {
+
+ real64 y0 = fTable [lower];
+ real64 y1 = fTable [upper];
+
+ real64 delta = (y1 - y0) / (real64) range;
+
+ for (uint32 j = lower + 1; j < upper; j++)
+ {
+
+ y0 += delta;
+
+ fTable [j] = (real32) y0;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_1d_table::Initialize (dng_memory_allocator &allocator,
+ const dng_1d_function &function,
+ bool subSample)
+ {
+
+ fBuffer.Reset (allocator.Allocate ((kTableSize + 2) * sizeof (real32)));
+
+ fTable = fBuffer->Buffer_real32 ();
+
+ if (subSample)
+ {
+
+ fTable [0 ] = (real32) function.Evaluate (0.0);
+ fTable [kTableSize] = (real32) function.Evaluate (1.0);
+
+ real32 maxDelta = Max_real32 (Abs_real32 (fTable [kTableSize] -
+ fTable [0 ]), 1.0f) *
+ (1.0f / 256.0f);
+
+ SubDivide (function,
+ 0,
+ kTableSize,
+ maxDelta);
+
+ }
+
+ else
+ {
+
+ for (uint32 j = 0; j <= kTableSize; j++)
+ {
+
+ real64 x = j * (1.0 / (real64) kTableSize);
+
+ real64 y = function.Evaluate (x);
+
+ fTable [j] = (real32) y;
+
+ }
+
+ }
+
+ fTable [kTableSize + 1] = fTable [kTableSize];
+
+ }
+
+/*****************************************************************************/
+
+void dng_1d_table::Expand16 (uint16 *table16) const
+ {
+
+ real64 step = (real64) kTableSize / 65535.0;
+
+ real64 y0 = fTable [0];
+ real64 y1 = fTable [1];
+
+ real64 base = y0 * 65535.0 + 0.5;
+ real64 slope = (y1 - y0) * 65535.0;
+
+ uint32 index = 1;
+ real64 fract = 0.0;
+
+ for (uint32 j = 0; j < 0x10000; j++)
+ {
+
+ table16 [j] = (uint16) (base + slope * fract);
+
+ fract += step;
+
+ if (fract > 1.0)
+ {
+
+ index += 1;
+ fract -= 1.0;
+
+ y0 = y1;
+ y1 = fTable [index];
+
+ base = y0 * 65535.0 + 0.5;
+ slope = (y1 - y0) * 65535.0;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_1d_table.h b/gpr/source/lib/dng_sdk/dng_1d_table.h
new file mode 100644
index 0000000..e24972a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_1d_table.h
@@ -0,0 +1,122 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_1d_table.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Definition of a lookup table based 1D floating-point to floating-point function abstraction using linear interpolation.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_1d_table__
+#define __dng_1d_table__
+
+/*****************************************************************************/
+
+#include "dng_assertions.h"
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief A 1D floating-point lookup table using linear interpolation.
+
+class dng_1d_table
+ {
+
+ public:
+
+ /// Constants denoting size of table.
+
+ enum
+ {
+ kTableBits = 12, //< Table is always a power of 2 in size. This is log2(kTableSize).
+ kTableSize = (1 << kTableBits) //< Number of entries in table.
+ };
+
+ protected:
+
+ AutoPtr<dng_memory_block> fBuffer;
+
+ real32 *fTable;
+
+ public:
+
+ dng_1d_table ();
+
+ virtual ~dng_1d_table ();
+
+ /// Set up table, initialize entries using functiion.
+ /// This method can throw an exception, e.g. if there is not enough memory.
+ /// \param allocator Memory allocator from which table memory is allocated.
+ /// \param function Table is initialized with values of finction.Evalluate(0.0) to function.Evaluate(1.0).
+ /// \param subSample If true, only sample the function a limited number of times and interpolate.
+
+ void Initialize (dng_memory_allocator &allocator,
+ const dng_1d_function &function,
+ bool subSample = false);
+
+ /// Lookup and interpolate mapping for an input.
+ /// \param x value from 0.0 to 1.0 used as input for mapping
+ /// \retval Approximation of function.Evaluate(x)
+
+ real32 Interpolate (real32 x) const
+ {
+
+ real32 y = x * (real32) kTableSize;
+
+ int32 index = (int32) y;
+
+ DNG_ASSERT (index >= 0 && index <= kTableSize,
+ "dng_1d_table::Interpolate parameter out of range");
+
+ real32 z = (real32) index;
+
+ real32 fract = y - z;
+
+ return fTable [index ] * (1.0f - fract) +
+ fTable [index + 1] * ( fract);
+
+ }
+
+ /// Direct access function for table data.
+
+ const real32 * Table () const
+ {
+ return fTable;
+ }
+
+ /// Expand the table to a 16-bit to 16-bit table.
+
+ void Expand16 (uint16 *table16) const;
+
+ private:
+
+ void SubDivide (const dng_1d_function &function,
+ uint32 lower,
+ uint32 upper,
+ real32 maxDelta);
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_1d_table (const dng_1d_table &table);
+
+ dng_1d_table & operator= (const dng_1d_table &table);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_abort_sniffer.cpp b/gpr/source/lib/dng_sdk/dng_abort_sniffer.cpp
new file mode 100644
index 0000000..4c65733
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_abort_sniffer.cpp
@@ -0,0 +1,242 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_abort_sniffer.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_abort_sniffer.h"
+
+#include "dng_mutex.h"
+
+/*****************************************************************************/
+
+#if qDNGThreadSafe
+
+/*****************************************************************************/
+
+class dng_priority_manager
+ {
+
+ private:
+
+ dng_mutex fMutex;
+
+ dng_condition fCondition;
+
+ uint32 fCounter [dng_priority_count];
+
+ public:
+
+ dng_priority_manager ();
+
+ void Increment (dng_priority priority);
+
+ void Decrement (dng_priority priority);
+
+ void Wait (dng_priority priority);
+
+ private:
+
+ dng_priority MinPriority ()
+ {
+
+ // Assumes mutex is locked.
+
+ for (uint32 level = dng_priority_maximum;
+ level > dng_priority_minimum;
+ level--)
+ {
+
+ if (fCounter [level])
+ {
+ return (dng_priority) level;
+ }
+
+ }
+
+ return dng_priority_minimum;
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+dng_priority_manager::dng_priority_manager ()
+
+ : fMutex ("dng_priority_manager::fMutex")
+ , fCondition ()
+
+ {
+
+ for (uint32 level = dng_priority_minimum;
+ level <= dng_priority_maximum;
+ level++)
+ {
+
+ fCounter [level] = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_priority_manager::Increment (dng_priority priority)
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ fCounter [priority] += 1;
+
+ }
+
+/*****************************************************************************/
+
+void dng_priority_manager::Decrement (dng_priority priority)
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ dng_priority oldMin = MinPriority ();
+
+ fCounter [priority] -= 1;
+
+ dng_priority newMin = MinPriority ();
+
+ if (newMin < oldMin)
+ {
+
+ fCondition.Broadcast ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_priority_manager::Wait (dng_priority priority)
+ {
+
+ if (priority < dng_priority_maximum)
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ while (priority < MinPriority ())
+ {
+
+ fCondition.Wait (fMutex);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+static dng_priority_manager gPriorityManager;
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+dng_set_minimum_priority::dng_set_minimum_priority (dng_priority priority)
+
+ : fPriority (priority)
+
+ {
+
+ #if qDNGThreadSafe
+
+ gPriorityManager.Increment (fPriority);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+dng_set_minimum_priority::~dng_set_minimum_priority ()
+ {
+
+ #if qDNGThreadSafe
+
+ gPriorityManager.Decrement (fPriority);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+dng_abort_sniffer::dng_abort_sniffer ()
+
+ : fPriority (dng_priority_maximum)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_abort_sniffer::~dng_abort_sniffer ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_abort_sniffer::SniffForAbort (dng_abort_sniffer *sniffer)
+ {
+
+ if (sniffer)
+ {
+
+ #if qDNGThreadSafe
+
+ gPriorityManager.Wait (sniffer->Priority ());
+
+ #endif
+
+ sniffer->Sniff ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_abort_sniffer::StartTask (const char * /* name */,
+ real64 /* fract */)
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_abort_sniffer::EndTask ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_abort_sniffer::UpdateProgress (real64 /* fract */)
+ {
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_abort_sniffer.h b/gpr/source/lib/dng_sdk/dng_abort_sniffer.h
new file mode 100644
index 0000000..3a2f553
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_abort_sniffer.h
@@ -0,0 +1,244 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_abort_sniffer.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Classes supporting user cancellation and progress tracking.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_abort_sniffer__
+#define __dng_abort_sniffer__
+
+/*****************************************************************************/
+
+#include "dng_flags.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Thread priority level.
+
+enum dng_priority
+ {
+
+ dng_priority_low,
+ dng_priority_medium,
+ dng_priority_high,
+
+ dng_priority_count,
+
+ dng_priority_minimum = dng_priority_low,
+ dng_priority_maximum = dng_priority_high
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Convenience class for setting thread priority level to minimum.
+
+class dng_set_minimum_priority
+ {
+
+ private:
+
+ dng_priority fPriority;
+
+ public:
+
+ dng_set_minimum_priority (dng_priority priority);
+
+ ~dng_set_minimum_priority ();
+
+ };
+
+/*****************************************************************************/
+
+/** \brief Class for signaling user cancellation and receiving progress updates.
+ *
+ * DNG SDK clients should derive a host application specific implementation
+ * from this class.
+ */
+
+class dng_abort_sniffer
+ {
+
+ friend class dng_sniffer_task;
+
+ private:
+
+ dng_priority fPriority;
+
+ public:
+
+ dng_abort_sniffer ();
+
+ virtual ~dng_abort_sniffer ();
+
+ /// Getter for priority level.
+
+ dng_priority Priority () const
+ {
+ return fPriority;
+ }
+
+ /// Setter for priority level.
+
+ void SetPriority (dng_priority priority)
+ {
+ fPriority = priority;
+ }
+
+ /// Check for pending user cancellation or other abort. ThrowUserCanceled
+ /// will be called if one is pending. This static method is provided as a
+ /// convenience for quickly testing for an abort and throwing an exception
+ /// if one is pending.
+ /// \param sniffer The dng_sniffer to test for a pending abort. Can be NULL,
+ /// in which case there an abort is never signalled.
+
+ static void SniffForAbort (dng_abort_sniffer *sniffer);
+
+ // A way to call Sniff while bypassing the priority wait.
+
+ void SniffNoPriorityWait ()
+ {
+ Sniff ();
+ }
+
+ // Specifies whether or not the sniffer may be called by multiple threads
+ // in parallel. Default result is false. Subclass must override to return
+ // true.
+
+ virtual bool ThreadSafe () const
+ {
+ return false;
+ }
+
+ protected:
+
+ /// Should be implemented by derived classes to check for an user
+ /// cancellation.
+
+ virtual void Sniff () = 0;
+
+ /// Signals the start of a named task withn processing in the DNG SDK.
+ /// Tasks may be nested.
+ /// \param name of the task
+ /// \param fract Percentage of total processing this task is expected to
+ /// take. From 0.0 to 1.0 .
+
+ virtual void StartTask (const char *name,
+ real64 fract);
+
+ /// Signals the end of the innermost task that has been started.
+
+ virtual void EndTask ();
+
+ /// Signals progress made on current task.
+ /// \param fract percentage of processing completed on current task.
+ /// From 0.0 to 1.0 .
+
+ virtual void UpdateProgress (real64 fract);
+
+ };
+
+/******************************************************************************/
+
+/// \brief Class to establish scope of a named subtask in DNG processing.
+///
+/// Instances of this class are intended to be stack allocated.
+
+class dng_sniffer_task
+ {
+
+ private:
+
+ dng_abort_sniffer *fSniffer;
+
+ public:
+
+ /// Inform a sniffer of a subtask in DNG processing.
+ /// \param sniffer The sniffer associated with the host on which this
+ /// processing is occurring.
+ /// \param name The name of this subtask as a NUL terminated string.
+ /// \param fract Percentage of total processing this task is expected
+ /// to take, from 0.0 to 1.0 .
+
+ dng_sniffer_task (dng_abort_sniffer *sniffer,
+ const char *name = NULL,
+ real64 fract = 0.0)
+
+ : fSniffer (sniffer)
+
+ {
+ if (fSniffer)
+ fSniffer->StartTask (name, fract);
+ }
+
+ ~dng_sniffer_task ()
+ {
+ if (fSniffer)
+ fSniffer->EndTask ();
+ }
+
+ /// Check for pending user cancellation or other abort. ThrowUserCanceled
+ /// will be called if one is pending.
+
+ void Sniff ()
+ {
+ dng_abort_sniffer::SniffForAbort (fSniffer);
+ }
+
+ /// Update progress on this subtask.
+ /// \param fract Percentage of processing completed on current task,
+ /// from 0.0 to 1.0 .
+
+ void UpdateProgress (real64 fract)
+ {
+ if (fSniffer)
+ fSniffer->UpdateProgress (fract);
+ }
+
+ /// Update progress on this subtask.
+ /// \param done Amount of task completed in arbitrary integer units.
+ /// \param total Total size of task in same arbitrary integer units as done.
+
+ void UpdateProgress (uint32 done,
+ uint32 total)
+ {
+ UpdateProgress ((real64) done /
+ (real64) total);
+ }
+
+ /// Signal task completed for progress purposes.
+
+ void Finish ()
+ {
+ UpdateProgress (1.0);
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_sniffer_task (const dng_sniffer_task &task);
+
+ dng_sniffer_task & operator= (const dng_sniffer_task &task);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_area_task.cpp b/gpr/source/lib/dng_sdk/dng_area_task.cpp
new file mode 100644
index 0000000..25b100e
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_area_task.cpp
@@ -0,0 +1,270 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_area_task.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_area_task.h"
+
+#include "dng_abort_sniffer.h"
+#include "dng_flags.h"
+#include "dng_sdk_limits.h"
+#include "dng_tile_iterator.h"
+#include "dng_utils.h"
+
+#if qImagecore
+extern bool gPrintTimings;
+#endif
+
+/*****************************************************************************/
+
+dng_area_task::dng_area_task ()
+
+ : fMaxThreads (kMaxMPThreads)
+
+ , fMinTaskArea (256 * 256)
+
+ , fUnitCell (1, 1)
+
+ , fMaxTileSize (256, 256)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_area_task::~dng_area_task ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_area_task::RepeatingTile1 () const
+ {
+
+ return dng_rect ();
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_area_task::RepeatingTile2 () const
+ {
+
+ return dng_rect ();
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_area_task::RepeatingTile3 () const
+ {
+
+ return dng_rect ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_area_task::Start (uint32 /* threadCount */,
+ const dng_point & /* tileSize */,
+ dng_memory_allocator * /* allocator */,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_area_task::Finish (uint32 /* threadCount */)
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_area_task::FindTileSize (const dng_rect &area) const
+ {
+
+ dng_rect repeatingTile1 = RepeatingTile1 ();
+ dng_rect repeatingTile2 = RepeatingTile2 ();
+ dng_rect repeatingTile3 = RepeatingTile3 ();
+
+ if (repeatingTile1.IsEmpty ())
+ {
+ repeatingTile1 = area;
+ }
+
+ if (repeatingTile2.IsEmpty ())
+ {
+ repeatingTile2 = area;
+ }
+
+ if (repeatingTile3.IsEmpty ())
+ {
+ repeatingTile3 = area;
+ }
+
+ uint32 repeatV = Min_uint32 (Min_uint32 (repeatingTile1.H (),
+ repeatingTile2.H ()),
+ repeatingTile3.H ());
+
+ uint32 repeatH = Min_uint32 (Min_uint32 (repeatingTile1.W (),
+ repeatingTile2.W ()),
+ repeatingTile3.W ());
+
+ dng_point maxTileSize = MaxTileSize ();
+
+ dng_point tileSize;
+
+ tileSize.v = Min_int32 (repeatV, maxTileSize.v);
+ tileSize.h = Min_int32 (repeatH, maxTileSize.h);
+
+ // What this is doing is, if the smallest repeating image tile is larger than the
+ // maximum tile size, adjusting the tile size down so that the tiles are as small
+ // as possible while still having the same number of tiles covering the
+ // repeat area. This makes the areas more equal in size, making MP
+ // algorithms work better.
+
+ // The image core team did not understand this code, and disabled it.
+ // Really stupid idea to turn off code you don't understand!
+ // I'm undoing this removal, because I think the code is correct and useful.
+
+ uint32 countV = (repeatV + tileSize.v - 1) / tileSize.v;
+ uint32 countH = (repeatH + tileSize.h - 1) / tileSize.h;
+
+ tileSize.v = (repeatV + countV - 1) / countV;
+ tileSize.h = (repeatH + countH - 1) / countH;
+
+ // Round up to unit cell size.
+
+ dng_point unitCell = UnitCell ();
+
+ if (unitCell.h != 1 || unitCell.v != 1)
+ {
+ tileSize.v = ((tileSize.v + unitCell.v - 1) / unitCell.v) * unitCell.v;
+ tileSize.h = ((tileSize.h + unitCell.h - 1) / unitCell.h) * unitCell.h;
+ }
+
+ // But if that is larger than maximum tile size, round down to unit cell size.
+
+ if (tileSize.v > maxTileSize.v)
+ {
+ tileSize.v = (maxTileSize.v / unitCell.v) * unitCell.v;
+ }
+
+ if (tileSize.h > maxTileSize.h)
+ {
+ tileSize.h = (maxTileSize.h / unitCell.h) * unitCell.h;
+ }
+
+ #if qImagecore
+ if (gPrintTimings)
+ {
+ fprintf (stdout, "\nRender tile for below: %d x %d\n", (int32) tileSize.h, (int32) tileSize.v);
+ }
+ #endif
+
+ return tileSize;
+
+ }
+
+/*****************************************************************************/
+
+void dng_area_task::ProcessOnThread (uint32 threadIndex,
+ const dng_rect &area,
+ const dng_point &tileSize,
+ dng_abort_sniffer *sniffer)
+ {
+
+ dng_rect repeatingTile1 = RepeatingTile1 ();
+ dng_rect repeatingTile2 = RepeatingTile2 ();
+ dng_rect repeatingTile3 = RepeatingTile3 ();
+
+ if (repeatingTile1.IsEmpty ())
+ {
+ repeatingTile1 = area;
+ }
+
+ if (repeatingTile2.IsEmpty ())
+ {
+ repeatingTile2 = area;
+ }
+
+ if (repeatingTile3.IsEmpty ())
+ {
+ repeatingTile3 = area;
+ }
+
+ dng_rect tile1;
+
+ dng_tile_iterator iter1 (repeatingTile3, area);
+
+ while (iter1.GetOneTile (tile1))
+ {
+
+ dng_rect tile2;
+
+ dng_tile_iterator iter2 (repeatingTile2, tile1);
+
+ while (iter2.GetOneTile (tile2))
+ {
+
+ dng_rect tile3;
+
+ dng_tile_iterator iter3 (repeatingTile1, tile2);
+
+ while (iter3.GetOneTile (tile3))
+ {
+
+ dng_rect tile4;
+
+ dng_tile_iterator iter4 (tileSize, tile3);
+
+ while (iter4.GetOneTile (tile4))
+ {
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ Process (threadIndex, tile4, sniffer);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_area_task::Perform (dng_area_task &task,
+ const dng_rect &area,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer)
+ {
+
+ dng_point tileSize (task.FindTileSize (area));
+
+ task.Start (1, tileSize, allocator, sniffer);
+
+ task.ProcessOnThread (0, area, tileSize, sniffer);
+
+ task.Finish (1);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_area_task.h b/gpr/source/lib/dng_sdk/dng_area_task.h
new file mode 100644
index 0000000..4824873
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_area_task.h
@@ -0,0 +1,198 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_area_task.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Class to handle partitioning a rectangular image processing operation taking into account multiple processing resources and memory constraints.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_area_task__
+#define __dng_area_task__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_point.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Abstract class for rectangular processing operations with support for partitioning across multiple processing resources and observing memory constraints.
+
+class dng_area_task
+ {
+
+ protected:
+
+ uint32 fMaxThreads;
+
+ uint32 fMinTaskArea;
+
+ dng_point fUnitCell;
+
+ dng_point fMaxTileSize;
+
+ public:
+
+ dng_area_task ();
+
+ virtual ~dng_area_task ();
+
+ /// Getter for the maximum number of threads (resources) that can be used for processing
+ ///
+ /// \retval Number of threads, minimum of 1, that can be used for this task.
+
+ virtual uint32 MaxThreads () const
+ {
+ return fMaxThreads;
+ }
+
+ /// Getter for minimum area of a partitioned rectangle.
+ /// Often it is not profitable to use more resources if it requires partitioning the input into chunks that are too small,
+ /// as the overhead increases more than the speedup. This method can be ovreridden for a specific task to indicate the smallest
+ /// area for partitioning. Default is 256x256 pixels.
+ ///
+ /// \retval Minimum area for a partitoned tile in order to give performant operation. (Partitions can be smaller due to small inputs and edge cases.)
+
+ virtual uint32 MinTaskArea () const
+ {
+ return fMinTaskArea;
+ }
+
+ /// Getter for dimensions of which partitioned tiles should be a multiple.
+ /// Various methods of processing prefer certain alignments. The partitioning attempts to construct tiles such that the
+ /// sizes are a multiple of the dimensions of this point.
+ ///
+ /// \retval a point giving preferred alignment in x and y
+
+ virtual dng_point UnitCell () const
+ {
+ return fUnitCell;
+ }
+
+ /// Getter for maximum size of a tile for processing.
+ /// Often processing will need to allocate temporary buffers or use other resources that are either fixed or in limited supply.
+ /// The maximum tile size forces further partitioning if the tile is bigger than this size.
+ ///
+ /// \retval Maximum tile size allowed for this area task.
+
+ virtual dng_point MaxTileSize () const
+ {
+ return fMaxTileSize;
+ }
+
+ /// Getter for RepeatingTile1.
+ /// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to establish a set of 0 to 3 tile patterns for which
+ /// the resulting partitions that the final Process method is called on will not cross tile boundaries in any of the
+ /// tile patterns. This can be used for a processing routine that needs to read from two tiles and write to a third
+ /// such that all the tiles are aligned and sized in a certain way. A RepeatingTile value is valid if it is non-empty.
+ /// Higher numbered RepeatingTile patterns are only used if all lower ones are non-empty. A RepeatingTile pattern must
+ /// be a multiple of UnitCell in size for all constraints of the partitionerr to be met.
+
+ virtual dng_rect RepeatingTile1 () const;
+
+ /// Getter for RepeatingTile2.
+ /// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to establish a set of 0 to 3 tile patterns for which
+ /// the resulting partitions that the final Process method is called on will not cross tile boundaries in any of the
+ /// tile patterns. This can be used for a processing routine that needs to read from two tiles and write to a third
+ /// such that all the tiles are aligned and sized in a certain way. A RepeatingTile value is valid if it is non-empty.
+ /// Higher numbered RepeatingTile patterns are only used if all lower ones are non-empty. A RepeatingTile pattern must
+ /// be a multiple of UnitCell in size for all constraints of the partitionerr to be met.
+
+ virtual dng_rect RepeatingTile2 () const;
+
+ /// Getter for RepeatingTile3.
+ /// RepeatingTile1, RepeatingTile2, and RepeatingTile3 are used to establish a set of 0 to 3 tile patterns for which
+ /// the resulting partitions that the final Process method is called on will not cross tile boundaries in any of the
+ /// tile patterns. This can be used for a processing routine that needs to read from two tiles and write to a third
+ /// such that all the tiles are aligned and sized in a certain way. A RepeatingTile value is valid if it is non-empty.
+ /// Higher numbered RepeatingTile patterns are only used if all lower ones are non-empty. A RepeatingTile pattern must
+ /// be a multiple of UnitCell in size for all constraints of the partitionerr to be met.
+
+ virtual dng_rect RepeatingTile3 () const;
+
+ /// Task startup method called before any processing is done on partitions.
+ /// The Start method is called before any processing is done and can be overridden to allocate temporary buffers, etc.
+ ///
+ /// \param threadCount Total number of threads that will be used for processing. Less than or equal to MaxThreads.
+ /// \param tileSize Size of source tiles which will be processed. (Not all tiles will be this size due to edge conditions.)
+ /// \param allocator dng_memory_allocator to use for allocating temporary buffers, etc.
+ /// \param sniffer Sniffer to test for user cancellation and to set up progress.
+
+ virtual void Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer);
+
+ /// Process one tile or fully partitioned area.
+ /// This method is overridden by derived classes to implement the actual image processing. Note that the sniffer can be ignored if it is certain that a
+ /// processing task will complete very quickly.
+ /// This method should never be called directly but rather accessed via Process.
+ /// There is no allocator parameter as all allocation should be done in Start.
+ ///
+ /// \param threadIndex 0 to threadCount - 1 index indicating which thread this is. (Can be used to get a thread-specific buffer allocated in the Start method.)
+ /// \param tile Area to process.
+ /// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
+
+ virtual void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer *sniffer) = 0;
+
+ /// Task computation finalization and teardown method.
+ /// Called after all resources have completed processing. Can be overridden to accumulate results and free resources allocated in Start.
+ ///
+ /// \param threadCount Number of threads used for processing. Same as value passed to Start.
+
+ virtual void Finish (uint32 threadCount);
+
+ /// Find tile size taking into account repeating tiles, unit cell, and maximum tile size.
+ /// \param area Computation area for which to find tile size.
+ /// \retval Tile size as height and width in point.
+
+ dng_point FindTileSize (const dng_rect &area) const;
+
+ /// Handle one resource's worth of partitioned tiles.
+ /// Called after thread partitioning has already been done. Area may be further subdivided to handle maximum tile size, etc.
+ /// It will be rare to override this method.
+ ///
+ /// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
+ /// \param area Tile area partitioned to this resource.
+ /// \param tileSize
+ /// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
+
+ void ProcessOnThread (uint32 threadIndex,
+ const dng_rect &area,
+ const dng_point &tileSize,
+ dng_abort_sniffer *sniffer);
+
+ /// Default resource partitioner that assumes a single resource to be used for processing.
+ /// Implementations that are aware of multiple processing resources should override (replace) this method.
+ /// This is usually done in dng_host::PerformAreaTask .
+ /// \param task The task to perform.
+ /// \param area The area on which mage processing should be performed.
+ /// \param allocator dng_memory_allocator to use for allocating temporary buffers, etc.
+ /// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
+
+ static void Perform (dng_area_task &task,
+ const dng_rect &area,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_assertions.h b/gpr/source/lib/dng_sdk/dng_assertions.h
new file mode 100644
index 0000000..3c45957
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_assertions.h
@@ -0,0 +1,133 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_assertions.h#3 $ */
+/* $DateTime: 2012/09/05 12:31:51 $ */
+/* $Change: 847652 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Conditionally compiled assertion check support.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_assertions__
+#define __dng_assertions__
+
+/*****************************************************************************/
+
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+#if qDNGDebug
+
+/// Platform-specific function to display an assert.
+
+void dng_show_message (const char *s);
+
+/// Show a formatted error message.
+
+void dng_show_message_f (const char *fmt, ...);
+
+#endif
+
+/*****************************************************************************/
+
+#ifndef DNG_ASSERT
+
+#if qDNGDebug
+
+/// Conditionally compiled macro to check an assertion and display a message if
+/// it fails and assertions are compiled in via qDNGDebug
+/// \param x Predicate which must be true.
+/// \param y String to display if x is not true.
+
+#define DNG_ASSERT(x,y) { if (!(x)) dng_show_message (y); }
+
+#else
+
+/// Conditionally compiled macro to check an assertion and display a message if
+/// it fails and assertions are compiled in via qDNGDebug
+/// \param x Predicate which must be true.
+/// \param y String to display if x is not true.
+
+#define DNG_ASSERT(x,y)
+
+#endif
+#endif
+
+/*****************************************************************************/
+
+#ifndef DNG_REQUIRE
+
+#if qDNGDebug
+
+/// Conditionally compiled macro to check an assertion, display a message, and throw
+/// an exception if it fails and assertions are compiled in via qDNGDebug
+/// \param condition Predicate which must be true.
+/// \param msg String to display if condition is not true.
+
+#define DNG_REQUIRE(condition,msg) \
+ do \
+ { \
+ \
+ if (!(condition)) \
+ { \
+ \
+ DNG_ASSERT(condition, msg); \
+ \
+ ThrowProgramError (msg); \
+ \
+ } \
+ \
+ } \
+ while (0)
+
+#else
+
+/// Conditionally compiled macro to check an assertion, display a message, and throw
+/// an exception if it fails and assertions are compiled in via qDNGDebug
+/// \param condition Predicate which must be true.
+/// \param msg String to display if condition is not true.
+
+#define DNG_REQUIRE(condition,msg) \
+ do \
+ { \
+ \
+ if (!(condition)) \
+ { \
+ \
+ ThrowProgramError (msg); \
+ \
+ } \
+ \
+ } \
+ while (0)
+
+#endif
+#endif
+
+/*****************************************************************************/
+
+#ifndef DNG_REPORT
+
+/// Macro to display an informational message
+/// \param x String to display.
+
+#define DNG_REPORT(x) DNG_ASSERT (false, x)
+
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_auto_ptr.h b/gpr/source/lib/dng_sdk/dng_auto_ptr.h
new file mode 100644
index 0000000..02154be
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_auto_ptr.h
@@ -0,0 +1,259 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_auto_ptr.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Class to implement std::auto_ptr like functionality even on platforms which do not
+ * have a full Standard C++ library.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_auto_ptr__
+#define __dng_auto_ptr__
+
+#include <stddef.h>
+
+/*****************************************************************************/
+
+// The following template has similar functionality to the STL auto_ptr, without
+// requiring all the weight of STL.
+
+/*****************************************************************************/
+
+/// \brief A class intended to be used in stack scope to hold a pointer from new. The
+/// held pointer will be deleted automatically if the scope is left without calling
+/// Release on the AutoPtr first.
+
+template<class T>
+class AutoPtr
+ {
+
+ private:
+
+ T *p_;
+
+ public:
+
+ /// Construct an AutoPtr with no referent.
+
+ AutoPtr () : p_ (0) { }
+
+ /// Construct an AutoPtr which owns the argument pointer.
+ /// \param p pointer which constructed AutoPtr takes ownership of. p will be
+ /// deleted on destruction or Reset unless Release is called first.
+
+ explicit AutoPtr (T *p) : p_( p ) { }
+
+ /// Reset is called on destruction.
+
+ ~AutoPtr ();
+
+ /// Call Reset with a pointer from new. Uses T's default constructor.
+
+ void Alloc ();
+
+ /// Return the owned pointer of this AutoPtr, NULL if none. No change in
+ /// ownership or other effects occur.
+
+ T *Get () const { return p_; }
+
+ /// Return the owned pointer of this AutoPtr, NULL if none. The AutoPtr gives
+ /// up ownership and takes NULL as its value.
+
+ T *Release ();
+
+ /// If a pointer is owned, it is deleted. Ownership is taken of passed in
+ /// pointer.
+ /// \param p pointer which constructed AutoPtr takes ownership of. p will be
+ /// deleted on destruction or Reset unless Release is called first.
+
+ void Reset (T *p);
+
+ /// If a pointer is owned, it is deleted and the AutoPtr takes NULL as its
+ /// value.
+
+ void Reset ();
+
+ /// Allows members of the owned pointer to be accessed directly. It is an
+ /// error to call this if the AutoPtr has NULL as its value.
+
+ T *operator-> () const { return p_; }
+
+ /// Returns a reference to the object that the owned pointer points to. It is
+ /// an error to call this if the AutoPtr has NULL as its value.
+
+ T &operator* () const { return *p_; }
+
+ /// Swap with another auto ptr.
+
+ friend inline void Swap (AutoPtr< T > &x, AutoPtr< T > &y)
+ {
+ T* temp = x.p_;
+ x.p_ = y.p_;
+ y.p_ = temp;
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator. I don't think the STL
+ // "feature" of grabbing ownership of the pointer is a good idea.
+
+ AutoPtr (AutoPtr<T> &rhs);
+
+ AutoPtr<T> & operator= (AutoPtr<T> &rhs);
+
+ };
+
+/*****************************************************************************/
+
+template<class T>
+AutoPtr<T>::~AutoPtr ()
+ {
+
+ delete p_;
+ p_ = 0;
+
+ }
+
+/*****************************************************************************/
+
+template<class T>
+T *AutoPtr<T>::Release ()
+ {
+ T *result = p_;
+ p_ = 0;
+ return result;
+ }
+
+/*****************************************************************************/
+
+template<class T>
+void AutoPtr<T>::Reset (T *p)
+ {
+
+ if (p_ != p)
+ {
+ if (p_ != 0)
+ delete p_;
+ p_ = p;
+ }
+
+ }
+
+/*****************************************************************************/
+
+template<class T>
+void AutoPtr<T>::Reset ()
+ {
+
+ if (p_ != 0)
+ {
+ delete p_;
+ p_ = 0;
+ }
+
+ }
+
+/*****************************************************************************/
+
+template<class T>
+void AutoPtr<T>::Alloc ()
+ {
+ this->Reset (new T);
+ }
+
+/*****************************************************************************/
+
+/// \brief A class intended to be used similarly to AutoPtr but for arrays.
+
+template<typename T>
+class AutoArray
+ {
+
+ public:
+
+ /// Construct an AutoArray which owns the argument pointer.
+ /// \param p array pointer which constructed AutoArray takes ownership of. p
+ /// will be deleted on destruction or Reset unless Release is called first.
+
+ explicit AutoArray (T *p_ = 0) : p (p_) { }
+
+ /// Reset is called on destruction.
+
+ ~AutoArray ()
+ {
+ delete [] p;
+ p = 0;
+ }
+
+ /// Return the owned array pointer of this AutoArray, NULL if none. The
+ /// AutoArray gives up ownership and takes NULL as its value.
+
+ T *Release ()
+ {
+ T *p_ = p;
+ p = 0;
+ return p_;
+ }
+
+ /// If a pointer is owned, it is deleted. Ownership is taken of passed in
+ /// pointer.
+ /// \param p array pointer which constructed AutoArray takes ownership of. p
+ /// will be deleted on destruction or Reset unless Release is called first.
+
+ void Reset (T *p_ = 0)
+ {
+ if (p != p_)
+ {
+ delete [] p;
+ p = p_;
+ }
+ }
+
+ /// Allows indexing into the AutoArray. It is an error to call this if the
+ /// AutoArray has NULL as its value.
+
+ T &operator[] (ptrdiff_t i) const
+ {
+ return p [i];
+ }
+
+ /// Return the owned pointer of this AutoArray, NULL if none. No change in
+ /// ownership or other effects occur.
+
+ T *Get () const
+ {
+ return p;
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ AutoArray (const AutoArray &);
+
+ const AutoArray & operator= (const AutoArray &);
+
+ private:
+
+ // Owned pointer or NULL.
+
+ T *p;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_bad_pixels.cpp b/gpr/source/lib/dng_sdk/dng_bad_pixels.cpp
new file mode 100644
index 0000000..920acd6
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_bad_pixels.cpp
@@ -0,0 +1,1856 @@
+/*****************************************************************************/
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bad_pixels.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_bad_pixels.h"
+
+#include "dng_filter_task.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_negative.h"
+
+#include <algorithm>
+
+/*****************************************************************************/
+
+dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant
+ (uint32 constant,
+ uint32 bayerPhase)
+
+ : dng_filter_opcode (dngOpcode_FixBadPixelsConstant,
+ dngVersion_1_3_0_0,
+ 0)
+
+ , fConstant (constant)
+ , fBayerPhase (bayerPhase)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant
+ (dng_stream &stream)
+
+ : dng_filter_opcode (dngOpcode_FixBadPixelsConstant,
+ stream,
+ "FixBadPixelsConstant")
+
+ , fConstant (0)
+ , fBayerPhase (0)
+
+ {
+
+ if (stream.Get_uint32 () != 8)
+ {
+ ThrowBadFormat ();
+ }
+
+ fConstant = stream.Get_uint32 ();
+ fBayerPhase = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Constant: %u\n", (unsigned) fConstant);
+
+ printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase);
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsConstant::PutData (dng_stream &stream) const
+ {
+
+ stream.Put_uint32 (8);
+
+ stream.Put_uint32 (fConstant );
+ stream.Put_uint32 (fBayerPhase);
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat ()
+ {
+
+ return dng_point (2, 2);
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_FixBadPixelsConstant::SrcArea (const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect srcArea = dstArea;
+
+ srcArea.t -= 2;
+ srcArea.l -= 2;
+
+ srcArea.b += 2;
+ srcArea.r += 2;
+
+ return srcArea;
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsConstant::Prepare (dng_negative & /* negative */,
+ uint32 /* threadCount */,
+ const dng_point & /* tileSize */,
+ const dng_rect & /* imageBounds */,
+ uint32 imagePlanes,
+ uint32 bufferPixelType,
+ dng_memory_allocator & /* allocator */)
+ {
+
+ // This opcode is restricted to single channel images.
+
+ if (imagePlanes != 1)
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ // This opcode is restricted to 16-bit images.
+
+ if (bufferPixelType != ttShort)
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsConstant::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dstBuffer.CopyArea (srcBuffer,
+ dstArea,
+ 0,
+ dstBuffer.fPlanes);
+
+ uint16 badPixel = (uint16) fConstant;
+
+ for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
+ {
+
+ const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (dstRow, dstArea.l, 0);
+ uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, dstArea.l, 0);
+
+ for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++)
+ {
+
+ if (*sPtr == badPixel)
+ {
+
+ uint32 count = 0;
+ uint32 total = 0;
+
+ uint16 value;
+
+ if (IsGreen (dstRow, dstCol)) // Green pixel
+ {
+
+ value = sPtr [-srcBuffer.fRowStep - 1];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ value = sPtr [-srcBuffer.fRowStep + 1];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ value = sPtr [srcBuffer.fRowStep - 1];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ value = sPtr [srcBuffer.fRowStep + 1];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ }
+
+ else // Red/blue pixel.
+ {
+
+ value = sPtr [-srcBuffer.fRowStep * 2];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ value = sPtr [srcBuffer.fRowStep * 2];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ value = sPtr [-2];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ value = sPtr [2];
+
+ if (value != badPixel)
+ {
+ count += 1;
+ total += value;
+ }
+
+ }
+
+ if (count == 4) // Most common case.
+ {
+
+ *dPtr = (uint16) ((total + 2) >> 2);
+
+ }
+
+ else if (count > 0)
+ {
+
+ *dPtr = (uint16) ((total + (count >> 1)) / count);
+
+ }
+
+ }
+
+ sPtr++;
+ dPtr++;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_bad_pixel_list::dng_bad_pixel_list ()
+
+ : fBadPoints ()
+ , fBadRects ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_bad_pixel_list::AddPoint (const dng_point &pt)
+ {
+
+ fBadPoints.push_back (pt);
+
+ }
+
+/*****************************************************************************/
+
+void dng_bad_pixel_list::AddRect (const dng_rect &r)
+ {
+
+ fBadRects.push_back (r);
+
+ }
+
+/*****************************************************************************/
+
+static bool SortBadPoints (const dng_point &a,
+ const dng_point &b)
+ {
+
+ if (a.v < b.v)
+ return true;
+
+ if (a.v > b.v)
+ return false;
+
+ return a.h < b.h;
+
+ }
+
+/*****************************************************************************/
+
+static bool SortBadRects (const dng_rect &a,
+ const dng_rect &b)
+ {
+
+ if (a.t < b.t)
+ return true;
+
+ if (a.t > b.t)
+ return false;
+
+ if (a.l < b.l)
+ return true;
+
+ if (a.l > b.l)
+ return false;
+
+ if (a.b < b.b)
+ return true;
+
+ if (a.b > b.b)
+ return false;
+
+ return a.r < b.r;
+
+ }
+
+/*****************************************************************************/
+
+void dng_bad_pixel_list::Sort ()
+ {
+
+ if (PointCount () > 1)
+ {
+
+ std::sort (fBadPoints.begin (),
+ fBadPoints.end (),
+ SortBadPoints);
+
+ }
+
+ if (RectCount () > 1)
+ {
+
+ std::sort (fBadRects.begin (),
+ fBadRects.end (),
+ SortBadRects);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_bad_pixel_list::IsPointIsolated (uint32 index,
+ uint32 radius) const
+ {
+
+ dng_point pt = Point (index);
+
+ // Search backward through bad point list.
+
+ for (int32 j = index - 1; j >= 0; j--)
+ {
+
+ const dng_point &pt2 = Point (j);
+
+ if (pt2.v < pt.v - (int32) radius)
+ {
+ break;
+ }
+
+ if (Abs_int32 (pt2.h - pt.h) <= radius)
+ {
+ return false;
+ }
+
+ }
+
+ // Search forward through bad point list.
+
+ for (uint32 k = index + 1; k < PointCount (); k++)
+ {
+
+ const dng_point &pt2 = Point (k);
+
+ if (pt2.v > pt.v + (int32) radius)
+ {
+ break;
+ }
+
+ if (Abs_int32 (pt2.h - pt.h) <= radius)
+ {
+ return false;
+ }
+
+ }
+
+ // Search through bad rectangle list.
+
+ dng_rect testRect (pt.v - radius,
+ pt.h - radius,
+ pt.v + radius + 1,
+ pt.h + radius + 1);
+
+ for (uint32 n = 0; n < RectCount (); n++)
+ {
+
+ if ((testRect & Rect (n)).NotEmpty ())
+ {
+ return false;
+ }
+
+ }
+
+ // Did not find point anywhere, so bad pixel is isolated.
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_bad_pixel_list::IsRectIsolated (uint32 index,
+ uint32 radius) const
+ {
+
+ dng_rect testRect = Rect (index);
+
+ testRect.t -= radius;
+ testRect.l -= radius;
+ testRect.b += radius;
+ testRect.r += radius;
+
+ for (uint32 n = 0; n < RectCount (); n++)
+ {
+
+ if (n != index)
+ {
+
+ if ((testRect & Rect (n)).NotEmpty ())
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_bad_pixel_list::IsPointValid (const dng_point &pt,
+ const dng_rect &imageBounds,
+ uint32 index) const
+ {
+
+ // The point must be in the image bounds to be valid.
+
+ if (pt.v < imageBounds.t ||
+ pt.h < imageBounds.l ||
+ pt.v >= imageBounds.b ||
+ pt.h >= imageBounds.r)
+ {
+ return false;
+ }
+
+ // Only search the bad point list if we have a starting search index.
+
+ if (index != kNoIndex)
+ {
+
+ // Search backward through bad point list.
+
+ for (int32 j = index - 1; j >= 0; j--)
+ {
+
+ const dng_point &pt2 = Point (j);
+
+ if (pt2.v < pt.v)
+ {
+ break;
+ }
+
+ if (pt2 == pt)
+ {
+ return false;
+ }
+
+ }
+
+ // Search forward through bad point list.
+
+ for (uint32 k = index + 1; k < PointCount (); k++)
+ {
+
+ const dng_point &pt2 = Point (k);
+
+ if (pt2.v > pt.v)
+ {
+ break;
+ }
+
+ if (pt2 == pt)
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ // Search through bad rectangle list.
+
+ for (uint32 n = 0; n < RectCount (); n++)
+ {
+
+ const dng_rect &r = Rect (n);
+
+ if (pt.v >= r.t &&
+ pt.h >= r.l &&
+ pt.v < r.b &&
+ pt.h < r.r)
+ {
+ return false;
+ }
+
+ }
+
+ // Did not find point anywhere, so pixel is valid.
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList
+ (AutoPtr<dng_bad_pixel_list> &list,
+ uint32 bayerPhase)
+
+
+ : dng_filter_opcode (dngOpcode_FixBadPixelsList,
+ dngVersion_1_3_0_0,
+ 0)
+
+ , fList ()
+
+ , fBayerPhase (bayerPhase)
+
+ {
+
+ fList.Reset (list.Release ());
+
+ fList->Sort ();
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList (dng_stream &stream)
+
+ : dng_filter_opcode (dngOpcode_FixBadPixelsList,
+ stream,
+ "FixBadPixelsList")
+
+ , fList ()
+
+ , fBayerPhase (0)
+
+ {
+
+ uint32 size = stream.Get_uint32 ();
+
+ fBayerPhase = stream.Get_uint32 ();
+
+ uint32 pCount = stream.Get_uint32 ();
+ uint32 rCount = stream.Get_uint32 ();
+
+ if (size != 12 + pCount * 8 + rCount * 16)
+ {
+ ThrowBadFormat ();
+ }
+
+ fList.Reset (new dng_bad_pixel_list);
+
+ uint32 index;
+
+ for (index = 0; index < pCount; index++)
+ {
+
+ dng_point pt;
+
+ pt.v = stream.Get_int32 ();
+ pt.h = stream.Get_int32 ();
+
+ fList->AddPoint (pt);
+
+ }
+
+ for (index = 0; index < rCount; index++)
+ {
+
+ dng_rect r;
+
+ r.t = stream.Get_int32 ();
+ r.l = stream.Get_int32 ();
+ r.b = stream.Get_int32 ();
+ r.r = stream.Get_int32 ();
+
+ fList->AddRect (r);
+
+ }
+
+ fList->Sort ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase);
+
+ printf ("Bad Pixels: %u\n", (unsigned) pCount);
+
+ for (index = 0; index < pCount && index < gDumpLineLimit; index++)
+ {
+ printf (" Pixel [%u]: v=%d, h=%d\n",
+ (unsigned) index,
+ (int) fList->Point (index).v,
+ (int) fList->Point (index).h);
+ }
+
+ if (pCount > gDumpLineLimit)
+ {
+ printf (" ... %u bad pixels skipped\n", (unsigned) (pCount - gDumpLineLimit));
+ }
+
+ printf ("Bad Rects: %u\n", (unsigned) rCount);
+
+ for (index = 0; index < rCount && index < gDumpLineLimit; index++)
+ {
+ printf (" Rect [%u]: t=%d, l=%d, b=%d, r=%d\n",
+ (unsigned) index,
+ (int) fList->Rect (index).t,
+ (int) fList->Rect (index).l,
+ (int) fList->Rect (index).b,
+ (int) fList->Rect (index).r);
+ }
+
+ if (rCount > gDumpLineLimit)
+ {
+ printf (" ... %u bad rects skipped\n", (unsigned) (rCount - gDumpLineLimit));
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::PutData (dng_stream &stream) const
+ {
+
+ uint32 pCount = fList->PointCount ();
+ uint32 rCount = fList->RectCount ();
+
+ stream.Put_uint32 (12 + pCount * 8 + rCount * 16);
+
+ stream.Put_uint32 (fBayerPhase);
+
+ stream.Put_uint32 (pCount);
+ stream.Put_uint32 (rCount);
+
+ uint32 index;
+
+ for (index = 0; index < pCount; index++)
+ {
+
+ const dng_point &pt (fList->Point (index));
+
+ stream.Put_int32 (pt.v);
+ stream.Put_int32 (pt.h);
+
+ }
+
+ for (index = 0; index < rCount; index++)
+ {
+
+ const dng_rect &r (fList->Rect (index));
+
+ stream.Put_int32 (r.t);
+ stream.Put_int32 (r.l);
+ stream.Put_int32 (r.b);
+ stream.Put_int32 (r.r);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_FixBadPixelsList::SrcArea (const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ int32 padding = 0;
+
+ if (fList->PointCount ())
+ {
+ padding += kBadPointPadding;
+ }
+
+ if (fList->RectCount ())
+ {
+ padding += kBadRectPadding;
+ }
+
+ dng_rect srcArea = dstArea;
+
+ srcArea.t -= padding;
+ srcArea.l -= padding;
+
+ srcArea.b += padding;
+ srcArea.r += padding;
+
+ return srcArea;
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_opcode_FixBadPixelsList::SrcRepeat ()
+ {
+
+ return dng_point (2, 2);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::Prepare (dng_negative & /* negative */,
+ uint32 /* threadCount */,
+ const dng_point & /* tileSize */,
+ const dng_rect & /* imageBounds */,
+ uint32 imagePlanes,
+ uint32 bufferPixelType,
+ dng_memory_allocator & /* allocator */)
+ {
+
+ // This opcode is restricted to single channel images.
+
+ if (imagePlanes != 1)
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ // This opcode is restricted to 16-bit images.
+
+ if (bufferPixelType != ttShort)
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::FixIsolatedPixel (dng_pixel_buffer &buffer,
+ dng_point &badPoint)
+ {
+
+ uint16 *p0 = buffer.DirtyPixel_uint16 (badPoint.v - 2, badPoint.h - 2, 0);
+ uint16 *p1 = buffer.DirtyPixel_uint16 (badPoint.v - 1, badPoint.h - 2, 0);
+ uint16 *p2 = buffer.DirtyPixel_uint16 (badPoint.v , badPoint.h - 2, 0);
+ uint16 *p3 = buffer.DirtyPixel_uint16 (badPoint.v + 1, badPoint.h - 2, 0);
+ uint16 *p4 = buffer.DirtyPixel_uint16 (badPoint.v + 2, badPoint.h - 2, 0);
+
+ uint32 est0;
+ uint32 est1;
+ uint32 est2;
+ uint32 est3;
+
+ uint32 grad0;
+ uint32 grad1;
+ uint32 grad2;
+ uint32 grad3;
+
+ if (IsGreen (badPoint.v, badPoint.h)) // Green pixel
+ {
+
+ // g00 b01 g02 b03 g04
+ // r10 g11 r12 g13 r14
+ // g20 b21 g22 b23 g24
+ // r30 g31 r32 g33 r34
+ // g40 b41 g42 b43 g44
+
+ int32 b01 = p0 [1];
+ int32 g02 = p0 [2];
+ int32 b03 = p0 [3];
+
+ int32 r10 = p1 [0];
+ int32 g11 = p1 [1];
+ int32 r12 = p1 [2];
+ int32 g13 = p1 [3];
+ int32 r14 = p1 [4];
+
+ int32 g20 = p2 [0];
+ int32 b21 = p2 [1];
+ int32 b23 = p2 [3];
+ int32 g24 = p2 [4];
+
+ int32 r30 = p3 [0];
+ int32 g31 = p3 [1];
+ int32 r32 = p3 [2];
+ int32 g33 = p3 [3];
+ int32 r34 = p3 [4];
+
+ int32 b41 = p4 [1];
+ int32 g42 = p4 [2];
+ int32 b43 = p4 [3];
+
+ est0 = g02 + g42;
+
+ grad0 = Abs_int32 (g02 - g42) +
+ Abs_int32 (g11 - g31) +
+ Abs_int32 (g13 - g33) +
+ Abs_int32 (b01 - b21) +
+ Abs_int32 (b03 - b23) +
+ Abs_int32 (b21 - b41) +
+ Abs_int32 (b23 - b43);
+
+ est1 = g11 + g33;
+
+ grad1 = Abs_int32 (g11 - g33) +
+ Abs_int32 (g02 - g24) +
+ Abs_int32 (g20 - g42) +
+ Abs_int32 (b01 - b23) +
+ Abs_int32 (r10 - r32) +
+ Abs_int32 (r12 - r34) +
+ Abs_int32 (b21 - b43);
+
+ est2 = g20 + g24;
+
+ grad2 = Abs_int32 (g20 - g24) +
+ Abs_int32 (g11 - g13) +
+ Abs_int32 (g31 - g33) +
+ Abs_int32 (r10 - r12) +
+ Abs_int32 (r30 - r32) +
+ Abs_int32 (r12 - r14) +
+ Abs_int32 (r32 - r34);
+
+ est3 = g13 + g31;
+
+ grad3 = Abs_int32 (g13 - g31) +
+ Abs_int32 (g02 - g20) +
+ Abs_int32 (g24 - g42) +
+ Abs_int32 (b03 - b21) +
+ Abs_int32 (r14 - r32) +
+ Abs_int32 (r12 - r30) +
+ Abs_int32 (b23 - b41);
+
+ }
+
+ else // Red/blue pixel
+ {
+
+ // b00 g01 b02 g03 b04
+ // g10 r11 g12 r13 g14
+ // b20 g21 b22 g23 b24
+ // g30 r31 g32 r33 g34
+ // b40 g41 b42 g43 b44
+
+ int32 b00 = p0 [0];
+ int32 g01 = p0 [1];
+ int32 b02 = p0 [2];
+ int32 g03 = p0 [3];
+ int32 b04 = p0 [4];
+
+ int32 g10 = p1 [0];
+ int32 r11 = p1 [1];
+ int32 g12 = p1 [2];
+ int32 r13 = p1 [3];
+ int32 g14 = p1 [4];
+
+ int32 b20 = p2 [0];
+ int32 g21 = p2 [1];
+ int32 g23 = p2 [3];
+ int32 b24 = p2 [4];
+
+ int32 g30 = p3 [0];
+ int32 r31 = p3 [1];
+ int32 g32 = p3 [2];
+ int32 r33 = p3 [3];
+ int32 g34 = p3 [4];
+
+ int32 b40 = p4 [0];
+ int32 g41 = p4 [1];
+ int32 b42 = p4 [2];
+ int32 g43 = p4 [3];
+ int32 b44 = p4 [4];
+
+ est0 = b02 + b42;
+
+ grad0 = Abs_int32 (b02 - b42) +
+ Abs_int32 (g12 - g32) +
+ Abs_int32 (g01 - g21) +
+ Abs_int32 (g21 - g41) +
+ Abs_int32 (g03 - g23) +
+ Abs_int32 (g23 - g43) +
+ Abs_int32 (r11 - r31) +
+ Abs_int32 (r13 - r33);
+
+ est1 = b00 + b44;
+
+ grad1 = Abs_int32 (b00 - b44) +
+ Abs_int32 (r11 - r33) +
+ Abs_int32 (g01 - g23) +
+ Abs_int32 (g10 - g32) +
+ Abs_int32 (g12 - g34) +
+ Abs_int32 (g21 - g43) +
+ Abs_int32 (b02 - b24) +
+ Abs_int32 (b20 - b42);
+
+ est2 = b20 + b24;
+
+ grad2 = Abs_int32 (b20 - b24) +
+ Abs_int32 (g21 - g23) +
+ Abs_int32 (g10 - g12) +
+ Abs_int32 (g12 - g14) +
+ Abs_int32 (g30 - g32) +
+ Abs_int32 (g32 - g34) +
+ Abs_int32 (r11 - r13) +
+ Abs_int32 (r31 - r33);
+
+ est3 = b04 + b40;
+
+ grad3 = Abs_int32 (b04 - b40) +
+ Abs_int32 (r13 - r31) +
+ Abs_int32 (g03 - g21) +
+ Abs_int32 (g14 - g32) +
+ Abs_int32 (g12 - g30) +
+ Abs_int32 (g23 - g41) +
+ Abs_int32 (b02 - b20) +
+ Abs_int32 (b24 - b42);
+
+ }
+
+ uint32 minGrad = Min_uint32 (grad0, grad1);
+
+ minGrad = Min_uint32 (minGrad, grad2);
+ minGrad = Min_uint32 (minGrad, grad3);
+
+ uint32 limit = (minGrad * 3) >> 1;
+
+ uint32 total = 0;
+ uint32 count = 0;
+
+ if (grad0 <= limit)
+ {
+ total += est0;
+ count += 2;
+ }
+
+ if (grad1 <= limit)
+ {
+ total += est1;
+ count += 2;
+ }
+
+ if (grad2 <= limit)
+ {
+ total += est2;
+ count += 2;
+ }
+
+ if (grad3 <= limit)
+ {
+ total += est3;
+ count += 2;
+ }
+
+ uint32 estimate = (total + (count >> 1)) / count;
+
+ p2 [2] = (uint16) estimate;
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::FixClusteredPixel (dng_pixel_buffer &buffer,
+ uint32 pointIndex,
+ const dng_rect &imageBounds)
+ {
+
+ const uint32 kNumSets = 3;
+ const uint32 kSetSize = 4;
+
+ static const int32 kOffset [kNumSets] [kSetSize] [2] =
+ {
+ {
+ { -1, 1 },
+ { -1, -1 },
+ { 1, -1 },
+ { 1, 1 }
+ },
+ {
+ { -2, 0 },
+ { 2, 0 },
+ { 0, -2 },
+ { 0, 2 }
+ },
+ {
+ { -2, -2 },
+ { -2, 2 },
+ { 2, -2 },
+ { 2, 2 }
+ }
+ };
+
+ dng_point badPoint = fList->Point (pointIndex);
+
+ bool isGreen = IsGreen (badPoint.v, badPoint.h);
+
+ uint16 *p = buffer.DirtyPixel_uint16 (badPoint.v, badPoint.h, 0);
+
+ for (uint32 set = 0; set < kNumSets; set++)
+ {
+
+ if (!isGreen && (kOffset [set] [0] [0] & 1) == 1)
+ {
+ continue;
+ }
+
+ uint32 total = 0;
+ uint32 count = 0;
+
+ for (uint32 entry = 0; entry < kSetSize; entry++)
+ {
+
+ dng_point offset (kOffset [set] [entry] [0],
+ kOffset [set] [entry] [1]);
+
+ if (fList->IsPointValid (badPoint + offset,
+ imageBounds,
+ pointIndex))
+ {
+
+ total += p [offset.v * buffer.fRowStep +
+ offset.h * buffer.fColStep];
+
+ count++;
+
+ }
+
+ }
+
+ if (count)
+ {
+
+ uint32 estimate = (total + (count >> 1)) / count;
+
+ p [0] = (uint16) estimate;
+
+ return;
+
+ }
+
+ }
+
+ // Unable to patch bad pixel. Leave pixel as is.
+
+ #if qDNGValidate
+
+ char s [256];
+
+ sprintf (s, "Unable to repair bad pixel, row %d, column %d",
+ (int) badPoint.v,
+ (int) badPoint.h);
+
+ ReportWarning (s);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::FixSingleColumn (dng_pixel_buffer &buffer,
+ const dng_rect &badRect)
+ {
+
+ int32 cs = buffer.fColStep;
+
+ for (int32 row = badRect.t; row < badRect.b; row++)
+ {
+
+ uint16 *p0 = buffer.DirtyPixel_uint16 (row - 4, badRect.l - 4, 0);
+ uint16 *p1 = buffer.DirtyPixel_uint16 (row - 3, badRect.l - 4, 0);
+ uint16 *p2 = buffer.DirtyPixel_uint16 (row - 2, badRect.l - 4, 0);
+ uint16 *p3 = buffer.DirtyPixel_uint16 (row - 1, badRect.l - 4, 0);
+ uint16 *p4 = buffer.DirtyPixel_uint16 (row , badRect.l - 4, 0);
+ uint16 *p5 = buffer.DirtyPixel_uint16 (row + 1, badRect.l - 4, 0);
+ uint16 *p6 = buffer.DirtyPixel_uint16 (row + 2, badRect.l - 4, 0);
+ uint16 *p7 = buffer.DirtyPixel_uint16 (row + 3, badRect.l - 4, 0);
+ uint16 *p8 = buffer.DirtyPixel_uint16 (row + 4, badRect.l - 4, 0);
+
+ uint32 est0;
+ uint32 est1;
+ uint32 est2;
+ uint32 est3;
+ uint32 est4;
+ uint32 est5;
+ uint32 est6;
+
+ uint32 grad0;
+ uint32 grad1;
+ uint32 grad2;
+ uint32 grad3;
+ uint32 grad4;
+ uint32 grad5;
+ uint32 grad6;
+
+ uint32 lower = 0;
+ uint32 upper = 0x0FFFF;
+
+ if (IsGreen (row, badRect.l)) // Green pixel
+ {
+
+ // g00 b01 g02 b03 g04 b05 g06 b07 g08
+ // r10 g11 r12 g13 r14 g15 r16 g17 r18
+ // g20 b21 g22 b23 g24 b25 g26 b27 g28
+ // r30 g31 r32 g33 r34 g35 r36 g37 r38
+ // g40 b41 g42 b43 g44 b45 g46 b47 g48
+ // r50 g51 r52 g53 r54 g55 r56 g57 r58
+ // g60 b61 g62 b63 g64 b65 g66 b67 g68
+ // r70 g71 r72 g73 r74 g75 r76 g77 r78
+ // g80 b81 g82 b83 g84 b85 g86 b87 g88
+
+ int32 b03 = p0 [3 * cs];
+ int32 b05 = p0 [5 * cs];
+
+ int32 g11 = p1 [1 * cs];
+ int32 g13 = p1 [3 * cs];
+ int32 g15 = p1 [5 * cs];
+ int32 g17 = p1 [7 * cs];
+
+ int32 g22 = p2 [2 * cs];
+ int32 b23 = p2 [3 * cs];
+ int32 b25 = p2 [5 * cs];
+ int32 g26 = p2 [6 * cs];
+
+ int32 r30 = p3 [0 * cs];
+ int32 g31 = p3 [1 * cs];
+ int32 r32 = p3 [2 * cs];
+ int32 g33 = p3 [3 * cs];
+ int32 g35 = p3 [5 * cs];
+ int32 r36 = p3 [6 * cs];
+ int32 g37 = p3 [7 * cs];
+ int32 r38 = p3 [8 * cs];
+
+ int32 g40 = p4 [0 * cs];
+ int32 g42 = p4 [2 * cs];
+ int32 b43 = p4 [3 * cs];
+ int32 b45 = p4 [5 * cs];
+ int32 g46 = p4 [6 * cs];
+ int32 g48 = p4 [8 * cs];
+
+ int32 r50 = p5 [0 * cs];
+ int32 g51 = p5 [1 * cs];
+ int32 r52 = p5 [2 * cs];
+ int32 g53 = p5 [3 * cs];
+ int32 g55 = p5 [5 * cs];
+ int32 r56 = p5 [6 * cs];
+ int32 g57 = p5 [7 * cs];
+ int32 r58 = p5 [8 * cs];
+
+ int32 g62 = p6 [2 * cs];
+ int32 b63 = p6 [3 * cs];
+ int32 b65 = p6 [5 * cs];
+ int32 g66 = p6 [6 * cs];
+
+ int32 g71 = p7 [1 * cs];
+ int32 g73 = p7 [3 * cs];
+ int32 g75 = p7 [5 * cs];
+ int32 g77 = p7 [7 * cs];
+
+ int32 b83 = p8 [3 * cs];
+ int32 b85 = p8 [5 * cs];
+
+ // In case there is some green split, make an estimate of
+ // of the local difference between the greens, and adjust
+ // the estimated green values for the difference
+ // between the two types of green pixels when estimating
+ // across green types.
+
+ int32 split = ((g22 + g62 + g26 + g66) * 4 +
+ (g42 + g46 ) * 8 -
+ (g11 + g13 + g15 + g17) -
+ (g31 + g33 + g35 + g37) * 3 -
+ (g51 + g53 + g55 + g57) * 3 -
+ (g71 + g73 + g75 + g77) + 16) >> 5;
+
+ est0 = g13 + g75 + split * 2;
+
+ grad0 = Abs_int32 (g13 - g75) +
+ Abs_int32 (g15 - g46) +
+ Abs_int32 (g22 - g53) +
+ Abs_int32 (g35 - g66) +
+ Abs_int32 (g42 - g73) +
+ Abs_int32 (b03 - b65) +
+ Abs_int32 (b23 - b85);
+
+ est1 = g33 + g55 + split * 2;
+
+ grad1 = Abs_int32 (g33 - g55) +
+ Abs_int32 (g22 - g55) +
+ Abs_int32 (g33 - g66) +
+ Abs_int32 (g13 - g35) +
+ Abs_int32 (g53 - g75) +
+ Abs_int32 (b23 - b45) +
+ Abs_int32 (b43 - b65);
+
+ est2 = g31 + g57 + split * 2;
+
+ grad2 = Abs_int32 (g31 - g57) +
+ Abs_int32 (g33 - g46) +
+ Abs_int32 (g35 - g48) +
+ Abs_int32 (g40 - g53) +
+ Abs_int32 (g42 - g55) +
+ Abs_int32 (r30 - r56) +
+ Abs_int32 (r32 - r58);
+
+ est3 = g42 + g46;
+
+ grad3 = Abs_int32 (g42 - g46) * 2 +
+ Abs_int32 (g33 - g35) +
+ Abs_int32 (g53 - g55) +
+ Abs_int32 (b23 - b25) +
+ Abs_int32 (b43 - b45) +
+ Abs_int32 (b63 - b65);
+
+ est4 = g37 + g51 + split * 2;
+
+ grad4 = Abs_int32 (g37 - g51) +
+ Abs_int32 (g35 - g42) +
+ Abs_int32 (g33 - g40) +
+ Abs_int32 (g48 - g55) +
+ Abs_int32 (g46 - g53) +
+ Abs_int32 (r38 - r52) +
+ Abs_int32 (r36 - r50);
+
+ est5 = g35 + g53 + split * 2;
+
+ grad5 = Abs_int32 (g35 - g53) +
+ Abs_int32 (g26 - g53) +
+ Abs_int32 (g35 - g62) +
+ Abs_int32 (g15 - g33) +
+ Abs_int32 (g55 - g73) +
+ Abs_int32 (b25 - b43) +
+ Abs_int32 (b45 - b63);
+
+ est6 = g15 + g73 + split * 2;
+
+ grad6 = Abs_int32 (g15 - g73) +
+ Abs_int32 (g13 - g42) +
+ Abs_int32 (g26 - g55) +
+ Abs_int32 (g33 - g62) +
+ Abs_int32 (g46 - g75) +
+ Abs_int32 (b05 - b63) +
+ Abs_int32 (b25 - b83);
+
+ lower = Min_uint32 (Min_uint32 (g33, g35),
+ Min_uint32 (g53, g55));
+
+ upper = Max_uint32 (Max_uint32 (g33, g35),
+ Max_uint32 (g53, g55));
+
+ lower = Pin_int32 (0, lower + split, 65535);
+ upper = Pin_int32 (0, upper + split, 65535);
+
+ }
+
+ else // Red/blue pixel
+ {
+
+ // b00 g01 b02 g03 b04 g05 b06 g07 b08
+ // g10 r11 g12 r13 g14 r15 g16 r17 g18
+ // b20 g21 b22 g23 b24 g25 b26 g27 b28
+ // g30 r31 g32 r33 g34 r35 g36 r37 g38
+ // b40 g41 b42 g43 b44 g45 b46 g47 b48
+ // g50 r51 g52 r53 g54 r55 g56 r57 g58
+ // b60 g61 b62 g63 b64 g65 b66 g67 b68
+ // g70 r71 g72 r73 g74 r75 g76 r77 g78
+ // b80 g81 b82 g83 b84 g85 b86 g87 b88
+
+ int32 b02 = p0 [2 * cs];
+ int32 g03 = p0 [3 * cs];
+ int32 g05 = p0 [5 * cs];
+ int32 b06 = p0 [6 * cs];
+
+ int32 r13 = p1 [3 * cs];
+ int32 r15 = p1 [5 * cs];
+
+ int32 b20 = p2 [0 * cs];
+ int32 b22 = p2 [2 * cs];
+ int32 g23 = p2 [3 * cs];
+ int32 g25 = p2 [5 * cs];
+ int32 b26 = p2 [6 * cs];
+ int32 b28 = p2 [8 * cs];
+
+ int32 r31 = p3 [1 * cs];
+ int32 g32 = p3 [2 * cs];
+ int32 r33 = p3 [3 * cs];
+ int32 r35 = p3 [5 * cs];
+ int32 g36 = p3 [6 * cs];
+ int32 r37 = p3 [7 * cs];
+
+ int32 g41 = p4 [1 * cs];
+ int32 b42 = p4 [2 * cs];
+ int32 g43 = p4 [3 * cs];
+ int32 g45 = p4 [5 * cs];
+ int32 b46 = p4 [6 * cs];
+ int32 g47 = p4 [7 * cs];
+
+ int32 r51 = p5 [1 * cs];
+ int32 g52 = p5 [2 * cs];
+ int32 r53 = p5 [3 * cs];
+ int32 r55 = p5 [5 * cs];
+ int32 g56 = p5 [6 * cs];
+ int32 r57 = p5 [7 * cs];
+
+ int32 b60 = p6 [0 * cs];
+ int32 b62 = p6 [2 * cs];
+ int32 g63 = p6 [3 * cs];
+ int32 g65 = p6 [5 * cs];
+ int32 b66 = p6 [6 * cs];
+ int32 b68 = p6 [8 * cs];
+
+ int32 r73 = p7 [3 * cs];
+ int32 r75 = p7 [5 * cs];
+
+ int32 b82 = p8 [2 * cs];
+ int32 g83 = p8 [3 * cs];
+ int32 g85 = p8 [5 * cs];
+ int32 b86 = p8 [6 * cs];
+
+ est0 = b02 + b86;
+
+ grad0 = Abs_int32 (b02 - b86) +
+ Abs_int32 (r13 - r55) +
+ Abs_int32 (r33 - r75) +
+ Abs_int32 (g03 - g45) +
+ Abs_int32 (g23 - g65) +
+ Abs_int32 (g43 - g85);
+
+ est1 = b22 + b66;
+
+ grad1 = Abs_int32 (b22 - b66) +
+ Abs_int32 (r13 - r35) +
+ Abs_int32 (r33 - r55) +
+ Abs_int32 (r53 - r75) +
+ Abs_int32 (g23 - g45) +
+ Abs_int32 (g43 - g65);
+
+ est2 = b20 + b68;
+
+ grad2 = Abs_int32 (b20 - b68) +
+ Abs_int32 (r31 - r55) +
+ Abs_int32 (r33 - r57) +
+ Abs_int32 (g23 - g47) +
+ Abs_int32 (g32 - g56) +
+ Abs_int32 (g41 - g65);
+
+ est3 = b42 + b46;
+
+ grad3 = Abs_int32 (b42 - b46) +
+ Abs_int32 (r33 - r35) +
+ Abs_int32 (r53 - r55) +
+ Abs_int32 (g32 - g36) +
+ Abs_int32 (g43 - g43) +
+ Abs_int32 (g52 - g56);
+
+ est4 = b28 + b60;
+
+ grad4 = Abs_int32 (b28 - b60) +
+ Abs_int32 (r37 - r53) +
+ Abs_int32 (r35 - r51) +
+ Abs_int32 (g25 - g41) +
+ Abs_int32 (g36 - g52) +
+ Abs_int32 (g47 - g63);
+
+ est5 = b26 + b62;
+
+ grad5 = Abs_int32 (b26 - b62) +
+ Abs_int32 (r15 - r33) +
+ Abs_int32 (r35 - r53) +
+ Abs_int32 (r55 - r73) +
+ Abs_int32 (g25 - g43) +
+ Abs_int32 (g45 - g63);
+
+ est6 = b06 + b82;
+
+ grad6 = Abs_int32 (b06 - b82) +
+ Abs_int32 (r15 - r53) +
+ Abs_int32 (r35 - r73) +
+ Abs_int32 (g05 - g43) +
+ Abs_int32 (g25 - g63) +
+ Abs_int32 (g45 - g83);
+
+ lower = Min_uint32 (b42, b46);
+ upper = Max_uint32 (b42, b46);
+
+ }
+
+ uint32 minGrad = Min_uint32 (grad0, grad1);
+
+ minGrad = Min_uint32 (minGrad, grad2);
+ minGrad = Min_uint32 (minGrad, grad3);
+ minGrad = Min_uint32 (minGrad, grad4);
+ minGrad = Min_uint32 (minGrad, grad5);
+ minGrad = Min_uint32 (minGrad, grad6);
+
+ uint32 limit = (minGrad * 3) >> 1;
+
+ uint32 total = 0;
+ uint32 count = 0;
+
+ if (grad0 <= limit)
+ {
+ total += est0;
+ count += 2;
+ }
+
+ if (grad1 <= limit)
+ {
+ total += est1;
+ count += 2;
+ }
+
+ if (grad2 <= limit)
+ {
+ total += est2;
+ count += 2;
+ }
+
+ if (grad3 <= limit)
+ {
+ total += est3;
+ count += 2;
+ }
+
+ if (grad4 <= limit)
+ {
+ total += est4;
+ count += 2;
+ }
+
+ if (grad5 <= limit)
+ {
+ total += est5;
+ count += 2;
+ }
+
+ if (grad6 <= limit)
+ {
+ total += est6;
+ count += 2;
+ }
+
+ uint32 estimate = (total + (count >> 1)) / count;
+
+ p4 [4] = (uint16) Pin_uint32 (lower, estimate, upper);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::FixSingleRow (dng_pixel_buffer &buffer,
+ const dng_rect &badRect)
+ {
+
+ dng_pixel_buffer tBuffer = buffer;
+
+ tBuffer.fArea = Transpose (buffer.fArea);
+
+ tBuffer.fRowStep = buffer.fColStep;
+ tBuffer.fColStep = buffer.fRowStep;
+
+ dng_rect tBadRect = Transpose (badRect);
+
+ FixSingleColumn (tBuffer, tBadRect);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::FixClusteredRect (dng_pixel_buffer &buffer,
+ const dng_rect &badRect,
+ const dng_rect &imageBounds)
+ {
+
+ const uint32 kNumSets = 8;
+ const uint32 kSetSize = 8;
+
+ static const int32 kOffset [kNumSets] [kSetSize] [2] =
+ {
+ {
+ { -1, 1 },
+ { -1, -1 },
+ { 1, -1 },
+ { 1, 1 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ },
+ {
+ { -2, 0 },
+ { 2, 0 },
+ { 0, -2 },
+ { 0, 2 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ },
+ {
+ { -2, -2 },
+ { -2, 2 },
+ { 2, -2 },
+ { 2, 2 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ },
+ {
+ { -1, -3 },
+ { -3, -1 },
+ { 1, -3 },
+ { 3, -1 },
+ { -1, 3 },
+ { -3, 1 },
+ { 1, 3 },
+ { 3, 1 }
+ },
+ {
+ { -4, 0 },
+ { 4, 0 },
+ { 0, -4 },
+ { 0, 4 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ },
+ {
+ { -3, -3 },
+ { -3, 3 },
+ { 3, -3 },
+ { 3, 3 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ },
+ {
+ { -2, -4 },
+ { -4, -2 },
+ { 2, -4 },
+ { 4, -2 },
+ { -2, 4 },
+ { -4, 2 },
+ { 2, 4 },
+ { 4, 2 }
+ },
+ {
+ { -4, -4 },
+ { -4, 4 },
+ { 4, -4 },
+ { 4, 4 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+ }
+ };
+
+ bool didFail = false;
+
+ for (int32 row = badRect.t; row < badRect.b; row++)
+ {
+
+ for (int32 col = badRect.l; col < badRect.r; col++)
+ {
+
+ uint16 *p = buffer.DirtyPixel_uint16 (row, col, 0);
+
+ bool isGreen = IsGreen (row, col);
+
+ bool didFixPixel = false;
+
+ for (uint32 set = 0; set < kNumSets && !didFixPixel; set++)
+ {
+
+ if (!isGreen && (kOffset [set] [0] [0] & 1) == 1)
+ {
+ continue;
+ }
+
+ uint32 total = 0;
+ uint32 count = 0;
+
+ for (uint32 entry = 0; entry < kSetSize; entry++)
+ {
+
+ dng_point offset (kOffset [set] [entry] [0],
+ kOffset [set] [entry] [1]);
+
+ if (offset.v == 0 &&
+ offset.h == 0)
+ {
+ break;
+ }
+
+ if (fList->IsPointValid (dng_point (row, col) + offset,
+ imageBounds))
+ {
+
+ total += p [offset.v * buffer.fRowStep +
+ offset.h * buffer.fColStep];
+
+ count++;
+
+ }
+
+ }
+
+ if (count)
+ {
+
+ uint32 estimate = (total + (count >> 1)) / count;
+
+ p [0] = (uint16) estimate;
+
+ didFixPixel = true;
+
+ }
+
+ }
+
+ if (!didFixPixel)
+ {
+
+ didFail = true;
+
+ }
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (didFail)
+ {
+
+ ReportWarning ("Unable to repair bad rectangle");
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixBadPixelsList::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds)
+ {
+
+ uint32 pointCount = fList->PointCount ();
+ uint32 rectCount = fList->RectCount ();
+
+ dng_rect fixArea = dstArea;
+
+ if (rectCount)
+ {
+ fixArea.t -= kBadRectPadding;
+ fixArea.l -= kBadRectPadding;
+ fixArea.b += kBadRectPadding;
+ fixArea.r += kBadRectPadding;
+ }
+
+ bool didFixPoint = false;
+
+ if (pointCount)
+ {
+
+ for (uint32 pointIndex = 0; pointIndex < pointCount; pointIndex++)
+ {
+
+ dng_point badPoint = fList->Point (pointIndex);
+
+ if (badPoint.v >= fixArea.t &&
+ badPoint.h >= fixArea.l &&
+ badPoint.v < fixArea.b &&
+ badPoint.h < fixArea.r)
+ {
+
+ bool isIsolated = fList->IsPointIsolated (pointIndex,
+ kBadPointPadding);
+
+ if (isIsolated &&
+ badPoint.v >= imageBounds.t + kBadPointPadding &&
+ badPoint.h >= imageBounds.l + kBadPointPadding &&
+ badPoint.v < imageBounds.b - kBadPointPadding &&
+ badPoint.h < imageBounds.r - kBadPointPadding)
+ {
+
+ FixIsolatedPixel (srcBuffer,
+ badPoint);
+
+ }
+
+ else
+ {
+
+ FixClusteredPixel (srcBuffer,
+ pointIndex,
+ imageBounds);
+
+ }
+
+ didFixPoint = true;
+
+ }
+
+ }
+
+ }
+
+ if (rectCount)
+ {
+
+ if (didFixPoint)
+ {
+
+ srcBuffer.RepeatSubArea (imageBounds,
+ SrcRepeat ().v,
+ SrcRepeat ().h);
+
+ }
+
+ for (uint32 rectIndex = 0; rectIndex < rectCount; rectIndex++)
+ {
+
+ dng_rect badRect = fList->Rect (rectIndex);
+
+ dng_rect overlap = dstArea & badRect;
+
+ if (overlap.NotEmpty ())
+ {
+
+ bool isIsolated = fList->IsRectIsolated (rectIndex,
+ kBadRectPadding);
+
+ if (isIsolated &&
+ badRect.r == badRect.l + 1 &&
+ badRect.l >= imageBounds.l + SrcRepeat ().h &&
+ badRect.r <= imageBounds.r - SrcRepeat ().v)
+ {
+
+ FixSingleColumn (srcBuffer,
+ overlap);
+
+ }
+
+ else if (isIsolated &&
+ badRect.b == badRect.t + 1 &&
+ badRect.t >= imageBounds.t + SrcRepeat ().h &&
+ badRect.b <= imageBounds.b - SrcRepeat ().v)
+ {
+
+ FixSingleRow (srcBuffer,
+ overlap);
+
+ }
+
+ else
+ {
+
+ FixClusteredRect (srcBuffer,
+ overlap,
+ imageBounds);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ dstBuffer.CopyArea (srcBuffer,
+ dstArea,
+ 0,
+ dstBuffer.fPlanes);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_bad_pixels.h b/gpr/source/lib/dng_sdk/dng_bad_pixels.h
new file mode 100644
index 0000000..c7b65d6
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_bad_pixels.h
@@ -0,0 +1,307 @@
+/*****************************************************************************/
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bad_pixels.h#3 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Opcodes to fix defective pixels, including individual pixels and regions (such as
+ * defective rows and columns).
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_bad_pixels__
+#define __dng_bad_pixels__
+
+/*****************************************************************************/
+
+#include "dng_opcodes.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+/// \brief An opcode to fix individual bad pixels that are marked with a constant
+/// value (e.g., 0) in a Bayer image.
+
+class dng_opcode_FixBadPixelsConstant: public dng_filter_opcode
+ {
+
+ private:
+
+ uint32 fConstant;
+
+ uint32 fBayerPhase;
+
+ public:
+
+ /// Construct an opcode to fix an individual bad pixels that are marked with
+ /// a constant value in a Bayer image.
+ /// \param constant The constant value that indicates a bad pixel.
+ /// \param bayerPhase The phase of the Bayer mosaic pattern (0, 1, 2, 3).
+
+ dng_opcode_FixBadPixelsConstant (uint32 constant,
+ uint32 bayerPhase);
+
+ dng_opcode_FixBadPixelsConstant (dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual dng_point SrcRepeat ();
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ virtual void Prepare (dng_negative &negative,
+ uint32 threadCount,
+ const dng_point &tileSize,
+ const dng_rect &imageBounds,
+ uint32 imagePlanes,
+ uint32 bufferPixelType,
+ dng_memory_allocator &allocator);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ protected:
+
+ bool IsGreen (int32 row, int32 col) const
+ {
+ return (((uint32) row + (uint32) col + fBayerPhase + (fBayerPhase >> 1)) & 1) == 0;
+ }
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A list of bad pixels and rectangles (usually single rows or columns).
+
+class dng_bad_pixel_list
+ {
+
+ public:
+
+ enum
+ {
+ kNoIndex = 0xFFFFFFFF
+ };
+
+ private:
+
+ // List of bad single pixels.
+
+ std::vector<dng_point> fBadPoints;
+
+ // List of bad rectangles (usually single rows or columns).
+
+ std::vector<dng_rect> fBadRects;
+
+ public:
+
+ /// Create an empty bad pixel list.
+
+ dng_bad_pixel_list ();
+
+ /// Returns the number of bad single pixels.
+
+ uint32 PointCount () const
+ {
+ return (uint32) fBadPoints.size ();
+ }
+
+ /// Retrieves the bad single pixel coordinate via the specified list index.
+ ///
+ /// \param index The list index from which to retrieve the bad single pixel
+ /// coordinate.
+
+ const dng_point & Point (uint32 index) const
+ {
+ return fBadPoints [index];
+ }
+
+ /// Returns the number of bad rectangles.
+
+ uint32 RectCount () const
+ {
+ return (uint32) fBadRects.size ();
+ }
+
+ /// Retrieves the bad rectangle via the specified list index.
+ ///
+ /// \param index The list index from which to retrieve the bad rectangle
+ /// coordinates.
+
+ const dng_rect & Rect (uint32 index) const
+ {
+ return fBadRects [index];
+ }
+
+ /// Returns true iff there are zero bad single pixels and zero bad
+ /// rectangles.
+
+ bool IsEmpty () const
+ {
+ return PointCount () == 0 &&
+ RectCount () == 0;
+ }
+
+ /// Returns true iff there is at least one bad single pixel or at least one
+ /// bad rectangle.
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ /// Add the specified coordinate to the list of bad single pixels.
+ ///
+ /// \param pt The bad single pixel to add.
+
+ void AddPoint (const dng_point &pt);
+
+ /// Add the specified rectangle to the list of bad rectangles.
+ ///
+ /// \param pt The bad rectangle to add.
+
+ void AddRect (const dng_rect &r);
+
+ /// Sort the bad single pixels and bad rectangles by coordinates (top to
+ /// bottom, then left to right).
+
+ void Sort ();
+
+ /// Returns true iff the specified bad single pixel is isolated, i.e., there
+ /// is no other bad single pixel or bad rectangle that lies within radius
+ /// pixels of this bad single pixel.
+ ///
+ /// \param index The index of the bad single pixel to test.
+ /// \param radius The pixel radius to test for isolation.
+
+ bool IsPointIsolated (uint32 index,
+ uint32 radius) const;
+
+ /// Returns true iff the specified bad rectangle is isolated, i.e., there
+ /// is no other bad single pixel or bad rectangle that lies within radius
+ /// pixels of this bad rectangle.
+ ///
+ /// \param index The index of the bad rectangle to test.
+ /// \param radius The pixel radius to test for isolation.
+
+ bool IsRectIsolated (uint32 index,
+ uint32 radius) const;
+
+ /// Returns true iff the specified point is valid, i.e., lies within the
+ /// specified image bounds, is different from all other bad single pixels,
+ /// and is not contained in any bad rectangle. The second and third
+ /// conditions are only checked if provided with a starting search index.
+ ///
+ /// \param pt The point to test for validity.
+ /// \param imageBounds The pt must lie within imageBounds to be valid.
+ /// \index The search index to use (or kNoIndex, to avoid a search) for
+ /// checking for validity.
+
+ bool IsPointValid (const dng_point &pt,
+ const dng_rect &imageBounds,
+ uint32 index = kNoIndex) const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to fix lists of bad pixels (indicated by position) in a Bayer
+/// image.
+
+class dng_opcode_FixBadPixelsList: public dng_filter_opcode
+ {
+
+ protected:
+
+ enum
+ {
+ kBadPointPadding = 2,
+ kBadRectPadding = 4
+ };
+
+ private:
+
+ AutoPtr<dng_bad_pixel_list> fList;
+
+ uint32 fBayerPhase;
+
+ public:
+
+ /// Construct an opcode to fix lists of bad pixels (indicated by position) in
+ /// a Bayer image.
+ /// \param list The list of bad pixels to fix.
+ /// \param bayerPhase The phase of the Bayer mosaic pattern (0, 1, 2, 3).
+
+ dng_opcode_FixBadPixelsList (AutoPtr<dng_bad_pixel_list> &list,
+ uint32 bayerPhase);
+
+ dng_opcode_FixBadPixelsList (dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual dng_point SrcRepeat ();
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ virtual void Prepare (dng_negative &negative,
+ uint32 threadCount,
+ const dng_point &tileSize,
+ const dng_rect &imageBounds,
+ uint32 imagePlanes,
+ uint32 bufferPixelType,
+ dng_memory_allocator &allocator);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ protected:
+
+ bool IsGreen (int32 row, int32 col) const
+ {
+ return ((row + col + fBayerPhase + (fBayerPhase >> 1)) & 1) == 0;
+ }
+
+ virtual void FixIsolatedPixel (dng_pixel_buffer &buffer,
+ dng_point &badPoint);
+
+ virtual void FixClusteredPixel (dng_pixel_buffer &buffer,
+ uint32 pointIndex,
+ const dng_rect &imageBounds);
+
+ virtual void FixSingleColumn (dng_pixel_buffer &buffer,
+ const dng_rect &badRect);
+
+ virtual void FixSingleRow (dng_pixel_buffer &buffer,
+ const dng_rect &badRect);
+
+ virtual void FixClusteredRect (dng_pixel_buffer &buffer,
+ const dng_rect &badRect,
+ const dng_rect &imageBounds);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_bottlenecks.cpp b/gpr/source/lib/dng_sdk/dng_bottlenecks.cpp
new file mode 100644
index 0000000..44fdb7a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_bottlenecks.cpp
@@ -0,0 +1,72 @@
+/*****************************************************************************/
+// Copyright 2006-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bottlenecks.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_bottlenecks.h"
+
+#include "dng_reference.h"
+
+/*****************************************************************************/
+
+dng_suite gDNGSuite =
+ {
+ RefZeroBytes,
+ RefCopyBytes,
+ RefSwapBytes16,
+ RefSwapBytes32,
+ RefSetArea8,
+ RefSetArea16,
+ RefSetArea32,
+ RefCopyArea8,
+ RefCopyArea16,
+ RefCopyArea32,
+ RefCopyArea8_16,
+ RefCopyArea8_S16,
+ RefCopyArea8_32,
+ RefCopyArea16_S16,
+ RefCopyArea16_32,
+ RefCopyArea8_R32,
+ RefCopyArea16_R32,
+ RefCopyAreaS16_R32,
+ RefCopyAreaR32_8,
+ RefCopyAreaR32_16,
+ RefCopyAreaR32_S16,
+ RefRepeatArea8,
+ RefRepeatArea16,
+ RefRepeatArea32,
+ RefShiftRight16,
+ RefBilinearRow16,
+ RefBilinearRow32,
+ RefBaselineABCtoRGB,
+ RefBaselineABCDtoRGB,
+ RefBaselineHueSatMap,
+ RefBaselineRGBtoGray,
+ RefBaselineRGBtoRGB,
+ RefBaseline1DTable,
+ RefBaselineRGBTone,
+ RefResampleDown16,
+ RefResampleDown32,
+ RefResampleAcross16,
+ RefResampleAcross32,
+ RefEqualBytes,
+ RefEqualArea8,
+ RefEqualArea16,
+ RefEqualArea32,
+ RefVignetteMask16,
+ RefVignette16,
+ RefVignette32,
+ RefMapArea16
+ };
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_bottlenecks.h b/gpr/source/lib/dng_sdk/dng_bottlenecks.h
new file mode 100644
index 0000000..ff8cbb0
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_bottlenecks.h
@@ -0,0 +1,1715 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bottlenecks.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Indirection mechanism for performance-critical routines that might be replaced
+ * with hand-optimized or hardware-specific implementations.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_bottlenecks__
+#define __dng_bottlenecks__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+typedef void (ZeroBytesProc)
+ (void *dPtr,
+ uint32 count);
+
+typedef void (CopyBytesProc)
+ (const void *sPtr,
+ void *dPtr,
+ uint32 count);
+
+/*****************************************************************************/
+
+typedef void (SwapBytes16Proc)
+ (uint16 *dPtr,
+ uint32 count);
+
+typedef void (SwapBytes32Proc)
+ (uint32 *dPtr,
+ uint32 count);
+
+/*****************************************************************************/
+
+typedef void (SetArea8Proc)
+ (uint8 *dPtr,
+ uint8 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+
+typedef void (SetArea16Proc)
+ (uint16 *dPtr,
+ uint16 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+
+typedef void (SetArea32Proc)
+ (uint32 *dPtr,
+ uint32 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+
+/*****************************************************************************/
+
+typedef void (CopyArea8Proc)
+ (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea16Proc)
+ (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea32Proc)
+ (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea8_16Proc)
+ (const uint8 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea8_S16Proc)
+ (const uint8 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea8_32Proc)
+ (const uint8 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea16_S16Proc)
+ (const uint16 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea16_32Proc)
+ (const uint16 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef void (CopyArea8_R32Proc)
+ (const uint8 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+typedef void (CopyArea16_R32Proc)
+ (const uint16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+typedef void (CopyAreaS16_R32Proc)
+ (const int16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+typedef void (CopyAreaR32_8Proc)
+ (const real32 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+typedef void (CopyAreaR32_16Proc)
+ (const real32 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+typedef void (CopyAreaR32_S16Proc)
+ (const real32 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+/*****************************************************************************/
+
+typedef void (RepeatArea8Proc)
+ (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH);
+
+typedef void (RepeatArea16Proc)
+ (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH);
+
+typedef void (RepeatArea32Proc)
+ (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH);
+
+/*****************************************************************************/
+
+typedef void (ShiftRight16Proc)
+ (uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 shift);
+
+/*****************************************************************************/
+
+typedef void (BilinearRow16Proc)
+ (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const uint16 * const * kernWeights,
+ uint32 sShift);
+
+typedef void (BilinearRow32Proc)
+ (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const real32 * const * kernWeights,
+ uint32 sShift);
+
+/*****************************************************************************/
+
+typedef void (BaselineABCtoRGBProc)
+ (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB);
+
+typedef void (BaselineABCDtoRGBProc)
+ (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ const real32 *sPtrD,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB);
+
+/*****************************************************************************/
+
+typedef void (BaselineHueSatMapProc)
+ (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_hue_sat_map &lut,
+ const dng_1d_table *encodeTable,
+ const dng_1d_table *decodeTable);
+
+/*****************************************************************************/
+
+typedef void (BaselineGrayToRGBProc)
+ (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrG,
+ uint32 count,
+ const dng_matrix &matrix);
+
+typedef void (BaselineRGBtoRGBProc)
+ (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_matrix &matrix);
+
+/*****************************************************************************/
+
+typedef void (Baseline1DTableProc)
+ (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 count,
+ const dng_1d_table &table);
+
+/*****************************************************************************/
+
+typedef void (BaselineRGBToneProc)
+ (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_1d_table &table);
+
+/*****************************************************************************/
+
+typedef void (ResampleDown16Proc)
+ (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 pixelRange);
+
+typedef void (ResampleDown32Proc)
+ (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const real32 *wPtr,
+ uint32 wCount);
+
+/*****************************************************************************/
+
+typedef void (ResampleAcross16Proc)
+ (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 wStep,
+ uint32 pixelRange);
+
+typedef void (ResampleAcross32Proc)
+ (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const real32 *wPtr,
+ uint32 wCount,
+ uint32 wStep);
+
+/*****************************************************************************/
+
+typedef bool (EqualBytesProc)
+ (const void *sPtr,
+ const void *dPtr,
+ uint32 count);
+
+typedef bool (EqualArea8Proc)
+ (const uint8 *sPtr,
+ const uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef bool (EqualArea16Proc)
+ (const uint16 *sPtr,
+ const uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+typedef bool (EqualArea32Proc)
+ (const uint32 *sPtr,
+ const uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+/*****************************************************************************/
+
+typedef void (VignetteMask16Proc)
+ (uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ int32 rowStep,
+ int64 offsetH,
+ int64 offsetV,
+ int64 stepH,
+ int64 stepV,
+ uint32 tBits,
+ const uint16 *table);
+
+typedef void (Vignette16Proc)
+ (int16 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits);
+
+/*****************************************************************************/
+
+typedef void (Vignette32Proc)
+ (real32 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits);
+
+/*****************************************************************************/
+
+typedef void (MapArea16Proc)
+ (uint16 *dPtr,
+ uint32 count0,
+ uint32 count1,
+ uint32 count2,
+ int32 step0,
+ int32 step1,
+ int32 step2,
+ const uint16 *map);
+
+/*****************************************************************************/
+
+struct dng_suite
+ {
+ ZeroBytesProc *ZeroBytes;
+ CopyBytesProc *CopyBytes;
+ SwapBytes16Proc *SwapBytes16;
+ SwapBytes32Proc *SwapBytes32;
+ SetArea8Proc *SetArea8;
+ SetArea16Proc *SetArea16;
+ SetArea32Proc *SetArea32;
+ CopyArea8Proc *CopyArea8;
+ CopyArea16Proc *CopyArea16;
+ CopyArea32Proc *CopyArea32;
+ CopyArea8_16Proc *CopyArea8_16;
+ CopyArea8_S16Proc *CopyArea8_S16;
+ CopyArea8_32Proc *CopyArea8_32;
+ CopyArea16_S16Proc *CopyArea16_S16;
+ CopyArea16_32Proc *CopyArea16_32;
+ CopyArea8_R32Proc *CopyArea8_R32;
+ CopyArea16_R32Proc *CopyArea16_R32;
+ CopyAreaS16_R32Proc *CopyAreaS16_R32;
+ CopyAreaR32_8Proc *CopyAreaR32_8;
+ CopyAreaR32_16Proc *CopyAreaR32_16;
+ CopyAreaR32_S16Proc *CopyAreaR32_S16;
+ RepeatArea8Proc *RepeatArea8;
+ RepeatArea16Proc *RepeatArea16;
+ RepeatArea32Proc *RepeatArea32;
+ ShiftRight16Proc *ShiftRight16;
+ BilinearRow16Proc *BilinearRow16;
+ BilinearRow32Proc *BilinearRow32;
+ BaselineABCtoRGBProc *BaselineABCtoRGB;
+ BaselineABCDtoRGBProc *BaselineABCDtoRGB;
+ BaselineHueSatMapProc *BaselineHueSatMap;
+ BaselineGrayToRGBProc *BaselineRGBtoGray;
+ BaselineRGBtoRGBProc *BaselineRGBtoRGB;
+ Baseline1DTableProc *Baseline1DTable;
+ BaselineRGBToneProc *BaselineRGBTone;
+ ResampleDown16Proc *ResampleDown16;
+ ResampleDown32Proc *ResampleDown32;
+ ResampleAcross16Proc *ResampleAcross16;
+ ResampleAcross32Proc *ResampleAcross32;
+ EqualBytesProc *EqualBytes;
+ EqualArea8Proc *EqualArea8;
+ EqualArea16Proc *EqualArea16;
+ EqualArea32Proc *EqualArea32;
+ VignetteMask16Proc *VignetteMask16;
+ Vignette16Proc *Vignette16;
+ Vignette32Proc *Vignette32;
+ MapArea16Proc *MapArea16;
+ };
+
+/*****************************************************************************/
+
+extern dng_suite gDNGSuite;
+
+/*****************************************************************************/
+
+inline void DoZeroBytes (void *dPtr,
+ uint32 count)
+ {
+
+ (gDNGSuite.ZeroBytes) (dPtr,
+ count);
+
+ }
+
+inline void DoCopyBytes (const void *sPtr,
+ void *dPtr,
+ uint32 count)
+ {
+
+ (gDNGSuite.CopyBytes) (sPtr,
+ dPtr,
+ count);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoSwapBytes16 (uint16 *dPtr,
+ uint32 count)
+ {
+
+ (gDNGSuite.SwapBytes16) (dPtr,
+ count);
+
+ }
+
+inline void DoSwapBytes32 (uint32 *dPtr,
+ uint32 count)
+ {
+
+ (gDNGSuite.SwapBytes32) (dPtr,
+ count);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoSetArea8 (uint8 *dPtr,
+ uint8 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
+ {
+
+ (gDNGSuite.SetArea8) (dPtr,
+ value,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep);
+
+ }
+
+inline void DoSetArea16 (uint16 *dPtr,
+ uint16 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
+ {
+
+ (gDNGSuite.SetArea16) (dPtr,
+ value,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep);
+
+ }
+
+inline void DoSetArea32 (uint32 *dPtr,
+ uint32 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
+ {
+
+ (gDNGSuite.SetArea32) (dPtr,
+ value,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoCopyArea8 (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea8) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea32 (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea8_16 (const uint8 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea8_16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea8_S16 (const uint8 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea8_S16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea8_32 (const uint8 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea8_32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea16_S16 (const uint16 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea16_S16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea16_32 (const uint16 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ (gDNGSuite.CopyArea16_32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline void DoCopyArea8_R32 (const uint8 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.CopyArea8_R32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ pixelRange);
+
+ }
+
+inline void DoCopyArea16_R32 (const uint16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.CopyArea16_R32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ pixelRange);
+
+ }
+
+inline void DoCopyAreaS16_R32 (const int16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.CopyAreaS16_R32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ pixelRange);
+
+ }
+
+inline void DoCopyAreaR32_8 (const real32 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.CopyAreaR32_8) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ pixelRange);
+
+ }
+
+inline void DoCopyAreaR32_16 (const real32 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.CopyAreaR32_16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ pixelRange);
+
+ }
+
+inline void DoCopyAreaR32_S16 (const real32 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.CopyAreaR32_S16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ pixelRange);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoRepeatArea8 (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH)
+ {
+
+ (gDNGSuite.RepeatArea8) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep,
+ repeatV,
+ repeatH,
+ phaseV,
+ phaseH);
+
+ }
+
+inline void DoRepeatArea16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH)
+ {
+
+ (gDNGSuite.RepeatArea16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep,
+ repeatV,
+ repeatH,
+ phaseV,
+ phaseH);
+
+ }
+
+inline void DoRepeatArea32 (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH)
+ {
+
+ (gDNGSuite.RepeatArea32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep,
+ repeatV,
+ repeatH,
+ phaseV,
+ phaseH);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoShiftRight16 (uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 shift)
+ {
+
+ (gDNGSuite.ShiftRight16) (dPtr,
+ rows,
+ cols,
+ planes,
+ rowStep,
+ colStep,
+ planeStep,
+ shift);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoBilinearRow16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const uint16 * const * kernWeights,
+ uint32 sShift)
+ {
+
+ (gDNGSuite.BilinearRow16) (sPtr,
+ dPtr,
+ cols,
+ patPhase,
+ patCount,
+ kernCounts,
+ kernOffsets,
+ kernWeights,
+ sShift);
+
+ }
+
+inline void DoBilinearRow32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const real32 * const * kernWeights,
+ uint32 sShift)
+ {
+
+ (gDNGSuite.BilinearRow32) (sPtr,
+ dPtr,
+ cols,
+ patPhase,
+ patCount,
+ kernCounts,
+ kernOffsets,
+ kernWeights,
+ sShift);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoBaselineABCtoRGB (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB)
+ {
+
+ (gDNGSuite.BaselineABCtoRGB) (sPtrA,
+ sPtrB,
+ sPtrC,
+ dPtrR,
+ dPtrG,
+ dPtrB,
+ count,
+ cameraWhite,
+ cameraToRGB);
+
+ }
+
+inline void DoBaselineABCDtoRGB (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ const real32 *sPtrD,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB)
+ {
+
+ (gDNGSuite.BaselineABCDtoRGB) (sPtrA,
+ sPtrB,
+ sPtrC,
+ sPtrD,
+ dPtrR,
+ dPtrG,
+ dPtrB,
+ count,
+ cameraWhite,
+ cameraToRGB);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoBaselineHueSatMap (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_hue_sat_map &lut,
+ const dng_1d_table *encodeTable,
+ const dng_1d_table *decodeTable)
+ {
+
+ (gDNGSuite.BaselineHueSatMap) (sPtrR,
+ sPtrG,
+ sPtrB,
+ dPtrR,
+ dPtrG,
+ dPtrB,
+ count,
+ lut,
+ encodeTable,
+ decodeTable);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoBaselineRGBtoGray (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrG,
+ uint32 count,
+ const dng_matrix &matrix)
+ {
+
+ (gDNGSuite.BaselineRGBtoGray) (sPtrR,
+ sPtrG,
+ sPtrB,
+ dPtrG,
+ count,
+ matrix);
+
+ }
+
+inline void DoBaselineRGBtoRGB (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_matrix &matrix)
+ {
+
+ (gDNGSuite.BaselineRGBtoRGB) (sPtrR,
+ sPtrG,
+ sPtrB,
+ dPtrR,
+ dPtrG,
+ dPtrB,
+ count,
+ matrix);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoBaseline1DTable (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 count,
+ const dng_1d_table &table)
+ {
+
+ (gDNGSuite.Baseline1DTable) (sPtr,
+ dPtr,
+ count,
+ table);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoBaselineRGBTone (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_1d_table &table)
+ {
+
+ (gDNGSuite.BaselineRGBTone) (sPtrR,
+ sPtrG,
+ sPtrB,
+ dPtrR,
+ dPtrG,
+ dPtrB,
+ count,
+ table);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoResampleDown16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.ResampleDown16) (sPtr,
+ dPtr,
+ sCount,
+ sRowStep,
+ wPtr,
+ wCount,
+ pixelRange);
+
+ }
+
+inline void DoResampleDown32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const real32 *wPtr,
+ uint32 wCount)
+ {
+
+ (gDNGSuite.ResampleDown32) (sPtr,
+ dPtr,
+ sCount,
+ sRowStep,
+ wPtr,
+ wCount);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoResampleAcross16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 wStep,
+ uint32 pixelRange)
+ {
+
+ (gDNGSuite.ResampleAcross16) (sPtr,
+ dPtr,
+ dCount,
+ coord,
+ wPtr,
+ wCount,
+ wStep,
+ pixelRange);
+
+ }
+
+inline void DoResampleAcross32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const real32 *wPtr,
+ uint32 wCount,
+ uint32 wStep)
+ {
+
+ (gDNGSuite.ResampleAcross32) (sPtr,
+ dPtr,
+ dCount,
+ coord,
+ wPtr,
+ wCount,
+ wStep);
+
+ }
+
+/*****************************************************************************/
+
+inline bool DoEqualBytes (const void *sPtr,
+ const void *dPtr,
+ uint32 count)
+ {
+
+ return (gDNGSuite.EqualBytes) (sPtr,
+ dPtr,
+ count);
+
+ }
+
+inline bool DoEqualArea8 (const uint8 *sPtr,
+ const uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ return (gDNGSuite.EqualArea8) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline bool DoEqualArea16 (const uint16 *sPtr,
+ const uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ return (gDNGSuite.EqualArea16) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+inline bool DoEqualArea32 (const uint32 *sPtr,
+ const uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ return (gDNGSuite.EqualArea32) (sPtr,
+ dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoVignetteMask16 (uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ int32 rowStep,
+ int64 offsetH,
+ int64 offsetV,
+ int64 stepH,
+ int64 stepV,
+ uint32 tBits,
+ const uint16 *table)
+ {
+
+ (gDNGSuite.VignetteMask16) (mPtr,
+ rows,
+ cols,
+ rowStep,
+ offsetH,
+ offsetV,
+ stepH,
+ stepV,
+ tBits,
+ table);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoVignette16 (int16 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits)
+ {
+
+ (gDNGSuite.Vignette16) (sPtr,
+ mPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sPlaneStep,
+ mRowStep,
+ mBits);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoVignette32 (real32 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits)
+ {
+
+ (gDNGSuite.Vignette32) (sPtr,
+ mPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sPlaneStep,
+ mRowStep,
+ mBits);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoMapArea16 (uint16 *dPtr,
+ uint32 count0,
+ uint32 count1,
+ uint32 count2,
+ int32 step0,
+ int32 step1,
+ int32 step2,
+ const uint16 *map)
+ {
+
+ (gDNGSuite.MapArea16) (dPtr,
+ count0,
+ count1,
+ count2,
+ step0,
+ step1,
+ step2,
+ map);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_camera_profile.cpp b/gpr/source/lib/dng_sdk/dng_camera_profile.cpp
new file mode 100644
index 0000000..6983b6d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_camera_profile.cpp
@@ -0,0 +1,1381 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_camera_profile.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+#include "dng_camera_profile.h"
+
+#include "dng_1d_table.h"
+#include "dng_assertions.h"
+#include "dng_color_space.h"
+#include "dng_host.h"
+#include "dng_exceptions.h"
+#include "dng_image_writer.h"
+#include "dng_info.h"
+#include "dng_parse_utils.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_temperature.h"
+#include "dng_xy_coord.h"
+
+/*****************************************************************************/
+
+const char * kProfileName_Embedded = "Embedded";
+
+const char * kAdobeCalibrationSignature = "com.adobe";
+
+/*****************************************************************************/
+
+dng_camera_profile::dng_camera_profile ()
+
+ : fName ()
+ , fCalibrationIlluminant1 (lsUnknown)
+ , fCalibrationIlluminant2 (lsUnknown)
+ , fColorMatrix1 ()
+ , fColorMatrix2 ()
+ , fForwardMatrix1 ()
+ , fForwardMatrix2 ()
+ , fReductionMatrix1 ()
+ , fReductionMatrix2 ()
+ , fFingerprint ()
+ , fCopyright ()
+ , fEmbedPolicy (pepAllowCopying)
+ , fHueSatDeltas1 ()
+ , fHueSatDeltas2 ()
+ , fHueSatMapEncoding (encoding_Linear)
+ , fLookTable ()
+ , fLookTableEncoding (encoding_Linear)
+ , fBaselineExposureOffset (0, 100)
+ , fDefaultBlackRender (defaultBlackRender_Auto)
+ , fToneCurve ()
+ , fProfileCalibrationSignature ()
+ , fUniqueCameraModelRestriction ()
+ , fWasReadFromDNG (false)
+ , fWasReadFromDisk (false)
+ , fWasBuiltinMatrix (false)
+ , fWasStubbed (false)
+
+ {
+
+ fToneCurve.SetInvalid ();
+
+ }
+
+/*****************************************************************************/
+
+dng_camera_profile::~dng_camera_profile ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_camera_profile::IlluminantToTemperature (uint32 light)
+ {
+
+ switch (light)
+ {
+
+ case lsStandardLightA:
+ case lsTungsten:
+ {
+ return 2850.0;
+ }
+
+ case lsISOStudioTungsten:
+ {
+ return 3200.0;
+ }
+
+ case lsD50:
+ {
+ return 5000.0;
+ }
+
+ case lsD55:
+ case lsDaylight:
+ case lsFineWeather:
+ case lsFlash:
+ case lsStandardLightB:
+ {
+ return 5500.0;
+ }
+
+ case lsD65:
+ case lsStandardLightC:
+ case lsCloudyWeather:
+ {
+ return 6500.0;
+ }
+
+ case lsD75:
+ case lsShade:
+ {
+ return 7500.0;
+ }
+
+ case lsDaylightFluorescent:
+ {
+ return (5700.0 + 7100.0) * 0.5;
+ }
+
+ case lsDayWhiteFluorescent:
+ {
+ return (4600.0 + 5500.0) * 0.5;
+ }
+
+ case lsCoolWhiteFluorescent:
+ case lsFluorescent:
+ {
+ return (3800.0 + 4500.0) * 0.5;
+ }
+
+ case lsWhiteFluorescent:
+ {
+ return (3250.0 + 3800.0) * 0.5;
+ }
+
+ case lsWarmWhiteFluorescent:
+ {
+ return (2600.0 + 3250.0) * 0.5;
+ }
+
+ default:
+ {
+ return 0.0;
+ }
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_camera_profile::NormalizeColorMatrix (dng_matrix &m)
+ {
+
+ if (m.NotEmpty ())
+ {
+
+ // Find scale factor to normalize the matrix.
+
+ dng_vector coord = m * PCStoXYZ ();
+
+ real64 maxCoord = coord.MaxEntry ();
+
+ if (maxCoord > 0.0 && (maxCoord < 0.99 || maxCoord > 1.01))
+ {
+
+ m.Scale (1.0 / maxCoord);
+
+ }
+
+ // Round to four decimal places.
+
+ m.Round (10000);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_camera_profile::SetColorMatrix1 (const dng_matrix &m)
+ {
+
+ fColorMatrix1 = m;
+
+ NormalizeColorMatrix (fColorMatrix1);
+
+ ClearFingerprint ();
+
+ }
+
+/******************************************************************************/
+
+void dng_camera_profile::SetColorMatrix2 (const dng_matrix &m)
+ {
+
+ fColorMatrix2 = m;
+
+ NormalizeColorMatrix (fColorMatrix2);
+
+ ClearFingerprint ();
+
+ }
+
+/******************************************************************************/
+
+// Make sure the forward matrix maps to exactly the PCS.
+
+void dng_camera_profile::NormalizeForwardMatrix (dng_matrix &m)
+ {
+
+ if (m.NotEmpty ())
+ {
+
+ dng_vector cameraOne;
+
+ cameraOne.SetIdentity (m.Cols ());
+
+ dng_vector xyz = m * cameraOne;
+
+ m = PCStoXYZ ().AsDiagonal () *
+ Invert (xyz.AsDiagonal ()) *
+ m;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_camera_profile::SetForwardMatrix1 (const dng_matrix &m)
+ {
+
+ fForwardMatrix1 = m;
+
+ fForwardMatrix1.Round (10000);
+
+ ClearFingerprint ();
+
+ }
+
+/******************************************************************************/
+
+void dng_camera_profile::SetForwardMatrix2 (const dng_matrix &m)
+ {
+
+ fForwardMatrix2 = m;
+
+ fForwardMatrix2.Round (10000);
+
+ ClearFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::SetReductionMatrix1 (const dng_matrix &m)
+ {
+
+ fReductionMatrix1 = m;
+
+ fReductionMatrix1.Round (10000);
+
+ ClearFingerprint ();
+
+ }
+
+/******************************************************************************/
+
+void dng_camera_profile::SetReductionMatrix2 (const dng_matrix &m)
+ {
+
+ fReductionMatrix2 = m;
+
+ fReductionMatrix2.Round (10000);
+
+ ClearFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_camera_profile::HasColorMatrix1 () const
+ {
+
+ return fColorMatrix1.Cols () == 3 &&
+ fColorMatrix1.Rows () > 1;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_camera_profile::HasColorMatrix2 () const
+ {
+
+ return fColorMatrix2.Cols () == 3 &&
+ fColorMatrix2.Rows () == fColorMatrix1.Rows ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::SetHueSatDeltas1 (const dng_hue_sat_map &deltas1)
+ {
+
+ fHueSatDeltas1 = deltas1;
+
+ ClearFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::SetHueSatDeltas2 (const dng_hue_sat_map &deltas2)
+ {
+
+ fHueSatDeltas2 = deltas2;
+
+ ClearFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::SetLookTable (const dng_hue_sat_map &table)
+ {
+
+ fLookTable = table;
+
+ ClearFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+static void FingerprintMatrix (dng_md5_printer_stream &printer,
+ const dng_matrix &matrix)
+ {
+
+ tag_matrix tag (0, matrix);
+
+ // Tag's Put routine doesn't write the header, only the data
+
+ tag.Put (printer);
+
+ }
+
+/*****************************************************************************/
+
+static void FingerprintHueSatMap (dng_md5_printer_stream &printer,
+ const dng_hue_sat_map &map)
+ {
+
+ if (map.IsNull ())
+ return;
+
+ uint32 hues;
+ uint32 sats;
+ uint32 vals;
+
+ map.GetDivisions (hues, sats, vals);
+
+ printer.Put_uint32 (hues);
+ printer.Put_uint32 (sats);
+ printer.Put_uint32 (vals);
+
+ for (uint32 val = 0; val < vals; val++)
+ for (uint32 hue = 0; hue < hues; hue++)
+ for (uint32 sat = 0; sat < sats; sat++)
+ {
+
+ dng_hue_sat_map::HSBModify modify;
+
+ map.GetDelta (hue, sat, val, modify);
+
+ printer.Put_real32 (modify.fHueShift);
+ printer.Put_real32 (modify.fSatScale);
+ printer.Put_real32 (modify.fValScale);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::CalculateFingerprint () const
+ {
+
+ DNG_ASSERT (!fWasStubbed, "CalculateFingerprint on stubbed profile");
+
+ dng_md5_printer_stream printer;
+
+ // MD5 hash is always calculated on little endian data.
+
+ printer.SetLittleEndian ();
+
+ // The data that we fingerprint closely matches that saved
+ // by the profile_tag_set class in dng_image_writer.cpp, with
+ // the exception of the fingerprint itself.
+
+ if (HasColorMatrix1 ())
+ {
+
+ uint32 colorChannels = ColorMatrix1 ().Rows ();
+
+ printer.Put_uint16 ((uint16) fCalibrationIlluminant1);
+
+ FingerprintMatrix (printer, fColorMatrix1);
+
+ if (fForwardMatrix1.Rows () == fColorMatrix1.Cols () &&
+ fForwardMatrix1.Cols () == fColorMatrix1.Rows ())
+ {
+
+ FingerprintMatrix (printer, fForwardMatrix1);
+
+ }
+
+ if (colorChannels > 3 && fReductionMatrix1.Rows () *
+ fReductionMatrix1.Cols () == colorChannels * 3)
+ {
+
+ FingerprintMatrix (printer, fReductionMatrix1);
+
+ }
+
+ if (HasColorMatrix2 ())
+ {
+
+ printer.Put_uint16 ((uint16) fCalibrationIlluminant2);
+
+ FingerprintMatrix (printer, fColorMatrix2);
+
+ if (fForwardMatrix2.Rows () == fColorMatrix2.Cols () &&
+ fForwardMatrix2.Cols () == fColorMatrix2.Rows ())
+ {
+
+ FingerprintMatrix (printer, fForwardMatrix2);
+
+ }
+
+ if (colorChannels > 3 && fReductionMatrix2.Rows () *
+ fReductionMatrix2.Cols () == colorChannels * 3)
+ {
+
+ FingerprintMatrix (printer, fReductionMatrix2);
+
+ }
+
+ }
+
+ printer.Put (fName.Get (),
+ fName.Length ());
+
+ printer.Put (fProfileCalibrationSignature.Get (),
+ fProfileCalibrationSignature.Length ());
+
+ printer.Put_uint32 (fEmbedPolicy);
+
+ printer.Put (fCopyright.Get (),
+ fCopyright.Length ());
+
+ bool haveHueSat1 = HueSatDeltas1 ().IsValid ();
+
+ bool haveHueSat2 = HueSatDeltas2 ().IsValid () &&
+ HasColorMatrix2 ();
+
+ if (haveHueSat1)
+ {
+
+ FingerprintHueSatMap (printer, fHueSatDeltas1);
+
+ }
+
+ if (haveHueSat2)
+ {
+
+ FingerprintHueSatMap (printer, fHueSatDeltas2);
+
+ }
+
+ if (haveHueSat1 || haveHueSat2)
+ {
+
+ if (fHueSatMapEncoding != 0)
+ {
+
+ printer.Put_uint32 (fHueSatMapEncoding);
+
+ }
+
+ }
+
+ if (fLookTable.IsValid ())
+ {
+
+ FingerprintHueSatMap (printer, fLookTable);
+
+ if (fLookTableEncoding != 0)
+ {
+
+ printer.Put_uint32 (fLookTableEncoding);
+
+ }
+
+ }
+
+ if (fBaselineExposureOffset.IsValid ())
+ {
+
+ if (fBaselineExposureOffset.As_real64 () != 0.0)
+ {
+
+ printer.Put_real64 (fBaselineExposureOffset.As_real64 ());
+
+ }
+
+ }
+
+ if (fDefaultBlackRender != 0)
+ {
+
+ printer.Put_int32 (fDefaultBlackRender);
+
+ }
+
+ if (fToneCurve.IsValid ())
+ {
+
+ for (uint32 i = 0; i < fToneCurve.fCoord.size (); i++)
+ {
+
+ printer.Put_real32 ((real32) fToneCurve.fCoord [i].h);
+ printer.Put_real32 ((real32) fToneCurve.fCoord [i].v);
+
+ }
+
+ }
+
+ }
+
+ fFingerprint = printer.Result ();
+
+ }
+
+/******************************************************************************/
+
+bool dng_camera_profile::ValidForwardMatrix (const dng_matrix &m)
+ {
+
+ const real64 kThreshold = 0.01;
+
+ if (m.NotEmpty ())
+ {
+
+ dng_vector cameraOne;
+
+ cameraOne.SetIdentity (m.Cols ());
+
+ dng_vector xyz = m * cameraOne;
+
+ dng_vector pcs = PCStoXYZ ();
+
+ if (Abs_real64 (xyz [0] - pcs [0]) > kThreshold ||
+ Abs_real64 (xyz [1] - pcs [1]) > kThreshold ||
+ Abs_real64 (xyz [2] - pcs [2]) > kThreshold)
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+bool dng_camera_profile::IsValid (uint32 channels) const
+ {
+
+ // For Monochrome images, we ignore the camera profile.
+
+ if (channels == 1)
+ {
+
+ return true;
+
+ }
+
+ // ColorMatrix1 is required for all color images.
+
+ if (fColorMatrix1.Cols () != 3 ||
+ fColorMatrix1.Rows () != channels)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ColorMatrix1 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ // ColorMatrix2 is optional, but it must be valid if present.
+
+ if (fColorMatrix2.Cols () != 0 ||
+ fColorMatrix2.Rows () != 0)
+ {
+
+ if (fColorMatrix2.Cols () != 3 ||
+ fColorMatrix2.Rows () != channels)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ColorMatrix2 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // ForwardMatrix1 is optional, but it must be valid if present.
+
+ if (fForwardMatrix1.Cols () != 0 ||
+ fForwardMatrix1.Rows () != 0)
+ {
+
+ if (fForwardMatrix1.Rows () != 3 ||
+ fForwardMatrix1.Cols () != channels)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ForwardMatrix1 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure ForwardMatrix1 does a valid mapping.
+
+ if (!ValidForwardMatrix (fForwardMatrix1))
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ForwardMatrix1 does not map equal camera values to XYZ D50");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // ForwardMatrix2 is optional, but it must be valid if present.
+
+ if (fForwardMatrix2.Cols () != 0 ||
+ fForwardMatrix2.Rows () != 0)
+ {
+
+ if (fForwardMatrix2.Rows () != 3 ||
+ fForwardMatrix2.Cols () != channels)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ForwardMatrix2 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure ForwardMatrix2 does a valid mapping.
+
+ if (!ValidForwardMatrix (fForwardMatrix2))
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ForwardMatrix2 does not map equal camera values to XYZ D50");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // ReductionMatrix1 is optional, but it must be valid if present.
+
+ if (fReductionMatrix1.Cols () != 0 ||
+ fReductionMatrix1.Rows () != 0)
+ {
+
+ if (fReductionMatrix1.Cols () != channels ||
+ fReductionMatrix1.Rows () != 3)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ReductionMatrix1 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // ReductionMatrix2 is optional, but it must be valid if present.
+
+ if (fReductionMatrix2.Cols () != 0 ||
+ fReductionMatrix2.Rows () != 0)
+ {
+
+ if (fReductionMatrix2.Cols () != channels ||
+ fReductionMatrix2.Rows () != 3)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ReductionMatrix2 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Make sure ColorMatrix1 is invertable.
+
+ try
+ {
+
+ if (fReductionMatrix1.NotEmpty ())
+ {
+
+ (void) Invert (fColorMatrix1,
+ fReductionMatrix1);
+
+ }
+
+ else
+ {
+
+ (void) Invert (fColorMatrix1);
+
+ }
+
+ }
+
+ catch (...)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ColorMatrix1 is not invertable");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure ColorMatrix2 is invertable.
+
+ if (fColorMatrix2.NotEmpty ())
+ {
+
+ try
+ {
+
+ if (fReductionMatrix2.NotEmpty ())
+ {
+
+ (void) Invert (fColorMatrix2,
+ fReductionMatrix2);
+
+ }
+
+ else
+ {
+
+ (void) Invert (fColorMatrix2);
+
+ }
+
+ }
+
+ catch (...)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ColorMatrix2 is not invertable");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_camera_profile::EqualData (const dng_camera_profile &profile) const
+ {
+
+ return fCalibrationIlluminant1 == profile.fCalibrationIlluminant1 &&
+ fCalibrationIlluminant2 == profile.fCalibrationIlluminant2 &&
+ fColorMatrix1 == profile.fColorMatrix1 &&
+ fColorMatrix2 == profile.fColorMatrix2 &&
+ fForwardMatrix1 == profile.fForwardMatrix1 &&
+ fForwardMatrix2 == profile.fForwardMatrix2 &&
+ fReductionMatrix1 == profile.fReductionMatrix1 &&
+ fReductionMatrix2 == profile.fReductionMatrix2 &&
+ fHueSatDeltas1 == profile.fHueSatDeltas1 &&
+ fHueSatDeltas2 == profile.fHueSatDeltas2 &&
+ fHueSatMapEncoding == profile.fHueSatMapEncoding &&
+ fLookTable == profile.fLookTable &&
+ fLookTableEncoding == profile.fLookTableEncoding &&
+ fDefaultBlackRender == profile.fDefaultBlackRender &&
+ fToneCurve == profile.fToneCurve &&
+ fBaselineExposureOffset.As_real64 () == profile.fBaselineExposureOffset.As_real64 () &&
+ fProfileCalibrationSignature == profile.fProfileCalibrationSignature;
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::ReadHueSatMap (dng_stream &stream,
+ dng_hue_sat_map &hueSatMap,
+ uint32 hues,
+ uint32 sats,
+ uint32 vals,
+ bool skipSat0)
+ {
+
+ hueSatMap.SetDivisions (hues, sats, vals);
+
+ for (uint32 val = 0; val < vals; val++)
+ {
+
+ for (uint32 hue = 0; hue < hues; hue++)
+ {
+
+ for (uint32 sat = skipSat0 ? 1 : 0; sat < sats; sat++)
+ {
+
+ dng_hue_sat_map::HSBModify modify;
+
+ modify.fHueShift = stream.Get_real32 ();
+ modify.fSatScale = stream.Get_real32 ();
+ modify.fValScale = stream.Get_real32 ();
+
+ hueSatMap.SetDelta (hue, sat, val, modify);
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::Parse (dng_stream &stream,
+ dng_camera_profile_info &profileInfo)
+ {
+
+ SetUniqueCameraModelRestriction (profileInfo.fUniqueCameraModel.Get ());
+
+ if (profileInfo.fProfileName.NotEmpty ())
+ {
+
+ SetName (profileInfo.fProfileName.Get ());
+
+ }
+
+ SetCopyright (profileInfo.fProfileCopyright.Get ());
+
+ SetEmbedPolicy (profileInfo.fEmbedPolicy);
+
+ SetCalibrationIlluminant1 (profileInfo.fCalibrationIlluminant1);
+
+ SetColorMatrix1 (profileInfo.fColorMatrix1);
+
+ if (profileInfo.fForwardMatrix1.NotEmpty ())
+ {
+
+ SetForwardMatrix1 (profileInfo.fForwardMatrix1);
+
+ }
+
+ if (profileInfo.fReductionMatrix1.NotEmpty ())
+ {
+
+ SetReductionMatrix1 (profileInfo.fReductionMatrix1);
+
+ }
+
+ if (profileInfo.fColorMatrix2.NotEmpty ())
+ {
+
+ SetCalibrationIlluminant2 (profileInfo.fCalibrationIlluminant2);
+
+ SetColorMatrix2 (profileInfo.fColorMatrix2);
+
+ if (profileInfo.fForwardMatrix2.NotEmpty ())
+ {
+
+ SetForwardMatrix2 (profileInfo.fForwardMatrix2);
+
+ }
+
+ if (profileInfo.fReductionMatrix2.NotEmpty ())
+ {
+
+ SetReductionMatrix2 (profileInfo.fReductionMatrix2);
+
+ }
+
+ }
+
+ SetProfileCalibrationSignature (profileInfo.fProfileCalibrationSignature.Get ());
+
+ if (profileInfo.fHueSatDeltas1Offset != 0 &&
+ profileInfo.fHueSatDeltas1Count != 0)
+ {
+
+ TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
+
+ stream.SetReadPosition (profileInfo.fHueSatDeltas1Offset);
+
+ bool skipSat0 = (profileInfo.fHueSatDeltas1Count == profileInfo.fProfileHues *
+ (profileInfo.fProfileSats - 1) *
+ profileInfo.fProfileVals * 3);
+
+ ReadHueSatMap (stream,
+ fHueSatDeltas1,
+ profileInfo.fProfileHues,
+ profileInfo.fProfileSats,
+ profileInfo.fProfileVals,
+ skipSat0);
+
+ }
+
+ if (profileInfo.fHueSatDeltas2Offset != 0 &&
+ profileInfo.fHueSatDeltas2Count != 0)
+ {
+
+ TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
+
+ stream.SetReadPosition (profileInfo.fHueSatDeltas2Offset);
+
+ bool skipSat0 = (profileInfo.fHueSatDeltas2Count == profileInfo.fProfileHues *
+ (profileInfo.fProfileSats - 1) *
+ profileInfo.fProfileVals * 3);
+
+ ReadHueSatMap (stream,
+ fHueSatDeltas2,
+ profileInfo.fProfileHues,
+ profileInfo.fProfileSats,
+ profileInfo.fProfileVals,
+ skipSat0);
+
+ }
+
+ if (profileInfo.fLookTableOffset != 0 &&
+ profileInfo.fLookTableCount != 0)
+ {
+
+ TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
+
+ stream.SetReadPosition (profileInfo.fLookTableOffset);
+
+ bool skipSat0 = (profileInfo.fLookTableCount == profileInfo.fLookTableHues *
+ (profileInfo.fLookTableSats - 1) *
+ profileInfo.fLookTableVals * 3);
+
+ ReadHueSatMap (stream,
+ fLookTable,
+ profileInfo.fLookTableHues,
+ profileInfo.fLookTableSats,
+ profileInfo.fLookTableVals,
+ skipSat0);
+
+ }
+
+ if ((profileInfo.fToneCurveCount & 1) == 0)
+ {
+
+ TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
+
+ stream.SetReadPosition (profileInfo.fToneCurveOffset);
+
+ uint32 points = profileInfo.fToneCurveCount / 2;
+
+ fToneCurve.fCoord.resize (points);
+
+ for (size_t i = 0; i < points; i++)
+ {
+
+ dng_point_real64 point;
+
+ point.h = stream.Get_real32 ();
+ point.v = stream.Get_real32 ();
+
+ fToneCurve.fCoord [i] = point;
+
+ }
+
+ }
+
+ SetHueSatMapEncoding (profileInfo.fHueSatMapEncoding);
+
+ SetLookTableEncoding (profileInfo.fLookTableEncoding);
+
+ SetBaselineExposureOffset (profileInfo.fBaselineExposureOffset.As_real64 ());
+
+ SetDefaultBlackRender (profileInfo.fDefaultBlackRender);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_camera_profile::ParseExtended (dng_stream &stream)
+ {
+
+ try
+ {
+
+ dng_camera_profile_info profileInfo;
+
+ if (!profileInfo.ParseExtended (stream))
+ {
+ return false;
+ }
+
+ Parse (stream, profileInfo);
+
+ return true;
+
+ }
+
+ catch (...)
+ {
+
+ // Eat parsing errors.
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::SetFourColorBayer ()
+ {
+
+ uint32 j;
+
+ if (!IsValid (3))
+ {
+ ThrowProgramError ();
+ }
+
+ if (fColorMatrix1.NotEmpty ())
+ {
+
+ dng_matrix m (4, 3);
+
+ for (j = 0; j < 3; j++)
+ {
+ m [0] [j] = fColorMatrix1 [0] [j];
+ m [1] [j] = fColorMatrix1 [1] [j];
+ m [2] [j] = fColorMatrix1 [2] [j];
+ m [3] [j] = fColorMatrix1 [1] [j];
+ }
+
+ fColorMatrix1 = m;
+
+ }
+
+ if (fColorMatrix2.NotEmpty ())
+ {
+
+ dng_matrix m (4, 3);
+
+ for (j = 0; j < 3; j++)
+ {
+ m [0] [j] = fColorMatrix2 [0] [j];
+ m [1] [j] = fColorMatrix2 [1] [j];
+ m [2] [j] = fColorMatrix2 [2] [j];
+ m [3] [j] = fColorMatrix2 [1] [j];
+ }
+
+ fColorMatrix2 = m;
+
+ }
+
+ fReductionMatrix1.Clear ();
+ fReductionMatrix2.Clear ();
+
+ fForwardMatrix1.Clear ();
+ fForwardMatrix2.Clear ();
+
+ }
+
+/*****************************************************************************/
+
+dng_hue_sat_map * dng_camera_profile::HueSatMapForWhite (const dng_xy_coord &white) const
+ {
+
+ if (fHueSatDeltas1.IsValid ())
+ {
+
+ // If we only have the first table, just use it for any color temperature.
+
+ if (!fHueSatDeltas2.IsValid ())
+ {
+
+ return new dng_hue_sat_map (fHueSatDeltas1);
+
+ }
+
+ // Else we need to interpolate based on color temperature.
+
+ real64 temperature1 = CalibrationTemperature1 ();
+ real64 temperature2 = CalibrationTemperature2 ();
+
+ if (temperature1 <= 0.0 ||
+ temperature2 <= 0.0 ||
+ temperature1 == temperature2)
+ {
+
+ return new dng_hue_sat_map (fHueSatDeltas1);
+
+ }
+
+ bool reverseOrder = temperature1 > temperature2;
+
+ if (reverseOrder)
+ {
+ real64 temp = temperature1;
+ temperature1 = temperature2;
+ temperature2 = temp;
+ }
+
+ // Convert to temperature/offset space.
+
+ dng_temperature td (white);
+
+ // Find fraction to weight the first calibration.
+
+ real64 g;
+
+ if (td.Temperature () <= temperature1)
+ g = 1.0;
+
+ else if (td.Temperature () >= temperature2)
+ g = 0.0;
+
+ else
+ {
+
+ real64 invT = 1.0 / td.Temperature ();
+
+ g = (invT - (1.0 / temperature2)) /
+ ((1.0 / temperature1) - (1.0 / temperature2));
+
+ }
+
+ // Fix up if we swapped the order.
+
+ if (reverseOrder)
+ {
+ g = 1.0 - g;
+ }
+
+ // Do the interpolation.
+
+ return dng_hue_sat_map::Interpolate (HueSatDeltas1 (),
+ HueSatDeltas2 (),
+ g);
+
+ }
+
+ return NULL;
+
+ }
+
+/*****************************************************************************/
+
+void dng_camera_profile::Stub ()
+ {
+
+ (void) Fingerprint ();
+
+ dng_hue_sat_map nullTable;
+
+ fHueSatDeltas1 = nullTable;
+ fHueSatDeltas2 = nullTable;
+
+ fLookTable = nullTable;
+
+ fToneCurve.SetInvalid ();
+
+ fWasStubbed = true;
+
+ }
+
+/*****************************************************************************/
+
+void SplitCameraProfileName (const dng_string &name,
+ dng_string &baseName,
+ int32 &version)
+ {
+
+ baseName = name;
+
+ version = 0;
+
+ uint32 len = baseName.Length ();
+
+ if (len > 5 && baseName.EndsWith (" beta"))
+ {
+
+ baseName.Truncate (len - 5);
+
+ version += -10;
+
+ }
+
+ else if (len > 7)
+ {
+
+ char lastChar = name.Get () [len - 1];
+
+ if (lastChar >= '0' && lastChar <= '9')
+ {
+
+ dng_string temp = name;
+
+ temp.Truncate (len - 1);
+
+ if (temp.EndsWith (" beta "))
+ {
+
+ baseName.Truncate (len - 7);
+
+ version += ((int32) (lastChar - '0')) - 10;
+
+ }
+
+ }
+
+ }
+
+ len = baseName.Length ();
+
+ if (len > 3)
+ {
+
+ char lastChar = name.Get () [len - 1];
+
+ if (lastChar >= '0' && lastChar <= '9')
+ {
+
+ dng_string temp = name;
+
+ temp.Truncate (len - 1);
+
+ if (temp.EndsWith (" v"))
+ {
+
+ baseName.Truncate (len - 3);
+
+ version += ((int32) (lastChar - '0')) * 100;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void BuildHueSatMapEncodingTable (dng_memory_allocator &allocator,
+ uint32 encoding,
+ AutoPtr<dng_1d_table> &encodeTable,
+ AutoPtr<dng_1d_table> &decodeTable,
+ bool subSample)
+ {
+
+ encodeTable.Reset ();
+ decodeTable.Reset ();
+
+ switch (encoding)
+ {
+
+ case encoding_Linear:
+ {
+
+ break;
+
+ }
+
+ case encoding_sRGB:
+ {
+
+ encodeTable.Reset (new dng_1d_table);
+ decodeTable.Reset (new dng_1d_table);
+
+ const dng_1d_function & curve = dng_function_GammaEncode_sRGB::Get ();
+
+ encodeTable->Initialize (allocator,
+ curve,
+ subSample);
+
+ const dng_1d_inverse inverse (curve);
+
+ decodeTable->Initialize (allocator,
+ inverse,
+ subSample);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ DNG_REPORT ("Unsupported hue sat map / look table encoding.");
+
+ break;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_camera_profile.h b/gpr/source/lib/dng_sdk/dng_camera_profile.h
new file mode 100644
index 0000000..df14a8a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_camera_profile.h
@@ -0,0 +1,878 @@
+/******************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/******************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_camera_profile.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for DNG camera color profile information.
+ * Per the \ref spec_dng "DNG 1.1.0 specification", a DNG file can store up to
+ * two sets of color profile information for a camera in the DNG file from that
+ * camera. The second set is optional and when there are two sets, they represent
+ * profiles made under different illumination.
+ *
+ * Profiling information is optionally separated into two parts. One part represents
+ * a profile for a reference camera. (ColorMatrix1 and ColorMatrix2 here.) The
+ * second is a per-camera calibration that takes into account unit-to-unit variation.
+ * This is designed to allow replacing the reference color matrix with one of one's
+ * own construction while maintaining any unit-specific calibration the camera
+ * manufacturer may have provided.
+ *
+ * See Appendix 6 of the \ref spec_dng "DNG 1.1.0 specification" for more information.
+ */
+
+#ifndef __dng_camera_profile__
+#define __dng_camera_profile__
+
+/******************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_assertions.h"
+#include "dng_classes.h"
+#include "dng_fingerprint.h"
+#include "dng_hue_sat_map.h"
+#include "dng_matrix.h"
+#include "dng_string.h"
+#include "dng_tag_values.h"
+#include "dng_tone_curve.h"
+
+/******************************************************************************/
+
+extern const char * kProfileName_Embedded;
+
+extern const char * kAdobeCalibrationSignature;
+
+/******************************************************************************/
+
+/// \brief An ID for a camera profile consisting of a name and optional fingerprint.
+
+class dng_camera_profile_id
+ {
+
+ private:
+
+ dng_string fName;
+
+ dng_fingerprint fFingerprint;
+
+ public:
+
+ /// Construct an invalid camera profile ID (empty name and fingerprint).
+
+ dng_camera_profile_id ()
+
+ : fName ()
+ , fFingerprint ()
+
+ {
+ }
+
+ /// Construct a camera profile ID with the specified name and no fingerprint.
+ /// \param name The name of the camera profile ID.
+
+ dng_camera_profile_id (const char *name)
+
+ : fName ()
+ , fFingerprint ()
+
+ {
+ fName.Set (name);
+ }
+
+ /// Construct a camera profile ID with the specified name and no fingerprint.
+ /// \param name The name of the camera profile ID.
+
+ dng_camera_profile_id (const dng_string &name)
+
+ : fName (name)
+ , fFingerprint ()
+
+ {
+ }
+
+ /// Construct a camera profile ID with the specified name and fingerprint.
+ /// \param name The name of the camera profile ID.
+ /// \param fingerprint The fingerprint of the camera profile ID.
+
+ dng_camera_profile_id (const char *name,
+ const dng_fingerprint &fingerprint)
+
+ : fName ()
+ , fFingerprint (fingerprint)
+
+ {
+ fName.Set (name);
+ DNG_ASSERT (!fFingerprint.IsValid () || fName.NotEmpty (),
+ "Cannot have profile fingerprint without name");
+ }
+
+ /// Construct a camera profile ID with the specified name and fingerprint.
+ /// \param name The name of the camera profile ID.
+ /// \param fingerprint The fingerprint of the camera profile ID.
+
+ dng_camera_profile_id (const dng_string &name,
+ const dng_fingerprint &fingerprint)
+
+ : fName (name)
+ , fFingerprint (fingerprint)
+
+ {
+ DNG_ASSERT (!fFingerprint.IsValid () || fName.NotEmpty (),
+ "Cannot have profile fingerprint without name");
+ }
+
+ /// Getter for the name of the camera profile ID.
+ /// \retval The name of the camera profile ID.
+
+ const dng_string & Name () const
+ {
+ return fName;
+ }
+
+ /// Getter for the fingerprint of the camera profile ID.
+ /// \retval The fingerprint of the camera profile ID.
+
+ const dng_fingerprint & Fingerprint () const
+ {
+ return fFingerprint;
+ }
+
+ /// Test for equality of two camera profile IDs.
+ /// \param The id of the camera profile ID to compare.
+
+ bool operator== (const dng_camera_profile_id &id) const
+ {
+ return fName == id.fName &&
+ fFingerprint == id.fFingerprint;
+ }
+
+ /// Test for inequality of two camera profile IDs.
+ /// \param The id of the camera profile ID to compare.
+
+ bool operator!= (const dng_camera_profile_id &id) const
+ {
+ return !(*this == id);
+ }
+
+ /// Returns true iff the camera profile ID is valid.
+
+ bool IsValid () const
+ {
+ return fName.NotEmpty (); // Fingerprint is optional.
+ }
+
+ /// Resets the name and fingerprint, thereby making this camera profile ID
+ /// invalid.
+
+ void Clear ()
+ {
+ *this = dng_camera_profile_id ();
+ }
+
+ };
+
+/******************************************************************************/
+
+/// \brief Container for DNG camera color profile and calibration data.
+
+class dng_camera_profile
+ {
+
+ protected:
+
+ // Name of this camera profile.
+
+ dng_string fName;
+
+ // Light sources for up to two calibrations. These use the EXIF
+ // encodings for illuminant and are used to distinguish which
+ // matrix to use.
+
+ uint32 fCalibrationIlluminant1;
+ uint32 fCalibrationIlluminant2;
+
+ // Color matrices for up to two calibrations.
+
+ // These matrices map XYZ values to non-white balanced camera values.
+ // Adobe needs to go that direction in order to determine the clipping
+ // points for highlight recovery logic based on the white point. If
+ // cameras were all 3-color, the matrix could be stored as a forward matrix,
+ // but we need the backwards matrix to deal with 4-color cameras.
+
+ dng_matrix fColorMatrix1;
+ dng_matrix fColorMatrix2;
+
+ // These matrices map white balanced camera values to XYZ chromatically
+ // adapted to D50 (the ICC profile PCS white point). If the matrices
+ // exist, then this implies that white balancing should be done by scaling
+ // camera values with a diagonal matrix.
+
+ dng_matrix fForwardMatrix1;
+ dng_matrix fForwardMatrix2;
+
+ // Dimensionality reduction hints for more than three color cameras.
+ // This is an optional matrix that maps the camera's color components
+ // to 3 components. These are only used if the forward matrices don't
+ // exist, and are used invert the color matrices.
+
+ dng_matrix fReductionMatrix1;
+ dng_matrix fReductionMatrix2;
+
+ // MD5 hash for all data bits of the profile.
+
+ mutable dng_fingerprint fFingerprint;
+
+ // Copyright notice from creator of profile.
+
+ dng_string fCopyright;
+
+ // Rules for how this profile can be embedded and/or copied.
+
+ uint32 fEmbedPolicy;
+
+ // 2-D (or 3-D) hue/sat tables to modify colors.
+
+ dng_hue_sat_map fHueSatDeltas1;
+ dng_hue_sat_map fHueSatDeltas2;
+
+ // Value (V of HSV) encoding for hue/sat tables.
+
+ uint32 fHueSatMapEncoding;
+
+ // 3-D hue/sat table to apply a "look".
+
+ dng_hue_sat_map fLookTable;
+
+ // Value (V of HSV) encoding for look table.
+
+ uint32 fLookTableEncoding;
+
+ // Baseline exposure offset. When using this profile, this offset value is
+ // added to the BaselineExposure value for the negative to determine the
+ // overall baseline exposure to apply.
+
+ dng_srational fBaselineExposureOffset;
+
+ // Default black rendering.
+
+ uint32 fDefaultBlackRender;
+
+ // The "as shot" tone curve for this profile. Check IsValid method
+ // to tell if one exists in profile.
+
+ dng_tone_curve fToneCurve;
+
+ // If this string matches the fCameraCalibrationSignature of the
+ // negative, then use the calibration matrix values from the negative.
+
+ dng_string fProfileCalibrationSignature;
+
+ // If non-empty, only allow use of this profile with camera having
+ // same unique model name.
+
+ dng_string fUniqueCameraModelRestriction;
+
+ // Was this profile read from inside a DNG file? (If so, we wnat
+ // to be sure to include it again when writing out an updated
+ // DNG file)
+
+ bool fWasReadFromDNG;
+
+ // Was this profile read from disk (i.e., an external profile)? (If so, we
+ // may need to refresh when changes are made externally to the profile
+ // directory.)
+
+ bool fWasReadFromDisk;
+
+ // Was this profile a built-in "Matrix" profile? (If so, we may need to
+ // refresh -- i.e., remove it from the list of available profiles -- when
+ // changes are made externally to the profile directory.)
+
+ bool fWasBuiltinMatrix;
+
+ // Was this profile stubbed to save memory (and no longer valid
+ // for building color conversion tables)?
+
+ bool fWasStubbed;
+
+ public:
+
+ dng_camera_profile ();
+
+ virtual ~dng_camera_profile ();
+
+ // API for profile name:
+
+ /// Setter for camera profile name.
+ /// \param name Name to use for this camera profile.
+
+ void SetName (const char *name)
+ {
+ fName.Set (name);
+ ClearFingerprint ();
+ }
+
+ /// Getter for camera profile name.
+ /// \retval Name of profile.
+
+ const dng_string & Name () const
+ {
+ return fName;
+ }
+
+ /// Test if this name is embedded.
+ /// \retval true if the name matches the name of the embedded camera profile.
+
+ bool NameIsEmbedded () const
+ {
+ return fName.Matches (kProfileName_Embedded, true);
+ }
+
+ // API for calibration illuminants:
+
+ /// Setter for first of up to two light sources used for calibration.
+ /// Uses the EXIF encodings for illuminant and is used to distinguish which
+ /// matrix to use.
+ /// Corresponds to the DNG CalibrationIlluminant1 tag.
+
+ void SetCalibrationIlluminant1 (uint32 light)
+ {
+ fCalibrationIlluminant1 = light;
+ ClearFingerprint ();
+ }
+
+ /// Setter for second of up to two light sources used for calibration.
+ /// Uses the EXIF encodings for illuminant and is used to distinguish which
+ /// matrix to use.
+ /// Corresponds to the DNG CalibrationIlluminant2 tag.
+
+ void SetCalibrationIlluminant2 (uint32 light)
+ {
+ fCalibrationIlluminant2 = light;
+ ClearFingerprint ();
+ }
+
+ /// Getter for first of up to two light sources used for calibration.
+ /// Uses the EXIF encodings for illuminant and is used to distinguish which
+ /// matrix to use.
+ /// Corresponds to the DNG CalibrationIlluminant1 tag.
+
+ uint32 CalibrationIlluminant1 () const
+ {
+ return fCalibrationIlluminant1;
+ }
+
+ /// Getter for second of up to two light sources used for calibration.
+ /// Uses the EXIF encodings for illuminant and is used to distinguish which
+ /// matrix to use.
+ /// Corresponds to the DNG CalibrationIlluminant2 tag.
+
+ uint32 CalibrationIlluminant2 () const
+ {
+ return fCalibrationIlluminant2;
+ }
+
+ /// Getter for first of up to two light sources used for calibration, returning
+ /// result as color temperature.
+
+ real64 CalibrationTemperature1 () const
+ {
+ return IlluminantToTemperature (CalibrationIlluminant1 ());
+ }
+
+ /// Getter for second of up to two light sources used for calibration, returning
+ /// result as color temperature.
+
+ real64 CalibrationTemperature2 () const
+ {
+ return IlluminantToTemperature (CalibrationIlluminant2 ());
+ }
+
+ // API for color matrices:
+
+ /// Utility function to normalize the scale of the color matrix.
+
+ static void NormalizeColorMatrix (dng_matrix &m);
+
+ /// Setter for first of up to two color matrices used for reference camera calibrations.
+ /// These matrices map XYZ values to camera values. The DNG SDK needs to map colors
+ /// that direction in order to determine the clipping points for
+ /// highlight recovery logic based on the white point. If cameras
+ /// were all three-color, the matrix could be stored as a forward matrix.
+ /// The inverse matrix is requried to support four-color cameras.
+
+ void SetColorMatrix1 (const dng_matrix &m);
+
+ /// Setter for second of up to two color matrices used for reference camera calibrations.
+ /// These matrices map XYZ values to camera values. The DNG SDK needs to map colors
+ /// that direction in order to determine the clipping points for
+ /// highlight recovery logic based on the white point. If cameras
+ /// were all three-color, the matrix could be stored as a forward matrix.
+ /// The inverse matrix is requried to support four-color cameras.
+
+ void SetColorMatrix2 (const dng_matrix &m);
+
+ /// Predicate to test if first camera matrix is set
+
+ bool HasColorMatrix1 () const;
+
+ /// Predicate to test if second camera matrix is set
+
+ bool HasColorMatrix2 () const;
+
+ /// Getter for first of up to two color matrices used for calibrations.
+
+ const dng_matrix & ColorMatrix1 () const
+ {
+ return fColorMatrix1;
+ }
+
+ /// Getter for second of up to two color matrices used for calibrations.
+
+ const dng_matrix & ColorMatrix2 () const
+ {
+ return fColorMatrix2;
+ }
+
+ // API for forward matrices:
+
+ /// Utility function to normalize the scale of the forward matrix.
+
+ static void NormalizeForwardMatrix (dng_matrix &m);
+
+ /// Setter for first of up to two forward matrices used for calibrations.
+
+ void SetForwardMatrix1 (const dng_matrix &m);
+
+ /// Setter for second of up to two forward matrices used for calibrations.
+
+ void SetForwardMatrix2 (const dng_matrix &m);
+
+ /// Getter for first of up to two forward matrices used for calibrations.
+
+ const dng_matrix & ForwardMatrix1 () const
+ {
+ return fForwardMatrix1;
+ }
+
+ /// Getter for second of up to two forward matrices used for calibrations.
+
+ const dng_matrix & ForwardMatrix2 () const
+ {
+ return fForwardMatrix2;
+ }
+
+ // API for reduction matrices:
+
+ /// Setter for first of up to two dimensionality reduction hints for four-color cameras.
+ /// This is an optional matrix that maps four components to three.
+ /// See Appendix 6 of the \ref spec_dng "DNG 1.1.0 specification."
+
+ void SetReductionMatrix1 (const dng_matrix &m);
+
+ /// Setter for second of up to two dimensionality reduction hints for four-color cameras.
+ /// This is an optional matrix that maps four components to three.
+ /// See Appendix 6 of the \ref spec_dng "DNG 1.1.0 specification."
+
+ void SetReductionMatrix2 (const dng_matrix &m);
+
+ /// Getter for first of up to two dimensionality reduction hints for four color cameras.
+
+ const dng_matrix & ReductionMatrix1 () const
+ {
+ return fReductionMatrix1;
+ }
+
+ /// Getter for second of up to two dimensionality reduction hints for four color cameras.
+
+ const dng_matrix & ReductionMatrix2 () const
+ {
+ return fReductionMatrix2;
+ }
+
+ /// Getter function from profile fingerprint.
+
+ const dng_fingerprint &Fingerprint () const
+ {
+
+ if (!fFingerprint.IsValid ())
+ CalculateFingerprint ();
+
+ return fFingerprint;
+
+ }
+
+ /// Getter for camera profile id.
+ /// \retval ID of profile.
+
+ dng_camera_profile_id ProfileID () const
+ {
+ return dng_camera_profile_id (Name (), Fingerprint ());
+ }
+
+ /// Setter for camera profile copyright.
+ /// \param copyright Copyright string to use for this camera profile.
+
+ void SetCopyright (const char *copyright)
+ {
+ fCopyright.Set (copyright);
+ ClearFingerprint ();
+ }
+
+ /// Getter for camera profile copyright.
+ /// \retval Copyright string for profile.
+
+ const dng_string & Copyright () const
+ {
+ return fCopyright;
+ }
+
+ // Accessors for embed policy.
+
+ /// Setter for camera profile embed policy.
+ /// \param policy Policy to use for this camera profile.
+
+ void SetEmbedPolicy (uint32 policy)
+ {
+ fEmbedPolicy = policy;
+ ClearFingerprint ();
+ }
+
+ /// Getter for camera profile embed policy.
+ /// \param Policy for profile.
+
+ uint32 EmbedPolicy () const
+ {
+ return fEmbedPolicy;
+ }
+
+ /// Returns true iff the profile is legal to embed in a DNG, per the
+ /// profile's embed policy.
+
+ bool IsLegalToEmbed () const
+ {
+ return WasReadFromDNG () ||
+ EmbedPolicy () == pepAllowCopying ||
+ EmbedPolicy () == pepEmbedIfUsed ||
+ EmbedPolicy () == pepNoRestrictions;
+ }
+
+ // Accessors for hue sat maps.
+
+ /// Returns true iff the profile has a valid HueSatMap color table.
+
+ bool HasHueSatDeltas () const
+ {
+ return fHueSatDeltas1.IsValid ();
+ }
+
+ /// Getter for first HueSatMap color table (for calibration illuminant 1).
+
+ const dng_hue_sat_map & HueSatDeltas1 () const
+ {
+ return fHueSatDeltas1;
+ }
+
+ /// Setter for first HueSatMap color table (for calibration illuminant 1).
+
+ void SetHueSatDeltas1 (const dng_hue_sat_map &deltas1);
+
+ /// Getter for second HueSatMap color table (for calibration illuminant 2).
+
+ const dng_hue_sat_map & HueSatDeltas2 () const
+ {
+ return fHueSatDeltas2;
+ }
+
+ /// Setter for second HueSatMap color table (for calibration illuminant 2).
+
+ void SetHueSatDeltas2 (const dng_hue_sat_map &deltas2);
+
+ // Accessors for hue sat map encoding.
+
+ /// Returns the hue sat map encoding (see ProfileHueSatMapEncoding tag).
+
+ uint32 HueSatMapEncoding () const
+ {
+ return fHueSatMapEncoding;
+ }
+
+ /// Sets the hue sat map encoding (see ProfileHueSatMapEncoding tag) to the
+ /// specified encoding.
+
+ void SetHueSatMapEncoding (uint32 encoding)
+ {
+ fHueSatMapEncoding = encoding;
+ ClearFingerprint ();
+ }
+
+ // Accessors for look table.
+
+ /// Returns true if the profile has a LookTable.
+
+ bool HasLookTable () const
+ {
+ return fLookTable.IsValid ();
+ }
+
+ /// Getter for LookTable.
+
+ const dng_hue_sat_map & LookTable () const
+ {
+ return fLookTable;
+ }
+
+ /// Setter for LookTable.
+
+ void SetLookTable (const dng_hue_sat_map &table);
+
+ // Accessors for look table encoding.
+
+ /// Returns the LookTable encoding (see ProfileLookTableEncoding tag).
+
+ uint32 LookTableEncoding () const
+ {
+ return fLookTableEncoding;
+ }
+
+ /// Sets the LookTable encoding (see ProfileLookTableEncoding tag) to the
+ /// specified encoding.
+
+ void SetLookTableEncoding (uint32 encoding)
+ {
+ fLookTableEncoding = encoding;
+ ClearFingerprint ();
+ }
+
+ // Accessors for baseline exposure offset.
+
+ /// Sets the baseline exposure offset of the profile (see
+ /// BaselineExposureOffset tag) to the specified value.
+
+ void SetBaselineExposureOffset (real64 exposureOffset)
+ {
+ fBaselineExposureOffset.Set_real64 (exposureOffset, 100);
+ ClearFingerprint ();
+ }
+
+ /// Returns the baseline exposure offset of the profile (see
+ /// BaselineExposureOffset tag).
+
+ const dng_srational & BaselineExposureOffset () const
+ {
+ return fBaselineExposureOffset;
+ }
+
+ // Accessors for default black render.
+
+ /// Sets the default black render of the profile (see DefaultBlackRender tag)
+ /// to the specified option.
+
+ void SetDefaultBlackRender (uint32 defaultBlackRender)
+ {
+ fDefaultBlackRender = defaultBlackRender;
+ ClearFingerprint ();
+ }
+
+ /// Returns the default black render of the profile (see DefaultBlackRender
+ /// tag).
+
+ uint32 DefaultBlackRender () const
+ {
+ return fDefaultBlackRender;
+ }
+
+ // Accessors for tone curve.
+
+ /// Returns the tone curve of the profile.
+
+ const dng_tone_curve & ToneCurve () const
+ {
+ return fToneCurve;
+ }
+
+ /// Sets the tone curve of the profile to the specified curve.
+
+ void SetToneCurve (const dng_tone_curve &curve)
+ {
+ fToneCurve = curve;
+ ClearFingerprint ();
+ }
+
+ // Accessors for profile calibration signature.
+
+ /// Sets the profile calibration signature (see ProfileCalibrationSignature
+ /// tag) to the specified string.
+
+ void SetProfileCalibrationSignature (const char *signature)
+ {
+ fProfileCalibrationSignature.Set (signature);
+ }
+
+ /// Returns the profile calibration signature (see ProfileCalibrationSignature
+ /// tag) of the profile.
+
+ const dng_string & ProfileCalibrationSignature () const
+ {
+ return fProfileCalibrationSignature;
+ }
+
+ /// Setter for camera unique model name to restrict use of this profile.
+ /// \param camera Camera unique model name designating only camera this
+ /// profile can be used with. (Empty string for no restriction.)
+
+ void SetUniqueCameraModelRestriction (const char *camera)
+ {
+ fUniqueCameraModelRestriction.Set (camera);
+ // Not included in fingerprint, so don't need ClearFingerprint ().
+ }
+
+ /// Getter for camera unique model name to restrict use of this profile.
+ /// \retval Unique model name of only camera this profile can be used with
+ /// or empty if no restriction.
+
+ const dng_string & UniqueCameraModelRestriction () const
+ {
+ return fUniqueCameraModelRestriction;
+ }
+
+ // Accessors for was read from DNG flag.
+
+ /// Sets internal flag to indicate this profile was originally read from a
+ /// DNG file.
+
+ void SetWasReadFromDNG (bool state = true)
+ {
+ fWasReadFromDNG = state;
+ }
+
+ /// Was this profile read from a DNG?
+
+ bool WasReadFromDNG () const
+ {
+ return fWasReadFromDNG;
+ }
+
+ // Accessors for was read from disk flag.
+
+ /// Sets internal flag to indicate this profile was originally read from
+ /// disk.
+
+ void SetWasReadFromDisk (bool state = true)
+ {
+ fWasReadFromDisk = state;
+ }
+
+ /// Was this profile read from disk?
+
+ bool WasReadFromDisk () const
+ {
+ return fWasReadFromDisk;
+ }
+
+ // Accessors for was built-in matrix flag.
+
+ /// Sets internal flag to indicate this profile was originally a built-in
+ /// matrix profile.
+
+ void SetWasBuiltinMatrix (bool state = true)
+ {
+ fWasBuiltinMatrix = state;
+ }
+
+ /// Was this profile a built-in matrix profile?
+
+ bool WasBuiltinMatrix () const
+ {
+ return fWasBuiltinMatrix;
+ }
+
+ /// Determines if this a valid profile for this number of color channels?
+ /// \retval true if the profile is valid.
+
+ bool IsValid (uint32 channels) const;
+
+ /// Predicate to check if two camera profiles are colorwise equal, thus ignores
+ /// the profile name.
+ /// \param profile Camera profile to compare to.
+
+ bool EqualData (const dng_camera_profile &profile) const;
+
+ /// Parse profile from dng_camera_profile_info data.
+
+ void Parse (dng_stream &stream,
+ dng_camera_profile_info &profileInfo);
+
+ /// Parse from an extended profile stream, which is similar to stand alone
+ /// TIFF file.
+
+ bool ParseExtended (dng_stream &stream);
+
+ /// Convert from a three-color to a four-color Bayer profile.
+
+ virtual void SetFourColorBayer ();
+
+ /// Find the hue/sat table to use for a given white point, if any.
+ /// The calling routine owns the resulting table.
+
+ dng_hue_sat_map * HueSatMapForWhite (const dng_xy_coord &white) const;
+
+ /// Stub out the profile (free memory used by large tables).
+
+ void Stub ();
+
+ /// Was this profile stubbed?
+
+ bool WasStubbed () const
+ {
+ return fWasStubbed;
+ }
+
+ protected:
+
+ static real64 IlluminantToTemperature (uint32 light);
+
+ void ClearFingerprint ()
+ {
+ fFingerprint.Clear ();
+ }
+
+ void CalculateFingerprint () const;
+
+ static bool ValidForwardMatrix (const dng_matrix &m);
+
+ static void ReadHueSatMap (dng_stream &stream,
+ dng_hue_sat_map &hueSatMap,
+ uint32 hues,
+ uint32 sats,
+ uint32 vals,
+ bool skipSat0);
+
+ };
+
+/******************************************************************************/
+
+void SplitCameraProfileName (const dng_string &name,
+ dng_string &baseName,
+ int32 &version);
+
+/*****************************************************************************/
+
+void BuildHueSatMapEncodingTable (dng_memory_allocator &allocator,
+ uint32 encoding,
+ AutoPtr<dng_1d_table> &encodeTable,
+ AutoPtr<dng_1d_table> &decodeTable,
+ bool subSample);
+
+/******************************************************************************/
+
+#endif
+
+/******************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_classes.h b/gpr/source/lib/dng_sdk/dng_classes.h
new file mode 100644
index 0000000..be72c4a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_classes.h
@@ -0,0 +1,100 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_classes.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*** \file
+ * Forward class declarations to avoid having to include many .h files in most places.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_classes__
+#define __dng_classes__
+
+/*****************************************************************************/
+
+class dng_1d_function;
+class dng_1d_table;
+class dng_abort_sniffer;
+class dng_area_task;
+class dng_basic_tag_set;
+class dng_camera_profile;
+class dng_camera_profile_id;
+class dng_camera_profile_info;
+class dng_color_space;
+class dng_color_spec;
+class dng_date_time;
+class dng_date_time_info;
+class dng_exif;
+class dng_fingerprint;
+class dng_host;
+class dng_hue_sat_map;
+class dng_ifd;
+class dng_image;
+class dng_image_preview;
+class dng_image_writer;
+class dng_info;
+class dng_iptc;
+class dng_jpeg_image;
+class dng_jpeg_preview;
+class dng_linearization_info;
+class dng_matrix;
+class dng_matrix_3by3;
+class dng_matrix_4by3;
+class dng_md5_printer;
+class dng_memory_allocator;
+class dng_memory_block;
+class dng_memory_data;
+class dng_memory_stream;
+class dng_metadata;
+class dng_mosaic_info;
+class dng_mutex;
+class dng_noise_function;
+class dng_noise_profile;
+class dng_opcode;
+class dng_opcode_list;
+class dng_orientation;
+class dng_negative;
+class dng_pixel_buffer;
+class dng_point;
+class dng_point_real64;
+class dng_preview;
+class dng_preview_info;
+class dng_preview_list;
+class dng_raw_preview;
+class dng_read_image;
+class dng_rect;
+class dng_rect_real64;
+class dng_render;
+class dng_resolution;
+class dng_shared;
+class dng_spline_solver;
+class dng_srational;
+class dng_stream;
+class dng_string;
+class dng_string_list;
+class dng_tiff_directory;
+class dng_tile_buffer;
+class dng_time_zone;
+class dng_tone_curve;
+class dng_urational;
+class dng_vector;
+class dng_vector_3;
+class dng_xmp;
+class dng_xmp_sdk;
+class dng_xy_coord;
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_color_space.cpp b/gpr/source/lib/dng_sdk/dng_color_space.cpp
new file mode 100644
index 0000000..72d465f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_color_space.cpp
@@ -0,0 +1,1072 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_color_space.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+#include "dng_color_space.h"
+
+#include "dng_1d_table.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_matrix.h"
+#include "dng_spline.h"
+#include "dng_utils.h"
+#include "dng_xy_coord.h"
+
+/*****************************************************************************/
+
+real64 dng_function_GammaEncode_sRGB::Evaluate (real64 x) const
+ {
+
+ if (x <= 0.0031308)
+ return x * 12.92;
+
+ else
+ return 1.055 * pow (x, 1.0 / 2.4) - 0.055;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_GammaEncode_sRGB::EvaluateInverse (real64 y) const
+ {
+
+ if (y <= 0.0031308 * 12.92)
+ return y * (1.0 / 12.92);
+
+ else
+ return pow ((y + 0.055) * (1.0 / 1.055), 2.4);
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_function_GammaEncode_sRGB::Get ()
+ {
+
+ static dng_function_GammaEncode_sRGB static_function;
+
+ return static_function;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_GammaEncode_1_8::Evaluate (real64 x) const
+ {
+
+ const real64 gamma = 1.0 / 1.8;
+
+ const real64 slope0 = 32.0;
+
+ const real64 x1 = 8.2118790552e-4; // pow (slope0, 1.0 / (gamma - 1.0)) * 2.0
+
+ const real64 y1 = 0.019310851; // pow (x1, gamma)
+
+ const real64 slope1 = 13.064306598; // gamma * pow (x1, gamma - 1.0)
+
+ if (x <= x1)
+ return EvaluateSplineSegment (x,
+ 0.0,
+ 0.0,
+ slope0,
+ x1,
+ y1,
+ slope1);
+
+ else
+ return pow (x, gamma);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_GammaEncode_1_8::EvaluateInverse (real64 y) const
+ {
+
+ if (y > 0.0 && y < 0.019310851)
+ {
+
+ return dng_1d_function::EvaluateInverse (y);
+
+ }
+
+ return pow (y, 1.8);
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_function_GammaEncode_1_8::Get ()
+ {
+
+ static dng_function_GammaEncode_1_8 static_function;
+
+ return static_function;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_GammaEncode_2_2::Evaluate (real64 x) const
+ {
+
+ const real64 gamma = 1.0 / 2.2;
+
+ const real64 slope0 = 32.0;
+
+ const real64 x1 = 0.0034800731; // pow (slope0, 1.0 / (gamma - 1.0)) * 2.0
+
+ const real64 y1 = 0.0763027458; // pow (x1, gamma)
+
+ const real64 slope1 = 9.9661890075; // gamma * pow (x1, gamma - 1.0)
+
+ if (x <= x1)
+ return EvaluateSplineSegment (x,
+ 0.0,
+ 0.0,
+ slope0,
+ x1,
+ y1,
+ slope1);
+
+ else
+ return pow (x, gamma);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_GammaEncode_2_2::EvaluateInverse (real64 y) const
+ {
+
+ if (y > 0.0 && y < 0.0763027458)
+ {
+
+ return dng_1d_function::EvaluateInverse (y);
+
+ }
+
+ return pow (y, 2.2);
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_function_GammaEncode_2_2::Get ()
+ {
+
+ static dng_function_GammaEncode_2_2 static_function;
+
+ return static_function;
+
+ }
+
+/*****************************************************************************/
+
+dng_color_space::dng_color_space ()
+
+ : fMatrixToPCS ()
+ , fMatrixFromPCS ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_color_space::~dng_color_space ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_color_space::SetMonochrome ()
+ {
+
+ fMatrixToPCS = PCStoXYZ ().AsColumn ();
+
+ dng_matrix m (1, 3);
+
+ m [0] [0] = 0.0;
+ m [0] [1] = 1.0;
+ m [0] [2] = 0.0;
+
+ fMatrixFromPCS = m;
+
+ }
+
+/*****************************************************************************/
+
+void dng_color_space::SetMatrixToPCS (const dng_matrix_3by3 &M)
+ {
+
+ // The matrix values are often rounded, so adjust to
+ // get them to convert device white exactly to the PCS.
+
+ dng_vector_3 W1 = M * dng_vector_3 (1.0, 1.0, 1.0);
+ dng_vector_3 W2 = PCStoXYZ ();
+
+ real64 s0 = W2 [0] / W1 [0];
+ real64 s1 = W2 [1] / W1 [1];
+ real64 s2 = W2 [2] / W1 [2];
+
+ dng_matrix_3by3 S (s0, 0, 0,
+ 0, s1, 0,
+ 0, 0, s2);
+
+ fMatrixToPCS = S * M;
+
+ // Find reverse matrix.
+
+ fMatrixFromPCS = Invert (fMatrixToPCS);
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_color_space::GammaFunction () const
+ {
+
+ return dng_1d_identity::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_color_space::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+ {
+
+ size = 0;
+ data = NULL;
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_sRGB::dng_space_sRGB ()
+ {
+
+ SetMatrixToPCS (dng_matrix_3by3 (0.4361, 0.3851, 0.1431,
+ 0.2225, 0.7169, 0.0606,
+ 0.0139, 0.0971, 0.7141));
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_space_sRGB::GammaFunction () const
+ {
+
+ return dng_function_GammaEncode_sRGB::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_space_sRGB::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+
+ {
+
+ static const uint8 ksRGBProfileData [] =
+ {
+ 0x00, 0x00, 0x0C, 0x48, 0x4C, 0x69, 0x6E, 0x6F, 0x02, 0x10, 0x00, 0x00,
+ 0x6D, 0x6E, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5A, 0x20,
+ 0x07, 0xCE, 0x00, 0x02, 0x00, 0x09, 0x00, 0x06, 0x00, 0x31, 0x00, 0x00,
+ 0x61, 0x63, 0x73, 0x70, 0x4D, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0x45, 0x43, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2D, 0x48, 0x50, 0x20, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x33,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x00, 0x6C,
+ 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x6B, 0x70, 0x74, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14,
+ 0x72, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x14,
+ 0x67, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x2C, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x14,
+ 0x64, 0x6D, 0x6E, 0x64, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0x00, 0x70,
+ 0x64, 0x6D, 0x64, 0x64, 0x00, 0x00, 0x02, 0xC4, 0x00, 0x00, 0x00, 0x88,
+ 0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x03, 0x4C, 0x00, 0x00, 0x00, 0x86,
+ 0x76, 0x69, 0x65, 0x77, 0x00, 0x00, 0x03, 0xD4, 0x00, 0x00, 0x00, 0x24,
+ 0x6C, 0x75, 0x6D, 0x69, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x00, 0x14,
+ 0x6D, 0x65, 0x61, 0x73, 0x00, 0x00, 0x04, 0x0C, 0x00, 0x00, 0x00, 0x24,
+ 0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x0C,
+ 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x3C, 0x00, 0x00, 0x08, 0x0C,
+ 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x3C, 0x00, 0x00, 0x08, 0x0C,
+ 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x04, 0x3C, 0x00, 0x00, 0x08, 0x0C,
+ 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x70, 0x79,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39,
+ 0x39, 0x38, 0x20, 0x48, 0x65, 0x77, 0x6C, 0x65, 0x74, 0x74, 0x2D, 0x50,
+ 0x61, 0x63, 0x6B, 0x61, 0x72, 0x64, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x61,
+ 0x6E, 0x79, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x12, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43,
+ 0x36, 0x31, 0x39, 0x36, 0x36, 0x2D, 0x32, 0x2E, 0x31, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x73, 0x52, 0x47,
+ 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2D, 0x32,
+ 0x2E, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xF3, 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xCC,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6F, 0xA2, 0x00, 0x00, 0x38, 0xF5,
+ 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x62, 0x99, 0x00, 0x00, 0xB7, 0x85, 0x00, 0x00, 0x18, 0xDA,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0xA0,
+ 0x00, 0x00, 0x0F, 0x84, 0x00, 0x00, 0xB6, 0xCF, 0x64, 0x65, 0x73, 0x63,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20,
+ 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x69,
+ 0x65, 0x63, 0x2E, 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x49, 0x45, 0x43, 0x20, 0x68, 0x74, 0x74,
+ 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x65, 0x63, 0x2E,
+ 0x63, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E,
+ 0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2D, 0x32, 0x2E,
+ 0x31, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x52, 0x47,
+ 0x42, 0x20, 0x63, 0x6F, 0x6C, 0x6F, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x20, 0x2D, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x49, 0x45, 0x43,
+ 0x20, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2D, 0x32, 0x2E, 0x31, 0x20, 0x44,
+ 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x63,
+ 0x6F, 0x6C, 0x6F, 0x75, 0x72, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20,
+ 0x2D, 0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x2C, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63,
+ 0x65, 0x20, 0x56, 0x69, 0x65, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x43, 0x6F,
+ 0x6E, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x49,
+ 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2D, 0x32, 0x2E, 0x31, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x52,
+ 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x56, 0x69, 0x65,
+ 0x77, 0x69, 0x6E, 0x67, 0x20, 0x43, 0x6F, 0x6E, 0x64, 0x69, 0x74, 0x69,
+ 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39,
+ 0x36, 0x36, 0x2D, 0x32, 0x2E, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x65, 0x77,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xA4, 0xFE, 0x00, 0x14, 0x5F, 0x2E,
+ 0x00, 0x10, 0xCF, 0x14, 0x00, 0x03, 0xED, 0xCC, 0x00, 0x04, 0x13, 0x0B,
+ 0x00, 0x03, 0x5C, 0x9E, 0x00, 0x00, 0x00, 0x01, 0x58, 0x59, 0x5A, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x09, 0x56, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x57, 0x1F, 0xE7, 0x6D, 0x65, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x8F,
+ 0x00, 0x00, 0x00, 0x02, 0x73, 0x69, 0x67, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x43, 0x52, 0x54, 0x20, 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F,
+ 0x00, 0x14, 0x00, 0x19, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2D,
+ 0x00, 0x32, 0x00, 0x37, 0x00, 0x3B, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4A,
+ 0x00, 0x4F, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5E, 0x00, 0x63, 0x00, 0x68,
+ 0x00, 0x6D, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7C, 0x00, 0x81, 0x00, 0x86,
+ 0x00, 0x8B, 0x00, 0x90, 0x00, 0x95, 0x00, 0x9A, 0x00, 0x9F, 0x00, 0xA4,
+ 0x00, 0xA9, 0x00, 0xAE, 0x00, 0xB2, 0x00, 0xB7, 0x00, 0xBC, 0x00, 0xC1,
+ 0x00, 0xC6, 0x00, 0xCB, 0x00, 0xD0, 0x00, 0xD5, 0x00, 0xDB, 0x00, 0xE0,
+ 0x00, 0xE5, 0x00, 0xEB, 0x00, 0xF0, 0x00, 0xF6, 0x00, 0xFB, 0x01, 0x01,
+ 0x01, 0x07, 0x01, 0x0D, 0x01, 0x13, 0x01, 0x19, 0x01, 0x1F, 0x01, 0x25,
+ 0x01, 0x2B, 0x01, 0x32, 0x01, 0x38, 0x01, 0x3E, 0x01, 0x45, 0x01, 0x4C,
+ 0x01, 0x52, 0x01, 0x59, 0x01, 0x60, 0x01, 0x67, 0x01, 0x6E, 0x01, 0x75,
+ 0x01, 0x7C, 0x01, 0x83, 0x01, 0x8B, 0x01, 0x92, 0x01, 0x9A, 0x01, 0xA1,
+ 0x01, 0xA9, 0x01, 0xB1, 0x01, 0xB9, 0x01, 0xC1, 0x01, 0xC9, 0x01, 0xD1,
+ 0x01, 0xD9, 0x01, 0xE1, 0x01, 0xE9, 0x01, 0xF2, 0x01, 0xFA, 0x02, 0x03,
+ 0x02, 0x0C, 0x02, 0x14, 0x02, 0x1D, 0x02, 0x26, 0x02, 0x2F, 0x02, 0x38,
+ 0x02, 0x41, 0x02, 0x4B, 0x02, 0x54, 0x02, 0x5D, 0x02, 0x67, 0x02, 0x71,
+ 0x02, 0x7A, 0x02, 0x84, 0x02, 0x8E, 0x02, 0x98, 0x02, 0xA2, 0x02, 0xAC,
+ 0x02, 0xB6, 0x02, 0xC1, 0x02, 0xCB, 0x02, 0xD5, 0x02, 0xE0, 0x02, 0xEB,
+ 0x02, 0xF5, 0x03, 0x00, 0x03, 0x0B, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2D,
+ 0x03, 0x38, 0x03, 0x43, 0x03, 0x4F, 0x03, 0x5A, 0x03, 0x66, 0x03, 0x72,
+ 0x03, 0x7E, 0x03, 0x8A, 0x03, 0x96, 0x03, 0xA2, 0x03, 0xAE, 0x03, 0xBA,
+ 0x03, 0xC7, 0x03, 0xD3, 0x03, 0xE0, 0x03, 0xEC, 0x03, 0xF9, 0x04, 0x06,
+ 0x04, 0x13, 0x04, 0x20, 0x04, 0x2D, 0x04, 0x3B, 0x04, 0x48, 0x04, 0x55,
+ 0x04, 0x63, 0x04, 0x71, 0x04, 0x7E, 0x04, 0x8C, 0x04, 0x9A, 0x04, 0xA8,
+ 0x04, 0xB6, 0x04, 0xC4, 0x04, 0xD3, 0x04, 0xE1, 0x04, 0xF0, 0x04, 0xFE,
+ 0x05, 0x0D, 0x05, 0x1C, 0x05, 0x2B, 0x05, 0x3A, 0x05, 0x49, 0x05, 0x58,
+ 0x05, 0x67, 0x05, 0x77, 0x05, 0x86, 0x05, 0x96, 0x05, 0xA6, 0x05, 0xB5,
+ 0x05, 0xC5, 0x05, 0xD5, 0x05, 0xE5, 0x05, 0xF6, 0x06, 0x06, 0x06, 0x16,
+ 0x06, 0x27, 0x06, 0x37, 0x06, 0x48, 0x06, 0x59, 0x06, 0x6A, 0x06, 0x7B,
+ 0x06, 0x8C, 0x06, 0x9D, 0x06, 0xAF, 0x06, 0xC0, 0x06, 0xD1, 0x06, 0xE3,
+ 0x06, 0xF5, 0x07, 0x07, 0x07, 0x19, 0x07, 0x2B, 0x07, 0x3D, 0x07, 0x4F,
+ 0x07, 0x61, 0x07, 0x74, 0x07, 0x86, 0x07, 0x99, 0x07, 0xAC, 0x07, 0xBF,
+ 0x07, 0xD2, 0x07, 0xE5, 0x07, 0xF8, 0x08, 0x0B, 0x08, 0x1F, 0x08, 0x32,
+ 0x08, 0x46, 0x08, 0x5A, 0x08, 0x6E, 0x08, 0x82, 0x08, 0x96, 0x08, 0xAA,
+ 0x08, 0xBE, 0x08, 0xD2, 0x08, 0xE7, 0x08, 0xFB, 0x09, 0x10, 0x09, 0x25,
+ 0x09, 0x3A, 0x09, 0x4F, 0x09, 0x64, 0x09, 0x79, 0x09, 0x8F, 0x09, 0xA4,
+ 0x09, 0xBA, 0x09, 0xCF, 0x09, 0xE5, 0x09, 0xFB, 0x0A, 0x11, 0x0A, 0x27,
+ 0x0A, 0x3D, 0x0A, 0x54, 0x0A, 0x6A, 0x0A, 0x81, 0x0A, 0x98, 0x0A, 0xAE,
+ 0x0A, 0xC5, 0x0A, 0xDC, 0x0A, 0xF3, 0x0B, 0x0B, 0x0B, 0x22, 0x0B, 0x39,
+ 0x0B, 0x51, 0x0B, 0x69, 0x0B, 0x80, 0x0B, 0x98, 0x0B, 0xB0, 0x0B, 0xC8,
+ 0x0B, 0xE1, 0x0B, 0xF9, 0x0C, 0x12, 0x0C, 0x2A, 0x0C, 0x43, 0x0C, 0x5C,
+ 0x0C, 0x75, 0x0C, 0x8E, 0x0C, 0xA7, 0x0C, 0xC0, 0x0C, 0xD9, 0x0C, 0xF3,
+ 0x0D, 0x0D, 0x0D, 0x26, 0x0D, 0x40, 0x0D, 0x5A, 0x0D, 0x74, 0x0D, 0x8E,
+ 0x0D, 0xA9, 0x0D, 0xC3, 0x0D, 0xDE, 0x0D, 0xF8, 0x0E, 0x13, 0x0E, 0x2E,
+ 0x0E, 0x49, 0x0E, 0x64, 0x0E, 0x7F, 0x0E, 0x9B, 0x0E, 0xB6, 0x0E, 0xD2,
+ 0x0E, 0xEE, 0x0F, 0x09, 0x0F, 0x25, 0x0F, 0x41, 0x0F, 0x5E, 0x0F, 0x7A,
+ 0x0F, 0x96, 0x0F, 0xB3, 0x0F, 0xCF, 0x0F, 0xEC, 0x10, 0x09, 0x10, 0x26,
+ 0x10, 0x43, 0x10, 0x61, 0x10, 0x7E, 0x10, 0x9B, 0x10, 0xB9, 0x10, 0xD7,
+ 0x10, 0xF5, 0x11, 0x13, 0x11, 0x31, 0x11, 0x4F, 0x11, 0x6D, 0x11, 0x8C,
+ 0x11, 0xAA, 0x11, 0xC9, 0x11, 0xE8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45,
+ 0x12, 0x64, 0x12, 0x84, 0x12, 0xA3, 0x12, 0xC3, 0x12, 0xE3, 0x13, 0x03,
+ 0x13, 0x23, 0x13, 0x43, 0x13, 0x63, 0x13, 0x83, 0x13, 0xA4, 0x13, 0xC5,
+ 0x13, 0xE5, 0x14, 0x06, 0x14, 0x27, 0x14, 0x49, 0x14, 0x6A, 0x14, 0x8B,
+ 0x14, 0xAD, 0x14, 0xCE, 0x14, 0xF0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56,
+ 0x15, 0x78, 0x15, 0x9B, 0x15, 0xBD, 0x15, 0xE0, 0x16, 0x03, 0x16, 0x26,
+ 0x16, 0x49, 0x16, 0x6C, 0x16, 0x8F, 0x16, 0xB2, 0x16, 0xD6, 0x16, 0xFA,
+ 0x17, 0x1D, 0x17, 0x41, 0x17, 0x65, 0x17, 0x89, 0x17, 0xAE, 0x17, 0xD2,
+ 0x17, 0xF7, 0x18, 0x1B, 0x18, 0x40, 0x18, 0x65, 0x18, 0x8A, 0x18, 0xAF,
+ 0x18, 0xD5, 0x18, 0xFA, 0x19, 0x20, 0x19, 0x45, 0x19, 0x6B, 0x19, 0x91,
+ 0x19, 0xB7, 0x19, 0xDD, 0x1A, 0x04, 0x1A, 0x2A, 0x1A, 0x51, 0x1A, 0x77,
+ 0x1A, 0x9E, 0x1A, 0xC5, 0x1A, 0xEC, 0x1B, 0x14, 0x1B, 0x3B, 0x1B, 0x63,
+ 0x1B, 0x8A, 0x1B, 0xB2, 0x1B, 0xDA, 0x1C, 0x02, 0x1C, 0x2A, 0x1C, 0x52,
+ 0x1C, 0x7B, 0x1C, 0xA3, 0x1C, 0xCC, 0x1C, 0xF5, 0x1D, 0x1E, 0x1D, 0x47,
+ 0x1D, 0x70, 0x1D, 0x99, 0x1D, 0xC3, 0x1D, 0xEC, 0x1E, 0x16, 0x1E, 0x40,
+ 0x1E, 0x6A, 0x1E, 0x94, 0x1E, 0xBE, 0x1E, 0xE9, 0x1F, 0x13, 0x1F, 0x3E,
+ 0x1F, 0x69, 0x1F, 0x94, 0x1F, 0xBF, 0x1F, 0xEA, 0x20, 0x15, 0x20, 0x41,
+ 0x20, 0x6C, 0x20, 0x98, 0x20, 0xC4, 0x20, 0xF0, 0x21, 0x1C, 0x21, 0x48,
+ 0x21, 0x75, 0x21, 0xA1, 0x21, 0xCE, 0x21, 0xFB, 0x22, 0x27, 0x22, 0x55,
+ 0x22, 0x82, 0x22, 0xAF, 0x22, 0xDD, 0x23, 0x0A, 0x23, 0x38, 0x23, 0x66,
+ 0x23, 0x94, 0x23, 0xC2, 0x23, 0xF0, 0x24, 0x1F, 0x24, 0x4D, 0x24, 0x7C,
+ 0x24, 0xAB, 0x24, 0xDA, 0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97,
+ 0x25, 0xC7, 0x25, 0xF7, 0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xB7,
+ 0x26, 0xE8, 0x27, 0x18, 0x27, 0x49, 0x27, 0x7A, 0x27, 0xAB, 0x27, 0xDC,
+ 0x28, 0x0D, 0x28, 0x3F, 0x28, 0x71, 0x28, 0xA2, 0x28, 0xD4, 0x29, 0x06,
+ 0x29, 0x38, 0x29, 0x6B, 0x29, 0x9D, 0x29, 0xD0, 0x2A, 0x02, 0x2A, 0x35,
+ 0x2A, 0x68, 0x2A, 0x9B, 0x2A, 0xCF, 0x2B, 0x02, 0x2B, 0x36, 0x2B, 0x69,
+ 0x2B, 0x9D, 0x2B, 0xD1, 0x2C, 0x05, 0x2C, 0x39, 0x2C, 0x6E, 0x2C, 0xA2,
+ 0x2C, 0xD7, 0x2D, 0x0C, 0x2D, 0x41, 0x2D, 0x76, 0x2D, 0xAB, 0x2D, 0xE1,
+ 0x2E, 0x16, 0x2E, 0x4C, 0x2E, 0x82, 0x2E, 0xB7, 0x2E, 0xEE, 0x2F, 0x24,
+ 0x2F, 0x5A, 0x2F, 0x91, 0x2F, 0xC7, 0x2F, 0xFE, 0x30, 0x35, 0x30, 0x6C,
+ 0x30, 0xA4, 0x30, 0xDB, 0x31, 0x12, 0x31, 0x4A, 0x31, 0x82, 0x31, 0xBA,
+ 0x31, 0xF2, 0x32, 0x2A, 0x32, 0x63, 0x32, 0x9B, 0x32, 0xD4, 0x33, 0x0D,
+ 0x33, 0x46, 0x33, 0x7F, 0x33, 0xB8, 0x33, 0xF1, 0x34, 0x2B, 0x34, 0x65,
+ 0x34, 0x9E, 0x34, 0xD8, 0x35, 0x13, 0x35, 0x4D, 0x35, 0x87, 0x35, 0xC2,
+ 0x35, 0xFD, 0x36, 0x37, 0x36, 0x72, 0x36, 0xAE, 0x36, 0xE9, 0x37, 0x24,
+ 0x37, 0x60, 0x37, 0x9C, 0x37, 0xD7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8C,
+ 0x38, 0xC8, 0x39, 0x05, 0x39, 0x42, 0x39, 0x7F, 0x39, 0xBC, 0x39, 0xF9,
+ 0x3A, 0x36, 0x3A, 0x74, 0x3A, 0xB2, 0x3A, 0xEF, 0x3B, 0x2D, 0x3B, 0x6B,
+ 0x3B, 0xAA, 0x3B, 0xE8, 0x3C, 0x27, 0x3C, 0x65, 0x3C, 0xA4, 0x3C, 0xE3,
+ 0x3D, 0x22, 0x3D, 0x61, 0x3D, 0xA1, 0x3D, 0xE0, 0x3E, 0x20, 0x3E, 0x60,
+ 0x3E, 0xA0, 0x3E, 0xE0, 0x3F, 0x21, 0x3F, 0x61, 0x3F, 0xA2, 0x3F, 0xE2,
+ 0x40, 0x23, 0x40, 0x64, 0x40, 0xA6, 0x40, 0xE7, 0x41, 0x29, 0x41, 0x6A,
+ 0x41, 0xAC, 0x41, 0xEE, 0x42, 0x30, 0x42, 0x72, 0x42, 0xB5, 0x42, 0xF7,
+ 0x43, 0x3A, 0x43, 0x7D, 0x43, 0xC0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8A,
+ 0x44, 0xCE, 0x45, 0x12, 0x45, 0x55, 0x45, 0x9A, 0x45, 0xDE, 0x46, 0x22,
+ 0x46, 0x67, 0x46, 0xAB, 0x46, 0xF0, 0x47, 0x35, 0x47, 0x7B, 0x47, 0xC0,
+ 0x48, 0x05, 0x48, 0x4B, 0x48, 0x91, 0x48, 0xD7, 0x49, 0x1D, 0x49, 0x63,
+ 0x49, 0xA9, 0x49, 0xF0, 0x4A, 0x37, 0x4A, 0x7D, 0x4A, 0xC4, 0x4B, 0x0C,
+ 0x4B, 0x53, 0x4B, 0x9A, 0x4B, 0xE2, 0x4C, 0x2A, 0x4C, 0x72, 0x4C, 0xBA,
+ 0x4D, 0x02, 0x4D, 0x4A, 0x4D, 0x93, 0x4D, 0xDC, 0x4E, 0x25, 0x4E, 0x6E,
+ 0x4E, 0xB7, 0x4F, 0x00, 0x4F, 0x49, 0x4F, 0x93, 0x4F, 0xDD, 0x50, 0x27,
+ 0x50, 0x71, 0x50, 0xBB, 0x51, 0x06, 0x51, 0x50, 0x51, 0x9B, 0x51, 0xE6,
+ 0x52, 0x31, 0x52, 0x7C, 0x52, 0xC7, 0x53, 0x13, 0x53, 0x5F, 0x53, 0xAA,
+ 0x53, 0xF6, 0x54, 0x42, 0x54, 0x8F, 0x54, 0xDB, 0x55, 0x28, 0x55, 0x75,
+ 0x55, 0xC2, 0x56, 0x0F, 0x56, 0x5C, 0x56, 0xA9, 0x56, 0xF7, 0x57, 0x44,
+ 0x57, 0x92, 0x57, 0xE0, 0x58, 0x2F, 0x58, 0x7D, 0x58, 0xCB, 0x59, 0x1A,
+ 0x59, 0x69, 0x59, 0xB8, 0x5A, 0x07, 0x5A, 0x56, 0x5A, 0xA6, 0x5A, 0xF5,
+ 0x5B, 0x45, 0x5B, 0x95, 0x5B, 0xE5, 0x5C, 0x35, 0x5C, 0x86, 0x5C, 0xD6,
+ 0x5D, 0x27, 0x5D, 0x78, 0x5D, 0xC9, 0x5E, 0x1A, 0x5E, 0x6C, 0x5E, 0xBD,
+ 0x5F, 0x0F, 0x5F, 0x61, 0x5F, 0xB3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xAA,
+ 0x60, 0xFC, 0x61, 0x4F, 0x61, 0xA2, 0x61, 0xF5, 0x62, 0x49, 0x62, 0x9C,
+ 0x62, 0xF0, 0x63, 0x43, 0x63, 0x97, 0x63, 0xEB, 0x64, 0x40, 0x64, 0x94,
+ 0x64, 0xE9, 0x65, 0x3D, 0x65, 0x92, 0x65, 0xE7, 0x66, 0x3D, 0x66, 0x92,
+ 0x66, 0xE8, 0x67, 0x3D, 0x67, 0x93, 0x67, 0xE9, 0x68, 0x3F, 0x68, 0x96,
+ 0x68, 0xEC, 0x69, 0x43, 0x69, 0x9A, 0x69, 0xF1, 0x6A, 0x48, 0x6A, 0x9F,
+ 0x6A, 0xF7, 0x6B, 0x4F, 0x6B, 0xA7, 0x6B, 0xFF, 0x6C, 0x57, 0x6C, 0xAF,
+ 0x6D, 0x08, 0x6D, 0x60, 0x6D, 0xB9, 0x6E, 0x12, 0x6E, 0x6B, 0x6E, 0xC4,
+ 0x6F, 0x1E, 0x6F, 0x78, 0x6F, 0xD1, 0x70, 0x2B, 0x70, 0x86, 0x70, 0xE0,
+ 0x71, 0x3A, 0x71, 0x95, 0x71, 0xF0, 0x72, 0x4B, 0x72, 0xA6, 0x73, 0x01,
+ 0x73, 0x5D, 0x73, 0xB8, 0x74, 0x14, 0x74, 0x70, 0x74, 0xCC, 0x75, 0x28,
+ 0x75, 0x85, 0x75, 0xE1, 0x76, 0x3E, 0x76, 0x9B, 0x76, 0xF8, 0x77, 0x56,
+ 0x77, 0xB3, 0x78, 0x11, 0x78, 0x6E, 0x78, 0xCC, 0x79, 0x2A, 0x79, 0x89,
+ 0x79, 0xE7, 0x7A, 0x46, 0x7A, 0xA5, 0x7B, 0x04, 0x7B, 0x63, 0x7B, 0xC2,
+ 0x7C, 0x21, 0x7C, 0x81, 0x7C, 0xE1, 0x7D, 0x41, 0x7D, 0xA1, 0x7E, 0x01,
+ 0x7E, 0x62, 0x7E, 0xC2, 0x7F, 0x23, 0x7F, 0x84, 0x7F, 0xE5, 0x80, 0x47,
+ 0x80, 0xA8, 0x81, 0x0A, 0x81, 0x6B, 0x81, 0xCD, 0x82, 0x30, 0x82, 0x92,
+ 0x82, 0xF4, 0x83, 0x57, 0x83, 0xBA, 0x84, 0x1D, 0x84, 0x80, 0x84, 0xE3,
+ 0x85, 0x47, 0x85, 0xAB, 0x86, 0x0E, 0x86, 0x72, 0x86, 0xD7, 0x87, 0x3B,
+ 0x87, 0x9F, 0x88, 0x04, 0x88, 0x69, 0x88, 0xCE, 0x89, 0x33, 0x89, 0x99,
+ 0x89, 0xFE, 0x8A, 0x64, 0x8A, 0xCA, 0x8B, 0x30, 0x8B, 0x96, 0x8B, 0xFC,
+ 0x8C, 0x63, 0x8C, 0xCA, 0x8D, 0x31, 0x8D, 0x98, 0x8D, 0xFF, 0x8E, 0x66,
+ 0x8E, 0xCE, 0x8F, 0x36, 0x8F, 0x9E, 0x90, 0x06, 0x90, 0x6E, 0x90, 0xD6,
+ 0x91, 0x3F, 0x91, 0xA8, 0x92, 0x11, 0x92, 0x7A, 0x92, 0xE3, 0x93, 0x4D,
+ 0x93, 0xB6, 0x94, 0x20, 0x94, 0x8A, 0x94, 0xF4, 0x95, 0x5F, 0x95, 0xC9,
+ 0x96, 0x34, 0x96, 0x9F, 0x97, 0x0A, 0x97, 0x75, 0x97, 0xE0, 0x98, 0x4C,
+ 0x98, 0xB8, 0x99, 0x24, 0x99, 0x90, 0x99, 0xFC, 0x9A, 0x68, 0x9A, 0xD5,
+ 0x9B, 0x42, 0x9B, 0xAF, 0x9C, 0x1C, 0x9C, 0x89, 0x9C, 0xF7, 0x9D, 0x64,
+ 0x9D, 0xD2, 0x9E, 0x40, 0x9E, 0xAE, 0x9F, 0x1D, 0x9F, 0x8B, 0x9F, 0xFA,
+ 0xA0, 0x69, 0xA0, 0xD8, 0xA1, 0x47, 0xA1, 0xB6, 0xA2, 0x26, 0xA2, 0x96,
+ 0xA3, 0x06, 0xA3, 0x76, 0xA3, 0xE6, 0xA4, 0x56, 0xA4, 0xC7, 0xA5, 0x38,
+ 0xA5, 0xA9, 0xA6, 0x1A, 0xA6, 0x8B, 0xA6, 0xFD, 0xA7, 0x6E, 0xA7, 0xE0,
+ 0xA8, 0x52, 0xA8, 0xC4, 0xA9, 0x37, 0xA9, 0xA9, 0xAA, 0x1C, 0xAA, 0x8F,
+ 0xAB, 0x02, 0xAB, 0x75, 0xAB, 0xE9, 0xAC, 0x5C, 0xAC, 0xD0, 0xAD, 0x44,
+ 0xAD, 0xB8, 0xAE, 0x2D, 0xAE, 0xA1, 0xAF, 0x16, 0xAF, 0x8B, 0xB0, 0x00,
+ 0xB0, 0x75, 0xB0, 0xEA, 0xB1, 0x60, 0xB1, 0xD6, 0xB2, 0x4B, 0xB2, 0xC2,
+ 0xB3, 0x38, 0xB3, 0xAE, 0xB4, 0x25, 0xB4, 0x9C, 0xB5, 0x13, 0xB5, 0x8A,
+ 0xB6, 0x01, 0xB6, 0x79, 0xB6, 0xF0, 0xB7, 0x68, 0xB7, 0xE0, 0xB8, 0x59,
+ 0xB8, 0xD1, 0xB9, 0x4A, 0xB9, 0xC2, 0xBA, 0x3B, 0xBA, 0xB5, 0xBB, 0x2E,
+ 0xBB, 0xA7, 0xBC, 0x21, 0xBC, 0x9B, 0xBD, 0x15, 0xBD, 0x8F, 0xBE, 0x0A,
+ 0xBE, 0x84, 0xBE, 0xFF, 0xBF, 0x7A, 0xBF, 0xF5, 0xC0, 0x70, 0xC0, 0xEC,
+ 0xC1, 0x67, 0xC1, 0xE3, 0xC2, 0x5F, 0xC2, 0xDB, 0xC3, 0x58, 0xC3, 0xD4,
+ 0xC4, 0x51, 0xC4, 0xCE, 0xC5, 0x4B, 0xC5, 0xC8, 0xC6, 0x46, 0xC6, 0xC3,
+ 0xC7, 0x41, 0xC7, 0xBF, 0xC8, 0x3D, 0xC8, 0xBC, 0xC9, 0x3A, 0xC9, 0xB9,
+ 0xCA, 0x38, 0xCA, 0xB7, 0xCB, 0x36, 0xCB, 0xB6, 0xCC, 0x35, 0xCC, 0xB5,
+ 0xCD, 0x35, 0xCD, 0xB5, 0xCE, 0x36, 0xCE, 0xB6, 0xCF, 0x37, 0xCF, 0xB8,
+ 0xD0, 0x39, 0xD0, 0xBA, 0xD1, 0x3C, 0xD1, 0xBE, 0xD2, 0x3F, 0xD2, 0xC1,
+ 0xD3, 0x44, 0xD3, 0xC6, 0xD4, 0x49, 0xD4, 0xCB, 0xD5, 0x4E, 0xD5, 0xD1,
+ 0xD6, 0x55, 0xD6, 0xD8, 0xD7, 0x5C, 0xD7, 0xE0, 0xD8, 0x64, 0xD8, 0xE8,
+ 0xD9, 0x6C, 0xD9, 0xF1, 0xDA, 0x76, 0xDA, 0xFB, 0xDB, 0x80, 0xDC, 0x05,
+ 0xDC, 0x8A, 0xDD, 0x10, 0xDD, 0x96, 0xDE, 0x1C, 0xDE, 0xA2, 0xDF, 0x29,
+ 0xDF, 0xAF, 0xE0, 0x36, 0xE0, 0xBD, 0xE1, 0x44, 0xE1, 0xCC, 0xE2, 0x53,
+ 0xE2, 0xDB, 0xE3, 0x63, 0xE3, 0xEB, 0xE4, 0x73, 0xE4, 0xFC, 0xE5, 0x84,
+ 0xE6, 0x0D, 0xE6, 0x96, 0xE7, 0x1F, 0xE7, 0xA9, 0xE8, 0x32, 0xE8, 0xBC,
+ 0xE9, 0x46, 0xE9, 0xD0, 0xEA, 0x5B, 0xEA, 0xE5, 0xEB, 0x70, 0xEB, 0xFB,
+ 0xEC, 0x86, 0xED, 0x11, 0xED, 0x9C, 0xEE, 0x28, 0xEE, 0xB4, 0xEF, 0x40,
+ 0xEF, 0xCC, 0xF0, 0x58, 0xF0, 0xE5, 0xF1, 0x72, 0xF1, 0xFF, 0xF2, 0x8C,
+ 0xF3, 0x19, 0xF3, 0xA7, 0xF4, 0x34, 0xF4, 0xC2, 0xF5, 0x50, 0xF5, 0xDE,
+ 0xF6, 0x6D, 0xF6, 0xFB, 0xF7, 0x8A, 0xF8, 0x19, 0xF8, 0xA8, 0xF9, 0x38,
+ 0xF9, 0xC7, 0xFA, 0x57, 0xFA, 0xE7, 0xFB, 0x77, 0xFC, 0x07, 0xFC, 0x98,
+ 0xFD, 0x29, 0xFD, 0xBA, 0xFE, 0x4B, 0xFE, 0xDC, 0xFF, 0x6D, 0xFF, 0xFF
+ };
+
+ size = sizeof (ksRGBProfileData);
+ data = ksRGBProfileData;
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_sRGB::Get ()
+ {
+
+ static dng_space_sRGB static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_AdobeRGB::dng_space_AdobeRGB ()
+ {
+
+ SetMatrixToPCS (dng_matrix_3by3 (0.6097, 0.2053, 0.1492,
+ 0.3111, 0.6257, 0.0632,
+ 0.0195, 0.0609, 0.7446));
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_space_AdobeRGB::GammaFunction () const
+ {
+
+ return dng_function_GammaEncode_2_2::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_space_AdobeRGB::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+
+ {
+
+ static const uint8 kAdobeRGBProfileData [] =
+ {
+ 0x00, 0x00, 0x02, 0x30, 0x41, 0x44, 0x42, 0x45, 0x02, 0x10, 0x00, 0x00,
+ 0x6D, 0x6E, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5A, 0x20,
+ 0x07, 0xCF, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, 0x4C, 0x00, 0x00, 0x00, 0x00,
+ 0x6E, 0x6F, 0x6E, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2D, 0x41, 0x44, 0x42, 0x45,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x32,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x6B,
+ 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x9C, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x6B, 0x70, 0x74, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x14,
+ 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x00, 0x0E,
+ 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xD4, 0x00, 0x00, 0x00, 0x0E,
+ 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xE4, 0x00, 0x00, 0x00, 0x0E,
+ 0x72, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x14,
+ 0x67, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x1C, 0x00, 0x00, 0x00, 0x14,
+ 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x70, 0x79,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x41,
+ 0x64, 0x6F, 0x62, 0x65, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x73,
+ 0x20, 0x49, 0x6E, 0x63, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x65,
+ 0x64, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x11, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x52, 0x47,
+ 0x42, 0x20, 0x28, 0x31, 0x39, 0x39, 0x38, 0x29, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xF3, 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xCC,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x33, 0x00, 0x00,
+ 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x02, 0x33, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x33, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x18, 0x00, 0x00, 0x4F, 0xA5,
+ 0x00, 0x00, 0x04, 0xFC, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x34, 0x8D, 0x00, 0x00, 0xA0, 0x2C, 0x00, 0x00, 0x0F, 0x95,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x31,
+ 0x00, 0x00, 0x10, 0x2F, 0x00, 0x00, 0xBE, 0x9C
+ };
+
+ size = sizeof (kAdobeRGBProfileData);
+ data = kAdobeRGBProfileData;
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_AdobeRGB::Get ()
+ {
+
+ static dng_space_AdobeRGB static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_ColorMatch::dng_space_ColorMatch ()
+ {
+
+ SetMatrixToPCS (dng_matrix_3by3 (0.5094, 0.3208, 0.1339,
+ 0.2749, 0.6581, 0.0670,
+ 0.0243, 0.1087, 0.6919));
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_space_ColorMatch::GammaFunction () const
+ {
+
+ return dng_function_GammaEncode_1_8::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_space_ColorMatch::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+
+ {
+
+ static const uint8 kColorMatchProfileData [] =
+ {
+ 0x00, 0x00, 0x02, 0x30, 0x41, 0x44, 0x42, 0x45, 0x02, 0x10, 0x00, 0x00,
+ 0x6D, 0x6E, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5A, 0x20,
+ 0x07, 0xCF, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, 0x4C, 0x00, 0x00, 0x00, 0x00,
+ 0x6E, 0x6F, 0x6E, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2D, 0x41, 0x44, 0x42, 0x45,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x32,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x00, 0x69,
+ 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x9C, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x6B, 0x70, 0x74, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00, 0x14,
+ 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x00, 0x0E,
+ 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xD4, 0x00, 0x00, 0x00, 0x0E,
+ 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xE4, 0x00, 0x00, 0x00, 0x0E,
+ 0x72, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x14,
+ 0x67, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x1C, 0x00, 0x00, 0x00, 0x14,
+ 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x70, 0x79,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x41,
+ 0x64, 0x6F, 0x62, 0x65, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x73,
+ 0x20, 0x49, 0x6E, 0x63, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x65,
+ 0x64, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0F, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x4D, 0x61, 0x74,
+ 0x63, 0x68, 0x20, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xF6, 0xDC, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x3A,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xCD, 0x00, 0x00,
+ 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0xCD, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x01, 0xCD, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x6B, 0x00, 0x00, 0x46, 0x63,
+ 0x00, 0x00, 0x06, 0x36, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x52, 0x23, 0x00, 0x00, 0xA8, 0x79, 0x00, 0x00, 0x1B, 0xD7,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x48,
+ 0x00, 0x00, 0x11, 0x25, 0x00, 0x00, 0xB1, 0x20
+ };
+
+ size = sizeof (kColorMatchProfileData);
+ data = kColorMatchProfileData;
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_ColorMatch::Get ()
+ {
+
+ static dng_space_ColorMatch static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_ProPhoto::dng_space_ProPhoto ()
+ {
+
+ SetMatrixToPCS (dng_matrix_3by3 (0.7977, 0.1352, 0.0313,
+ 0.2880, 0.7119, 0.0001,
+ 0.0000, 0.0000, 0.8249));
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_space_ProPhoto::GammaFunction () const
+ {
+
+ return dng_function_GammaEncode_1_8::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_space_ProPhoto::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+
+ {
+
+ static const uint8 kProPhotoProfileData [] =
+ {
+ 0x00, 0x00, 0x03, 0xAC, 0x4B, 0x43, 0x4D, 0x53, 0x02, 0x10, 0x00, 0x00,
+ 0x6D, 0x6E, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5A, 0x20,
+ 0x07, 0xCE, 0x00, 0x0C, 0x00, 0x01, 0x00, 0x12, 0x00, 0x3A, 0x00, 0x15,
+ 0x61, 0x63, 0x73, 0x70, 0x4D, 0x53, 0x46, 0x54, 0x00, 0x00, 0x00, 0x00,
+ 0x4B, 0x4F, 0x44, 0x41, 0x52, 0x4F, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2B, 0x4B, 0x4F, 0x44, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C,
+ 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x48,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x5C, 0x00, 0x00, 0x00, 0x83,
+ 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x14,
+ 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x0E,
+ 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x0E,
+ 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x00, 0x0E,
+ 0x72, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14,
+ 0x67, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x02, 0x2C, 0x00, 0x00, 0x00, 0x14,
+ 0x64, 0x6D, 0x6E, 0x64, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x6E,
+ 0x64, 0x6D, 0x64, 0x64, 0x00, 0x00, 0x02, 0xB0, 0x00, 0x00, 0x00, 0xD1,
+ 0x6D, 0x6D, 0x6F, 0x64, 0x00, 0x00, 0x03, 0x84, 0x00, 0x00, 0x00, 0x28,
+ 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x70, 0x79,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x45, 0x61,
+ 0x73, 0x74, 0x6D, 0x61, 0x6E, 0x20, 0x4B, 0x6F, 0x64, 0x61, 0x6B, 0x20,
+ 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x6E, 0x79, 0x2C, 0x20, 0x31, 0x39, 0x39,
+ 0x39, 0x2C, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2E, 0x00,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D,
+ 0x50, 0x72, 0x6F, 0x50, 0x68, 0x6F, 0x74, 0x6F, 0x20, 0x52, 0x47, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xFE, 0xFF, 0x00,
+ 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x50, 0x00, 0x68, 0x00, 0x6F, 0x00,
+ 0x74, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x52, 0x00, 0x47, 0x00, 0x42, 0x00,
+ 0x00, 0x00, 0x00, 0x0D, 0x50, 0x72, 0x6F, 0x50, 0x68, 0x6F, 0x74, 0x6F,
+ 0x20, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2C, 0x63, 0x75, 0x72, 0x76,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xCD, 0x00, 0x00,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x34,
+ 0x00, 0x00, 0x49, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x9C, 0x00, 0x00, 0xB6, 0x3E,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xD3, 0x2D,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
+ 0x4B, 0x4F, 0x44, 0x41, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x07, 0xFE, 0xFF, 0x00, 0x4B, 0x00, 0x4F, 0x00, 0x44, 0x00, 0x41,
+ 0x00, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x06, 0x4B, 0x4F, 0x44, 0x41, 0x4B,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x27, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63,
+ 0x65, 0x20, 0x4F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x4D, 0x65, 0x64,
+ 0x69, 0x75, 0x6D, 0x20, 0x4D, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x52,
+ 0x4F, 0x4D, 0x4D, 0x29, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x28, 0xFE, 0xFF, 0x00, 0x52, 0x00, 0x65, 0x00, 0x66, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x65, 0x00,
+ 0x20, 0x00, 0x4F, 0x00, 0x75, 0x00, 0x74, 0x00, 0x70, 0x00, 0x75, 0x00,
+ 0x74, 0x00, 0x20, 0x00, 0x4D, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00,
+ 0x75, 0x00, 0x6D, 0x00, 0x20, 0x00, 0x4D, 0x00, 0x65, 0x00, 0x74, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x63, 0x00, 0x28, 0x00, 0x52, 0x00, 0x4F, 0x00,
+ 0x4D, 0x00, 0x4D, 0x00, 0x29, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x27, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x20,
+ 0x4F, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x4D, 0x65, 0x64, 0x69, 0x75,
+ 0x6D, 0x20, 0x4D, 0x65, 0x74, 0x72, 0x69, 0x63, 0x28, 0x52, 0x4F, 0x4D,
+ 0x4D, 0x29, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6D, 0x6D, 0x6F, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10,
+ 0x00, 0x00, 0x9D, 0x03, 0x01, 0x01, 0x01, 0x01, 0xB0, 0xCF, 0x3B, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+ };
+
+ size = sizeof (kProPhotoProfileData);
+ data = kProPhotoProfileData;
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_ProPhoto::Get ()
+ {
+
+ static dng_space_ProPhoto static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_GrayGamma18::dng_space_GrayGamma18 ()
+ {
+
+ SetMonochrome ();
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_space_GrayGamma18::GammaFunction () const
+ {
+
+ return dng_function_GammaEncode_1_8::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_space_GrayGamma18::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+
+ {
+
+ static const uint8 kGamma18ProfileData [] =
+ {
+ 0x00, 0x00, 0x01, 0x98, 0x41, 0x44, 0x42, 0x45, 0x02, 0x10, 0x00, 0x00,
+ 0x6D, 0x6E, 0x74, 0x72, 0x47, 0x52, 0x41, 0x59, 0x58, 0x59, 0x5A, 0x20,
+ 0x07, 0xCF, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, 0x4C, 0x00, 0x00, 0x00, 0x00,
+ 0x6E, 0x6F, 0x6E, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2D, 0x41, 0x44, 0x42, 0x45,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x32,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0x69,
+ 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x6B, 0x70, 0x74, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x00, 0x14,
+ 0x6B, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x0E,
+ 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x70, 0x79,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x41,
+ 0x64, 0x6F, 0x62, 0x65, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x73,
+ 0x20, 0x49, 0x6E, 0x63, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x65,
+ 0x64, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0F, 0x47, 0x72, 0x61, 0x79, 0x20, 0x47, 0x61, 0x6D,
+ 0x6D, 0x61, 0x20, 0x31, 0x2E, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xF3, 0x54, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xCF,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xCD, 0x00, 0x00
+ };
+
+ size = sizeof (kGamma18ProfileData);
+ data = kGamma18ProfileData;
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_GrayGamma18::Get ()
+ {
+
+ static dng_space_GrayGamma18 static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_GrayGamma22::dng_space_GrayGamma22 ()
+ {
+
+ SetMonochrome ();
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_space_GrayGamma22::GammaFunction () const
+ {
+
+ return dng_function_GammaEncode_2_2::Get ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_space_GrayGamma22::ICCProfile (uint32 &size,
+ const uint8 *&data) const
+
+ {
+
+ static const uint8 kGamma22ProfileData [] =
+ {
+ 0x00, 0x00, 0x01, 0x98, 0x41, 0x44, 0x42, 0x45, 0x02, 0x10, 0x00, 0x00,
+ 0x6D, 0x6E, 0x74, 0x72, 0x47, 0x52, 0x41, 0x59, 0x58, 0x59, 0x5A, 0x20,
+ 0x07, 0xCF, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, 0x4C, 0x00, 0x00, 0x00, 0x00,
+ 0x6E, 0x6F, 0x6E, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD6,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x2D, 0x41, 0x44, 0x42, 0x45,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x32,
+ 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0x69,
+ 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x00, 0x14,
+ 0x62, 0x6B, 0x70, 0x74, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x00, 0x14,
+ 0x6B, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x00, 0x0E,
+ 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6F, 0x70, 0x79,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x41,
+ 0x64, 0x6F, 0x62, 0x65, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x73,
+ 0x20, 0x49, 0x6E, 0x63, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x65,
+ 0x64, 0x00, 0x00, 0x00, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0F, 0x47, 0x72, 0x61, 0x79, 0x20, 0x47, 0x61, 0x6D,
+ 0x6D, 0x61, 0x20, 0x32, 0x2E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xF3, 0x54, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x16, 0xCF,
+ 0x58, 0x59, 0x5A, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x76,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x33, 0x00, 0x00
+ };
+
+ size = sizeof (kGamma22ProfileData);
+ data = kGamma22ProfileData;
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_GrayGamma22::Get ()
+ {
+
+ static dng_space_GrayGamma22 static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
+
+dng_space_fakeRGB::dng_space_fakeRGB ()
+ {
+
+ SetMatrixToPCS (dng_matrix_3by3 (0.6097, 0.2053, 0.1492,
+ 0.3111, 0.6257, 0.0632,
+ 0.0195, 0.0609, 0.7446));
+
+ }
+
+/*****************************************************************************/
+
+const dng_color_space & dng_space_fakeRGB::Get ()
+ {
+
+ static dng_space_fakeRGB static_space;
+
+ return static_space;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_color_space.h b/gpr/source/lib/dng_sdk/dng_color_space.h
new file mode 100644
index 0000000..00d0d14
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_color_space.h
@@ -0,0 +1,351 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_color_space.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Standard gamma functions and color spaces used within the DNG SDK.
+ */
+
+#ifndef __dng_color_space__
+#define __dng_color_space__
+
+/*****************************************************************************/
+
+#include "dng_1d_function.h"
+#include "dng_classes.h"
+#include "dng_matrix.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief A dng_1d_function for gamma encoding in sRGB color space
+
+class dng_function_GammaEncode_sRGB: public dng_1d_function
+ {
+
+ public:
+
+ virtual real64 Evaluate (real64 x) const;
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ static const dng_1d_function & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A dng_1d_function for gamma encoding with 1.8 gamma.
+
+class dng_function_GammaEncode_1_8: public dng_1d_function
+ {
+
+ public:
+
+ virtual real64 Evaluate (real64 x) const;
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ static const dng_1d_function & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A dng_1d_function for gamma encoding with 2.2 gamma.
+
+class dng_function_GammaEncode_2_2: public dng_1d_function
+ {
+
+ public:
+
+ virtual real64 Evaluate (real64 x) const;
+
+ virtual real64 EvaluateInverse (real64 y) const;
+
+ static const dng_1d_function & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An abstract color space
+
+class dng_color_space
+ {
+
+ protected:
+
+ dng_matrix fMatrixToPCS;
+
+ dng_matrix fMatrixFromPCS;
+
+ public:
+
+ virtual ~dng_color_space ();
+
+ /// Return a matrix which transforms source data in this color space into the
+ /// Profile Connection Space.
+
+ const dng_matrix & MatrixToPCS () const
+ {
+ return fMatrixToPCS;
+ }
+
+ /// Return a matrix which transforms Profile Connection Space data into this
+ /// color space.
+
+ const dng_matrix & MatrixFromPCS () const
+ {
+ return fMatrixFromPCS;
+ }
+
+ /// Predicate which is true if this color space is monochrome (has only a
+ /// single column).
+
+ bool IsMonochrome () const
+ {
+ return fMatrixToPCS.Cols () == 1;
+ }
+
+ /// Getter for the gamma function for this color space.
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns true if this color space is linear. (I.e. has gamma 1.0.)
+
+ bool IsLinear () const
+ {
+ return GammaFunction ().IsIdentity ();
+ }
+
+ /// Map an input value through this color space's encoding gamma.
+
+ real64 GammaEncode (real64 x) const
+ {
+ return GammaFunction ().Evaluate (x);
+ }
+
+ /// Map an input value through this color space's decoding gamma (inverse of
+ /// the encoding gamma).
+
+ real64 GammaDecode (real64 y) const
+ {
+ return GammaFunction ().EvaluateInverse (y);
+ }
+
+ /// Getter for ICC profile, if this color space has one.
+ /// \param size Out parameter which receives size on return.
+ /// \param data Receives bytes of profile.
+ /// \retval Returns true if this color space has an ICC profile, false otherwise.
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ protected:
+
+ dng_color_space ();
+
+ void SetMonochrome ();
+
+ void SetMatrixToPCS (const dng_matrix_3by3 &M);
+
+ };
+
+/*****************************************************************************/
+
+/// Singleton class for sRGB color space.
+
+class dng_space_sRGB: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_sRGB ();
+
+ public:
+
+ /// Returns dng_function_GammaEncode_sRGB
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns sRGB IEC61966-2.1 ICC profile
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ /// Static method for getting single global instance of this color space.
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Singleton class for AdobeRGB color space.
+
+class dng_space_AdobeRGB: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_AdobeRGB ();
+
+ public:
+
+ /// Returns dng_function_GammaEncode_1_8
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns AdobeRGB (1998) ICC profile
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ /// Static method for getting single global instance of this color space.
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Singleton class for ColorMatch color space.
+
+class dng_space_ColorMatch: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_ColorMatch ();
+
+ public:
+
+ /// Returns dng_function_GammaEncode_1_8
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns ColorMatch RGB ICC profile
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ /// Static method for getting single global instance of this color space.
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Singleton class for ProPhoto RGB color space.
+
+class dng_space_ProPhoto: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_ProPhoto ();
+
+ public:
+
+ /// Returns dng_function_GammaEncode_1_8
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns ProPhoto RGB ICC profile
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ /// Static method for getting single global instance of this color space.
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Singleton class for gamma 1.8 grayscale color space.
+
+class dng_space_GrayGamma18: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_GrayGamma18 ();
+
+ public:
+
+ /// Returns dng_function_GammaEncode_1_8
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns simple grayscale gamma 1.8 ICC profile
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ /// Static method for getting single global instance of this color space.
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Singleton class for gamma 2.2 grayscale color space.
+
+class dng_space_GrayGamma22: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_GrayGamma22 ();
+
+ public:
+
+ /// Returns dng_function_GammaEncode_2_2
+
+ virtual const dng_1d_function & GammaFunction () const;
+
+ /// Returns simple grayscale gamma 2.2 ICC profile
+
+ virtual bool ICCProfile (uint32 &size,
+ const uint8 *&data) const;
+
+ /// Static method for getting single global instance of this color space.
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+class dng_space_fakeRGB: public dng_color_space
+ {
+
+ protected:
+
+ dng_space_fakeRGB ();
+
+ public:
+
+ static const dng_color_space & Get ();
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_color_spec.cpp b/gpr/source/lib/dng_sdk/dng_color_spec.cpp
new file mode 100644
index 0000000..139cdee
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_color_spec.cpp
@@ -0,0 +1,559 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_color_spec.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+#include "dng_color_spec.h"
+
+#include "dng_assertions.h"
+#include "dng_camera_profile.h"
+#include "dng_exceptions.h"
+#include "dng_matrix.h"
+#include "dng_negative.h"
+#include "dng_temperature.h"
+#include "dng_utils.h"
+#include "dng_xy_coord.h"
+
+/*****************************************************************************/
+
+dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1,
+ const dng_xy_coord &white2)
+ {
+
+ // Use the linearized Bradford adaptation matrix.
+
+ dng_matrix_3by3 Mb ( 0.8951, 0.2664, -0.1614,
+ -0.7502, 1.7135, 0.0367,
+ 0.0389, -0.0685, 1.0296);
+
+ dng_vector_3 w1 = Mb * XYtoXYZ (white1);
+ dng_vector_3 w2 = Mb * XYtoXYZ (white2);
+
+ // Negative white coordinates are kind of meaningless.
+
+ w1 [0] = Max_real64 (w1 [0], 0.0);
+ w1 [1] = Max_real64 (w1 [1], 0.0);
+ w1 [2] = Max_real64 (w1 [2], 0.0);
+
+ w2 [0] = Max_real64 (w2 [0], 0.0);
+ w2 [1] = Max_real64 (w2 [1], 0.0);
+ w2 [2] = Max_real64 (w2 [2], 0.0);
+
+ // Limit scaling to something reasonable.
+
+ dng_matrix_3by3 A;
+
+ A [0] [0] = Pin_real64 (0.1, w1 [0] > 0.0 ? w2 [0] / w1 [0] : 10.0, 10.0);
+ A [1] [1] = Pin_real64 (0.1, w1 [1] > 0.0 ? w2 [1] / w1 [1] : 10.0, 10.0);
+ A [2] [2] = Pin_real64 (0.1, w1 [2] > 0.0 ? w2 [2] / w1 [2] : 10.0, 10.0);
+
+ dng_matrix_3by3 B = Invert (Mb) * A * Mb;
+
+ return B;
+
+ }
+
+/******************************************************************************/
+
+dng_color_spec::dng_color_spec (const dng_negative &negative,
+ const dng_camera_profile *profile)
+
+ : fChannels (negative.ColorChannels ())
+
+ , fTemperature1 (0.0)
+ , fTemperature2 (0.0)
+
+ , fColorMatrix1 ()
+ , fColorMatrix2 ()
+
+ , fForwardMatrix1 ()
+ , fForwardMatrix2 ()
+
+ , fReductionMatrix1 ()
+ , fReductionMatrix2 ()
+
+ , fCameraCalibration1 ()
+ , fCameraCalibration2 ()
+
+ , fAnalogBalance ()
+
+ , fWhiteXY ()
+
+ , fCameraWhite ()
+ , fCameraToPCS ()
+
+ , fPCStoCamera ()
+
+ {
+
+ if (fChannels > 1)
+ {
+
+ if (!profile || !profile->IsValid (fChannels))
+ {
+ ThrowBadFormat ();
+ }
+
+ if (profile->WasStubbed ())
+ {
+ ThrowProgramError ("Using stubbed profile");
+ }
+
+ fTemperature1 = profile->CalibrationTemperature1 ();
+ fTemperature2 = profile->CalibrationTemperature2 ();
+
+ fColorMatrix1 = profile->ColorMatrix1 ();
+ fColorMatrix2 = profile->ColorMatrix2 ();
+
+ fForwardMatrix1 = profile->ForwardMatrix1 ();
+ fForwardMatrix2 = profile->ForwardMatrix2 ();
+
+ fReductionMatrix1 = profile->ReductionMatrix1 ();
+ fReductionMatrix2 = profile->ReductionMatrix2 ();
+
+ fCameraCalibration1.SetIdentity (fChannels);
+ fCameraCalibration2.SetIdentity (fChannels);
+
+ if (negative. CameraCalibrationSignature () ==
+ profile->ProfileCalibrationSignature ())
+ {
+
+ if (negative.CameraCalibration1 ().Rows () == fChannels &&
+ negative.CameraCalibration1 ().Cols () == fChannels)
+ {
+
+ fCameraCalibration1 = negative.CameraCalibration1 ();
+
+ }
+
+ if (negative.CameraCalibration2 ().Rows () == fChannels &&
+ negative.CameraCalibration2 ().Cols () == fChannels)
+ {
+
+ fCameraCalibration2 = negative.CameraCalibration2 ();
+
+ }
+
+ }
+
+ fAnalogBalance = dng_matrix (fChannels, fChannels);
+
+ for (uint32 j = 0; j < fChannels; j++)
+ {
+
+ fAnalogBalance [j] [j] = negative.AnalogBalance (j);
+
+ }
+
+ dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix1);
+
+ fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1;
+
+ if (!profile->HasColorMatrix2 () ||
+ fTemperature1 <= 0.0 ||
+ fTemperature2 <= 0.0 ||
+ fTemperature1 == fTemperature2)
+ {
+
+ fTemperature1 = 5000.0;
+ fTemperature2 = 5000.0;
+
+ fColorMatrix2 = fColorMatrix1;
+ fForwardMatrix2 = fForwardMatrix1;
+ fReductionMatrix2 = fReductionMatrix1;
+ fCameraCalibration2 = fCameraCalibration1;
+
+ }
+
+ else
+ {
+
+ dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix2);
+
+ fColorMatrix2 = fAnalogBalance * fCameraCalibration2 * fColorMatrix2;
+
+ // Swap values if temperatures are out of order.
+
+ if (fTemperature1 > fTemperature2)
+ {
+
+ real64 temp = fTemperature1;
+ fTemperature1 = fTemperature2;
+ fTemperature2 = temp;
+
+ dng_matrix T = fColorMatrix1;
+ fColorMatrix1 = fColorMatrix2;
+ fColorMatrix2 = T;
+
+ T = fForwardMatrix1;
+ fForwardMatrix1 = fForwardMatrix2;
+ fForwardMatrix2 = T;
+
+ T = fReductionMatrix1;
+ fReductionMatrix1 = fReductionMatrix2;
+ fReductionMatrix2 = T;
+
+ T = fCameraCalibration1;
+ fCameraCalibration1 = fCameraCalibration2;
+ fCameraCalibration2 = T;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix dng_color_spec::FindXYZtoCamera (const dng_xy_coord &white,
+ dng_matrix *forwardMatrix,
+ dng_matrix *reductionMatrix,
+ dng_matrix *cameraCalibration)
+ {
+
+ // Convert to temperature/offset space.
+
+ dng_temperature td (white);
+
+ // Find fraction to weight the first calibration.
+
+ real64 g;
+
+ if (td.Temperature () <= fTemperature1)
+ g = 1.0;
+
+ else if (td.Temperature () >= fTemperature2)
+ g = 0.0;
+
+ else
+ {
+
+ real64 invT = 1.0 / td.Temperature ();
+
+ g = (invT - (1.0 / fTemperature2)) /
+ ((1.0 / fTemperature1) - (1.0 / fTemperature2));
+
+ }
+
+ // Interpolate the color matrix.
+
+ dng_matrix colorMatrix;
+
+ if (g >= 1.0)
+ colorMatrix = fColorMatrix1;
+
+ else if (g <= 0.0)
+ colorMatrix = fColorMatrix2;
+
+ else
+ colorMatrix = (g ) * fColorMatrix1 +
+ (1.0 - g) * fColorMatrix2;
+
+ // Interpolate forward matrix, if any.
+
+ if (forwardMatrix)
+ {
+
+ bool has1 = fForwardMatrix1.NotEmpty ();
+ bool has2 = fForwardMatrix2.NotEmpty ();
+
+ if (has1 && has2)
+ {
+
+ if (g >= 1.0)
+ *forwardMatrix = fForwardMatrix1;
+
+ else if (g <= 0.0)
+ *forwardMatrix = fForwardMatrix2;
+
+ else
+ *forwardMatrix = (g ) * fForwardMatrix1 +
+ (1.0 - g) * fForwardMatrix2;
+
+ }
+
+ else if (has1)
+ {
+
+ *forwardMatrix = fForwardMatrix1;
+
+ }
+
+ else if (has2)
+ {
+
+ *forwardMatrix = fForwardMatrix2;
+
+ }
+
+ else
+ {
+
+ forwardMatrix->Clear ();
+
+ }
+
+ }
+
+ // Interpolate reduction matrix, if any.
+
+ if (reductionMatrix)
+ {
+
+ bool has1 = fReductionMatrix1.NotEmpty ();
+ bool has2 = fReductionMatrix2.NotEmpty ();
+
+ if (has1 && has2)
+ {
+
+ if (g >= 1.0)
+ *reductionMatrix = fReductionMatrix1;
+
+ else if (g <= 0.0)
+ *reductionMatrix = fReductionMatrix2;
+
+ else
+ *reductionMatrix = (g ) * fReductionMatrix1 +
+ (1.0 - g) * fReductionMatrix2;
+
+ }
+
+ else if (has1)
+ {
+
+ *reductionMatrix = fReductionMatrix1;
+
+ }
+
+ else if (has2)
+ {
+
+ *reductionMatrix = fReductionMatrix2;
+
+ }
+
+ else
+ {
+
+ reductionMatrix->Clear ();
+
+ }
+
+ }
+
+ // Interpolate camera calibration matrix.
+
+ if (cameraCalibration)
+ {
+
+ if (g >= 1.0)
+ *cameraCalibration = fCameraCalibration1;
+
+ else if (g <= 0.0)
+ *cameraCalibration = fCameraCalibration2;
+
+ else
+ *cameraCalibration = (g ) * fCameraCalibration1 +
+ (1.0 - g) * fCameraCalibration2;
+
+ }
+
+ // Return the interpolated color matrix.
+
+ return colorMatrix;
+
+ }
+
+/*****************************************************************************/
+
+void dng_color_spec::SetWhiteXY (const dng_xy_coord &white)
+ {
+
+ fWhiteXY = white;
+
+ // Deal with monochrome cameras.
+
+ if (fChannels == 1)
+ {
+
+ fCameraWhite.SetIdentity (1);
+
+ fCameraToPCS = PCStoXYZ ().AsColumn ();
+
+ return;
+
+ }
+
+ // Interpolate an matric values for this white point.
+
+ dng_matrix colorMatrix;
+ dng_matrix forwardMatrix;
+ dng_matrix reductionMatrix;
+ dng_matrix cameraCalibration;
+
+ colorMatrix = FindXYZtoCamera (fWhiteXY,
+ &forwardMatrix,
+ &reductionMatrix,
+ &cameraCalibration);
+
+ // Find the camera white values.
+
+ fCameraWhite = colorMatrix * XYtoXYZ (fWhiteXY);
+
+ real64 whiteScale = 1.0 / MaxEntry (fCameraWhite);
+
+ for (uint32 j = 0; j < fChannels; j++)
+ {
+
+ // We don't support non-positive values for camera neutral values.
+
+ fCameraWhite [j] = Pin_real64 (0.001,
+ whiteScale * fCameraWhite [j],
+ 1.0);
+
+ }
+
+ // Find PCS to Camera transform. Scale matrix so PCS white can just be
+ // reached when the first camera channel saturates
+
+ fPCStoCamera = colorMatrix * MapWhiteMatrix (PCStoXY (), fWhiteXY);
+
+ real64 scale = MaxEntry (fPCStoCamera * PCStoXYZ ());
+
+ fPCStoCamera = (1.0 / scale) * fPCStoCamera;
+
+ // If we have a forward matrix, then just use that.
+
+ if (forwardMatrix.NotEmpty ())
+ {
+
+ dng_matrix individualToReference = Invert (fAnalogBalance * cameraCalibration);
+
+ dng_vector refCameraWhite = individualToReference * fCameraWhite;
+
+ fCameraToPCS = forwardMatrix *
+ Invert (refCameraWhite.AsDiagonal ()) *
+ individualToReference;
+
+ }
+
+ // Else we need to use the adapt in XYZ method.
+
+ else
+ {
+
+ // Invert this PCS to camera matrix. Note that if there are more than three
+ // camera channels, this inversion is non-unique.
+
+ fCameraToPCS = Invert (fPCStoCamera, reductionMatrix);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+const dng_xy_coord & dng_color_spec::WhiteXY () const
+ {
+
+ DNG_ASSERT (fWhiteXY.IsValid (), "Using invalid WhiteXY");
+
+ return fWhiteXY;
+
+ }
+
+/*****************************************************************************/
+
+const dng_vector & dng_color_spec::CameraWhite () const
+ {
+
+ DNG_ASSERT (fCameraWhite.NotEmpty (), "Using invalid CameraWhite");
+
+ return fCameraWhite;
+
+ }
+
+/*****************************************************************************/
+
+const dng_matrix & dng_color_spec::CameraToPCS () const
+ {
+
+ DNG_ASSERT (fCameraToPCS.NotEmpty (), "Using invalid CameraToPCS");
+
+ return fCameraToPCS;
+
+ }
+
+/*****************************************************************************/
+
+const dng_matrix & dng_color_spec::PCStoCamera () const
+ {
+
+ DNG_ASSERT (fPCStoCamera.NotEmpty (), "Using invalid PCStoCamera");
+
+ return fPCStoCamera;
+
+ }
+
+/*****************************************************************************/
+
+dng_xy_coord dng_color_spec::NeutralToXY (const dng_vector &neutral)
+ {
+
+ const uint32 kMaxPasses = 30;
+
+ if (fChannels == 1)
+ {
+
+ return PCStoXY ();
+
+ }
+
+ dng_xy_coord last = D50_xy_coord ();
+
+ for (uint32 pass = 0; pass < kMaxPasses; pass++)
+ {
+
+ dng_matrix xyzToCamera = FindXYZtoCamera (last);
+
+ dng_xy_coord next = XYZtoXY (Invert (xyzToCamera) * neutral);
+
+ if (Abs_real64 (next.x - last.x) +
+ Abs_real64 (next.y - last.y) < 0.0000001)
+ {
+
+ return next;
+
+ }
+
+ // If we reach the limit without converging, we are most likely
+ // in a two value oscillation. So take the average of the last
+ // two estimates and give up.
+
+ if (pass == kMaxPasses - 1)
+ {
+
+ next.x = (last.x + next.x) * 0.5;
+ next.y = (last.y + next.y) * 0.5;
+
+ }
+
+ last = next;
+
+ }
+
+ return last;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_color_spec.h b/gpr/source/lib/dng_sdk/dng_color_spec.h
new file mode 100644
index 0000000..0d06dde
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_color_spec.h
@@ -0,0 +1,146 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_color_spec.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Class for holding a specific color transform.
+*/
+
+#ifndef __dng_color_spec__
+#define __dng_color_spec__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_matrix.h"
+#include "dng_types.h"
+#include "dng_xy_coord.h"
+
+/*****************************************************************************/
+
+/// \brief Compute a 3x3 matrix which maps colors from white point white1 to
+/// white point white2
+///
+/// Uses linearized Bradford adaptation matrix to compute a mapping from
+/// colors measured with one white point (white1) to another (white2).
+
+dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1,
+ const dng_xy_coord &white2);
+
+/*****************************************************************************/
+
+/// Color transform taking into account white point and camera calibration and
+/// individual calibration from DNG negative.
+
+class dng_color_spec
+ {
+
+ private:
+
+ uint32 fChannels;
+
+ real64 fTemperature1;
+ real64 fTemperature2;
+
+ dng_matrix fColorMatrix1;
+ dng_matrix fColorMatrix2;
+
+ dng_matrix fForwardMatrix1;
+ dng_matrix fForwardMatrix2;
+
+ dng_matrix fReductionMatrix1;
+ dng_matrix fReductionMatrix2;
+
+ dng_matrix fCameraCalibration1;
+ dng_matrix fCameraCalibration2;
+
+ dng_matrix fAnalogBalance;
+
+ dng_xy_coord fWhiteXY;
+
+ dng_vector fCameraWhite;
+ dng_matrix fCameraToPCS;
+
+ dng_matrix fPCStoCamera;
+
+ public:
+
+ /// Read calibration info from DNG negative and construct a
+ /// dng_color_spec.
+
+ dng_color_spec (const dng_negative &negative,
+ const dng_camera_profile *profile);
+
+ virtual ~dng_color_spec ()
+ {
+ }
+
+ /// Number of channels used for this color transform. Three
+ /// for most cameras.
+
+ uint32 Channels () const
+ {
+ return fChannels;
+ }
+
+ /// Setter for white point. Value is as XY colorspace coordinate.
+ /// \param white White point to set as an XY value.
+
+ void SetWhiteXY (const dng_xy_coord &white);
+
+ /// Getter for white point. Value is as XY colorspace coordinate.
+ /// \retval XY value of white point.
+
+ const dng_xy_coord & WhiteXY () const;
+
+ /// Return white point in camera native color coordinates.
+ /// \retval A dng_vector with components ranging from 0.0 to 1.0
+ /// that is normalized such that one component is equal to 1.0 .
+
+ const dng_vector & CameraWhite () const;
+
+ /// Getter for camera to Profile Connection Space color transform.
+ /// \retval A transform that takes into account all camera calibration
+ /// transforms and white point.
+
+ const dng_matrix & CameraToPCS () const;
+
+ /// Getter for Profile Connection Space to camera color transform.
+ /// \retval A transform that takes into account all camera calibration
+ /// transforms and white point.
+
+ const dng_matrix & PCStoCamera () const;
+
+ /// Return the XY value to use for SetWhiteXY for a given camera color
+ /// space coordinate as the white point.
+ /// \param neutral A camera color space value to use for white point.
+ /// Components range from 0.0 to 1.0 and should be normalized such that
+ /// the largest value is 1.0 .
+ /// \retval White point in XY space that makes neutral map to this
+ /// XY value as closely as possible.
+
+ dng_xy_coord NeutralToXY (const dng_vector &neutral);
+
+ private:
+
+ dng_matrix FindXYZtoCamera (const dng_xy_coord &white,
+ dng_matrix *forwardMatrix = NULL,
+ dng_matrix *reductionMatrix = NULL,
+ dng_matrix *cameraCalibration = NULL);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_date_time.cpp b/gpr/source/lib/dng_sdk/dng_date_time.cpp
new file mode 100644
index 0000000..770d300
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_date_time.cpp
@@ -0,0 +1,961 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_date_time.cpp#2 $ */
+/* $DateTime: 2012/06/01 07:28:57 $ */
+/* $Change: 832715 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_date_time.h"
+
+#include "dng_exceptions.h"
+#include "dng_mutex.h"
+#include "dng_stream.h"
+#include "dng_string.h"
+#include "dng_utils.h"
+
+#include <time.h>
+
+#include "stdc_includes.h"
+
+#if qMacOS && qEnableCarbon
+#include <CoreServices/CoreServices.h>
+#endif
+
+#if qWinOS
+#include <windows.h>
+#endif
+
+/******************************************************************************/
+
+// MWG says don't use fake time zones in XMP, but there is some
+// old software that requires them to work correctly.
+
+bool gDNGUseFakeTimeZonesInXMP = false;
+
+/******************************************************************************/
+
+dng_date_time::dng_date_time ()
+
+ : fYear (0)
+ , fMonth (0)
+ , fDay (0)
+ , fHour (0)
+ , fMinute (0)
+ , fSecond (0)
+
+ {
+
+ }
+
+/******************************************************************************/
+
+dng_date_time::dng_date_time (uint32 year,
+ uint32 month,
+ uint32 day,
+ uint32 hour,
+ uint32 minute,
+ uint32 second)
+
+ : fYear (year)
+ , fMonth (month)
+ , fDay (day)
+ , fHour (hour)
+ , fMinute (minute)
+ , fSecond (second)
+
+ {
+
+ }
+
+/******************************************************************************/
+
+bool dng_date_time::IsValid () const
+ {
+
+ return fYear >= 1 && fYear <= 9999 &&
+ fMonth >= 1 && fMonth <= 12 &&
+ fDay >= 1 && fDay <= 31 &&
+ fHour <= 23 &&
+ fMinute <= 59 &&
+ fSecond <= 59;
+
+ }
+
+/*****************************************************************************/
+
+void dng_date_time::Clear ()
+ {
+
+ *this = dng_date_time ();
+
+ }
+
+/*****************************************************************************/
+
+static uint32 DateTimeParseU32 (const char *&s)
+ {
+
+ uint32 x = 0;
+
+ while (*s == ' ' || *s == ':')
+ s++;
+
+ while (*s >= '0' && *s <= '9')
+ {
+ x = x * 10 + (uint32) (*(s++) - '0');
+ }
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_date_time::Parse (const char *s)
+ {
+
+ fYear = DateTimeParseU32 (s);
+ fMonth = DateTimeParseU32 (s);
+ fDay = DateTimeParseU32 (s);
+ fHour = DateTimeParseU32 (s);
+ fMinute = DateTimeParseU32 (s);
+ fSecond = DateTimeParseU32 (s);
+
+ return IsValid ();
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_time_zone::Encode_ISO_8601 () const
+ {
+
+ dng_string result;
+
+ if (IsValid ())
+ {
+
+ if (OffsetMinutes () == 0)
+ {
+
+ result.Set ("Z");
+
+ }
+
+ else
+ {
+
+ char s [64];
+
+ int offset = OffsetMinutes ();
+
+ if (offset > 0)
+ {
+
+ sprintf (s, "+%02d:%02d", offset / 60, offset % 60);
+
+ }
+
+ else
+ {
+
+ offset = -offset;
+
+ sprintf (s, "-%02d:%02d", offset / 60, offset % 60);
+
+ }
+
+ result.Set (s);
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_date_time_info::dng_date_time_info ()
+
+ : fDateOnly (true)
+ , fDateTime ()
+ , fSubseconds ()
+ , fTimeZone ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_date_time_info::IsValid () const
+ {
+
+ return fDateTime.IsValid ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_date_time_info::SetDate (uint32 year,
+ uint32 month,
+ uint32 day)
+ {
+
+ fDateTime.fYear = year;
+ fDateTime.fMonth = month;
+ fDateTime.fDay = day;
+
+ }
+
+/*****************************************************************************/
+
+void dng_date_time_info::SetTime (uint32 hour,
+ uint32 minute,
+ uint32 second)
+ {
+
+ fDateOnly = false;
+
+ fDateTime.fHour = hour;
+ fDateTime.fMinute = minute;
+ fDateTime.fSecond = second;
+
+ }
+
+/*****************************************************************************/
+
+void dng_date_time_info::Decode_ISO_8601 (const char *s)
+ {
+
+ Clear ();
+
+ uint32 len = (uint32) strlen (s);
+
+ if (!len)
+ {
+ return;
+ }
+
+ unsigned year = 0;
+ unsigned month = 0;
+ unsigned day = 0;
+
+ if (sscanf (s,
+ "%u-%u-%u",
+ &year,
+ &month,
+ &day) != 3)
+ {
+ return;
+ }
+
+ SetDate ((uint32) year,
+ (uint32) month,
+ (uint32) day);
+
+ if (fDateTime.NotValid ())
+ {
+ Clear ();
+ return;
+ }
+
+ for (uint32 j = 0; j < len; j++)
+ {
+
+ if (s [j] == 'T')
+ {
+
+ unsigned hour = 0;
+ unsigned minute = 0;
+ unsigned second = 0;
+
+ int items = sscanf (s + j + 1,
+ "%u:%u:%u",
+ &hour,
+ &minute,
+ &second);
+
+ if (items >= 2 && items <= 3)
+ {
+
+ SetTime ((uint32) hour,
+ (uint32) minute,
+ (uint32) second);
+
+ if (fDateTime.NotValid ())
+ {
+ Clear ();
+ return;
+ }
+
+ if (items == 3)
+ {
+
+ for (uint32 k = j + 1; k < len; k++)
+ {
+
+ if (s [k] == '.')
+ {
+
+ while (++k < len && s [k] >= '0' && s [k] <= '9')
+ {
+
+ char ss [2];
+
+ ss [0] = s [k];
+ ss [1] = 0;
+
+ fSubseconds.Append (ss);
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ for (uint32 k = j + 1; k < len; k++)
+ {
+
+ if (s [k] == 'Z')
+ {
+
+ fTimeZone.SetOffsetMinutes (0);
+
+ break;
+
+ }
+
+ if (s [k] == '+' || s [k] == '-')
+ {
+
+ int32 sign = (s [k] == '-' ? -1 : 1);
+
+ unsigned tzhour = 0;
+ unsigned tzmin = 0;
+
+ if (sscanf (s + k + 1,
+ "%u:%u",
+ &tzhour,
+ &tzmin) > 0)
+ {
+
+ fTimeZone.SetOffsetMinutes (sign * (tzhour * 60 + tzmin));
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_date_time_info::Encode_ISO_8601 () const
+ {
+
+ dng_string result;
+
+ if (IsValid ())
+ {
+
+ char s [256];
+
+ sprintf (s,
+ "%04u-%02u-%02u",
+ (unsigned) fDateTime.fYear,
+ (unsigned) fDateTime.fMonth,
+ (unsigned) fDateTime.fDay);
+
+ result.Set (s);
+
+ if (!fDateOnly)
+ {
+
+ sprintf (s,
+ "T%02u:%02u:%02u",
+ (unsigned) fDateTime.fHour,
+ (unsigned) fDateTime.fMinute,
+ (unsigned) fDateTime.fSecond);
+
+ result.Append (s);
+
+ if (fSubseconds.NotEmpty ())
+ {
+
+ bool subsecondsValid = true;
+
+ uint32 len = fSubseconds.Length ();
+
+ for (uint32 index = 0; index < len; index++)
+ {
+
+ if (fSubseconds.Get () [index] < '0' ||
+ fSubseconds.Get () [index] > '9')
+ {
+ subsecondsValid = false;
+ break;
+ }
+
+ }
+
+ if (subsecondsValid)
+ {
+ result.Append (".");
+ result.Append (fSubseconds.Get ());
+ }
+
+ }
+
+ if (gDNGUseFakeTimeZonesInXMP)
+ {
+
+ // Kludge: Early versions of the XMP toolkit assume Zulu time
+ // if the time zone is missing. It is safer for fill in the
+ // local time zone.
+
+ dng_time_zone tempZone = fTimeZone;
+
+ if (tempZone.NotValid ())
+ {
+ tempZone = LocalTimeZone (fDateTime);
+ }
+
+ result.Append (tempZone.Encode_ISO_8601 ().Get ());
+
+ }
+
+ else
+ {
+
+ // MWG: Now we don't fill in the local time zone. So only
+ // add the time zone if it is known and valid.
+
+ if (fTimeZone.IsValid ())
+ {
+ result.Append (fTimeZone.Encode_ISO_8601 ().Get ());
+ }
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_date_time_info::Decode_IPTC_Date (const char *s)
+ {
+
+ if (strlen (s) == 8)
+ {
+
+ unsigned year = 0;
+ unsigned month = 0;
+ unsigned day = 0;
+
+ if (sscanf (s,
+ "%4u%2u%2u",
+ &year,
+ &month,
+ &day) == 3)
+ {
+
+ SetDate ((uint32) year,
+ (uint32) month,
+ (uint32) day);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_date_time_info::Encode_IPTC_Date () const
+ {
+
+ dng_string result;
+
+ if (IsValid ())
+ {
+
+ char s [64];
+
+ sprintf (s,
+ "%04u%02u%02u",
+ (unsigned) fDateTime.fYear,
+ (unsigned) fDateTime.fMonth,
+ (unsigned) fDateTime.fDay);
+
+ result.Set (s);
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_date_time_info::Decode_IPTC_Time (const char *s)
+ {
+
+ if (strlen (s) == 11)
+ {
+
+ char time [12];
+
+ memcpy (time, s, sizeof (time));
+
+ if (time [6] == '+' ||
+ time [6] == '-')
+ {
+
+ int tzsign = (time [6] == '-') ? -1 : 1;
+
+ time [6] = 0;
+
+ unsigned hour = 0;
+ unsigned minute = 0;
+ unsigned second = 0;
+ unsigned tzhour = 0;
+ unsigned tzmin = 0;
+
+ if (sscanf (time,
+ "%2u%2u%2u",
+ &hour,
+ &minute,
+ &second) == 3 &&
+ sscanf (time + 7,
+ "%2u%2u",
+ &tzhour,
+ &tzmin) == 2)
+ {
+
+ dng_time_zone zone;
+
+ zone.SetOffsetMinutes (tzsign * (tzhour * 60 + tzmin));
+
+ if (zone.IsValid ())
+ {
+
+ SetTime ((uint32) hour,
+ (uint32) minute,
+ (uint32) second);
+
+ SetZone (zone);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ else if (strlen (s) == 6)
+ {
+
+ unsigned hour = 0;
+ unsigned minute = 0;
+ unsigned second = 0;
+
+ if (sscanf (s,
+ "%2u%2u%2u",
+ &hour,
+ &minute,
+ &second) == 3)
+ {
+
+ SetTime ((uint32) hour,
+ (uint32) minute,
+ (uint32) second);
+
+ }
+
+ }
+
+ else if (strlen (s) == 4)
+ {
+
+ unsigned hour = 0;
+ unsigned minute = 0;
+
+ if (sscanf (s,
+ "%2u%2u",
+ &hour,
+ &minute) == 2)
+ {
+
+ SetTime ((uint32) hour,
+ (uint32) minute,
+ 0);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_date_time_info::Encode_IPTC_Time () const
+ {
+
+ dng_string result;
+
+ if (IsValid () && !fDateOnly)
+ {
+
+ char s [64];
+
+ if (fTimeZone.IsValid ())
+ {
+
+ sprintf (s,
+ "%02u%02u%02u%c%02u%02u",
+ (unsigned) fDateTime.fHour,
+ (unsigned) fDateTime.fMinute,
+ (unsigned) fDateTime.fSecond,
+ (int) (fTimeZone.OffsetMinutes () >= 0 ? '+' : '-'),
+ (unsigned) (Abs_int32 (fTimeZone.OffsetMinutes ()) / 60),
+ (unsigned) (Abs_int32 (fTimeZone.OffsetMinutes ()) % 60));
+
+ }
+
+ else
+ {
+
+ sprintf (s,
+ "%02u%02u%02u",
+ (unsigned) fDateTime.fHour,
+ (unsigned) fDateTime.fMinute,
+ (unsigned) fDateTime.fSecond);
+
+ }
+
+ result.Set (s);
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+static dng_mutex gDateTimeMutex ("gDateTimeMutex");
+
+/*****************************************************************************/
+
+void CurrentDateTimeAndZone (dng_date_time_info &info)
+ {
+
+ time_t sec;
+
+ time (&sec);
+
+ tm t;
+ tm zt;
+
+ {
+
+ dng_lock_mutex lock (&gDateTimeMutex);
+
+ t = *localtime (&sec);
+ zt = *gmtime (&sec);
+
+ }
+
+ dng_date_time dt;
+
+ dt.fYear = t.tm_year + 1900;
+ dt.fMonth = t.tm_mon + 1;
+ dt.fDay = t.tm_mday;
+ dt.fHour = t.tm_hour;
+ dt.fMinute = t.tm_min;
+ dt.fSecond = t.tm_sec;
+
+ info.SetDateTime (dt);
+
+ int tzHour = t.tm_hour - zt.tm_hour;
+ int tzMin = t.tm_min - zt.tm_min;
+
+ bool zonePositive = (t.tm_year > zt.tm_year) ||
+ (t.tm_year == zt.tm_year && t.tm_yday > zt.tm_yday) ||
+ (t.tm_year == zt.tm_year && t.tm_yday == zt.tm_yday && tzHour > 0) ||
+ (t.tm_year == zt.tm_year && t.tm_yday == zt.tm_yday && tzHour == 0 && tzMin >= 0);
+
+ tzMin += tzHour * 60;
+
+ if (zonePositive)
+ {
+
+ while (tzMin < 0)
+ tzMin += 24 * 60;
+
+ }
+
+ else
+ {
+
+ while (tzMin > 0)
+ tzMin -= 24 * 60;
+
+ }
+
+ dng_time_zone zone;
+
+ zone.SetOffsetMinutes (tzMin);
+
+ info.SetZone (zone);
+
+ }
+
+/*****************************************************************************/
+
+void DecodeUnixTime (uint32 unixTime, dng_date_time &dt)
+ {
+
+ time_t sec = (time_t) unixTime;
+
+ tm t;
+
+ {
+
+ dng_lock_mutex lock (&gDateTimeMutex);
+
+ #if qMacOS && !defined(__MACH__)
+
+ // Macintosh CFM stores time in local time zone.
+
+ tm *tp = localtime (&sec);
+
+ #else
+
+ // Macintosh Mach-O and Windows stores time in Zulu time.
+
+ tm *tp = gmtime (&sec);
+
+ #endif
+
+ if (!tp)
+ {
+ dt.Clear ();
+ return;
+ }
+
+ t = *tp;
+
+ }
+
+ dt.fYear = t.tm_year + 1900;
+ dt.fMonth = t.tm_mon + 1;
+ dt.fDay = t.tm_mday;
+ dt.fHour = t.tm_hour;
+ dt.fMinute = t.tm_min;
+ dt.fSecond = t.tm_sec;
+
+ }
+
+/*****************************************************************************/
+
+dng_time_zone LocalTimeZone (const dng_date_time &dt)
+ {
+
+ dng_time_zone result;
+
+ if (dt.IsValid ())
+ {
+
+ #if qMacOS && qEnableCarbon
+
+ CFTimeZoneRef zoneRef = CFTimeZoneCopyDefault ();
+
+ if (zoneRef)
+ {
+
+ CFGregorianDate gregDate;
+
+ gregDate.year = dt.fYear;
+ gregDate.month = (SInt8) dt.fMonth;
+ gregDate.day = (SInt8) dt.fDay;
+ gregDate.hour = (SInt8) dt.fHour;
+ gregDate.minute = (SInt8) dt.fMinute;
+ gregDate.second = (SInt8) dt.fSecond;
+
+ CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime (gregDate, zoneRef);
+
+ CFTimeInterval secondsDelta = CFTimeZoneGetSecondsFromGMT (zoneRef, absTime);
+
+ CFRelease (zoneRef);
+
+ result.SetOffsetSeconds (Round_int32 (secondsDelta));
+
+ if (result.IsValid ())
+ {
+ return result;
+ }
+
+ }
+
+ #endif
+
+ #if qWinOS
+
+ if (GetTimeZoneInformation != NULL &&
+ SystemTimeToTzSpecificLocalTime != NULL &&
+ SystemTimeToFileTime != NULL)
+ {
+
+ TIME_ZONE_INFORMATION tzInfo;
+
+ DWORD x = GetTimeZoneInformation (&tzInfo);
+
+ SYSTEMTIME localST;
+
+ memset (&localST, 0, sizeof (localST));
+
+ localST.wYear = (WORD) dt.fYear;
+ localST.wMonth = (WORD) dt.fMonth;
+ localST.wDay = (WORD) dt.fDay;
+ localST.wHour = (WORD) dt.fHour;
+ localST.wMinute = (WORD) dt.fMinute;
+ localST.wSecond = (WORD) dt.fSecond;
+
+ SYSTEMTIME utcST;
+
+ if (TzSpecificLocalTimeToSystemTime (&tzInfo, &localST, &utcST))
+ {
+
+ FILETIME localFT;
+ FILETIME utcFT;
+
+ (void) SystemTimeToFileTime (&localST, &localFT);
+ (void) SystemTimeToFileTime (&utcST , &utcFT );
+
+ uint64 time1 = (((uint64) localFT.dwHighDateTime) << 32) + localFT.dwLowDateTime;
+ uint64 time2 = (((uint64) utcFT .dwHighDateTime) << 32) + utcFT .dwLowDateTime;
+
+ // FILETIMEs are in units to 100 ns. Convert to seconds.
+
+ int64 time1Sec = time1 / 10000000;
+ int64 time2Sec = time2 / 10000000;
+
+ int32 delta = (int32) (time1Sec - time2Sec);
+
+ result.SetOffsetSeconds (delta);
+
+ if (result.IsValid ())
+ {
+ return result;
+ }
+
+ }
+
+ }
+
+ #endif
+
+ }
+
+ // Figure out local time zone.
+
+ dng_date_time_info current_info;
+
+ CurrentDateTimeAndZone (current_info);
+
+ result = current_info.TimeZone ();
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_date_time_storage_info::dng_date_time_storage_info ()
+
+ : fOffset (kDNGStreamInvalidOffset )
+ , fFormat (dng_date_time_format_unknown)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_date_time_storage_info::dng_date_time_storage_info (uint64 offset,
+ dng_date_time_format format)
+
+ : fOffset (offset)
+ , fFormat (format)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_date_time_storage_info::IsValid () const
+ {
+
+ return fOffset != kDNGStreamInvalidOffset;
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_date_time_storage_info::Offset () const
+ {
+
+ if (!IsValid ())
+ ThrowProgramError ();
+
+ return fOffset;
+
+ }
+
+/*****************************************************************************/
+
+dng_date_time_format dng_date_time_storage_info::Format () const
+ {
+
+ if (!IsValid ())
+ ThrowProgramError ();
+
+ return fFormat;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_date_time.h b/gpr/source/lib/dng_sdk/dng_date_time.h
new file mode 100644
index 0000000..3f923f2
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_date_time.h
@@ -0,0 +1,385 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_date_time.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Functions and classes for working with dates and times in DNG files.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_date_time__
+#define __dng_date_time__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_string.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Class for holding a date/time and converting to and from relevant
+/// date/time formats
+
+class dng_date_time
+ {
+
+ public:
+
+ uint32 fYear;
+ uint32 fMonth;
+ uint32 fDay;
+ uint32 fHour;
+ uint32 fMinute;
+ uint32 fSecond;
+
+ public:
+
+ /// Construct an invalid date/time
+
+ dng_date_time ();
+
+ /// Construct a date/time with specific values.
+ /// \param year Year to use as actual integer value, such as 2006.
+ /// \param month Month to use from 1 - 12, where 1 is January.
+ /// \param day Day of month to use from 1 -31, where 1 is the first.
+ /// \param hour Hour of day to use from 0 - 23, where 0 is midnight.
+ /// \param minute Minute of hour to use from 0 - 59.
+ /// \param second Second of minute to use from 0 - 59.
+
+ dng_date_time (uint32 year,
+ uint32 month,
+ uint32 day,
+ uint32 hour,
+ uint32 minute,
+ uint32 second);
+
+ /// Predicate to determine if a date is valid.
+ /// \retval true if all fields are within range.
+
+ bool IsValid () const;
+
+ /// Predicate to determine if a date is invalid.
+ /// \retval true if any field is out of range.
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ /// Equal operator.
+
+ bool operator== (const dng_date_time &dt) const
+ {
+ return fYear == dt.fYear &&
+ fMonth == dt.fMonth &&
+ fDay == dt.fDay &&
+ fHour == dt.fHour &&
+ fMinute == dt.fMinute &&
+ fSecond == dt.fSecond;
+ }
+
+ // Not-equal operator.
+
+ bool operator!= (const dng_date_time &dt) const
+ {
+ return !(*this == dt);
+ }
+
+ /// Set date to an invalid value.
+
+ void Clear ();
+
+ /// Parse an EXIF format date string.
+ /// \param s Input date string to parse.
+ /// \retval true if date was parsed successfully and date is valid.
+
+ bool Parse (const char *s);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class for holding a time zone.
+
+class dng_time_zone
+ {
+
+ private:
+
+ enum
+ {
+
+ kMaxOffsetHours = 15,
+ kMinOffsetHours = -kMaxOffsetHours,
+
+ kMaxOffsetMinutes = kMaxOffsetHours * 60,
+ kMinOffsetMinutes = kMinOffsetHours * 60,
+
+ kInvalidOffset = kMinOffsetMinutes - 1
+
+ };
+
+ // Offset from GMT in minutes. Positive numbers are
+ // ahead of GMT, negative number are behind GMT.
+
+ int32 fOffsetMinutes;
+
+ public:
+
+ dng_time_zone ()
+ : fOffsetMinutes (kInvalidOffset)
+ {
+ }
+
+ void Clear ()
+ {
+ fOffsetMinutes = kInvalidOffset;
+ }
+
+ void SetOffsetHours (int32 offset)
+ {
+ fOffsetMinutes = offset * 60;
+ }
+
+ void SetOffsetMinutes (int32 offset)
+ {
+ fOffsetMinutes = offset;
+ }
+
+ void SetOffsetSeconds (int32 offset)
+ {
+ fOffsetMinutes = (offset > 0) ? ((offset + 30) / 60)
+ : ((offset - 30) / 60);
+ }
+
+ bool IsValid () const
+ {
+ return fOffsetMinutes >= kMinOffsetMinutes &&
+ fOffsetMinutes <= kMaxOffsetMinutes;
+ }
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ int32 OffsetMinutes () const
+ {
+ return fOffsetMinutes;
+ }
+
+ bool IsExactHourOffset () const
+ {
+ return IsValid () && ((fOffsetMinutes % 60) == 0);
+ }
+
+ int32 ExactHourOffset () const
+ {
+ return fOffsetMinutes / 60;
+ }
+
+ dng_string Encode_ISO_8601 () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class for holding complete data/time/zone information.
+
+class dng_date_time_info
+ {
+
+ private:
+
+ // Is only the date valid and not the time?
+
+ bool fDateOnly;
+
+ // Date and time.
+
+ dng_date_time fDateTime;
+
+ // Subseconds string (stored in a separate tag in EXIF).
+
+ dng_string fSubseconds;
+
+ // Time zone, if known.
+
+ dng_time_zone fTimeZone;
+
+ public:
+
+ dng_date_time_info ();
+
+ bool IsValid () const;
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ void Clear ()
+ {
+ *this = dng_date_time_info ();
+ }
+
+ const dng_date_time & DateTime () const
+ {
+ return fDateTime;
+ }
+
+ void SetDateTime (const dng_date_time &dt)
+ {
+ fDateOnly = false;
+ fDateTime = dt;
+ }
+
+ const dng_string & Subseconds () const
+ {
+ return fSubseconds;
+ }
+
+ void SetSubseconds (const dng_string &s)
+ {
+ fSubseconds = s;
+ }
+
+ const dng_time_zone & TimeZone () const
+ {
+ return fTimeZone;
+ }
+
+ void SetZone (const dng_time_zone &zone)
+ {
+ fTimeZone = zone;
+ }
+
+ void Decode_ISO_8601 (const char *s);
+
+ dng_string Encode_ISO_8601 () const;
+
+ void Decode_IPTC_Date (const char *s);
+
+ dng_string Encode_IPTC_Date () const;
+
+ void Decode_IPTC_Time (const char *s);
+
+ dng_string Encode_IPTC_Time () const;
+
+ private:
+
+ void SetDate (uint32 year,
+ uint32 month,
+ uint32 day);
+
+ void SetTime (uint32 hour,
+ uint32 minute,
+ uint32 second);
+
+ };
+
+/*****************************************************************************/
+
+/// Get the current date/time and timezone.
+/// \param info Receives current data/time/zone.
+
+void CurrentDateTimeAndZone (dng_date_time_info &info);
+
+/*****************************************************************************/
+
+/// Convert UNIX "seconds since Jan 1, 1970" time to a dng_date_time
+
+void DecodeUnixTime (uint32 unixTime, dng_date_time &dt);
+
+/*****************************************************************************/
+
+/// Return timezone of current location at a given date.
+/// \param dt Date at which to compute timezone difference. (For example, used
+/// to determine Daylight Savings, etc.)
+/// \retval Time zone for date/time dt.
+
+dng_time_zone LocalTimeZone (const dng_date_time &dt);
+
+/*****************************************************************************/
+
+/// Tag to encode date represenation format
+
+enum dng_date_time_format
+ {
+ dng_date_time_format_unknown = 0, /// Date format not known
+ dng_date_time_format_exif = 1, /// EXIF date string
+ dng_date_time_format_unix_little_endian = 2, /// 32-bit UNIX time as 4-byte little endian
+ dng_date_time_format_unix_big_endian = 3 /// 32-bit UNIX time as 4-byte big endian
+ };
+
+/*****************************************************************************/
+
+/// \brief Store file offset from which date was read.
+///
+/// Used internally by Adobe to update date in original file.
+/// \warning Use at your own risk.
+
+class dng_date_time_storage_info
+ {
+
+ private:
+
+ uint64 fOffset;
+
+ dng_date_time_format fFormat;
+
+ public:
+
+ /// The default constructor initializes to an invalid state.
+
+ dng_date_time_storage_info ();
+
+ /// Construct with file offset and date format.
+
+ dng_date_time_storage_info (uint64 offset,
+ dng_date_time_format format);
+
+ /// Predicate to determine if an offset is valid.
+ /// \retval true if offset is valid.
+
+ bool IsValid () const;
+
+ // The accessors throw if the data is not valid.
+
+ /// Getter for offset in file.
+ /// \exception dng_exception with fErrorCode equal to dng_error_unknown
+ /// if offset is not valid.
+
+ uint64 Offset () const;
+
+ /// Get for format date was originally stored in file. Throws a
+ /// dng_error_unknown exception if offset is invalid.
+ /// \exception dng_exception with fErrorCode equal to dng_error_unknown
+ /// if offset is not valid.
+
+ dng_date_time_format Format () const;
+
+ };
+
+/*****************************************************************************/
+
+// Kludge: Global boolean to turn on fake time zones in XMP for old software.
+
+extern bool gDNGUseFakeTimeZonesInXMP;
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_errors.h b/gpr/source/lib/dng_sdk/dng_errors.h
new file mode 100644
index 0000000..44feb5a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_errors.h
@@ -0,0 +1,58 @@
+/*****************************************************************************/
+// Copyright 2006-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_errors.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Error code values.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_errors__
+#define __dng_errors__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// Type for all errors used in DNG SDK. Generally held inside a dng_exception.
+
+typedef int32 dng_error_code;
+
+enum
+ {
+ dng_error_none = 0, //!< No error. Success.
+ dng_error_unknown = 100000, //!< Logic or program error or other unclassifiable error.
+ dng_error_not_yet_implemented, //!< Functionality requested is not yet implemented.
+ dng_error_silent, //!< An error which should not be signalled to user.
+ dng_error_user_canceled, //!< Processing stopped by user (or host application) request
+ dng_error_host_insufficient, //!< Necessary host functionality is not present.
+ dng_error_memory, //!< Out of memory.
+ dng_error_bad_format, //!< File format is not valid.
+ dng_error_matrix_math, //!< Matrix has wrong shape, is badly conditioned, or similar problem.
+ dng_error_open_file, //!< Could not open file.
+ dng_error_read_file, //!< Error reading file.
+ dng_error_write_file, //!< Error writing file.
+ dng_error_end_of_file, //!< Unexpected end of file.
+ dng_error_file_is_damaged, //!< File is damaged in some way.
+ dng_error_image_too_big_dng, //!< Image is too big to save as DNG.
+ dng_error_image_too_big_tiff, //!< Image is too big to save as TIFF.
+ dng_error_unsupported_dng //!< DNG version is unsupported.
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_exceptions.cpp b/gpr/source/lib/dng_sdk/dng_exceptions.cpp
new file mode 100644
index 0000000..6ca4ece
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_exceptions.cpp
@@ -0,0 +1,205 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_exceptions.cpp#2 $ */
+/* $DateTime: 2012/06/06 12:08:58 $ */
+/* $Change: 833617 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_exceptions.h"
+
+#include "dng_flags.h"
+#include "dng_globals.h"
+
+/*****************************************************************************/
+
+#ifndef qDNGReportErrors
+// assuming this isn't enable on Win, because it's using printf, but an app can redirect that to console
+#define qDNGReportErrors ((qDNGDebug && qMacOS) || qDNGValidate)
+#endif
+
+/*****************************************************************************/
+
+void ReportWarning (const char *message,
+ const char *sub_message)
+ {
+
+
+ #if qDNGReportErrors
+
+ if (sub_message)
+ fprintf (stderr, "*** Warning: %s (%s) ***\n", message, sub_message);
+ else
+ fprintf (stderr, "*** Warning: %s ***\n", message);
+
+ #else
+
+ (void) message;
+ (void) sub_message;
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void ReportError (const char *message,
+ const char *sub_message)
+ {
+
+ #if qDNGReportErrors
+
+ if (sub_message)
+ fprintf (stderr, "*** Error: %s (%s) ***\n", message, sub_message);
+ else
+ fprintf (stderr, "*** Error: %s ***\n", message);
+
+ #else
+
+ (void) message;
+ (void) sub_message;
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void Throw_dng_error (dng_error_code err,
+ const char *message,
+ const char *sub_message,
+ bool silent)
+ {
+
+ #if qDNGReportErrors
+
+ {
+
+ if (!message)
+ {
+
+ switch (err)
+ {
+
+ case dng_error_none:
+ case dng_error_silent:
+ case dng_error_user_canceled:
+ {
+ break;
+ }
+
+ case dng_error_not_yet_implemented:
+ {
+ message = "Not yet implemented";
+ break;
+ }
+
+ case dng_error_host_insufficient:
+ {
+ message = "Host insufficient";
+ break;
+ }
+
+ case dng_error_memory:
+ {
+ message = "Unable to allocate memory";
+ break;
+ }
+
+ case dng_error_bad_format:
+ {
+ message = "File format is invalid";
+ break;
+ }
+
+ case dng_error_matrix_math:
+ {
+ message = "Matrix math error";
+ break;
+ }
+
+ case dng_error_open_file:
+ {
+ message = "Unable to open file";
+ break;
+ }
+
+ case dng_error_read_file:
+ {
+ message = "File read error";
+ break;
+ }
+
+ case dng_error_write_file:
+ {
+ message = "File write error";
+ break;
+ }
+
+ case dng_error_end_of_file:
+ {
+ message = "Unexpected end-of-file";
+ break;
+ }
+
+ case dng_error_file_is_damaged:
+ {
+ message = "File is damaged";
+ break;
+ }
+
+ case dng_error_image_too_big_dng:
+ {
+ message = "Image is too big to save as DNG";
+ break;
+ }
+
+ case dng_error_image_too_big_tiff:
+ {
+ message = "Image is too big to save as TIFF";
+ break;
+ }
+
+ case dng_error_unsupported_dng:
+ {
+ message = "DNG version is unsupported";
+ break;
+ }
+
+ default:
+ {
+ message = "Unknown error";
+ break;
+ }
+
+ }
+
+ }
+
+ if (message && !silent)
+ {
+ ReportError (message, sub_message);
+ }
+
+ }
+
+ #else
+
+ (void) message;
+ (void) sub_message;
+ (void) silent;
+
+ #endif
+
+ throw dng_exception (err);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_exceptions.h b/gpr/source/lib/dng_sdk/dng_exceptions.h
new file mode 100644
index 0000000..7bfb1cd
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_exceptions.h
@@ -0,0 +1,301 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_exceptions.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * C++ exception support for DNG SDK.
+*/
+
+/*****************************************************************************/
+
+#ifndef __dng_exceptions__
+#define __dng_exceptions__
+
+/*****************************************************************************/
+
+#include "dng_errors.h"
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+/// Display a warning message. Note that this may just eat the message.
+
+void ReportWarning (const char *message,
+ const char *sub_message = NULL);
+
+/*****************************************************************************/
+
+/// Display an error message. Note that this may just eat the message.
+
+void ReportError (const char *message,
+ const char *sub_message = NULL);
+
+/*****************************************************************************/
+
+/// \brief All exceptions thrown by the DNG SDK use this exception class.
+
+class dng_exception
+ {
+
+ private:
+
+ dng_error_code fErrorCode;
+
+ public:
+
+ /// Construct an exception representing the given error code.
+ /// \param code Error code this exception is for.
+
+ dng_exception (dng_error_code code)
+
+ : fErrorCode (code)
+
+ {
+ }
+
+ virtual ~dng_exception ()
+ {
+ }
+
+ /// Getter for error code of this exception
+ /// \retval The error code of this exception.
+
+ dng_error_code ErrorCode () const
+ {
+ return fErrorCode;
+ }
+
+ };
+
+/******************************************************************************/
+
+/// \brief Throw an exception based on an arbitrary error code.
+
+void Throw_dng_error (dng_error_code err,
+ const char * message = NULL,
+ const char * sub_message = NULL,
+ bool silent = false);
+
+/******************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code if
+/// error_code is not dng_error_none .
+
+inline void Fail_dng_error (dng_error_code err)
+ {
+
+ if (err != dng_error_none)
+ {
+
+ Throw_dng_error (err);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_unknown .
+
+inline void ThrowProgramError (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_unknown, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_not_yet_implemented .
+
+inline void ThrowNotYetImplemented (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_not_yet_implemented, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_silent .
+
+inline void ThrowSilentError ()
+ {
+
+ Throw_dng_error (dng_error_silent);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_user_canceled .
+
+inline void ThrowUserCanceled ()
+ {
+
+ Throw_dng_error (dng_error_user_canceled);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_host_insufficient .
+
+inline void ThrowHostInsufficient (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_host_insufficient, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_memory .
+
+inline void ThrowMemoryFull (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_memory, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_bad_format .
+
+inline void ThrowBadFormat (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_bad_format, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_matrix_math .
+
+inline void ThrowMatrixMath (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_matrix_math, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_open_file .
+
+inline void ThrowOpenFile (const char * sub_message = NULL, bool silent = false)
+ {
+
+ Throw_dng_error (dng_error_open_file, NULL, sub_message, silent);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_read_file .
+
+inline void ThrowReadFile (const char *sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_read_file, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_write_file .
+
+inline void ThrowWriteFile (const char *sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_write_file, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_end_of_file .
+
+inline void ThrowEndOfFile (const char *sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_end_of_file, NULL, sub_message);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_file_is_damaged .
+
+inline void ThrowFileIsDamaged ()
+ {
+
+ Throw_dng_error (dng_error_file_is_damaged);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_image_too_big_dng .
+
+inline void ThrowImageTooBigDNG ()
+ {
+
+ Throw_dng_error (dng_error_image_too_big_dng);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_image_too_big_tiff .
+
+inline void ThrowImageTooBigTIFF ()
+ {
+
+ Throw_dng_error (dng_error_image_too_big_tiff);
+
+ }
+
+/*****************************************************************************/
+
+/// \brief Convenience function to throw dng_exception with error code
+/// dng_error_unsupported_dng .
+
+inline void ThrowUnsupportedDNG ()
+ {
+
+ Throw_dng_error (dng_error_unsupported_dng);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_exif.cpp b/gpr/source/lib/dng_sdk/dng_exif.cpp
new file mode 100644
index 0000000..294557d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_exif.cpp
@@ -0,0 +1,4381 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_exif.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_exif.h"
+
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_parse_utils.h"
+#include "dng_globals.h"
+#include "dng_exceptions.h"
+#include "dng_tag_values.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_exif::dng_exif ()
+
+ : fImageDescription ()
+ , fMake ()
+ , fModel ()
+ , fSoftware ()
+ , fArtist ()
+ , fCopyright ()
+ , fCopyright2 ()
+ , fUserComment ()
+
+ , fDateTime ()
+ , fDateTimeStorageInfo ()
+
+ , fDateTimeOriginal ()
+ , fDateTimeOriginalStorageInfo ()
+
+ , fDateTimeDigitized ()
+ , fDateTimeDigitizedStorageInfo ()
+
+ , fTIFF_EP_StandardID (0)
+ , fExifVersion (0)
+ , fFlashPixVersion (0)
+
+ , fExposureTime ()
+ , fFNumber ()
+ , fShutterSpeedValue ()
+ , fApertureValue ()
+ , fBrightnessValue ()
+ , fExposureBiasValue ()
+ , fMaxApertureValue ()
+ , fFocalLength ()
+ , fDigitalZoomRatio ()
+ , fExposureIndex ()
+ , fSubjectDistance ()
+ , fGamma ()
+
+ , fBatteryLevelR ()
+ , fBatteryLevelA ()
+
+ , fExposureProgram (0xFFFFFFFF)
+ , fMeteringMode (0xFFFFFFFF)
+ , fLightSource (0xFFFFFFFF)
+ , fFlash (0xFFFFFFFF)
+ , fFlashMask (0x0000FFFF)
+ , fSensingMethod (0xFFFFFFFF)
+ , fColorSpace (0xFFFFFFFF)
+ , fFileSource (0xFFFFFFFF)
+ , fSceneType (0xFFFFFFFF)
+ , fCustomRendered (0xFFFFFFFF)
+ , fExposureMode (0xFFFFFFFF)
+ , fWhiteBalance (0xFFFFFFFF)
+ , fSceneCaptureType (0xFFFFFFFF)
+ , fGainControl (0xFFFFFFFF)
+ , fContrast (0xFFFFFFFF)
+ , fSaturation (0xFFFFFFFF)
+ , fSharpness (0xFFFFFFFF)
+ , fSubjectDistanceRange (0xFFFFFFFF)
+ , fSelfTimerMode (0xFFFFFFFF)
+ , fImageNumber (0xFFFFFFFF)
+
+ , fFocalLengthIn35mmFilm (0)
+
+ , fSensitivityType (0)
+ , fStandardOutputSensitivity (0)
+ , fRecommendedExposureIndex (0)
+ , fISOSpeed (0)
+ , fISOSpeedLatitudeyyy (0)
+ , fISOSpeedLatitudezzz (0)
+
+ , fSubjectAreaCount (0)
+
+ , fComponentsConfiguration (0)
+
+ , fCompresssedBitsPerPixel ()
+
+ , fPixelXDimension (0)
+ , fPixelYDimension (0)
+
+ , fFocalPlaneXResolution ()
+ , fFocalPlaneYResolution ()
+
+ , fFocalPlaneResolutionUnit (0xFFFFFFFF)
+
+ , fCFARepeatPatternRows (0)
+ , fCFARepeatPatternCols (0)
+
+ , fImageUniqueID ()
+
+ , fGPSVersionID (0)
+ , fGPSLatitudeRef ()
+ , fGPSLongitudeRef ()
+ , fGPSAltitudeRef (0xFFFFFFFF)
+ , fGPSAltitude ()
+ , fGPSSatellites ()
+ , fGPSStatus ()
+ , fGPSMeasureMode ()
+ , fGPSDOP ()
+ , fGPSSpeedRef ()
+ , fGPSSpeed ()
+ , fGPSTrackRef ()
+ , fGPSTrack ()
+ , fGPSImgDirectionRef ()
+ , fGPSImgDirection ()
+ , fGPSMapDatum ()
+ , fGPSDestLatitudeRef ()
+ , fGPSDestLongitudeRef ()
+ , fGPSDestBearingRef ()
+ , fGPSDestBearing ()
+ , fGPSDestDistanceRef ()
+ , fGPSDestDistance ()
+ , fGPSProcessingMethod ()
+ , fGPSAreaInformation ()
+ , fGPSDateStamp ()
+ , fGPSDifferential (0xFFFFFFFF)
+ , fGPSHPositioningError ()
+
+ , fInteroperabilityIndex ()
+
+ , fInteroperabilityVersion (0)
+
+ , fRelatedImageFileFormat ()
+
+ , fRelatedImageWidth (0)
+ , fRelatedImageLength (0)
+
+ , fCameraSerialNumber ()
+
+ , fLensID ()
+ , fLensMake ()
+ , fLensName ()
+ , fLensSerialNumber ()
+
+ , fLensNameWasReadFromExif (false)
+
+ , fApproxFocusDistance ()
+
+ , fFlashCompensation ()
+
+ , fOwnerName ()
+ , fFirmware ()
+
+ {
+
+ uint32 j;
+ uint32 k;
+
+ fISOSpeedRatings [0] = 0;
+ fISOSpeedRatings [1] = 0;
+ fISOSpeedRatings [2] = 0;
+
+ for (j = 0; j < kMaxCFAPattern; j++)
+ for (k = 0; k < kMaxCFAPattern; k++)
+ {
+ fCFAPattern [j] [k] = 255;
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_exif::~dng_exif ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_exif * dng_exif::Clone () const
+ {
+
+ dng_exif *result = new dng_exif (*this);
+
+ if (!result)
+ {
+ ThrowMemoryFull ();
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::SetEmpty ()
+ {
+
+ *this = dng_exif ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::CopyGPSFrom (const dng_exif &exif)
+ {
+
+ fGPSVersionID = exif.fGPSVersionID;
+ fGPSLatitudeRef = exif.fGPSLatitudeRef;
+ fGPSLatitude [0] = exif.fGPSLatitude [0];
+ fGPSLatitude [1] = exif.fGPSLatitude [1];
+ fGPSLatitude [2] = exif.fGPSLatitude [2];
+ fGPSLongitudeRef = exif.fGPSLongitudeRef;
+ fGPSLongitude [0] = exif.fGPSLongitude [0];
+ fGPSLongitude [1] = exif.fGPSLongitude [1];
+ fGPSLongitude [2] = exif.fGPSLongitude [2];
+ fGPSAltitudeRef = exif.fGPSAltitudeRef;
+ fGPSAltitude = exif.fGPSAltitude;
+ fGPSTimeStamp [0] = exif.fGPSTimeStamp [0];
+ fGPSTimeStamp [1] = exif.fGPSTimeStamp [1];
+ fGPSTimeStamp [2] = exif.fGPSTimeStamp [2];
+ fGPSSatellites = exif.fGPSSatellites;
+ fGPSStatus = exif.fGPSStatus;
+ fGPSMeasureMode = exif.fGPSMeasureMode;
+ fGPSDOP = exif.fGPSDOP;
+ fGPSSpeedRef = exif.fGPSSpeedRef;
+ fGPSSpeed = exif.fGPSSpeed;
+ fGPSTrackRef = exif.fGPSTrackRef;
+ fGPSTrack = exif.fGPSTrack;
+ fGPSImgDirectionRef = exif.fGPSImgDirectionRef;
+ fGPSImgDirection = exif.fGPSImgDirection;
+ fGPSMapDatum = exif.fGPSMapDatum;
+ fGPSDestLatitudeRef = exif.fGPSDestLatitudeRef;
+ fGPSDestLatitude [0] = exif.fGPSDestLatitude [0];
+ fGPSDestLatitude [1] = exif.fGPSDestLatitude [1];
+ fGPSDestLatitude [2] = exif.fGPSDestLatitude [2];
+ fGPSDestLongitudeRef = exif.fGPSDestLongitudeRef;
+ fGPSDestLongitude [0] = exif.fGPSDestLongitude [0];
+ fGPSDestLongitude [1] = exif.fGPSDestLongitude [1];
+ fGPSDestLongitude [2] = exif.fGPSDestLongitude [2];
+ fGPSDestBearingRef = exif.fGPSDestBearingRef;
+ fGPSDestBearing = exif.fGPSDestBearing;
+ fGPSDestDistanceRef = exif.fGPSDestDistanceRef;
+ fGPSDestDistance = exif.fGPSDestDistance;
+ fGPSProcessingMethod = exif.fGPSProcessingMethod;
+ fGPSAreaInformation = exif.fGPSAreaInformation;
+ fGPSDateStamp = exif.fGPSDateStamp;
+ fGPSDifferential = exif.fGPSDifferential;
+ fGPSHPositioningError = exif.fGPSHPositioningError;
+
+ }
+
+/*****************************************************************************/
+
+// Fix up common errors and rounding issues with EXIF exposure times.
+
+real64 dng_exif::SnapExposureTime (real64 et)
+ {
+
+ // Protection against invalid values.
+
+ if (et <= 0.0)
+ return 0.0;
+
+ // If near a standard shutter speed, snap to it.
+
+ static const real64 kStandardSpeed [] =
+ {
+ 30.0,
+ 25.0,
+ 20.0,
+ 15.0,
+ 13.0,
+ 10.0,
+ 8.0,
+ 6.0,
+ 5.0,
+ 4.0,
+ 3.2,
+ 3.0,
+ 2.5,
+ 2.0,
+ 1.6,
+ 1.5,
+ 1.3,
+ 1.0,
+ 0.8,
+ 0.7,
+ 0.6,
+ 0.5,
+ 0.4,
+ 0.3,
+ 1.0 / 4.0,
+ 1.0 / 5.0,
+ 1.0 / 6.0,
+ 1.0 / 8.0,
+ 1.0 / 10.0,
+ 1.0 / 13.0,
+ 1.0 / 15.0,
+ 1.0 / 20.0,
+ 1.0 / 25.0,
+ 1.0 / 30.0,
+ 1.0 / 40.0,
+ 1.0 / 45.0,
+ 1.0 / 50.0,
+ 1.0 / 60.0,
+ 1.0 / 80.0,
+ 1.0 / 90.0,
+ 1.0 / 100.0,
+ 1.0 / 125.0,
+ 1.0 / 160.0,
+ 1.0 / 180.0,
+ 1.0 / 200.0,
+ 1.0 / 250.0,
+ 1.0 / 320.0,
+ 1.0 / 350.0,
+ 1.0 / 400.0,
+ 1.0 / 500.0,
+ 1.0 / 640.0,
+ 1.0 / 750.0,
+ 1.0 / 800.0,
+ 1.0 / 1000.0,
+ 1.0 / 1250.0,
+ 1.0 / 1500.0,
+ 1.0 / 1600.0,
+ 1.0 / 2000.0,
+ 1.0 / 2500.0,
+ 1.0 / 3000.0,
+ 1.0 / 3200.0,
+ 1.0 / 4000.0,
+ 1.0 / 5000.0,
+ 1.0 / 6000.0,
+ 1.0 / 6400.0,
+ 1.0 / 8000.0,
+ 1.0 / 10000.0,
+ 1.0 / 12000.0,
+ 1.0 / 12800.0,
+ 1.0 / 16000.0
+ };
+
+ uint32 count = sizeof (kStandardSpeed ) /
+ sizeof (kStandardSpeed [0]);
+
+ for (uint32 fudge = 0; fudge <= 1; fudge++)
+ {
+
+ real64 testSpeed = et;
+
+ if (fudge == 1)
+ {
+
+ // Often APEX values are rounded to a power of two,
+ // which results in non-standard shutter speeds.
+
+ if (et >= 0.1)
+ {
+
+ // No fudging slower than 1/10 second
+
+ break;
+
+ }
+
+ else if (et >= 0.01)
+ {
+
+ // Between 1/10 and 1/100 the commonly misrounded
+ // speeds are 1/15, 1/30, 1/60, which are often encoded as
+ // 1/16, 1/32, 1/64. Try fudging and see if we get
+ // near a standard speed.
+
+ testSpeed *= 16.0 / 15.0;
+
+ }
+
+ else
+ {
+
+ // Faster than 1/100, the commonly misrounded
+ // speeds are 1/125, 1/250, 1/500, etc., which
+ // are often encoded as 1/128, 1/256, 1/512.
+
+ testSpeed *= 128.0 / 125.0;
+
+ }
+
+ }
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ if (testSpeed >= kStandardSpeed [index] * 0.98 &&
+ testSpeed <= kStandardSpeed [index] * 1.02)
+ {
+
+ return kStandardSpeed [index];
+
+ }
+
+ }
+
+ }
+
+ // We are not near any standard speeds. Round the non-standard value to something
+ // that looks reasonable.
+
+ if (et >= 10.0)
+ {
+
+ // Round to nearest second.
+
+ et = floor (et + 0.5);
+
+ }
+
+ else if (et >= 0.5)
+ {
+
+ // Round to nearest 1/10 second
+
+ et = floor (et * 10.0 + 0.5) * 0.1;
+
+ }
+
+ else if (et >= 1.0 / 20.0)
+ {
+
+ // Round to an exact inverse.
+
+ et = 1.0 / floor (1.0 / et + 0.5);
+
+ }
+
+ else if (et >= 1.0 / 130.0)
+ {
+
+ // Round inverse to multiple of 5
+
+ et = 0.2 / floor (0.2 / et + 0.5);
+
+ }
+
+ else if (et >= 1.0 / 750.0)
+ {
+
+ // Round inverse to multiple of 10
+
+ et = 0.1 / floor (0.1 / et + 0.5);
+
+ }
+
+ else if (et >= 1.0 / 1300.0)
+ {
+
+ // Round inverse to multiple of 50
+
+ et = 0.02 / floor (0.02 / et + 0.5);
+
+ }
+
+ else if (et >= 1.0 / 15000.0)
+ {
+
+ // Round inverse to multiple of 100
+
+ et = 0.01 / floor (0.01 / et + 0.5);
+
+ }
+
+ else
+ {
+
+ // Round inverse to multiple of 1000
+
+ et = 0.001 / floor (0.001 / et + 0.5);
+
+ }
+
+ return et;
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::SetExposureTime (real64 et, bool snap)
+ {
+
+ fExposureTime.Clear ();
+
+ fShutterSpeedValue.Clear ();
+
+ if (snap)
+ {
+
+ et = SnapExposureTime (et);
+
+ }
+
+ if (et >= 1.0 / 32768.0 && et <= 32768.0)
+ {
+
+ if (et >= 100.0)
+ {
+
+ fExposureTime.Set_real64 (et, 1);
+
+ }
+
+ else if (et >= 1.0)
+ {
+
+ fExposureTime.Set_real64 (et, 10);
+
+ fExposureTime.ReduceByFactor (10);
+
+ }
+
+ else if (et <= 0.1)
+ {
+
+ fExposureTime = dng_urational (1, Round_uint32 (1.0 / et));
+
+ }
+
+ else
+ {
+
+ fExposureTime.Set_real64 (et, 100);
+
+ fExposureTime.ReduceByFactor (10);
+
+ for (uint32 f = 2; f <= 9; f++)
+ {
+
+ real64 z = 1.0 / (real64) f / et;
+
+ if (z >= 0.99 && z <= 1.01)
+ {
+
+ fExposureTime = dng_urational (1, f);
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ // Now mirror this value to the ShutterSpeedValue field.
+
+ et = fExposureTime.As_real64 ();
+
+ fShutterSpeedValue.Set_real64 (-log (et) / log (2.0), 1000000);
+
+ fShutterSpeedValue.ReduceByFactor (10);
+ fShutterSpeedValue.ReduceByFactor (10);
+ fShutterSpeedValue.ReduceByFactor (10);
+ fShutterSpeedValue.ReduceByFactor (10);
+ fShutterSpeedValue.ReduceByFactor (10);
+ fShutterSpeedValue.ReduceByFactor (10);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::SetShutterSpeedValue (real64 ss)
+ {
+
+ if (fExposureTime.NotValid ())
+ {
+
+ real64 et = pow (2.0, -ss);
+
+ SetExposureTime (et, true);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+dng_urational dng_exif::EncodeFNumber (real64 fs)
+ {
+
+ dng_urational y;
+
+ if (fs > 10.0)
+ {
+
+ y.Set_real64 (fs, 1);
+
+ }
+
+ else if (fs < 1.0)
+ {
+
+ y.Set_real64 (fs, 100);
+
+ y.ReduceByFactor (10);
+ y.ReduceByFactor (10);
+
+ }
+
+ else
+ {
+
+ y.Set_real64 (fs, 10);
+
+ y.ReduceByFactor (10);
+
+ }
+
+ return y;
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::SetFNumber (real64 fs)
+ {
+
+ fFNumber.Clear ();
+
+ fApertureValue.Clear ();
+
+ // Allow f-number values less than 1.0 (e.g., f/0.95), even though they would
+ // correspond to negative APEX values, which the EXIF specification does not
+ // support (ApertureValue is a rational, not srational). The ApertureValue tag
+ // will be omitted in the case where fs < 1.0.
+
+ if (fs > 0.0 && fs <= 32768.0)
+ {
+
+ fFNumber = EncodeFNumber (fs);
+
+ // Now mirror this value to the ApertureValue field.
+
+ real64 av = FNumberToApertureValue (fFNumber);
+
+ if (av >= 0.0 && av <= 99.99)
+ {
+
+ fApertureValue.Set_real64 (av, 1000000);
+
+ fApertureValue.ReduceByFactor (10);
+ fApertureValue.ReduceByFactor (10);
+ fApertureValue.ReduceByFactor (10);
+ fApertureValue.ReduceByFactor (10);
+ fApertureValue.ReduceByFactor (10);
+ fApertureValue.ReduceByFactor (10);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::SetApertureValue (real64 av)
+ {
+
+ if (fFNumber.NotValid ())
+ {
+
+ SetFNumber (ApertureValueToFNumber (av));
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_exif::ApertureValueToFNumber (real64 av)
+ {
+
+ return pow (2.0, 0.5 * av);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_exif::ApertureValueToFNumber (const dng_urational &av)
+ {
+
+ return ApertureValueToFNumber (av.As_real64 ());
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_exif::FNumberToApertureValue (real64 fNumber)
+ {
+
+ return 2.0 * log (fNumber) / log (2.0);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_exif::FNumberToApertureValue (const dng_urational &fNumber)
+ {
+
+ return FNumberToApertureValue (fNumber.As_real64 ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::UpdateDateTime (const dng_date_time_info &dt)
+ {
+
+ fDateTime = dt;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_exif::AtLeastVersion0230 () const
+ {
+
+ uint32 b0 = (fExifVersion >> 24) & 0xff;
+ uint32 b1 = (fExifVersion >> 16) & 0xff;
+ uint32 b2 = (fExifVersion >> 8) & 0xff;
+
+ return (b0 > 0) || (b1 >= 2 && b2 >= 3);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_exif::ParseTag (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ bool isMainIFD,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset)
+ {
+
+ if (parentCode == 0)
+ {
+
+ if (Parse_ifd0 (stream,
+ shared,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ if (parentCode == 0 || isMainIFD)
+ {
+
+ if (Parse_ifd0_main (stream,
+ shared,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ if (parentCode == 0 ||
+ parentCode == tcExifIFD)
+ {
+
+ if (Parse_ifd0_exif (stream,
+ shared,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ if (parentCode == tcGPSInfo)
+ {
+
+ if (Parse_gps (stream,
+ shared,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ if (parentCode == tcInteroperabilityIFD)
+ {
+
+ if (Parse_interoperability (stream,
+ shared,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in IFD 0.
+
+bool dng_exif::Parse_ifd0 (dng_stream &stream,
+ dng_shared & /* shared */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 /* tagOffset */)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcImageDescription:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fImageDescription);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ImageDescription: ");
+
+ DumpString (fImageDescription);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcMake:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fMake);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Make: ");
+
+ DumpString (fMake);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcModel:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fModel);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Model: ");
+
+ DumpString (fModel);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSoftware:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fSoftware);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Software: ");
+
+ DumpString (fSoftware);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDateTime:
+ {
+
+ uint64 tagPosition = stream.PositionInOriginalFile ();
+
+ dng_date_time dt;
+
+ if (!ParseDateTimeTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ dt))
+ {
+ return false;
+ }
+
+ fDateTime.SetDateTime (dt);
+
+ fDateTimeStorageInfo = dng_date_time_storage_info (tagPosition,
+ dng_date_time_format_exif);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DateTime: ");
+
+ DumpDateTime (fDateTime.DateTime ());
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcArtist:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fArtist);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Artist: ");
+
+ DumpString (fArtist);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCopyright:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseDualStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fCopyright,
+ fCopyright2);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Copyright: ");
+
+ DumpString (fCopyright);
+
+ if (fCopyright2.Get () [0] != 0)
+ {
+
+ printf (" ");
+
+ DumpString (fCopyright2);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcTIFF_EP_StandardID:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fTIFF_EP_StandardID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("TIFF/EPStandardID: %u.%u.%u.%u\n",
+ (unsigned) b0,
+ (unsigned) b1,
+ (unsigned) b2,
+ (unsigned) b3);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraSerialNumber:
+ case tcKodakCameraSerialNumber: // Kodak uses a very similar tag.
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fCameraSerialNumber);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (fCameraSerialNumber);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLensInfo:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
+ return false;
+
+ fLensInfo [0] = stream.TagValue_urational (tagType);
+ fLensInfo [1] = stream.TagValue_urational (tagType);
+ fLensInfo [2] = stream.TagValue_urational (tagType);
+ fLensInfo [3] = stream.TagValue_urational (tagType);
+
+ // Some third party software wrote zero rather and undefined values
+ // for unknown entries. Work around this bug.
+
+ for (uint32 j = 0; j < 4; j++)
+ {
+
+ if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
+ {
+
+ fLensInfo [j] = dng_urational (0, 0);
+
+ #if qDNGValidate
+
+ ReportWarning ("Zero entry in LensInfo tag--should be undefined");
+
+ #endif
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("LensInfo: ");
+
+ real64 minFL = fLensInfo [0].As_real64 ();
+ real64 maxFL = fLensInfo [1].As_real64 ();
+
+ if (minFL == maxFL)
+ printf ("%0.1f mm", minFL);
+ else
+ printf ("%0.1f-%0.1f mm", minFL, maxFL);
+
+ if (fLensInfo [2].d)
+ {
+
+ real64 minFS = fLensInfo [2].As_real64 ();
+ real64 maxFS = fLensInfo [3].As_real64 ();
+
+ if (minFS == maxFS)
+ printf (" f/%0.1f", minFS);
+ else
+ printf (" f/%0.1f-%0.1f", minFS, maxFS);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in IFD 0 or the main image IFD.
+
+bool dng_exif::Parse_ifd0_main (dng_stream &stream,
+ dng_shared & /* shared */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 /* tagOffset */)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcFocalPlaneXResolution:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalPlaneXResolution = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalPlaneXResolution: %0.4f\n",
+ fFocalPlaneXResolution.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalPlaneYResolution:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalPlaneYResolution = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalPlaneYResolution: %0.4f\n",
+ fFocalPlaneYResolution.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalPlaneResolutionUnit:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalPlaneResolutionUnit: %s\n",
+ LookupResolutionUnit (fFocalPlaneResolutionUnit));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSensingMethod:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSensingMethod = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SensingMethod: %s\n",
+ LookupSensingMethod (fSensingMethod));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in IFD 0 or EXIF IFD.
+
+bool dng_exif::Parse_ifd0_exif (dng_stream &stream,
+ dng_shared & /* shared */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 /* tagOffset */)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcBatteryLevel:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational, ttAscii);
+
+ if (tagType == ttAscii)
+ {
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fBatteryLevelA);
+
+ }
+
+ else
+ {
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBatteryLevelR = stream.TagValue_urational (tagType);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BatteryLevel: ");
+
+ if (tagType == ttAscii)
+ {
+
+ DumpString (fBatteryLevelA);
+
+ }
+
+ else
+ {
+
+ printf ("%0.2f", fBatteryLevelR.As_real64 ());
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExposureTime:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ dng_urational et = stream.TagValue_urational (tagType);
+
+ SetExposureTime (et.As_real64 (), false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ExposureTime: ");
+
+ DumpExposureTime (et.As_real64 ());
+
+ printf ("\n");
+
+ }
+
+ if (et.As_real64 () <= 0.0)
+ {
+
+ ReportWarning ("The ExposureTime is <= 0");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFNumber:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ dng_urational fs = stream.TagValue_urational (tagType);
+
+ // Sometimes "unknown" is recorded as zero.
+
+ if (fs.As_real64 () <= 0.0)
+ {
+ fs.Clear ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FNumber: f/%0.2f\n",
+ fs.As_real64 ());
+
+ }
+
+ #endif
+
+ SetFNumber (fs.As_real64 ());
+
+ break;
+
+ }
+
+ case tcExposureProgram:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fExposureProgram = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ExposureProgram: %s\n",
+ LookupExposureProgram (fExposureProgram));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcISOSpeedRatings:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1, 3);
+
+ for (uint32 j = 0; j < tagCount && j < 3; j++)
+ {
+
+ fISOSpeedRatings [j] = stream.TagValue_uint32 (tagType);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ISOSpeedRatings:");
+
+ for (uint32 j = 0; j < tagCount && j < 3; j++)
+ {
+
+ printf (" %u", (unsigned) fISOSpeedRatings [j]);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSensitivityType:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSensitivityType = (uint32) stream.Get_uint16 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SensitivityType: %s\n",
+ LookupSensitivityType (fSensitivityType));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcStandardOutputSensitivity:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fStandardOutputSensitivity = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("StandardOutputSensitivity: %u\n",
+ (unsigned) fStandardOutputSensitivity);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRecommendedExposureIndex:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fRecommendedExposureIndex = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("RecommendedExposureIndex: %u\n",
+ (unsigned) fRecommendedExposureIndex);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcISOSpeed:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fISOSpeed = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ISOSpeed: %u\n",
+ (unsigned) fISOSpeed);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcISOSpeedLatitudeyyy:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fISOSpeedLatitudeyyy = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ISOSpeedLatitudeyyy: %u\n",
+ (unsigned) fISOSpeedLatitudeyyy);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcISOSpeedLatitudezzz:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fISOSpeedLatitudezzz = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ISOSpeedLatitudezzz: %u\n",
+ (unsigned) fISOSpeedLatitudezzz);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcTimeZoneOffset:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1, 2);
+
+ dng_time_zone zoneOriginal;
+
+ zoneOriginal.SetOffsetHours (stream.TagValue_int32 (tagType));
+
+ fDateTimeOriginal.SetZone (zoneOriginal);
+
+ dng_time_zone zoneCurrent;
+
+ if (tagCount >= 2)
+ {
+
+ zoneCurrent.SetOffsetHours (stream.TagValue_int32 (tagType));
+
+ fDateTime.SetZone (zoneCurrent);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("TimeZoneOffset: DateTimeOriginal = %d",
+ (int) zoneOriginal.ExactHourOffset ());
+
+ if (tagCount >= 2)
+ {
+
+ printf (", DateTime = %d",
+ (int) zoneCurrent.ExactHourOffset ());
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSelfTimerMode:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSelfTimerMode = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SelfTimerMode: ");
+
+ if (fSelfTimerMode)
+ {
+
+ printf ("%u sec", (unsigned) fSelfTimerMode);
+
+ }
+
+ else
+ {
+
+ printf ("Off");
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExifVersion:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fExifVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ real64 x = (b0 - '0') * 10.00 +
+ (b1 - '0') * 1.00 +
+ (b2 - '0') * 0.10 +
+ (b3 - '0') * 0.01;
+
+ printf ("ExifVersion: %0.2f\n", x);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDateTimeOriginal:
+ {
+
+ uint64 tagPosition = stream.PositionInOriginalFile ();
+
+ dng_date_time dt;
+
+ if (!ParseDateTimeTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ dt))
+ {
+ return false;
+ }
+
+ fDateTimeOriginal.SetDateTime (dt);
+
+ fDateTimeOriginalStorageInfo = dng_date_time_storage_info (tagPosition,
+ dng_date_time_format_exif);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DateTimeOriginal: ");
+
+ DumpDateTime (fDateTimeOriginal.DateTime ());
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDateTimeDigitized:
+ {
+
+ uint64 tagPosition = stream.PositionInOriginalFile ();
+
+ dng_date_time dt;
+
+ if (!ParseDateTimeTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ dt))
+ {
+ return false;
+ }
+
+ fDateTimeDigitized.SetDateTime (dt);
+
+ fDateTimeDigitizedStorageInfo = dng_date_time_storage_info (tagPosition,
+ dng_date_time_format_exif);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DateTimeDigitized: ");
+
+ DumpDateTime (fDateTimeDigitized.DateTime ());
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcComponentsConfiguration:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fComponentsConfiguration = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ComponentsConfiguration: %s %s %s %s\n",
+ LookupComponent (b0),
+ LookupComponent (b1),
+ LookupComponent (b2),
+ LookupComponent (b3));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCompressedBitsPerPixel:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCompresssedBitsPerPixel = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CompressedBitsPerPixel: %0.2f\n",
+ fCompresssedBitsPerPixel.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcShutterSpeedValue:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ dng_srational ss = stream.TagValue_srational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ShutterSpeedValue: ");
+
+ real64 x = pow (2.0, -ss.As_real64 ());
+
+ DumpExposureTime (x);
+
+ printf ("\n");
+
+ }
+
+ // The ExposureTime and ShutterSpeedValue tags should be consistent.
+
+ if (fExposureTime.IsValid ())
+ {
+
+ real64 et = fExposureTime.As_real64 ();
+
+ real64 tv1 = -1.0 * log (et) / log (2.0);
+
+ real64 tv2 = ss.As_real64 ();
+
+ // Make sure they are within 0.25 APEX values.
+
+ if (Abs_real64 (tv1 - tv2) > 0.25)
+ {
+
+ ReportWarning ("The ExposureTime and ShutterSpeedValue tags have conflicting values");
+
+ }
+
+ }
+
+ #endif
+
+ SetShutterSpeedValue (ss.As_real64 ());
+
+ break;
+
+ }
+
+ case tcApertureValue:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ dng_urational av = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ real64 x = pow (2.0, 0.5 * av.As_real64 ());
+
+ printf ("ApertureValue: f/%0.2f\n", x);
+
+ }
+
+ // The FNumber and ApertureValue tags should be consistent.
+
+ if (fFNumber.IsValid () && av.IsValid ())
+ {
+
+ real64 fs = fFNumber.As_real64 ();
+
+ real64 av1 = FNumberToApertureValue (fs);
+
+ real64 av2 = av.As_real64 ();
+
+ if (Abs_real64 (av1 - av2) > 0.25)
+ {
+
+ ReportWarning ("The FNumber and ApertureValue tags have conflicting values");
+
+ }
+
+ }
+
+ #endif
+
+ SetApertureValue (av.As_real64 ());
+
+ break;
+
+ }
+
+ case tcBrightnessValue:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBrightnessValue = stream.TagValue_srational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BrightnessValue: %0.2f\n",
+ fBrightnessValue.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExposureBiasValue:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fExposureBiasValue = stream.TagValue_srational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ExposureBiasValue: %0.2f\n",
+ fExposureBiasValue.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcMaxApertureValue:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fMaxApertureValue = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ real64 x = pow (2.0, 0.5 * fMaxApertureValue.As_real64 ());
+
+ printf ("MaxApertureValue: f/%0.1f\n", x);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubjectDistance:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSubjectDistance = stream.TagValue_urational (tagType);
+
+ fApproxFocusDistance = fSubjectDistance;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SubjectDistance: %u/%u\n",
+ (unsigned) fSubjectDistance.n,
+ (unsigned) fSubjectDistance.d);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcMeteringMode:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fMeteringMode = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("MeteringMode: %s\n",
+ LookupMeteringMode (fMeteringMode));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLightSource:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fLightSource = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("LightSource: %s\n",
+ LookupLightSource (fLightSource));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFlash:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFlash = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Flash: %u\n", (unsigned) fFlash);
+
+ if ((fFlash >> 5) & 1)
+ {
+ printf (" No flash function\n");
+ }
+
+ else
+ {
+
+ if (fFlash & 0x1)
+ {
+
+ printf (" Flash fired\n");
+
+ switch ((fFlash >> 1) & 0x3)
+ {
+
+ case 2:
+ printf (" Strobe return light not detected\n");
+ break;
+
+ case 3:
+ printf (" Strobe return light detected\n");
+ break;
+
+ }
+
+ }
+
+ else
+ {
+ printf (" Flash did not fire\n");
+ }
+
+ switch ((fFlash >> 3) & 0x3)
+ {
+
+ case 1:
+ printf (" Compulsory flash firing\n");
+ break;
+
+ case 2:
+ printf (" Compulsory flash suppression\n");
+ break;
+
+ case 3:
+ printf (" Auto mode\n");
+ break;
+
+ }
+
+ if ((fFlash >> 6) & 1)
+ {
+ printf (" Red-eye reduction supported\n");
+ }
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalLength:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalLength = stream.TagValue_urational (tagType);
+
+ // Sometimes "unknown" is recorded as zero.
+
+ if (fFocalLength.As_real64 () <= 0.0)
+ {
+ fFocalLength.Clear ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalLength: %0.1f mm\n",
+ fFocalLength.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcImageNumber:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fImageNumber = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("ImageNumber: %u\n", (unsigned) fImageNumber);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExposureIndex:
+ case tcExposureIndexExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fExposureIndex = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ISO %0.1f\n",
+ LookupTagCode (parentCode, tagCode),
+ fExposureIndex.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcUserComment:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ ParseEncodedStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fUserComment);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("UserComment: ");
+
+ DumpString (fUserComment);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubsecTime:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ dng_string subsecs;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ subsecs);
+
+ fDateTime.SetSubseconds (subsecs);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SubsecTime: ");
+
+ DumpString (subsecs);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubsecTimeOriginal:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ dng_string subsecs;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ subsecs);
+
+ fDateTimeOriginal.SetSubseconds (subsecs);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SubsecTimeOriginal: ");
+
+ DumpString (subsecs);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubsecTimeDigitized:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ dng_string subsecs;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ subsecs);
+
+ fDateTimeDigitized.SetSubseconds (subsecs);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SubsecTimeDigitized: ");
+
+ DumpString (subsecs);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFlashPixVersion:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fFlashPixVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ real64 x = (b0 - '0') * 10.00 +
+ (b1 - '0') * 1.00 +
+ (b2 - '0') * 0.10 +
+ (b3 - '0') * 0.01;
+
+ printf ("FlashPixVersion: %0.2f\n", x);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcColorSpace:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fColorSpace = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ColorSpace: %s\n",
+ LookupColorSpace (fColorSpace));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPixelXDimension:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPixelXDimension = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("PixelXDimension: %u\n", (unsigned) fPixelXDimension);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPixelYDimension:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPixelYDimension = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("PixelYDimension: %u\n", (unsigned) fPixelYDimension);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalPlaneXResolutionExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalPlaneXResolution = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalPlaneXResolutionExif: %0.4f\n",
+ fFocalPlaneXResolution.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalPlaneYResolutionExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalPlaneYResolution = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalPlaneYResolutionExif: %0.4f\n",
+ fFocalPlaneYResolution.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalPlaneResolutionUnitExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalPlaneResolutionUnitExif: %s\n",
+ LookupResolutionUnit (fFocalPlaneResolutionUnit));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSensingMethodExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSensingMethod = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SensingMethodExif: %s\n",
+ LookupSensingMethod (fSensingMethod));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFileSource:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFileSource = stream.Get_uint8 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FileSource: %s\n",
+ LookupFileSource (fFileSource));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSceneType:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSceneType = stream.Get_uint8 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SceneType: %s\n",
+ LookupSceneType (fSceneType));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCFAPatternExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ if (tagCount <= 4)
+ {
+ return false;
+ }
+
+ uint32 cols = stream.Get_uint16 ();
+ uint32 rows = stream.Get_uint16 ();
+
+ if (tagCount != 4 + cols * rows)
+ {
+ return false;
+ }
+
+ if (cols < 1 || cols > kMaxCFAPattern ||
+ rows < 1 || rows > kMaxCFAPattern)
+ {
+ return false;
+ }
+
+ fCFARepeatPatternCols = cols;
+ fCFARepeatPatternRows = rows;
+
+ // Note that the Exif spec stores this array in a different
+ // scan order than the TIFF-EP spec.
+
+ for (uint32 j = 0; j < fCFARepeatPatternCols; j++)
+ for (uint32 k = 0; k < fCFARepeatPatternRows; k++)
+ {
+
+ fCFAPattern [k] [j] = stream.Get_uint8 ();
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CFAPatternExif:\n");
+
+ for (uint32 j = 0; j < fCFARepeatPatternRows; j++)
+ {
+
+ int32 spaces = 4;
+
+ for (uint32 k = 0; k < fCFARepeatPatternCols; k++)
+ {
+
+ while (spaces-- > 0)
+ {
+ printf (" ");
+ }
+
+ const char *name = LookupCFAColor (fCFAPattern [j] [k]);
+
+ spaces = 9 - (int32) strlen (name);
+
+ printf ("%s", name);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCustomRendered:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCustomRendered = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CustomRendered: %s\n",
+ LookupCustomRendered (fCustomRendered));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExposureMode:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fExposureMode = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ExposureMode: %s\n",
+ LookupExposureMode (fExposureMode));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcWhiteBalance:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fWhiteBalance = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("WhiteBalance: %s\n",
+ LookupWhiteBalance (fWhiteBalance));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDigitalZoomRatio:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDigitalZoomRatio = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DigitalZoomRatio: ");
+
+ if (fDigitalZoomRatio.n == 0 ||
+ fDigitalZoomRatio.d == 0)
+ {
+
+ printf ("Not used\n");
+
+ }
+
+ else
+ {
+
+ printf ("%0.2f\n", fDigitalZoomRatio.As_real64 ());
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFocalLengthIn35mmFilm:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFocalLengthIn35mmFilm = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("FocalLengthIn35mmFilm: %u mm\n",
+ (unsigned) fFocalLengthIn35mmFilm);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSceneCaptureType:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSceneCaptureType = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SceneCaptureType: %s\n",
+ LookupSceneCaptureType (fSceneCaptureType));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGainControl:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fGainControl = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("GainControl: %s\n",
+ LookupGainControl (fGainControl));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcContrast:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fContrast = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Contrast: %s\n",
+ LookupContrast (fContrast));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSaturation:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSaturation = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Saturation: %s\n",
+ LookupSaturation (fSaturation));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSharpness:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSharpness = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Sharpness: %s\n",
+ LookupSharpness (fSharpness));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubjectDistanceRange:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSubjectDistanceRange = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SubjectDistanceRange: %s\n",
+ LookupSubjectDistanceRange (fSubjectDistanceRange));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubjectArea:
+ case tcSubjectLocation:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2, 4))
+ {
+ return false;
+ }
+
+ if (tagCode == tcSubjectLocation)
+ {
+ CheckTagCount (parentCode, tagCode, tagCount, 2);
+ }
+
+ fSubjectAreaCount = tagCount;
+
+ for (uint32 j = 0; j < tagCount; j++)
+ {
+
+ fSubjectArea [j] = stream.TagValue_uint32 (tagType);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s:", LookupTagCode (parentCode, tagCode));
+
+ for (uint32 j = 0; j < fSubjectAreaCount; j++)
+ {
+
+ printf (" %u", (unsigned) fSubjectArea [j]);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGamma:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fGamma = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Gamma: %0.2f\n",
+ fGamma.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcImageUniqueID:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 33))
+ return false;
+
+ dng_string s;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ s);
+
+ if (s.Length () != 32)
+ return false;
+
+ dng_fingerprint f;
+
+ for (uint32 j = 0; j < 32; j++)
+ {
+
+ char c = ForceUppercase (s.Get () [j]);
+
+ uint32 digit;
+
+ if (c >= '0' && c <= '9')
+ {
+ digit = c - '0';
+ }
+
+ else if (c >= 'A' && c <= 'F')
+ {
+ digit = c - 'A' + 10;
+ }
+
+ else
+ return false;
+
+ f.data [j >> 1] *= 16;
+ f.data [j >> 1] += (uint8) digit;
+
+ }
+
+ fImageUniqueID = f;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ImageUniqueID: ");
+
+ DumpFingerprint (fImageUniqueID);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraOwnerNameExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fOwnerName);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CameraOwnerName: ");
+
+ DumpString (fOwnerName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraSerialNumberExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fCameraSerialNumber);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (fCameraSerialNumber);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLensSpecificationExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
+ return false;
+
+ fLensInfo [0] = stream.TagValue_urational (tagType);
+ fLensInfo [1] = stream.TagValue_urational (tagType);
+ fLensInfo [2] = stream.TagValue_urational (tagType);
+ fLensInfo [3] = stream.TagValue_urational (tagType);
+
+ // Some third party software wrote zero rather than undefined values for
+ // unknown entries. Work around this bug.
+
+ for (uint32 j = 0; j < 4; j++)
+ {
+
+ if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
+ {
+
+ fLensInfo [j] = dng_urational (0, 0);
+
+ #if qDNGValidate
+
+ ReportWarning ("Zero entry in LensSpecification tag--should be undefined");
+
+ #endif
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("LensSpecificationExif: ");
+
+ real64 minFL = fLensInfo [0].As_real64 ();
+ real64 maxFL = fLensInfo [1].As_real64 ();
+
+ if (minFL == maxFL)
+ printf ("%0.1f mm", minFL);
+ else
+ printf ("%0.1f-%0.1f mm", minFL, maxFL);
+
+ if (fLensInfo [2].d)
+ {
+
+ real64 minFS = fLensInfo [2].As_real64 ();
+ real64 maxFS = fLensInfo [3].As_real64 ();
+
+ if (minFS == maxFS)
+ printf (" f/%0.1f", minFS);
+ else
+ printf (" f/%0.1f-%0.1f", minFS, maxFS);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLensMakeExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fLensMake);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (fLensMake);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLensModelExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fLensName);
+
+ fLensNameWasReadFromExif = fLensName.NotEmpty ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (fLensName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLensSerialNumberExif:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fLensSerialNumber);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (fLensSerialNumber);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in GPS IFD
+
+bool dng_exif::Parse_gps (dng_stream &stream,
+ dng_shared & /* shared */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 /* tagOffset */)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcGPSVersionID:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fGPSVersionID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("GPSVersionID: %u.%u.%u.%u\n",
+ (unsigned) b0,
+ (unsigned) b1,
+ (unsigned) b2,
+ (unsigned) b3);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSLatitudeRef:
+ case tcGPSLongitudeRef:
+ case tcGPSSatellites:
+ case tcGPSStatus:
+ case tcGPSMeasureMode:
+ case tcGPSSpeedRef:
+ case tcGPSTrackRef:
+ case tcGPSImgDirectionRef:
+ case tcGPSMapDatum:
+ case tcGPSDestLatitudeRef:
+ case tcGPSDestLongitudeRef:
+ case tcGPSDestBearingRef:
+ case tcGPSDestDistanceRef:
+ case tcGPSDateStamp:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
+ return false;
+
+ dng_string *s;
+
+ switch (tagCode)
+ {
+
+ case tcGPSLatitudeRef:
+ s = &fGPSLatitudeRef;
+ break;
+
+ case tcGPSLongitudeRef:
+ s = &fGPSLongitudeRef;
+ break;
+
+ case tcGPSSatellites:
+ s = &fGPSSatellites;
+ break;
+
+ case tcGPSStatus:
+ s = &fGPSStatus;
+ break;
+
+ case tcGPSMeasureMode:
+ s = &fGPSMeasureMode;
+ break;
+
+ case tcGPSSpeedRef:
+ s = &fGPSSpeedRef;
+ break;
+
+ case tcGPSTrackRef:
+ s = &fGPSTrackRef;
+ break;
+
+ case tcGPSImgDirectionRef:
+ s = &fGPSImgDirectionRef;
+ break;
+
+ case tcGPSMapDatum:
+ s = &fGPSMapDatum;
+ break;
+
+ case tcGPSDestLatitudeRef:
+ s = &fGPSDestLatitudeRef;
+ break;
+
+ case tcGPSDestLongitudeRef:
+ s = &fGPSDestLongitudeRef;
+ break;
+
+ case tcGPSDestBearingRef:
+ s = &fGPSDestBearingRef;
+ break;
+
+ case tcGPSDestDistanceRef:
+ s = &fGPSDestDistanceRef;
+ break;
+
+ case tcGPSDateStamp:
+ s = &fGPSDateStamp;
+ break;
+
+ default:
+ return false;
+
+ }
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ *s);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (*s);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSLatitude:
+ case tcGPSLongitude:
+ case tcGPSTimeStamp:
+ case tcGPSDestLatitude:
+ case tcGPSDestLongitude:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 3))
+ return false;
+
+ dng_urational *u;
+
+ switch (tagCode)
+ {
+
+ case tcGPSLatitude:
+ u = fGPSLatitude;
+ break;
+
+ case tcGPSLongitude:
+ u = fGPSLongitude;
+ break;
+
+ case tcGPSTimeStamp:
+ u = fGPSTimeStamp;
+ break;
+
+ case tcGPSDestLatitude:
+ u = fGPSDestLatitude;
+ break;
+
+ case tcGPSDestLongitude:
+ u = fGPSDestLongitude;
+ break;
+
+ default:
+ return false;
+
+ }
+
+ u [0] = stream.TagValue_urational (tagType);
+ u [1] = stream.TagValue_urational (tagType);
+ u [2] = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s:", LookupTagCode (parentCode, tagCode));
+
+ for (uint32 j = 0; j < 3; j++)
+ {
+
+ if (u [j].d == 0)
+ printf (" -");
+
+ else
+ printf (" %0.4f", u [j].As_real64 ());
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSAltitudeRef:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fGPSAltitudeRef = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("GPSAltitudeRef: ");
+
+ switch (fGPSAltitudeRef)
+ {
+
+ case 0:
+ printf ("Sea level");
+ break;
+
+ case 1:
+ printf ("Sea level reference (negative value)");
+ break;
+
+ default:
+ printf ("%u", (unsigned) fGPSAltitudeRef);
+ break;
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSAltitude:
+ case tcGPSDOP:
+ case tcGPSSpeed:
+ case tcGPSTrack:
+ case tcGPSImgDirection:
+ case tcGPSDestBearing:
+ case tcGPSDestDistance:
+ case tcGPSHPositioningError:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
+ return false;
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ dng_urational *u;
+
+ switch (tagCode)
+ {
+
+ case tcGPSAltitude:
+ u = &fGPSAltitude;
+ break;
+
+ case tcGPSDOP:
+ u = &fGPSDOP;
+ break;
+
+ case tcGPSSpeed:
+ u = &fGPSSpeed;
+ break;
+
+ case tcGPSTrack:
+ u = &fGPSTrack;
+ break;
+
+ case tcGPSImgDirection:
+ u = &fGPSImgDirection;
+ break;
+
+ case tcGPSDestBearing:
+ u = &fGPSDestBearing;
+ break;
+
+ case tcGPSDestDistance:
+ u = &fGPSDestDistance;
+ break;
+
+ case tcGPSHPositioningError:
+ u = &fGPSHPositioningError;
+ break;
+
+ default:
+ return false;
+
+ }
+
+ *u = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s:", LookupTagCode (parentCode, tagCode));
+
+ if (u->d == 0)
+ printf (" -");
+
+ else
+ printf (" %0.4f", u->As_real64 ());
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSProcessingMethod:
+ case tcGPSAreaInformation:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttUndefined))
+ return false;
+
+ dng_string *s;
+
+ switch (tagCode)
+ {
+
+ case tcGPSProcessingMethod:
+ s = &fGPSProcessingMethod;
+ break;
+
+ case tcGPSAreaInformation:
+ s = &fGPSAreaInformation;
+ break;
+
+ default:
+ return false;
+
+ }
+
+ ParseEncodedStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ *s);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: ", LookupTagCode (parentCode, tagCode));
+
+ DumpString (*s);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSDifferential:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fGPSDifferential = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("GPSDifferential: ");
+
+ switch (fGPSDifferential)
+ {
+
+ case 0:
+ printf ("Measurement without differential correction");
+ break;
+
+ case 1:
+ printf ("Differential correction applied");
+ break;
+
+ default:
+ printf ("%u", (unsigned) fGPSDifferential);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in Interoperability IFD
+
+bool dng_exif::Parse_interoperability (dng_stream &stream,
+ dng_shared & /* shared */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 /* tagOffset */)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcInteroperabilityIndex:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fInteroperabilityIndex);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("InteroperabilityIndex: ");
+
+ DumpString (fInteroperabilityIndex);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcInteroperabilityVersion:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fInteroperabilityVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ real64 x = (b0 - '0') * 10.00 +
+ (b1 - '0') * 1.00 +
+ (b2 - '0') * 0.10 +
+ (b3 - '0') * 0.01;
+
+ printf ("InteroperabilityVersion: %0.2f\n", x);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRelatedImageFileFormat:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fRelatedImageFileFormat);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("RelatedImageFileFormat: ");
+
+ DumpString (fRelatedImageFileFormat);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRelatedImageWidth:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fRelatedImageWidth = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("RelatedImageWidth: %u\n", (unsigned) fRelatedImageWidth);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRelatedImageLength:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fRelatedImageLength = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("RelatedImageLength: %u\n", (unsigned) fRelatedImageLength);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::PostParse (dng_host & /* host */,
+ dng_shared & /* shared */)
+ {
+
+ #if qDNGValidate
+
+ const real64 kAPEX_Slop = 0.25;
+
+ // Sanity check on MaxApertureValue.
+
+ if (fMaxApertureValue.d)
+ {
+
+ real64 mav = fMaxApertureValue.As_real64 ();
+
+ // Compare against ApertureValue or FNumber.
+
+ real64 av = mav;
+
+ if (fApertureValue.d)
+ {
+
+ av = fApertureValue.As_real64 ();
+
+ }
+
+ else if (fFNumber.d)
+ {
+
+ real64 fs = fFNumber.As_real64 ();
+
+ if (fs >= 1.0)
+ {
+
+ av = FNumberToApertureValue (fs);
+
+ }
+
+ }
+
+ if (mav > av + kAPEX_Slop)
+ {
+
+ ReportWarning ("MaxApertureValue conflicts with ApertureValue and/or FNumber");
+
+ }
+
+ // Compare against LensInfo
+
+ if (fLensInfo [2].d && fLensInfo [3].d)
+ {
+
+ real64 fs1 = fLensInfo [2].As_real64 ();
+ real64 fs2 = fLensInfo [3].As_real64 ();
+
+ if (fs1 >= 1.0 && fs2 >= 1.0 && fs2 >= fs1)
+ {
+
+ real64 av1 = FNumberToApertureValue (fs1);
+ real64 av2 = FNumberToApertureValue (fs2);
+
+ // Wide angle adapters might create an effective
+ // wide FS, and tele-extenders always result
+ // in a higher FS.
+
+ if (mav < av1 - kAPEX_Slop - 1.0 ||
+ mav > av2 + kAPEX_Slop + 2.0)
+ {
+
+ ReportWarning ("Possible MaxApertureValue conflict with LensInfo");
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Sanity check on FocalLength.
+
+ if (fFocalLength.d)
+ {
+
+ real64 fl = fFocalLength.As_real64 ();
+
+ if (fl < 1.0)
+ {
+
+ ReportWarning ("FocalLength is less than 1.0 mm (legal but unlikely)");
+
+ }
+
+ else if (fLensInfo [0].d && fLensInfo [1].d)
+ {
+
+ real64 minFL = fLensInfo [0].As_real64 ();
+ real64 maxFL = fLensInfo [1].As_real64 ();
+
+ // Allow for wide-angle converters and tele-extenders.
+
+ if (fl < minFL * 0.6 ||
+ fl > maxFL * 2.1)
+ {
+
+ ReportWarning ("Possible FocalLength conflict with LensInfo");
+
+ }
+
+ }
+
+ }
+
+ #endif
+
+ // Mirror DateTimeOriginal to DateTime.
+
+ if (fDateTime.NotValid () && fDateTimeOriginal.IsValid ())
+ {
+
+ fDateTime = fDateTimeOriginal;
+
+ }
+
+ // Mirror EXIF 2.3 sensitivity tags to ISOSpeedRatings.
+
+ if (fISOSpeedRatings [0] == 0 || fISOSpeedRatings [0] == 65535)
+ {
+
+ // Prefer Recommended Exposure Index, then Standard Output Sensitivity, then
+ // ISO Speed, then Exposure Index.
+
+ if (fRecommendedExposureIndex != 0 &&
+ (fSensitivityType == stRecommendedExposureIndex ||
+ fSensitivityType == stSOSandREI ||
+ fSensitivityType == stREIandISOSpeed ||
+ fSensitivityType == stSOSandREIandISOSpeed))
+ {
+
+ fISOSpeedRatings [0] = fRecommendedExposureIndex;
+
+ }
+
+ else if (fStandardOutputSensitivity != 0 &&
+ (fSensitivityType == stStandardOutputSensitivity ||
+ fSensitivityType == stSOSandREI ||
+ fSensitivityType == stSOSandISOSpeed ||
+ fSensitivityType == stSOSandREIandISOSpeed))
+ {
+
+ fISOSpeedRatings [0] = fStandardOutputSensitivity;
+
+ }
+
+ else if (fISOSpeed != 0 &&
+ (fSensitivityType == stISOSpeed ||
+ fSensitivityType == stSOSandISOSpeed ||
+ fSensitivityType == stREIandISOSpeed ||
+ fSensitivityType == stSOSandREIandISOSpeed))
+ {
+
+ fISOSpeedRatings [0] = fISOSpeed;
+
+ }
+
+ }
+
+ // Mirror ExposureIndex to ISOSpeedRatings.
+
+ if (fExposureIndex.IsValid () && fISOSpeedRatings [0] == 0)
+ {
+
+ fISOSpeedRatings [0] = Round_uint32 (fExposureIndex.As_real64 ());
+
+ }
+
+ // Kodak sets the GPSAltitudeRef without setting the GPSAltitude.
+
+ if (fGPSAltitude.NotValid ())
+ {
+
+ fGPSAltitudeRef = 0xFFFFFFFF;
+
+ }
+
+ // If there is no valid GPS data, clear the GPS version number.
+
+ if (fGPSLatitude [0].NotValid () &&
+ fGPSLongitude [0].NotValid () &&
+ fGPSAltitude .NotValid () &&
+ fGPSTimeStamp [0].NotValid () &&
+ fGPSDateStamp .IsEmpty ())
+ {
+
+ fGPSVersionID = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_exif.h b/gpr/source/lib/dng_sdk/dng_exif.h
new file mode 100644
index 0000000..a85fc7d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_exif.h
@@ -0,0 +1,351 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_exif.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * EXIF read access support. See the \ref spec_exif "EXIF specification" for full
+ * description of tags.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_exif__
+#define __dng_exif__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_date_time.h"
+#include "dng_fingerprint.h"
+#include "dng_types.h"
+#include "dng_matrix.h"
+#include "dng_rational.h"
+#include "dng_string.h"
+#include "dng_stream.h"
+#include "dng_sdk_limits.h"
+
+/*****************************************************************************/
+
+/// \brief Container class for parsing and holding EXIF tags.
+///
+/// Public member fields are documented in \ref spec_exif "EXIF specification."
+
+class dng_exif
+ {
+
+ public:
+
+ dng_string fImageDescription;
+ dng_string fMake;
+ dng_string fModel;
+ dng_string fSoftware;
+ dng_string fArtist;
+ dng_string fCopyright;
+ dng_string fCopyright2;
+ dng_string fUserComment;
+
+ dng_date_time_info fDateTime;
+ dng_date_time_storage_info fDateTimeStorageInfo;
+
+ dng_date_time_info fDateTimeOriginal;
+ dng_date_time_storage_info fDateTimeOriginalStorageInfo;
+
+ dng_date_time_info fDateTimeDigitized;
+ dng_date_time_storage_info fDateTimeDigitizedStorageInfo;
+
+ uint32 fTIFF_EP_StandardID;
+ uint32 fExifVersion;
+ uint32 fFlashPixVersion;
+
+ dng_urational fExposureTime;
+ dng_urational fFNumber;
+ dng_srational fShutterSpeedValue;
+ dng_urational fApertureValue;
+ dng_srational fBrightnessValue;
+ dng_srational fExposureBiasValue;
+ dng_urational fMaxApertureValue;
+ dng_urational fFocalLength;
+ dng_urational fDigitalZoomRatio;
+ dng_urational fExposureIndex;
+ dng_urational fSubjectDistance;
+ dng_urational fGamma;
+
+ dng_urational fBatteryLevelR;
+ dng_string fBatteryLevelA;
+
+ uint32 fExposureProgram;
+ uint32 fMeteringMode;
+ uint32 fLightSource;
+ uint32 fFlash;
+ uint32 fFlashMask;
+ uint32 fSensingMethod;
+ uint32 fColorSpace;
+ uint32 fFileSource;
+ uint32 fSceneType;
+ uint32 fCustomRendered;
+ uint32 fExposureMode;
+ uint32 fWhiteBalance;
+ uint32 fSceneCaptureType;
+ uint32 fGainControl;
+ uint32 fContrast;
+ uint32 fSaturation;
+ uint32 fSharpness;
+ uint32 fSubjectDistanceRange;
+ uint32 fSelfTimerMode;
+ uint32 fImageNumber;
+
+ uint32 fFocalLengthIn35mmFilm;
+
+ uint32 fISOSpeedRatings [3]; // EXIF 2.3: PhotographicSensitivity.
+
+ // Sensitivity tags added in EXIF 2.3.
+
+ uint32 fSensitivityType;
+ uint32 fStandardOutputSensitivity;
+ uint32 fRecommendedExposureIndex;
+ uint32 fISOSpeed;
+ uint32 fISOSpeedLatitudeyyy;
+ uint32 fISOSpeedLatitudezzz;
+
+ uint32 fSubjectAreaCount;
+ uint32 fSubjectArea [4];
+
+ uint32 fComponentsConfiguration;
+
+ dng_urational fCompresssedBitsPerPixel;
+
+ uint32 fPixelXDimension;
+ uint32 fPixelYDimension;
+
+ dng_urational fFocalPlaneXResolution;
+ dng_urational fFocalPlaneYResolution;
+
+ uint32 fFocalPlaneResolutionUnit;
+
+ uint32 fCFARepeatPatternRows;
+ uint32 fCFARepeatPatternCols;
+
+ uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
+
+ dng_fingerprint fImageUniqueID;
+
+ uint32 fGPSVersionID;
+ dng_string fGPSLatitudeRef;
+ dng_urational fGPSLatitude [3];
+ dng_string fGPSLongitudeRef;
+ dng_urational fGPSLongitude [3];
+ uint32 fGPSAltitudeRef;
+ dng_urational fGPSAltitude;
+ dng_urational fGPSTimeStamp [3];
+ dng_string fGPSSatellites;
+ dng_string fGPSStatus;
+ dng_string fGPSMeasureMode;
+ dng_urational fGPSDOP;
+ dng_string fGPSSpeedRef;
+ dng_urational fGPSSpeed;
+ dng_string fGPSTrackRef;
+ dng_urational fGPSTrack;
+ dng_string fGPSImgDirectionRef;
+ dng_urational fGPSImgDirection;
+ dng_string fGPSMapDatum;
+ dng_string fGPSDestLatitudeRef;
+ dng_urational fGPSDestLatitude [3];
+ dng_string fGPSDestLongitudeRef;
+ dng_urational fGPSDestLongitude [3];
+ dng_string fGPSDestBearingRef;
+ dng_urational fGPSDestBearing;
+ dng_string fGPSDestDistanceRef;
+ dng_urational fGPSDestDistance;
+ dng_string fGPSProcessingMethod;
+ dng_string fGPSAreaInformation;
+ dng_string fGPSDateStamp;
+ uint32 fGPSDifferential;
+ dng_urational fGPSHPositioningError;
+
+ dng_string fInteroperabilityIndex;
+
+ uint32 fInteroperabilityVersion;
+
+ dng_string fRelatedImageFileFormat;
+
+ uint32 fRelatedImageWidth;
+ uint32 fRelatedImageLength;
+
+ dng_string fCameraSerialNumber; // EXIF 2.3: BodySerialNumber.
+
+ dng_urational fLensInfo [4]; // EXIF 2.3: LensSpecification.
+
+ dng_string fLensID;
+ dng_string fLensMake;
+ dng_string fLensName; // EXIF 2.3: LensModel.
+ dng_string fLensSerialNumber;
+
+ // Was the lens name field read from a LensModel tag?
+
+ bool fLensNameWasReadFromExif;
+
+ // Private field to hold the approximate focus distance of the lens, in
+ // meters. This value is often coarsely measured/reported and hence should be
+ // interpreted only as a rough estimate of the true distance from the plane
+ // of focus (in object space) to the focal plane. It is still useful for the
+ // purposes of applying lens corrections.
+
+ dng_urational fApproxFocusDistance;
+
+ dng_srational fFlashCompensation;
+
+ dng_string fOwnerName; // EXIF 2.3: CameraOwnerName.
+ dng_string fFirmware;
+
+ public:
+
+ dng_exif ();
+
+ virtual ~dng_exif ();
+
+ /// Make clone.
+
+ virtual dng_exif * Clone () const;
+
+ /// Clear all EXIF fields.
+
+ void SetEmpty ();
+
+ /// Copy all GPS-related fields.
+ /// \param exif Source object from which to copy GPS fields.
+
+ void CopyGPSFrom (const dng_exif &exif);
+
+ /// Utility to fix up common errors and rounding issues with EXIF exposure
+ /// times.
+
+ static real64 SnapExposureTime (real64 et);
+
+ /// Set exposure time and shutter speed fields. Optionally fix up common
+ /// errors and rounding issues with EXIF exposure times.
+ /// \param et Exposure time in seconds.
+ /// \param snap Set to true to fix up common errors and rounding issues with
+ /// EXIF exposure times.
+
+ void SetExposureTime (real64 et,
+ bool snap = true);
+
+ /// Set shutter speed value (APEX units) and exposure time.
+ /// \param Shutter speed in APEX units.
+
+ void SetShutterSpeedValue (real64 ss);
+
+ /// Utility to encode f-number as a rational.
+ /// \param fs The f-number to encode.
+
+ static dng_urational EncodeFNumber (real64 fs);
+
+ /// Set the FNumber and ApertureValue fields.
+ /// \param fs The f-number to set.
+
+ void SetFNumber (real64 fs);
+
+ /// Set the FNumber and ApertureValue fields.
+ /// \param av The aperture value (APEX units).
+
+ void SetApertureValue (real64 av);
+
+ /// Utility to convert aperture value (APEX units) to f-number.
+ /// \param av The aperture value (APEX units) to convert.
+
+ static real64 ApertureValueToFNumber (real64 av);
+
+ /// Utility to convert aperture value (APEX units) to f-number.
+ /// \param av The aperture value (APEX units) to convert.
+
+ static real64 ApertureValueToFNumber (const dng_urational &av);
+
+ /// Utility to convert f-number to aperture value (APEX units).
+ /// \param fNumber The f-number to convert.
+
+ static real64 FNumberToApertureValue (real64 fNumber);
+
+ /// Utility to convert f-number to aperture value (APEX units).
+ /// \param fNumber The f-number to convert.
+
+ static real64 FNumberToApertureValue (const dng_urational &fNumber);
+
+ /// Set the DateTime field.
+ /// \param dt The DateTime value.
+
+ void UpdateDateTime (const dng_date_time_info &dt);
+
+ /// Returns true iff the EXIF version is at least 2.3.
+
+ bool AtLeastVersion0230 () const;
+
+ virtual bool ParseTag (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ bool isMainIFD,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual void PostParse (dng_host &host,
+ dng_shared &shared);
+
+ protected:
+
+ virtual bool Parse_ifd0 (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual bool Parse_ifd0_main (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual bool Parse_ifd0_exif (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual bool Parse_gps (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual bool Parse_interoperability (dng_stream &stream,
+ dng_shared &shared,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_fast_module.h b/gpr/source/lib/dng_sdk/dng_fast_module.h
new file mode 100644
index 0000000..ee6a10f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_fast_module.h
@@ -0,0 +1,31 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_fast_module.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Include file to set optimization to highest level for performance-critical routines.
+ * Normal files should have otpimization set to normal level to save code size as there is less
+ * cache pollution this way.
+ */
+
+/*****************************************************************************/
+
+// Include this file in modules that contain routines that should be as fast
+// as possible, even at the expense of slight code size increases.
+
+/*****************************************************************************/
+
+#ifdef _MSC_VER
+#pragma optimize ("t", on)
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_file_stream.cpp b/gpr/source/lib/dng_sdk/dng_file_stream.cpp
new file mode 100644
index 0000000..4a8a79f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_file_stream.cpp
@@ -0,0 +1,135 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_file_stream.cpp#2 $ */
+/* $DateTime: 2012/06/01 07:28:57 $ */
+/* $Change: 832715 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_file_stream.h"
+
+#include "dng_exceptions.h"
+
+/*****************************************************************************/
+
+dng_file_stream::dng_file_stream (const char *filename,
+ bool output,
+ uint32 bufferSize)
+
+ : dng_stream ((dng_abort_sniffer *) NULL,
+ bufferSize,
+ 0)
+
+ , fFile (NULL)
+
+ {
+
+ fFile = fopen (filename, output ? "wb" : "rb");
+
+ if (!fFile)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unable to open file",
+ filename);
+
+ ThrowSilentError ();
+
+ #else
+
+ ThrowOpenFile ();
+
+ #endif
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_file_stream::~dng_file_stream ()
+ {
+
+ if (fFile)
+ {
+ fclose (fFile);
+ fFile = NULL;
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_file_stream::DoGetLength ()
+ {
+
+ if (fseek (fFile, 0, SEEK_END) != 0)
+ {
+
+ ThrowReadFile ();
+
+ }
+
+ return (uint64) ftell (fFile);
+
+ }
+
+/*****************************************************************************/
+
+void dng_file_stream::DoRead (void *data,
+ uint32 count,
+ uint64 offset)
+ {
+
+ if (fseek (fFile, (long) offset, SEEK_SET) != 0)
+ {
+
+ ThrowReadFile ();
+
+ }
+
+ uint32 bytesRead = (uint32) fread (data, 1, count, fFile);
+
+ if (bytesRead != count)
+ {
+
+ ThrowReadFile ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_file_stream::DoWrite (const void *data,
+ uint32 count,
+ uint64 offset)
+ {
+
+ if (fseek (fFile, (uint32) offset, SEEK_SET) != 0)
+ {
+
+ ThrowWriteFile ();
+
+ }
+
+ uint32 bytesWritten = (uint32) fwrite (data, 1, count, fFile);
+
+ if (bytesWritten != count)
+ {
+
+ ThrowWriteFile ();
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_file_stream.h b/gpr/source/lib/dng_sdk/dng_file_stream.h
new file mode 100644
index 0000000..89a46b6
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_file_stream.h
@@ -0,0 +1,78 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_file_stream.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Simple, portable, file read/write support.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_file_stream__
+#define __dng_file_stream__
+
+/*****************************************************************************/
+
+#include <stdio.h>
+#include "dng_stream.h"
+
+/*****************************************************************************/
+
+/// \brief A stream to/from a disk file. See dng_stream for read/write interface
+
+class dng_file_stream: public dng_stream
+ {
+
+ private:
+
+ FILE *fFile;
+
+ public:
+
+ /// Open a stream on a file.
+ /// \param filename Pathname in platform synax.
+ /// \param output Set to true if writing, false otherwise.
+ /// \param bufferSize size of internal buffer to use. Defaults to 4k.
+
+ dng_file_stream (const char *filename,
+ bool output = false,
+ uint32 bufferSize = kDefaultBufferSize);
+
+ virtual ~dng_file_stream ();
+
+ protected:
+
+ virtual uint64 DoGetLength ();
+
+ virtual void DoRead (void *data,
+ uint32 count,
+ uint64 offset);
+
+ virtual void DoWrite (const void *data,
+ uint32 count,
+ uint64 offset);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_file_stream (const dng_file_stream &stream);
+
+ dng_file_stream & operator= (const dng_file_stream &stream);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_filter_task.cpp b/gpr/source/lib/dng_sdk/dng_filter_task.cpp
new file mode 100644
index 0000000..f8fc560
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_filter_task.cpp
@@ -0,0 +1,167 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_filter_task.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_filter_task.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_image.h"
+#include "dng_memory.h"
+#include "dng_tag_types.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_filter_task::dng_filter_task (const dng_image &srcImage,
+ dng_image &dstImage)
+
+ : fSrcImage (srcImage)
+ , fDstImage (dstImage)
+
+ , fSrcPlane (0 )
+ , fSrcPlanes (srcImage.Planes ())
+ , fSrcPixelType (srcImage.PixelType ())
+
+ , fDstPlane (0 )
+ , fDstPlanes (dstImage.Planes ())
+ , fDstPixelType (dstImage.PixelType ())
+
+ , fSrcRepeat (1, 1)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_filter_task::~dng_filter_task ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_filter_task::Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ dng_point srcTileSize = SrcTileSize (tileSize);
+
+ uint32 srcPixelSize = TagTypeSize (fSrcPixelType);
+
+ uint32 srcBufferSize = srcTileSize.v *
+ RoundUpForPixelSize (srcTileSize.h, srcPixelSize) *
+ srcPixelSize *
+ fSrcPlanes;
+
+ uint32 dstPixelSize = TagTypeSize (fDstPixelType);
+
+ uint32 dstBufferSize = tileSize.v *
+ RoundUpForPixelSize (tileSize.h, dstPixelSize) *
+ dstPixelSize *
+ fDstPlanes;
+
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
+ fSrcBuffer [threadIndex] . Reset (allocator->Allocate (srcBufferSize));
+
+ fDstBuffer [threadIndex] . Reset (allocator->Allocate (dstBufferSize));
+
+ // Zero buffers so any pad bytes have defined values.
+
+ DoZeroBytes (fSrcBuffer [threadIndex]->Buffer (),
+ fSrcBuffer [threadIndex]->LogicalSize ());
+
+ DoZeroBytes (fDstBuffer [threadIndex]->Buffer (),
+ fDstBuffer [threadIndex]->LogicalSize ());
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_filter_task::Process (uint32 threadIndex,
+ const dng_rect &area,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ // Find source area for this destination area.
+
+ dng_rect srcArea = SrcArea (area);
+
+ // Setup srcBuffer.
+
+ dng_pixel_buffer srcBuffer;
+
+ srcBuffer.fArea = srcArea;
+
+ srcBuffer.fPlane = fSrcPlane;
+ srcBuffer.fPlanes = fSrcPlanes;
+
+ srcBuffer.fPixelType = fSrcPixelType;
+ srcBuffer.fPixelSize = TagTypeSize (fSrcPixelType);
+
+ srcBuffer.fPlaneStep = RoundUpForPixelSize (srcArea.W (),
+ srcBuffer.fPixelSize);
+
+ srcBuffer.fRowStep = srcBuffer.fPlaneStep *
+ srcBuffer.fPlanes;
+
+ srcBuffer.fData = fSrcBuffer [threadIndex]->Buffer ();
+
+ // Setup dstBuffer.
+
+ dng_pixel_buffer dstBuffer;
+
+ dstBuffer.fArea = area;
+
+ dstBuffer.fPlane = fDstPlane;
+ dstBuffer.fPlanes = fDstPlanes;
+
+ dstBuffer.fPixelType = fDstPixelType;
+ dstBuffer.fPixelSize = TagTypeSize (fDstPixelType);
+
+ dstBuffer.fPlaneStep = RoundUpForPixelSize (area.W (),
+ dstBuffer.fPixelSize);
+
+ dstBuffer.fRowStep = dstBuffer.fPlaneStep *
+ dstBuffer.fPlanes;
+
+ dstBuffer.fData = fDstBuffer [threadIndex]->Buffer ();
+
+ // Get source pixels.
+
+ fSrcImage.Get (srcBuffer,
+ dng_image::edge_repeat,
+ fSrcRepeat.v,
+ fSrcRepeat.h);
+
+ // Process area.
+
+ ProcessArea (threadIndex,
+ srcBuffer,
+ dstBuffer);
+
+ // Save result pixels.
+
+ fDstImage.Put (dstBuffer);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_filter_task.h b/gpr/source/lib/dng_sdk/dng_filter_task.h
new file mode 100644
index 0000000..e5f932d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_filter_task.h
@@ -0,0 +1,157 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_filter_task.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Specialization of dng_area_task for processing an area from one dng_image to an
+ * area of another.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_filter_task__
+#define __dng_filter_task__
+
+/*****************************************************************************/
+
+#include "dng_area_task.h"
+#include "dng_auto_ptr.h"
+#include "dng_point.h"
+#include "dng_rect.h"
+#include "dng_sdk_limits.h"
+
+/*****************************************************************************/
+
+/// \brief Represents a task which filters an area of a source dng_image to an area
+/// of a destination dng_image.
+
+class dng_filter_task: public dng_area_task
+ {
+
+ protected:
+
+ const dng_image &fSrcImage;
+
+ dng_image &fDstImage;
+
+ uint32 fSrcPlane;
+ uint32 fSrcPlanes;
+ uint32 fSrcPixelType;
+
+ uint32 fDstPlane;
+ uint32 fDstPlanes;
+ uint32 fDstPixelType;
+
+ dng_point fSrcRepeat;
+
+ AutoPtr<dng_memory_block> fSrcBuffer [kMaxMPThreads];
+ AutoPtr<dng_memory_block> fDstBuffer [kMaxMPThreads];
+
+ public:
+
+ /// Construct a filter task given a source and destination images.
+ /// \param srcImage Image from which source pixels are read.
+ /// \param dstImage Image to which result pixels are written.
+
+ dng_filter_task (const dng_image &srcImage,
+ dng_image &dstImage);
+
+ virtual ~dng_filter_task ();
+
+ /// Compute the source area needed for a given destination area. Default
+ /// implementation assumes destination area is equal to source area for all
+ /// cases.
+ ///
+ /// \param dstArea Area to for which pixels will be computed.
+ ///
+ /// \retval The source area needed as input to calculate the requested
+ /// destination area.
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea)
+ {
+ return dstArea;
+ }
+
+ /// Given a destination tile size, calculate input tile size. Simlar to
+ /// SrcArea, and should seldom be overridden.
+ ///
+ /// \param dstTileSize The destination tile size that is targeted for output.
+ ///
+ /// \retval The source tile size needed to compute a tile of the destination
+ /// size.
+
+ virtual dng_point SrcTileSize (const dng_point &dstTileSize)
+ {
+ return SrcArea (dng_rect (dstTileSize)).Size ();
+ }
+
+ /// Implements filtering operation from one buffer to another. Source and
+ /// destination pixels are set up in member fields of this class. Ideally, no
+ /// allocation should be done in this routine.
+ ///
+ /// \param threadIndex The thread on which this routine is being called,
+ /// between 0 and threadCount - 1 for the threadCount passed to Start method.
+ ///
+ /// \param srcBuffer Input area and source pixels.
+ ///
+ /// \param dstBuffer Output area and destination pixels.
+
+ virtual void ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer) = 0;
+
+ /// Called prior to processing on specific threads. Can be used to allocate
+ /// per-thread memory buffers, etc.
+ ///
+ /// \param threadCount Total number of threads that will be used for
+ /// processing. Less than or equal to MaxThreads of dng_area_task.
+ ///
+ /// \param tileSize Size of source tiles which will be processed. (Not all
+ /// tiles will be this size due to edge conditions.)
+ ///
+ /// \param allocator dng_memory_allocator to use for allocating temporary
+ /// buffers, etc.
+ ///
+ /// \param sniffer Sniffer to test for user cancellation and to set up
+ /// progress.
+
+ virtual void Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer);
+
+ /// Process one tile or partitioned area. Should not be overridden. Instead,
+ /// override ProcessArea, which is where to implement filter processing for a
+ /// specific type of dng_filter_task. There is no allocator parameter as all
+ /// allocation should be done in Start.
+ ///
+ /// \param threadIndex 0 to threadCount - 1 index indicating which thread
+ /// this is. (Can be used to get a thread-specific buffer allocated in the
+ /// Start method.)
+ ///
+ /// \param area Size of tiles to be used for sizing buffers, etc. (Edges of
+ /// processing can be smaller.)
+ ///
+ /// \param sniffer dng_abort_sniffer to use to check for user cancellation
+ /// and progress updates.
+
+ virtual void Process (uint32 threadIndex,
+ const dng_rect &area,
+ dng_abort_sniffer *sniffer);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_fingerprint.cpp b/gpr/source/lib/dng_sdk/dng_fingerprint.cpp
new file mode 100644
index 0000000..5256873
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_fingerprint.cpp
@@ -0,0 +1,589 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_fingerprint.cpp#3 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_fingerprint.h"
+
+#include "dng_assertions.h"
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+dng_fingerprint::dng_fingerprint ()
+ {
+
+ for (uint32 j = 0; j < 16; j++)
+ {
+
+ data [j] = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_fingerprint::IsNull () const
+ {
+
+ for (uint32 j = 0; j < 16; j++)
+ {
+
+ if (data [j] != 0)
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_fingerprint::operator== (const dng_fingerprint &print) const
+ {
+
+ for (uint32 j = 0; j < 16; j++)
+ {
+
+ if (data [j] != print.data [j])
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+uint32 dng_fingerprint::Collapse32 () const
+ {
+
+ uint32 x = 0;
+
+ for (uint32 j = 0; j < 4; j++)
+ {
+
+ uint32 y = 0;
+
+ for (uint32 k = 0; k < 4; k++)
+ {
+
+ y = (y << 8) + (uint32) data [j * 4 + k];
+
+ }
+
+ x = x ^ y;
+
+ }
+
+ return x;
+
+ }
+
+/******************************************************************************/
+
+static char NumToHexChar (unsigned int c)
+ {
+
+ if (c < 10)
+ {
+ return (char) ('0' + c);
+ }
+
+ else
+ {
+ return (char) ('A' + c - 10);
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_fingerprint::ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const
+ {
+
+ for (size_t i = 0; i < kDNGFingerprintSize; i++)
+ {
+
+ unsigned char c = data [i];
+
+ resultStr [i * 2] = NumToHexChar (c >> 4);
+ resultStr [i * 2 + 1] = NumToHexChar (c & 15);
+
+ }
+
+ resultStr [kDNGFingerprintSize * 2] = '\0';
+
+ }
+
+/******************************************************************************/
+
+static int HexCharToNum (char hexChar)
+ {
+
+ if (hexChar >= '0' && hexChar <= '9')
+ {
+ return hexChar - '0';
+ }
+
+ else if (hexChar >= 'A' && hexChar <= 'F')
+ {
+ return hexChar - 'A' + 10;
+ }
+
+ else if (hexChar >= 'a' && hexChar <= 'f')
+ {
+ return hexChar - 'a' + 10;
+ }
+
+ return -1;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_fingerprint::FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1])
+ {
+
+ for (size_t i = 0; i < kDNGFingerprintSize; i++)
+ {
+
+ int highNibble = HexCharToNum (inputStr [i * 2]);
+
+ if (highNibble < 0)
+ {
+ return false;
+ }
+
+ int lowNibble = HexCharToNum (inputStr [i * 2 + 1]);
+
+ if (lowNibble < 0)
+ {
+ return false;
+ }
+
+ data [i] = (uint8) ((highNibble << 4) + lowNibble);
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
+
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+// rights reserved.
+//
+// License to copy and use this software is granted provided that it
+// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+// Algorithm" in all material mentioning or referencing this software
+// or this function.
+//
+// License is also granted to make and use derivative works provided
+// that such works are identified as "derived from the RSA Data
+// Security, Inc. MD5 Message-Digest Algorithm" in all material
+// mentioning or referencing the derived work.
+//
+// RSA Data Security, Inc. makes no representations concerning either
+// the merchantability of this software or the suitability of this
+// software for any particular purpose. It is provided "as is"
+// without express or implied warranty of any kind.
+//
+// These notices must be retained in any copies of any part of this
+// documentation and/or software.
+
+/******************************************************************************/
+
+dng_md5_printer::dng_md5_printer ()
+
+ : final (false)
+ , result ()
+
+ {
+
+ Reset ();
+
+ }
+
+/******************************************************************************/
+
+void dng_md5_printer::Reset ()
+ {
+
+ // No bits processed yet.
+
+ count [0] = 0;
+ count [1] = 0;
+
+ // Load magic initialization constants.
+
+ state [0] = 0x67452301;
+ state [1] = 0xefcdab89;
+ state [2] = 0x98badcfe;
+ state [3] = 0x10325476;
+
+ // Not finalized yet.
+
+ final = false;
+
+ }
+
+/******************************************************************************/
+
+void dng_md5_printer::Process (const void *data,
+ uint32 inputLen)
+ {
+
+ DNG_ASSERT (!final, "Fingerprint already finalized!");
+
+ const uint8 *input = (const uint8 *) data;
+
+ // Compute number of bytes mod 64
+
+ uint32 index = (count [0] >> 3) & 0x3F;
+
+ // Update number of bits
+
+ if ((count [0] += inputLen << 3) < (inputLen << 3))
+ {
+ count [1]++;
+ }
+
+ count [1] += inputLen >> 29;
+
+ // Transform as many times as possible.
+
+ uint32 i = 0;
+
+ uint32 partLen = 64 - index;
+
+ if (inputLen >= partLen)
+ {
+
+ memcpy (&buffer [index],
+ input,
+ partLen);
+
+ MD5Transform (state, buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ {
+
+ MD5Transform (state, &input [i]);
+
+ }
+
+ index = 0;
+
+ }
+
+ // Buffer remaining input
+
+ memcpy (&buffer [index],
+ &input [i],
+ inputLen - i);
+
+ }
+
+/******************************************************************************/
+
+const dng_fingerprint & dng_md5_printer::Result ()
+ {
+
+ if (!final)
+ {
+
+ static uint8 PADDING [64] =
+ {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ // Save number of bits
+
+ uint8 bits [8];
+
+ Encode (bits, count, 8);
+
+ // Pad out to 56 mod 64.
+
+ uint32 index = (count [0] >> 3) & 0x3f;
+
+ uint32 padLen = (index < 56) ? (56 - index) : (120 - index);
+
+ Process (PADDING, padLen);
+
+ // Append length (before padding)
+
+ Process (bits, 8);
+
+ // Store state in digest
+
+ Encode (result.data, state, 16);
+
+ // We are now finalized.
+
+ final = true;
+
+ }
+
+ return result;
+
+ }
+
+/******************************************************************************/
+
+// Encodes input (uint32) into output (uint8). Assumes len is
+// a multiple of 4.
+
+void dng_md5_printer::Encode (uint8 *output,
+ const uint32 *input,
+ uint32 len)
+ {
+
+ uint32 i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+ output [j ] = (uint8) ((input [i] ) & 0xff);
+ output [j+1] = (uint8) ((input [i] >> 8) & 0xff);
+ output [j+2] = (uint8) ((input [i] >> 16) & 0xff);
+ output [j+3] = (uint8) ((input [i] >> 24) & 0xff);
+ }
+
+ }
+
+/******************************************************************************/
+
+// Decodes input (uint8) into output (uint32). Assumes len is
+// a multiple of 4.
+
+void dng_md5_printer::Decode (uint32 *output,
+ const uint8 *input,
+ uint32 len)
+ {
+
+ // Check for non-aligned case.
+
+ if (((uintptr) input) & 3)
+ {
+
+ uint32 i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ {
+
+ output [i] = (((uint32) input [j ]) ) |
+ (((uint32) input [j+1]) << 8) |
+ (((uint32) input [j+2]) << 16) |
+ (((uint32) input [j+3]) << 24);
+
+ }
+
+ }
+
+ // Else use optimized code for aligned case.
+
+ else
+ {
+
+ len = len >> 2;
+
+ const uint32 *sPtr = (const uint32 *) input;
+
+ uint32 *dPtr = output;
+
+ while (len--)
+ {
+
+ #if qDNGBigEndian
+
+ uint32 data = *(sPtr++);
+
+ data = (data >> 24) |
+ ((data >> 8) & 0x0000FF00) |
+ ((data << 8) & 0x00FF0000) |
+ (data << 24);
+
+ *(dPtr++) = data;
+
+ #else
+
+ *(dPtr++) = *(sPtr++);
+
+ #endif
+
+ }
+
+ }
+
+ }
+
+/******************************************************************************/
+
+// MD5 basic transformation. Transforms state based on block.
+
+void dng_md5_printer::MD5Transform (uint32 state [4],
+ const uint8 block [64])
+ {
+
+ enum
+ {
+ S11 = 7,
+ S12 = 12,
+ S13 = 17,
+ S14 = 22,
+ S21 = 5,
+ S22 = 9,
+ S23 = 14,
+ S24 = 20,
+ S31 = 4,
+ S32 = 11,
+ S33 = 16,
+ S34 = 23,
+ S41 = 6,
+ S42 = 10,
+ S43 = 15,
+ S44 = 21
+ };
+
+ #if qDNGBigEndian
+
+ uint32 x [16];
+
+ Decode (x, block, 64);
+
+ #else
+
+ uint32 temp [16];
+
+ const uint32 *x;
+
+ if (((uintptr) block) & 3)
+ {
+
+ Decode (temp, block, 64);
+
+ x = temp;
+
+ }
+
+ else
+ x = (const uint32 *) block;
+
+ #endif
+
+ uint32 a = state [0];
+ uint32 b = state [1];
+ uint32 c = state [2];
+ uint32 d = state [3];
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state [0] += a;
+ state [1] += b;
+ state [2] += c;
+ state [3] += d;
+
+ }
+
+/*****************************************************************************/
+
+// End of RSA Data Security, Inc. derived code.
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_fingerprint.h b/gpr/source/lib/dng_sdk/dng_fingerprint.h
new file mode 100644
index 0000000..b8c5cfb
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_fingerprint.h
@@ -0,0 +1,377 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_fingerprint.h#2 $ */
+/* $DateTime: 2012/07/11 10:36:56 $ */
+/* $Change: 838485 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Fingerprint (cryptographic hashing) support for generating strong hashes of image
+ * data.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_fingerprint__
+#define __dng_fingerprint__
+
+/*****************************************************************************/
+
+#include "dng_exceptions.h"
+#include "dng_types.h"
+#include "dng_stream.h"
+
+#include <cstring>
+
+/*****************************************************************************/
+
+/// \brief Container fingerprint (MD5 only at present).
+
+class dng_fingerprint
+ {
+
+ public:
+
+ static const size_t kDNGFingerprintSize = 16;
+
+ uint8 data [kDNGFingerprintSize];
+
+ public:
+
+ dng_fingerprint ();
+
+ /// Check if fingerprint is all zeros.
+
+ bool IsNull () const;
+
+ /// Same as IsNull but expresses intention of testing validity.
+
+ bool IsValid () const
+ {
+ return !IsNull ();
+ }
+
+ /// Set to all zeros, a value used to indicate an invalid fingerprint.
+
+ void Clear ()
+ {
+ *this = dng_fingerprint ();
+ }
+
+ /// Test if two fingerprints are equal.
+
+ bool operator== (const dng_fingerprint &print) const;
+
+ /// Test if two fingerprints are not equal.
+
+ bool operator!= (const dng_fingerprint &print) const
+ {
+ return !(*this == print);
+ }
+
+ /// Produce a 32-bit hash value from fingerprint used for faster hashing of
+ /// fingerprints.
+
+ uint32 Collapse32 () const;
+
+ /// Convert fingerprint to UTF-8 string.
+ ///
+ /// \param resultStr The output array to which the UTF-8 encoding of the
+ /// fingerprint will be written.
+
+ void ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const;
+
+ /// Convert UTF-8 string to fingerprint. Returns true on success, false on
+ /// failure.
+ ///
+ /// \param inputStr The input array from which the UTF-8 encoding of the
+ /// fingerprint will be read.
+ ///
+ /// \retval True indicates success.
+
+ bool FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1]);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Utility to compare fingerprints (e.g., for sorting).
+
+struct dng_fingerprint_less_than
+ {
+
+ /// Less-than comparison.
+
+ bool operator() (const dng_fingerprint &a,
+ const dng_fingerprint &b) const
+ {
+
+ return memcmp (a.data,
+ b.data,
+ sizeof (a.data)) < 0;
+
+ }
+
+ };
+
+/******************************************************************************/
+
+// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
+
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+// rights reserved.
+//
+// License to copy and use this software is granted provided that it
+// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+// Algorithm" in all material mentioning or referencing this software
+// or this function.
+//
+// License is also granted to make and use derivative works provided
+// that such works are identified as "derived from the RSA Data
+// Security, Inc. MD5 Message-Digest Algorithm" in all material
+// mentioning or referencing the derived work.
+//
+// RSA Data Security, Inc. makes no representations concerning either
+// the merchantability of this software or the suitability of this
+// software for any particular purpose. It is provided "as is"
+// without express or implied warranty of any kind.
+//
+// These notices must be retained in any copies of any part of this
+// documentation and/or software.
+
+/// \brief Class to hash binary data to a fingerprint using the MD5 Message-Digest
+/// Algorithm.
+
+class dng_md5_printer
+ {
+
+ public:
+
+ dng_md5_printer ();
+
+ virtual ~dng_md5_printer ()
+ {
+ }
+
+ /// Reset the fingerprint.
+
+ void Reset ();
+
+ /// Append the data to the stream to be hashed.
+ /// \param data The data to be hashed.
+ /// \param inputLen The length of data, in bytes.
+
+ void Process (const void *data,
+ uint32 inputLen);
+
+ /// Append the string to the stream to be hashed.
+ /// \param text The string to be hashed.
+
+ void Process (const char *text)
+ {
+
+ Process (text, (uint32) strlen (text));
+
+ }
+
+ /// Get the fingerprint (i.e., result of the hash).
+
+ const dng_fingerprint & Result ();
+
+ private:
+
+ static void Encode (uint8 *output,
+ const uint32 *input,
+ uint32 len);
+
+ static void Decode (uint32 *output,
+ const uint8 *input,
+ uint32 len);
+
+ // F, G, H and I are basic MD5 functions.
+
+ static inline uint32 F (uint32 x,
+ uint32 y,
+ uint32 z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ static inline uint32 G (uint32 x,
+ uint32 y,
+ uint32 z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ static inline uint32 H (uint32 x,
+ uint32 y,
+ uint32 z)
+ {
+ return x ^ y ^ z;
+ }
+
+ static inline uint32 I (uint32 x,
+ uint32 y,
+ uint32 z)
+ {
+ return y ^ (x | ~z);
+ }
+
+ // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+
+ static inline void FF (uint32 &a,
+ uint32 b,
+ uint32 c,
+ uint32 d,
+ uint32 x,
+ uint32 s,
+ uint32 ac)
+ {
+ a += F (b, c, d) + x + ac;
+ a = (a << s) | (a >> (32 - s));
+ a += b;
+ }
+
+ static inline void GG (uint32 &a,
+ uint32 b,
+ uint32 c,
+ uint32 d,
+ uint32 x,
+ uint32 s,
+ uint32 ac)
+ {
+ a += G (b, c, d) + x + ac;
+ a = (a << s) | (a >> (32 - s));
+ a += b;
+ }
+
+ static inline void HH (uint32 &a,
+ uint32 b,
+ uint32 c,
+ uint32 d,
+ uint32 x,
+ uint32 s,
+ uint32 ac)
+ {
+ a += H (b, c, d) + x + ac;
+ a = (a << s) | (a >> (32 - s));
+ a += b;
+ }
+
+ static inline void II (uint32 &a,
+ uint32 b,
+ uint32 c,
+ uint32 d,
+ uint32 x,
+ uint32 s,
+ uint32 ac)
+ {
+ a += I (b, c, d) + x + ac;
+ a = (a << s) | (a >> (32 - s));
+ a += b;
+ }
+
+ static void MD5Transform (uint32 state [4],
+ const uint8 block [64]);
+
+ private:
+
+ uint32 state [4];
+
+ uint32 count [2];
+
+ uint8 buffer [64];
+
+ bool final;
+
+ dng_fingerprint result;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A dng_stream based interface to the MD5 printing logic.
+
+class dng_md5_printer_stream : public dng_stream, dng_md5_printer
+ {
+
+ private:
+
+ uint64 fNextOffset;
+
+ public:
+
+ /// Create an empty MD5 printer stream.
+
+ dng_md5_printer_stream ()
+
+ : fNextOffset (0)
+
+ {
+ }
+
+ virtual uint64 DoGetLength ()
+ {
+
+ return fNextOffset;
+
+ }
+
+ virtual void DoRead (void * /* data */,
+ uint32 /* count */,
+ uint64 /* offset */)
+ {
+
+ ThrowProgramError ();
+
+ }
+
+ virtual void DoSetLength (uint64 length)
+ {
+
+ if (length != fNextOffset)
+ {
+ ThrowProgramError ();
+ }
+
+ }
+
+ virtual void DoWrite (const void *data,
+ uint32 count2,
+ uint64 offset)
+ {
+
+ if (offset != fNextOffset)
+ {
+ ThrowProgramError ();
+ }
+
+ Process (data, count2);
+
+ fNextOffset += count2;
+
+ }
+
+ const dng_fingerprint & Result ()
+ {
+
+ Flush ();
+
+ return dng_md5_printer::Result ();
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_flags.h b/gpr/source/lib/dng_sdk/dng_flags.h
new file mode 100644
index 0000000..b0ab558
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_flags.h
@@ -0,0 +1,267 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_flags.h#5 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Conditional compilation flags for DNG SDK.
+ *
+ * All conditional compilation macros for the DNG SDK begin with a lowercase 'q'.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_flags__
+#define __dng_flags__
+
+#define METADATA_CLEANUP 0
+
+#include "gpr_platform.h"
+
+/*****************************************************************************/
+
+/// \def qMacOS
+/// 1 if compiling for Mac OS X.
+
+/// \def qWinOS
+/// 1 if compiling for Windows.
+
+// Make sure qMacOS and qWinOS are defined.
+
+#if !defined(qMacOS) && !defined(qWinOS)
+#include "RawEnvironment.h"
+#endif
+
+#if !defined(qMacOS) && !defined(qWinOS)
+#error Unable to figure out platform
+#endif
+
+
+/*****************************************************************************/
+
+// Platforms.
+
+#ifndef qImagecore
+#define qImagecore 0
+#endif
+
+#ifndef qiPhone
+#define qiPhone 0
+#endif
+
+#ifndef qiPhoneSimulator
+#define qiPhoneSimulator 0
+#endif
+
+#ifndef qAndroid
+#define qAndroid 0
+#endif
+
+#ifndef qAndroidArm7
+#define qAndroidArm7 0
+#endif
+
+/*****************************************************************************/
+
+// Establish WIN32 and WIN64 definitions.
+
+#if defined(_WIN32) && !defined(WIN32)
+#define WIN32 1
+#endif
+
+#if defined(_WIN64) && !defined(WIN64)
+#define WIN64 1
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGDebug
+/// 1 if debug code is compiled in, 0 otherwise. Enables assertions and other debug
+/// checks in exchange for slower processing.
+
+// Figure out if debug build or not.
+
+#ifndef qDNGDebug
+
+#if defined(Debug)
+#define qDNGDebug Debug
+
+#elif defined(_DEBUG)
+#define qDNGDebug _DEBUG
+
+#else
+#define qDNGDebug 0
+
+#endif
+#endif
+
+/*****************************************************************************/
+
+// Figure out byte order.
+
+/// \def qDNGBigEndian
+/// 1 if this target platform is big endian (e.g. PowerPC Macintosh), else 0.
+///
+/// \def qDNGLittleEndian
+/// 1 if this target platform is little endian (e.g. x86 processors), else 0.
+
+#ifndef qDNGBigEndian
+
+#if defined(qDNGLittleEndian)
+#define qDNGBigEndian !qDNGLittleEndian
+
+#elif defined(__POWERPC__)
+#define qDNGBigEndian 1
+
+#elif defined(__INTEL__)
+#define qDNGBigEndian 0
+
+#elif defined(_M_IX86)
+#define qDNGBigEndian 0
+
+#elif defined(_M_X64) || defined(__amd64__)
+#define qDNGBigEndian 0
+
+#elif defined(__LITTLE_ENDIAN__)
+#define qDNGBigEndian 0
+
+#elif defined(__BIG_ENDIAN__)
+#define qDNGBigEndian 1
+
+#elif defined(_ARM_)
+#define qDNGBigEndian 0
+
+#else
+
+#ifndef qXCodeRez
+#error Unable to figure out byte order.
+#endif
+
+#endif
+#endif
+
+#ifndef qXCodeRez
+
+#ifndef qDNGLittleEndian
+#define qDNGLittleEndian !qDNGBigEndian
+#endif
+
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNG64Bit
+/// 1 if this target platform uses 64-bit addresses, 0 otherwise.
+
+#ifndef qDNG64Bit
+
+#if qMacOS
+
+#ifdef __LP64__
+#if __LP64__
+#define qDNG64Bit 1
+#endif
+#endif
+
+#elif qWinOS
+
+#ifdef WIN64
+#if WIN64
+#define qDNG64Bit 1
+#endif
+#endif
+
+#endif
+
+#ifndef qDNG64Bit
+#define qDNG64Bit 0
+#endif
+
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGThreadSafe
+/// 1 if target platform has thread support and threadsafe libraries, 0 otherwise.
+
+#ifndef qDNGThreadSafe
+#define qDNGThreadSafe (qMacOS || qWinOS)
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGValidateTarget
+/// 1 if dng_validate command line tool is being built, 0 otherwise.
+
+#ifndef qDNGValidateTarget
+#define qDNGValidateTarget 0
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGValidate
+/// 1 if DNG validation code is enabled, 0 otherwise.
+
+#ifndef qDNGValidate
+#define qDNGValidate qDNGValidateTarget
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGPrintMessages
+/// 1 if dng_show_message should use fprintf to stderr. 0 if it should use a platform
+/// specific interrupt mechanism.
+
+#ifndef qDNGPrintMessages
+#define qDNGPrintMessages qDNGValidate
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGCodec
+/// 1 to build the Windows Imaging Component Codec (e.g. for Vista).
+
+#ifndef qDNGCodec
+#define qDNGCodec 0
+#endif
+
+/*****************************************************************************/
+
+// Experimental features -- work in progress for Lightroom 4.0 and Camera Raw 7.0.
+// Turn this off for Lightroom 3.x & Camera Raw 6.x dot releases.
+
+#ifndef qDNGExperimental
+#define qDNGExperimental 1
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGXMPFiles
+/// 1 to use XMPFiles.
+
+#ifndef qDNGXMPFiles
+#define qDNGXMPFiles 0
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGXMPDocOps
+/// 1 to use XMPDocOps.
+
+#ifndef qDNGXMPDocOps
+#define qDNGXMPDocOps 0
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_gain_map.cpp b/gpr/source/lib/dng_sdk/dng_gain_map.cpp
new file mode 100644
index 0000000..48114eb
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_gain_map.cpp
@@ -0,0 +1,582 @@
+/*****************************************************************************/
+// Copyright 2008-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_gain_map.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_gain_map.h"
+
+#include "dng_exceptions.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_pixel_buffer.h"
+#include "dng_stream.h"
+#include "dng_tag_values.h"
+
+/*****************************************************************************/
+
+class dng_gain_map_interpolator
+ {
+
+ private:
+
+ const dng_gain_map &fMap;
+
+ dng_point_real64 fScale;
+ dng_point_real64 fOffset;
+
+ int32 fColumn;
+ int32 fPlane;
+
+ uint32 fRowIndex1;
+ uint32 fRowIndex2;
+ real32 fRowFract;
+
+ int32 fResetColumn;
+
+ real32 fValueBase;
+ real32 fValueStep;
+ real32 fValueIndex;
+
+ public:
+
+ dng_gain_map_interpolator (const dng_gain_map &map,
+ const dng_rect &mapBounds,
+ int32 row,
+ int32 column,
+ uint32 plane);
+
+ real32 Interpolate () const
+ {
+
+ return fValueBase + fValueStep * fValueIndex;
+
+ }
+
+ void Increment ()
+ {
+
+ if (++fColumn >= fResetColumn)
+ {
+
+ ResetColumn ();
+
+ }
+
+ else
+ {
+
+ fValueIndex += 1.0f;
+
+ }
+
+ }
+
+ private:
+
+ real32 InterpolateEntry (uint32 colIndex);
+
+ void ResetColumn ();
+
+ };
+
+/*****************************************************************************/
+
+dng_gain_map_interpolator::dng_gain_map_interpolator (const dng_gain_map &map,
+ const dng_rect &mapBounds,
+ int32 row,
+ int32 column,
+ uint32 plane)
+
+ : fMap (map)
+
+ , fScale (1.0 / mapBounds.H (),
+ 1.0 / mapBounds.W ())
+
+ , fOffset (0.5 - mapBounds.t,
+ 0.5 - mapBounds.l)
+
+ , fColumn (column)
+ , fPlane (plane)
+
+ , fRowIndex1 (0)
+ , fRowIndex2 (0)
+ , fRowFract (0.0f)
+
+ , fResetColumn (0)
+
+ , fValueBase (0.0f)
+ , fValueStep (0.0f)
+ , fValueIndex (0.0f)
+
+ {
+
+ real64 rowIndexF = (fScale.v * (row + fOffset.v) -
+ fMap.Origin ().v) / fMap.Spacing ().v;
+
+ if (rowIndexF <= 0.0)
+ {
+
+ fRowIndex1 = 0;
+ fRowIndex2 = 0;
+
+ fRowFract = 0.0f;
+
+ }
+
+ else
+ {
+
+ fRowIndex1 = (uint32) rowIndexF;
+
+ if ((int32) fRowIndex1 >= fMap.Points ().v - 1)
+ {
+
+ fRowIndex1 = fMap.Points ().v - 1;
+ fRowIndex2 = fRowIndex1;
+
+ fRowFract = 0.0f;
+
+ }
+
+ else
+ {
+
+ fRowIndex2 = fRowIndex1 + 1;
+
+ fRowFract = (real32) (rowIndexF - (real64) fRowIndex1);
+
+ }
+
+ }
+
+ ResetColumn ();
+
+ }
+
+/*****************************************************************************/
+
+real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex)
+ {
+
+ return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) +
+ fMap.Entry (fRowIndex2, colIndex, fPlane) * ( fRowFract);
+
+ }
+
+/*****************************************************************************/
+
+void dng_gain_map_interpolator::ResetColumn ()
+ {
+
+ real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) -
+ fMap.Origin ().h) / fMap.Spacing ().h;
+
+ if (colIndexF <= 0.0)
+ {
+
+ fValueBase = InterpolateEntry (0);
+
+ fValueStep = 0.0f;
+
+ fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h);
+
+ }
+
+ else
+ {
+
+ uint32 colIndex = (uint32) colIndexF;
+
+ if ((int32) colIndex >= fMap.Points ().h - 1)
+ {
+
+ fValueBase = InterpolateEntry (fMap.Points ().h - 1);
+
+ fValueStep = 0.0f;
+
+ fResetColumn = 0x7FFFFFFF;
+
+ }
+
+ else
+ {
+
+ real64 base = InterpolateEntry (colIndex);
+ real64 delta = InterpolateEntry (colIndex + 1) - base;
+
+ fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex));
+
+ fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h);
+
+ fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h +
+ fMap.Origin ().h) / fScale.h - fOffset.h);
+
+ }
+
+ }
+
+ fValueIndex = 0.0f;
+
+ }
+
+/*****************************************************************************/
+
+dng_gain_map::dng_gain_map (dng_memory_allocator &allocator,
+ const dng_point &points,
+ const dng_point_real64 &spacing,
+ const dng_point_real64 &origin,
+ uint32 planes)
+
+ : fPoints (points)
+ , fSpacing (spacing)
+ , fOrigin (origin)
+ , fPlanes (planes)
+
+ , fRowStep (planes * points.h)
+
+ , fBuffer ()
+
+ {
+
+ fBuffer.Reset (allocator.Allocate (fPoints.v *
+ fPoints.h *
+ fPlanes * (uint32) sizeof (real32)));
+
+ }
+
+/*****************************************************************************/
+
+real32 dng_gain_map::Interpolate (int32 row,
+ int32 col,
+ uint32 plane,
+ const dng_rect &bounds) const
+ {
+
+ dng_gain_map_interpolator interp (*this,
+ bounds,
+ row,
+ col,
+ plane);
+
+ return interp.Interpolate ();
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_gain_map::PutStreamSize () const
+ {
+
+ return 44 + fPoints.v * fPoints.h * fPlanes * 4;
+
+ }
+
+/*****************************************************************************/
+
+void dng_gain_map::PutStream (dng_stream &stream) const
+ {
+
+ stream.Put_uint32 (fPoints.v);
+ stream.Put_uint32 (fPoints.h);
+
+ stream.Put_real64 (fSpacing.v);
+ stream.Put_real64 (fSpacing.h);
+
+ stream.Put_real64 (fOrigin.v);
+ stream.Put_real64 (fOrigin.h);
+
+ stream.Put_uint32 (fPlanes);
+
+ for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++)
+ {
+
+ for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++)
+ {
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ stream.Put_real32 (Entry (rowIndex,
+ colIndex,
+ plane));
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_gain_map * dng_gain_map::GetStream (dng_stream &stream, dng_memory_allocator &allocator)
+ {
+
+ dng_point mapPoints;
+
+ mapPoints.v = stream.Get_uint32 ();
+ mapPoints.h = stream.Get_uint32 ();
+
+ dng_point_real64 mapSpacing;
+
+ mapSpacing.v = stream.Get_real64 ();
+ mapSpacing.h = stream.Get_real64 ();
+
+ dng_point_real64 mapOrigin;
+
+ mapOrigin.v = stream.Get_real64 ();
+ mapOrigin.h = stream.Get_real64 ();
+
+ uint32 mapPlanes = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Points: v=%d, h=%d\n",
+ (int) mapPoints.v,
+ (int) mapPoints.h);
+
+ printf ("Spacing: v=%.6f, h=%.6f\n",
+ mapSpacing.v,
+ mapSpacing.h);
+
+ printf ("Origin: v=%.6f, h=%.6f\n",
+ mapOrigin.v,
+ mapOrigin.h);
+
+ printf ("Planes: %u\n",
+ (unsigned) mapPlanes);
+
+ }
+
+ #endif
+
+ if (mapPoints.v == 1)
+ {
+ mapSpacing.v = 1.0;
+ mapOrigin.v = 0.0;
+ }
+
+ if (mapPoints.h == 1)
+ {
+ mapSpacing.h = 1.0;
+ mapOrigin.h = 0.0;
+ }
+
+ if (mapPoints.v < 1 ||
+ mapPoints.h < 1 ||
+ mapSpacing.v <= 0.0 ||
+ mapSpacing.h <= 0.0 ||
+ mapPlanes < 1)
+ {
+ ThrowBadFormat ();
+ }
+
+ AutoPtr<dng_gain_map> map (new dng_gain_map (allocator,
+ mapPoints,
+ mapSpacing,
+ mapOrigin,
+ mapPlanes));
+
+ #if qDNGValidate
+
+ uint32 linesPrinted = 0;
+ uint32 linesSkipped = 0;
+
+ #endif
+
+ for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++)
+ {
+
+ for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++)
+ {
+
+ for (uint32 plane = 0; plane < mapPlanes; plane++)
+ {
+
+ real32 x = stream.Get_real32 ();
+
+ map->Entry (rowIndex, colIndex, plane) = x;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ if (linesPrinted < gDumpLineLimit)
+ {
+
+ printf (" Map [%3u] [%3u] [%u] = %.4f\n",
+ (unsigned) rowIndex,
+ (unsigned) colIndex,
+ (unsigned) plane,
+ x);
+
+ linesPrinted++;
+
+ }
+
+ else
+ linesSkipped++;
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (linesSkipped)
+ {
+
+ printf (" ... %u map entries skipped\n", (unsigned) linesSkipped);
+
+ }
+
+ #endif
+
+ return map.Release ();
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec,
+ AutoPtr<dng_gain_map> &gainMap)
+
+ : dng_inplace_opcode (dngOpcode_GainMap,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+
+ , fGainMap ()
+
+ {
+
+ fGainMap.Reset (gainMap.Release ());
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host,
+ dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_GainMap,
+ stream,
+ "GainMap")
+
+ , fAreaSpec ()
+
+ , fGainMap ()
+
+ {
+
+ uint32 byteCount = stream.Get_uint32 ();
+
+ uint64 startPosition = stream.Position ();
+
+ fAreaSpec.GetData (stream);
+
+ fGainMap.Reset (dng_gain_map::GetStream (stream, host.Allocator()));
+
+ if (stream.Position () != startPosition + byteCount)
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_GainMap::PutData (dng_stream &stream) const
+ {
+
+ stream.Put_uint32 (dng_area_spec::kDataSize +
+ fGainMap->PutStreamSize ());
+
+ fAreaSpec.PutData (stream);
+
+ fGainMap->PutStream (stream);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_GainMap::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ uint32 cols = overlap.W ();
+
+ uint32 colPitch = fAreaSpec.ColPitch ();
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1);
+
+ for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
+ {
+
+ real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
+
+ dng_gain_map_interpolator interp (*fGainMap,
+ imageBounds,
+ row,
+ overlap.l,
+ mapPlane);
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 gain = interp.Interpolate ();
+
+ dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f);
+
+ for (uint32 j = 0; j < colPitch; j++)
+ {
+ interp.Increment ();
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_gain_map.h b/gpr/source/lib/dng_sdk/dng_gain_map.h
new file mode 100644
index 0000000..f13cde1
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_gain_map.h
@@ -0,0 +1,218 @@
+/*****************************************************************************/
+// Copyright 2008-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_gain_map.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Opcode to fix 2D uniformity defects, such as shading.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_gain_map__
+#define __dng_gain_map__
+
+/*****************************************************************************/
+
+#include "dng_memory.h"
+#include "dng_misc_opcodes.h"
+#include "dng_tag_types.h"
+
+/*****************************************************************************/
+
+/// \brief Holds a discrete (i.e., sampled) 2D representation of a gain map. This is
+/// effectively an image containing scale factors.
+
+class dng_gain_map
+ {
+
+ private:
+
+ dng_point fPoints;
+
+ dng_point_real64 fSpacing;
+
+ dng_point_real64 fOrigin;
+
+ uint32 fPlanes;
+
+ uint32 fRowStep;
+
+ AutoPtr<dng_memory_block> fBuffer;
+
+ public:
+
+ /// Construct a gain map with the specified memory allocator, number of
+ /// samples (points), sample spacing, origin, and number of color planes.
+
+ dng_gain_map (dng_memory_allocator &allocator,
+ const dng_point &points,
+ const dng_point_real64 &spacing,
+ const dng_point_real64 &origin,
+ uint32 planes);
+
+ /// The number of samples in the horizontal and vertical directions.
+
+ const dng_point & Points () const
+ {
+ return fPoints;
+ }
+
+ /// The space between adjacent samples in the horizontal and vertical
+ /// directions.
+
+ const dng_point_real64 & Spacing () const
+ {
+ return fSpacing;
+ }
+
+ /// The 2D coordinate for the first (i.e., top-left-most) sample.
+
+ const dng_point_real64 & Origin () const
+ {
+ return fOrigin;
+ }
+
+ /// The number of color planes.
+
+ uint32 Planes () const
+ {
+ return fPlanes;
+ }
+
+ /// Getter for a gain map sample (specified by row, column, and plane).
+
+ real32 & Entry (uint32 rowIndex,
+ uint32 colIndex,
+ uint32 plane)
+ {
+
+ return *(fBuffer->Buffer_real32 () +
+ rowIndex * fRowStep +
+ colIndex * fPlanes +
+ plane);
+
+ }
+
+ /// Getter for a gain map sample (specified by row index, column index, and
+ /// plane index).
+
+ const real32 & Entry (uint32 rowIndex,
+ uint32 colIndex,
+ uint32 plane) const
+ {
+
+ return *(fBuffer->Buffer_real32 () +
+ rowIndex * fRowStep +
+ colIndex * fPlanes +
+ plane);
+
+ }
+
+ /// Compute the interpolated gain (i.e., scale factor) at the specified pixel
+ /// position and color plane, within the specified image bounds (in pixels).
+
+ real32 Interpolate (int32 row,
+ int32 col,
+ uint32 plane,
+ const dng_rect &bounds) const;
+
+ /// The number of bytes needed to hold the gain map data.
+
+ uint32 PutStreamSize () const;
+
+ /// Write the gain map to the specified stream.
+
+ void PutStream (dng_stream &stream) const;
+
+ /// Read a gain map from the specified stream.
+
+ static dng_gain_map * GetStream (dng_stream &stream, dng_memory_allocator &allocator);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_gain_map (const dng_gain_map &map);
+
+ dng_gain_map & operator= (const dng_gain_map &map);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to fix 2D spatially-varying light falloff or color casts (i.e.,
+/// uniformity issues). This is commonly due to shading.
+
+class dng_opcode_GainMap: public dng_inplace_opcode
+ {
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ AutoPtr<dng_gain_map> fGainMap;
+
+ public:
+
+ /// Construct a GainMap opcode for the specified image area and the specified
+ /// gain map.
+
+ dng_opcode_GainMap (const dng_area_spec &areaSpec,
+ AutoPtr<dng_gain_map> &gainMap);
+
+ /// Construct a GainMap opcode from the specified stream.
+
+ dng_opcode_GainMap (dng_host &host,
+ dng_stream &stream);
+
+ /// Write the opcode to the specified stream.
+
+ virtual void PutData (dng_stream &stream) const;
+
+ /// The pixel data type of this opcode.
+
+ virtual uint32 BufferPixelType (uint32 /* imagePixelType */)
+ {
+ return ttFloat;
+ }
+
+ /// The adjusted bounds (processing area) of this opcode. It is limited to
+ /// the intersection of the specified image area and the GainMap area.
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds)
+ {
+ return fAreaSpec.Overlap (imageBounds);
+ }
+
+ /// Apply the gain map.
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_opcode_GainMap (const dng_opcode_GainMap &opcode);
+
+ dng_opcode_GainMap & operator= (const dng_opcode_GainMap &opcode);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_globals.cpp b/gpr/source/lib/dng_sdk/dng_globals.cpp
new file mode 100644
index 0000000..b279295
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_globals.cpp
@@ -0,0 +1,28 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_globals.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_globals.h"
+
+/*****************************************************************************/
+
+#if qDNGValidate
+
+bool gVerbose = false;
+
+uint32 gDumpLineLimit = 100;
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_globals.h b/gpr/source/lib/dng_sdk/dng_globals.h
new file mode 100644
index 0000000..ad48017
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_globals.h
@@ -0,0 +1,46 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_globals.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Definitions of global variables controling DNG SDK behavior. Currenntly only used for validation control.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_globals__
+#define __dng_globals__
+
+/*****************************************************************************/
+
+#include "dng_flags.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+#if qDNGValidate
+
+/// When validation (qValidate) is turned on, this globale enables verbose output about DNG tags and other properties.
+
+extern bool gVerbose;
+
+/// When validation (qValidate) is turned on, and verbose mode (gVerbose) is enabled, limits the number of lines of text that are dumped for each tag.
+
+extern uint32 gDumpLineLimit;
+
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_host.cpp b/gpr/source/lib/dng_sdk/dng_host.cpp
new file mode 100644
index 0000000..91ebdc0
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_host.cpp
@@ -0,0 +1,539 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_host.cpp#2 $ */
+/* $DateTime: 2012/06/14 20:24:41 $ */
+/* $Change: 835078 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_host.h"
+
+#include "dng_abort_sniffer.h"
+#include "dng_area_task.h"
+#include "dng_bad_pixels.h"
+#include "dng_exceptions.h"
+#include "dng_exif.h"
+#include "dng_gain_map.h"
+#include "dng_ifd.h"
+#include "dng_lens_correction.h"
+#include "dng_memory.h"
+#include "dng_misc_opcodes.h"
+#include "dng_negative.h"
+#include "dng_resample.h"
+#include "dng_shared.h"
+#include "dng_simple_image.h"
+#include "dng_xmp.h"
+
+/*****************************************************************************/
+
+dng_host::dng_host (dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer)
+
+ : fAllocator (allocator)
+ , fSniffer (sniffer)
+
+ , fNeedsMeta (true)
+ , fNeedsImage (true)
+ , fForPreview (false)
+ , fMinimumSize (0)
+ , fPreferredSize (0)
+ , fMaximumSize (0)
+ , fCropFactor (1.0)
+ , fSaveDNGVersion (dngVersion_None)
+ , fSaveLinearDNG (false)
+ , fKeepOriginalFile (false)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_host::~dng_host ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_allocator & dng_host::Allocator ()
+ {
+
+ if (fAllocator)
+ {
+
+ return *fAllocator;
+
+ }
+
+ else
+ {
+
+ return gDefaultDNGMemoryAllocator;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_host::Allocate (uint32 logicalSize)
+ {
+
+ return Allocator ().Allocate (logicalSize);
+
+ }
+
+/*****************************************************************************/
+
+void dng_host::SniffForAbort ()
+ {
+
+ dng_abort_sniffer::SniffForAbort (Sniffer ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_host::ValidateSizes ()
+ {
+
+ // The maximum size limits the other two sizes.
+
+ if (MaximumSize ())
+ {
+ SetMinimumSize (Min_uint32 (MinimumSize (), MaximumSize ()));
+ SetPreferredSize (Min_uint32 (PreferredSize (), MaximumSize ()));
+ }
+
+ // If we have a preferred size, it limits the minimum size.
+
+ if (PreferredSize ())
+ {
+ SetMinimumSize (Min_uint32 (MinimumSize (), PreferredSize ()));
+ }
+
+ // Else find default value for preferred size.
+
+ else
+ {
+
+ // If preferred size is zero, then we want the maximim
+ // size image.
+
+ if (MaximumSize ())
+ {
+ SetPreferredSize (MaximumSize ());
+ }
+
+ }
+
+ // If we don't have a minimum size, find default.
+
+ if (!MinimumSize ())
+ {
+
+ // A common size for embedded thumbnails is 120 by 160 pixels,
+ // So allow 120 by 160 pixels to be used for thumbnails when the
+ // preferred size is 256 pixel.
+
+ if (PreferredSize () >= 160 && PreferredSize () <= 256)
+ {
+ SetMinimumSize (160);
+ }
+
+ // Many sensors are near a multiple of 1024 pixels in size, but after
+ // the default crop, they are a just under. We can get an extra factor
+ // of size reduction if we allow a slight undershoot in the final size
+ // when computing large previews.
+
+ else if (PreferredSize () >= 490 && PreferredSize () <= 512)
+ {
+ SetMinimumSize (490);
+ }
+
+ else if (PreferredSize () >= 980 && PreferredSize () <= 1024)
+ {
+ SetMinimumSize (980);
+ }
+
+ else if (PreferredSize () >= 1470 && PreferredSize () <= 1536)
+ {
+ SetMinimumSize (1470);
+ }
+
+ else if (PreferredSize () >= 1960 && PreferredSize () <= 2048)
+ {
+ SetMinimumSize (1960);
+ }
+
+ // Else minimum size is same as preferred size.
+
+ else
+ {
+ SetMinimumSize (PreferredSize ());
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_host::SaveDNGVersion () const
+ {
+
+ return fSaveDNGVersion;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_host::SaveLinearDNG (const dng_negative & /* negative */) const
+ {
+
+ return fSaveLinearDNG;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_host::IsTransientError (dng_error_code code)
+ {
+
+ switch (code)
+ {
+
+ case dng_error_memory:
+ case dng_error_user_canceled:
+ {
+ return true;
+ }
+
+ default:
+ break;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_host::PerformAreaTask (dng_area_task &task,
+ const dng_rect &area)
+ {
+
+ dng_area_task::Perform (task,
+ area,
+ &Allocator (),
+ Sniffer ());
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_host::PerformAreaTaskThreads ()
+ {
+
+ return 1;
+
+ }
+
+/*****************************************************************************/
+
+dng_exif * dng_host::Make_dng_exif ()
+ {
+
+ dng_exif *result = new dng_exif ();
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp * dng_host::Make_dng_xmp ()
+ {
+
+ dng_xmp *result = new dng_xmp (Allocator ());
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_shared * dng_host::Make_dng_shared ()
+ {
+
+ dng_shared *result = new dng_shared ();
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_ifd * dng_host::Make_dng_ifd ()
+ {
+
+ dng_ifd *result = new dng_ifd ();
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_negative * dng_host::Make_dng_negative ()
+ {
+
+ return dng_negative::Make (*this);
+
+ }
+
+/*****************************************************************************/
+
+dng_image * dng_host::Make_dng_image (const dng_rect &bounds,
+ uint32 planes,
+ uint32 pixelType)
+ {
+
+ dng_image *result = new dng_simple_image (bounds,
+ planes,
+ pixelType,
+ Allocator ());
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode * dng_host::Make_dng_opcode (uint32 opcodeID,
+ dng_stream &stream)
+ {
+
+ dng_opcode *result = NULL;
+
+ switch (opcodeID)
+ {
+
+ case dngOpcode_WarpRectilinear:
+ {
+
+ result = new dng_opcode_WarpRectilinear (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_WarpFisheye:
+ {
+
+ result = new dng_opcode_WarpFisheye (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_FixVignetteRadial:
+ {
+
+ result = new dng_opcode_FixVignetteRadial (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_FixBadPixelsConstant:
+ {
+
+ result = new dng_opcode_FixBadPixelsConstant (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_FixBadPixelsList:
+ {
+
+ result = new dng_opcode_FixBadPixelsList (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_TrimBounds:
+ {
+
+ result = new dng_opcode_TrimBounds (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_MapTable:
+ {
+
+ result = new dng_opcode_MapTable (*this,
+ stream);
+
+ break;
+
+ }
+
+ case dngOpcode_MapPolynomial:
+ {
+
+ result = new dng_opcode_MapPolynomial (stream);
+
+ break;
+
+ }
+
+ case dngOpcode_GainMap:
+ {
+
+ result = new dng_opcode_GainMap (*this,
+ stream);
+
+ break;
+
+ }
+
+ case dngOpcode_DeltaPerRow:
+ {
+
+ result = new dng_opcode_DeltaPerRow (*this,
+ stream);
+
+ break;
+
+ }
+
+ case dngOpcode_DeltaPerColumn:
+ {
+
+ result = new dng_opcode_DeltaPerColumn (*this,
+ stream);
+
+ break;
+
+ }
+
+ case dngOpcode_ScalePerRow:
+ {
+
+ result = new dng_opcode_ScalePerRow (*this,
+ stream);
+
+ break;
+
+ }
+
+ case dngOpcode_ScalePerColumn:
+ {
+
+ result = new dng_opcode_ScalePerColumn (*this,
+ stream);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ result = new dng_opcode_Unknown (*this,
+ opcodeID,
+ stream);
+
+ }
+
+ }
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_host::ApplyOpcodeList (dng_opcode_list &list,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image)
+ {
+
+ list.Apply (*this,
+ negative,
+ image);
+
+ }
+
+/*****************************************************************************/
+
+void dng_host::ResampleImage (const dng_image &srcImage,
+ dng_image &dstImage)
+ {
+
+ ::ResampleImage (*this,
+ srcImage,
+ dstImage,
+ srcImage.Bounds (),
+ dstImage.Bounds (),
+ dng_resample_bicubic::Get ());
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_host.h b/gpr/source/lib/dng_sdk/dng_host.h
new file mode 100644
index 0000000..3e82504
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_host.h
@@ -0,0 +1,411 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_host.h#2 $ */
+/* $DateTime: 2012/06/14 20:24:41 $ */
+/* $Change: 835078 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Class definition for dng_host, initial point of contact and control between
+ * host application and DNG SDK.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_host__
+#define __dng_host__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_errors.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief The main class for communication between the application and the
+/// DNG SDK. Used to customize memory allocation and other behaviors.
+///
+/// dng_host allows setting parameters for the DNG conversion, mediates callback
+/// style interactions between the host application and the DNG SDK, and allows
+/// controlling certain internal behavior of the SDK such as memory allocation.
+/// Many applications will be able to use the default implementation of dng_host
+/// by just setting the dng_memory_allocator and dng_abort_sniffer in the
+/// constructor. More complex interactions will require deriving a class from
+/// dng_host.
+///
+/// Multiple dng_host objects can be allocated in a single process. This may
+/// be useful for DNG processing on separate threads. (Distinct dng_host objects
+/// are completely threadsafe for read/write. The application is responsible for
+/// establishing mutual exclusion for read/write access to a single dng_host
+/// object if it is used in multiple threads.)
+
+class dng_host
+ {
+
+ private:
+
+ dng_memory_allocator *fAllocator;
+
+ dng_abort_sniffer *fSniffer;
+
+ // Does the host require all the image metadata (vs. just checking
+ // to see if the file is readable)?
+
+ bool fNeedsMeta;
+
+ // Does the host require actual image data (vs. just getting metadata
+ // or just checking to see if the file is readable)?
+
+ bool fNeedsImage;
+
+ // If we need the image data, can it be read at preview quality?
+
+ bool fForPreview;
+
+ // If non-zero, the minimum size (longer of the two pixel dimensions)
+ // image to read. If zero, or if the full size image is smaller than
+ // this, read the full size image.
+
+ uint32 fMinimumSize;
+
+ // What is the preferred size for a preview image? This can
+ // be slightly larger than the minimum size. Zero if we want
+ // the full resolution image.
+
+ uint32 fPreferredSize;
+
+ // What is the maximum size for a preview image? Zero if there
+ // is no maximum size limit.
+
+ uint32 fMaximumSize;
+
+ // The fraction of the image kept after a crop. This is used to
+ // adjust the sizes to take into account the cropping that
+ // will be peformed.
+
+ real64 fCropFactor;
+
+ // What DNG version should we keep enough data to save?
+
+ uint32 fSaveDNGVersion;
+
+ // Do we want to force saving to a linear DNG?
+
+ bool fSaveLinearDNG;
+
+ // Keep the original raw file data block?
+
+ bool fKeepOriginalFile;
+
+ // Payload for General Purpose Metadata Format (GPMF)
+ AutoPtr<dng_memory_block> gpmf_payload;
+
+ public:
+
+ AutoPtr<dng_memory_block>& GetGPMFPayload() { return gpmf_payload; };
+
+ /// Allocate a dng_host object, possiblly with custom allocator and sniffer.
+ /// \param allocator Allows controlling all memory allocation done via this
+ /// dng_host. Defaults to singleton global dng_memory_allocator, which calls
+ /// new/delete dng_malloc_block for appropriate size.
+ /// \param sniffer Used to periodically check if pending DNG conversions
+ /// should be aborted and to communicate progress updates. Defaults to singleton
+ /// global dng_abort_sniffer, which never aborts and ignores progress updated.
+
+ dng_host (dng_memory_allocator *allocator = NULL,
+ dng_abort_sniffer *sniffer = NULL);
+
+ /// Clean up direct memory for dng_host. Memory allocator and abort sniffer
+ /// are not deleted. Objects such as dng_image and others returned from
+ /// host can still be used after host is deleted.
+
+ virtual ~dng_host ();
+
+ /// Getter for host's memory allocator.
+
+ dng_memory_allocator & Allocator ();
+
+ /// Alocate a new dng_memory_block using the host's memory allocator.
+ /// Uses the Allocator() property of host to allocate a new block of memory.
+ /// Will call ThrowMemoryFull if block cannot be allocated.
+ /// \param logicalSize Number of usable bytes returned dng_memory_block
+ /// must contain.
+
+ virtual dng_memory_block * Allocate (uint32 logicalSize);
+
+ /// Setter for host's abort sniffer.
+
+ void SetSniffer (dng_abort_sniffer *sniffer)
+ {
+ fSniffer = sniffer;
+ }
+
+ /// Getter for host's abort sniffer.
+
+ dng_abort_sniffer * Sniffer ()
+ {
+ return fSniffer;
+ }
+
+ /// Check for pending abort. Should call ThrowUserCanceled if an abort
+ /// is pending.
+
+ virtual void SniffForAbort ();
+
+ /// Setter for flag determining whether all XMP metadata should be parsed.
+ /// Defaults to true. One might not want metadata when doing a quick check
+ /// to see if a file is readable.
+ /// \param needs If true, metadata is needed.
+
+ void SetNeedsMeta (bool needs)
+ {
+ fNeedsMeta = needs;
+ }
+
+ /// Getter for flag determining whether all XMP metadata should be parsed.
+
+ bool NeedsMeta () const
+ {
+ return fNeedsMeta;
+ }
+
+ /// Setter for flag determining whether DNG image data is needed. Defaults
+ /// to true. Image data might not be needed for applications which only
+ /// manipulate metadata.
+ /// \param needs If true, image data is needed.
+
+ void SetNeedsImage (bool needs)
+ {
+ fNeedsImage = needs;
+ }
+
+ /// Setter for flag determining whether DNG image data is needed.
+
+ bool NeedsImage () const
+ {
+ return fNeedsImage;
+ }
+
+ /// Setter for flag determining whether image should be preview quality,
+ /// or full quality.
+ /// \param preview If true, rendered images are for preview.
+
+ void SetForPreview (bool preview)
+ {
+ fForPreview = preview;
+ }
+
+ /// Getter for flag determining whether image should be preview quality.
+ /// Preview quality images may be rendered more quickly. Current DNG SDK
+ /// does not change rendering behavior based on this flag, but derived
+ /// versions may use this getter to choose between a slower more accurate path
+ /// and a faster "good enough for preview" one. Data produce with ForPreview set
+ /// to true should not be written back to a DNG file, except as a preview image.
+
+ bool ForPreview () const
+ {
+ return fForPreview;
+ }
+
+ /// Setter for the minimum preview size.
+ /// \param size Minimum pixel size (long side of image).
+
+ void SetMinimumSize (uint32 size)
+ {
+ fMinimumSize = size;
+ }
+
+ /// Getter for the minimum preview size.
+
+ uint32 MinimumSize () const
+ {
+ return fMinimumSize;
+ }
+
+ /// Setter for the preferred preview size.
+ /// \param size Preferred pixel size (long side of image).
+
+ void SetPreferredSize (uint32 size)
+ {
+ fPreferredSize = size;
+ }
+
+ /// Getter for the preferred preview size.
+
+ uint32 PreferredSize () const
+ {
+ return fPreferredSize;
+ }
+
+ /// Setter for the maximum preview size.
+ /// \param size Maximum pixel size (long side of image).
+
+ void SetMaximumSize (uint32 size)
+ {
+ fMaximumSize = size;
+ }
+
+ /// Getter for the maximum preview size.
+
+ uint32 MaximumSize () const
+ {
+ return fMaximumSize;
+ }
+
+ /// Setter for the cropping factor.
+ /// \param cropFactor Fraction of image to be used after crop.
+
+ void SetCropFactor (real64 cropFactor)
+ {
+ fCropFactor = cropFactor;
+ }
+
+ /// Getter for the cropping factor.
+
+ real64 CropFactor () const
+ {
+ return fCropFactor;
+ }
+
+ /// Makes sures minimum, preferred, and maximum sizes are reasonable.
+
+ void ValidateSizes ();
+
+ /// Setter for what version to save DNG file compatible with.
+ /// \param version What version to save DNG file compatible with.
+
+ void SetSaveDNGVersion (uint32 version)
+ {
+ fSaveDNGVersion = version;
+ }
+
+ /// Getter for what version to save DNG file compatible with.
+
+ virtual uint32 SaveDNGVersion () const;
+
+ /// Setter for flag determining whether to force saving a linear DNG file.
+ /// \param linear If true, we should force saving a linear DNG file.
+
+ void SetSaveLinearDNG (bool linear)
+ {
+ fSaveLinearDNG = linear;
+ }
+
+ /// Getter for flag determining whether to save a linear DNG file.
+
+ virtual bool SaveLinearDNG (const dng_negative &negative) const;
+
+ /// Setter for flag determining whether to keep original RAW file data.
+ /// \param keep If true, origianl RAW data will be kept.
+
+ void SetKeepOriginalFile (bool keep)
+ {
+ fKeepOriginalFile = keep;
+ }
+
+ /// Getter for flag determining whether to keep original RAW file data.
+
+ bool KeepOriginalFile ()
+ {
+ return fKeepOriginalFile;
+ }
+
+ /// Determine if an error is the result of a temporary, but planned-for
+ /// occurence such as user cancellation or memory exhaustion. This method is
+ /// sometimes used to determine whether to try and continue processing a DNG
+ /// file despite errors in the file format, etc. In such cases, processing will
+ /// be continued if IsTransientError returns false. This is so that user cancellation
+ /// and memory exhaustion always terminate processing.
+ /// \param code Error to test for transience.
+
+ virtual bool IsTransientError (dng_error_code code);
+
+ /// General top-level botttleneck for image processing tasks.
+ /// Default implementation calls dng_area_task::PerformAreaTask method on
+ /// task. Can be overridden in derived classes to support multiprocessing,
+ /// for example.
+ /// \param task Image processing task to perform on area.
+ /// \param area Rectangle over which to perform image processing task.
+
+ virtual void PerformAreaTask (dng_area_task &task,
+ const dng_rect &area);
+
+ /// How many multiprocessing threads does PerformAreaTask use?
+ /// Default implementation always returns 1 since it is single threaded.
+
+ virtual uint32 PerformAreaTaskThreads ();
+
+ /// Factory method for dng_exif class. Can be used to customize allocation or
+ /// to ensure a derived class is used instead of dng_exif.
+
+ virtual dng_exif * Make_dng_exif ();
+
+ /// Factory method for dng_xmp class. Can be used to customize allocation or
+ /// to ensure a derived class is used instead of dng_xmp.
+
+ virtual dng_xmp * Make_dng_xmp ();
+
+ /// Factory method for dng_shared class. Can be used to customize allocation
+ /// or to ensure a derived class is used instead of dng_shared.
+
+ virtual dng_shared * Make_dng_shared ();
+
+ /// Factory method for dng_ifd class. Can be used to customize allocation or
+ /// to ensure a derived class is used instead of dng_ifd.
+
+ virtual dng_ifd * Make_dng_ifd ();
+
+ /// Factory method for dng_negative class. Can be used to customize allocation
+ /// or to ensure a derived class is used instead of dng_negative.
+
+ virtual dng_negative * Make_dng_negative ();
+
+ /// Factory method for dng_image class. Can be used to customize allocation
+ /// or to ensure a derived class is used instead of dng_simple_image.
+
+ virtual dng_image * Make_dng_image (const dng_rect &bounds,
+ uint32 planes,
+ uint32 pixelType);
+
+ /// Factory method for parsing dng_opcode based classs. Can be used to
+ /// override opcode implementations.
+
+ virtual dng_opcode * Make_dng_opcode (uint32 opcodeID,
+ dng_stream &stream);
+
+ /// Factory method to apply a dng_opcode_list. Can be used to override
+ /// opcode list applications.
+
+ virtual void ApplyOpcodeList (dng_opcode_list &list,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ /// Factory method to resample an image. Can be used to override
+ /// image method used to resample images.
+
+ virtual void ResampleImage (const dng_image &srcImage,
+ dng_image &dstImage);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_host (const dng_host &host);
+
+ dng_host & operator= (const dng_host &host);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_hue_sat_map.cpp b/gpr/source/lib/dng_sdk/dng_hue_sat_map.cpp
new file mode 100644
index 0000000..8fddcca
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_hue_sat_map.cpp
@@ -0,0 +1,367 @@
+/*****************************************************************************/
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_hue_sat_map.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_hue_sat_map.h"
+
+#include "dng_assertions.h"
+#include "dng_auto_ptr.h"
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_host.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+dng_hue_sat_map::dng_hue_sat_map ()
+
+ : fHueDivisions (0)
+ , fSatDivisions (0)
+ , fValDivisions (0)
+ , fHueStep (0)
+ , fValStep (0)
+ , fDeltas ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_hue_sat_map::dng_hue_sat_map (const dng_hue_sat_map &src)
+
+ : fHueDivisions (0)
+ , fSatDivisions (0)
+ , fValDivisions (0)
+ , fHueStep (0)
+ , fValStep (0)
+ , fDeltas ()
+
+ {
+
+ *this = src;
+
+ }
+
+/*****************************************************************************/
+
+dng_hue_sat_map &dng_hue_sat_map::operator= (const dng_hue_sat_map &rhs)
+ {
+
+ if (this != &rhs)
+ {
+
+ if (!rhs.IsValid ())
+ {
+
+ SetInvalid ();
+
+ }
+
+ else
+ {
+
+ fHueDivisions = rhs.fHueDivisions;
+ fSatDivisions = rhs.fSatDivisions;
+ fValDivisions = rhs.fValDivisions;
+
+ fHueStep = rhs.fHueStep;
+ fValStep = rhs.fValStep;
+
+ fDeltas = rhs.fDeltas;
+
+ }
+
+ }
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+dng_hue_sat_map::~dng_hue_sat_map ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_hue_sat_map::SetDivisions (uint32 hueDivisions,
+ uint32 satDivisions,
+ uint32 valDivisions)
+ {
+
+ DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division.");
+ DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions.");
+
+ if (valDivisions == 0)
+ valDivisions = 1;
+
+ if (hueDivisions == fHueDivisions &&
+ satDivisions == fSatDivisions &&
+ valDivisions == fValDivisions)
+ {
+ return;
+ }
+
+ fHueDivisions = hueDivisions;
+ fSatDivisions = satDivisions;
+ fValDivisions = valDivisions;
+
+ fHueStep = satDivisions;
+ fValStep = hueDivisions * fHueStep;
+
+ uint32 size = DeltasCount () * (uint32) sizeof (HSBModify);
+
+ fDeltas.Allocate (size);
+
+ DoZeroBytes (fDeltas.Buffer (), size);
+
+ }
+
+/*****************************************************************************/
+
+void dng_hue_sat_map::GetDelta (uint32 hueDiv,
+ uint32 satDiv,
+ uint32 valDiv,
+ HSBModify &modify) const
+ {
+
+ if (hueDiv >= fHueDivisions ||
+ satDiv >= fSatDivisions ||
+ valDiv >= fValDivisions ||
+ fDeltas.Buffer () == NULL)
+ {
+
+ DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
+
+ ThrowProgramError ();
+
+ }
+
+ int32 offset = valDiv * fValStep +
+ hueDiv * fHueStep +
+ satDiv;
+
+ const HSBModify *deltas = GetConstDeltas ();
+
+ modify.fHueShift = deltas [offset].fHueShift;
+ modify.fSatScale = deltas [offset].fSatScale;
+ modify.fValScale = deltas [offset].fValScale;
+
+ }
+
+/*****************************************************************************/
+
+void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv,
+ uint32 satDiv,
+ uint32 valDiv,
+ const HSBModify &modify)
+ {
+
+ if (hueDiv >= fHueDivisions ||
+ satDiv >= fSatDivisions ||
+ valDiv >= fValDivisions ||
+ fDeltas.Buffer () == NULL)
+ {
+
+ DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
+
+ ThrowProgramError ();
+
+ }
+
+ // Set this entry.
+
+ int32 offset = valDiv * fValStep +
+ hueDiv * fHueStep +
+ satDiv;
+
+ SafeGetDeltas () [offset] = modify;
+
+ // The zero saturation entry is required to have a value scale
+ // of 1.0f.
+
+ if (satDiv == 0)
+ {
+
+ if (modify.fValScale != 1.0f)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Value scale for zero saturation entries must be 1.0");
+
+ #endif
+
+ SafeGetDeltas () [offset] . fValScale = 1.0f;
+
+ }
+
+ }
+
+ // If we are settings the first saturation entry and we have not
+ // set the zero saturation entry yet, fill in the zero saturation entry
+ // by extrapolating first saturation entry.
+
+ if (satDiv == 1)
+ {
+
+ HSBModify zeroSatModify;
+
+ GetDelta (hueDiv, 0, valDiv, zeroSatModify);
+
+ if (zeroSatModify.fValScale != 1.0f)
+ {
+
+ zeroSatModify.fHueShift = modify.fHueShift;
+ zeroSatModify.fSatScale = modify.fSatScale;
+ zeroSatModify.fValScale = 1.0f;
+
+ SetDelta (hueDiv, 0, valDiv, zeroSatModify);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const
+ {
+
+ if (fHueDivisions != rhs.fHueDivisions ||
+ fSatDivisions != rhs.fSatDivisions ||
+ fValDivisions != rhs.fValDivisions)
+ return false;
+
+ if (!IsValid ())
+ return true;
+
+ return memcmp (GetConstDeltas (),
+ rhs.GetConstDeltas (),
+ DeltasCount () * sizeof (HSBModify)) == 0;
+
+ }
+
+/*****************************************************************************/
+
+dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
+ const dng_hue_sat_map &map2,
+ real64 weight1)
+ {
+
+ if (weight1 >= 1.0)
+ {
+
+ if (!map1.IsValid ())
+ {
+
+ DNG_REPORT ("map1 is not valid");
+
+ ThrowProgramError ();
+
+ }
+
+ return new dng_hue_sat_map (map1);
+
+ }
+
+ if (weight1 <= 0.0)
+ {
+
+ if (!map2.IsValid ())
+ {
+ DNG_REPORT ("map2 is not valid");
+
+ ThrowProgramError ();
+
+ }
+
+ return new dng_hue_sat_map (map2);
+
+ }
+
+ // Both maps must be valid if we are using both.
+
+ if (!map1.IsValid () || !map2.IsValid ())
+ {
+
+ DNG_REPORT ("map1 or map2 is not valid");
+
+ ThrowProgramError ();
+
+ }
+
+ // Must have the same dimensions.
+
+ if (map1.fHueDivisions != map2.fHueDivisions ||
+ map1.fSatDivisions != map2.fSatDivisions ||
+ map1.fValDivisions != map2.fValDivisions)
+ {
+
+ DNG_REPORT ("map1 and map2 have different sizes");
+
+ ThrowProgramError ();
+
+ }
+
+ // Make table to hold interpolated results.
+
+ AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
+
+ result->SetDivisions (map1.fHueDivisions,
+ map1.fSatDivisions,
+ map1.fValDivisions);
+
+ // Interpolate between the tables.
+
+ real32 w1 = (real32) weight1;
+ real32 w2 = 1.0f - w1;
+
+ const HSBModify *data1 = map1.GetConstDeltas ();
+ const HSBModify *data2 = map2.GetConstDeltas ();
+
+ HSBModify *data3 = result->SafeGetDeltas ();
+
+ uint32 count = map1.DeltasCount ();
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ data3->fHueShift = w1 * data1->fHueShift +
+ w2 * data2->fHueShift;
+
+ data3->fSatScale = w1 * data1->fSatScale +
+ w2 * data2->fSatScale;
+
+ data3->fValScale = w1 * data1->fValScale +
+ w2 * data2->fValScale;
+
+ data1++;
+ data2++;
+ data3++;
+
+ }
+
+ // Return interpolated tables.
+
+ return result.Release ();
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_hue_sat_map.h b/gpr/source/lib/dng_sdk/dng_hue_sat_map.h
new file mode 100644
index 0000000..c0816e2
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_hue_sat_map.h
@@ -0,0 +1,229 @@
+/*****************************************************************************/
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_hue_sat_map.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Table-based color correction data structure.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_hue_sat_map__
+#define __dng_hue_sat_map__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_ref_counted_block.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief A 3D table that maps HSV (hue, saturation, and value) floating-point
+/// input coordinates in the range [0,1] to delta signals. The table must have at
+/// least 1 sample in the hue dimension, at least 2 samples in the saturation
+/// dimension, and at least 1 sample in the value dimension. Tables are stored in
+/// value-hue-saturation order.
+
+class dng_hue_sat_map
+ {
+
+ public:
+
+ /// HSV delta signal. \param fHueShift is a delta value specified in degrees.
+ /// This parameter, added to the original hue, determines the output hue. A
+ /// value of 0 means no change. \param fSatScale and \param fValScale are
+ /// scale factors that are applied to saturation and value components,
+ /// respectively. These scale factors, multiplied by the original saturation
+ /// and value, determine the output saturation and value. A scale factor of
+ /// 1.0 means no change.
+
+ struct HSBModify
+ {
+ real32 fHueShift;
+ real32 fSatScale;
+ real32 fValScale;
+ };
+
+ private:
+
+ uint32 fHueDivisions;
+ uint32 fSatDivisions;
+ uint32 fValDivisions;
+
+ uint32 fHueStep;
+ uint32 fValStep;
+
+ dng_ref_counted_block fDeltas;
+
+ HSBModify *SafeGetDeltas ()
+ {
+ return (HSBModify *) fDeltas.Buffer_real32 ();
+ }
+
+ public:
+
+ /// Construct an empty (and invalid) hue sat map.
+
+ dng_hue_sat_map ();
+
+ /// Copy an existing hue sat map.
+
+ dng_hue_sat_map (const dng_hue_sat_map &src);
+
+ /// Copy an existing hue sat map.
+
+ dng_hue_sat_map & operator= (const dng_hue_sat_map &rhs);
+
+ /// Destructor.
+
+ virtual ~dng_hue_sat_map ();
+
+ /// Is this hue sat map invalid?
+
+ bool IsNull () const
+ {
+ return !IsValid ();
+ }
+
+ /// Is this hue sat map valid?
+
+ bool IsValid () const
+ {
+
+ return fHueDivisions > 0 &&
+ fSatDivisions > 1 &&
+ fValDivisions > 0 &&
+ fDeltas.Buffer ();
+
+ }
+
+ /// Clear the hue sat map, making it invalid.
+
+ void SetInvalid ()
+ {
+
+ fHueDivisions = 0;
+ fSatDivisions = 0;
+ fValDivisions = 0;
+
+ fHueStep = 0;
+ fValStep = 0;
+
+ fDeltas.Clear ();
+
+ }
+
+ /// Get the table dimensions (number of samples in each dimension).
+
+ void GetDivisions (uint32 &hueDivisions,
+ uint32 &satDivisions,
+ uint32 &valDivisions) const
+ {
+ hueDivisions = fHueDivisions;
+ satDivisions = fSatDivisions;
+ valDivisions = fValDivisions;
+ }
+
+ /// Set the table dimensions (number of samples in each dimension). This
+ /// erases any existing table data.
+
+ void SetDivisions (uint32 hueDivisions,
+ uint32 satDivisions,
+ uint32 valDivisions = 1);
+
+ /// Get a specific table entry, specified by table indices.
+
+ void GetDelta (uint32 hueDiv,
+ uint32 satDiv,
+ uint32 valDiv,
+ HSBModify &modify) const;
+
+ /// Make sure the table is writeable.
+
+ void EnsureWriteable ()
+ {
+ fDeltas.EnsureWriteable ();
+ }
+
+ /// Set a specific table entry, specified by table indices.
+
+ void SetDelta (uint32 hueDiv,
+ uint32 satDiv,
+ uint32 valDiv,
+ const HSBModify &modify)
+ {
+
+ EnsureWriteable ();
+
+ SetDeltaKnownWriteable (hueDiv,
+ satDiv,
+ valDiv,
+ modify);
+
+ }
+
+ /// Same as SetDelta, without checking that the table is writeable.
+
+ void SetDeltaKnownWriteable (uint32 hueDiv,
+ uint32 satDiv,
+ uint32 valDiv,
+ const HSBModify &modify);
+
+ /// Get the total number of samples (across all dimensions).
+
+ uint32 DeltasCount () const
+ {
+ return fValDivisions *
+ fHueDivisions *
+ fSatDivisions;
+ }
+
+ /// Direct read/write access to table entries. The entries are stored in
+ /// value-hue-saturation order (outer to inner).
+
+ HSBModify *GetDeltas ()
+ {
+
+ EnsureWriteable ();
+
+ return (HSBModify *) fDeltas.Buffer_real32 ();
+
+ }
+
+ /// Direct read-only access to table entries. The entries are stored in
+ /// value-hue-saturation order (outer to inner).
+
+ const HSBModify *GetConstDeltas () const
+ {
+ return (const HSBModify *) fDeltas.Buffer_real32 ();
+ }
+
+ /// Equality test.
+
+ bool operator== (const dng_hue_sat_map &rhs) const;
+
+ /// Compute a linearly-interpolated hue sat map (i.e., delta and scale factors)
+ /// from the specified tables, with the specified weight. map1 and map2 must
+ /// have the same dimensions.
+
+ static dng_hue_sat_map * Interpolate (const dng_hue_sat_map &map1,
+ const dng_hue_sat_map &map2,
+ real64 weight1);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_ifd.cpp b/gpr/source/lib/dng_sdk/dng_ifd.cpp
new file mode 100644
index 0000000..949635d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_ifd.cpp
@@ -0,0 +1,4266 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_ifd.cpp#3 $ */
+/* $DateTime: 2012/06/05 11:05:39 $ */
+/* $Change: 833352 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_ifd.h"
+
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_globals.h"
+#include "dng_ifd.h"
+#include "dng_types.h"
+#include "dng_parse_utils.h"
+#include "dng_read_image.h"
+#include "dng_stream.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_preview_info::dng_preview_info ()
+
+ : fIsPrimary (true)
+ , fApplicationName ()
+ , fApplicationVersion ()
+ , fSettingsName ()
+ , fSettingsDigest ()
+ , fColorSpace (previewColorSpace_MaxEnum)
+ , fDateTime ()
+ , fRawToPreviewGain (1.0)
+ , fCacheVersion (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_preview_info::~dng_preview_info ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_ifd::dng_ifd ()
+
+ : fUsesNewSubFileType (false)
+ , fNewSubFileType (0)
+
+ , fImageWidth (0)
+ , fImageLength (0)
+
+ , fCompression (ccUncompressed)
+ , fPredictor (cpNullPredictor)
+
+ , fPhotometricInterpretation (0xFFFFFFFF)
+
+ , fFillOrder (1)
+
+ , fOrientation (0)
+ , fOrientationType (0)
+ , fOrientationOffset (kDNGStreamInvalidOffset)
+ , fOrientationBigEndian (false)
+
+ , fSamplesPerPixel (1)
+
+ , fPlanarConfiguration (pcInterleaved)
+
+ , fXResolution (0.0)
+ , fYResolution (0.0)
+ , fResolutionUnit (0)
+
+ , fUsesStrips (false)
+ , fUsesTiles (false)
+
+ , fTileWidth (0)
+ , fTileLength (0)
+
+ , fTileOffsetsType (0)
+ , fTileOffsetsCount (0)
+ , fTileOffsetsOffset (0)
+
+ , fTileByteCountsType (0)
+ , fTileByteCountsCount (0)
+ , fTileByteCountsOffset (0)
+
+ , fSubIFDsCount (0)
+ , fSubIFDsOffset (0)
+
+ , fExtraSamplesCount (0)
+
+ , fJPEGTablesCount (0)
+ , fJPEGTablesOffset (0)
+
+ , fJPEGInterchangeFormat (0)
+ , fJPEGInterchangeFormatLength (0)
+
+ , fYCbCrCoefficientR (0.0)
+ , fYCbCrCoefficientG (0.0)
+ , fYCbCrCoefficientB (0.0)
+
+ , fYCbCrSubSampleH (0)
+ , fYCbCrSubSampleV (0)
+
+ , fYCbCrPositioning (0)
+
+ , fCFARepeatPatternRows (0)
+ , fCFARepeatPatternCols (0)
+
+ , fCFALayout (1)
+
+ , fLinearizationTableType (0)
+ , fLinearizationTableCount (0)
+ , fLinearizationTableOffset (0)
+
+ , fBlackLevelRepeatRows (1)
+ , fBlackLevelRepeatCols (1)
+
+ , fBlackLevelDeltaHType (0)
+ , fBlackLevelDeltaHCount (0)
+ , fBlackLevelDeltaHOffset (0)
+
+ , fBlackLevelDeltaVType (0)
+ , fBlackLevelDeltaVCount (0)
+ , fBlackLevelDeltaVOffset (0)
+
+ , fDefaultScaleH (1, 1)
+ , fDefaultScaleV (1, 1)
+
+ , fBestQualityScale (1, 1)
+
+ , fDefaultCropOriginH (0, 1)
+ , fDefaultCropOriginV (0, 1)
+
+ , fDefaultCropSizeH ()
+ , fDefaultCropSizeV ()
+
+ , fDefaultUserCropT (0, 1)
+ , fDefaultUserCropL (0, 1)
+ , fDefaultUserCropB (1, 1)
+ , fDefaultUserCropR (1, 1)
+
+ , fBayerGreenSplit (0)
+
+ , fChromaBlurRadius ()
+
+ , fAntiAliasStrength (1, 1)
+
+ , fActiveArea ()
+
+ , fMaskedAreaCount (0)
+
+ , fRowInterleaveFactor (1)
+
+ , fSubTileBlockRows (1)
+ , fSubTileBlockCols (1)
+
+ , fPreviewInfo ()
+
+ , fOpcodeList1Count (0)
+ , fOpcodeList1Offset (0)
+
+ , fOpcodeList2Count (0)
+ , fOpcodeList2Offset (0)
+
+ , fOpcodeList3Count (0)
+ , fOpcodeList3Offset (0)
+
+ , fLosslessJPEGBug16 (false)
+
+ , fSampleBitShift (0)
+
+ , fThisIFD (0)
+ , fNextIFD (0)
+
+ , fCompressionQuality (-1)
+
+ , fPatchFirstJPEGByte (false)
+
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 n;
+
+ for (j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+ fBitsPerSample [j] = 0;
+ }
+
+ for (j = 0; j < kMaxTileInfo; j++)
+ {
+ fTileOffset [j] = 0;
+ fTileByteCount [j] = 0;
+ }
+
+ for (j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+ fExtraSamples [j] = esUnspecified;
+ }
+
+ for (j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+ fSampleFormat [j] = sfUnsignedInteger;
+ }
+
+ for (j = 0; j < 6; j++)
+ {
+ fReferenceBlackWhite [j] = 0.0;
+ }
+
+ for (j = 0; j < kMaxCFAPattern; j++)
+ for (k = 0; k < kMaxCFAPattern; k++)
+ {
+ fCFAPattern [j] [k] = 255;
+ }
+
+ for (j = 0; j < kMaxColorPlanes; j++)
+ {
+ fCFAPlaneColor [j] = (uint8) (j < 3 ? j : 255);
+ }
+
+ for (j = 0; j < kMaxBlackPattern; j++)
+ for (k = 0; k < kMaxBlackPattern; k++)
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ fBlackLevel [j] [k] [n] = 0.0;
+ }
+
+ for (j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+ fWhiteLevel [j] = -1.0; // Don't know real default yet.
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_ifd::~dng_ifd ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in IFDs that contain images.
+
+bool dng_ifd::ParseTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset)
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 n;
+
+ switch (tagCode)
+ {
+
+ case tcNewSubFileType:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fUsesNewSubFileType = true;
+
+ fNewSubFileType = stream.TagValue_uint32 (tagType);
+
+ fPreviewInfo.fIsPrimary = (fNewSubFileType == sfPreviewImage);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("NewSubFileType: %s\n",
+ LookupNewSubFileType (fNewSubFileType));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcImageWidth:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fImageWidth = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("ImageWidth: %u\n", (unsigned) fImageWidth);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcImageLength:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fImageLength = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("ImageLength: %u\n", (unsigned) fImageLength);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBitsPerSample:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1, 0x0FFFF);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("BitsPerSample:");
+ }
+
+ #endif
+
+ bool extrasMatch = true;
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ uint32 x = stream.TagValue_uint32 (tagType);
+
+ if (j < kMaxSamplesPerPixel)
+ {
+ fBitsPerSample [j] = x;
+ }
+
+ else if (x != fBitsPerSample [kMaxSamplesPerPixel - 1])
+ {
+ extrasMatch = false;
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf (" %u", (unsigned) x);
+ }
+
+ #endif
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\n");
+ }
+
+ #endif
+
+ if (!extrasMatch)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("BitsPerSample not constant");
+
+ #endif
+
+ ThrowBadFormat ();
+
+ }
+
+ break;
+
+ }
+
+ case tcCompression:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCompression = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Compression: %s\n",
+ LookupCompression (fCompression));
+
+ }
+
+ #endif
+
+ // Correct a common TIFF writer mistake.
+
+ if (fCompression == 0)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s has invalid zero compression code",
+ LookupParentCode (parentCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ fCompression = ccUncompressed;
+
+ }
+
+ break;
+
+ }
+
+ case tcPhotometricInterpretation:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPhotometricInterpretation = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PhotometricInterpretation: %s\n",
+ LookupPhotometricInterpretation (fPhotometricInterpretation));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcFillOrder:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fFillOrder = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("FillOrder: %u\n", (unsigned) fFillOrder);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcStripOffsets:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ fUsesStrips = true;
+
+ fTileOffsetsType = tagType;
+ fTileOffsetsCount = tagCount;
+ fTileOffsetsOffset = tagOffset;
+
+ if (tagCount <= kMaxTileInfo)
+ {
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ fTileOffset [j] = stream.TagValue_uint32 (tagType);
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ DumpTagValues (stream,
+ "Offset",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOrientation:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fOrientationType = tagType;
+ fOrientationOffset = stream.PositionInOriginalFile ();
+ fOrientationBigEndian = stream.BigEndian ();
+
+ fOrientation = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Orientation: %s\n",
+ LookupOrientation (fOrientation));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSamplesPerPixel:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fSamplesPerPixel = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("SamplesPerPixel: %u\n", (unsigned) fSamplesPerPixel);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRowsPerStrip:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fUsesStrips = true;
+
+ fTileLength = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("RowsPerStrip: %u\n", (unsigned) fTileLength);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcStripByteCounts:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ fUsesStrips = true;
+
+ fTileByteCountsType = tagType;
+ fTileByteCountsCount = tagCount;
+ fTileByteCountsOffset = tagOffset;
+
+ if (tagCount <= kMaxTileInfo)
+ {
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ fTileByteCount [j] = stream.TagValue_uint32 (tagType);
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ DumpTagValues (stream,
+ "Count",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcXResolution:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fXResolution = stream.TagValue_real64 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("XResolution: %0.2f\n", fXResolution);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcYResolution:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fYResolution = stream.TagValue_real64 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("YResolution: %0.2f\n", fYResolution);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPlanarConfiguration:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPlanarConfiguration = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("PlanarConfiguration: %u\n", (unsigned) fPlanarConfiguration);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcResolutionUnit:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fResolutionUnit = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ResolutionUnit: %s\n",
+ LookupResolutionUnit (fResolutionUnit));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPredictor:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPredictor = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Predictor: %s\n",
+ LookupPredictor (fPredictor));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcTileWidth:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fUsesTiles = true;
+
+ fTileWidth = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("TileWidth: %u\n", (unsigned) fTileWidth);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcTileLength:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fUsesTiles = true;
+
+ fTileLength = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("TileLength: %u\n", (unsigned) fTileLength);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcTileOffsets:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ fUsesTiles = true;
+
+ fTileOffsetsType = tagType;
+ fTileOffsetsCount = tagCount;
+ fTileOffsetsOffset = tagOffset;
+
+ if (tagCount <= kMaxTileInfo)
+ {
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ fTileOffset [j] = stream.TagValue_uint32 (tagType);
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ DumpTagValues (stream,
+ "Offset",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcTileByteCounts:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ fUsesTiles = true;
+
+ fTileByteCountsType = tagType;
+ fTileByteCountsCount = tagCount;
+ fTileByteCountsOffset = tagOffset;
+
+ if (tagCount <= kMaxTileInfo)
+ {
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ fTileByteCount [j] = stream.TagValue_uint32 (tagType);
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ DumpTagValues (stream,
+ "Count",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubIFDs:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
+
+ fSubIFDsCount = tagCount;
+ fSubIFDsOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ DumpTagValues (stream,
+ "IFD",
+ parentCode,
+ tagCode,
+ ttLong,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExtraSamples:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1, fSamplesPerPixel);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("ExtraSamples:");
+ }
+
+ #endif
+
+ fExtraSamplesCount = tagCount;
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ uint32 x = stream.TagValue_uint32 (tagType);
+
+ if (j < kMaxSamplesPerPixel)
+ {
+ fExtraSamples [j] = x;
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf (" %u", (unsigned) x);
+ }
+
+ #endif
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\n");
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSampleFormat:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, fSamplesPerPixel);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("SampleFormat:");
+ }
+
+ #endif
+
+ bool extrasMatch = true;
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ uint32 x = stream.TagValue_uint32 (tagType);
+
+ if (j < kMaxSamplesPerPixel)
+ {
+ fSampleFormat [j] = x;
+ }
+
+ else if (x != fSampleFormat [kMaxSamplesPerPixel - 1])
+ {
+ extrasMatch = false;
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf (" %s", LookupSampleFormat (x));
+ }
+
+ #endif
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\n");
+ }
+
+ #endif
+
+ if (!extrasMatch)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("SampleFormat not constant");
+
+ #endif
+
+ ThrowBadFormat ();
+
+ }
+
+ break;
+
+ }
+
+ case tcJPEGTables:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fJPEGTablesCount = tagCount;
+ fJPEGTablesOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("JPEGTables: count = %u, offset = %u\n",
+ (unsigned) fJPEGTablesCount,
+ (unsigned) fJPEGTablesOffset);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcJPEGInterchangeFormat:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fJPEGInterchangeFormat = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("JPEGInterchangeFormat: %u\n",
+ (unsigned) fJPEGInterchangeFormat);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcJPEGInterchangeFormatLength:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fJPEGInterchangeFormatLength = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("JPEGInterchangeFormatLength: %u\n",
+ (unsigned) fJPEGInterchangeFormatLength);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcYCbCrCoefficients:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 3))
+ {
+ return false;
+ }
+
+ fYCbCrCoefficientR = stream.TagValue_real64 (tagType);
+ fYCbCrCoefficientG = stream.TagValue_real64 (tagType);
+ fYCbCrCoefficientB = stream.TagValue_real64 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("YCbCrCoefficients: R = %0.3f, G = %0.3f, B = %0.3f\n",
+ fYCbCrCoefficientR,
+ fYCbCrCoefficientG,
+ fYCbCrCoefficientB);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcYCbCrSubSampling:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ {
+ return false;
+ }
+
+ fYCbCrSubSampleH = stream.TagValue_uint32 (tagType);
+ fYCbCrSubSampleV = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("YCbCrSubSampling: H = %u, V = %u\n",
+ (unsigned) fYCbCrSubSampleH,
+ (unsigned) fYCbCrSubSampleV);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcYCbCrPositioning:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fYCbCrPositioning = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("YCbCrPositioning: %u\n",
+ (unsigned) fYCbCrPositioning);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcReferenceBlackWhite:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 6))
+ {
+ return false;
+ }
+
+ for (j = 0; j < 6; j++)
+ {
+ fReferenceBlackWhite [j] = stream.TagValue_real64 (tagType);
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ReferenceBlackWhite: %0.1f %0.1f %0.1f %0.1f %0.1f %0.1f\n",
+ fReferenceBlackWhite [0],
+ fReferenceBlackWhite [1],
+ fReferenceBlackWhite [2],
+ fReferenceBlackWhite [3],
+ fReferenceBlackWhite [4],
+ fReferenceBlackWhite [5]);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCFARepeatPatternDim:
+ {
+
+ CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ {
+ return false;
+ }
+
+ fCFARepeatPatternRows = stream.TagValue_uint32 (tagType);
+ fCFARepeatPatternCols = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CFARepeatPatternDim: Rows = %u, Cols = %u\n",
+ (unsigned) fCFARepeatPatternRows,
+ (unsigned) fCFARepeatPatternCols);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCFAPattern:
+ {
+
+ CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ {
+ return false;
+ }
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, fCFARepeatPatternRows *
+ fCFARepeatPatternCols))
+ {
+ return false;
+ }
+
+ if (fCFARepeatPatternRows < 1 || fCFARepeatPatternRows > kMaxCFAPattern ||
+ fCFARepeatPatternCols < 1 || fCFARepeatPatternCols > kMaxCFAPattern)
+ {
+ return false;
+ }
+
+ // Note that the Exif spec stores this array in a different
+ // scan order than the TIFF-EP spec.
+
+ for (j = 0; j < fCFARepeatPatternRows; j++)
+ for (k = 0; k < fCFARepeatPatternCols; k++)
+ {
+
+ fCFAPattern [j] [k] = stream.Get_uint8 ();
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CFAPattern:\n");
+
+ for (j = 0; j < fCFARepeatPatternRows; j++)
+ {
+
+ int32 spaces = 4;
+
+ for (k = 0; k < fCFARepeatPatternCols; k++)
+ {
+
+ while (spaces-- > 0)
+ {
+ printf (" ");
+ }
+
+ const char *name = LookupCFAColor (fCFAPattern [j] [k]);
+
+ spaces = 9 - (int32) strlen (name);
+
+ printf ("%s", name);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCFAPlaneColor:
+ {
+
+ CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ {
+ return false;
+ }
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 3, kMaxColorPlanes))
+ {
+ return false;
+ }
+
+ for (j = 0; j < kMaxColorPlanes; j++)
+ {
+
+ if (j < tagCount)
+ fCFAPlaneColor [j] = stream.Get_uint8 ();
+
+ else
+ fCFAPlaneColor [j] = 255;
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CFAPlaneColor:");
+
+ for (j = 0; j < tagCount; j++)
+ {
+
+ printf (" %s", LookupCFAColor (fCFAPlaneColor [j]));
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCFALayout:
+ {
+
+ CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCFALayout = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CFALayout: %s\n",
+ LookupCFALayout (fCFALayout));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLinearizationTable:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ fLinearizationTableType = tagType;
+ fLinearizationTableCount = tagCount;
+ fLinearizationTableOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ DumpTagValues (stream,
+ "Table",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBlackLevelRepeatDim:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ {
+ return false;
+ }
+
+ fBlackLevelRepeatRows = stream.TagValue_uint32 (tagType);
+ fBlackLevelRepeatCols = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BlackLevelRepeatDim: Rows = %u, Cols = %u\n",
+ (unsigned) fBlackLevelRepeatRows,
+ (unsigned) fBlackLevelRepeatCols);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBlackLevel:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, fBlackLevelRepeatRows *
+ fBlackLevelRepeatCols *
+ fSamplesPerPixel))
+ {
+ return false;
+ }
+
+ if (fBlackLevelRepeatRows < 1 || fBlackLevelRepeatRows > kMaxBlackPattern ||
+ fBlackLevelRepeatCols < 1 || fBlackLevelRepeatCols > kMaxBlackPattern ||
+ fSamplesPerPixel < 1 || fSamplesPerPixel > kMaxSamplesPerPixel)
+ {
+ return false;
+ }
+
+ for (j = 0; j < fBlackLevelRepeatRows; j++)
+ for (k = 0; k < fBlackLevelRepeatCols; k++)
+ for (n = 0; n < fSamplesPerPixel; n++)
+ {
+
+ fBlackLevel [j] [k] [n] = stream.TagValue_real64 (tagType);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BlackLevel:");
+
+ if (fBlackLevelRepeatRows == 1 &&
+ fBlackLevelRepeatCols == 1)
+ {
+
+ for (n = 0; n < fSamplesPerPixel; n++)
+ {
+ printf (" %0.2f", fBlackLevel [0] [0] [n]);
+ }
+
+ printf ("\n");
+
+ }
+
+ else
+ {
+
+ printf ("\n");
+
+ for (n = 0; n < fSamplesPerPixel; n++)
+ {
+
+ if (fSamplesPerPixel > 1)
+ {
+ printf (" Sample: %u\n", (unsigned) n);
+ }
+
+ for (j = 0; j < fBlackLevelRepeatRows; j++)
+ {
+
+ printf (" ");
+
+ for (k = 0; k < fBlackLevelRepeatCols; k++)
+ {
+
+ printf (" %8.2f", fBlackLevel [j] [k] [n]);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ }
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBlackLevelDeltaH:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ fBlackLevelDeltaHType = tagType;
+ fBlackLevelDeltaHCount = tagCount;
+ fBlackLevelDeltaHOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ DumpTagValues (stream,
+ "Delta",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBlackLevelDeltaV:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ fBlackLevelDeltaVType = tagType;
+ fBlackLevelDeltaVCount = tagCount;
+ fBlackLevelDeltaVOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ DumpTagValues (stream,
+ "Delta",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcWhiteLevel:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, fSamplesPerPixel))
+ return false;
+
+ for (j = 0; j < tagCount && j < kMaxSamplesPerPixel; j++)
+ {
+
+ fWhiteLevel [j] = stream.TagValue_real64 (tagType);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("WhiteLevel:");
+
+ for (j = 0; j < tagCount && j < kMaxSamplesPerPixel; j++)
+ {
+
+ printf (" %0.0f", fWhiteLevel [j]);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDefaultScale:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fDefaultScaleH = stream.TagValue_urational (tagType);
+ fDefaultScaleV = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DefaultScale: H = %0.4f V = %0.4f\n",
+ fDefaultScaleH.As_real64 (),
+ fDefaultScaleV.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDefaultCropOrigin:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fDefaultCropOriginH = stream.TagValue_urational (tagType);
+ fDefaultCropOriginV = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DefaultCropOrigin: H = %0.2f V = %0.2f\n",
+ fDefaultCropOriginH.As_real64 (),
+ fDefaultCropOriginV.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDefaultCropSize:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fDefaultCropSizeH = stream.TagValue_urational (tagType);
+ fDefaultCropSizeV = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DefaultCropSize: H = %0.2f V = %0.2f\n",
+ fDefaultCropSizeH.As_real64 (),
+ fDefaultCropSizeV.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDefaultUserCrop:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
+ return false;
+
+ fDefaultUserCropT = stream.TagValue_urational (tagType);
+ fDefaultUserCropL = stream.TagValue_urational (tagType);
+ fDefaultUserCropB = stream.TagValue_urational (tagType);
+ fDefaultUserCropR = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DefaultUserCrop: T = %0.2lf L = %0.2lf B = %0.2lf R = %0.2lf\n",
+ (double) fDefaultUserCropT.As_real64 (),
+ (double) fDefaultUserCropL.As_real64 (),
+ (double) fDefaultUserCropB.As_real64 (),
+ (double) fDefaultUserCropR.As_real64 ());
+
+
+ }
+
+ #endif // qDNGValidate
+
+ break;
+
+ }
+
+ case tcBayerGreenSplit:
+ {
+
+ CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBayerGreenSplit = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("BayerGreenSplit: %u\n", (unsigned) fBayerGreenSplit);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcChromaBlurRadius:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fChromaBlurRadius = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ChromaBlurRadius: %0.2f\n",
+ fChromaBlurRadius.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAntiAliasStrength:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fAntiAliasStrength = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AntiAliasStrength: %0.2f\n",
+ fAntiAliasStrength.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBestQualityScale:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBestQualityScale = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BestQualityScale: %0.4f\n",
+ fBestQualityScale.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcActiveArea:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
+ return false;
+
+ fActiveArea.t = stream.TagValue_int32 (tagType);
+ fActiveArea.l = stream.TagValue_int32 (tagType);
+ fActiveArea.b = stream.TagValue_int32 (tagType);
+ fActiveArea.r = stream.TagValue_int32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ActiveArea: T = %d L = %d B = %d R = %d\n",
+ (int) fActiveArea.t,
+ (int) fActiveArea.l,
+ (int) fActiveArea.b,
+ (int) fActiveArea.r);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcMaskedAreas:
+ {
+
+ CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ uint32 rect_count = tagCount / 4;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, rect_count * 4))
+ return false;
+
+ fMaskedAreaCount = rect_count;
+
+ if (fMaskedAreaCount > kMaxMaskedAreas)
+ fMaskedAreaCount = kMaxMaskedAreas;
+
+ for (j = 0; j < fMaskedAreaCount; j++)
+ {
+
+ fMaskedArea [j].t = stream.TagValue_int32 (tagType);
+ fMaskedArea [j].l = stream.TagValue_int32 (tagType);
+ fMaskedArea [j].b = stream.TagValue_int32 (tagType);
+ fMaskedArea [j].r = stream.TagValue_int32 (tagType);
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("MaskedAreas: %u\n", (unsigned) fMaskedAreaCount);
+
+ for (j = 0; j < fMaskedAreaCount; j++)
+ {
+
+ printf (" Area [%u]: T = %d L = %d B = %d R = %d\n",
+ (unsigned) j,
+ (int) fMaskedArea [j].t,
+ (int) fMaskedArea [j].l,
+ (int) fMaskedArea [j].b,
+ (int) fMaskedArea [j].r);
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPreviewApplicationName:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fPreviewInfo.fApplicationName,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PreviewApplicationName: ");
+
+ DumpString (fPreviewInfo.fApplicationName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPreviewApplicationVersion:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fPreviewInfo.fApplicationVersion,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PreviewApplicationVersion: ");
+
+ DumpString (fPreviewInfo.fApplicationVersion);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPreviewSettingsName:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fPreviewInfo.fSettingsName,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PreviewSettingsName: ");
+
+ DumpString (fPreviewInfo.fSettingsName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPreviewSettingsDigest:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
+ return false;
+
+ stream.Get (fPreviewInfo.fSettingsDigest.data, 16);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PreviewSettingsDigest: ");
+
+ DumpFingerprint (fPreviewInfo.fSettingsDigest);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPreviewColorSpace:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPreviewInfo.fColorSpace = (PreviewColorSpaceEnum)
+ stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PreviewColorSpace: %s\n",
+ LookupPreviewColorSpace ((uint32) fPreviewInfo.fColorSpace));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPreviewDateTime:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fPreviewInfo.fDateTime,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("PreviewDateTime: ");
+
+ DumpString (fPreviewInfo.fDateTime);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRowInterleaveFactor:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
+ return false;
+
+ fRowInterleaveFactor = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("RowInterleaveFactor: %u\n",
+ (unsigned) fRowInterleaveFactor);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcSubTileBlockSize:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fSubTileBlockRows = stream.TagValue_uint32 (tagType);
+ fSubTileBlockCols = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("SubTileBlockSize: rows = %u, cols = %u\n",
+ (unsigned) fSubTileBlockRows,
+ (unsigned) fSubTileBlockCols);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOpcodeList1:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fOpcodeList1Count = tagCount;
+ fOpcodeList1Offset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OpcodeList1: count = %u, offset = %u\n",
+ (unsigned) fOpcodeList1Count,
+ (unsigned) fOpcodeList1Offset);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOpcodeList2:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fOpcodeList2Count = tagCount;
+ fOpcodeList2Offset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OpcodeList2: count = %u, offset = %u\n",
+ (unsigned) fOpcodeList2Count,
+ (unsigned) fOpcodeList2Offset);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOpcodeList3:
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fOpcodeList3Count = tagCount;
+ fOpcodeList3Offset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OpcodeList3: count = %u, offset = %u\n",
+ (unsigned) fOpcodeList3Count,
+ (unsigned) fOpcodeList3Offset);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRawToPreviewGain:
+ {
+
+ #if qDNGValidate
+
+ if (fNewSubFileType != sfPreviewImage)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed IFDs with NewSubFileType != PreviewImage",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttDouble);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
+ return false;
+
+ fPreviewInfo.fRawToPreviewGain = stream.TagValue_real64 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("RawToPreviewGain = %f\n",
+ fPreviewInfo.fRawToPreviewGain);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCacheVersion:
+ {
+
+ #if qDNGValidate
+
+ if (fNewSubFileType != sfPreviewImage)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed IFDs with NewSubFileType != PreviewImage",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
+ return false;
+
+ fPreviewInfo.fCacheVersion = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CacheVersion = 0x%x\n",
+ (unsigned) fPreviewInfo.fCacheVersion);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_ifd::PostParse ()
+ {
+
+ uint32 j;
+ uint32 k;
+
+ // There is only one PlanarConfiguration for single sample imaages.
+
+ if (fSamplesPerPixel == 1)
+ {
+ fPlanarConfiguration = pcInterleaved;
+ }
+
+ // Default tile size.
+
+ if (fTileWidth == 0)
+ {
+ fTileWidth = fImageWidth;
+ }
+
+ if (fTileLength == 0)
+ {
+ fTileLength = fImageLength;
+ }
+
+ // Default ActiveArea.
+
+ dng_rect imageArea (0, 0, fImageLength, fImageWidth);
+
+ if (fActiveArea.IsZero ())
+ {
+ fActiveArea = imageArea;
+ }
+
+ // Default crop size.
+
+ if (fDefaultCropSizeH.d == 0)
+ {
+ fDefaultCropSizeH = dng_urational (fActiveArea.W (), 1);
+ }
+
+ if (fDefaultCropSizeV.d == 0)
+ {
+ fDefaultCropSizeV = dng_urational (fActiveArea.H (), 1);
+ }
+
+ // Default white level.
+
+ uint32 defaultWhite = (fSampleFormat [0] == sfFloatingPoint) ?
+ 1 :
+ (uint32) ((((uint64) 1) << fBitsPerSample [0]) - 1);
+
+ for (j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+
+ if (fWhiteLevel [j] < 0.0)
+ {
+ fWhiteLevel [j] = (real64) defaultWhite;
+ }
+
+ }
+
+ // Check AntiAliasStrength.
+
+ if (fAntiAliasStrength.As_real64 () < 0.0 ||
+ fAntiAliasStrength.As_real64 () > 1.0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid AntiAliasStrength");
+
+ #endif
+
+ fAntiAliasStrength = dng_urational (1, 1);
+
+ }
+
+ // Check MaskedAreas.
+
+ for (j = 0; j < fMaskedAreaCount; j++)
+ {
+
+ const dng_rect &r = fMaskedArea [j];
+
+ if (r.IsEmpty () || ((r & imageArea) != r))
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid MaskedArea");
+
+ #endif
+
+ fMaskedAreaCount = 0;
+
+ break;
+
+ }
+
+ if ((r & fActiveArea).NotEmpty ())
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("MaskedArea overlaps ActiveArea");
+
+ #endif
+
+ fMaskedAreaCount = 0;
+
+ break;
+
+ }
+
+ for (k = 0; k < j; k++)
+ {
+
+ if ((r & fMaskedArea [k]).NotEmpty ())
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("MaskedAreas overlap each other");
+
+ #endif
+
+ fMaskedAreaCount = 0;
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_ifd::IsValidCFA (dng_shared &shared,
+ uint32 parentCode)
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 n;
+
+ #if !qDNGValidate
+
+ (void) parentCode; // Unused
+
+ #endif
+
+ if (fCFARepeatPatternRows < 1 || fCFARepeatPatternRows > kMaxCFAPattern ||
+ fCFARepeatPatternCols < 1 || fCFARepeatPatternCols > kMaxCFAPattern)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid CFAPatternRepeatDim",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ uint32 count [kMaxColorPlanes];
+
+ for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++)
+ {
+ count [n] = 0;
+ }
+
+ for (j = 0; j < fCFARepeatPatternRows; j++)
+ {
+
+ for (k = 0; k < fCFARepeatPatternCols; k++)
+ {
+
+ bool found = false;
+
+ for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++)
+ {
+
+ if (fCFAPattern [j] [k] == fCFAPlaneColor [n])
+ {
+ found = true;
+ count [n] ++;
+ break;
+ }
+
+ }
+
+ if (!found)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("CFAPattern contains colors not included in the CFAPlaneColor tag",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++)
+ {
+
+ if (count [n] == 0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("CFAPattern does not contain all the colors in the CFAPlaneColor tag",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ if (fCFALayout < 1 || fCFALayout > 9)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid CFALayout",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_ifd::IsValidDNG (dng_shared &shared,
+ uint32 parentCode)
+ {
+
+ uint32 j;
+
+ bool isFloatingPoint = (fSampleFormat [0] == sfFloatingPoint);
+
+ dng_rect imageArea (0, 0, fImageLength, fImageWidth);
+
+ uint32 defaultWhite = isFloatingPoint ?
+ 1 :
+ (uint32) ((((uint64) 1) << fBitsPerSample [0]) - 1);
+
+ bool isMonochrome = (shared.fCameraProfile.fColorPlanes == 1);
+ bool isColor = !isMonochrome;
+
+ bool isMainIFD = (fNewSubFileType == sfMainImage);
+
+ // Check NewSubFileType.
+
+ if (!fUsesNewSubFileType)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing NewSubFileType",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fNewSubFileType != sfMainImage &&
+ fNewSubFileType != sfPreviewImage &&
+ fNewSubFileType != sfTransparencyMask &&
+ fNewSubFileType != sfPreviewMask &&
+ fNewSubFileType != sfAltPreviewImage)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unexpected NewSubFileType",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check ImageWidth and ImageLength.
+
+ if (fImageWidth < 1)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid ImageWidth",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fImageLength < 1)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid ImageLength",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fImageWidth > kMaxImageSide ||
+ fImageLength > kMaxImageSide)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Image size is larger than supported");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check PhotometricInterpretation.
+
+ if (fNewSubFileType == sfTransparencyMask ||
+ fNewSubFileType == sfPreviewMask)
+ {
+
+ if (fPhotometricInterpretation != piTransparencyMask)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("NewSubFileType requires PhotometricInterpretation = TransparencyMask",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ else
+ {
+
+ switch (fPhotometricInterpretation)
+ {
+
+ case piBlackIsZero:
+ case piRGB:
+ case piYCbCr:
+ {
+
+ if (isMainIFD)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("PhotometricInterpretation requires NewSubFileType = 1",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ break;
+
+ }
+
+ case piCFA:
+ {
+
+ if (!isMainIFD)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("PhotometricInterpretation requires NewSubFileType = 0",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ break;
+
+ }
+
+ case piLinearRaw:
+ break;
+
+ default:
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid PhotometricInterpretation",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ switch (fPhotometricInterpretation)
+ {
+
+ case piBlackIsZero:
+ {
+
+ // Allow black in white previews even in color images since the
+ // raw processing software may be converting to grayscale.
+
+ if (isColor && isMainIFD)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("PhotometricInterpretation forbids use of ColorMatrix1 tag",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ break;
+
+ }
+
+ case piRGB:
+ case piYCbCr:
+ {
+
+ // Allow color previews even in monochrome DNG files, since the
+ // raw procesing software may be adding color effects.
+
+ break;
+
+ }
+
+ case piCFA:
+ {
+
+ if (isMonochrome)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("PhotometricInterpretation requires use of ColorMatrix1 tag",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ if (isFloatingPoint)
+ {
+
+ if (fPhotometricInterpretation != piCFA &&
+ fPhotometricInterpretation != piLinearRaw &&
+ fPhotometricInterpretation != piTransparencyMask)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Floating point data requires PhotometricInterpretation CFA or LinearRaw or TransparencyMask",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check SamplesPerPixel and BitsPerSample.
+
+ uint32 minSamplesPerPixel = 1;
+ uint32 maxSamplesPerPixel = 1;
+
+ uint32 minBitsPerSample = 8;
+ uint32 maxBitsPerSample = 16;
+
+ switch (fPhotometricInterpretation)
+ {
+
+ case piBlackIsZero:
+ break;
+
+ case piRGB:
+ case piYCbCr:
+ {
+ minSamplesPerPixel = 3;
+ maxSamplesPerPixel = 3;
+ break;
+ }
+
+ case piCFA:
+ {
+ maxSamplesPerPixel = kMaxSamplesPerPixel;
+ maxBitsPerSample = 32;
+ break;
+ }
+
+ case piLinearRaw:
+ {
+ minSamplesPerPixel = shared.fCameraProfile.fColorPlanes;
+ maxSamplesPerPixel = shared.fCameraProfile.fColorPlanes;
+ maxBitsPerSample = 32;
+ break;
+ }
+
+ case piTransparencyMask:
+ {
+ minBitsPerSample = 8;
+ maxBitsPerSample = 16;
+ break;
+ }
+
+ }
+
+ if (isFloatingPoint)
+ {
+ minBitsPerSample = 16;
+ maxBitsPerSample = 32;
+ }
+
+ if (fSamplesPerPixel < minSamplesPerPixel ||
+ fSamplesPerPixel > maxSamplesPerPixel)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid SamplesPerPixel",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ for (j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+
+ if (j < fSamplesPerPixel)
+ {
+
+ if (fBitsPerSample [j] < minBitsPerSample ||
+ fBitsPerSample [j] > maxBitsPerSample)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid BitsPerSample",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (isFloatingPoint &&
+ fBitsPerSample [j] != 16 &&
+ fBitsPerSample [j] != 24 &&
+ fBitsPerSample [j] != 32)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid BitsPerSample for floating point",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (minBitsPerSample == 8 &&
+ maxBitsPerSample == 16 &&
+ fBitsPerSample [j] != 8 &&
+ fBitsPerSample [j] != 16)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Rendered previews and integer masks require 8 or 16 bits per sample",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (j > 0 && fBitsPerSample [j] != fBitsPerSample [0])
+ {
+
+ #if qDNGValidate
+
+ ReportError ("BitsPerSample not equal for all samples",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ else
+ {
+
+ if (fBitsPerSample [j] != 0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Too many values specified in BitsPerSample",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ // Check Compression.
+
+ switch (fCompression)
+ {
+
+ case ccUncompressed:
+ break;
+
+#if GPR_WRITING || GPR_READING
+ case ccVc5:
+ break;
+#endif
+
+ case ccJPEG:
+ {
+
+ if (fPhotometricInterpretation == piRGB)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("JPEG previews should use PhotometricInterpretation = YCbYb",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fBitsPerSample [0] > 16)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("JPEG compression is limited to 16 bits/sample",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ break;
+
+ }
+
+ case ccLossyJPEG:
+ {
+
+ if (fPhotometricInterpretation != piLinearRaw)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Lossy JPEG compression code requires PhotometricInterpretation = LinearRaw",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fBitsPerSample [0] != 8)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Lossy JPEG compression is limited to 8 bits/sample",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ break;
+
+ }
+
+ case ccDeflate:
+ {
+
+ if (!isFloatingPoint &&
+ fBitsPerSample [0] != 32 &&
+ fPhotometricInterpretation != piTransparencyMask)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("ZIP compression is limited to floating point and 32-bit integer and transparency masks",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unsupported Compression",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check Predictor.
+
+ if (isFloatingPoint && fCompression == ccDeflate &&
+ (fPredictor == cpFloatingPoint ||
+ fPredictor == cpFloatingPointX2 ||
+ fPredictor == cpFloatingPointX4))
+ {
+
+ // These combinations are supported.
+
+ }
+
+ else if (!isFloatingPoint && fCompression == ccDeflate &&
+ (fPredictor == cpHorizontalDifference ||
+ fPredictor == cpHorizontalDifferenceX2 ||
+ fPredictor == cpHorizontalDifferenceX4))
+ {
+
+ // These combinations are supported.
+
+ }
+
+ else if (fPredictor != cpNullPredictor)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unsupported Predictor",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check FillOrder.
+
+ if (fFillOrder != 1)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unsupported FillOrder",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check PlanarConfiguration.
+
+ if (fPlanarConfiguration != pcInterleaved)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unsupported PlanarConfiguration",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check ExtraSamples.
+
+ if (fExtraSamplesCount != 0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unsupported ExtraSamples",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check SampleFormat.
+
+ for (j = 0; j < fSamplesPerPixel; j++)
+ {
+
+ if (fSampleFormat [j] != (isFloatingPoint ? sfFloatingPoint : sfUnsignedInteger))
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unsupported SampleFormat",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check Orientation.
+
+ if (fOrientation > 9)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unknown Orientation",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ #if qDNGValidate
+
+ if (fOrientation != 0 && parentCode != 0)
+ {
+
+ ReportWarning ("Unexpected Orientation tag",
+ LookupParentCode (parentCode));
+
+ }
+
+ if (fOrientation == 0 && parentCode == 0)
+ {
+
+ ReportWarning ("Missing Orientation tag",
+ LookupParentCode (parentCode));
+
+ }
+
+ #endif
+
+ // Check Strips vs. Tiles.
+
+ if (!fUsesStrips && !fUsesTiles)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("IFD uses neither strips nor tiles",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fUsesStrips && fUsesTiles)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("IFD uses both strips and tiles",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check tile info.
+
+ uint32 tilesWide = (fImageWidth + fTileWidth - 1) / fTileWidth;
+ uint32 tilesHigh = (fImageLength + fTileLength - 1) / fTileLength;
+
+ uint32 tileCount = tilesWide * tilesHigh;
+
+ if (fTileOffsetsCount != tileCount)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid Strip/TileOffsets",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fTileByteCountsCount != tileCount)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Missing or invalid Strip/TileByteCounts",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check CFA pattern.
+
+ if (fPhotometricInterpretation == piCFA)
+ {
+
+ if (!IsValidCFA (shared, parentCode))
+ {
+
+ return false;
+
+ }
+
+ }
+
+ // Check ActiveArea.
+
+ if (((fActiveArea & imageArea) != fActiveArea) || fActiveArea.IsEmpty ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid ActiveArea",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fActiveArea != imageArea)
+ {
+
+ if (shared.fDNGBackwardVersion < dngVersion_1_1_0_0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Non-default ActiveArea tag not allowed in this DNG version",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check LinearizationTable.
+
+ if (fLinearizationTableCount)
+ {
+
+ if (fLinearizationTableType != ttShort)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalidate LinearizationTable type",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fLinearizationTableCount < 2 ||
+ fLinearizationTableCount > 65536)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalidate LinearizationTable count",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (isFloatingPoint || fBitsPerSample [0] > 16)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Linearization table not allowed for this data type",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check BlackLevelRepeatDim.
+
+ if (fBlackLevelRepeatRows < 1 || fBlackLevelRepeatRows > kMaxBlackPattern ||
+ fBlackLevelRepeatCols < 1 || fBlackLevelRepeatCols > kMaxBlackPattern)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid BlackLevelRepeatDim",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check BlackLevelDeltaH.
+
+ if (fBlackLevelDeltaHCount != 0 &&
+ fBlackLevelDeltaHCount != fActiveArea.W ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid BlackLevelDeltaH count",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check BlackLevelDeltaV.
+
+ if (fBlackLevelDeltaVCount != 0 &&
+ fBlackLevelDeltaVCount != fActiveArea.H ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid BlackLevelDeltaV count",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check WhiteLevel.
+
+ real64 maxWhite = fLinearizationTableCount ? 65535.0
+ : (real64) defaultWhite;
+
+ for (j = 0; j < fSamplesPerPixel; j++)
+ {
+
+ if (fWhiteLevel [j] < 1.0 || (fWhiteLevel [j] > maxWhite && !isFloatingPoint))
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid WhiteLevel",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check BlackLevel.
+
+ for (j = 0; j < kMaxBlackPattern; j++)
+ {
+
+ for (uint32 k = 0; k < kMaxBlackPattern; k++)
+ {
+
+ for (uint32 s = 0; s < kMaxSamplesPerPixel; s++)
+ {
+
+ const real64 black = fBlackLevel [j][k][s];
+
+ if (black >= fWhiteLevel [s])
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid BlackLevel",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Check DefaultScale.
+
+ if (fDefaultScaleH.As_real64 () <= 0.0 ||
+ fDefaultScaleV.As_real64 () <= 0.0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid DefaultScale");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check BestQualityScale.
+
+ if (fBestQualityScale.As_real64 () < 1.0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid BestQualityScale");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check DefaultCropOrigin.
+
+ if (fDefaultCropOriginH.As_real64 () < 0.0 ||
+ fDefaultCropOriginV.As_real64 () < 0.0 ||
+ fDefaultCropOriginH.As_real64 () >= (real64) fActiveArea.W () ||
+ fDefaultCropOriginV.As_real64 () >= (real64) fActiveArea.H ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid DefaultCropOrigin");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check DefaultCropSize.
+
+ if (fDefaultCropSizeH.As_real64 () <= 0.0 ||
+ fDefaultCropSizeV.As_real64 () <= 0.0 ||
+ fDefaultCropSizeH.As_real64 () > (real64) fActiveArea.W () ||
+ fDefaultCropSizeV.As_real64 () > (real64) fActiveArea.H ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid DefaultCropSize");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check DefaultCrop area.
+
+ if (fDefaultCropOriginH.As_real64 () +
+ fDefaultCropSizeH .As_real64 () > (real64) fActiveArea.W () ||
+ fDefaultCropOriginV.As_real64 () +
+ fDefaultCropSizeV .As_real64 () > (real64) fActiveArea.H ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Default crop extends outside ActiveArea");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check DefaultUserCrop.
+
+ if (fDefaultUserCropT.As_real64 () < 0.0 ||
+ fDefaultUserCropL.As_real64 () < 0.0 ||
+ fDefaultUserCropB.As_real64 () > 1.0 ||
+ fDefaultUserCropR.As_real64 () > 1.0 ||
+ fDefaultUserCropT.As_real64 () >= fDefaultUserCropB.As_real64 () ||
+ fDefaultUserCropL.As_real64 () >= fDefaultUserCropR.As_real64 ())
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid DefaultUserCrop");
+
+ #endif // qDNGValidate
+
+ return false;
+
+ }
+
+ // The default crop and default user crop tags are not allowed for the
+ // non-main image. If they are there, at least require that they be NOPs.
+
+ if (!isMainIFD)
+ {
+
+ if (Round_int32 (fDefaultCropOriginH.As_real64 ()) != 0 ||
+ Round_int32 (fDefaultCropOriginV.As_real64 ()) != 0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("non-default DefaultCropOrigin on non-main image");
+
+ #endif
+
+ return false;
+
+ }
+
+ if (Round_int32 (fDefaultCropSizeH.As_real64 ()) != (int32) fImageWidth ||
+ Round_int32 (fDefaultCropSizeV.As_real64 ()) != (int32) fImageLength)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("non-default DefaultCropSize on non-main image");
+
+ #endif
+
+ return false;
+
+ }
+
+ if (fDefaultUserCropT.As_real64 () != 0.0 ||
+ fDefaultUserCropL.As_real64 () != 0.0 ||
+ fDefaultUserCropB.As_real64 () != 1.0 ||
+ fDefaultUserCropR.As_real64 () != 1.0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("non-default DefaultCUserCrop on non-main image");
+
+ #endif // qDNGValidate
+
+ return false;
+
+ }
+
+ }
+
+ // Warning if too little padding on CFA image.
+
+ #if qDNGValidate
+
+ if (fPhotometricInterpretation == piCFA)
+ {
+
+ const real64 kMinPad = 1.9;
+
+ if (fDefaultCropOriginH.As_real64 () < kMinPad)
+ {
+
+ ReportWarning ("Too little padding on left edge of CFA image",
+ "possible interpolation artifacts");
+
+ }
+
+ if (fDefaultCropOriginV.As_real64 () < kMinPad)
+ {
+
+ ReportWarning ("Too little padding on top edge of CFA image",
+ "possible interpolation artifacts");
+
+ }
+
+ if (fDefaultCropOriginH.As_real64 () +
+ fDefaultCropSizeH .As_real64 () > (real64) fActiveArea.W () - kMinPad)
+ {
+
+ ReportWarning ("Too little padding on right edge of CFA image",
+ "possible interpolation artifacts");
+
+ }
+
+ if (fDefaultCropOriginV.As_real64 () +
+ fDefaultCropSizeV .As_real64 () > (real64) fActiveArea.H () - kMinPad)
+ {
+
+ ReportWarning ("Too little padding on bottom edge of CFA image",
+ "possible interpolation artifacts");
+
+ }
+
+ }
+
+ #endif
+
+ // Check RowInterleaveFactor
+
+ if (fRowInterleaveFactor != 1)
+ {
+
+ if (fRowInterleaveFactor < 1 ||
+ fRowInterleaveFactor > fImageLength)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("RowInterleaveFactor out of valid range",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (shared.fDNGBackwardVersion < dngVersion_1_2_0_0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Non-default RowInterleaveFactor tag not allowed in this DNG version",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check SubTileBlockSize
+
+ if (fSubTileBlockRows != 1 || fSubTileBlockCols != 1)
+ {
+
+ if (fSubTileBlockRows < 2 || fSubTileBlockRows > fTileLength ||
+ fSubTileBlockCols < 1 || fSubTileBlockCols > fTileWidth)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("SubTileBlockSize out of valid range",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if ((fTileLength % fSubTileBlockRows) != 0 ||
+ (fTileWidth % fSubTileBlockCols) != 0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("TileSize not exact multiple of SubTileBlockSize",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ if (shared.fDNGBackwardVersion < dngVersion_1_2_0_0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Non-default SubTileBlockSize tag not allowed in this DNG version",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_ifd::TilesAcross () const
+ {
+
+ if (fTileWidth)
+ {
+
+ return (fImageWidth + fTileWidth - 1) / fTileWidth;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_ifd::TilesDown () const
+ {
+
+ if (fTileLength)
+ {
+
+ return (fImageLength + fTileLength - 1) / fTileLength;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_ifd::TilesPerImage () const
+ {
+
+ uint32 total = TilesAcross () * TilesDown ();
+
+ if (fPlanarConfiguration == pcPlanar)
+ {
+
+ total *= fSamplesPerPixel;
+
+ }
+
+ return total;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_ifd::TileArea (uint32 rowIndex,
+ uint32 colIndex) const
+ {
+
+ dng_rect r;
+
+ r.t = rowIndex * fTileLength;
+ r.b = r.t + fTileLength;
+
+ r.l = colIndex * fTileWidth;
+ r.r = r.l + fTileWidth;
+
+ // If this IFD is using strips rather than tiles, the last strip
+ // is trimmed so it does not extend beyond the end of the image.
+
+ if (fUsesStrips)
+ {
+
+ r.b = Min_uint32 (r.b, fImageLength);
+
+ }
+
+ return r;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_ifd::TileByteCount (const dng_rect &tile) const
+ {
+
+ if ( fCompression == ccUncompressed )
+
+ {
+
+ uint32 bitsPerRow = tile.W () *
+ fBitsPerSample [0];
+
+ if (fPlanarConfiguration == pcInterleaved)
+ {
+
+ bitsPerRow *= fSamplesPerPixel;
+
+ }
+
+ uint32 bytesPerRow = (bitsPerRow + 7) >> 3;
+
+ if (fPlanarConfiguration == pcRowInterleaved)
+ {
+
+ bytesPerRow *= fSamplesPerPixel;
+
+ }
+
+ return bytesPerRow * tile.H ();
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_ifd::SetSingleStrip ()
+ {
+
+ fTileWidth = fImageWidth;
+ fTileLength = fImageLength;
+
+ fUsesTiles = false;
+ fUsesStrips = true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_ifd::FindTileSize (uint32 bytesPerTile,
+ uint32 cellH,
+ uint32 cellV)
+ {
+
+ uint32 bytesPerSample = fSamplesPerPixel *
+ ((fBitsPerSample [0] + 7) >> 3);
+
+ uint32 samplesPerTile = bytesPerTile / bytesPerSample;
+
+ uint32 tileSide = Round_uint32 (sqrt ((real64) samplesPerTile));
+
+ fTileWidth = Min_uint32 (fImageWidth, tileSide);
+
+ uint32 across = TilesAcross ();
+
+ fTileWidth = (fImageWidth + across - 1) / across;
+
+ fTileWidth = ((fTileWidth + cellH - 1) / cellH) * cellH;
+
+ fTileLength = Pin_uint32 (1,
+ samplesPerTile / fTileWidth,
+ fImageLength);
+
+ uint32 down = TilesDown ();
+
+ fTileLength = (fImageLength + down - 1) / down;
+
+ fTileLength = ((fTileLength + cellV - 1) / cellV) * cellV;
+
+ fUsesTiles = true;
+ fUsesStrips = false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_ifd::FindStripSize (uint32 bytesPerStrip,
+ uint32 cellV)
+ {
+
+ uint32 bytesPerSample = fSamplesPerPixel *
+ ((fBitsPerSample [0] + 7) >> 3);
+
+ uint32 samplesPerStrip = bytesPerStrip / bytesPerSample;
+
+ fTileWidth = fImageWidth;
+
+ fTileLength = Pin_uint32 (1,
+ samplesPerStrip / fTileWidth,
+ fImageLength);
+
+ uint32 down = TilesDown ();
+
+ fTileLength = (fImageLength + down - 1) / down;
+
+ fTileLength = ((fTileLength + cellV - 1) / cellV) * cellV;
+
+ fUsesTiles = false;
+ fUsesStrips = true;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_ifd::PixelType () const
+ {
+
+ if (fSampleFormat [0] == sfFloatingPoint)
+ {
+ return ttFloat;
+ }
+
+ if (fBitsPerSample [0] <= 8)
+ {
+ return ttByte;
+ }
+
+ else if (fBitsPerSample [0] <= 16)
+ {
+ return ttShort;
+ }
+
+ return ttLong;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_ifd::IsBaselineJPEG () const
+ {
+
+ if (fBitsPerSample [0] != 8)
+ {
+ return false;
+ }
+
+ if (fSampleFormat [0] != sfUnsignedInteger)
+ {
+ return false;
+ }
+
+ if (fCompression == ccLossyJPEG)
+ {
+ return true;
+ }
+
+ if (fCompression != ccJPEG)
+ {
+ return false;
+ }
+
+ switch (fPhotometricInterpretation)
+ {
+
+ case piBlackIsZero:
+ {
+ return (fSamplesPerPixel == 1);
+ }
+
+ case piYCbCr:
+ {
+ return (fSamplesPerPixel == 3 ) &&
+ (fPlanarConfiguration == pcInterleaved);
+ }
+
+ default:
+ break;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_ifd::CanRead () const
+ {
+
+ dng_read_image reader;
+
+ return reader.CanRead (*this);
+
+ }
+
+/*****************************************************************************/
+
+void dng_ifd::ReadImage (dng_host &host,
+ dng_stream &stream,
+ dng_image &image,
+ dng_jpeg_image *jpegImage,
+ dng_fingerprint *jpegDigest) const
+ {
+
+ dng_read_image reader;
+
+ reader.Read (host,
+ *this,
+ stream,
+ image,
+ jpegImage,
+ jpegDigest);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_ifd.h b/gpr/source/lib/dng_sdk/dng_ifd.h
new file mode 100644
index 0000000..c0b681d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_ifd.h
@@ -0,0 +1,305 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_ifd.h#3 $ */
+/* $DateTime: 2012/06/05 11:05:39 $ */
+/* $Change: 833352 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * DNG image file directory support.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_ifd__
+#define __dng_ifd__
+
+/*****************************************************************************/
+
+#include "dng_fingerprint.h"
+#include "dng_rect.h"
+#include "dng_shared.h"
+#include "dng_stream.h"
+#include "dng_string.h"
+#include "dng_sdk_limits.h"
+#include "dng_tag_values.h"
+
+/*****************************************************************************/
+
+class dng_preview_info
+ {
+
+ public:
+
+ bool fIsPrimary;
+
+ dng_string fApplicationName;
+
+ dng_string fApplicationVersion;
+
+ dng_string fSettingsName;
+
+ dng_fingerprint fSettingsDigest;
+
+ PreviewColorSpaceEnum fColorSpace;
+
+ dng_string fDateTime;
+
+ real64 fRawToPreviewGain;
+
+ uint32 fCacheVersion;
+
+ public:
+
+ dng_preview_info ();
+
+ ~dng_preview_info ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Container for a single image file directory of a digital negative.
+///
+/// See \ref spec_dng "DNG 1.1.0 specification" for documentation of specific tags.
+
+class dng_ifd
+ {
+
+ public:
+
+ bool fUsesNewSubFileType;
+
+ uint32 fNewSubFileType;
+
+ uint32 fImageWidth;
+ uint32 fImageLength;
+
+ uint32 fBitsPerSample [kMaxSamplesPerPixel];
+
+ uint32 fCompression;
+
+ uint32 fPredictor;
+
+ uint32 fPhotometricInterpretation;
+
+ uint32 fFillOrder;
+
+ uint32 fOrientation;
+ uint32 fOrientationType;
+ uint64 fOrientationOffset;
+ bool fOrientationBigEndian;
+
+ uint32 fSamplesPerPixel;
+
+ uint32 fPlanarConfiguration;
+
+ real64 fXResolution;
+ real64 fYResolution;
+
+ uint32 fResolutionUnit;
+
+ bool fUsesStrips;
+ bool fUsesTiles;
+
+ uint32 fTileWidth;
+ uint32 fTileLength;
+
+ enum
+ {
+ kMaxTileInfo = 32
+ };
+
+ uint32 fTileOffsetsType;
+ uint32 fTileOffsetsCount;
+ uint64 fTileOffsetsOffset;
+ uint64 fTileOffset [kMaxTileInfo];
+
+ uint32 fTileByteCountsType;
+ uint32 fTileByteCountsCount;
+ uint64 fTileByteCountsOffset;
+ uint32 fTileByteCount [kMaxTileInfo];
+
+ uint32 fSubIFDsCount;
+ uint64 fSubIFDsOffset;
+
+ uint32 fExtraSamplesCount;
+ uint32 fExtraSamples [kMaxSamplesPerPixel];
+
+ uint32 fSampleFormat [kMaxSamplesPerPixel];
+
+ uint32 fJPEGTablesCount;
+ uint64 fJPEGTablesOffset;
+
+ uint64 fJPEGInterchangeFormat;
+ uint32 fJPEGInterchangeFormatLength;
+
+ real64 fYCbCrCoefficientR;
+ real64 fYCbCrCoefficientG;
+ real64 fYCbCrCoefficientB;
+
+ uint32 fYCbCrSubSampleH;
+ uint32 fYCbCrSubSampleV;
+
+ uint32 fYCbCrPositioning;
+
+ real64 fReferenceBlackWhite [6];
+
+ uint32 fCFARepeatPatternRows;
+ uint32 fCFARepeatPatternCols;
+
+ uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
+
+ uint8 fCFAPlaneColor [kMaxColorPlanes];
+
+ uint32 fCFALayout;
+
+ uint32 fLinearizationTableType;
+ uint32 fLinearizationTableCount;
+ uint64 fLinearizationTableOffset;
+
+ uint32 fBlackLevelRepeatRows;
+ uint32 fBlackLevelRepeatCols;
+
+ real64 fBlackLevel [kMaxBlackPattern] [kMaxBlackPattern] [kMaxSamplesPerPixel];
+
+ uint32 fBlackLevelDeltaHType;
+ uint32 fBlackLevelDeltaHCount;
+ uint64 fBlackLevelDeltaHOffset;
+
+ uint32 fBlackLevelDeltaVType;
+ uint32 fBlackLevelDeltaVCount;
+ uint64 fBlackLevelDeltaVOffset;
+
+ real64 fWhiteLevel [kMaxSamplesPerPixel];
+
+ dng_urational fDefaultScaleH;
+ dng_urational fDefaultScaleV;
+
+ dng_urational fBestQualityScale;
+
+ dng_urational fDefaultCropOriginH;
+ dng_urational fDefaultCropOriginV;
+
+ dng_urational fDefaultCropSizeH;
+ dng_urational fDefaultCropSizeV;
+
+ dng_urational fDefaultUserCropT;
+ dng_urational fDefaultUserCropL;
+ dng_urational fDefaultUserCropB;
+ dng_urational fDefaultUserCropR;
+
+ uint32 fBayerGreenSplit;
+
+ dng_urational fChromaBlurRadius;
+
+ dng_urational fAntiAliasStrength;
+
+ dng_rect fActiveArea;
+
+ uint32 fMaskedAreaCount;
+ dng_rect fMaskedArea [kMaxMaskedAreas];
+
+ uint32 fRowInterleaveFactor;
+
+ uint32 fSubTileBlockRows;
+ uint32 fSubTileBlockCols;
+
+ dng_preview_info fPreviewInfo;
+
+ uint32 fOpcodeList1Count;
+ uint64 fOpcodeList1Offset;
+
+ uint32 fOpcodeList2Count;
+ uint64 fOpcodeList2Offset;
+
+ uint32 fOpcodeList3Count;
+ uint64 fOpcodeList3Offset;
+
+ bool fLosslessJPEGBug16;
+
+ uint32 fSampleBitShift;
+
+ uint64 fThisIFD;
+ uint64 fNextIFD;
+
+ int32 fCompressionQuality;
+
+ bool fPatchFirstJPEGByte;
+
+ public:
+
+ dng_ifd ();
+
+ virtual ~dng_ifd ();
+
+ virtual bool ParseTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual void PostParse ();
+
+ virtual bool IsValidDNG (dng_shared &shared,
+ uint32 parentCode);
+
+ dng_rect Bounds () const
+ {
+ return dng_rect (0,
+ 0,
+ fImageLength,
+ fImageWidth);
+ }
+
+ uint32 TilesAcross () const;
+
+ uint32 TilesDown () const;
+
+ uint32 TilesPerImage () const;
+
+ dng_rect TileArea (uint32 rowIndex,
+ uint32 colIndex) const;
+
+ virtual uint32 TileByteCount (const dng_rect &tile) const;
+
+ void SetSingleStrip ();
+
+ void FindTileSize (uint32 bytesPerTile = 128 * 1024,
+ uint32 cellH = 16,
+ uint32 cellV = 16);
+
+ void FindStripSize (uint32 bytesPerStrip = 128 * 1024,
+ uint32 cellV = 16);
+
+ virtual uint32 PixelType () const;
+
+ virtual bool IsBaselineJPEG () const;
+
+ virtual bool CanRead () const;
+
+ virtual void ReadImage (dng_host &host,
+ dng_stream &stream,
+ dng_image &image,
+ dng_jpeg_image *jpegImage = NULL,
+ dng_fingerprint *jpegDigest = NULL) const;
+
+ protected:
+
+ virtual bool IsValidCFA (dng_shared &shared,
+ uint32 parentCode);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_image.cpp b/gpr/source/lib/dng_sdk/dng_image.cpp
new file mode 100644
index 0000000..50fd085
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_image.cpp
@@ -0,0 +1,848 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_image.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_image.h"
+
+#include "dng_assertions.h"
+#include "dng_exceptions.h"
+#include "dng_orientation.h"
+#include "dng_pixel_buffer.h"
+#include "dng_tag_types.h"
+#include "dng_tile_iterator.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_tile_buffer::dng_tile_buffer (const dng_image &image,
+ const dng_rect &tile,
+ bool dirty)
+
+ : fImage (image)
+ , fRefData (NULL)
+
+ {
+
+ fImage.AcquireTileBuffer (*this,
+ tile,
+ dirty);
+
+ }
+
+/*****************************************************************************/
+
+dng_tile_buffer::~dng_tile_buffer ()
+ {
+
+ fImage.ReleaseTileBuffer (*this);
+
+ }
+
+/*****************************************************************************/
+
+dng_const_tile_buffer::dng_const_tile_buffer (const dng_image &image,
+ const dng_rect &tile)
+
+ : dng_tile_buffer (image, tile, false)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_const_tile_buffer::~dng_const_tile_buffer ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_dirty_tile_buffer::dng_dirty_tile_buffer (dng_image &image,
+ const dng_rect &tile)
+
+ : dng_tile_buffer (image, tile, true)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_dirty_tile_buffer::~dng_dirty_tile_buffer ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_image::dng_image (const dng_rect &bounds,
+ uint32 planes,
+ uint32 pixelType)
+
+ : fBounds (bounds)
+ , fPlanes (planes)
+ , fPixelType (pixelType)
+
+ {
+
+ if (bounds.IsEmpty () || planes == 0 || PixelSize () == 0)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Fuzz: Attempt to create zero size image");
+
+ #endif
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_image::~dng_image ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_image * dng_image::Clone () const
+ {
+
+ ThrowProgramError ("Clone is not supported by this dng_image subclass");
+
+ return NULL;
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::SetPixelType (uint32 pixelType)
+ {
+
+ if (TagTypeSize (pixelType) != PixelSize ())
+ {
+
+ ThrowProgramError ("Cannot change pixel size for existing image");
+
+ }
+
+ fPixelType = pixelType;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_image::PixelSize () const
+ {
+
+ return TagTypeSize (PixelType ());
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_image::PixelRange () const
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ case ttSByte:
+ {
+ return 0x0FF;
+ }
+
+ case ttShort:
+ case ttSShort:
+ {
+ return 0x0FFFF;
+ }
+
+ case ttLong:
+ case ttSLong:
+ {
+ return 0xFFFFFFFF;
+ }
+
+ default:
+ break;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_image::RepeatingTile () const
+ {
+
+ return fBounds;
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::AcquireTileBuffer (dng_tile_buffer & /* buffer */,
+ const dng_rect & /* area */,
+ bool /* dirty */) const
+ {
+
+ ThrowProgramError ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::ReleaseTileBuffer (dng_tile_buffer & /* buffer */) const
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::DoGet (dng_pixel_buffer &buffer) const
+ {
+
+ dng_rect tile;
+
+ dng_tile_iterator iter (*this, buffer.fArea);
+
+ while (iter.GetOneTile (tile))
+ {
+
+ dng_const_tile_buffer tileBuffer (*this, tile);
+
+ buffer.CopyArea (tileBuffer,
+ tile,
+ buffer.fPlane,
+ buffer.fPlanes);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::DoPut (const dng_pixel_buffer &buffer)
+ {
+
+ dng_rect tile;
+
+ dng_tile_iterator iter (*this, buffer.fArea);
+
+ while (iter.GetOneTile (tile))
+ {
+
+ dng_dirty_tile_buffer tileBuffer (*this, tile);
+
+ tileBuffer.CopyArea (buffer,
+ tile,
+ buffer.fPlane,
+ buffer.fPlanes);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::GetRepeat (dng_pixel_buffer &buffer,
+ const dng_rect &srcArea,
+ const dng_rect &dstArea) const
+ {
+
+ // If we already have the entire srcArea in the
+ // buffer, we can just repeat that.
+
+ if ((srcArea & buffer.fArea) == srcArea)
+ {
+
+ buffer.RepeatArea (srcArea,
+ dstArea);
+
+ }
+
+ // Else we first need to get the srcArea into the buffer area.
+
+ else
+ {
+
+ // Find repeating pattern size.
+
+ dng_point repeat = srcArea.Size ();
+
+ // Find pattern phase at top-left corner of destination area.
+
+ dng_point phase = dng_pixel_buffer::RepeatPhase (srcArea,
+ dstArea);
+
+ // Find new source area at top-left of dstArea.
+
+ dng_rect newArea = srcArea + (dstArea.TL () -
+ srcArea.TL ());
+
+ // Find quadrant split coordinates.
+
+ int32 splitV = newArea.t + repeat.v - phase.v;
+ int32 splitH = newArea.l + repeat.h - phase.h;
+
+ // Top-left quadrant.
+
+ dng_rect dst1 (dng_rect (newArea.t,
+ newArea.l,
+ splitV,
+ splitH) & dstArea);
+
+ if (dst1.NotEmpty ())
+ {
+
+ dng_pixel_buffer temp (buffer);
+
+ temp.fArea = dst1 + (srcArea.TL () -
+ dstArea.TL () +
+ dng_point (phase.v, phase.h));
+
+ temp.fData = buffer.DirtyPixel (dst1.t,
+ dst1.l,
+ buffer.fPlane);
+
+ DoGet (temp);
+
+ }
+
+ // Top-right quadrant.
+
+ dng_rect dst2 (dng_rect (newArea.t,
+ splitH,
+ splitV,
+ newArea.r) & dstArea);
+
+ if (dst2.NotEmpty ())
+ {
+
+ dng_pixel_buffer temp (buffer);
+
+ temp.fArea = dst2 + (srcArea.TL () -
+ dstArea.TL () +
+ dng_point (phase.v, -phase.h));
+
+ temp.fData = buffer.DirtyPixel (dst2.t,
+ dst2.l,
+ buffer.fPlane);
+
+ DoGet (temp);
+
+ }
+
+ // Bottom-left quadrant.
+
+ dng_rect dst3 (dng_rect (splitV,
+ newArea.l,
+ newArea.b,
+ splitH) & dstArea);
+
+ if (dst3.NotEmpty ())
+ {
+
+ dng_pixel_buffer temp (buffer);
+
+ temp.fArea = dst3 + (srcArea.TL () -
+ dstArea.TL () +
+ dng_point (-phase.v, phase.h));
+
+ temp.fData = buffer.DirtyPixel (dst3.t,
+ dst3.l,
+ buffer.fPlane);
+
+ DoGet (temp);
+
+ }
+
+ // Bottom-right quadrant.
+
+ dng_rect dst4 (dng_rect (splitV,
+ splitH,
+ newArea.b,
+ newArea.r) & dstArea);
+
+ if (dst4.NotEmpty ())
+ {
+
+ dng_pixel_buffer temp (buffer);
+
+ temp.fArea = dst4 + (srcArea.TL () -
+ dstArea.TL () +
+ dng_point (-phase.v, -phase.h));
+
+ temp.fData = buffer.DirtyPixel (dst4.t,
+ dst4.l,
+ buffer.fPlane);
+
+ DoGet (temp);
+
+ }
+
+ // Replicate this new source area.
+
+ buffer.RepeatArea (newArea,
+ dstArea);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::GetEdge (dng_pixel_buffer &buffer,
+ edge_option edgeOption,
+ const dng_rect &srcArea,
+ const dng_rect &dstArea) const
+ {
+
+ switch (edgeOption)
+ {
+
+ case edge_zero:
+ {
+
+ buffer.SetZero (dstArea,
+ buffer.fPlane,
+ buffer.fPlanes);
+
+ break;
+
+ }
+
+ case edge_repeat:
+ {
+
+ GetRepeat (buffer,
+ srcArea,
+ dstArea);
+
+ break;
+
+ }
+
+ case edge_repeat_zero_last:
+ {
+
+ if (buffer.fPlanes > 1)
+ {
+
+ dng_pixel_buffer buffer1 (buffer);
+
+ buffer1.fPlanes--;
+
+ GetEdge (buffer1,
+ edge_repeat,
+ srcArea,
+ dstArea);
+
+ }
+
+ dng_pixel_buffer buffer2 (buffer);
+
+ buffer2.fPlane = buffer.fPlanes - 1;
+ buffer2.fPlanes = 1;
+
+ buffer2.fData = buffer.DirtyPixel (buffer2.fArea.t,
+ buffer2.fArea.l,
+ buffer2.fPlane);
+
+ GetEdge (buffer2,
+ edge_zero,
+ srcArea,
+ dstArea);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowProgramError ();
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::Get (dng_pixel_buffer &buffer,
+ edge_option edgeOption,
+ uint32 repeatV,
+ uint32 repeatH) const
+ {
+
+ // Find the overlap with the image bounds.
+
+ dng_rect overlap = buffer.fArea & fBounds;
+
+ // Move the overlapping pixels.
+
+ if (overlap.NotEmpty ())
+ {
+
+ dng_pixel_buffer temp (buffer);
+
+ temp.fArea = overlap;
+
+ temp.fData = buffer.DirtyPixel (overlap.t,
+ overlap.l,
+ buffer.fPlane);
+
+ DoGet (temp);
+
+ }
+
+ // See if we need to pad the edge values.
+
+ if ((edgeOption != edge_none) && (overlap != buffer.fArea))
+ {
+
+ dng_rect areaT (buffer.fArea);
+ dng_rect areaL (buffer.fArea);
+ dng_rect areaB (buffer.fArea);
+ dng_rect areaR (buffer.fArea);
+
+ areaT.b = Min_int32 (areaT.b, fBounds.t);
+ areaL.r = Min_int32 (areaL.r, fBounds.l);
+ areaB.t = Max_int32 (areaB.t, fBounds.b);
+ areaR.l = Max_int32 (areaR.l, fBounds.r);
+
+ dng_rect areaH (buffer.fArea);
+ dng_rect areaV (buffer.fArea);
+
+ areaH.l = Max_int32 (areaH.l, fBounds.l);
+ areaH.r = Min_int32 (areaH.r, fBounds.r);
+
+ areaV.t = Max_int32 (areaV.t, fBounds.t);
+ areaV.b = Min_int32 (areaV.b, fBounds.b);
+
+ // Top left.
+
+ dng_rect areaTL = areaT & areaL;
+
+ if (areaTL.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (fBounds.t,
+ fBounds.l,
+ fBounds.t + repeatV,
+ fBounds.l + repeatH),
+ areaTL);
+
+ }
+
+ // Top middle.
+
+ dng_rect areaTM = areaT & areaH;
+
+ if (areaTM.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (fBounds.t,
+ areaTM.l,
+ fBounds.t + repeatV,
+ areaTM.r),
+ areaTM);
+
+ }
+
+ // Top right.
+
+ dng_rect areaTR = areaT & areaR;
+
+ if (areaTR.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (fBounds.t,
+ fBounds.r - repeatH,
+ fBounds.t + repeatV,
+ fBounds.r),
+ areaTR);
+
+ }
+
+ // Left middle.
+
+ dng_rect areaLM = areaL & areaV;
+
+ if (areaLM.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (areaLM.t,
+ fBounds.l,
+ areaLM.b,
+ fBounds.l + repeatH),
+ areaLM);
+
+ }
+
+ // Right middle.
+
+ dng_rect areaRM = areaR & areaV;
+
+ if (areaRM.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (areaRM.t,
+ fBounds.r - repeatH,
+ areaRM.b,
+ fBounds.r),
+ areaRM);
+
+ }
+
+ // Bottom left.
+
+ dng_rect areaBL = areaB & areaL;
+
+ if (areaBL.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (fBounds.b - repeatV,
+ fBounds.l,
+ fBounds.b,
+ fBounds.l + repeatH),
+ areaBL);
+
+ }
+
+ // Bottom middle.
+
+ dng_rect areaBM = areaB & areaH;
+
+ if (areaBM.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (fBounds.b - repeatV,
+ areaBM.l,
+ fBounds.b,
+ areaBM.r),
+ areaBM);
+
+ }
+
+ // Bottom right.
+
+ dng_rect areaBR = areaB & areaR;
+
+ if (areaBR.NotEmpty ())
+ {
+
+ GetEdge (buffer,
+ edgeOption,
+ dng_rect (fBounds.b - repeatV,
+ fBounds.r - repeatH,
+ fBounds.b,
+ fBounds.r),
+ areaBR);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::Put (const dng_pixel_buffer &buffer)
+ {
+
+ // Move the overlapping pixels.
+
+ dng_rect overlap = buffer.fArea & fBounds;
+
+ if (overlap.NotEmpty ())
+ {
+
+ dng_pixel_buffer temp (buffer);
+
+ temp.fArea = overlap;
+
+ temp.fData = (void *) buffer.ConstPixel (overlap.t,
+ overlap.l,
+ buffer.fPlane);
+
+ // Move the overlapping planes.
+
+ if (temp.fPlane < Planes ())
+ {
+
+ temp.fPlanes = Min_uint32 (temp.fPlanes,
+ Planes () - temp.fPlane);
+
+ DoPut (temp);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::Trim (const dng_rect &r)
+ {
+
+ if (r != Bounds ())
+ {
+
+ ThrowProgramError ("Trim is not support by this dng_image subclass");
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::Rotate (const dng_orientation &orientation)
+ {
+
+ if (orientation != dng_orientation::Normal ())
+ {
+
+ ThrowProgramError ("Rotate is not support by this dng_image subclass");
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::CopyArea (const dng_image &src,
+ const dng_rect &area,
+ uint32 srcPlane,
+ uint32 dstPlane,
+ uint32 planes)
+ {
+
+ if (&src == this)
+ return;
+
+ dng_tile_iterator destIter(*this, area);
+ dng_rect destTileArea;
+
+ while (destIter.GetOneTile(destTileArea))
+ {
+ dng_tile_iterator srcIter(src, destTileArea);
+ dng_rect srcTileArea;
+
+ while (srcIter.GetOneTile(srcTileArea))
+ {
+
+ dng_dirty_tile_buffer destTile(*this, srcTileArea);
+ dng_const_tile_buffer srcTile(src, srcTileArea);
+
+ destTile.CopyArea (srcTile, srcTileArea, srcPlane, dstPlane, planes);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_image::EqualArea (const dng_image &src,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes) const
+ {
+
+ if (&src == this)
+ return true;
+
+ dng_tile_iterator destIter (*this, area);
+
+ dng_rect destTileArea;
+
+ while (destIter.GetOneTile (destTileArea))
+ {
+
+ dng_tile_iterator srcIter (src, destTileArea);
+
+ dng_rect srcTileArea;
+
+ while (srcIter.GetOneTile (srcTileArea))
+ {
+
+ dng_const_tile_buffer destTile (*this, srcTileArea);
+ dng_const_tile_buffer srcTile (src , srcTileArea);
+
+ if (!destTile.EqualArea (srcTile, srcTileArea, plane, planes))
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_image::SetConstant (uint32 value,
+ const dng_rect &area)
+ {
+
+ dng_tile_iterator iter (*this, area);
+
+ dng_rect tileArea;
+
+ while (iter.GetOneTile (tileArea))
+ {
+
+ dng_dirty_tile_buffer buffer (*this, tileArea);
+
+ buffer.SetConstant (tileArea,
+ 0,
+ fPlanes,
+ value);
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_image.h b/gpr/source/lib/dng_sdk/dng_image.h
new file mode 100644
index 0000000..013182d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_image.h
@@ -0,0 +1,433 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_image.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for working with image data in DNG SDK.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_image__
+#define __dng_image__
+
+/*****************************************************************************/
+
+#include "dng_assertions.h"
+#include "dng_classes.h"
+#include "dng_pixel_buffer.h"
+#include "dng_point.h"
+#include "dng_rect.h"
+#include "dng_tag_types.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Class to get resource acquisition is instantiation behavior for tile
+/// buffers. Can be dirty or constant tile access.
+
+class dng_tile_buffer: public dng_pixel_buffer
+ {
+
+ protected:
+
+ const dng_image &fImage;
+
+ void *fRefData;
+
+ protected:
+
+ /// Obtain a tile from an image.
+ /// \param image Image tile will come from.
+ /// \param tile Rectangle denoting extent of tile.
+ /// \param dirty Flag indicating whether this is read-only or read-write acesss.
+
+ dng_tile_buffer (const dng_image &image,
+ const dng_rect &tile,
+ bool dirty);
+
+ virtual ~dng_tile_buffer ();
+
+ public:
+
+ void SetRefData (void *refData)
+ {
+ fRefData = refData;
+ }
+
+ void * GetRefData () const
+ {
+ return fRefData;
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_tile_buffer (const dng_tile_buffer &buffer);
+
+ dng_tile_buffer & operator= (const dng_tile_buffer &buffer);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to get resource acquisition is instantiation behavior for
+/// constant (read-only) tile buffers.
+
+class dng_const_tile_buffer: public dng_tile_buffer
+ {
+
+ public:
+
+ /// Obtain a read-only tile from an image.
+ /// \param image Image tile will come from.
+ /// \param tile Rectangle denoting extent of tile.
+
+ dng_const_tile_buffer (const dng_image &image,
+ const dng_rect &tile);
+
+ virtual ~dng_const_tile_buffer ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to get resource acquisition is instantiation behavior for
+/// dirty (writable) tile buffers.
+
+class dng_dirty_tile_buffer: public dng_tile_buffer
+ {
+
+ public:
+
+ /// Obtain a writable tile from an image.
+ /// \param image Image tile will come from.
+ /// \param tile Rectangle denoting extent of tile.
+
+ dng_dirty_tile_buffer (dng_image &image,
+ const dng_rect &tile);
+
+ virtual ~dng_dirty_tile_buffer ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Base class for holding image data in DNG SDK. See dng_simple_image
+/// for derived class most often used in DNG SDK.
+
+class dng_image
+ {
+
+ friend class dng_tile_buffer;
+
+ protected:
+
+ // Bounds for this image.
+
+ dng_rect fBounds;
+
+ // Number of image planes.
+
+ uint32 fPlanes;
+
+ // Basic pixel type (TIFF tag type code).
+
+ uint32 fPixelType;
+
+ public:
+
+ /// How to handle requests to get image areas outside the image bounds.
+
+ enum edge_option
+ {
+
+ /// Leave edge pixels unchanged.
+
+ edge_none,
+
+ /// Pad with zeros.
+
+ edge_zero,
+
+ /// Repeat edge pixels.
+
+ edge_repeat,
+
+ /// Repeat edge pixels, except for last plane which is zero padded.
+
+ edge_repeat_zero_last
+
+ };
+
+ protected:
+
+ dng_image (const dng_rect &bounds,
+ uint32 planes,
+ uint32 pixelType);
+
+ public:
+
+ virtual ~dng_image ();
+
+ virtual dng_image * Clone () const;
+
+ /// Getter method for bounds of an image.
+
+ const dng_rect & Bounds () const
+ {
+ return fBounds;
+ }
+
+ /// Getter method for size of an image.
+
+ dng_point Size () const
+ {
+ return Bounds ().Size ();
+ }
+
+ /// Getter method for width of an image.
+
+ uint32 Width () const
+ {
+ return Bounds ().W ();
+ }
+
+ /// Getter method for height of an image.
+
+ uint32 Height () const
+ {
+ return Bounds ().H ();
+ }
+
+ /// Getter method for number of planes in an image.
+
+ uint32 Planes () const
+ {
+ return fPlanes;
+ }
+
+ /// Getter for pixel type.
+ /// \retval See dng_tagtypes.h . Valid values are ttByte, ttShort, ttSShort,
+ /// ttLong, ttFloat .
+
+ uint32 PixelType () const
+ {
+ return fPixelType;
+ }
+
+ /// Setter for pixel type.
+ /// \param pixelType The new pixel type .
+
+ virtual void SetPixelType (uint32 pixelType);
+
+ /// Getter for pixel size.
+ /// \retval Size, in bytes, of pixel type for this image .
+
+ uint32 PixelSize () const;
+
+ /// Getter for pixel range.
+ /// For unsigned types, range is 0 to return value.
+ /// For signed types, range is return value - 0x8000U.
+ /// For ttFloat type, pixel range is 0.0 to 1.0 and this routine returns 1.
+
+ uint32 PixelRange () const;
+
+ /// Getter for best "tile stride" for accessing image.
+
+ virtual dng_rect RepeatingTile () const;
+
+ /// Get a pixel buffer of data on image with proper edge padding.
+ /// \param buffer Receives resulting pixel buffer.
+ /// \param edgeOption edge_option describing how to pad edges.
+ /// \param repeatV Amount of repeated padding needed in vertical for
+ /// edge_repeat and edge_repeat_zero_last edgeOption cases.
+ /// \param repeatH Amount of repeated padding needed in horizontal for
+ /// edge_repeat and edge_repeat_zero_last edgeOption cases.
+
+ void Get (dng_pixel_buffer &buffer,
+ edge_option edgeOption = edge_none,
+ uint32 repeatV = 1,
+ uint32 repeatH = 1) const;
+
+ /// Put a pixel buffer into image.
+ /// \param buffer Pixel buffer to copy from.
+
+ void Put (const dng_pixel_buffer &buffer);
+
+ /// Shrink bounds of image to given rectangle.
+ /// \param r Rectangle to crop to.
+
+ virtual void Trim (const dng_rect &r);
+
+ /// Rotate image to reflect given orientation change.
+ /// \param orientation Directive to rotate image in a certain way.
+
+ virtual void Rotate (const dng_orientation &orientation);
+
+ /// Copy image data from an area of one image to same area of another.
+ /// \param src Image to copy from.
+ /// \param area Rectangle of images to copy.
+ /// \param srcPlane Plane to start copying in src.
+ /// \param dstPlane Plane to start copying in this.
+ /// \param planes Number of planes to copy.
+
+ void CopyArea (const dng_image &src,
+ const dng_rect &area,
+ uint32 srcPlane,
+ uint32 dstPlane,
+ uint32 planes);
+
+ /// Copy image data from an area of one image to same area of another.
+ /// \param src Image to copy from.
+ /// \param area Rectangle of images to copy.
+ /// \param plane Plane to start copying in src and this.
+ /// \param planes Number of planes to copy.
+
+ void CopyArea (const dng_image &src,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes)
+ {
+
+ CopyArea (src, area, plane, plane, planes);
+
+ }
+
+ /// Return true if the contents of an area of the image are the same as those of another.
+ /// \param rhs Image to compare against.
+ /// \param area Rectangle of image to test.
+ /// \param plane Plane to start comparing.
+ /// \param planes Number of planes to compare.
+
+ bool EqualArea (const dng_image &rhs,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes) const;
+
+ // Routines to set the entire image to a constant value.
+
+ void SetConstant_uint8 (uint8 value,
+ const dng_rect &area)
+ {
+
+ DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");
+
+ SetConstant ((uint32) value, area);
+
+ }
+
+ void SetConstant_uint8 (uint8 value)
+ {
+ SetConstant (value, Bounds ());
+ }
+
+ void SetConstant_uint16 (uint16 value,
+ const dng_rect &area)
+ {
+
+ DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");
+
+ SetConstant ((uint32) value, area);
+
+ }
+
+ void SetConstant_uint16 (uint16 value)
+ {
+ SetConstant_uint16 (value, Bounds ());
+ }
+
+ void SetConstant_int16 (int16 value,
+ const dng_rect &area)
+ {
+
+ DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");
+
+ SetConstant ((uint32) (uint16) value, area);
+
+ }
+
+ void SetConstant_int16 (int16 value)
+ {
+ SetConstant_int16 (value, Bounds ());
+ }
+
+ void SetConstant_uint32 (uint32 value,
+ const dng_rect &area)
+ {
+
+ DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");
+
+ SetConstant (value, area);
+
+ }
+
+ void SetConstant_uint32 (uint32 value)
+ {
+ SetConstant_uint32 (value, Bounds ());
+ }
+
+ void SetConstant_real32 (real32 value,
+ const dng_rect &area)
+ {
+
+ DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");
+
+ union
+ {
+ uint32 i;
+ real32 f;
+ } x;
+
+ x.f = value;
+
+ SetConstant (x.i, area);
+
+ }
+
+ void SetConstant_real32 (real32 value)
+ {
+ SetConstant_real32 (value, Bounds ());
+ }
+
+ virtual void GetRepeat (dng_pixel_buffer &buffer,
+ const dng_rect &srcArea,
+ const dng_rect &dstArea) const;
+
+ protected:
+
+ virtual void AcquireTileBuffer (dng_tile_buffer &buffer,
+ const dng_rect &area,
+ bool dirty) const;
+
+ virtual void ReleaseTileBuffer (dng_tile_buffer &buffer) const;
+
+ virtual void DoGet (dng_pixel_buffer &buffer) const;
+
+ virtual void DoPut (const dng_pixel_buffer &buffer);
+
+ void GetEdge (dng_pixel_buffer &buffer,
+ edge_option edgeOption,
+ const dng_rect &srcArea,
+ const dng_rect &dstArea) const;
+
+ virtual void SetConstant (uint32 value,
+ const dng_rect &area);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_image_writer.cpp b/gpr/source/lib/dng_sdk/dng_image_writer.cpp
new file mode 120000
index 0000000..1b5bfed
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_image_writer.cpp
@@ -0,0 +1 @@
+../../../../.git/annex/objects/39/7q/SHA256E-s127574--7b62f1cf4fff6fca446605664f5230053caa39a43d73269e41a6c2667a023ded.cpp/SHA256E-s127574--7b62f1cf4fff6fca446605664f5230053caa39a43d73269e41a6c2667a023ded.cpp \ No newline at end of file
diff --git a/gpr/source/lib/dng_sdk/dng_image_writer.h b/gpr/source/lib/dng_sdk/dng_image_writer.h
new file mode 100644
index 0000000..23b34d1
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_image_writer.h
@@ -0,0 +1,1253 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_image_writer.h#3 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for writing DNG images to files.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_image_writer__
+#define __dng_image_writer__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_fingerprint.h"
+#include "dng_memory.h"
+#include "dng_point.h"
+#include "dng_rational.h"
+#include "dng_sdk_limits.h"
+#include "dng_string.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Image resolution.
+
+class dng_resolution
+ {
+
+ public:
+
+ dng_urational fXResolution;
+ dng_urational fYResolution;
+
+ uint16 fResolutionUnit;
+
+ public:
+
+ dng_resolution ();
+
+ };
+
+/*****************************************************************************/
+
+class tiff_tag
+ {
+
+ protected:
+
+ uint16 fCode;
+
+ uint16 fType;
+
+ uint32 fCount;
+
+ protected:
+
+ tiff_tag (uint16 code,
+ uint16 type,
+ uint32 count)
+
+ : fCode (code)
+ , fType (type)
+ , fCount (count)
+
+ {
+ }
+
+ public:
+
+ virtual ~tiff_tag ()
+ {
+ }
+
+ uint16 Code () const
+ {
+ return fCode;
+ }
+
+ uint16 Type () const
+ {
+ return fType;
+ }
+
+ uint32 Count () const
+ {
+ return fCount;
+ }
+
+ void SetCount (uint32 count)
+ {
+ fCount = count;
+ }
+
+ uint32 Size () const
+ {
+ return TagTypeSize (Type ()) * Count ();
+ }
+
+ virtual void Put (dng_stream &stream) const = 0;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ tiff_tag (const tiff_tag &tag);
+
+ tiff_tag & operator= (const tiff_tag &tag);
+
+ };
+
+/******************************************************************************/
+
+class tag_data_ptr: public tiff_tag
+ {
+
+ protected:
+
+ const void *fData;
+
+ public:
+
+ tag_data_ptr (uint16 code,
+ uint16 type,
+ uint32 count,
+ const void *data)
+
+ : tiff_tag (code, type, count)
+
+ , fData (data)
+
+ {
+ }
+
+ void SetData (const void *data)
+ {
+ fData = data;
+ }
+
+ virtual void Put (dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ tag_data_ptr (const tag_data_ptr &tag);
+
+ tag_data_ptr & operator= (const tag_data_ptr &tag);
+
+ };
+
+/******************************************************************************/
+
+class tag_string: public tiff_tag
+ {
+
+ protected:
+
+ dng_string fString;
+
+ public:
+
+ tag_string (uint16 code,
+ const dng_string &s,
+ bool forceASCII = true);
+
+ virtual void Put (dng_stream &stream) const;
+
+ };
+
+/******************************************************************************/
+
+class tag_encoded_text: public tiff_tag
+ {
+
+ private:
+
+ dng_string fText;
+
+ dng_memory_data fUTF16;
+
+ public:
+
+ tag_encoded_text (uint16 code,
+ const dng_string &text);
+
+ virtual void Put (dng_stream &stream) const;
+
+ };
+
+/******************************************************************************/
+
+class tag_uint8: public tag_data_ptr
+ {
+
+ private:
+
+ uint8 fValue;
+
+ public:
+
+ tag_uint8 (uint16 code,
+ uint8 value = 0)
+
+ : tag_data_ptr (code, ttByte, 1, &fValue)
+
+ , fValue (value)
+
+ {
+ }
+
+ void Set (uint8 value)
+ {
+ fValue = value;
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_uint8_ptr: public tag_data_ptr
+ {
+
+ public:
+
+ tag_uint8_ptr (uint16 code,
+ const uint8 *data,
+ uint32 count = 1)
+
+ : tag_data_ptr (code, ttByte, count, data)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_uint16: public tag_data_ptr
+ {
+
+ private:
+
+ uint16 fValue;
+
+ public:
+
+ tag_uint16 (uint16 code,
+ uint16 value = 0)
+
+ : tag_data_ptr (code, ttShort, 1, &fValue)
+
+ , fValue (value)
+
+ {
+ }
+
+ void Set (uint16 value)
+ {
+ fValue = value;
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_int16_ptr: public tag_data_ptr
+ {
+
+ public:
+
+ tag_int16_ptr (uint16 code,
+ const int16 *data,
+ uint32 count = 1)
+
+ : tag_data_ptr (code, ttSShort, count, data)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_uint16_ptr: public tag_data_ptr
+ {
+
+ public:
+
+ tag_uint16_ptr (uint16 code,
+ const uint16 *data,
+ uint32 count = 1)
+
+ : tag_data_ptr (code, ttShort, count, data)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_uint32: public tag_data_ptr
+ {
+
+ private:
+
+ uint32 fValue;
+
+ public:
+
+ tag_uint32 (uint16 code,
+ uint32 value = 0)
+
+ : tag_data_ptr (code, ttLong, 1, &fValue)
+
+ , fValue (value)
+
+ {
+ }
+
+ void Set (uint32 value)
+ {
+ fValue = value;
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_uint32_ptr: public tag_data_ptr
+ {
+
+ public:
+
+ tag_uint32_ptr (uint16 code,
+ const uint32 *data,
+ uint32 count = 1)
+
+ : tag_data_ptr (code, ttLong, count, data)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_urational: public tag_data_ptr
+ {
+
+ private:
+
+ const dng_urational fValue;
+
+ public:
+
+ tag_urational (uint16 code,
+ const dng_urational &value)
+
+ : tag_data_ptr (code, ttRational, 1, &fValue)
+
+ , fValue (value)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_urational_ptr: public tag_data_ptr
+ {
+
+ public:
+
+ tag_urational_ptr (uint16 code,
+ const dng_urational *data = NULL,
+ uint32 count = 1)
+
+ : tag_data_ptr (code, ttRational, count, data)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_srational: public tag_data_ptr
+ {
+
+ private:
+
+ const dng_srational fValue;
+
+ public:
+
+ tag_srational (uint16 code,
+ const dng_srational &value)
+
+ : tag_data_ptr (code, ttSRational, 1, &fValue)
+
+ , fValue (value)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_srational_ptr: public tag_data_ptr
+ {
+
+ public:
+
+ tag_srational_ptr (uint16 code,
+ const dng_srational *data = NULL,
+ uint32 count = 1)
+
+ : tag_data_ptr (code, ttSRational, count, data)
+
+ {
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_real64: public tag_data_ptr
+ {
+
+ private:
+
+ real64 fValue;
+
+ public:
+
+ tag_real64 (uint16 code,
+ real64 value = 0.0)
+
+ : tag_data_ptr (code, ttDouble, 1, &fValue)
+
+ , fValue (value)
+
+ {
+ }
+
+ void Set (real64 value)
+ {
+ fValue = value;
+ }
+
+ };
+
+/******************************************************************************/
+
+class tag_matrix: public tag_srational_ptr
+ {
+
+ private:
+
+ dng_srational fEntry [kMaxColorPlanes *
+ kMaxColorPlanes];
+
+ public:
+
+ tag_matrix (uint16 code,
+ const dng_matrix &m);
+
+ };
+
+/******************************************************************************/
+
+class tag_icc_profile: public tag_data_ptr
+ {
+
+ public:
+
+ tag_icc_profile (const void *profileData, uint32 profileSize);
+
+ };
+
+/******************************************************************************/
+
+class tag_cfa_pattern: public tiff_tag
+ {
+
+ private:
+
+ uint32 fRows;
+ uint32 fCols;
+
+ const uint8 *fPattern;
+
+ public:
+
+ tag_cfa_pattern (uint16 code,
+ uint32 rows,
+ uint32 cols,
+ const uint8 *pattern)
+
+ : tiff_tag (code, ttUndefined, 4 + rows * cols)
+
+ , fRows (rows )
+ , fCols (cols )
+ , fPattern (pattern)
+
+ {
+ }
+
+ virtual void Put (dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ tag_cfa_pattern (const tag_cfa_pattern &tag);
+
+ tag_cfa_pattern & operator= (const tag_cfa_pattern &tag);
+
+ };
+
+/******************************************************************************/
+
+class tag_exif_date_time: public tag_data_ptr
+ {
+
+ private:
+
+ char fData [20];
+
+ public:
+
+ tag_exif_date_time (uint16 code,
+ const dng_date_time &dt);
+
+ };
+
+/******************************************************************************/
+
+class tag_iptc: public tiff_tag
+ {
+
+ private:
+
+ const void *fData;
+
+ uint32 fLength;
+
+ public:
+
+ tag_iptc (const void *data,
+ uint32 length);
+
+ virtual void Put (dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ tag_iptc (const tag_iptc &tag);
+
+ tag_iptc & operator= (const tag_iptc &tag);
+
+ };
+
+/******************************************************************************/
+
+class tag_xmp: public tag_uint8_ptr
+ {
+
+ private:
+
+ AutoPtr<dng_memory_block> fBuffer;
+
+ public:
+
+ tag_xmp (const dng_xmp *xmp);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ tag_xmp (const tag_xmp &tag);
+
+ tag_xmp & operator= (const tag_xmp &tag);
+
+ };
+
+/******************************************************************************/
+
+class dng_tiff_directory
+ {
+
+ private:
+
+ enum
+ {
+ kMaxEntries = 100
+ };
+
+ uint32 fEntries;
+
+ const tiff_tag *fTag [kMaxEntries];
+
+ uint32 fChained;
+
+ public:
+
+ dng_tiff_directory ()
+
+ : fEntries (0)
+ , fChained (0)
+
+ {
+ }
+
+ virtual ~dng_tiff_directory ()
+ {
+ }
+
+ void Add (const tiff_tag *tag);
+
+ void SetChained (uint32 offset)
+ {
+ fChained = offset;
+ }
+
+ uint32 Size () const;
+
+ enum OffsetsBase
+ {
+ offsetsRelativeToStream = 0,
+ offsetsRelativeToExplicitBase = 1,
+ offsetsRelativeToIFD = 2
+ };
+
+ void Put (dng_stream &stream,
+ OffsetsBase offsetsBase = offsetsRelativeToStream,
+ uint32 explicitBase = 0) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_tiff_directory (const dng_tiff_directory &dir);
+
+ dng_tiff_directory & operator= (const dng_tiff_directory &dir);
+
+ };
+
+/******************************************************************************/
+
+class dng_basic_tag_set
+ {
+
+ private:
+
+ tag_uint32 fNewSubFileType;
+
+ tag_uint32 fImageWidth;
+ tag_uint32 fImageLength;
+
+ tag_uint16 fPhotoInterpretation;
+
+ tag_uint16 fFillOrder;
+
+ tag_uint16 fSamplesPerPixel;
+
+ uint16 fBitsPerSampleData [kMaxSamplesPerPixel];
+
+ tag_uint16_ptr fBitsPerSample;
+
+ bool fStrips;
+
+ tag_uint32 fTileWidth;
+ tag_uint32 fTileLength;
+
+ dng_memory_data fTileInfoBuffer;
+
+ uint32 *fTileOffsetData;
+
+ tag_uint32_ptr fTileOffsets;
+
+ uint32 *fTileByteCountData;
+
+ tag_uint32_ptr fTileByteCounts;
+
+ tag_uint16 fPlanarConfiguration;
+
+ tag_uint16 fCompression;
+
+ tag_uint16 fPredictor;
+
+ uint16 fExtraSamplesData [kMaxSamplesPerPixel];
+
+ tag_uint16_ptr fExtraSamples;
+
+ uint16 fSampleFormatData [kMaxSamplesPerPixel];
+
+ tag_uint16_ptr fSampleFormat;
+
+ tag_uint16 fRowInterleaveFactor;
+
+ uint16 fSubTileBlockSizeData [2];
+
+ tag_uint16_ptr fSubTileBlockSize;
+
+ public:
+
+ dng_basic_tag_set (dng_tiff_directory &directory,
+ const dng_ifd &info);
+
+ virtual ~dng_basic_tag_set ()
+ {
+ }
+
+ void SetTileOffset (uint32 index,
+ uint32 offset)
+ {
+ fTileOffsetData [index] = offset;
+ }
+
+ void SetTileByteCount (uint32 index,
+ uint32 count)
+ {
+ fTileByteCountData [index] = count;
+ }
+
+ bool WritingStrips () const
+ {
+ return fStrips;
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_basic_tag_set (const dng_basic_tag_set &set);
+
+ dng_basic_tag_set & operator= (const dng_basic_tag_set &set);
+
+ };
+
+/******************************************************************************/
+
+class exif_tag_set
+ {
+
+ protected:
+
+ dng_tiff_directory fExifIFD;
+ dng_tiff_directory fGPSIFD;
+
+ private:
+
+ tag_uint32 fExifLink;
+ tag_uint32 fGPSLink;
+
+ bool fAddedExifLink;
+ bool fAddedGPSLink;
+
+ uint8 fExifVersionData [4];
+
+ tag_data_ptr fExifVersion;
+
+ tag_urational fExposureTime;
+ tag_srational fShutterSpeedValue;
+
+ tag_urational fFNumber;
+ tag_urational fApertureValue;
+
+ tag_srational fBrightnessValue;
+
+ tag_srational fExposureBiasValue;
+
+ tag_urational fMaxApertureValue;
+
+ tag_urational fSubjectDistance;
+
+ tag_urational fFocalLength;
+
+ tag_uint16 fISOSpeedRatings;
+
+ tag_uint16 fSensitivityType;
+ tag_uint32 fStandardOutputSensitivity;
+ tag_uint32 fRecommendedExposureIndex;
+ tag_uint32 fISOSpeed;
+ tag_uint32 fISOSpeedLatitudeyyy;
+ tag_uint32 fISOSpeedLatitudezzz;
+
+ tag_uint16 fFlash;
+
+ tag_uint16 fExposureProgram;
+
+ tag_uint16 fMeteringMode;
+
+ tag_uint16 fLightSource;
+
+ tag_uint16 fSensingMethod;
+
+ tag_uint16 fFocalLength35mm;
+
+ uint8 fFileSourceData;
+ tag_data_ptr fFileSource;
+
+ uint8 fSceneTypeData;
+ tag_data_ptr fSceneType;
+
+ tag_cfa_pattern fCFAPattern;
+
+ tag_uint16 fCustomRendered;
+ tag_uint16 fExposureMode;
+ tag_uint16 fWhiteBalance;
+ tag_uint16 fSceneCaptureType;
+ tag_uint16 fGainControl;
+ tag_uint16 fContrast;
+ tag_uint16 fSaturation;
+ tag_uint16 fSharpness;
+ tag_uint16 fSubjectDistanceRange;
+
+ tag_urational fDigitalZoomRatio;
+
+ tag_urational fExposureIndex;
+
+ tag_uint32 fImageNumber;
+
+ tag_uint16 fSelfTimerMode;
+
+ tag_string fBatteryLevelA;
+ tag_urational fBatteryLevelR;
+
+ tag_urational fFocalPlaneXResolution;
+ tag_urational fFocalPlaneYResolution;
+
+ tag_uint16 fFocalPlaneResolutionUnit;
+
+ uint16 fSubjectAreaData [4];
+
+ tag_uint16_ptr fSubjectArea;
+
+ dng_urational fLensInfoData [4];
+
+ tag_urational_ptr fLensInfo;
+
+ tag_exif_date_time fDateTime;
+ tag_exif_date_time fDateTimeOriginal;
+ tag_exif_date_time fDateTimeDigitized;
+
+ tag_string fSubsecTime;
+ tag_string fSubsecTimeOriginal;
+ tag_string fSubsecTimeDigitized;
+
+ tag_string fMake;
+ tag_string fModel;
+ tag_string fArtist;
+ tag_string fSoftware;
+ tag_string fCopyright;
+ tag_string fImageDescription;
+
+ tag_string fSerialNumber;
+
+ tag_uint16 fMakerNoteSafety;
+
+ tag_data_ptr fMakerNote;
+
+ tag_encoded_text fUserComment;
+
+ char fImageUniqueIDData [33];
+
+ tag_data_ptr fImageUniqueID;
+
+ // EXIF 2.3 tags.
+
+ tag_string fCameraOwnerName;
+ tag_string fBodySerialNumber;
+ tag_urational_ptr fLensSpecification;
+ tag_string fLensMake;
+ tag_string fLensModel;
+ tag_string fLensSerialNumber;
+
+ uint8 fGPSVersionData [4];
+
+ tag_uint8_ptr fGPSVersionID;
+
+ tag_string fGPSLatitudeRef;
+ tag_urational_ptr fGPSLatitude;
+
+ tag_string fGPSLongitudeRef;
+ tag_urational_ptr fGPSLongitude;
+
+ tag_uint8 fGPSAltitudeRef;
+ tag_urational fGPSAltitude;
+
+ tag_urational_ptr fGPSTimeStamp;
+
+ tag_string fGPSSatellites;
+ tag_string fGPSStatus;
+ tag_string fGPSMeasureMode;
+
+ tag_urational fGPSDOP;
+
+ tag_string fGPSSpeedRef;
+ tag_urational fGPSSpeed;
+
+ tag_string fGPSTrackRef;
+ tag_urational fGPSTrack;
+
+ tag_string fGPSImgDirectionRef;
+ tag_urational fGPSImgDirection;
+
+ tag_string fGPSMapDatum;
+
+ tag_string fGPSDestLatitudeRef;
+ tag_urational_ptr fGPSDestLatitude;
+
+ tag_string fGPSDestLongitudeRef;
+ tag_urational_ptr fGPSDestLongitude;
+
+ tag_string fGPSDestBearingRef;
+ tag_urational fGPSDestBearing;
+
+ tag_string fGPSDestDistanceRef;
+ tag_urational fGPSDestDistance;
+
+ tag_encoded_text fGPSProcessingMethod;
+ tag_encoded_text fGPSAreaInformation;
+
+ tag_string fGPSDateStamp;
+
+ tag_uint16 fGPSDifferential;
+
+ tag_urational fGPSHPositioningError;
+
+ public:
+
+ exif_tag_set (dng_tiff_directory &directory,
+ const dng_exif &exif,
+ bool makerNoteSafe = false,
+ const void *makerNoteData = NULL,
+ uint32 makerNoteLength = 0,
+ bool insideDNG = false);
+
+ void Locate (uint32 offset)
+ {
+ fExifLink.Set (offset);
+ fGPSLink .Set (offset + fExifIFD.Size ());
+ }
+
+ uint32 Size () const
+ {
+ return fExifIFD.Size () +
+ fGPSIFD .Size ();
+ }
+
+ void Put (dng_stream &stream) const
+ {
+ fExifIFD.Put (stream);
+ fGPSIFD .Put (stream);
+ }
+
+ protected:
+
+ void AddLinks (dng_tiff_directory &directory);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ exif_tag_set (const exif_tag_set &set);
+
+ exif_tag_set & operator= (const exif_tag_set &set);
+
+ };
+
+/******************************************************************************/
+
+class tiff_dng_extended_color_profile: private dng_tiff_directory
+ {
+
+ protected:
+
+ const dng_camera_profile &fProfile;
+
+ public:
+
+ tiff_dng_extended_color_profile (const dng_camera_profile &profile);
+
+ void Put (dng_stream &stream,
+ bool includeModelRestriction = true);
+
+ };
+
+/*****************************************************************************/
+
+class tag_dng_noise_profile: public tag_data_ptr
+ {
+
+ protected:
+
+ real64 fValues [2 * kMaxColorPlanes];
+
+ public:
+
+ explicit tag_dng_noise_profile (const dng_noise_profile &profile);
+
+ };
+
+/*****************************************************************************/
+
+// Enum to control the subset of metadata to save to a file.
+
+enum dng_metadata_subset
+ {
+
+ kMetadataSubset_CopyrightOnly = 0,
+ kMetadataSubset_CopyrightAndContact,
+ kMetadataSubset_AllExceptCameraInfo,
+ kMetadataSubset_All,
+ kMetadataSubset_AllExceptLocationInfo,
+ kMetadataSubset_AllExceptCameraAndLocation,
+
+ kMetadataSubset_Last = kMetadataSubset_AllExceptCameraAndLocation
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Support for writing dng_image or dng_negative instances to a
+/// dng_stream in TIFF or DNG format.
+
+class dng_image_writer
+ {
+
+ bool fComputeMd5Sum; // Set to true to compute md5sum
+
+ friend class dng_jpeg_image;
+ friend class dng_jpeg_image_encode_task;
+ friend class dng_write_tiles_task;
+
+ protected:
+
+ enum
+ {
+
+ // Target size for buffer used to copy data to the image.
+
+ kImageBufferSize = 128 * 1024
+
+ };
+
+ public:
+
+ dng_image_writer ();
+
+ virtual ~dng_image_writer ();
+
+#if GPR_WRITING
+ virtual uint32 GetDefaultCompression() { return ccJPEG; }
+#endif
+
+ void SetComputeMd5Sum(bool x) { fComputeMd5Sum = x; }
+
+ virtual void EncodeJPEGPreview (dng_host &host,
+ const dng_image &image,
+ dng_jpeg_preview &preview,
+ int32 quality = -1);
+
+ virtual void WriteImage (dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels = 1);
+
+ /// Write a dng_image to a dng_stream in TIFF format.
+ /// \param host Host interface used for progress updates, abort testing, buffer allocation, etc.
+ /// \param stream The dng_stream on which to write the TIFF.
+ /// \param image The actual image data to be written.
+ /// \param photometricInterpretation Either piBlackIsZero for monochrome or piRGB for RGB images.
+ /// \param compression Must be ccUncompressed.
+ /// \param negative or metadata If non-NULL, EXIF, IPTC, and XMP metadata from this negative is written to TIFF.
+ /// \param space If non-null and color space has an ICC profile, TIFF will be tagged with this
+ /// profile. No color space conversion of image data occurs.
+ /// \param resolution If non-NULL, TIFF will be tagged with this resolution.
+ /// \param thumbnail If non-NULL, will be stored in TIFF as preview image.
+ /// \param imageResources If non-NULL, will image resources be stored in TIFF as well.
+ /// \param metadataSubset The subset of metadata (e.g., copyright only) to include in the TIFF.
+
+ void WriteTIFF (dng_host &host,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 photometricInterpretation,
+ uint32 compression,
+ dng_negative *negative,
+ const dng_color_space *space = NULL,
+ const dng_resolution *resolution = NULL,
+ const dng_jpeg_preview *thumbnail = NULL,
+ const dng_memory_block *imageResources = NULL,
+ dng_metadata_subset metadataSubset = kMetadataSubset_All);
+
+ void WriteTIFF (dng_host &host,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 photometricInterpretation = piBlackIsZero,
+ uint32 compression = ccUncompressed,
+ const dng_metadata *metadata = NULL,
+ const dng_color_space *space = NULL,
+ const dng_resolution *resolution = NULL,
+ const dng_jpeg_preview *thumbnail = NULL,
+ const dng_memory_block *imageResources = NULL,
+ dng_metadata_subset metadataSubset = kMetadataSubset_All);
+
+ /// Write a dng_image to a dng_stream in TIFF format.
+ /// \param host Host interface used for progress updates, abort testing, buffer allocation, etc.
+ /// \param stream The dng_stream on which to write the TIFF.
+ /// \param image The actual image data to be written.
+ /// \param photometricInterpretation Either piBlackIsZero for monochrome or piRGB for RGB images.
+ /// \param compression Must be ccUncompressed.
+ /// \param negative or metadata If non-NULL, EXIF, IPTC, and XMP metadata from this negative is written to TIFF.
+ /// \param profileData If non-null, TIFF will be tagged with this profile. No color space conversion
+ /// of image data occurs.
+ /// \param profileSize The size for the profile data.
+ /// \param resolution If non-NULL, TIFF will be tagged with this resolution.
+ /// \param thumbnail If non-NULL, will be stored in TIFF as preview image.
+ /// \param imageResources If non-NULL, will image resources be stored in TIFF as well.
+ /// \param metadataSubset The subset of metadata (e.g., copyright only) to include in the TIFF.
+
+ void WriteTIFFWithProfile (dng_host &host,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 photometricInterpretation,
+ uint32 compression,
+ dng_negative *negative,
+ const void *profileData = NULL,
+ uint32 profileSize = 0,
+ const dng_resolution *resolution = NULL,
+ const dng_jpeg_preview *thumbnail = NULL,
+ const dng_memory_block *imageResources = NULL,
+ dng_metadata_subset metadataSubset = kMetadataSubset_All);
+
+ virtual void WriteTIFFWithProfile (dng_host &host,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 photometricInterpretation = piBlackIsZero,
+ uint32 compression = ccUncompressed,
+ const dng_metadata *metadata = NULL,
+ const void *profileData = NULL,
+ uint32 profileSize = 0,
+ const dng_resolution *resolution = NULL,
+ const dng_jpeg_preview *thumbnail = NULL,
+ const dng_memory_block *imageResources = NULL,
+ dng_metadata_subset metadataSubset = kMetadataSubset_All);
+
+ /// Write a dng_image to a dng_stream in DNG format.
+ /// \param host Host interface used for progress updates, abort testing, buffer allocation, etc.
+ /// \param stream The dng_stream on which to write the TIFF.
+ /// \param negative The image data and metadata (EXIF, IPTC, XMP) to be written.
+ /// \param previewList List of previews (not counting thumbnail) to write to the file. Defaults to empty.
+ /// \param maxBackwardVersion The DNG file should be readable by readers at least back to this version.
+ /// \param uncompressed True to force uncompressed images. Otherwise use normal compression.
+
+ void WriteDNG (dng_host &host,
+ dng_stream &stream,
+ dng_negative &negative,
+ const dng_preview_list *previewList = NULL,
+ uint32 maxBackwardVersion = dngVersion_SaveDefault,
+ bool uncompressed = false);
+
+ /// Write a dng_image to a dng_stream in DNG format.
+ /// \param host Host interface used for progress updates, abort testing, buffer allocation, etc.
+ /// \param stream The dng_stream on which to write the TIFF.
+ /// \param negative The image data to be written.
+ /// \param metadata The metadata (EXIF, IPTC, XMP) to be written.
+ /// \param previewList List of previews (not counting thumbnail) to write to the file. Defaults to empty.
+ /// \param maxBackwardVersion The DNG file should be readable by readers at least back to this version.
+ /// \param uncompressed True to force uncompressed images. Otherwise use normal compression.
+
+ virtual void WriteDNG (dng_host &host,
+ dng_stream &stream,
+ const dng_negative &negative,
+ const dng_metadata &metadata,
+ const dng_preview_list *previewList = NULL,
+ uint32 maxBackwardVersion = dngVersion_SaveDefault,
+ bool uncompressed = false);
+
+ /// Resolve metadata conflicts and apply metadata policies in keeping
+ /// with Metadata Working Group (MWG) guidelines.
+
+ virtual void CleanUpMetadata (dng_host &host,
+ dng_metadata &metadata,
+ dng_metadata_subset metadataSubset,
+ const char *dstMIMI,
+ const char *software = NULL);
+
+ protected:
+
+ virtual uint32 CompressedBufferSize (const dng_ifd &ifd,
+ uint32 uncompressedSize);
+
+ virtual void EncodePredictor (dng_host &host,
+ const dng_ifd &ifd,
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &tempBuffer);
+
+ virtual void ByteSwapBuffer (dng_host &host,
+ dng_pixel_buffer &buffer);
+
+ void ReorderSubTileBlocks (const dng_ifd &ifd,
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer);
+
+ virtual void WriteData (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &compressedBuffer);
+
+ virtual void WriteTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ const dng_image &image,
+ const dng_rect &tileArea,
+ uint32 fakeChannels,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_info.cpp b/gpr/source/lib/dng_sdk/dng_info.cpp
new file mode 100644
index 0000000..cf4a599
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_info.cpp
@@ -0,0 +1,2529 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_info.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_info.h"
+
+#include "dng_camera_profile.h"
+#include "dng_exceptions.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_tag_codes.h"
+#include "dng_parse_utils.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_info::dng_info ()
+
+ : fTIFFBlockOffset (0)
+ , fTIFFBlockOriginalOffset (kDNGStreamInvalidOffset)
+ , fBigEndian (false)
+ , fMagic (0)
+ , fExif ()
+ , fShared ()
+ , fMainIndex (-1)
+ , fMaskIndex (-1)
+ , fIFDCount (0)
+ , fChainedIFDCount (0)
+ , fMakerNoteNextIFD (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_info::~dng_info ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::ValidateMagic ()
+ {
+
+ switch (fMagic)
+ {
+
+ case magicTIFF:
+ case magicExtendedProfile:
+ case magicRawCache:
+ case magicPanasonic:
+ case magicOlympusA:
+ case magicOlympusB:
+ {
+
+ return;
+
+ }
+
+ default:
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid TIFF magic number");
+
+ #endif
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::ParseTag (dng_host &host,
+ dng_stream &stream,
+ dng_exif *exif,
+ dng_shared *shared,
+ dng_ifd *ifd,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset,
+ int64 offsetDelta)
+ {
+
+ bool isSubIFD = parentCode >= tcFirstSubIFD &&
+ parentCode <= tcLastSubIFD;
+
+ bool isMainIFD = (parentCode == 0 || isSubIFD) &&
+ ifd &&
+ ifd->fUsesNewSubFileType &&
+ ifd->fNewSubFileType == sfMainImage;
+
+ // Panasonic RAW format stores private tags using tag codes < 254 in
+ // IFD 0. Redirect the parsing of these tags into a logical
+ // "PanasonicRAW" IFD.
+
+ // Panasonic is starting to use some higher numbers also (280..283).
+
+ if (fMagic == 85 && parentCode == 0 && (tagCode < tcNewSubFileType ||
+ (tagCode >= 280 && tagCode <= 283)))
+ {
+
+ parentCode = tcPanasonicRAW;
+
+ ifd = NULL;
+
+ }
+
+ stream.SetReadPosition (tagOffset);
+
+ if (ifd && ifd->ParseTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return;
+
+ }
+
+ stream.SetReadPosition (tagOffset);
+
+ if (exif && shared && exif->ParseTag (stream,
+ *shared,
+ parentCode,
+ isMainIFD,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return;
+
+ }
+
+ stream.SetReadPosition (tagOffset);
+
+ if (shared && exif && shared->ParseTag (stream,
+ *exif,
+ parentCode,
+ isMainIFD,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset,
+ offsetDelta))
+ {
+
+ return;
+
+ }
+
+ if (parentCode == tcLeicaMakerNote &&
+ tagType == ttUndefined &&
+ tagCount >= 14)
+ {
+
+ if (ParseMakerNoteIFD (host,
+ stream,
+ tagCount,
+ tagOffset,
+ offsetDelta,
+ tagOffset,
+ stream.Length (),
+ tcLeicaMakerNote))
+ {
+
+ return;
+
+ }
+
+ }
+
+ if (parentCode == tcOlympusMakerNote &&
+ tagType == ttUndefined &&
+ tagCount >= 14)
+ {
+
+ uint32 olympusMakerParent = 0;
+
+ switch (tagCode)
+ {
+
+ case 8208:
+ olympusMakerParent = tcOlympusMakerNote8208;
+ break;
+
+ case 8224:
+ olympusMakerParent = tcOlympusMakerNote8224;
+ break;
+
+ case 8240:
+ olympusMakerParent = tcOlympusMakerNote8240;
+ break;
+
+ case 8256:
+ olympusMakerParent = tcOlympusMakerNote8256;
+ break;
+
+ case 8272:
+ olympusMakerParent = tcOlympusMakerNote8272;
+ break;
+
+ case 12288:
+ olympusMakerParent = tcOlympusMakerNote12288;
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (olympusMakerParent)
+ {
+
+ // Olympus made a mistake in some camera models in computing
+ // the size of these sub-tags, so we fudge the count.
+
+ if (ParseMakerNoteIFD (host,
+ stream,
+ stream.Length () - tagOffset,
+ tagOffset,
+ offsetDelta,
+ tagOffset,
+ stream.Length (),
+ olympusMakerParent))
+ {
+
+ return;
+
+ }
+
+ }
+
+ }
+
+ if (parentCode == tcRicohMakerNote &&
+ tagCode == 0x2001 &&
+ tagType == ttUndefined &&
+ tagCount > 22)
+ {
+
+ char header [20];
+
+ stream.SetReadPosition (tagOffset);
+
+ stream.Get (header, sizeof (header));
+
+ if (memcmp (header, "[Ricoh Camera Info]", 19) == 0)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ tagCount - 20,
+ tagOffset + 20,
+ offsetDelta,
+ tagOffset + 20,
+ tagOffset + tagCount,
+ tcRicohMakerNoteCameraInfo);
+
+ return;
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ if (gVerbose)
+ {
+
+ printf ("*");
+
+ DumpTagValues (stream,
+ LookupTagType (tagType),
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ // If type is ASCII, then parse anyway so we report any ASCII
+ // NULL termination or character set errors.
+
+ else if (tagType == ttAscii)
+ {
+
+ dng_string s;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ s,
+ false);
+
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+bool dng_info::ValidateIFD (dng_stream &stream,
+ uint64 ifdOffset,
+ int64 offsetDelta)
+ {
+
+ // Make sure we have a count.
+
+ if (ifdOffset + 2 > stream.Length ())
+ {
+ return false;
+ }
+
+ // Get entry count.
+
+ stream.SetReadPosition (ifdOffset);
+
+ uint32 ifdEntries = stream.Get_uint16 ();
+
+ if (ifdEntries < 1)
+ {
+ return false;
+ }
+
+ // Make sure we have room for all entries and next IFD link.
+
+ if (ifdOffset + 2 + ifdEntries * 12 + 4 > stream.Length ())
+ {
+ return false;
+ }
+
+ // Check each entry.
+
+ for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
+ {
+
+ stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
+
+ stream.Skip (2); // Ignore tag code.
+
+ uint32 tagType = stream.Get_uint16 ();
+ uint32 tagCount = stream.Get_uint32 ();
+
+ uint32 tag_type_size = TagTypeSize (tagType);
+
+ if (tag_type_size == 0)
+ {
+ return false;
+ }
+
+ uint32 tag_data_size = tagCount * tag_type_size;
+
+ if (tag_data_size > 4)
+ {
+
+ uint64 tagOffset = stream.Get_uint32 ();
+
+ tagOffset += offsetDelta;
+
+ if (tagOffset + tag_data_size > stream.Length ())
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::ParseIFD (dng_host &host,
+ dng_stream &stream,
+ dng_exif *exif,
+ dng_shared *shared,
+ dng_ifd *ifd,
+ uint64 ifdOffset,
+ int64 offsetDelta,
+ uint32 parentCode)
+ {
+
+ #if qDNGValidate
+
+ bool isMakerNote = (parentCode >= tcFirstMakerNoteIFD &&
+ parentCode <= tcLastMakerNoteIFD);
+
+ #endif
+
+ stream.SetReadPosition (ifdOffset);
+
+ if (ifd)
+ {
+ ifd->fThisIFD = ifdOffset;
+ }
+
+ uint32 ifdEntries = stream.Get_uint16 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: Offset = %u, Entries = %u\n\n",
+ LookupParentCode (parentCode),
+ (unsigned) ifdOffset,
+ (unsigned) ifdEntries);
+
+ }
+
+ if ((ifdOffset & 1) && !isMakerNote)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s has odd offset (%u)",
+ LookupParentCode (parentCode),
+ (unsigned) ifdOffset);
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ uint32 prev_tag_code = 0;
+
+ for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
+ {
+
+ stream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
+
+ uint32 tagCode = stream.Get_uint16 ();
+ uint32 tagType = stream.Get_uint16 ();
+
+ // Minolta 7D files have a bug in the EXIF block where the count
+ // is wrong, and we run off into next IFD link. So if abort parsing
+ // if we get a zero code/type combinations.
+
+ if (tagCode == 0 && tagType == 0)
+ {
+
+ #if qDNGValidate
+
+ char message [256];
+
+ sprintf (message,
+ "%s had zero/zero tag code/type entry",
+ LookupParentCode (parentCode));
+
+ ReportWarning (message);
+
+ #endif
+
+ return;
+
+ }
+
+ uint32 tagCount = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ {
+
+ if (tag_index > 0 && tagCode <= prev_tag_code && !isMakerNote)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s tags are not sorted in ascending numerical order",
+ LookupParentCode (parentCode));
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ #endif
+
+ prev_tag_code = tagCode;
+
+ uint32 tag_type_size = TagTypeSize (tagType);
+
+ if (tag_type_size == 0)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has unknown type (%u)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode),
+ (unsigned) tagType);
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ continue;
+
+ }
+
+ uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
+
+ if (tagCount * tag_type_size > 4)
+ {
+
+ tagOffset = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ {
+
+ if (!(ifdOffset & 1) &&
+ (tagOffset & 1) &&
+ !isMakerNote &&
+ parentCode != tcKodakDCRPrivateIFD &&
+ parentCode != tcKodakKDCPrivateIFD)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has odd data offset (%u)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode),
+ (unsigned) tagOffset);
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ #endif
+
+ tagOffset += offsetDelta;
+
+ stream.SetReadPosition (tagOffset);
+
+ }
+
+ ParseTag (host,
+ stream,
+ exif,
+ shared,
+ ifd,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset,
+ offsetDelta);
+
+ }
+
+ stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
+
+ uint32 nextIFD = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("NextIFD = %u\n", (unsigned) nextIFD);
+ }
+
+ #endif
+
+ if (ifd)
+ {
+ ifd->fNextIFD = nextIFD;
+ }
+
+ #if qDNGValidate
+
+ if (nextIFD)
+ {
+
+ if (parentCode != 0 &&
+ (parentCode < tcFirstChainedIFD ||
+ parentCode > tcLastChainedIFD ))
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s has an unexpected non-zero NextIFD (%u)",
+ LookupParentCode (parentCode),
+ (unsigned) nextIFD);
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ if (gVerbose)
+ {
+ printf ("\n");
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+bool dng_info::ParseMakerNoteIFD (dng_host &host,
+ dng_stream &stream,
+ uint64 ifdSize,
+ uint64 ifdOffset,
+ int64 offsetDelta,
+ uint64 minOffset,
+ uint64 maxOffset,
+ uint32 parentCode)
+ {
+
+ uint32 tagIndex;
+ uint32 tagCode;
+ uint32 tagType;
+ uint32 tagCount;
+
+ // Assume there is no next IFD pointer.
+
+ fMakerNoteNextIFD = 0;
+
+ // If size is too small to hold a single entry IFD, abort.
+
+ if (ifdSize < 14)
+ {
+ return false;
+ }
+
+ // Get entry count.
+
+ stream.SetReadPosition (ifdOffset);
+
+ uint32 ifdEntries = stream.Get_uint16 ();
+
+ // Make the entry count if reasonable for the MakerNote size.
+
+ if (ifdEntries < 1 || 2 + ifdEntries * 12 > ifdSize)
+ {
+ return false;
+ }
+
+ // Scan IFD to verify all the tag types are all valid.
+
+ for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
+ {
+
+ stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
+
+ tagType = stream.Get_uint16 ();
+
+ // Kludge: Some Canon MakerNotes contain tagType = 0 tags, so we
+ // need to ignore them. This was a "firmware 1.0.4" Canon 40D raw file.
+
+ if (parentCode == tcCanonMakerNote && tagType == 0)
+ {
+ continue;
+ }
+
+ if (TagTypeSize (tagType) == 0)
+ {
+ return false;
+ }
+
+ }
+
+ // OK, the IFD looks reasonable enough to parse.
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("%s: Offset = %u, Entries = %u\n\n",
+ LookupParentCode (parentCode),
+ (unsigned) ifdOffset,
+ (unsigned) ifdEntries);
+
+ }
+
+ #endif
+
+ for (tagIndex = 0; tagIndex < ifdEntries; tagIndex++)
+ {
+
+ stream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
+
+ tagCode = stream.Get_uint16 ();
+ tagType = stream.Get_uint16 ();
+ tagCount = stream.Get_uint32 ();
+
+ if (tagType == 0)
+ {
+ continue;
+ }
+
+ uint32 tagSize = tagCount * TagTypeSize (tagType);
+
+ uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
+
+ if (tagSize > 4)
+ {
+
+ tagOffset = stream.Get_uint32 () + offsetDelta;
+
+ if (tagOffset < minOffset ||
+ tagOffset + tagSize > maxOffset)
+ {
+
+ // Tag data is outside the valid offset range,
+ // so ignore this tag.
+
+ continue;
+
+ }
+
+ stream.SetReadPosition (tagOffset);
+
+ }
+
+ // Olympus switched to using IFDs in version 3 makernotes.
+
+ if (parentCode == tcOlympusMakerNote &&
+ tagType == ttIFD &&
+ tagCount == 1)
+ {
+
+ uint32 olympusMakerParent = 0;
+
+ switch (tagCode)
+ {
+
+ case 8208:
+ olympusMakerParent = tcOlympusMakerNote8208;
+ break;
+
+ case 8224:
+ olympusMakerParent = tcOlympusMakerNote8224;
+ break;
+
+ case 8240:
+ olympusMakerParent = tcOlympusMakerNote8240;
+ break;
+
+ case 8256:
+ olympusMakerParent = tcOlympusMakerNote8256;
+ break;
+
+ case 8272:
+ olympusMakerParent = tcOlympusMakerNote8272;
+ break;
+
+ case 12288:
+ olympusMakerParent = tcOlympusMakerNote12288;
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (olympusMakerParent)
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ uint64 subMakerNoteOffset = stream.Get_uint32 () + offsetDelta;
+
+ if (subMakerNoteOffset >= minOffset &&
+ subMakerNoteOffset < maxOffset)
+ {
+
+ if (ParseMakerNoteIFD (host,
+ stream,
+ maxOffset - subMakerNoteOffset,
+ subMakerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ olympusMakerParent))
+ {
+
+ continue;
+
+ }
+
+ }
+
+ }
+
+ stream.SetReadPosition (tagOffset);
+
+ }
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset,
+ offsetDelta);
+
+ }
+
+ // Grab next IFD pointer, for possible use.
+
+ if (ifdSize >= 2 + ifdEntries * 12 + 4)
+ {
+
+ stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
+
+ fMakerNoteNextIFD = stream.Get_uint32 ();
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\n");
+ }
+
+ #endif
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::ParseMakerNote (dng_host &host,
+ dng_stream &stream,
+ uint32 makerNoteCount,
+ uint64 makerNoteOffset,
+ int64 offsetDelta,
+ uint64 minOffset,
+ uint64 maxOffset)
+ {
+
+ uint8 firstBytes [16];
+
+ memset (firstBytes, 0, sizeof (firstBytes));
+
+ stream.SetReadPosition (makerNoteOffset);
+
+ stream.Get (firstBytes, (uint32) Min_uint64 (sizeof (firstBytes),
+ makerNoteCount));
+
+ // Epson MakerNote with header.
+
+ if (memcmp (firstBytes, "EPSON\000\001\000", 8) == 0)
+ {
+
+ if (makerNoteCount > 8)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 8,
+ makerNoteOffset + 8,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcEpsonMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Fujifilm MakerNote.
+
+ if (memcmp (firstBytes, "FUJIFILM", 8) == 0)
+ {
+
+ stream.SetReadPosition (makerNoteOffset + 8);
+
+ TempLittleEndian tempEndian (stream);
+
+ uint32 ifd_offset = stream.Get_uint32 ();
+
+ if (ifd_offset >= 12 && ifd_offset < makerNoteCount)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - ifd_offset,
+ makerNoteOffset + ifd_offset,
+ makerNoteOffset,
+ minOffset,
+ maxOffset,
+ tcFujiMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Leica MakerNote for models that store entry offsets relative to the start of
+ // the MakerNote (e.g., M9).
+
+ if ((memcmp (firstBytes, "LEICA\000\000\000", 8) == 0) ||
+ (memcmp (firstBytes, "LEICA0\003\000", 8) == 0) ||
+ (memcmp (firstBytes, "LEICA\000\001\000", 8) == 0) ||
+ (memcmp (firstBytes, "LEICA\000\005\000", 8) == 0))
+ {
+
+ if (makerNoteCount > 8)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 8,
+ makerNoteOffset + 8,
+ makerNoteOffset,
+ minOffset,
+ maxOffset,
+ tcLeicaMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Leica MakerNote for models that store absolute entry offsets (i.e., relative
+ // to the start of the file, e.g., S2).
+
+ if (memcmp (firstBytes, "LEICA\000\002\377", 8) == 0)
+ {
+
+ if (makerNoteCount > 8)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 8,
+ makerNoteOffset + 8,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcLeicaMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Nikon version 2 MakerNote with header.
+
+ if (memcmp (firstBytes, "Nikon\000\002", 7) == 0)
+ {
+
+ stream.SetReadPosition (makerNoteOffset + 10);
+
+ bool bigEndian = false;
+
+ uint16 endianMark = stream.Get_uint16 ();
+
+ if (endianMark == byteOrderMM)
+ {
+ bigEndian = true;
+ }
+
+ else if (endianMark != byteOrderII)
+ {
+ return;
+ }
+
+ TempBigEndian temp_endian (stream, bigEndian);
+
+ uint16 magic = stream.Get_uint16 ();
+
+ if (magic != 42)
+ {
+ return;
+ }
+
+ uint32 ifd_offset = stream.Get_uint32 ();
+
+ if (ifd_offset >= 8 && ifd_offset < makerNoteCount - 10)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 10 - ifd_offset,
+ makerNoteOffset + 10 + ifd_offset,
+ makerNoteOffset + 10,
+ minOffset,
+ maxOffset,
+ tcNikonMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Newer version of Olympus MakerNote with byte order mark.
+
+ if (memcmp (firstBytes, "OLYMPUS\000", 8) == 0)
+ {
+
+ stream.SetReadPosition (makerNoteOffset + 8);
+
+ bool bigEndian = false;
+
+ uint16 endianMark = stream.Get_uint16 ();
+
+ if (endianMark == byteOrderMM)
+ {
+ bigEndian = true;
+ }
+
+ else if (endianMark != byteOrderII)
+ {
+ return;
+ }
+
+ TempBigEndian temp_endian (stream, bigEndian);
+
+ uint16 version = stream.Get_uint16 ();
+
+ if (version != 3)
+ {
+ return;
+ }
+
+ if (makerNoteCount > 12)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 12,
+ makerNoteOffset + 12,
+ makerNoteOffset,
+ minOffset,
+ maxOffset,
+ tcOlympusMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Olympus MakerNote with header.
+
+ if (memcmp (firstBytes, "OLYMP", 5) == 0)
+ {
+
+ if (makerNoteCount > 8)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 8,
+ makerNoteOffset + 8,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcOlympusMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Panasonic MakerNote.
+
+ if (memcmp (firstBytes, "Panasonic\000\000\000", 12) == 0)
+ {
+
+ if (makerNoteCount > 12)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 12,
+ makerNoteOffset + 12,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcPanasonicMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Pentax MakerNote.
+
+ if (memcmp (firstBytes, "AOC", 4) == 0)
+ {
+
+ if (makerNoteCount > 6)
+ {
+
+ stream.SetReadPosition (makerNoteOffset + 4);
+
+ bool bigEndian = stream.BigEndian ();
+
+ uint16 endianMark = stream.Get_uint16 ();
+
+ if (endianMark == byteOrderMM)
+ {
+ bigEndian = true;
+ }
+
+ else if (endianMark == byteOrderII)
+ {
+ bigEndian = false;
+ }
+
+ TempBigEndian temp_endian (stream, bigEndian);
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 6,
+ makerNoteOffset + 6,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcPentaxMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Ricoh MakerNote.
+
+ if (memcmp (firstBytes, "RICOH", 5) == 0 ||
+ memcmp (firstBytes, "Ricoh", 5) == 0)
+ {
+
+ if (makerNoteCount > 8)
+ {
+
+ TempBigEndian tempEndian (stream);
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 8,
+ makerNoteOffset + 8,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcRicohMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Nikon MakerNote without header.
+
+ if (fExif->fMake.StartsWith ("NIKON"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcNikonMakerNote);
+
+ return;
+
+ }
+
+ // Canon MakerNote.
+
+ if (fExif->fMake.StartsWith ("CANON"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcCanonMakerNote);
+
+ return;
+
+ }
+
+ // Minolta MakerNote.
+
+ if (fExif->fMake.StartsWith ("MINOLTA" ) ||
+ fExif->fMake.StartsWith ("KONICA MINOLTA"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcMinoltaMakerNote);
+
+ return;
+
+ }
+
+ // Sony MakerNote.
+
+ if (fExif->fMake.StartsWith ("SONY"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcSonyMakerNote);
+
+ return;
+
+ }
+
+ // Kodak MakerNote.
+
+ if (fExif->fMake.StartsWith ("EASTMAN KODAK"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcKodakMakerNote);
+
+ return;
+
+ }
+
+ // Mamiya MakerNote.
+
+ if (fExif->fMake.StartsWith ("Mamiya"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcMamiyaMakerNote);
+
+ // Mamiya uses a MakerNote chain.
+
+ while (fMakerNoteNextIFD)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ offsetDelta + fMakerNoteNextIFD,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcMamiyaMakerNote);
+
+ }
+
+ return;
+
+ }
+
+ // Nikon MakerNote without header.
+
+ if (fExif->fMake.StartsWith ("Hasselblad"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ offsetDelta,
+ minOffset,
+ maxOffset,
+ tcHasselbladMakerNote);
+
+ return;
+
+ }
+
+ // Samsung MakerNote.
+
+ if (fExif->fMake.StartsWith ("Samsung"))
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount,
+ makerNoteOffset,
+ makerNoteOffset,
+ minOffset,
+ maxOffset,
+ tcSamsungMakerNote);
+
+ return;
+
+ }
+
+ // Casio MakerNote.
+
+ if (fExif->fMake.StartsWith ("CASIO COMPUTER") &&
+ memcmp (firstBytes, "QVC\000\000\000", 6) == 0)
+ {
+
+ ParseMakerNoteIFD (host,
+ stream,
+ makerNoteCount - 6,
+ makerNoteOffset + 6,
+ makerNoteOffset,
+ minOffset,
+ maxOffset,
+ tcCasioMakerNote);
+
+ return;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::ParseSonyPrivateData (dng_host & /* host */,
+ dng_stream & /* stream */,
+ uint64 /* count */,
+ uint64 /* oldOffset */,
+ uint64 /* newOffset */)
+ {
+
+ // Sony private data is encrypted, sorry.
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::ParseDNGPrivateData (dng_host &host,
+ dng_stream &stream)
+ {
+
+ if (fShared->fDNGPrivateDataCount < 2)
+ {
+ return;
+ }
+
+ // DNG private data should always start with a null-terminated
+ // company name, to define the format of the private data.
+
+ dng_string privateName;
+
+ {
+
+ char buffer [64];
+
+ stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
+
+ uint32 readLength = Min_uint32 (fShared->fDNGPrivateDataCount,
+ sizeof (buffer) - 1);
+
+ stream.Get (buffer, readLength);
+
+ buffer [readLength] = 0;
+
+ privateName.Set (buffer);
+
+ }
+
+ if (privateName.StartsWith ("GoPro" ) )
+ {
+
+#if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Parsing GoPro DNGPrivateData\n\n");
+ }
+#endif
+
+ if( fShared->fDNGPrivateDataCount > 0 )
+ {
+ host.GetGPMFPayload().Reset (host.Allocate( fShared->fDNGPrivateDataCount + 1 ) );
+
+ stream.SetReadPosition (fShared->fDNGPrivateDataOffset);
+
+ stream.Get ( host.GetGPMFPayload().Get()->Buffer(), fShared->fDNGPrivateDataCount );
+ }
+
+ return;
+
+ }
+
+ // Pentax is storing their MakerNote in the DNGPrivateData data.
+
+ if (privateName.StartsWith ("PENTAX" ) ||
+ privateName.StartsWith ("SAMSUNG"))
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Parsing Pentax/Samsung DNGPrivateData\n\n");
+ }
+
+ #endif
+
+ stream.SetReadPosition (fShared->fDNGPrivateDataOffset + 8);
+
+ bool bigEndian = stream.BigEndian ();
+
+ uint16 endianMark = stream.Get_uint16 ();
+
+ if (endianMark == byteOrderMM)
+ {
+ bigEndian = true;
+ }
+
+ else if (endianMark == byteOrderII)
+ {
+ bigEndian = false;
+ }
+
+ TempBigEndian temp_endian (stream, bigEndian);
+
+ ParseMakerNoteIFD (host,
+ stream,
+ fShared->fDNGPrivateDataCount - 10,
+ fShared->fDNGPrivateDataOffset + 10,
+ fShared->fDNGPrivateDataOffset,
+ fShared->fDNGPrivateDataOffset,
+ fShared->fDNGPrivateDataOffset + fShared->fDNGPrivateDataCount,
+ tcPentaxMakerNote);
+
+ return;
+
+ }
+
+ // Stop parsing if this is not an Adobe format block.
+
+ if (!privateName.Matches ("Adobe"))
+ {
+ return;
+ }
+
+ TempBigEndian temp_order (stream);
+
+ uint32 section_offset = 6;
+
+ while (section_offset + 8 < fShared->fDNGPrivateDataCount)
+ {
+
+ stream.SetReadPosition (fShared->fDNGPrivateDataOffset + section_offset);
+
+ uint32 section_key = stream.Get_uint32 ();
+ uint32 section_count = stream.Get_uint32 ();
+
+ if (section_key == DNG_CHAR4 ('M','a','k','N') && section_count > 6)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Found MakerNote inside DNGPrivateData\n\n");
+ }
+
+ #endif
+
+ uint16 order_mark = stream.Get_uint16 ();
+ uint64 old_offset = stream.Get_uint32 ();
+
+ uint32 tempSize = section_count - 6;
+
+ AutoPtr<dng_memory_block> tempBlock (host.Allocate (tempSize));
+
+ uint64 positionInOriginalFile = stream.PositionInOriginalFile();
+
+ stream.Get (tempBlock->Buffer (), tempSize);
+
+ dng_stream tempStream (tempBlock->Buffer (),
+ tempSize,
+ positionInOriginalFile);
+
+ tempStream.SetBigEndian (order_mark == byteOrderMM);
+
+ ParseMakerNote (host,
+ tempStream,
+ tempSize,
+ 0,
+ 0 - old_offset,
+ 0,
+ tempSize);
+
+ }
+
+ else if (section_key == DNG_CHAR4 ('S','R','2',' ') && section_count > 6)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Found Sony private data inside DNGPrivateData\n\n");
+ }
+
+ #endif
+
+ uint16 order_mark = stream.Get_uint16 ();
+ uint64 old_offset = stream.Get_uint32 ();
+
+ uint64 new_offset = fShared->fDNGPrivateDataOffset + section_offset + 14;
+
+ TempBigEndian sr2_order (stream, order_mark == byteOrderMM);
+
+ ParseSonyPrivateData (host,
+ stream,
+ section_count - 6,
+ old_offset,
+ new_offset);
+
+ }
+
+ else if (section_key == DNG_CHAR4 ('R','A','F',' ') && section_count > 4)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Found Fuji RAF tags inside DNGPrivateData\n\n");
+ }
+
+ #endif
+
+ uint16 order_mark = stream.Get_uint16 ();
+
+ uint32 tagCount = stream.Get_uint32 ();
+
+ uint64 tagOffset = stream.Position ();
+
+ if (tagCount)
+ {
+
+ TempBigEndian raf_order (stream, order_mark == byteOrderMM);
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ tcFujiRAF,
+ tcFujiHeader,
+ ttUndefined,
+ tagCount,
+ tagOffset,
+ 0);
+
+ stream.SetReadPosition (tagOffset + tagCount);
+
+ }
+
+ tagCount = stream.Get_uint32 ();
+
+ tagOffset = stream.Position ();
+
+ if (tagCount)
+ {
+
+ TempBigEndian raf_order (stream, order_mark == byteOrderMM);
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ tcFujiRAF,
+ tcFujiRawInfo1,
+ ttUndefined,
+ tagCount,
+ tagOffset,
+ 0);
+
+ stream.SetReadPosition (tagOffset + tagCount);
+
+ }
+
+ tagCount = stream.Get_uint32 ();
+
+ tagOffset = stream.Position ();
+
+ if (tagCount)
+ {
+
+ TempBigEndian raf_order (stream, order_mark == byteOrderMM);
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ tcFujiRAF,
+ tcFujiRawInfo2,
+ ttUndefined,
+ tagCount,
+ tagOffset,
+ 0);
+
+ stream.SetReadPosition (tagOffset + tagCount);
+
+ }
+
+ }
+
+ else if (section_key == DNG_CHAR4 ('C','n','t','x') && section_count > 4)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Found Contax Raw header inside DNGPrivateData\n\n");
+ }
+
+ #endif
+
+ uint16 order_mark = stream.Get_uint16 ();
+
+ uint32 tagCount = stream.Get_uint32 ();
+
+ uint64 tagOffset = stream.Position ();
+
+ if (tagCount)
+ {
+
+ TempBigEndian contax_order (stream, order_mark == byteOrderMM);
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ tcContaxRAW,
+ tcContaxHeader,
+ ttUndefined,
+ tagCount,
+ tagOffset,
+ 0);
+
+ }
+
+ }
+
+ else if (section_key == DNG_CHAR4 ('C','R','W',' ') && section_count > 4)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Found Canon CRW tags inside DNGPrivateData\n\n");
+ }
+
+ #endif
+
+ uint16 order_mark = stream.Get_uint16 ();
+ uint32 entries = stream.Get_uint16 ();
+
+ uint64 crwTagStart = stream.Position ();
+
+ for (uint32 parsePass = 1; parsePass <= 2; parsePass++)
+ {
+
+ stream.SetReadPosition (crwTagStart);
+
+ for (uint32 index = 0; index < entries; index++)
+ {
+
+ uint32 tagCode = stream.Get_uint16 ();
+
+ uint32 tagCount = stream.Get_uint32 ();
+
+ uint64 tagOffset = stream.Position ();
+
+ // We need to grab the model id tag first, and then all the
+ // other tags.
+
+ if ((parsePass == 1) == (tagCode == 0x5834))
+ {
+
+ TempBigEndian tag_order (stream, order_mark == byteOrderMM);
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ tcCanonCRW,
+ tagCode,
+ ttUndefined,
+ tagCount,
+ tagOffset,
+ 0);
+
+ }
+
+ stream.SetReadPosition (tagOffset + tagCount);
+
+ }
+
+ }
+
+ }
+
+ else if (section_count > 4)
+ {
+
+ uint32 parentCode = 0;
+
+ bool code32 = false;
+ bool hasType = true;
+
+ switch (section_key)
+ {
+
+ case DNG_CHAR4 ('M','R','W',' '):
+ {
+ parentCode = tcMinoltaMRW;
+ code32 = true;
+ hasType = false;
+ break;
+ }
+
+ case DNG_CHAR4 ('P','a','n','o'):
+ {
+ parentCode = tcPanasonicRAW;
+ break;
+ }
+
+ case DNG_CHAR4 ('L','e','a','f'):
+ {
+ parentCode = tcLeafMOS;
+ break;
+ }
+
+ case DNG_CHAR4 ('K','o','d','a'):
+ {
+ parentCode = tcKodakDCRPrivateIFD;
+ break;
+ }
+
+ case DNG_CHAR4 ('K','D','C',' '):
+ {
+ parentCode = tcKodakKDCPrivateIFD;
+ break;
+ }
+
+ default:
+ break;
+
+ }
+
+ if (parentCode)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Found %s tags inside DNGPrivateData\n\n",
+ LookupParentCode (parentCode));
+ }
+
+ #endif
+
+ uint16 order_mark = stream.Get_uint16 ();
+ uint32 entries = stream.Get_uint16 ();
+
+ for (uint32 index = 0; index < entries; index++)
+ {
+
+ uint32 tagCode = code32 ? stream.Get_uint32 ()
+ : stream.Get_uint16 ();
+
+ uint32 tagType = hasType ? stream.Get_uint16 ()
+ : ttUndefined;
+
+ uint32 tagCount = stream.Get_uint32 ();
+
+ uint32 tagSize = tagCount * TagTypeSize (tagType);
+
+ uint64 tagOffset = stream.Position ();
+
+ TempBigEndian tag_order (stream, order_mark == byteOrderMM);
+
+ ParseTag (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset,
+ 0);
+
+ stream.SetReadPosition (tagOffset + tagSize);
+
+ }
+
+ }
+
+ }
+
+ section_offset += 8 + section_count;
+
+ if (section_offset & 1)
+ {
+ section_offset++;
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::Parse (dng_host &host,
+ dng_stream &stream)
+ {
+
+ fTIFFBlockOffset = stream.Position ();
+
+ fTIFFBlockOriginalOffset = stream.PositionInOriginalFile ();
+
+ // Check byte order indicator.
+
+ uint16 byteOrder = stream.Get_uint16 ();
+
+ if (byteOrder == byteOrderII)
+ {
+
+ fBigEndian = false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\nUses little-endian byte order\n");
+ }
+
+ #endif
+
+ stream.SetLittleEndian ();
+
+ }
+
+ else if (byteOrder == byteOrderMM)
+ {
+
+ fBigEndian = true;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\nUses big-endian byte order\n");
+ }
+
+ #endif
+
+ stream.SetBigEndian ();
+
+ }
+
+ else
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unknown byte order");
+
+ #endif
+
+ ThrowBadFormat ();
+
+ }
+
+ // Check "magic number" indicator.
+
+ fMagic = stream.Get_uint16 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("Magic number = %u\n\n", (unsigned) fMagic);
+ }
+
+ #endif
+
+ ValidateMagic ();
+
+ // Parse IFD 0.
+
+ uint64 next_offset = stream.Get_uint32 ();
+
+ fExif.Reset (host.Make_dng_exif ());
+
+ fShared.Reset (host.Make_dng_shared ());
+
+ fIFD [0].Reset (host.Make_dng_ifd ());
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ fIFD [0].Get (),
+ fTIFFBlockOffset + next_offset,
+ fTIFFBlockOffset,
+ 0);
+
+ next_offset = fIFD [0]->fNextIFD;
+
+ fIFDCount = 1;
+
+ // Parse chained IFDs.
+
+ while (next_offset)
+ {
+
+ if (next_offset >= stream.Length ())
+ {
+
+ #if qDNGValidate
+
+ {
+
+ ReportWarning ("Chained IFD offset past end of stream");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ // Some TIFF file writers forget about the next IFD offset, so
+ // validate the IFD at that offset before parsing it.
+
+ if (!ValidateIFD (stream,
+ fTIFFBlockOffset + next_offset,
+ fTIFFBlockOffset))
+ {
+
+ #if qDNGValidate
+
+ {
+
+ ReportWarning ("Chained IFD is not valid");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ if (fChainedIFDCount == kMaxChainedIFDs)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ());
+
+ ParseIFD (host,
+ stream,
+ NULL,
+ NULL,
+ fChainedIFD [fChainedIFDCount].Get (),
+ fTIFFBlockOffset + next_offset,
+ fTIFFBlockOffset,
+ tcFirstChainedIFD + fChainedIFDCount);
+
+ next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD;
+
+ fChainedIFDCount++;
+
+ }
+
+ // Parse SubIFDs.
+
+ uint32 searchedIFDs = 0;
+
+ bool tooManySubIFDs = false;
+
+ while (searchedIFDs < fIFDCount && !tooManySubIFDs)
+ {
+
+ uint32 searchLimit = fIFDCount;
+
+ for (uint32 searchIndex = searchedIFDs;
+ searchIndex < searchLimit && !tooManySubIFDs;
+ searchIndex++)
+ {
+
+ for (uint32 subIndex = 0;
+ subIndex < fIFD [searchIndex]->fSubIFDsCount;
+ subIndex++)
+ {
+
+ if (fIFDCount == kMaxSubIFDs + 1)
+ {
+
+ tooManySubIFDs = true;
+
+ break;
+
+ }
+
+ stream.SetReadPosition (fIFD [searchIndex]->fSubIFDsOffset +
+ subIndex * 4);
+
+ uint32 sub_ifd_offset = stream.Get_uint32 ();
+
+ fIFD [fIFDCount].Reset (host.Make_dng_ifd ());
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ fIFD [fIFDCount].Get (),
+ fTIFFBlockOffset + sub_ifd_offset,
+ fTIFFBlockOffset,
+ tcFirstSubIFD + fIFDCount - 1);
+
+ fIFDCount++;
+
+ }
+
+ searchedIFDs = searchLimit;
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ {
+
+ if (tooManySubIFDs)
+ {
+
+ ReportWarning ("SubIFD count exceeds DNG SDK parsing limit");
+
+ }
+
+ }
+
+ #endif
+
+ // Parse EXIF IFD.
+
+ if (fShared->fExifIFD)
+ {
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ fTIFFBlockOffset + fShared->fExifIFD,
+ fTIFFBlockOffset,
+ tcExifIFD);
+
+ }
+
+ // Parse GPS IFD.
+
+ if (fShared->fGPSInfo)
+ {
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ fTIFFBlockOffset + fShared->fGPSInfo,
+ fTIFFBlockOffset,
+ tcGPSInfo);
+
+ }
+
+ // Parse Interoperability IFD.
+
+ if (fShared->fInteroperabilityIFD)
+ {
+
+ // Some Kodak KDC files have bogus Interoperability IFDs, so
+ // validate the IFD before trying to parse it.
+
+ if (ValidateIFD (stream,
+ fTIFFBlockOffset + fShared->fInteroperabilityIFD,
+ fTIFFBlockOffset))
+ {
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ fTIFFBlockOffset + fShared->fInteroperabilityIFD,
+ fTIFFBlockOffset,
+ tcInteroperabilityIFD);
+
+ }
+
+ #if qDNGValidate
+
+ else
+ {
+
+ ReportWarning ("The Interoperability IFD is not a valid IFD");
+
+ }
+
+ #endif
+
+ }
+
+ // Parse Kodak DCR Private IFD.
+
+ if (fShared->fKodakDCRPrivateIFD)
+ {
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ fTIFFBlockOffset + fShared->fKodakDCRPrivateIFD,
+ fTIFFBlockOffset,
+ tcKodakDCRPrivateIFD);
+
+ }
+
+ // Parse Kodak KDC Private IFD.
+
+ if (fShared->fKodakKDCPrivateIFD)
+ {
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ NULL,
+ fTIFFBlockOffset + fShared->fKodakKDCPrivateIFD,
+ fTIFFBlockOffset,
+ tcKodakKDCPrivateIFD);
+
+ }
+
+ // Parse MakerNote tag.
+
+ if (fShared->fMakerNoteCount)
+ {
+
+ ParseMakerNote (host,
+ stream,
+ (uint32) (fTIFFBlockOffset + fShared->fMakerNoteCount),
+ fShared->fMakerNoteOffset,
+ fTIFFBlockOffset,
+ 0,
+ stream.Length ());
+
+ }
+
+ // Parse DNGPrivateData tag.
+
+ if (fShared->fDNGPrivateDataCount &&
+ fShared->fDNGVersion)
+ {
+
+ ParseDNGPrivateData (host, stream);
+
+ }
+
+ #if qDNGValidate
+
+ // If we are running dng_validate on stand-alone camera profile file,
+ // complete the validation of the profile.
+
+ if (fMagic == magicExtendedProfile)
+ {
+
+ dng_camera_profile_info &profileInfo = fShared->fCameraProfile;
+
+ dng_camera_profile profile;
+
+ profile.Parse (stream, profileInfo);
+
+ if (profileInfo.fColorPlanes < 3 || !profile.IsValid (profileInfo.fColorPlanes))
+ {
+
+ ReportError ("Invalid camera profile file");
+
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_info::PostParse (dng_host &host)
+ {
+
+ uint32 index;
+
+ fExif->PostParse (host, *fShared.Get ());
+
+ fShared->PostParse (host, *fExif.Get ());
+
+ for (index = 0; index < fIFDCount; index++)
+ {
+
+ fIFD [index]->PostParse ();
+
+ }
+
+ for (index = 0; index < fChainedIFDCount; index++)
+ {
+
+ fChainedIFD [index]->PostParse ();
+
+ }
+
+ if (fShared->fDNGVersion != 0)
+ {
+
+ // Find main IFD.
+
+ fMainIndex = -1;
+
+ for (index = 0; index < fIFDCount; index++)
+ {
+
+ if (fIFD [index]->fUsesNewSubFileType &&
+ fIFD [index]->fNewSubFileType == sfMainImage)
+ {
+
+ if (fMainIndex == -1)
+ {
+
+ fMainIndex = index;
+
+ }
+
+ #if qDNGValidate
+
+ else
+ {
+
+ ReportError ("Multiple IFDs marked as main image");
+
+ }
+
+ #endif
+
+ }
+
+ else if (fIFD [index]->fNewSubFileType == sfPreviewImage ||
+ fIFD [index]->fNewSubFileType == sfAltPreviewImage)
+ {
+
+ // Fill in default color space for DNG previews if not included.
+
+ if (fIFD [index]->fPreviewInfo.fColorSpace == previewColorSpace_MaxEnum)
+ {
+
+ if (fIFD [index]->fSamplesPerPixel == 1)
+ {
+
+ fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_GrayGamma22;
+
+ }
+
+ else
+ {
+
+ fIFD [index]->fPreviewInfo.fColorSpace = previewColorSpace_sRGB;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Deal with lossless JPEG bug in early DNG versions.
+
+ if (fShared->fDNGVersion < dngVersion_1_1_0_0)
+ {
+
+ if (fMainIndex != -1)
+ {
+
+ fIFD [fMainIndex]->fLosslessJPEGBug16 = true;
+
+ }
+
+ }
+
+ // Find mask index.
+
+ for (index = 0; index < fIFDCount; index++)
+ {
+
+ if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
+ {
+
+ if (fMaskIndex == -1)
+ {
+
+ fMaskIndex = index;
+
+ }
+
+ #if qDNGValidate
+
+ else
+ {
+
+ ReportError ("Multiple IFDs marked as transparency mask image");
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+ // Warn about Chained IFDs.
+
+ #if qDNGValidate
+
+ if (fChainedIFDCount > 0)
+ {
+
+ ReportWarning ("This file has Chained IFDs, which will be ignored by DNG readers");
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_info::IsValidDNG ()
+ {
+
+ // Check shared info.
+
+ if (!fShared->IsValidDNG ())
+ {
+
+ return false;
+
+ }
+
+ // Check TIFF magic number.
+
+ if (fMagic != 42)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Invalid TIFF magic number");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure we have a main image IFD.
+
+ if (fMainIndex == -1)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Unable to find main image IFD");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure is each IFD is valid.
+
+ for (uint32 index = 0; index < fIFDCount; index++)
+ {
+
+ uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
+
+ if (!fIFD [index]->IsValidDNG (*fShared.Get (),
+ parentCode))
+ {
+
+ // Only errors in the main and transparency mask IFDs are fatal to parsing.
+
+ if (index == (uint32) fMainIndex ||
+ index == (uint32) fMaskIndex)
+ {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_info.h b/gpr/source/lib/dng_sdk/dng_info.h
new file mode 100644
index 0000000..3ccefd1
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_info.h
@@ -0,0 +1,163 @@
+/*****************************************************************************/
+// Copyright 2006-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_info.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Class for holding top-level information about a DNG image.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_info__
+#define __dng_info__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_ifd.h"
+#include "dng_exif.h"
+#include "dng_shared.h"
+#include "dng_errors.h"
+#include "dng_sdk_limits.h"
+#include "dng_auto_ptr.h"
+
+/*****************************************************************************/
+
+/// \brief Top-level structure of DNG file with access to metadata.
+///
+/// See \ref spec_dng "DNG 1.1.0 specification" for information on member fields of this class.
+
+class dng_info
+ {
+
+ public:
+
+ uint64 fTIFFBlockOffset;
+
+ uint64 fTIFFBlockOriginalOffset;
+
+ bool fBigEndian;
+
+ uint32 fMagic;
+
+ AutoPtr<dng_exif> fExif;
+
+ AutoPtr<dng_shared> fShared;
+
+ int32 fMainIndex;
+
+ int32 fMaskIndex;
+
+ uint32 fIFDCount;
+
+ AutoPtr<dng_ifd> fIFD [kMaxSubIFDs + 1];
+
+ uint32 fChainedIFDCount;
+
+ AutoPtr<dng_ifd> fChainedIFD [kMaxChainedIFDs];
+
+ protected:
+
+ uint32 fMakerNoteNextIFD;
+
+ public:
+
+ dng_info ();
+
+ virtual ~dng_info ();
+
+ /// Read dng_info from a dng_stream
+ /// \param host DNG host used for progress updating, abort testing, buffer allocation, etc.
+ /// \param stream Stream to read DNG data from.
+
+ virtual void Parse (dng_host &host,
+ dng_stream &stream);
+
+ /// Must be called immediately after a successful Parse operation.
+
+ virtual void PostParse (dng_host &host);
+
+ /// Test validity of DNG data.
+ /// \retval true if stream provided a valid DNG.
+
+ virtual bool IsValidDNG ();
+
+ protected:
+
+ virtual void ValidateMagic ();
+
+ virtual void ParseTag (dng_host &host,
+ dng_stream &stream,
+ dng_exif *exif,
+ dng_shared *shared,
+ dng_ifd *ifd,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset,
+ int64 offsetDelta);
+
+ virtual bool ValidateIFD (dng_stream &stream,
+ uint64 ifdOffset,
+ int64 offsetDelta);
+
+ virtual void ParseIFD (dng_host &host,
+ dng_stream &stream,
+ dng_exif *exif,
+ dng_shared *shared,
+ dng_ifd *ifd,
+ uint64 ifdOffset,
+ int64 offsetDelta,
+ uint32 parentCode);
+
+ virtual bool ParseMakerNoteIFD (dng_host &host,
+ dng_stream &stream,
+ uint64 ifdSize,
+ uint64 ifdOffset,
+ int64 offsetDelta,
+ uint64 minOffset,
+ uint64 maxOffset,
+ uint32 parentCode);
+
+ virtual void ParseMakerNote (dng_host &host,
+ dng_stream &stream,
+ uint32 makerNoteCount,
+ uint64 makerNoteOffset,
+ int64 offsetDelta,
+ uint64 minOffset,
+ uint64 maxOffset);
+
+ virtual void ParseSonyPrivateData (dng_host &host,
+ dng_stream &stream,
+ uint64 count,
+ uint64 oldOffset,
+ uint64 newOffset);
+
+ virtual void ParseDNGPrivateData (dng_host &host,
+ dng_stream &stream);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_info (const dng_info &info);
+
+ dng_info & operator= (const dng_info &info);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_iptc.cpp b/gpr/source/lib/dng_sdk/dng_iptc.cpp
new file mode 100644
index 0000000..98c263d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_iptc.cpp
@@ -0,0 +1,987 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_iptc.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_iptc.h"
+
+#include "dng_assertions.h"
+#include "dng_auto_ptr.h"
+#include "dng_memory_stream.h"
+#include "dng_stream.h"
+#include "dng_utils.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+dng_iptc::dng_iptc ()
+
+ : fTitle ()
+
+ , fUrgency (-1)
+
+ , fCategory ()
+
+ , fSupplementalCategories ()
+
+ , fKeywords ()
+
+ , fInstructions ()
+
+ , fDateTimeCreated ()
+
+ , fDigitalCreationDateTime ()
+
+ , fAuthors ()
+ , fAuthorsPosition ()
+
+ , fCity ()
+ , fState ()
+ , fCountry ()
+ , fCountryCode ()
+
+ , fLocation ()
+
+ , fTransmissionReference ()
+
+ , fHeadline ()
+
+ , fCredit ()
+
+ , fSource ()
+
+ , fCopyrightNotice ()
+
+ , fDescription ()
+ , fDescriptionWriter ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_iptc::~dng_iptc ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_iptc::IsEmpty () const
+ {
+
+ if (fTitle.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fUrgency >= 0)
+ {
+ return false;
+ }
+
+ if (fCategory.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fSupplementalCategories.Count () > 0)
+ {
+ return false;
+ }
+
+ if (fKeywords.Count () > 0)
+ {
+ return false;
+ }
+
+ if (fInstructions.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fDateTimeCreated.IsValid ())
+ {
+ return false;
+ }
+
+ if (fDigitalCreationDateTime.IsValid ())
+ {
+ return false;
+ }
+
+ if (fAuthors.Count () != 0 ||
+ fAuthorsPosition.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCity .NotEmpty () ||
+ fState .NotEmpty () ||
+ fCountry.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCountryCode.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fLocation.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fTransmissionReference.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fHeadline.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCredit.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fSource.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCopyrightNotice.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fDescription .NotEmpty () ||
+ fDescriptionWriter.NotEmpty ())
+ {
+ return false;
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_iptc::ParseString (dng_stream &stream,
+ dng_string &s,
+ CharSet charSet)
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ dng_memory_data buffer (length + 1);
+
+ char *c = buffer.Buffer_char ();
+
+ stream.Get (c, length);
+
+ c [length] = 0;
+
+ switch (charSet)
+ {
+
+ case kCharSetUTF8:
+ {
+ s.Set_UTF8 (c);
+ break;
+ }
+
+ default:
+ {
+ s.Set_SystemEncoding (c);
+ }
+
+ }
+
+ s.SetLineEndingsToNewLines ();
+
+ s.StripLowASCII ();
+
+ s.TrimTrailingBlanks ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_iptc::Parse (const void *blockData,
+ uint32 blockSize,
+ uint64 offsetInOriginalFile)
+ {
+
+ dng_stream stream (blockData,
+ blockSize,
+ offsetInOriginalFile);
+
+ stream.SetBigEndian ();
+
+ // Make a first pass though the data, trying to figure out the
+ // character set.
+
+ CharSet charSet = kCharSetUnknown;
+
+ bool isValidUTF8 = true;
+
+ bool hasEncodingMarker = false;
+
+ uint64 firstOffset = stream.Position ();
+
+ uint64 nextOffset = firstOffset;
+
+ while (nextOffset + 5 < stream.Length ())
+ {
+
+ stream.SetReadPosition (nextOffset);
+
+ uint8 firstByte = stream.Get_uint8 ();
+
+ if (firstByte != 0x1C) break;
+
+ uint8 record = stream.Get_uint8 ();
+ uint8 dataSet = stream.Get_uint8 ();
+ uint32 dataSize = stream.Get_uint16 ();
+
+ nextOffset = stream.Position () + dataSize;
+
+ if (record == 1)
+ {
+
+ switch (dataSet)
+ {
+
+ case 90:
+ {
+
+ hasEncodingMarker = true;
+
+ if (dataSize == 3)
+ {
+
+ uint32 byte1 = stream.Get_uint8 ();
+ uint32 byte2 = stream.Get_uint8 ();
+ uint32 byte3 = stream.Get_uint8 ();
+
+ if (byte1 == 27 /* Escape */ &&
+ byte2 == 0x25 &&
+ byte3 == 0x47)
+ {
+
+ charSet = kCharSetUTF8;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ }
+
+ else if (record == 2)
+ {
+
+ dng_memory_data buffer (dataSize + 1);
+
+ char *s = buffer.Buffer_char ();
+
+ stream.Get (s, dataSize);
+
+ s [dataSize] = 0;
+
+ isValidUTF8 = isValidUTF8 && dng_string::IsUTF8 (s);
+
+ }
+
+ }
+
+ // If we don't have an encoding marker, and the data is valid
+ // UTF-8, then assume that it is UTF-8 (rather than system encoding).
+
+ if (!hasEncodingMarker && isValidUTF8)
+ {
+
+ charSet = kCharSetUTF8;
+
+ }
+
+ // Make a second pass though the data, actually reading the data.
+
+ nextOffset = firstOffset;
+
+ while (nextOffset + 5 < stream.Length ())
+ {
+
+ stream.SetReadPosition (nextOffset);
+
+ uint8 firstByte = stream.Get_uint8 ();
+
+ if (firstByte != 0x1C) break;
+
+ uint8 record = stream.Get_uint8 ();
+ uint8 dataSet = stream.Get_uint8 ();
+ uint32 dataSize = stream.Get_uint16 ();
+
+ nextOffset = stream.Position () + dataSize;
+
+ if (record == 2)
+ {
+
+ stream.SetReadPosition (stream.Position () - 2);
+
+ switch ((DataSet) dataSet)
+ {
+
+ case kObjectNameSet:
+ {
+ ParseString (stream, fTitle, charSet);
+ break;
+ }
+
+ case kUrgencySet:
+ {
+
+ int32 size = stream.Get_uint16 ();
+
+ if (size == 1)
+ {
+
+ char c = stream.Get_int8 ();
+
+ if (c >= '0' && c <= '9')
+ {
+ fUrgency = c - '0';
+ }
+
+ }
+
+ break;
+
+ }
+
+ case kCategorySet:
+ {
+ ParseString (stream, fCategory, charSet);
+ break;
+ }
+
+ case kSupplementalCategoriesSet:
+ {
+
+ dng_string category;
+
+ ParseString (stream, category, charSet);
+
+ if (category.NotEmpty ())
+ {
+ fSupplementalCategories.Append (category);
+ }
+
+ break;
+
+ }
+
+ case kKeywordsSet:
+ {
+
+ dng_string keyword;
+
+ ParseString (stream, keyword, charSet);
+
+ if (keyword.NotEmpty ())
+ {
+ fKeywords.Append (keyword);
+ }
+
+ break;
+
+ }
+
+ case kSpecialInstructionsSet:
+ {
+ ParseString (stream, fInstructions, charSet);
+ break;
+ }
+
+ case kDateCreatedSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length == 8)
+ {
+
+ char date [9];
+
+ stream.Get (date, 8);
+
+ date [8] = 0;
+
+ fDateTimeCreated.Decode_IPTC_Date (date);
+
+ }
+
+ break;
+
+ }
+
+ case kTimeCreatedSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length >= 4 && length <= 11)
+ {
+
+ char time [12];
+
+ stream.Get (time, length);
+
+ time [length] = 0;
+
+ fDateTimeCreated.Decode_IPTC_Time (time);
+
+ }
+
+ break;
+
+ }
+
+ case kDigitalCreationDateSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length == 8)
+ {
+
+ char date [9];
+
+ stream.Get (date, 8);
+
+ date [8] = 0;
+
+ fDigitalCreationDateTime.Decode_IPTC_Date (date);
+
+ }
+
+ break;
+
+ }
+
+ case kDigitalCreationTimeSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length >= 4 && length <= 11)
+ {
+
+ char time [12];
+
+ stream.Get (time, length);
+
+ time [length] = 0;
+
+ fDigitalCreationDateTime.Decode_IPTC_Time (time);
+
+ }
+
+ break;
+
+ }
+
+ case kBylineSet:
+ {
+
+ dng_string author;
+
+ ParseString (stream, author, charSet);
+
+ if (author.NotEmpty ())
+ {
+ fAuthors.Append (author);
+ }
+
+ break;
+
+ }
+
+ case kBylineTitleSet:
+ {
+ ParseString (stream, fAuthorsPosition, charSet);
+ break;
+ }
+
+ case kCitySet:
+ {
+ ParseString (stream, fCity, charSet);
+ break;
+ }
+
+ case kProvinceStateSet:
+ {
+ ParseString (stream, fState, charSet);
+ break;
+ }
+
+ case kCountryNameSet:
+ {
+ ParseString (stream, fCountry, charSet);
+ break;
+ }
+
+ case kCountryCodeSet:
+ {
+ ParseString (stream, fCountryCode, charSet);
+ break;
+ }
+
+ case kSublocationSet:
+ {
+ ParseString (stream, fLocation, charSet);
+ break;
+ }
+
+ case kOriginalTransmissionReferenceSet:
+ {
+ ParseString (stream, fTransmissionReference, charSet);
+ break;
+ }
+
+ case kHeadlineSet:
+ {
+ ParseString (stream, fHeadline, charSet);
+ break;
+ }
+
+ case kCreditSet:
+ {
+ ParseString (stream, fCredit, charSet);
+ break;
+ }
+
+ case kSourceSet:
+ {
+ ParseString (stream, fSource, charSet);
+ break;
+ }
+
+ case kCopyrightNoticeSet:
+ {
+ ParseString (stream, fCopyrightNotice, charSet);
+ break;
+ }
+
+ case kCaptionSet:
+ {
+ ParseString (stream, fDescription, charSet);
+ break;
+ }
+
+ case kCaptionWriterSet:
+ {
+ ParseString (stream, fDescriptionWriter, charSet);
+ break;
+ }
+
+ // All other IPTC records are not part of the IPTC core
+ // and/or are not kept in sync with XMP tags, so we ignore
+ // them.
+
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_iptc::SpoolString (dng_stream &stream,
+ const dng_string &s,
+ uint8 dataSet,
+ uint32 maxChars,
+ CharSet charSet)
+ {
+
+ if (s.IsEmpty ())
+ {
+ return;
+ }
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (dataSet);
+
+ dng_string ss (s);
+
+ ss.SetLineEndingsToReturns ();
+
+ if (charSet == kCharSetUTF8)
+ {
+
+ // UTF-8 encoding.
+
+ if (ss.Length () > maxChars)
+ {
+ ss.Truncate (maxChars);
+ }
+
+ uint32 len = ss.Length ();
+
+ stream.Put_uint16 ((uint16) len);
+
+ stream.Put (ss.Get (), len);
+
+ }
+
+ else
+ {
+
+ // System character set encoding.
+
+ dng_memory_data buffer;
+
+ uint32 len = ss.Get_SystemEncoding (buffer);
+
+ if (len > maxChars)
+ {
+
+ uint32 lower = 0;
+ uint32 upper = ss.Length () - 1;
+
+ while (upper > lower)
+ {
+
+ uint32 middle = (upper + lower + 1) >> 1;
+
+ dng_string sss (ss);
+
+ sss.Truncate (middle);
+
+ len = sss.Get_SystemEncoding (buffer);
+
+ if (len <= maxChars)
+ {
+
+ lower = middle;
+
+ }
+
+ else
+ {
+
+ upper = middle - 1;
+
+ }
+
+ }
+
+ ss.Truncate (lower);
+
+ len = ss.Get_SystemEncoding (buffer);
+
+ }
+
+ stream.Put_uint16 ((uint16) len);
+
+ stream.Put (buffer.Buffer_char (), len);
+
+ }
+
+ }
+/*****************************************************************************/
+
+dng_memory_block * dng_iptc::Spool (dng_memory_allocator &allocator,
+ bool padForTIFF)
+ {
+
+ uint32 j;
+
+ char s [64];
+
+ dng_memory_stream stream (allocator, NULL, 2048);
+
+ stream.SetBigEndian ();
+
+ // Medata working group - now we just always write UTF-8.
+
+ CharSet charSet = kCharSetUTF8;
+
+ // UTF-8 encoding marker.
+
+ if (charSet == kCharSetUTF8)
+ {
+
+ stream.Put_uint16 (0x1C01);
+ stream.Put_uint8 (90);
+ stream.Put_uint16 (3);
+ stream.Put_uint8 (27);
+ stream.Put_uint8 (0x25);
+ stream.Put_uint8 (0x47);
+
+ }
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kRecordVersionSet);
+ stream.Put_uint16 (2);
+ stream.Put_uint16 (4);
+
+ SpoolString (stream,
+ fTitle,
+ kObjectNameSet,
+ 64,
+ charSet);
+
+ if (fUrgency >= 0)
+ {
+
+ sprintf (s, "%1u", (unsigned) fUrgency);
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kUrgencySet);
+
+ stream.Put_uint16 (1);
+
+ stream.Put (s, 1);
+
+ }
+
+ SpoolString (stream,
+ fCategory,
+ kCategorySet,
+ 3,
+ charSet);
+
+ for (j = 0; j < fSupplementalCategories.Count (); j++)
+ {
+
+ SpoolString (stream,
+ fSupplementalCategories [j],
+ kSupplementalCategoriesSet,
+ 32,
+ charSet);
+
+ }
+
+ for (j = 0; j < fKeywords.Count (); j++)
+ {
+
+ SpoolString (stream,
+ fKeywords [j],
+ kKeywordsSet,
+ 64,
+ charSet);
+
+ }
+
+ SpoolString (stream,
+ fInstructions,
+ kSpecialInstructionsSet,
+ 255,
+ charSet);
+
+ if (fDateTimeCreated.IsValid ())
+ {
+
+ dng_string dateString = fDateTimeCreated.Encode_IPTC_Date ();
+
+ if (dateString.NotEmpty ())
+ {
+
+ DNG_ASSERT (dateString.Length () == 8, "Wrong length IPTC date");
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kDateCreatedSet);
+
+ stream.Put_uint16 (8);
+
+ stream.Put (dateString.Get (), 8);
+
+ }
+
+ dng_string timeString = fDateTimeCreated.Encode_IPTC_Time ();
+
+ if (timeString.NotEmpty ())
+ {
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kTimeCreatedSet);
+
+ stream.Put_uint16 ((uint16)timeString.Length ());
+
+ stream.Put (timeString.Get (), timeString.Length ());
+
+ }
+
+ }
+
+ if (fDigitalCreationDateTime.IsValid ())
+ {
+
+ dng_string dateString = fDigitalCreationDateTime.Encode_IPTC_Date ();
+
+ if (dateString.NotEmpty ())
+ {
+
+ DNG_ASSERT (dateString.Length () == 8, "Wrong length IPTC date");
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kDigitalCreationDateSet);
+
+ stream.Put_uint16 (8);
+
+ stream.Put (dateString.Get (), 8);
+
+ }
+
+ dng_string timeString = fDigitalCreationDateTime.Encode_IPTC_Time ();
+
+ if (timeString.NotEmpty ())
+ {
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kDigitalCreationTimeSet);
+
+ stream.Put_uint16 ((uint16)timeString.Length ());
+
+ stream.Put (timeString.Get (), timeString.Length ());
+
+ }
+
+ }
+
+ for (j = 0; j < fAuthors.Count (); j++)
+ {
+
+ SpoolString (stream,
+ fAuthors [j],
+ kBylineSet,
+ 32,
+ charSet);
+
+ }
+
+ SpoolString (stream,
+ fAuthorsPosition,
+ kBylineTitleSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fCity,
+ kCitySet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fLocation,
+ kSublocationSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fState,
+ kProvinceStateSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fCountryCode,
+ kCountryCodeSet,
+ 3,
+ charSet);
+
+ SpoolString (stream,
+ fCountry,
+ kCountryNameSet,
+ 64,
+ charSet);
+
+ SpoolString (stream,
+ fTransmissionReference,
+ kOriginalTransmissionReferenceSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fHeadline,
+ kHeadlineSet,
+ 255,
+ charSet);
+
+ SpoolString (stream,
+ fCredit,
+ kCreditSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fSource,
+ kSourceSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fCopyrightNotice,
+ kCopyrightNoticeSet,
+ 128,
+ charSet);
+
+ SpoolString (stream,
+ fDescription,
+ kCaptionSet,
+ 2000,
+ charSet);
+
+ SpoolString (stream,
+ fDescriptionWriter,
+ kCaptionWriterSet,
+ 32,
+ charSet);
+
+ if (padForTIFF)
+ {
+
+ while (stream.Length () & 3)
+ {
+ stream.Put_uint8 (0);
+ }
+
+ }
+
+ stream.Flush ();
+
+ return stream.AsMemoryBlock (allocator);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_iptc.h b/gpr/source/lib/dng_sdk/dng_iptc.h
new file mode 100644
index 0000000..82ebaeb
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_iptc.h
@@ -0,0 +1,172 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_iptc.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for IPTC metadata within DNG files.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_iptc__
+#define __dng_iptc__
+
+/*****************************************************************************/
+
+#include "dng_date_time.h"
+#include "dng_string.h"
+#include "dng_string_list.h"
+
+/*****************************************************************************/
+
+/// \brief Class for reading and holding IPTC metadata associated with a DNG file.
+///
+/// See the \ref spec_iptc "IPTC specification"
+/// for information on member fields of this class.
+
+class dng_iptc
+ {
+
+ public:
+
+ dng_string fTitle;
+
+ int32 fUrgency;
+
+ dng_string fCategory;
+
+ dng_string_list fSupplementalCategories;
+
+ dng_string_list fKeywords;
+
+ dng_string fInstructions;
+
+ dng_date_time_info fDateTimeCreated;
+
+ dng_date_time_info fDigitalCreationDateTime;
+
+ dng_string_list fAuthors;
+
+ dng_string fAuthorsPosition;
+
+ dng_string fCity;
+ dng_string fState;
+ dng_string fCountry;
+ dng_string fCountryCode;
+
+ dng_string fLocation;
+
+ dng_string fTransmissionReference;
+
+ dng_string fHeadline;
+
+ dng_string fCredit;
+
+ dng_string fSource;
+
+ dng_string fCopyrightNotice;
+
+ dng_string fDescription;
+ dng_string fDescriptionWriter;
+
+ protected:
+
+ enum DataSet
+ {
+ kRecordVersionSet = 0,
+ kObjectNameSet = 5,
+ kUrgencySet = 10,
+ kCategorySet = 15,
+ kSupplementalCategoriesSet = 20,
+ kKeywordsSet = 25,
+ kSpecialInstructionsSet = 40,
+ kDateCreatedSet = 55,
+ kTimeCreatedSet = 60,
+ kDigitalCreationDateSet = 62,
+ kDigitalCreationTimeSet = 63,
+ kBylineSet = 80,
+ kBylineTitleSet = 85,
+ kCitySet = 90,
+ kSublocationSet = 92,
+ kProvinceStateSet = 95,
+ kCountryCodeSet = 100,
+ kCountryNameSet = 101,
+ kOriginalTransmissionReferenceSet = 103,
+ kHeadlineSet = 105,
+ kCreditSet = 110,
+ kSourceSet = 115,
+ kCopyrightNoticeSet = 116,
+ kCaptionSet = 120,
+ kCaptionWriterSet = 122
+ };
+
+ enum CharSet
+ {
+ kCharSetUnknown = 0,
+ kCharSetUTF8 = 1
+ };
+
+ public:
+
+ dng_iptc ();
+
+ virtual ~dng_iptc ();
+
+ /// Test if IPTC metadata exists.
+ /// \retval true if no IPTC metadata exists for this DNG.
+
+ bool IsEmpty () const;
+
+ /// Test if IPTC metadata exists.
+ /// \retval true if IPTC metadata exists for this DNG.
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ /// Parse a complete block of IPTC data.
+ /// \param blockData The block of IPTC data.
+ /// \param blockSize Size in bytes of data block.
+ /// \param offsetInOriginalFile Used to enable certain file patching operations such as updating date/time in place.
+
+ void Parse (const void *blockData,
+ uint32 blockSize,
+ uint64 offsetInOriginalFile);
+
+ /// Serialize IPTC data to a memory block.
+ /// \param allocator Memory allocator used to acquire memory block.
+ /// \param padForTIFF Forces length of block to be a multiple of four bytes in accordance with TIFF standard.
+ /// \retval Memory block
+
+ dng_memory_block * Spool (dng_memory_allocator &allocator,
+ bool padForTIFF);
+
+ protected:
+
+ void ParseString (dng_stream &stream,
+ dng_string &s,
+ CharSet charSet);
+
+ void SpoolString (dng_stream &stream,
+ const dng_string &s,
+ uint8 dataSet,
+ uint32 maxChars,
+ CharSet charSet);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_jpeg_image.cpp b/gpr/source/lib/dng_sdk/dng_jpeg_image.cpp
new file mode 100644
index 0000000..362cc83
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_jpeg_image.cpp
@@ -0,0 +1,385 @@
+/*****************************************************************************/
+// Copyright 2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_jpeg_image.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_jpeg_image.h"
+
+#include "dng_abort_sniffer.h"
+#include "dng_area_task.h"
+#include "dng_assertions.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image.h"
+#include "dng_image_writer.h"
+#include "dng_memory_stream.h"
+#include "dng_mutex.h"
+
+/*****************************************************************************/
+
+dng_jpeg_image::dng_jpeg_image ()
+
+ : fImageSize ()
+ , fTileSize ()
+ , fUsesStrips (false)
+ , fJPEGTables ()
+ , fJPEGData ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+class dng_jpeg_image_encode_task : public dng_area_task
+ {
+
+ private:
+
+ dng_host &fHost;
+
+ dng_image_writer &fWriter;
+
+ const dng_image &fImage;
+
+ dng_jpeg_image &fJPEGImage;
+
+ uint32 fTileCount;
+
+ const dng_ifd &fIFD;
+
+ dng_mutex fMutex;
+
+ uint32 fNextTileIndex;
+
+ public:
+
+ dng_jpeg_image_encode_task (dng_host &host,
+ dng_image_writer &writer,
+ const dng_image &image,
+ dng_jpeg_image &jpegImage,
+ uint32 tileCount,
+ const dng_ifd &ifd)
+
+ : fHost (host)
+ , fWriter (writer)
+ , fImage (image)
+ , fJPEGImage (jpegImage)
+ , fTileCount (tileCount)
+ , fIFD (ifd)
+ , fMutex ("dng_jpeg_image_encode_task")
+ , fNextTileIndex (0)
+
+ {
+
+ fMinTaskArea = 16 * 16;
+ fUnitCell = dng_point (16, 16);
+ fMaxTileSize = dng_point (16, 16);
+
+ }
+
+ void Process (uint32 /* threadIndex */,
+ const dng_rect & /* tile */,
+ dng_abort_sniffer *sniffer)
+ {
+
+ AutoPtr<dng_memory_block> compressedBuffer;
+ AutoPtr<dng_memory_block> uncompressedBuffer;
+ AutoPtr<dng_memory_block> subTileBlockBuffer;
+ AutoPtr<dng_memory_block> tempBuffer;
+
+ uint32 uncompressedSize = fIFD.fTileLength *
+ fIFD.fTileWidth *
+ fIFD.fSamplesPerPixel;
+
+ uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize));
+
+ uint32 tilesAcross = fIFD.TilesAcross ();
+
+ while (true)
+ {
+
+ uint32 tileIndex;
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ if (fNextTileIndex == fTileCount)
+ {
+ return;
+ }
+
+ tileIndex = fNextTileIndex++;
+
+ }
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ uint32 rowIndex = tileIndex / tilesAcross;
+ uint32 colIndex = tileIndex % tilesAcross;
+
+ dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
+
+ dng_memory_stream stream (fHost.Allocator ());
+
+ fWriter.WriteTile (fHost,
+ fIFD,
+ stream,
+ fImage,
+ tileArea,
+ 1,
+ compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer,
+ tempBuffer);
+
+ fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ()));
+
+ }
+
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_jpeg_image_encode_task (const dng_jpeg_image_encode_task &);
+
+ dng_jpeg_image_encode_task & operator= (const dng_jpeg_image_encode_task &);
+
+ };
+
+/*****************************************************************************/
+
+void dng_jpeg_image::Encode (dng_host &host,
+ const dng_negative &negative,
+ dng_image_writer &writer,
+ const dng_image &image)
+ {
+
+ #if qDNGValidate
+ dng_timer timer ("Encode JPEG Proxy time");
+ #endif
+
+ DNG_ASSERT (image.PixelType () == ttByte, "Cannot JPEG encode non-byte image");
+
+ fImageSize = image.Bounds ().Size ();
+
+ dng_ifd ifd;
+
+ ifd.fImageWidth = fImageSize.h;
+ ifd.fImageLength = fImageSize.v;
+
+ ifd.fSamplesPerPixel = image.Planes ();
+
+ ifd.fBitsPerSample [0] = 8;
+ ifd.fBitsPerSample [1] = 8;
+ ifd.fBitsPerSample [2] = 8;
+ ifd.fBitsPerSample [3] = 8;
+
+ ifd.fPhotometricInterpretation = piLinearRaw;
+
+ ifd.fCompression = ccLossyJPEG;
+
+ ifd.FindTileSize (512 * 512 * ifd.fSamplesPerPixel);
+
+ fTileSize.h = ifd.fTileWidth;
+ fTileSize.v = ifd.fTileLength;
+
+ // Need a higher quality for raw proxies than non-raw proxies,
+ // since users often perform much greater color changes. Also, use
+ // we are targeting a "large" size proxy (larger than 5MP pixels), or this
+ // is a full size proxy, then use a higher quality.
+
+ bool useHigherQuality = (uint64) ifd.fImageWidth *
+ (uint64) ifd.fImageLength > 5000000 ||
+ image.Bounds ().Size () == negative.OriginalDefaultFinalSize ();
+
+ if (negative.ColorimetricReference () == crSceneReferred)
+ {
+ ifd.fCompressionQuality = useHigherQuality ? 11 : 10;
+ }
+ else
+ {
+ ifd.fCompressionQuality = useHigherQuality ? 10 : 8;
+ }
+
+ uint32 tilesAcross = ifd.TilesAcross ();
+ uint32 tilesDown = ifd.TilesDown ();
+
+ uint32 tileCount = tilesAcross * tilesDown;
+
+ fJPEGData.Reset (new dng_jpeg_image_tile_ptr [tileCount]);
+
+ uint32 threadCount = Min_uint32 (tileCount,
+ host.PerformAreaTaskThreads ());
+
+ dng_jpeg_image_encode_task task (host,
+ writer,
+ image,
+ *this,
+ tileCount,
+ ifd);
+
+ host.PerformAreaTask (task,
+ dng_rect (0, 0, 16, 16 * threadCount));
+
+ }
+
+/*****************************************************************************/
+
+class dng_jpeg_image_find_digest_task : public dng_area_task
+ {
+
+ private:
+
+ const dng_jpeg_image &fJPEGImage;
+
+ uint32 fTileCount;
+
+ dng_fingerprint *fDigests;
+
+ dng_mutex fMutex;
+
+ uint32 fNextTileIndex;
+
+ public:
+
+ dng_jpeg_image_find_digest_task (const dng_jpeg_image &jpegImage,
+ uint32 tileCount,
+ dng_fingerprint *digests)
+
+ : fJPEGImage (jpegImage)
+ , fTileCount (tileCount)
+ , fDigests (digests)
+ , fMutex ("dng_jpeg_image_find_digest_task")
+ , fNextTileIndex (0)
+
+ {
+
+ fMinTaskArea = 16 * 16;
+ fUnitCell = dng_point (16, 16);
+ fMaxTileSize = dng_point (16, 16);
+
+ }
+
+ void Process (uint32 /* threadIndex */,
+ const dng_rect & /* tile */,
+ dng_abort_sniffer *sniffer)
+ {
+
+ while (true)
+ {
+
+ uint32 tileIndex;
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ if (fNextTileIndex == fTileCount)
+ {
+ return;
+ }
+
+ tileIndex = fNextTileIndex++;
+
+ }
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ dng_md5_printer printer;
+
+ printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer (),
+ fJPEGImage.fJPEGData [tileIndex]->LogicalSize ());
+
+ fDigests [tileIndex] = printer.Result ();
+
+ }
+
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_jpeg_image_find_digest_task (const dng_jpeg_image_find_digest_task &);
+
+ dng_jpeg_image_find_digest_task & operator= (const dng_jpeg_image_find_digest_task &);
+
+ };
+
+/*****************************************************************************/
+
+dng_fingerprint dng_jpeg_image::FindDigest (dng_host &host) const
+ {
+
+ uint32 tileCount = TileCount ();
+
+ uint32 arrayCount = tileCount + (fJPEGTables.Get () ? 1 : 0);
+
+ AutoArray<dng_fingerprint> digests (new dng_fingerprint [arrayCount]);
+
+ // Compute digest of each compressed tile.
+
+ {
+
+ uint32 threadCount = Min_uint32 (tileCount,
+ host.PerformAreaTaskThreads ());
+
+ dng_jpeg_image_find_digest_task task (*this,
+ tileCount,
+ digests.Get ());
+
+ host.PerformAreaTask (task,
+ dng_rect (0, 0, 16, 16 * threadCount));
+
+ }
+
+ // Compute digest of JPEG tables, if any.
+
+ if (fJPEGTables.Get ())
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (fJPEGTables->Buffer (),
+ fJPEGTables->LogicalSize ());
+
+ digests [tileCount] = printer.Result ();
+
+ }
+
+ // Combine digests into a single digest.
+
+ {
+
+ dng_md5_printer printer;
+
+ for (uint32 k = 0; k < arrayCount; k++)
+ {
+
+ printer.Process (digests [k].data,
+ dng_fingerprint::kDNGFingerprintSize);
+
+ }
+
+ return printer.Result ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
diff --git a/gpr/source/lib/dng_sdk/dng_jpeg_image.h b/gpr/source/lib/dng_sdk/dng_jpeg_image.h
new file mode 100644
index 0000000..01748bb
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_jpeg_image.h
@@ -0,0 +1,92 @@
+/*****************************************************************************/
+// Copyright 2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_jpeg_image.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_jpeg_image__
+#define __dng_jpeg_image__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_memory.h"
+#include "dng_point.h"
+
+/*****************************************************************************/
+
+typedef AutoPtr<dng_memory_block> dng_jpeg_image_tile_ptr;
+
+/*****************************************************************************/
+
+class dng_jpeg_image
+ {
+
+ public:
+
+ dng_point fImageSize;
+
+ dng_point fTileSize;
+
+ bool fUsesStrips;
+
+ AutoPtr<dng_memory_block> fJPEGTables;
+
+ AutoArray<dng_jpeg_image_tile_ptr> fJPEGData;
+
+ public:
+
+ dng_jpeg_image ();
+
+ uint32 TilesAcross () const
+ {
+ if (fTileSize.h)
+ {
+ return (fImageSize.h + fTileSize.h - 1) / fTileSize.h;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ uint32 TilesDown () const
+ {
+ if (fTileSize.v)
+ {
+ return (fImageSize.v + fTileSize.v - 1) / fTileSize.v;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ uint32 TileCount () const
+ {
+ return TilesAcross () * TilesDown ();
+ }
+
+ void Encode (dng_host &host,
+ const dng_negative &negative,
+ dng_image_writer &writer,
+ const dng_image &image);
+
+ dng_fingerprint FindDigest (dng_host &host) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_lens_correction.cpp b/gpr/source/lib/dng_sdk/dng_lens_correction.cpp
new file mode 100644
index 0000000..74f3c54
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_lens_correction.cpp
@@ -0,0 +1,2373 @@
+/*****************************************************************************/
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_lens_correction.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include <cfloat>
+#include <limits.h>
+
+#include "dng_1d_table.h"
+#include "dng_assertions.h"
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_filter_task.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_lens_correction.h"
+#include "dng_negative.h"
+#include "dng_sdk_limits.h"
+#include "dng_tag_values.h"
+
+/*****************************************************************************/
+
+dng_warp_params::dng_warp_params ()
+
+ : fPlanes (1)
+ , fCenter (0.5, 0.5)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params::dng_warp_params (uint32 planes,
+ const dng_point_real64 &center)
+
+ : fPlanes (planes)
+ , fCenter (center)
+
+ {
+
+ DNG_ASSERT (planes >= 1, "Too few planes." );
+ DNG_ASSERT (planes <= kMaxColorPlanes, "Too many planes.");
+
+ DNG_ASSERT (fCenter.h >= 0.0 && fCenter.h <= 1.0,
+ "Center (horizontal) out of range.");
+
+ DNG_ASSERT (fCenter.v >= 0.0 && fCenter.v <= 1.0,
+ "Center (vertical) out of range.");
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params::~dng_warp_params ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsNOPAll () const
+ {
+
+ return IsRadNOPAll () &&
+ IsTanNOPAll ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsNOP (uint32 plane) const
+ {
+
+ return IsRadNOP (plane) &&
+ IsTanNOP (plane);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsRadNOPAll () const
+ {
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ if (!IsRadNOP (plane))
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsRadNOP (uint32 /* plane */) const
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsTanNOPAll () const
+ {
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ if (!IsTanNOP (plane))
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsTanNOP (uint32 /* plane */) const
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsValid () const
+ {
+
+ if (fPlanes < 1 || fPlanes > kMaxColorPlanes)
+ {
+
+ return false;
+
+ }
+
+ if (fCenter.h < 0.0 ||
+ fCenter.h > 1.0 ||
+ fCenter.v < 0.0 ||
+ fCenter.v > 1.0)
+ {
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params::IsValidForNegative (const dng_negative &negative) const
+ {
+
+ if (!IsValid ())
+ {
+ return false;
+ }
+
+ if ((fPlanes != 1) &&
+ (fPlanes != negative.ColorChannels ()))
+ {
+ return false;
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params::EvaluateInverse (uint32 plane,
+ real64 y) const
+ {
+
+ const uint32 kMaxIterations = 30;
+ const real64 kNearZero = 1.0e-10;
+
+ real64 x0 = 0.0;
+ real64 y0 = Evaluate (plane,
+ x0);
+
+ real64 x1 = 1.0;
+ real64 y1 = Evaluate (plane,
+ x1);
+
+ for (uint32 iteration = 0; iteration < kMaxIterations; iteration++)
+ {
+
+ if (Abs_real64 (y1 - y0) < kNearZero)
+ {
+ break;
+ }
+
+ const real64 x2 = Pin_real64 (0.0,
+ x1 + (y - y1) * (x1 - x0) / (y1 - y0),
+ 1.0);
+
+ const real64 y2 = Evaluate (plane,
+ x2);
+
+ x0 = x1;
+ y0 = y1;
+
+ x1 = x2;
+ y1 = y2;
+
+ }
+
+ return x1;
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_warp_params::EvaluateTangential2 (uint32 plane,
+ const dng_point_real64 &diff) const
+ {
+
+ const real64 dvdv = diff.v * diff.v;
+ const real64 dhdh = diff.h * diff.h;
+
+ const real64 rr = dvdv + dhdh;
+
+ dng_point_real64 diffSqr (dvdv,
+ dhdh);
+
+ return EvaluateTangential (plane,
+ rr,
+ diff,
+ diffSqr);
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_warp_params::EvaluateTangential3 (uint32 plane,
+ real64 r2,
+ const dng_point_real64 &diff) const
+ {
+
+ dng_point_real64 diffSqr (diff.v * diff.v,
+ diff.h * diff.h);
+
+ return EvaluateTangential (plane,
+ r2,
+ diff,
+ diffSqr);
+
+ }
+
+/*****************************************************************************/
+
+void dng_warp_params::Dump () const
+ {
+
+ #if qDNGValidate
+
+ printf ("Planes: %u\n", (unsigned) fPlanes);
+
+ printf (" Optical center:\n"
+ " h = %.6lf\n"
+ " v = %.6lf\n",
+ fCenter.h,
+ fCenter.v);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params_rectilinear::dng_warp_params_rectilinear ()
+
+ : dng_warp_params ()
+
+ {
+
+ for (uint32 plane = 0; plane < kMaxColorPlanes; plane++)
+ {
+
+ fRadParams [plane] = dng_vector (4);
+ fTanParams [plane] = dng_vector (2);
+
+ fRadParams [plane][0] = 1.0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params_rectilinear::dng_warp_params_rectilinear (uint32 planes,
+ const dng_vector radParams [],
+ const dng_vector tanParams [],
+ const dng_point_real64 &center)
+
+ : dng_warp_params (planes,
+ center)
+
+ {
+
+ for (uint32 i = 0; i < fPlanes; i++)
+ {
+ fRadParams [i] = radParams [i];
+ fTanParams [i] = tanParams [i];
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params_rectilinear::~dng_warp_params_rectilinear ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params_rectilinear::IsRadNOP (uint32 plane) const
+ {
+
+ DNG_ASSERT (plane < fPlanes, "plane out of range.");
+
+ const dng_vector &r = fRadParams [plane];
+
+ return (r [0] == 1.0 &&
+ r [1] == 0.0 &&
+ r [2] == 0.0 &&
+ r [3] == 0.0);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params_rectilinear::IsTanNOP (uint32 plane) const
+ {
+
+ DNG_ASSERT (plane < fPlanes, "plane out of range.");
+
+ const dng_vector &t = fTanParams [plane];
+
+ return (t [0] == 0.0 &&
+ t [1] == 0.0);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params_rectilinear::IsValid () const
+ {
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ if (fRadParams [plane].Count () != 4)
+ {
+ return false;
+ }
+
+ if (fTanParams [plane].Count () < 2)
+ {
+ return false;
+ }
+
+ }
+
+ return dng_warp_params::IsValid ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_warp_params_rectilinear::PropagateToAllPlanes (uint32 totalPlanes)
+ {
+
+ for (uint32 plane = fPlanes; plane < totalPlanes; plane++)
+ {
+
+ fRadParams [plane] = fRadParams [0];
+ fTanParams [plane] = fTanParams [0];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params_rectilinear::Evaluate (uint32 plane,
+ real64 x) const
+ {
+
+ const dng_vector &K = fRadParams [plane]; // Coefficients.
+
+ const real64 x2 = x * x;
+
+ return x * (K [0] + x2 * (K [1] + x2 * (K [2] + x2 * K [3])));
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params_rectilinear::EvaluateRatio (uint32 plane,
+ real64 r2) const
+ {
+
+ const dng_vector &K = fRadParams [plane]; // Coefficients.
+
+ return K [0] + r2 * (K [1] + r2 * (K [2] + r2 * K [3]));
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_warp_params_rectilinear::EvaluateTangential (uint32 plane,
+ real64 r2,
+ const dng_point_real64 &diff,
+ const dng_point_real64 &diff2) const
+ {
+
+ const real64 kt0 = fTanParams [plane][0];
+ const real64 kt1 = fTanParams [plane][1];
+
+ const real64 dh = diff.h;
+ const real64 dv = diff.v;
+
+ const real64 dhdh = diff2.h;
+ const real64 dvdv = diff2.v;
+
+ return dng_point_real64 (kt0 * (r2 + 2.0 * dvdv) + (2.0 * kt1 * dh * dv), // v
+ kt1 * (r2 + 2.0 * dhdh) + (2.0 * kt0 * dh * dv)); // h
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params_rectilinear::MaxSrcRadiusGap (real64 maxDstGap) const
+ {
+
+ real64 maxSrcGap = 0.0;
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ const dng_vector &coefs = fRadParams [plane];
+
+ const real64 k3 = coefs [1];
+ const real64 k5 = coefs [2];
+ const real64 k7 = coefs [3];
+
+ //
+ // Let f (r) be the radius warp function. Consider the function
+ //
+ // gap (r) = f (r + maxDstGap) - f (r)
+ //
+ // We wish to maximize gap (r) over the domain [0, 1 - maxDstGap]. This will
+ // give us a reasonable upper bound on the src tile size, independent of
+ // dstBounds.
+ //
+ // As usual, we maximize gap (r) by examining its critical points, i.e., by
+ // considering the roots of its derivative which lie in the domain [0, 1 -
+ // maxDstGap]. gap' (r) is a 5th-order polynomial. One of its roots is
+ // -maxDstGap / 2, which is negative and hence lies outside the domain of
+ // interest. This leaves 4 other possible roots. We solve for these
+ // analytically below.
+ //
+
+ real64 roots [4];
+ uint32 numRoots = 0;
+
+ if (k7 == 0.0)
+ {
+
+ if (k5 == 0.0)
+ {
+
+ // No roots in [0,1].
+
+ }
+
+ else
+ {
+
+ // k7 is zero, but k5 is non-zero. At most two real roots.
+
+ const real64 discrim = 25.0 * (-6.0 * k3 * k5 - 5.0 * k5 * maxDstGap * maxDstGap);
+
+ if (discrim >= 0.0)
+ {
+
+ // Two real roots.
+
+ const real64 scale = 0.1 * k5;
+ const real64 offset = -5.0 * maxDstGap * k5;
+ const real64 sDiscrim = sqrt (discrim);
+
+ roots [numRoots++] = scale * (offset + sDiscrim);
+ roots [numRoots++] = scale * (offset - sDiscrim);
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ // k7 is non-zero. Up to 4 real roots.
+
+ const real64 d = maxDstGap;
+ const real64 d2 = d * d;
+ const real64 d4 = d2 * d2;
+
+ const real64 discrim = 25.0 * k5 * k5
+ - 63.0 * k3 * k7
+ + 35.0 * d2 * k5 * k7
+ + 49.0 * d4 * k7 * k7;
+
+ if (discrim >= 0.0)
+ {
+
+ const real64 sDiscrim = 4.0 * k7 * sqrt (discrim);
+
+ const real64 offset = -20.0 * k5 * k7 - 35.0 * d2 * k7 * k7;
+
+ const real64 discrim1 = offset - sDiscrim;
+ const real64 discrim2 = offset + sDiscrim;
+
+ const real64 scale = sqrt (21.0) / (42.0 * k7);
+
+ if (discrim1 >= 0.0)
+ {
+
+ const real64 offset1 = -d * 0.5;
+ const real64 sDiscrim1 = scale * sqrt (discrim1);
+
+ roots [numRoots++] = offset1 + sDiscrim1;
+ roots [numRoots++] = offset1 - sDiscrim1;
+
+ }
+
+ if (discrim2 >= 0.0)
+ {
+
+ const real64 offset2 = -d * 0.5;
+ const real64 sDiscrim2 = scale * sqrt (discrim2);
+
+ roots [numRoots++] = offset2 + sDiscrim2;
+ roots [numRoots++] = offset2 - sDiscrim2;
+
+ }
+
+ }
+
+ }
+
+ real64 planeMaxSrcGap = 0.0;
+
+ // Examine the endpoints.
+
+ {
+
+ // Check left endpoint: f (maxDstGap) - f (0). Remember that f (0) == 0.
+
+ const real64 gap1 = Evaluate (plane, maxDstGap);
+
+ planeMaxSrcGap = Max_real64 (planeMaxSrcGap, gap1);
+
+ // Check right endpoint: f (1) - f (1 - maxDstGap).
+
+ const real64 gap2 = Evaluate (plane, 1.0)
+ - Evaluate (plane, 1.0 - maxDstGap);
+
+ planeMaxSrcGap = Max_real64 (planeMaxSrcGap, gap2);
+
+ }
+
+ // Examine the roots we found, if any.
+
+ for (uint32 i = 0; i < numRoots; i++)
+ {
+
+ const real64 r = roots [i];
+
+ if (r > 0.0 && r < 1.0 - maxDstGap)
+ {
+
+ const real64 gap = Evaluate (plane, r + maxDstGap)
+ - Evaluate (plane, r);
+
+ planeMaxSrcGap = Max_real64 (planeMaxSrcGap, gap);
+
+ }
+
+ }
+
+ maxSrcGap = Max_real64 (maxSrcGap,
+ planeMaxSrcGap);
+
+ }
+
+ return maxSrcGap;
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_warp_params_rectilinear::MaxSrcTanGap (dng_point_real64 minDst,
+ dng_point_real64 maxDst) const
+ {
+
+ const real64 v [] = { minDst.v, maxDst.v, 0.0 };
+ const real64 h [] = { minDst.h, maxDst.h, 0.0 };
+
+ dng_point_real64 maxGap;
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ real64 hMin = +FLT_MAX;
+ real64 hMax = -FLT_MAX;
+
+ real64 vMin = +FLT_MAX;
+ real64 vMax = -FLT_MAX;
+
+ for (uint32 i = 0; i < 3; i++)
+ {
+
+ for (uint32 j = 0; j < 3; j++)
+ {
+
+ dng_point_real64 dstDiff (v [i],
+ h [j]);
+
+ dng_point_real64 srcDiff = EvaluateTangential2 (plane,
+ dstDiff);
+
+ hMin = Min_real64 (hMin, srcDiff.h);
+ hMax = Max_real64 (hMax, srcDiff.h);
+
+ vMin = Min_real64 (vMin, srcDiff.v);
+ vMax = Max_real64 (vMax, srcDiff.v);
+
+ }
+
+ }
+
+ const real64 hGap = hMax - hMin;
+ const real64 vGap = vMax - vMin;
+
+ maxGap.h = Max_real64 (maxGap.h, hGap);
+ maxGap.v = Max_real64 (maxGap.v, vGap);
+
+ }
+
+ return maxGap;
+
+ }
+
+/*****************************************************************************/
+
+void dng_warp_params_rectilinear::Dump () const
+ {
+
+ #if qDNGValidate
+
+ dng_warp_params::Dump ();
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ printf (" Plane %u:\n", (unsigned) plane);
+
+ printf (" Radial params: %.6lf, %.6lf, %.6lf, %.6lf\n",
+ fRadParams [plane][0],
+ fRadParams [plane][1],
+ fRadParams [plane][2],
+ fRadParams [plane][3]);
+
+ printf (" Tangential params: %.6lf, %.6lf\n",
+ fTanParams [plane][0],
+ fTanParams [plane][1]);
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params_fisheye::dng_warp_params_fisheye ()
+
+ : dng_warp_params ()
+
+ {
+
+ for (uint32 plane = 0; plane < kMaxColorPlanes; plane++)
+ {
+
+ fRadParams [plane] = dng_vector (4);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params_fisheye::dng_warp_params_fisheye (uint32 planes,
+ const dng_vector radParams [],
+ const dng_point_real64 &center)
+
+ : dng_warp_params (planes, center)
+
+ {
+
+ for (uint32 i = 0; i < fPlanes; i++)
+ {
+
+ fRadParams [i] = radParams [i];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_warp_params_fisheye::~dng_warp_params_fisheye ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params_fisheye::IsRadNOP (uint32 /* plane */) const
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params_fisheye::IsTanNOP (uint32 /* plane */) const
+ {
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_warp_params_fisheye::IsValid () const
+ {
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ if (fRadParams [plane].Count () != 4)
+ {
+ return false;
+ }
+
+ }
+
+ return dng_warp_params::IsValid ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_warp_params_fisheye::PropagateToAllPlanes (uint32 totalPlanes)
+ {
+
+ for (uint32 plane = fPlanes; plane < totalPlanes; plane++)
+ {
+
+ fRadParams [plane] = fRadParams [0];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params_fisheye::Evaluate (uint32 plane,
+ real64 r) const
+ {
+
+ const real64 t = atan (r);
+
+ const dng_vector &K = fRadParams [plane];
+
+ const real64 t2 = t * t;
+
+ return t * (K [0] + t2 * (K [1] + t2 * (K [2] + t2 * K [3])));
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params_fisheye::EvaluateRatio (uint32 plane,
+ real64 rSqr) const
+ {
+
+ const real64 eps = 1.0e-12;
+
+ if (rSqr < eps)
+ {
+
+ // r is very close to zero.
+
+ return 1.0;
+
+ }
+
+ const real64 r = sqrt (rSqr);
+
+ return Evaluate (plane, r) / r;
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_warp_params_fisheye::EvaluateTangential (uint32 /* plane */,
+ real64 /* r2 */,
+ const dng_point_real64 & /* diff */,
+ const dng_point_real64 & /* diff2 */) const
+ {
+
+ // This fisheye model does not support tangential warping.
+
+ ThrowProgramError ();
+
+ return dng_point_real64 (0.0, 0.0);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_warp_params_fisheye::MaxSrcRadiusGap (real64 maxDstGap) const
+ {
+
+ //
+ // Let f (r) be the radius warp function. Consider the function
+ //
+ // gap (r) = f (r + maxDstGap) - f (r)
+ //
+ // We wish to maximize gap (r) over the domain [0, 1 - maxDstGap]. This will
+ // give us a reasonable upper bound on the src tile size, independent of
+ // dstBounds.
+ //
+ // Ideally, we'd like to maximize gap (r) by examining its critical points,
+ // i.e., by considering the roots of its derivative which lie in the domain [0,
+ // 1 - maxDstGap]. However, gap' (r) is too complex to find its roots
+ // analytically.
+ //
+
+ real64 maxSrcGap = 0.0;
+
+ DNG_REQUIRE (maxDstGap > 0.0, "maxDstGap must be positive.");
+
+ const real64 kMaxValue = 1.0 - maxDstGap;
+
+ const uint32 kSteps = 128;
+
+ const real64 kNorm = kMaxValue / real64 (kSteps - 1);
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ for (uint32 i = 0; i < kSteps; i++)
+ {
+
+ const real64 tt = i * kNorm;
+
+ const real64 gap = Evaluate (plane, tt + maxDstGap)
+ - Evaluate (plane, tt);
+
+ maxSrcGap = Max_real64 (maxSrcGap,
+ gap);
+
+ }
+
+ }
+
+ return maxSrcGap;
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_warp_params_fisheye::MaxSrcTanGap (dng_point_real64 /* minDst */,
+ dng_point_real64 /* maxDst */) const
+ {
+
+ // This fisheye model does not support tangential distortion.
+
+ return dng_point_real64 (0.0, 0.0);
+
+ }
+
+/*****************************************************************************/
+
+void dng_warp_params_fisheye::Dump () const
+ {
+
+ #if qDNGValidate
+
+ dng_warp_params::Dump ();
+
+ for (uint32 plane = 0; plane < fPlanes; plane++)
+ {
+
+ printf (" Plane %u:\n", (unsigned) plane);
+
+ printf (" Radial params: %.6lf, %.6lf, %.6lf, %.6lf\n",
+ fRadParams [plane][0],
+ fRadParams [plane][1],
+ fRadParams [plane][2],
+ fRadParams [plane][3]);
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+class dng_filter_warp: public dng_filter_task
+ {
+
+ protected:
+
+ AutoPtr<dng_warp_params> fParams;
+
+ dng_point_real64 fCenter;
+
+ dng_resample_weights_2d fWeights;
+
+ real64 fNormRadius;
+ real64 fInvNormRadius;
+
+ bool fIsRadNOP;
+ bool fIsTanNOP;
+
+ const real64 fPixelScaleV;
+ const real64 fPixelScaleVInv;
+
+ public:
+
+ dng_filter_warp (const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_negative &negative,
+ AutoPtr<dng_warp_params> &params);
+
+ virtual void Initialize (dng_host &host);
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea);
+
+ virtual dng_point SrcTileSize (const dng_point &dstTileSize);
+
+ virtual void ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer);
+
+ virtual dng_point_real64 GetSrcPixelPosition (const dng_point_real64 &dst,
+ uint32 plane);
+
+ };
+
+/*****************************************************************************/
+
+dng_filter_warp::dng_filter_warp (const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_negative &negative,
+ AutoPtr<dng_warp_params> &params)
+
+ : dng_filter_task (srcImage,
+ dstImage)
+
+ , fParams (params.Release ())
+
+ , fCenter ()
+
+ , fWeights ()
+
+ , fNormRadius (1.0)
+ , fInvNormRadius (1.0)
+
+ , fIsRadNOP (false)
+ , fIsTanNOP (false)
+
+ , fPixelScaleV (1.0 / negative.PixelAspectRatio ())
+ , fPixelScaleVInv (1.0 / fPixelScaleV)
+
+ {
+
+ // Force float processing.
+
+ fSrcPixelType = ttFloat;
+ fDstPixelType = ttFloat;
+
+ fIsRadNOP = fParams->IsRadNOPAll ();
+ fIsTanNOP = fParams->IsTanNOPAll ();
+
+ const uint32 negPlanes = negative.ColorChannels ();
+
+ DNG_ASSERT (negPlanes >= 1, "Too few planes." );
+ DNG_ASSERT (negPlanes <= kMaxColorPlanes, "Too many planes.");
+
+ (void) negPlanes;
+
+ // At least one set of params must do something interesting.
+
+ if (fIsRadNOP && fIsTanNOP)
+ {
+ ThrowProgramError ();
+ }
+
+ // Make sure the warp params are valid for this negative.
+
+ if (!fParams->IsValidForNegative (negative))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Compute center.
+
+ const dng_rect bounds = srcImage.Bounds ();
+
+ fCenter.h = Lerp_real64 ((real64) bounds.l,
+ (real64) bounds.r,
+ fParams->fCenter.h);
+
+ fCenter.v = Lerp_real64 ((real64) bounds.t,
+ (real64) bounds.b,
+ fParams->fCenter.v);
+
+ // Compute max pixel radius and derive various normalized radius values. Note
+ // that when computing the max pixel radius, we must take into account the pixel
+ // aspect ratio.
+
+ {
+
+ dng_rect squareBounds (bounds);
+
+ squareBounds.b = squareBounds.t +
+ Round_int32 (fPixelScaleV * (real64) squareBounds.H ());
+
+ const dng_point_real64 squareCenter (Lerp_real64 ((real64) squareBounds.t,
+ (real64) squareBounds.b,
+ fParams->fCenter.v),
+
+ Lerp_real64 ((real64) squareBounds.l,
+ (real64) squareBounds.r,
+ fParams->fCenter.h));
+
+ fNormRadius = MaxDistancePointToRect (squareCenter,
+ squareBounds);
+
+ fInvNormRadius = 1.0 / fNormRadius;
+
+ }
+
+ // Propagate warp params to other planes.
+
+ fParams->PropagateToAllPlanes (fDstPlanes);
+
+ }
+
+/*****************************************************************************/
+
+void dng_filter_warp::Initialize (dng_host &host)
+ {
+
+ // Make resample weights.
+
+ const dng_resample_function &kernel = dng_resample_bicubic::Get ();
+
+ fWeights.Initialize (kernel,
+ host.Allocator ());
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea)
+ {
+
+ // Walk each pixel of the boundary of dstArea, map it to the uncorrected src
+ // pixel position, and return the rectangle that contains all such src pixels.
+
+ int32 xMin = INT_MAX;
+ int32 xMax = INT_MIN;
+ int32 yMin = INT_MAX;
+ int32 yMax = INT_MIN;
+
+ for (uint32 plane = 0; plane < fDstPlanes; plane++)
+ {
+
+ // Top and bottom edges.
+
+ for (int32 c = dstArea.l; c < dstArea.r; c++)
+ {
+
+ // Top edge.
+
+ {
+
+ const dng_point_real64 dst (dstArea.t, c);
+
+ const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
+
+ const int32 y = (int32) floor (src.v);
+
+ yMin = Min_int32 (yMin, y);
+
+ }
+
+ // Bottom edge.
+
+ {
+
+ const dng_point_real64 dst (dstArea.b - 1, c);
+
+ const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
+
+ const int32 y = (int32) ceil (src.v);
+
+ yMax = Max_int32 (yMax, y);
+
+ }
+
+ }
+
+ // Left and right edges.
+
+ for (int32 r = dstArea.t; r < dstArea.b; r++)
+ {
+
+ // Left edge.
+
+ {
+
+ const dng_point_real64 dst (r, dstArea.l);
+
+ const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
+
+ const int32 x = (int32) floor (src.h);
+
+ xMin = Min_int32 (xMin, x);
+
+ }
+
+ // Right edge.
+
+ {
+
+ const dng_point_real64 dst (r, dstArea.r - 1);
+
+ const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
+
+ const int32 x = (int32) ceil (src.h);
+
+ xMax = Max_int32 (xMax, x);
+
+ }
+
+ }
+
+ }
+
+ // Pad each side by filter radius.
+
+ const int32 pad = (int32) fWeights.Radius ();
+
+ xMin -= pad;
+ yMin -= pad;
+ xMax += pad;
+ yMax += pad;
+
+ xMax += 1;
+ yMax += 1;
+
+ const dng_rect srcArea (yMin,
+ xMin,
+ yMax,
+ xMax);
+
+ return srcArea;
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_filter_warp::SrcTileSize (const dng_point &dstTileSize)
+ {
+
+ // Obtain an upper bound on the source tile size. We'll do this by considering
+ // upper bounds on the radial and tangential warp components separately, then add
+ // them together. This is not a tight bound but is good enough because the
+ // tangential terms are usually quite small.
+
+ // Get upper bound on src tile size from radial warp.
+
+ DNG_REQUIRE (dstTileSize.v > 0, "Invalid tile height.");
+ DNG_REQUIRE (dstTileSize.h > 0, "Invalid tile width.");
+
+ const real64 maxDstGap = fInvNormRadius * hypot ((real64) dstTileSize.h,
+ (real64) dstTileSize.v);
+
+ dng_point srcTileSize;
+
+ if (maxDstGap >= 1.0)
+ {
+
+ // The proposed tile size is unusually large, i.e., its hypotenuse is larger
+ // than the maximum radius. Bite the bullet and just return a tile size big
+ // enough to process the whole image.
+
+ srcTileSize = SrcArea (fDstImage.Bounds ()).Size ();
+
+ }
+
+ else
+ {
+
+ // maxDstGap < 1.0.
+
+ const real64 maxSrcGap = fParams->MaxSrcRadiusGap (maxDstGap);
+
+ const int32 dim = (int32) ceil (maxSrcGap * fNormRadius);
+
+ srcTileSize = dng_point (dim, dim);
+
+ }
+
+ srcTileSize.h += (int32) (fWeights.Width ());
+ srcTileSize.v += (int32) (fWeights.Width ());
+
+ // Get upper bound on src tile size from tangential warp.
+
+ const dng_rect_real64 bounds (fSrcImage.Bounds ());
+
+ const dng_point_real64 minDst ((bounds.t - fCenter.v) * fInvNormRadius,
+ (bounds.l - fCenter.h) * fInvNormRadius);
+
+ const dng_point_real64 maxDst ((bounds.b - 1.0 - fCenter.v) * fInvNormRadius,
+ (bounds.r - 1.0 - fCenter.h) * fInvNormRadius);
+
+ const dng_point_real64 srcTanGap = fParams->MaxSrcTanGap (minDst,
+ maxDst);
+
+ // Add the two bounds together.
+
+ srcTileSize.v += (int32) ceil (srcTanGap.v * fNormRadius);
+ srcTileSize.h += (int32) ceil (srcTanGap.h * fNormRadius);
+
+ return srcTileSize;
+
+ }
+
+/*****************************************************************************/
+
+void dng_filter_warp::ProcessArea (uint32 /* threadIndex */,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer)
+ {
+
+ // Prepare resample constants.
+
+ const int32 wCount = fWeights.Width ();
+
+ const dng_point srcOffset (fWeights.Offset (),
+ fWeights.Offset ());
+
+ const real64 numSubsamples = (real64) kResampleSubsampleCount2D;
+
+ // Prepare area and step constants.
+
+ const dng_rect srcArea = srcBuffer.fArea;
+ const dng_rect dstArea = dstBuffer.fArea;
+
+ const int32 srcRowStep = (int32) srcBuffer.RowStep ();
+
+ const int32 hMin = srcArea.l;
+ const int32 hMax = srcArea.r - wCount - 1;
+
+ const int32 vMin = srcArea.t;
+ const int32 vMax = srcArea.b - wCount - 1;
+
+ // Warp each plane.
+
+ for (uint32 plane = 0; plane < dstBuffer.fPlanes; plane++)
+ {
+
+ real32 *dPtr = dstBuffer.DirtyPixel_real32 (dstArea.t,
+ dstArea.l,
+ plane);
+
+ for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
+ {
+
+ uint32 dstIndex = 0;
+
+ for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++, dstIndex++)
+ {
+
+ // Get destination (corrected) pixel position.
+
+ const dng_point_real64 dPos ((real64) dstRow,
+ (real64) dstCol);
+
+ // Warp to source (uncorrected) pixel position.
+
+ const dng_point_real64 sPos = GetSrcPixelPosition (dPos,
+ plane);
+
+ // Decompose into integer and fractional parts.
+
+ dng_point sInt ((int32) floor (sPos.v),
+ (int32) floor (sPos.h));
+
+ dng_point sFct ((int32) ((sPos.v - (real64) sInt.v) * numSubsamples),
+ (int32) ((sPos.h - (real64) sInt.h) * numSubsamples));
+
+ // Add resample offset.
+
+ sInt = sInt + srcOffset;
+
+ // Clip.
+
+ if (sInt.h < hMin)
+ {
+ sInt.h = hMin;
+ sFct.h = 0;
+ }
+
+ else if (sInt.h > hMax)
+ {
+ sInt.h = hMax;
+ sFct.h = 0;
+ }
+
+ if (sInt.v < vMin)
+ {
+ sInt.v = vMin;
+ sFct.v = 0;
+ }
+
+ else if (sInt.v > vMax)
+ {
+ sInt.v = vMax;
+ sFct.v = 0;
+ }
+
+ // Perform 2D resample.
+
+ const real32 *w = fWeights.Weights32 (sFct);
+
+ const real32 *s = srcBuffer.ConstPixel_real32 (sInt.v,
+ sInt.h,
+ plane);
+
+ real32 total = 0.0f;
+
+ for (int32 i = 0; i < wCount; i++)
+ {
+
+ for (int32 j = 0; j < wCount; j++)
+ {
+
+ total += w [j] * s [j];
+
+ }
+
+ w += wCount;
+ s += srcRowStep;
+
+ }
+
+ // Store final pixel value.
+
+ dPtr [dstIndex] = Pin_real32 (total);
+
+ }
+
+ // Advance to next row.
+
+ dPtr += dstBuffer.RowStep ();
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_point_real64 dng_filter_warp::GetSrcPixelPosition (const dng_point_real64 &dst,
+ uint32 plane)
+ {
+
+ const dng_point_real64 diff = dst - fCenter;
+
+ const dng_point_real64 diffNorm (diff.v * fInvNormRadius,
+ diff.h * fInvNormRadius);
+
+ const dng_point_real64 diffNormScaled (diffNorm.v * fPixelScaleV,
+ diffNorm.h);
+
+ const dng_point_real64 diffNormSqr (diffNormScaled.v * diffNormScaled.v,
+ diffNormScaled.h * diffNormScaled.h);
+
+ const real64 rr = Min_real64 (diffNormSqr.v + diffNormSqr.h,
+ 1.0);
+
+ dng_point_real64 dSrc;
+
+ if (fIsTanNOP)
+ {
+
+ // Radial only.
+
+ const real64 ratio = fParams->EvaluateRatio (plane,
+ rr);
+
+ dSrc.h = diff.h * ratio;
+ dSrc.v = diff.v * ratio;
+
+ }
+
+ else if (fIsRadNOP)
+ {
+
+ // Tangential only.
+
+ const dng_point_real64 tan = fParams->EvaluateTangential (plane,
+ rr,
+ diffNormScaled,
+ diffNormSqr);
+
+ dSrc.h = diff.h + (fNormRadius * tan.h);
+ dSrc.v = diff.v + (fNormRadius * tan.v * fPixelScaleVInv);
+
+ }
+
+ else
+ {
+
+ // Radial and tangential.
+
+ const real64 ratio = fParams->EvaluateRatio (plane,
+ rr);
+
+ const dng_point_real64 tan = fParams->EvaluateTangential (plane,
+ rr,
+ diffNormScaled,
+ diffNormSqr);
+
+ dSrc.h = fNormRadius * (diffNorm.h * ratio + tan.h);
+ dSrc.v = fNormRadius * (diffNorm.v * ratio + tan.v * fPixelScaleVInv);
+
+ }
+
+ return fCenter + dSrc;
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_WarpRectilinear::dng_opcode_WarpRectilinear (const dng_warp_params_rectilinear &params,
+ uint32 flags)
+
+ : dng_opcode (dngOpcode_WarpRectilinear,
+ dngVersion_1_3_0_0,
+ flags)
+
+ , fWarpParams (params)
+
+ {
+
+ if (!params.IsValid ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_WarpRectilinear::dng_opcode_WarpRectilinear (dng_stream &stream)
+
+ : dng_opcode (dngOpcode_WarpRectilinear,
+ stream,
+ "WarpRectilinear")
+
+ , fWarpParams ()
+
+ {
+
+ // Grab the size in bytes.
+
+ const uint32 bytes = stream.Get_uint32 ();
+
+ // Grab the number of planes to warp.
+
+ fWarpParams.fPlanes = stream.Get_uint32 ();
+
+ // Verify number of planes.
+
+ if (fWarpParams.fPlanes == 0 ||
+ fWarpParams.fPlanes > kMaxColorPlanes)
+ {
+ ThrowBadFormat ();
+ }
+
+ // Verify the size.
+
+ if (bytes != ParamBytes (fWarpParams.fPlanes))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Read warp parameters for each plane.
+
+ for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
+ {
+
+ fWarpParams.fRadParams [plane][0] = stream.Get_real64 ();
+ fWarpParams.fRadParams [plane][1] = stream.Get_real64 ();
+ fWarpParams.fRadParams [plane][2] = stream.Get_real64 ();
+ fWarpParams.fRadParams [plane][3] = stream.Get_real64 ();
+
+ fWarpParams.fTanParams [plane][0] = stream.Get_real64 ();
+ fWarpParams.fTanParams [plane][1] = stream.Get_real64 ();
+
+ }
+
+ // Read the image center.
+
+ fWarpParams.fCenter.h = stream.Get_real64 ();
+ fWarpParams.fCenter.v = stream.Get_real64 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ fWarpParams.Dump ();
+
+ }
+
+ #endif
+
+ if (!fWarpParams.IsValid ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode_WarpRectilinear::IsNOP () const
+ {
+
+ return fWarpParams.IsNOPAll ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode_WarpRectilinear::IsValidForNegative (const dng_negative &negative) const
+ {
+
+ return fWarpParams.IsValidForNegative (negative);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_WarpRectilinear::PutData (dng_stream &stream) const
+ {
+
+ const uint32 bytes = ParamBytes (fWarpParams.fPlanes);
+
+ stream.Put_uint32 (bytes);
+
+ stream.Put_uint32 (fWarpParams.fPlanes);
+
+ for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
+ {
+
+ stream.Put_real64 (fWarpParams.fRadParams [plane][0]);
+ stream.Put_real64 (fWarpParams.fRadParams [plane][1]);
+ stream.Put_real64 (fWarpParams.fRadParams [plane][2]);
+ stream.Put_real64 (fWarpParams.fRadParams [plane][3]);
+
+ stream.Put_real64 (fWarpParams.fTanParams [plane][0]);
+ stream.Put_real64 (fWarpParams.fTanParams [plane][1]);
+
+ }
+
+ stream.Put_real64 (fWarpParams.fCenter.h);
+ stream.Put_real64 (fWarpParams.fCenter.v);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_WarpRectilinear::Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image)
+ {
+
+ #if qDNGValidate
+
+ dng_timer timer ("WarpRectilinear time");
+
+ #endif
+
+ // Allocate destination image.
+
+ AutoPtr<dng_image> dstImage (host.Make_dng_image (image->Bounds (),
+ image->Planes (),
+ image->PixelType ()));
+
+ // Warp the image.
+
+ AutoPtr<dng_warp_params> params (new dng_warp_params_rectilinear (fWarpParams));
+
+ dng_filter_warp filter (*image,
+ *dstImage,
+ negative,
+ params);
+
+ filter.Initialize (host);
+
+ host.PerformAreaTask (filter,
+ image->Bounds ());
+
+ // Return the new image.
+
+ image.Reset (dstImage.Release ());
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_WarpRectilinear::ParamBytes (uint32 planes)
+ {
+
+ return (1 * (uint32) sizeof (uint32) ) + // Number of planes.
+ (6 * (uint32) sizeof (real64) * planes) + // Warp coefficients.
+ (2 * (uint32) sizeof (real64) ); // Optical center.
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_WarpFisheye::dng_opcode_WarpFisheye (const dng_warp_params_fisheye &params,
+ uint32 flags)
+
+ : dng_opcode (dngOpcode_WarpFisheye,
+ dngVersion_1_3_0_0,
+ flags)
+
+ , fWarpParams (params)
+
+ {
+
+ if (!params.IsValid ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_WarpFisheye::dng_opcode_WarpFisheye (dng_stream &stream)
+
+ : dng_opcode (dngOpcode_WarpFisheye,
+ stream,
+ "WarpFisheye")
+
+ , fWarpParams ()
+
+ {
+
+ // Grab the size in bytes.
+
+ const uint32 bytes = stream.Get_uint32 ();
+
+ // Grab the number of planes to warp.
+
+ fWarpParams.fPlanes = stream.Get_uint32 ();
+
+ // Verify number of planes.
+
+ if (fWarpParams.fPlanes == 0 ||
+ fWarpParams.fPlanes > kMaxColorPlanes)
+ {
+ ThrowBadFormat ();
+ }
+
+ // Verify the size.
+
+ if (bytes != ParamBytes (fWarpParams.fPlanes))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Read warp parameters for each plane.
+
+ for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
+ {
+
+ fWarpParams.fRadParams [plane][0] = stream.Get_real64 ();
+ fWarpParams.fRadParams [plane][1] = stream.Get_real64 ();
+ fWarpParams.fRadParams [plane][2] = stream.Get_real64 ();
+ fWarpParams.fRadParams [plane][3] = stream.Get_real64 ();
+
+ }
+
+ // Read the image center.
+
+ fWarpParams.fCenter.h = stream.Get_real64 ();
+ fWarpParams.fCenter.v = stream.Get_real64 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ fWarpParams.Dump ();
+
+ }
+
+ #endif
+
+ if (!fWarpParams.IsValid ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode_WarpFisheye::IsNOP () const
+ {
+
+ return fWarpParams.IsNOPAll ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode_WarpFisheye::IsValidForNegative (const dng_negative &negative) const
+ {
+
+ return fWarpParams.IsValidForNegative (negative);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_WarpFisheye::PutData (dng_stream &stream) const
+ {
+
+ const uint32 bytes = ParamBytes (fWarpParams.fPlanes);
+
+ stream.Put_uint32 (bytes);
+
+ // Write the number of planes.
+
+ stream.Put_uint32 (fWarpParams.fPlanes);
+
+ // Write the warp coefficients.
+
+ for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
+ {
+
+ stream.Put_real64 (fWarpParams.fRadParams [plane][0]);
+ stream.Put_real64 (fWarpParams.fRadParams [plane][1]);
+ stream.Put_real64 (fWarpParams.fRadParams [plane][2]);
+ stream.Put_real64 (fWarpParams.fRadParams [plane][3]);
+
+ }
+
+ // Write the optical center.
+
+ stream.Put_real64 (fWarpParams.fCenter.h);
+ stream.Put_real64 (fWarpParams.fCenter.v);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_WarpFisheye::Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image)
+ {
+
+ #if qDNGValidate
+
+ dng_timer timer ("WarpFisheye time");
+
+ #endif
+
+ // Allocate destination image.
+
+ AutoPtr<dng_image> dstImage (host.Make_dng_image (image->Bounds (),
+ image->Planes (),
+ image->PixelType ()));
+
+ // Warp the image.
+
+ AutoPtr<dng_warp_params> params (new dng_warp_params_fisheye (fWarpParams));
+
+ dng_filter_warp filter (*image,
+ *dstImage,
+ negative,
+ params);
+
+ filter.Initialize (host);
+
+ host.PerformAreaTask (filter,
+ image->Bounds ());
+
+ // Return the new image.
+
+ image.Reset (dstImage.Release ());
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_WarpFisheye::ParamBytes (uint32 planes)
+ {
+
+ return (1 * (uint32) sizeof (uint32) ) + // Number of planes.
+ (4 * (uint32) sizeof (real64) * planes) + // Warp coefficients.
+ (2 * (uint32) sizeof (real64) ); // Optical center.
+
+ }
+
+/*****************************************************************************/
+
+dng_vignette_radial_params::dng_vignette_radial_params ()
+
+ : fParams (kNumTerms)
+ , fCenter (0.5, 0.5)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_vignette_radial_params::dng_vignette_radial_params (const std::vector<real64> &params,
+ const dng_point_real64 &center)
+
+ : fParams (params)
+ , fCenter (center)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_vignette_radial_params::IsNOP () const
+ {
+
+ for (uint32 i = 0; i < fParams.size (); i++)
+ {
+
+ if (fParams [i] != 0.0)
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_vignette_radial_params::IsValid () const
+ {
+
+ if (fParams.size () != kNumTerms)
+ {
+ return false;
+ }
+
+ if (fCenter.h < 0.0 ||
+ fCenter.h > 1.0 ||
+ fCenter.v < 0.0 ||
+ fCenter.v > 1.0)
+ {
+ return false;
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_vignette_radial_params::Dump () const
+ {
+
+ #if qDNGValidate
+
+ printf (" Radial vignette params: ");
+
+ for (uint32 i = 0; i < fParams.size (); i++)
+ {
+
+ printf ("%s%.6lf",
+ (i == 0) ? "" : ", ",
+ fParams [i]);
+
+ }
+
+ printf ("\n");
+
+ printf (" Optical center:\n"
+ " h = %.6lf\n"
+ " v = %.6lf\n",
+ fCenter.h,
+ fCenter.v);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+class dng_vignette_radial_function: public dng_1d_function
+ {
+
+ protected:
+
+ const dng_vignette_radial_params fParams;
+
+ public:
+
+ explicit dng_vignette_radial_function (const dng_vignette_radial_params &params)
+
+ : fParams (params)
+
+ {
+
+ }
+
+ // x represents r^2, where r is the normalized Euclidean distance from the
+ // optical center to a pixel. r lies in [0,1], so r^2 (and hence x) also lies
+ // in [0,1].
+
+ virtual real64 Evaluate (real64 x) const
+ {
+
+ DNG_REQUIRE (fParams.fParams.size () == dng_vignette_radial_params::kNumTerms,
+ "Bad number of vignette opcode coefficients.");
+
+ real64 sum = 0.0;
+
+ const std::vector<real64> &v = fParams.fParams;
+
+ for (std::vector<real64>::const_reverse_iterator i = v.rbegin (); i != v.rend (); i++)
+ {
+ sum = x * ((*i) + sum);
+ }
+
+ sum += 1.0;
+
+ return sum;
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+dng_opcode_FixVignetteRadial::dng_opcode_FixVignetteRadial (const dng_vignette_radial_params &params,
+ uint32 flags)
+
+ : dng_inplace_opcode (dngOpcode_FixVignetteRadial,
+ dngVersion_1_3_0_0,
+ flags)
+
+ , fParams (params)
+
+ , fImagePlanes (1)
+
+ , fSrcOriginH (0)
+ , fSrcOriginV (0)
+
+ , fSrcStepH (0)
+ , fSrcStepV (0)
+
+ , fTableInputBits (0)
+ , fTableOutputBits (0)
+
+ , fGainTable ()
+
+ {
+
+ if (!params.IsValid ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_FixVignetteRadial::dng_opcode_FixVignetteRadial (dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_FixVignetteRadial,
+ stream,
+ "FixVignetteRadial")
+
+ , fParams ()
+
+ , fImagePlanes (1)
+
+ , fSrcOriginH (0)
+ , fSrcOriginV (0)
+
+ , fSrcStepH (0)
+ , fSrcStepV (0)
+
+ , fTableInputBits (0)
+ , fTableOutputBits (0)
+
+ , fGainTable ()
+
+ {
+
+ // Grab the size in bytes.
+
+ const uint32 bytes = stream.Get_uint32 ();
+
+ // Verify the size.
+
+ if (bytes != ParamBytes ())
+ {
+ ThrowBadFormat ();
+ }
+
+ // Read vignette coefficients.
+
+ fParams.fParams = std::vector<real64> (dng_vignette_radial_params::kNumTerms);
+
+ for (uint32 i = 0; i < dng_vignette_radial_params::kNumTerms; i++)
+ {
+ fParams.fParams [i] = stream.Get_real64 ();
+ }
+
+ // Read the image center.
+
+ fParams.fCenter.h = stream.Get_real64 ();
+ fParams.fCenter.v = stream.Get_real64 ();
+
+ // Debug.
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ fParams.Dump ();
+
+ }
+
+ #endif
+
+ if (!fParams.IsValid ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode_FixVignetteRadial::IsNOP () const
+ {
+
+ return fParams.IsNOP ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode_FixVignetteRadial::IsValidForNegative (const dng_negative & /* negative */) const
+ {
+
+ return fParams.IsValid ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixVignetteRadial::PutData (dng_stream &stream) const
+ {
+
+ const uint32 bytes = ParamBytes ();
+
+ stream.Put_uint32 (bytes);
+
+ DNG_REQUIRE (fParams.fParams.size () == dng_vignette_radial_params::kNumTerms,
+ "Bad number of vignette opcode coefficients.");
+
+ for (uint32 i = 0; i < dng_vignette_radial_params::kNumTerms; i++)
+ {
+ stream.Put_real64 (fParams.fParams [i]);
+ }
+
+ stream.Put_real64 (fParams.fCenter.h);
+ stream.Put_real64 (fParams.fCenter.v);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixVignetteRadial::Prepare (dng_negative &negative,
+ uint32 threadCount,
+ const dng_point &tileSize,
+ const dng_rect &imageBounds,
+ uint32 imagePlanes,
+ uint32 bufferPixelType,
+ dng_memory_allocator &allocator)
+ {
+
+ // This opcode is restricted to 32-bit images.
+
+ if (bufferPixelType != ttFloat)
+ {
+ ThrowBadFormat ();
+ }
+
+ // Sanity check number of planes.
+
+ DNG_ASSERT (imagePlanes >= 1 && imagePlanes <= kMaxColorPlanes,
+ "Bad number of planes.");
+
+ if (imagePlanes < 1 || imagePlanes > kMaxColorPlanes)
+ {
+ ThrowProgramError ();
+ }
+
+ fImagePlanes = imagePlanes;
+
+ // Set the vignette correction curve.
+
+ const dng_vignette_radial_function curve (fParams);
+
+ // Grab the destination image area.
+
+ const dng_rect_real64 bounds (imageBounds);
+
+ // Determine the optical center and maximum radius in pixel coordinates.
+
+ const dng_point_real64 centerPixel (Lerp_real64 (bounds.t,
+ bounds.b,
+ fParams.fCenter.v),
+
+ Lerp_real64 (bounds.l,
+ bounds.r,
+ fParams.fCenter.h));
+
+ const real64 pixelScaleV = 1.0 / negative.PixelAspectRatio ();
+
+ const real64 maxRadius = hypot (Max_real64 (Abs_real64 (centerPixel.v - bounds.t),
+ Abs_real64 (centerPixel.v - bounds.b)) * pixelScaleV,
+
+ Max_real64 (Abs_real64 (centerPixel.h - bounds.l),
+ Abs_real64 (centerPixel.h - bounds.r)));
+
+ const dng_point_real64 radius (maxRadius,
+ maxRadius);
+
+ // Find origin and scale.
+
+ const real64 pixelScaleH = 1.0;
+
+ fSrcOriginH = Real64ToFixed64 (-centerPixel.h * pixelScaleH / radius.h);
+ fSrcOriginV = Real64ToFixed64 (-centerPixel.v * pixelScaleV / radius.v);
+
+ fSrcStepH = Real64ToFixed64 (pixelScaleH / radius.h);
+ fSrcStepV = Real64ToFixed64 (pixelScaleV / radius.v);
+
+ // Adjust for pixel centers.
+
+ fSrcOriginH += fSrcStepH >> 1;
+ fSrcOriginV += fSrcStepV >> 1;
+
+ // Evaluate 32-bit vignette correction table.
+
+ dng_1d_table table32;
+
+ table32.Initialize (allocator,
+ curve,
+ false);
+
+ // Find maximum scale factor.
+
+ const real64 maxScale = Max_real32 (table32.Interpolate (0.0f),
+ table32.Interpolate (1.0f));
+
+ // Find table input bits.
+
+ fTableInputBits = 16;
+
+ // Find table output bits.
+
+ fTableOutputBits = 15;
+
+ while ((1 << fTableOutputBits) * maxScale > 65535.0)
+ {
+ fTableOutputBits--;
+ }
+
+ // Allocate 16-bit scale table.
+
+ const uint32 tableEntries = (1 << fTableInputBits) + 1;
+
+ fGainTable.Reset (allocator.Allocate (tableEntries * (uint32) sizeof (uint16)));
+
+ uint16 *table16 = fGainTable->Buffer_uint16 ();
+
+ // Interpolate 32-bit table into 16-bit table.
+
+ const real32 scale0 = 1.0f / (1 << fTableInputBits );
+ const real32 scale1 = 1.0f * (1 << fTableOutputBits);
+
+ for (uint32 index = 0; index < tableEntries; index++)
+ {
+
+ real32 x = index * scale0;
+
+ real32 y = table32.Interpolate (x) * scale1;
+
+ table16 [index] = (uint16) Round_uint32 (y);
+
+ }
+
+ // Prepare vignette mask buffers.
+
+ {
+
+ const uint32 pixelType = ttShort;
+ const uint32 pixelSize = TagTypeSize (pixelType);
+
+ const uint32 bufferSize = tileSize.v *
+ RoundUpForPixelSize (tileSize.h, pixelSize) *
+ pixelSize *
+ imagePlanes;
+
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
+ fMaskBuffers [threadIndex] . Reset (allocator.Allocate (bufferSize));
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_FixVignetteRadial::ProcessArea (dng_negative & /* negative */,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ // Setup mask pixel buffer.
+
+ dng_pixel_buffer maskPixelBuffer;
+
+ maskPixelBuffer.fArea = dstArea;
+
+ maskPixelBuffer.fPlane = 0;
+ maskPixelBuffer.fPlanes = fImagePlanes;
+
+ maskPixelBuffer.fPixelType = ttShort;
+ maskPixelBuffer.fPixelSize = TagTypeSize (maskPixelBuffer.fPixelType);
+
+ maskPixelBuffer.fPlaneStep = RoundUpForPixelSize (dstArea.W (),
+ maskPixelBuffer.fPixelSize);
+
+ maskPixelBuffer.fRowStep = maskPixelBuffer.fPlaneStep * maskPixelBuffer.fPlanes;
+
+ maskPixelBuffer.fData = fMaskBuffers [threadIndex]->Buffer ();
+
+ // Compute mask.
+
+ DoVignetteMask16 (maskPixelBuffer.DirtyPixel_uint16 (dstArea.t, dstArea.l),
+ dstArea.H (),
+ dstArea.W (),
+ maskPixelBuffer.RowStep (),
+ fSrcOriginH + fSrcStepH * dstArea.l,
+ fSrcOriginV + fSrcStepV * dstArea.t,
+ fSrcStepH,
+ fSrcStepV,
+ fTableInputBits,
+ fGainTable->Buffer_uint16 ());
+
+ // Apply mask.
+
+ DoVignette32 (buffer.DirtyPixel_real32 (dstArea.t, dstArea.l),
+ maskPixelBuffer.ConstPixel_uint16 (dstArea.t, dstArea.l),
+ dstArea.H (),
+ dstArea.W (),
+ fImagePlanes,
+ buffer.RowStep (),
+ buffer.PlaneStep (),
+ maskPixelBuffer.RowStep (),
+ fTableOutputBits);
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_FixVignetteRadial::ParamBytes ()
+ {
+
+ const uint32 N = dng_vignette_radial_params::kNumTerms;
+
+ return ((N * sizeof (real64)) + // Vignette coefficients.
+ (2 * sizeof (real64))); // Optical center.
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_lens_correction.h b/gpr/source/lib/dng_sdk/dng_lens_correction.h
new file mode 100644
index 0000000..ae1ca6b
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_lens_correction.h
@@ -0,0 +1,638 @@
+/*****************************************************************************/
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_lens_correction.h#2 $ */
+/* $DateTime: 2012/08/02 06:09:06 $ */
+/* $Change: 841096 $ */
+/* $Author: erichan $ */
+
+/** \file
+ * Opcodes to fix lens aberrations such as geometric distortion, lateral chromatic
+ * aberration, and vignetting (peripheral illumination falloff).
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_lens_correction__
+#define __dng_lens_correction__
+
+/*****************************************************************************/
+
+#include "dng_1d_function.h"
+#include "dng_matrix.h"
+#include "dng_opcodes.h"
+#include "dng_pixel_buffer.h"
+#include "dng_point.h"
+#include "dng_resample.h"
+#include "dng_sdk_limits.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+/// \brief Abstract base class holding common warp opcode parameters (e.g.,
+/// number of planes, optical center) and common warp routines.
+
+class dng_warp_params
+ {
+
+ public:
+
+ // Number of planes to be warped. Must be either 1 or equal to the
+ // number of planes of the image to be processed. If set to 1, then a
+ // single set of warp parameters applies to all planes of the image.
+ // fPlanes must be at least 1 and no greater than kMaxColorPlanes (see
+ // dng_sdk_limits.h).
+
+ uint32 fPlanes;
+
+ // The optical center of the lens in normalized [0,1] coordinates with
+ // respect to the image's active area. For example, a value of (0.5,
+ // 0.5) indicates that the optical center of the lens is at the center
+ // of the image's active area. A normalized radius of 1.0 corresponds to
+ // the distance from fCenter to the farthest corner of the image's
+ // active area. Each component of fCenter must lie in the range [0,1].
+
+ dng_point_real64 fCenter;
+
+ public:
+
+ /// Create empty (invalid) warp parameters.
+
+ dng_warp_params ();
+
+ /// Create warp parameters with specified number of planes and image
+ /// center.
+ ///
+ /// \param planes The number of planes of parameters specified: It must
+ /// be either 1 or equal to the number of planes of the image to be
+ /// processed.
+ ///
+ /// \param fCenter The image center in relative coordinates.
+
+ dng_warp_params (uint32 planes,
+ const dng_point_real64 &fCenter);
+
+ virtual ~dng_warp_params ();
+
+ /// Is the entire correction a NOP for all planes?
+
+ virtual bool IsNOPAll () const;
+
+ /// Is the entire correction a NOP for the specified plane?
+
+ virtual bool IsNOP (uint32 plane) const;
+
+ /// Is the radial correction a NOP for all planes?
+
+ virtual bool IsRadNOPAll () const;
+
+ /// Is the radial correction a NOP for the specified plane?
+
+ virtual bool IsRadNOP (uint32 plane) const;
+
+ /// Is the tangential correction a NOP for all planes?
+
+ virtual bool IsTanNOPAll () const;
+
+ /// Is the tangential correction a NOP for the specified plane?
+
+ virtual bool IsTanNOP (uint32 plane) const;
+
+ /// Do these warp params appear valid?
+
+ virtual bool IsValid () const;
+
+ /// Are these warp params valid for the specified negative?
+
+ virtual bool IsValidForNegative (const dng_negative &negative) const;
+
+ /// Propagate warp parameters from first plane to all other planes.
+
+ virtual void PropagateToAllPlanes (uint32 totalPlanes) = 0;
+
+ /// Evaluate the 1D radial warp function for the specified plane.
+ /// Parameter r is the destination (i.e., corrected) normalized radius,
+ /// i.e., the normalized Euclidean distance between a corrected pixel
+ /// position and the optical center in the image. r lies in the range
+ /// [0,1]. The returned result is non-negative.
+
+ virtual real64 Evaluate (uint32 plane,
+ real64 r) const = 0;
+
+ /// Compute and return the inverse of Evaluate () above. The base
+ /// implementation uses Newton's method to perform the inversion.
+ /// Parameter r is the source (i.e., uncorrected) normalized radius,
+ /// i.e., normalized Euclidean distance between a corrected pixel
+ /// position and the optical center in the image. Both r and the
+ /// computed result are non-negative.
+
+ virtual real64 EvaluateInverse (uint32 plane,
+ real64 r) const;
+
+ /// Evaluate the 1D radial warp ratio function for the specified plane.
+ /// Parameter r2 is the square of the destination (i.e., corrected)
+ /// normalized radius, i.e., the square of the normalized Euclidean
+ /// distance between a corrected pixel position and the optical center
+ /// in the image. r2 must lie in the range [0,1]. Note that this is
+ /// different than the Evaluate () function, above, in that the argument
+ /// to EvaluateRatio () is the square of the radius, not the radius
+ /// itself. The returned result is non-negative. Mathematically,
+ /// EvaluateRatio (r * r) is the same as Evaluate (r) / r.
+
+ virtual real64 EvaluateRatio (uint32 plane,
+ real64 r2) const = 0;
+
+ /// Evaluate the 2D tangential warp for the specified plane. Parameter
+ /// r2 is the square of the destination (i.e., corrected) normalized
+ /// radius, i.e., the square of the normalized Euclidean distance
+ /// between a corrected pixel position P and the optical center in the
+ /// image. r2 must lie in the range [0,1]. diff contains the vertical
+ /// and horizontal Euclidean distances (in pixels) between P and the
+ /// optical center. diff2 contains the squares of the vertical and
+ /// horizontal Euclidean distances (in pixels) between P and the optical
+ /// center. The returned result is the tangential warp offset, measured
+ /// in pixels.
+
+ virtual dng_point_real64 EvaluateTangential (uint32 plane,
+ real64 r2,
+ const dng_point_real64 &diff,
+ const dng_point_real64 &diff2) const = 0;
+
+ /// Evaluate the 2D tangential warp for the specified plane. diff
+ /// contains the vertical and horizontal Euclidean distances (in pixels)
+ /// between the destination (i.e., corrected) pixel position and the
+ /// optical center in the image. The returned result is the tangential
+ /// warp offset, measured in pixels.
+
+ dng_point_real64 EvaluateTangential2 (uint32 plane,
+ const dng_point_real64 &diff) const;
+
+ /// Evaluate the 2D tangential warp for the specified plane. Parameter
+ /// r2 is the square of the destination (i.e., corrected) normalized
+ /// radius, i.e., the square of the normalized Euclidean distance
+ /// between a corrected pixel position P and the optical center in the
+ /// image. r2 must lie in the range [0,1]. diff contains the vertical
+ /// and horizontal Euclidean distances (in pixels) between P and the
+ /// optical center. The returned result is the tangential warp offset,
+ /// measured in pixels.
+
+ dng_point_real64 EvaluateTangential3 (uint32 plane,
+ real64 r2,
+ const dng_point_real64 &diff) const;
+
+ /// Compute and return the maximum warped radius gap. Let D be a
+ /// rectangle in a destination (corrected) image. Let rDstFar and
+ /// rDstNear be the farthest and nearest points to the image center,
+ /// respectively. Then the specified parameter maxDstGap is the
+ /// Euclidean distance between rDstFar and rDstNear. Warp D through this
+ /// warp function to a closed and bounded (generally not rectangular)
+ /// region S. Let rSrcfar and rSrcNear be the farthest and nearest
+ /// points to the image center, respectively. This routine returns a
+ /// value that is at least (rSrcFar - rSrcNear).
+
+ virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const = 0;
+
+ /// Compute and return the maximum warped tangential gap. minDst is the
+ /// top-left pixel of the image in normalized pixel coordinates. maxDst
+ /// is the bottom-right pixel of the image in normalized pixel
+ /// coordinates. MaxSrcTanGap () computes the maximum absolute shift in
+ /// normalized pixels in the horizontal and vertical directions that can
+ /// occur as a result of the tangential warp.
+
+ virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst,
+ dng_point_real64 maxDst) const = 0;
+
+ /// Debug parameters.
+
+ virtual void Dump () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Warp parameters for pinhole perspective rectilinear (not fisheye)
+/// camera model. Supports radial and tangential (decentering) distortion
+/// correction parameters.
+///
+/// Note the restrictions described below.
+
+class dng_warp_params_rectilinear: public dng_warp_params
+ {
+
+ public:
+
+ // Radial and tangential polynomial coefficients. These define a warp
+ // from corrected pixel coordinates (xDst, yDst) to uncorrected pixel
+ // coordinates (xSrc, ySrc) for each plane P as follows:
+ //
+ // Let kr0 = fRadParams [P][0]
+ // kr1 = fRadParams [P][1]
+ // kr2 = fRadParams [P][2]
+ // kr3 = fRadParams [P][3]
+ //
+ // kt0 = fTanParams [P][0]
+ // kt1 = fTanParams [P][1]
+ //
+ // Let (xCenter, yCenter) be the optical image center (see fCenter,
+ // below) expressed in pixel coordinates. Let maxDist be the Euclidean
+ // distance (in pixels) from (xCenter, yCenter) to the farthest image
+ // corner.
+ //
+ // First, compute the normalized distance of the corrected pixel
+ // position (xDst, yDst) from the image center:
+ //
+ // dx = (xDst - xCenter) / maxDist
+ // dy = (yDst - yCenter) / maxDist
+ //
+ // r^2 = dx^2 + dy^2
+ //
+ // Compute the radial correction term:
+ //
+ // ratio = kr0 + (kr1 * r^2) + (kr2 * r^4) + (kr3 * r^6)
+ //
+ // dxRad = dx * ratio
+ // dyRad = dy * ratio
+ //
+ // Compute the tangential correction term:
+ //
+ // dxTan = (2 * kt0 * dx * dy) + kt1 * (r^2 + 2 * dx^2)
+ // dyTan = (2 * kt1 * dx * dy) + kt0 * (r^2 + 2 * dy^2)
+ //
+ // Compute the uncorrected pixel position (xSrc, ySrc):
+ //
+ // xSrc = xCenter + (dxRad + dxTan) * maxDist
+ // ySrc = yCenter + (dyRad + dyTan) * maxDist
+ //
+ // Mathematical definitions and restrictions:
+ //
+ // Let { xSrc, ySrc } = f (xDst, yDst) be the warp function defined
+ // above.
+ //
+ // Let xSrc = fx (xDst, yDst) be the x-component of the warp function.
+ // Let ySrc = fy (xDst, yDst) be the y-component of the warp function.
+ //
+ // f (x, y) must be an invertible function.
+ //
+ // fx (x, y) must be an increasing function of x.
+ // fy (x, y) must be an increasing function of x.
+ //
+ // The parameters kr0, kr1, kr2, and kr3 must define an increasing
+ // radial warp function. Specifically, let w (r) be the radial warp
+ // function:
+ //
+ // w (r) = (kr0 * r) + (kr1 * r^3) + (kr2 * r^5) + (kr3 * r^7).
+ //
+ // w (r) must be an increasing function.
+
+ dng_vector fRadParams [kMaxColorPlanes];
+ dng_vector fTanParams [kMaxColorPlanes];
+
+ public:
+
+ /// Create empty (invalid) rectilinear warp parameters.
+
+ dng_warp_params_rectilinear ();
+
+ /// Create rectilinear warp parameters with the specified number of
+ /// planes, radial component terms, tangential component terms, and
+ /// image center in relative coordinates.
+
+ dng_warp_params_rectilinear (uint32 planes,
+ const dng_vector radParams [],
+ const dng_vector tanParams [],
+ const dng_point_real64 &fCenter);
+
+ virtual ~dng_warp_params_rectilinear ();
+
+ // Overridden methods.
+
+ virtual bool IsRadNOP (uint32 plane) const;
+
+ virtual bool IsTanNOP (uint32 plane) const;
+
+ virtual bool IsValid () const;
+
+ virtual void PropagateToAllPlanes (uint32 totalPlanes);
+
+ virtual real64 Evaluate (uint32 plane,
+ real64 r) const;
+
+ virtual real64 EvaluateRatio (uint32 plane,
+ real64 r2) const;
+
+ virtual dng_point_real64 EvaluateTangential (uint32 plane,
+ real64 r2,
+ const dng_point_real64 &diff,
+ const dng_point_real64 &diff2) const;
+
+ virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const;
+
+ virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst,
+ dng_point_real64 maxDst) const;
+
+ virtual void Dump () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Warp parameters for fisheye camera model (radial component only).
+/// Note the restrictions described below.
+
+class dng_warp_params_fisheye: public dng_warp_params
+ {
+
+ public:
+
+ // Radial warp coefficients. These define a warp from corrected pixel
+ // coordinates (xDst, yDst) to uncorrected pixel coordinates (xSrc,
+ // ySrc) for each plane P as follows:
+ //
+ // Let kr0 = fRadParams [P][0]
+ // kr1 = fRadParams [P][1]
+ // kr2 = fRadParams [P][2]
+ // kr3 = fRadParams [P][3]
+ //
+ // Let (xCenter, yCenter) be the optical image center (see fCenter,
+ // below) expressed in pixel coordinates. Let maxDist be the Euclidean
+ // distance (in pixels) from (xCenter, yCenter) to the farthest image
+ // corner.
+ //
+ // First, compute the normalized distance of the corrected pixel
+ // position (xDst, yDst) from the image center:
+ //
+ // dx = (xDst - xCenter) / maxDist
+ // dy = (yDst - yCenter) / maxDist
+ //
+ // r = sqrt (dx^2 + dy^2)
+ //
+ // Compute the radial correction term:
+ //
+ // t = atan (r)
+ //
+ // rWarp = (kr0 * t) + (kr1 * t^3) + (kr2 * t^5) + (kr3 * t^7)
+ //
+ // ratio = rWarp / r
+ //
+ // dxRad = dx * ratio
+ // dyRad = dy * ratio
+ //
+ // Compute the uncorrected pixel position (xSrc, ySrc):
+ //
+ // xSrc = xCenter + (dxRad * maxDist)
+ // ySrc = yCenter + (dyRad * maxDist)
+ //
+ // The parameters kr0, kr1, kr2, and kr3 must define an increasing
+ // radial warp function. Specifically, let w (r) be the radial warp
+ // function:
+ //
+ // t = atan (r)
+ //
+ // w (r) = (kr0 * t) + (kr1 * t^3) + (kr2 * t^5) + (kr3 * t^7).
+ //
+ // w (r) must be an increasing function.
+
+ dng_vector fRadParams [kMaxColorPlanes];
+
+ public:
+
+ /// Create empty (invalid) fisheye warp parameters.
+
+ dng_warp_params_fisheye ();
+
+ /// Create rectilinear warp parameters with the specified number of
+ /// planes, radial component terms, and image center in relative
+ /// coordinates.
+
+ dng_warp_params_fisheye (uint32 planes,
+ const dng_vector radParams [],
+ const dng_point_real64 &fCenter);
+
+ virtual ~dng_warp_params_fisheye ();
+
+ // Overridden methods.
+
+ virtual bool IsRadNOP (uint32 plane) const;
+
+ virtual bool IsTanNOP (uint32 plane) const;
+
+ virtual bool IsValid () const;
+
+ virtual void PropagateToAllPlanes (uint32 totalPlanes);
+
+ virtual real64 Evaluate (uint32 plane,
+ real64 r) const;
+
+ virtual real64 EvaluateRatio (uint32 plane,
+ real64 r2) const;
+
+ virtual dng_point_real64 EvaluateTangential (uint32 plane,
+ real64 r2,
+ const dng_point_real64 &diff,
+ const dng_point_real64 &diff2) const;
+
+ virtual real64 MaxSrcRadiusGap (real64 maxDstGap) const;
+
+ virtual dng_point_real64 MaxSrcTanGap (dng_point_real64 minDst,
+ dng_point_real64 maxDst) const;
+
+ virtual void Dump () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Warp opcode for pinhole perspective (rectilinear) camera model.
+
+class dng_opcode_WarpRectilinear: public dng_opcode
+ {
+
+ protected:
+
+ dng_warp_params_rectilinear fWarpParams;
+
+ public:
+
+ dng_opcode_WarpRectilinear (const dng_warp_params_rectilinear &params,
+ uint32 flags);
+
+ explicit dng_opcode_WarpRectilinear (dng_stream &stream);
+
+ // Overridden methods.
+
+ virtual bool IsNOP () const;
+
+ virtual bool IsValidForNegative (const dng_negative &negative) const;
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ protected:
+
+ static uint32 ParamBytes (uint32 planes);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Warp opcode for fisheye camera model.
+
+class dng_opcode_WarpFisheye: public dng_opcode
+ {
+
+ protected:
+
+ dng_warp_params_fisheye fWarpParams;
+
+ public:
+
+ dng_opcode_WarpFisheye (const dng_warp_params_fisheye &params,
+ uint32 flags);
+
+ explicit dng_opcode_WarpFisheye (dng_stream &stream);
+
+ // Overridden methods.
+
+ virtual bool IsNOP () const;
+
+ virtual bool IsValidForNegative (const dng_negative &negative) const;
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ protected:
+
+ static uint32 ParamBytes (uint32 planes);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Radially-symmetric vignette (peripheral illuminational falloff)
+/// correction parameters.
+
+class dng_vignette_radial_params
+ {
+
+ public:
+
+ static const uint32 kNumTerms = 5;
+
+ public:
+
+ // Let v be an uncorrected pixel value of a pixel p in linear space.
+ //
+ // Let r be the Euclidean distance between p and the optical center.
+ //
+ // Compute corrected pixel value v' = v * g, where g is the gain.
+ //
+ // Let k0 = fParams [0]
+ // Let k1 = fParams [1]
+ // Let k2 = fParams [2]
+ // Let k3 = fParams [3]
+ // Let k4 = fParams [4]
+ //
+ // Gain g = 1 + (k0 * r^2) + (k1 * r^4) + (k2 * r^6) + (k3 * r^8) + (k4 * r^10)
+
+ std::vector<real64> fParams;
+
+ dng_point_real64 fCenter;
+
+ public:
+
+ dng_vignette_radial_params ();
+
+ dng_vignette_radial_params (const std::vector<real64> &params,
+ const dng_point_real64 &center);
+
+ bool IsNOP () const;
+
+ bool IsValid () const;
+
+ // For debugging.
+
+ void Dump () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Radially-symmetric lens vignette correction opcode.
+
+class dng_opcode_FixVignetteRadial: public dng_inplace_opcode
+ {
+
+ protected:
+
+ dng_vignette_radial_params fParams;
+
+ uint32 fImagePlanes;
+
+ int64 fSrcOriginH;
+ int64 fSrcOriginV;
+
+ int64 fSrcStepH;
+ int64 fSrcStepV;
+
+ uint32 fTableInputBits;
+ uint32 fTableOutputBits;
+
+ AutoPtr<dng_memory_block> fGainTable;
+
+ AutoPtr<dng_memory_block> fMaskBuffers [kMaxMPThreads];
+
+ public:
+
+ dng_opcode_FixVignetteRadial (const dng_vignette_radial_params &params,
+ uint32 flags);
+
+ explicit dng_opcode_FixVignetteRadial (dng_stream &stream);
+
+ virtual bool IsNOP () const;
+
+ virtual bool IsValidForNegative (const dng_negative &) const;
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 /* imagePixelType */)
+ {
+ return ttFloat;
+ }
+
+ virtual void Prepare (dng_negative &negative,
+ uint32 threadCount,
+ const dng_point &tileSize,
+ const dng_rect &imageBounds,
+ uint32 imagePlanes,
+ uint32 bufferPixelType,
+ dng_memory_allocator &allocator);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ protected:
+
+ static uint32 ParamBytes ();
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_linearization_info.cpp b/gpr/source/lib/dng_sdk/dng_linearization_info.cpp
new file mode 100644
index 0000000..1c1309b
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_linearization_info.cpp
@@ -0,0 +1,1517 @@
+/*****************************************************************************/
+// Copyright 2006-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_linearization_info.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_linearization_info.h"
+
+#include "dng_area_task.h"
+#include "dng_exceptions.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_info.h"
+#include "dng_negative.h"
+#include "dng_pixel_buffer.h"
+#include "dng_tag_types.h"
+#include "dng_tile_iterator.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+class dng_linearize_plane
+ {
+
+ private:
+
+ const dng_image & fSrcImage;
+ dng_image & fDstImage;
+
+ uint32 fPlane;
+
+ dng_rect fActiveArea;
+
+ uint32 fSrcPixelType;
+ uint32 fDstPixelType;
+
+ bool fReal32;
+
+ real32 fScale;
+
+ AutoPtr<dng_memory_block> fScale_buffer;
+
+ uint32 fBlack_2D_rows;
+ uint32 fBlack_2D_cols;
+
+ AutoPtr<dng_memory_block> fBlack_2D_buffer;
+
+ uint32 fBlack_1D_rows;
+
+ AutoPtr<dng_memory_block> fBlack_1D_buffer;
+
+ public:
+
+ dng_linearize_plane (dng_host &host,
+ dng_linearization_info &info,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 plane);
+
+ ~dng_linearize_plane ();
+
+ void Process (const dng_rect &tile);
+
+ };
+
+/*****************************************************************************/
+
+dng_linearize_plane::dng_linearize_plane (dng_host &host,
+ dng_linearization_info &info,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 plane)
+
+ : fSrcImage (srcImage)
+ , fDstImage (dstImage)
+ , fPlane (plane)
+ , fActiveArea (info.fActiveArea)
+ , fSrcPixelType (srcImage.PixelType ())
+ , fDstPixelType (dstImage.PixelType ())
+ , fReal32 (false)
+ , fScale (0.0f)
+ , fScale_buffer ()
+ , fBlack_2D_rows (0)
+ , fBlack_2D_cols (0)
+ , fBlack_2D_buffer ()
+ , fBlack_1D_rows (0)
+ , fBlack_1D_buffer ()
+
+ {
+
+ uint32 j;
+ uint32 k;
+
+ // Make sure the source pixel type is supported.
+
+ if (fSrcPixelType != ttByte &&
+ fSrcPixelType != ttShort &&
+ fSrcPixelType != ttLong &&
+ fSrcPixelType != ttFloat)
+ {
+
+ DNG_REPORT ("Unsupported source pixel type");
+
+ ThrowProgramError ();
+
+ }
+
+ if (fDstPixelType != ttShort &&
+ fDstPixelType != ttFloat)
+ {
+
+ DNG_REPORT ("Unsupported destination pixel type");
+
+ ThrowProgramError ();
+
+ }
+
+ if (fSrcPixelType == ttFloat &&
+ fDstPixelType != ttFloat)
+ {
+
+ DNG_REPORT ("Cannot convert floating point stage1 to non-floating stage2");
+
+ ThrowProgramError ();
+
+ }
+
+ // Are we using floating point math?
+
+ fReal32 = (fSrcPixelType == ttLong ||
+ fDstPixelType == ttFloat);
+
+ // Find the scale for this plane.
+
+ real64 maxBlack = info.MaxBlackLevel (plane);
+
+ real64 minRange = info.fWhiteLevel [plane] - maxBlack;
+
+ if (minRange <= 0.0)
+ {
+ ThrowBadFormat ();
+ }
+
+ real64 scale = 1.0 / minRange;
+
+ fScale = (real32) scale;
+
+ // Calculate two-dimensional black pattern, if any.
+
+ if (info.fBlackDeltaH.Get ())
+ {
+
+ fBlack_2D_rows = info.fBlackLevelRepeatRows;
+ fBlack_2D_cols = info.fActiveArea.W ();
+
+ }
+
+ else if (info.fBlackLevelRepeatCols > 1)
+ {
+
+ fBlack_2D_rows = info.fBlackLevelRepeatRows;
+ fBlack_2D_cols = info.fBlackLevelRepeatCols;
+
+ }
+
+ if (fBlack_2D_rows)
+ {
+
+ fBlack_2D_buffer.Reset (host.Allocate (fBlack_2D_rows * fBlack_2D_cols * 4));
+
+ for (j = 0; j < fBlack_2D_rows; j++)
+ {
+
+ for (k = 0; k < fBlack_2D_cols; k++)
+ {
+
+ real64 x = info.fBlackLevel [j]
+ [k % info.fBlackLevelRepeatCols]
+ [plane];
+
+ if (info.fBlackDeltaH.Get ())
+ {
+
+ x += info.fBlackDeltaH->Buffer_real64 () [k];
+
+ }
+
+ x *= scale;
+
+ uint32 index = j * fBlack_2D_cols + k;
+
+ if (fReal32)
+ {
+
+ fBlack_2D_buffer->Buffer_real32 () [index] = (real32) x;
+
+ }
+
+ else
+ {
+
+ x *= 0x0FFFF * 256.0;
+
+ int32 y = Round_int32 (x);
+
+ fBlack_2D_buffer->Buffer_int32 () [index] = y;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Calculate one-dimensional (per row) black pattern, if any.
+
+ if (info.fBlackDeltaV.Get ())
+ {
+
+ fBlack_1D_rows = info.fActiveArea.H ();
+
+ }
+
+ else if (fBlack_2D_rows == 0 &&
+ (info.fBlackLevelRepeatRows > 1 || fSrcPixelType != ttShort))
+ {
+
+ fBlack_1D_rows = info.fBlackLevelRepeatRows;
+
+ }
+
+ if (fBlack_1D_rows)
+ {
+
+ fBlack_1D_buffer.Reset (host.Allocate (fBlack_1D_rows * 4));
+
+ bool allZero = true;
+
+ for (j = 0; j < fBlack_1D_rows; j++)
+ {
+
+ real64 x = 0.0;
+
+ if (fBlack_2D_rows == 0)
+ {
+
+ x = info.fBlackLevel [j % info.fBlackLevelRepeatRows]
+ [0]
+ [plane];
+
+ }
+
+ if (info.fBlackDeltaV.Get ())
+ {
+
+ x += info.fBlackDeltaV->Buffer_real64 () [j];
+
+ }
+
+ allZero = allZero && (x == 0.0);
+
+ x *= scale;
+
+ if (fReal32)
+ {
+
+ fBlack_1D_buffer->Buffer_real32 () [j] = (real32) x;
+
+ }
+
+ else
+ {
+
+ x *= 0x0FFFF * 256.0;
+
+ int32 y = Round_int32 (x);
+
+ fBlack_1D_buffer->Buffer_int32 () [j] = y;
+
+ }
+
+ }
+
+ if (allZero)
+ {
+
+ fBlack_1D_rows = 0;
+
+ fBlack_1D_buffer.Reset ();
+
+ }
+
+ }
+
+ // Calculate scale table, if any.
+
+ if (fSrcPixelType != ttLong &&
+ fSrcPixelType != ttFloat)
+ {
+
+ // Find linearization table, if any.
+
+ uint16 *lut = NULL;
+
+ uint32 lutEntries = 0;
+
+ if (info.fLinearizationTable.Get ())
+ {
+
+ lut = info.fLinearizationTable->Buffer_uint16 ();
+
+ lutEntries = info.fLinearizationTable->LogicalSize () >> 1;
+
+ }
+
+ // If the black level does not vary from pixel to pixel, then
+ // the entire process can be a single LUT.
+
+ if (fBlack_1D_rows == 0 &&
+ fBlack_2D_rows == 0)
+ {
+
+ fScale_buffer.Reset (host.Allocate (0x10000 *
+ TagTypeSize (fDstPixelType)));
+
+ for (j = 0; j < 0x10000; j++)
+ {
+
+ uint32 x = j;
+
+ // Apply linearization table, if any.
+
+ if (lut)
+ {
+
+ x = Min_uint32 (x, lutEntries - 1);
+
+ x = lut [x];
+
+ }
+
+ // Subtract constant black level.
+
+ real64 y = x - info.fBlackLevel [0] [0] [plane];
+
+ // Apply scale.
+
+ y *= scale;
+
+ // We can burn in the clipping also.
+
+ y = Pin_real64 (0.0, y, 1.0);
+
+ // Store output value in table.
+
+ if (fDstPixelType == ttShort)
+ {
+
+ uint16 z = (uint16) Round_uint32 (y * 0x0FFFF);
+
+ fScale_buffer->Buffer_uint16 () [j] = z;
+
+ }
+
+ else
+ {
+
+ fScale_buffer->Buffer_real32 () [j] = (real32) y;
+
+ }
+
+ }
+
+ }
+
+ // Else we only do the scaling operation in the scale table.
+
+ else
+ {
+
+ fScale_buffer.Reset (host.Allocate (0x10000 * 4));
+
+ for (j = 0; j < 0x10000; j++)
+ {
+
+ uint32 x = j;
+
+ // Apply linearization table, if any.
+
+ if (lut)
+ {
+
+ x = Min_uint32 (x, lutEntries - 1);
+
+ x = lut [x];
+
+ }
+
+ // Apply scale.
+
+ real64 y = x * scale;
+
+ // Store output value in table.
+
+ if (fReal32)
+ {
+
+ fScale_buffer->Buffer_real32 () [j] = (real32) y;
+
+ }
+
+ else
+ {
+
+ int32 z = Round_int32 (y * 0x0FFFF * 256.0);
+
+ fScale_buffer->Buffer_int32 () [j] = z;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_linearize_plane::~dng_linearize_plane ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_linearize_plane::Process (const dng_rect &srcTile)
+ {
+
+ // Process tile.
+
+ dng_rect dstTile = srcTile - fActiveArea.TL ();
+
+ dng_const_tile_buffer srcBuffer (fSrcImage, srcTile);
+ dng_dirty_tile_buffer dstBuffer (fDstImage, dstTile);
+
+ int32 sStep = srcBuffer.fColStep;
+ int32 dStep = dstBuffer.fColStep;
+
+ uint32 count = srcTile.W ();
+
+ uint32 dstCol = dstTile.l;
+
+ uint32 rows = srcTile.H ();
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint32 dstRow = dstTile.t + row;
+
+ const void *sPtr = srcBuffer.ConstPixel (srcTile.t + row,
+ srcTile.l,
+ fPlane);
+
+ void *dPtr = dstBuffer.DirtyPixel (dstRow,
+ dstCol,
+ fPlane);
+
+ // Floating point source case.
+
+ if (fSrcPixelType == ttFloat)
+ {
+
+ real32 scale = fScale;
+
+ const real32 *srcPtr = (const real32 *) sPtr;
+
+ real32 *dstPtr = (real32 *) dPtr;
+
+ // Optimize scale only case, which is the most common.
+
+ if (fBlack_1D_rows == 0 &&
+ fBlack_2D_cols == 0)
+ {
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ *dstPtr = (*srcPtr) * scale;
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ else
+ {
+
+ real32 b1 = 0.0f;
+
+ if (fBlack_1D_rows)
+ {
+ b1 = fBlack_1D_buffer->Buffer_real32 () [dstRow % fBlack_1D_rows];
+ }
+
+ const real32 *b2 = NULL;
+
+ uint32 b2_count = fBlack_2D_cols;
+ uint32 b2_phase = 0;
+
+ if (b2_count)
+ {
+
+ b2 = fBlack_2D_buffer->Buffer_real32 () +
+ b2_count * (dstRow % fBlack_2D_rows);
+
+ b2_phase = dstCol % b2_count;
+
+ }
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ real32 x = (*srcPtr) * scale - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ *dstPtr = x;
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ }
+
+ // Simple LUT case.
+
+ else if (fBlack_1D_rows == 0 &&
+ fBlack_2D_rows == 0 && fSrcPixelType != ttLong)
+ {
+
+ if (fDstPixelType == ttShort)
+ {
+
+ const uint16 *lut = fScale_buffer->Buffer_uint16 ();
+
+ uint16 *dstPtr = (uint16 *) dPtr;
+
+ if (fSrcPixelType == ttByte)
+ {
+
+ const uint8 *srcPtr = (const uint8 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ *dstPtr = lut [*srcPtr];
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ else
+ {
+
+ const uint16 *srcPtr = (const uint16 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ *dstPtr = lut [*srcPtr];
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ const real32 *lut = fScale_buffer->Buffer_real32 ();
+
+ real32 *dstPtr = (real32 *) dPtr;
+
+ if (fSrcPixelType == ttByte)
+ {
+
+ const uint8 *srcPtr = (const uint8 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ *dstPtr = lut [*srcPtr];
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ else
+ {
+
+ const uint16 *srcPtr = (const uint16 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ *dstPtr = lut [*srcPtr];
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Integer math case.
+
+ else if (!fReal32)
+ {
+
+ const int32 *lut = fScale_buffer->Buffer_int32 ();
+
+ int32 b1 = 0;
+
+ if (fBlack_1D_rows)
+ {
+ b1 = fBlack_1D_buffer->Buffer_int32 () [dstRow % fBlack_1D_rows];
+ }
+
+ const int32 *b2 = NULL;
+
+ uint32 b2_count = fBlack_2D_cols;
+ uint32 b2_phase = 0;
+
+ if (b2_count)
+ {
+
+ b2 = fBlack_2D_buffer->Buffer_int32 () +
+ b2_count * (dstRow % fBlack_2D_rows);
+
+ b2_phase = dstCol % b2_count;
+
+ }
+
+ uint16 *dstPtr = (uint16 *) dPtr;
+
+ b1 -= 128; // Rounding for 8 bit shift
+
+ if (fSrcPixelType == ttByte)
+ {
+
+ const uint8 *srcPtr = (const uint8 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ int32 x = lut [*srcPtr] - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ x >>= 8;
+
+ *dstPtr = Pin_uint16 (x);
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ else
+ {
+
+ const uint16 *srcPtr = (const uint16 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ int32 x = lut [*srcPtr] - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ x >>= 8;
+
+ *dstPtr = Pin_uint16 (x);
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ }
+
+ // Floating point math cases.
+
+ else
+ {
+
+ real32 b1 = 0.0f;
+
+ if (fBlack_1D_rows)
+ {
+ b1 = fBlack_1D_buffer->Buffer_real32 () [dstRow % fBlack_1D_rows];
+ }
+
+ const real32 *b2 = NULL;
+
+ uint32 b2_count = fBlack_2D_cols;
+ uint32 b2_phase = 0;
+
+ if (b2_count)
+ {
+
+ b2 = fBlack_2D_buffer->Buffer_real32 () +
+ b2_count * (dstRow % fBlack_2D_rows);
+
+ b2_phase = dstCol % b2_count;
+
+ }
+
+ // Case 1: uint8/uint16 -> real32
+
+ if (fSrcPixelType != ttLong)
+ {
+
+ const real32 *lut = fScale_buffer->Buffer_real32 ();
+
+ real32 *dstPtr = (real32 *) dPtr;
+
+ if (fSrcPixelType == ttByte)
+ {
+
+ const uint8 *srcPtr = (const uint8 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ real32 x = lut [*srcPtr] - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ x = Pin_real32 (0.0f, x, 1.0f);
+
+ *dstPtr = x;
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ else
+ {
+
+ const uint16 *srcPtr = (const uint16 *) sPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ real32 x = lut [*srcPtr] - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ x = Pin_real32 (0.0f, x, 1.0f);
+
+ *dstPtr = x;
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ }
+
+ // Otherwise source is uint32
+
+ else
+ {
+
+ real32 scale = fScale;
+
+ const uint32 *srcPtr = (const uint32 *) sPtr;
+
+ // Case 2: uint32 -> real32
+
+ if (fDstPixelType == ttFloat)
+ {
+
+ real32 *dstPtr = (real32 *) dPtr;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ real32 x = ((real32) *srcPtr) * scale - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ x = Pin_real32 (0.0f, x, 1.0f);
+
+ *dstPtr = x;
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ // Case 3: uint32 -> uint16
+
+ else
+ {
+
+ uint16 *dstPtr = (uint16 *) dPtr;
+
+ real32 dstScale = (real32) 0x0FFFF;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ real32 x = ((real32) *srcPtr) * scale - b1;
+
+ if (b2_count)
+ {
+
+ x -= b2 [b2_phase];
+
+ if (++b2_phase == b2_count)
+ {
+ b2_phase = 0;
+ }
+
+ }
+
+ x = Pin_real32 (0.0f, x, 1.0f);
+
+ *dstPtr = (uint16) (x * dstScale + 0.5f);
+
+ srcPtr += sStep;
+ dstPtr += dStep;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_linearize_image: public dng_area_task
+ {
+
+ private:
+
+ const dng_image & fSrcImage;
+ dng_image & fDstImage;
+
+ dng_rect fActiveArea;
+
+ AutoPtr<dng_linearize_plane> fPlaneTask [kMaxColorPlanes];
+
+ public:
+
+ dng_linearize_image (dng_host &host,
+ dng_linearization_info &info,
+ const dng_image &srcImage,
+ dng_image &dstImage);
+
+ virtual ~dng_linearize_image ();
+
+ virtual dng_rect RepeatingTile1 () const;
+
+ virtual dng_rect RepeatingTile2 () const;
+
+ virtual void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer *sniffer);
+
+ };
+
+/*****************************************************************************/
+
+dng_linearize_image::dng_linearize_image (dng_host &host,
+ dng_linearization_info &info,
+ const dng_image &srcImage,
+ dng_image &dstImage)
+
+ : fSrcImage (srcImage)
+ , fDstImage (dstImage)
+ , fActiveArea (info.fActiveArea)
+
+ {
+
+ // Build linearization table for each plane.
+
+ for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
+ {
+
+ fPlaneTask [plane].Reset (new dng_linearize_plane (host,
+ info,
+ srcImage,
+ dstImage,
+ plane));
+
+ }
+
+ // Adjust maximum tile size.
+
+ fMaxTileSize = dng_point (1024, 1024);
+
+ }
+
+/*****************************************************************************/
+
+dng_linearize_image::~dng_linearize_image ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_linearize_image::RepeatingTile1 () const
+ {
+
+ return fSrcImage.RepeatingTile ();
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_linearize_image::RepeatingTile2 () const
+ {
+
+ return fDstImage.RepeatingTile () + fActiveArea.TL ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_linearize_image::Process (uint32 /* threadIndex */,
+ const dng_rect &srcTile,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ // Process each plane.
+
+ for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
+ {
+
+ fPlaneTask [plane]->Process (srcTile);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_linearization_info::dng_linearization_info ()
+
+ : fActiveArea ()
+ , fMaskedAreaCount (0)
+ , fLinearizationTable ()
+ , fBlackLevelRepeatRows (1)
+ , fBlackLevelRepeatCols (1)
+ , fBlackDeltaH ()
+ , fBlackDeltaV ()
+ , fBlackDenom (256)
+
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 n;
+
+ for (j = 0; j < kMaxBlackPattern; j++)
+ for (k = 0; k < kMaxBlackPattern; k++)
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ fBlackLevel [j] [k] [n] = 0.0;
+ }
+
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ fWhiteLevel [n] = 65535.0;
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_linearization_info::~dng_linearization_info ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_linearization_info::RoundBlacks ()
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 n;
+
+ real64 maxAbs = 0.0;
+
+ for (j = 0; j < fBlackLevelRepeatRows; j++)
+ for (k = 0; k < fBlackLevelRepeatCols; k++)
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+
+ maxAbs = Max_real64 (maxAbs,
+ Abs_real64 (fBlackLevel [j] [k] [n]));
+
+ }
+
+ uint32 count = RowBlackCount ();
+
+ for (j = 0; j < count; j++)
+ {
+
+ maxAbs = Max_real64 (maxAbs,
+ Abs_real64 (fBlackDeltaV->Buffer_real64 () [j]));
+
+ }
+
+ count = ColumnBlackCount ();
+
+ for (j = 0; j < count; j++)
+ {
+
+ maxAbs = Max_real64 (maxAbs,
+ Abs_real64 (fBlackDeltaH->Buffer_real64 () [j]));
+
+
+ }
+
+ fBlackDenom = 256;
+
+ while (fBlackDenom > 1 && (maxAbs * fBlackDenom) >= 30000.0 * 65536.0)
+ {
+ fBlackDenom >>= 1;
+ }
+
+ for (j = 0; j < fBlackLevelRepeatRows; j++)
+ for (k = 0; k < fBlackLevelRepeatCols; k++)
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+
+ fBlackLevel [j] [k] [n] = BlackLevel (j, k, n).As_real64 ();
+
+ }
+
+ count = RowBlackCount ();
+
+ for (j = 0; j < count; j++)
+ {
+
+ fBlackDeltaV->Buffer_real64 () [j] = RowBlack (j).As_real64 ();
+
+ }
+
+ count = ColumnBlackCount ();
+
+ for (j = 0; j < count; j++)
+ {
+
+ fBlackDeltaH->Buffer_real64 () [j] = ColumnBlack (j).As_real64 ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_linearization_info::Parse (dng_host &host,
+ dng_stream &stream,
+ dng_info &info)
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 n;
+
+ // Find main image IFD.
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
+
+ // Copy active area.
+
+ fActiveArea = rawIFD.fActiveArea;
+
+ // Copy masked areas.
+
+ fMaskedAreaCount = rawIFD.fMaskedAreaCount;
+
+ for (j = 0; j < fMaskedAreaCount; j++)
+ {
+ fMaskedArea [j] = rawIFD.fMaskedArea [j];
+ }
+
+ // Read linearization LUT.
+
+ if (rawIFD.fLinearizationTableCount)
+ {
+
+ uint32 size = rawIFD.fLinearizationTableCount * (uint32) sizeof (uint16);
+
+ fLinearizationTable.Reset (host.Allocate (size));
+
+ uint16 *table = fLinearizationTable->Buffer_uint16 ();
+
+ stream.SetReadPosition (rawIFD.fLinearizationTableOffset);
+
+ for (j = 0; j < rawIFD.fLinearizationTableCount; j++)
+ {
+ table [j] = stream.Get_uint16 ();
+ }
+
+ }
+
+ // Copy black level pattern.
+
+ fBlackLevelRepeatRows = rawIFD.fBlackLevelRepeatRows;
+ fBlackLevelRepeatCols = rawIFD.fBlackLevelRepeatCols;
+
+ for (j = 0; j < kMaxBlackPattern; j++)
+ for (k = 0; k < kMaxBlackPattern; k++)
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ fBlackLevel [j] [k] [n] = rawIFD.fBlackLevel [j] [k] [n];
+ }
+
+ // Read BlackDeltaH.
+
+ if (rawIFD.fBlackLevelDeltaHCount)
+ {
+
+ uint32 size = rawIFD.fBlackLevelDeltaHCount * (uint32) sizeof (real64);
+
+ fBlackDeltaH.Reset (host.Allocate (size));
+
+ real64 *blacks = fBlackDeltaH->Buffer_real64 ();
+
+ stream.SetReadPosition (rawIFD.fBlackLevelDeltaHOffset);
+
+ for (j = 0; j < rawIFD.fBlackLevelDeltaHCount; j++)
+ {
+ blacks [j] = stream.TagValue_real64 (rawIFD.fBlackLevelDeltaHType);
+ }
+
+ }
+
+ // Read BlackDeltaV.
+
+ if (rawIFD.fBlackLevelDeltaVCount)
+ {
+
+ uint32 size = rawIFD.fBlackLevelDeltaVCount * (uint32) sizeof (real64);
+
+ fBlackDeltaV.Reset (host.Allocate (size));
+
+ real64 *blacks = fBlackDeltaV->Buffer_real64 ();
+
+ stream.SetReadPosition (rawIFD.fBlackLevelDeltaVOffset);
+
+ for (j = 0; j < rawIFD.fBlackLevelDeltaVCount; j++)
+ {
+ blacks [j] = stream.TagValue_real64 (rawIFD.fBlackLevelDeltaVType);
+ }
+
+ }
+
+ // Copy white level.
+
+ for (n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ fWhiteLevel [n] = rawIFD.fWhiteLevel [n];
+ }
+
+ // Round off black levels.
+
+ RoundBlacks ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_linearization_info::PostParse (dng_host & /* host */,
+ dng_negative &negative)
+ {
+
+ if (fActiveArea.IsEmpty ())
+ {
+
+ fActiveArea = negative.Stage1Image ()->Bounds ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_linearization_info::MaxBlackLevel (uint32 plane) const
+ {
+
+ uint32 j;
+ uint32 k;
+
+ // Find maximum value of fBlackDeltaH for each phase of black pattern.
+
+ real64 maxDeltaH [kMaxBlackPattern];
+
+ for (j = 0; j < fBlackLevelRepeatCols; j++)
+ {
+ maxDeltaH [j] = 0.0;
+ }
+
+ if (fBlackDeltaH.Get ())
+ {
+
+ real64 *table = fBlackDeltaH->Buffer_real64 ();
+
+ uint32 entries = fBlackDeltaH->LogicalSize () / (uint32) sizeof (table [0]);
+
+ for (j = 0; j < entries; j++)
+ {
+
+ real64 &entry = maxDeltaH [j % fBlackLevelRepeatCols];
+
+ if (j < fBlackLevelRepeatCols)
+ {
+ entry = table [j];
+ }
+ else
+ {
+ entry = Max_real64 (entry, table [j]);
+ }
+
+ }
+
+ }
+
+ // Find maximum value of fBlackDeltaV for each phase of black pattern.
+
+ real64 maxDeltaV [kMaxBlackPattern];
+
+ for (j = 0; j < fBlackLevelRepeatRows; j++)
+ {
+ maxDeltaV [j] = 0.0;
+ }
+
+ if (fBlackDeltaV.Get ())
+ {
+
+ real64 *table = fBlackDeltaV->Buffer_real64 ();
+
+ uint32 entries = fBlackDeltaV->LogicalSize () / (uint32) sizeof (table [0]);
+
+ for (j = 0; j < entries; j++)
+ {
+
+ real64 &entry = maxDeltaV [j % fBlackLevelRepeatRows];
+
+ if (j < fBlackLevelRepeatRows)
+ {
+ entry = table [j];
+ }
+ else
+ {
+ entry = Max_real64 (entry, table [j]);
+ }
+
+ }
+
+ }
+
+ // Now scan the pattern and find the maximum value after row and column
+ // deltas.
+
+ real64 maxBlack = 0.0;
+
+ for (j = 0; j < fBlackLevelRepeatRows; j++)
+ {
+
+ for (k = 0; k < fBlackLevelRepeatCols; k++)
+ {
+
+ real64 black = fBlackLevel [j] [k] [plane];
+
+ black += maxDeltaH [k];
+ black += maxDeltaV [j];
+
+ if (j == 0 && k == 0)
+ {
+ maxBlack = black;
+ }
+ else
+ {
+ maxBlack = Max_real64 (maxBlack, black);
+ }
+
+ }
+
+ }
+
+ return maxBlack;
+
+ }
+
+/*****************************************************************************/
+
+void dng_linearization_info::Linearize (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage)
+ {
+
+ dng_linearize_image processor (host,
+ *this,
+ srcImage,
+ dstImage);
+
+ host.PerformAreaTask (processor,
+ fActiveArea);
+
+ }
+
+/*****************************************************************************/
+
+dng_urational dng_linearization_info::BlackLevel (uint32 row,
+ uint32 col,
+ uint32 plane) const
+ {
+
+ dng_urational r;
+
+ r.Set_real64 (fBlackLevel [row] [col] [plane], fBlackDenom);
+
+ return r;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_linearization_info::RowBlackCount () const
+ {
+
+ if (fBlackDeltaV.Get ())
+ {
+
+ return fBlackDeltaV->LogicalSize () >> 3;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+dng_srational dng_linearization_info::RowBlack (uint32 row) const
+ {
+
+ if (fBlackDeltaV.Get ())
+ {
+
+ dng_srational r;
+
+ r.Set_real64 (fBlackDeltaV->Buffer_real64 () [row], fBlackDenom);
+
+ return r;
+
+ }
+
+ return dng_srational (0, 1);
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_linearization_info::ColumnBlackCount () const
+ {
+
+ if (fBlackDeltaH.Get ())
+ {
+
+ return fBlackDeltaH->LogicalSize () >> 3;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+dng_srational dng_linearization_info::ColumnBlack (uint32 col) const
+ {
+
+ if (fBlackDeltaH.Get ())
+ {
+
+ dng_srational r;
+
+ r.Set_real64 (fBlackDeltaH->Buffer_real64 () [col], fBlackDenom);
+
+ return r;
+
+ }
+
+ return dng_srational (0, 1);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_linearization_info.h b/gpr/source/lib/dng_sdk/dng_linearization_info.h
new file mode 100644
index 0000000..510cf11
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_linearization_info.h
@@ -0,0 +1,164 @@
+/*****************************************************************************/
+// Copyright 2006-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_linearization_info.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for linearization table and black level tags.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_linearization_info__
+#define __dng_linearization_info__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_memory.h"
+#include "dng_rational.h"
+#include "dng_rect.h"
+#include "dng_sdk_limits.h"
+
+/*****************************************************************************/
+
+/// \brief Class for managing data values related to DNG linearization.
+///
+/// See LinearizationTable, BlackLevel, BlackLevelRepeatDim, BlackLevelDeltaH,
+/// BlackLevelDeltaV and WhiteLevel tags in the \ref spec_dng "DNG 1.1.0 specification".
+
+class dng_linearization_info
+ {
+
+ public:
+
+ /// This rectangle defines the active (non-masked) pixels of the sensor.
+ /// The order of the rectangle coordinates is: top, left, bottom, right.
+
+ dng_rect fActiveArea;
+
+ /// Number of rectangles in fMaskedArea
+
+ uint32 fMaskedAreaCount;
+
+ /// List of non-overlapping rectangle coordinates of fully masked pixels.
+ /// Can be optionally used by DNG readers to measure the black encoding level.
+ /// The order of each rectangle's coordinates is: top, left, bottom, right.
+ /// If the raw image data has already had its black encoding level subtracted, then this tag should
+ /// not be used, since the masked pixels are no longer useful.
+ /// Note that DNG writers are still required to include an estimate and store the black encoding level
+ /// using the black level DNG tags. Support for the MaskedAreas tag is not required of DNG
+ /// readers.
+
+ dng_rect fMaskedArea [kMaxMaskedAreas];
+
+ /// A lookup table that maps stored values into linear values.
+ /// This tag is typically used to increase compression ratios by storing the raw data in a non-linear, more
+ /// visually uniform space with fewer total encoding levels.
+ /// If SamplesPerPixel is not equal to one, e.g. Fuji S3 type sensor, this single table applies to all the samples for each
+ /// pixel.
+
+ AutoPtr<dng_memory_block> fLinearizationTable;
+
+ /// Actual number of rows in fBlackLevel pattern
+
+ uint32 fBlackLevelRepeatRows;
+
+ /// Actual number of columns in fBlackLevel pattern
+
+ uint32 fBlackLevelRepeatCols;
+
+ /// Repeating pattern of black level deltas fBlackLevelRepeatRows by fBlackLevelRepeatCols in size.
+
+ real64 fBlackLevel [kMaxBlackPattern] [kMaxBlackPattern] [kMaxSamplesPerPixel];
+
+ /// Memory block of double-precision floating point deltas between baseline black level and a given column's black level
+
+ AutoPtr<dng_memory_block> fBlackDeltaH;
+
+ /// Memory block of double-precision floating point deltas between baseline black level and a given row's black level
+
+ AutoPtr<dng_memory_block> fBlackDeltaV;
+
+ /// Single white level (maximum sensor value) for each sample plane.
+
+ real64 fWhiteLevel [kMaxSamplesPerPixel];
+
+ protected:
+
+ int32 fBlackDenom;
+
+ public:
+
+ dng_linearization_info ();
+
+ virtual ~dng_linearization_info ();
+
+ void RoundBlacks ();
+
+ virtual void Parse (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ virtual void PostParse (dng_host &host,
+ dng_negative &negative);
+
+ /// Compute the maximum black level for a given sample plane taking into account base
+ /// black level, repeated black level patter, and row/column delta maps.
+
+ real64 MaxBlackLevel (uint32 plane) const;
+
+ /// Convert raw data from in-file format to a true linear image using linearization data from DNG.
+ /// \param host Used to allocate buffers, check for aborts, and post progress updates.
+ /// \param srcImage Input pre-linearization RAW samples.
+ /// \param dstImage Output linearized image.
+
+ virtual void Linearize (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage);
+
+ /// Compute black level for one coordinate and sample plane in the image.
+ /// \param row Row to compute black level for.
+ /// \param col Column to compute black level for.
+ /// \param plane Sample plane to compute black level for.
+
+ dng_urational BlackLevel (uint32 row,
+ uint32 col,
+ uint32 plane) const;
+
+ /// Number of per-row black level deltas in fBlackDeltaV.
+
+ uint32 RowBlackCount () const;
+
+ /// Lookup black level delta for a given row.
+ /// \param row Row to get black level for.
+ /// \retval black level for indicated row.
+
+ dng_srational RowBlack (uint32 row) const;
+
+ /// Number of per-column black level deltas in fBlackDeltaV.
+
+ uint32 ColumnBlackCount () const;
+
+ /// Lookup black level delta for a given column.
+ /// \param col Column to get black level for.
+ /// \retval black level for indicated column.
+
+ dng_srational ColumnBlack (uint32 col) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_lossless_jpeg.cpp b/gpr/source/lib/dng_sdk/dng_lossless_jpeg.cpp
new file mode 100644
index 0000000..b841352
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_lossless_jpeg.cpp
@@ -0,0 +1,3765 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_lossless_jpeg.cpp#2 $ */
+/* $DateTime: 2012/06/01 07:28:57 $ */
+/* $Change: 832715 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+// Lossless JPEG code adapted from:
+
+/* Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Part of the Independent JPEG Group's software.
+ * See the file Copyright for more details.
+ *
+ * Copyright (c) 1993 Brian C. Smith, The Regents of the University
+ * of California
+ * All rights reserved.
+ *
+ * Copyright (c) 1994 Kongji Huang and Brian C. Smith.
+ * Cornell University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF CORNELL
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * CORNELL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND CORNELL UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+/*****************************************************************************/
+#include "stdc_includes.h"
+
+#include "dng_lossless_jpeg.h"
+
+#include "dng_assertions.h"
+#include "dng_exceptions.h"
+#include "dng_memory.h"
+#include "dng_stream.h"
+#include "dng_tag_codes.h"
+
+/*****************************************************************************/
+
+// This module contains routines that should be as fast as possible, even
+// at the expense of slight code size increases.
+
+#include "dng_fast_module.h"
+
+/*****************************************************************************/
+
+// The qSupportCanon_sRAW stuff not actually required for DNG support, but
+// only included to allow this code to be used on Canon sRAW files.
+
+#ifndef qSupportCanon_sRAW
+#define qSupportCanon_sRAW 1
+#endif
+
+// The qSupportHasselblad_3FR stuff not actually required for DNG support, but
+// only included to allow this code to be used on Hasselblad 3FR files.
+
+#ifndef qSupportHasselblad_3FR
+#define qSupportHasselblad_3FR 1
+#endif
+
+/*****************************************************************************/
+
+/*
+ * One of the following structures is created for each huffman coding
+ * table. We use the same structure for encoding and decoding, so there
+ * may be some extra fields for encoding that aren't used in the decoding
+ * and vice-versa.
+ */
+
+struct HuffmanTable
+ {
+
+ /*
+ * These two fields directly represent the contents of a JPEG DHT
+ * marker
+ */
+ uint8 bits[17];
+ uint8 huffval[256];
+
+ /*
+ * The remaining fields are computed from the above to allow more
+ * efficient coding and decoding. These fields should be considered
+ * private to the Huffman compression & decompression modules.
+ */
+
+ uint16 mincode[17];
+ int32 maxcode[18];
+ int16 valptr[17];
+ int32 numbits[256];
+ int32 value[256];
+
+ uint16 ehufco[256];
+ int8 ehufsi[256];
+
+ };
+
+/*****************************************************************************/
+
+// Computes the derived fields in the Huffman table structure.
+
+static void FixHuffTbl (HuffmanTable *htbl)
+ {
+
+ int32 l;
+ int32 i;
+
+ const uint32 bitMask [] =
+ {
+ 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
+ 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
+ 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
+ 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
+ 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
+ 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
+ 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
+ 0x0000000f, 0x00000007, 0x00000003, 0x00000001
+ };
+
+ // Figure C.1: make table of Huffman code length for each symbol
+ // Note that this is in code-length order.
+
+ int8 huffsize [257];
+
+ int32 p = 0;
+
+ for (l = 1; l <= 16; l++)
+ {
+
+ for (i = 1; i <= (int32) htbl->bits [l]; i++)
+ huffsize [p++] = (int8) l;
+
+ }
+
+ huffsize [p] = 0;
+
+ int32 lastp = p;
+
+ // Figure C.2: generate the codes themselves
+ // Note that this is in code-length order.
+
+ uint16 huffcode [257];
+
+ uint16 code = 0;
+
+ int32 si = huffsize [0];
+
+ p = 0;
+
+ while (huffsize [p])
+ {
+
+ while (((int32) huffsize [p]) == si)
+ {
+ huffcode [p++] = code;
+ code++;
+ }
+
+ code <<= 1;
+
+ si++;
+
+ }
+
+ // Figure C.3: generate encoding tables
+ // These are code and size indexed by symbol value
+ // Set any codeless symbols to have code length 0; this allows
+ // EmitBits to detect any attempt to emit such symbols.
+
+ memset (htbl->ehufsi, 0, sizeof (htbl->ehufsi));
+
+ for (p = 0; p < lastp; p++)
+ {
+
+ htbl->ehufco [htbl->huffval [p]] = huffcode [p];
+ htbl->ehufsi [htbl->huffval [p]] = huffsize [p];
+
+ }
+
+ // Figure F.15: generate decoding tables
+
+ p = 0;
+
+ for (l = 1; l <= 16; l++)
+ {
+
+ if (htbl->bits [l])
+ {
+
+ htbl->valptr [l] = (int16) p;
+ htbl->mincode [l] = huffcode [p];
+
+ p += htbl->bits [l];
+
+ htbl->maxcode [l] = huffcode [p - 1];
+
+ }
+
+ else
+ {
+ htbl->maxcode [l] = -1;
+ }
+
+ }
+
+ // We put in this value to ensure HuffDecode terminates.
+
+ htbl->maxcode[17] = 0xFFFFFL;
+
+ // Build the numbits, value lookup tables.
+ // These table allow us to gather 8 bits from the bits stream,
+ // and immediately lookup the size and value of the huffman codes.
+ // If size is zero, it means that more than 8 bits are in the huffman
+ // code (this happens about 3-4% of the time).
+
+ memset (htbl->numbits, 0, sizeof (htbl->numbits));
+
+ for (p = 0; p < lastp; p++)
+ {
+
+ int32 size = huffsize [p];
+
+ if (size <= 8)
+ {
+
+ int32 value = htbl->huffval [p];
+
+ code = huffcode [p];
+
+ int32 ll = code << (8 -size);
+
+ int32 ul = (size < 8 ? ll | bitMask [24 + size]
+ : ll);
+
+ for (i = ll; i <= ul; i++)
+ {
+ htbl->numbits [i] = size;
+ htbl->value [i] = value;
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ * The following structure stores basic information about one component.
+ */
+
+struct JpegComponentInfo
+ {
+
+ /*
+ * These values are fixed over the whole image.
+ * They are read from the SOF marker.
+ */
+ int16 componentId; /* identifier for this component (0..255) */
+ int16 componentIndex; /* its index in SOF or cPtr->compInfo[] */
+
+ /*
+ * Downsampling is not normally used in lossless JPEG, although
+ * it is permitted by the JPEG standard (DIS). We set all sampling
+ * factors to 1 in this program.
+ */
+ int16 hSampFactor; /* horizontal sampling factor */
+ int16 vSampFactor; /* vertical sampling factor */
+
+ /*
+ * Huffman table selector (0..3). The value may vary
+ * between scans. It is read from the SOS marker.
+ */
+ int16 dcTblNo;
+
+ };
+
+/*
+ * One of the following structures is used to pass around the
+ * decompression information.
+ */
+
+struct DecompressInfo
+ {
+
+ /*
+ * Image width, height, and image data precision (bits/sample)
+ * These fields are set by ReadFileHeader or ReadScanHeader
+ */
+ int32 imageWidth;
+ int32 imageHeight;
+ int32 dataPrecision;
+
+ /*
+ * compInfo[i] describes component that appears i'th in SOF
+ * numComponents is the # of color components in JPEG image.
+ */
+ JpegComponentInfo *compInfo;
+ int16 numComponents;
+
+ /*
+ * *curCompInfo[i] describes component that appears i'th in SOS.
+ * compsInScan is the # of color components in current scan.
+ */
+ JpegComponentInfo *curCompInfo[4];
+ int16 compsInScan;
+
+ /*
+ * MCUmembership[i] indexes the i'th component of MCU into the
+ * curCompInfo array.
+ */
+ int16 MCUmembership[10];
+
+ /*
+ * ptrs to Huffman coding tables, or NULL if not defined
+ */
+ HuffmanTable *dcHuffTblPtrs[4];
+
+ /*
+ * prediction selection value (PSV) and point transform parameter (Pt)
+ */
+ int32 Ss;
+ int32 Pt;
+
+ /*
+ * In lossless JPEG, restart interval shall be an integer
+ * multiple of the number of MCU in a MCU row.
+ */
+ int32 restartInterval;/* MCUs per restart interval, 0 = no restart */
+ int32 restartInRows; /*if > 0, MCU rows per restart interval; 0 = no restart*/
+
+ /*
+ * these fields are private data for the entropy decoder
+ */
+ int32 restartRowsToGo; /* MCUs rows left in this restart interval */
+ int16 nextRestartNum; /* # of next RSTn marker (0..7) */
+
+ };
+
+/*****************************************************************************/
+
+// An MCU (minimum coding unit) is an array of samples.
+
+typedef uint16 ComponentType; // the type of image components
+
+typedef ComponentType *MCU; // MCU - array of samples
+
+/*****************************************************************************/
+
+class dng_lossless_decoder
+ {
+
+ private:
+
+ dng_stream *fStream; // Input data.
+
+ dng_spooler *fSpooler; // Output data.
+
+ bool fBug16; // Decode data with the "16-bit" bug.
+
+ dng_memory_data huffmanBuffer [4];
+
+ dng_memory_data compInfoBuffer;
+
+ DecompressInfo info;
+
+ dng_memory_data mcuBuffer1;
+ dng_memory_data mcuBuffer2;
+ dng_memory_data mcuBuffer3;
+ dng_memory_data mcuBuffer4;
+
+ MCU *mcuROW1;
+ MCU *mcuROW2;
+
+ uint64 getBuffer; // current bit-extraction buffer
+ int32 bitsLeft; // # of unused bits in it
+
+ #if qSupportHasselblad_3FR
+ bool fHasselblad3FR;
+ #endif
+
+ public:
+
+ dng_lossless_decoder (dng_stream *stream,
+ dng_spooler *spooler,
+ bool bug16);
+
+ void StartRead (uint32 &imageWidth,
+ uint32 &imageHeight,
+ uint32 &imageChannels);
+
+ void FinishRead ();
+
+ private:
+
+ uint8 GetJpegChar ()
+ {
+ return fStream->Get_uint8 ();
+ }
+
+ void UnGetJpegChar ()
+ {
+ fStream->SetReadPosition (fStream->Position () - 1);
+ }
+
+ uint16 Get2bytes ();
+
+ void SkipVariable ();
+
+ void GetDht ();
+
+ void GetDri ();
+
+ void GetApp0 ();
+
+ void GetSof (int32 code);
+
+ void GetSos ();
+
+ void GetSoi ();
+
+ int32 NextMarker ();
+
+ JpegMarker ProcessTables ();
+
+ void ReadFileHeader ();
+
+ int32 ReadScanHeader ();
+
+ void DecoderStructInit ();
+
+ void HuffDecoderInit ();
+
+ void ProcessRestart ();
+
+ int32 QuickPredict (int32 col,
+ int32 curComp,
+ MCU *curRowBuf,
+ MCU *prevRowBuf);
+
+ void FillBitBuffer (int32 nbits);
+
+ int32 show_bits8 ();
+
+ void flush_bits (int32 nbits);
+
+ int32 get_bits (int32 nbits);
+
+ int32 get_bit ();
+
+ int32 HuffDecode (HuffmanTable *htbl);
+
+ void HuffExtend (int32 &x, int32 s);
+
+ void PmPutRow (MCU *buf,
+ int32 numComp,
+ int32 numCol,
+ int32 row);
+
+ void DecodeFirstRow (MCU *curRowBuf);
+
+ void DecodeImage ();
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_lossless_decoder (const dng_lossless_decoder &decoder);
+
+ dng_lossless_decoder & operator= (const dng_lossless_decoder &decoder);
+
+ };
+
+/*****************************************************************************/
+
+dng_lossless_decoder::dng_lossless_decoder (dng_stream *stream,
+ dng_spooler *spooler,
+ bool bug16)
+
+ : fStream (stream )
+ , fSpooler (spooler)
+ , fBug16 (bug16 )
+
+ , compInfoBuffer ()
+ , info ()
+ , mcuBuffer1 ()
+ , mcuBuffer2 ()
+ , mcuBuffer3 ()
+ , mcuBuffer4 ()
+ , mcuROW1 (NULL)
+ , mcuROW2 (NULL)
+ , getBuffer (0)
+ , bitsLeft (0)
+
+ #if qSupportHasselblad_3FR
+ , fHasselblad3FR (false)
+ #endif
+
+ {
+
+ memset (&info, 0, sizeof (info));
+
+ }
+
+/*****************************************************************************/
+
+uint16 dng_lossless_decoder::Get2bytes ()
+ {
+
+ uint16 a = GetJpegChar ();
+
+ return (uint16) ((a << 8) + GetJpegChar ());
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * SkipVariable --
+ *
+ * Skip over an unknown or uninteresting variable-length marker
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitstream is parsed over marker.
+ *
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::SkipVariable ()
+ {
+
+ uint32 length = Get2bytes () - 2;
+
+ fStream->Skip (length);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GetDht --
+ *
+ * Process a DHT marker
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * A huffman table is read.
+ * Exits on error.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::GetDht ()
+ {
+
+ int32 length = Get2bytes () - 2;
+
+ while (length > 0)
+ {
+
+ int32 index = GetJpegChar ();
+
+ if (index < 0 || index >= 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ HuffmanTable *&htblptr = info.dcHuffTblPtrs [index];
+
+ if (htblptr == NULL)
+ {
+
+ huffmanBuffer [index] . Allocate (sizeof (HuffmanTable));
+
+ htblptr = (HuffmanTable *) huffmanBuffer [index] . Buffer ();
+
+ }
+
+ htblptr->bits [0] = 0;
+
+ int32 count = 0;
+
+ for (int32 i = 1; i <= 16; i++)
+ {
+
+ htblptr->bits [i] = GetJpegChar ();
+
+ count += htblptr->bits [i];
+
+ }
+
+ if (count > 256)
+ {
+ ThrowBadFormat ();
+ }
+
+ for (int32 j = 0; j < count; j++)
+ {
+
+ htblptr->huffval [j] = GetJpegChar ();
+
+ }
+
+ length -= 1 + 16 + count;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GetDri --
+ *
+ * Process a DRI marker
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Exits on error.
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::GetDri ()
+ {
+
+ if (Get2bytes () != 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ info.restartInterval = Get2bytes ();
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GetApp0 --
+ *
+ * Process an APP0 marker.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Bitstream is parsed
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::GetApp0 ()
+ {
+
+ SkipVariable ();
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GetSof --
+ *
+ * Process a SOFn marker
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitstream is parsed
+ * Exits on error
+ * info structure is filled in
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::GetSof (int32 /*code*/)
+ {
+
+ int32 length = Get2bytes ();
+
+ info.dataPrecision = GetJpegChar ();
+ info.imageHeight = Get2bytes ();
+ info.imageWidth = Get2bytes ();
+ info.numComponents = GetJpegChar ();
+
+ // We don't support files in which the image height is initially
+ // specified as 0 and is later redefined by DNL. As long as we
+ // have to check that, might as well have a general sanity check.
+
+ if ((info.imageHeight <= 0) ||
+ (info.imageWidth <= 0) ||
+ (info.numComponents <= 0))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Lossless JPEG specifies data precision to be from 2 to 16 bits/sample.
+
+ const int32 MinPrecisionBits = 2;
+ const int32 MaxPrecisionBits = 16;
+
+ if ((info.dataPrecision < MinPrecisionBits) ||
+ (info.dataPrecision > MaxPrecisionBits))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Check length of tag.
+
+ if (length != (info.numComponents * 3 + 8))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Allocate per component info.
+
+ compInfoBuffer.Allocate (info.numComponents *
+ (uint32) sizeof (JpegComponentInfo));
+
+ info.compInfo = (JpegComponentInfo *) compInfoBuffer.Buffer ();
+
+ // Read in the per compent info.
+
+ for (int32 ci = 0; ci < info.numComponents; ci++)
+ {
+
+ JpegComponentInfo *compptr = &info.compInfo [ci];
+
+ compptr->componentIndex = (int16) ci;
+
+ compptr->componentId = GetJpegChar ();
+
+ int32 c = GetJpegChar ();
+
+ compptr->hSampFactor = (int16) ((c >> 4) & 15);
+ compptr->vSampFactor = (int16) ((c ) & 15);
+
+ (void) GetJpegChar (); /* skip Tq */
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GetSos --
+ *
+ * Process a SOS marker
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ * Exits on error.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::GetSos ()
+ {
+
+ int32 length = Get2bytes ();
+
+ // Get the number of image components.
+
+ int32 n = GetJpegChar ();
+ info.compsInScan = (int16) n;
+
+ // Check length.
+
+ length -= 3;
+
+ if (length != (n * 2 + 3) || n < 1 || n > 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ // Find index and huffman table for each component.
+
+ for (int32 i = 0; i < n; i++)
+ {
+
+ int32 cc = GetJpegChar ();
+ int32 c = GetJpegChar ();
+
+ int32 ci;
+
+ for (ci = 0; ci < info.numComponents; ci++)
+ {
+
+ if (cc == info.compInfo[ci].componentId)
+ {
+ break;
+ }
+
+ }
+
+ if (ci >= info.numComponents)
+ {
+ ThrowBadFormat ();
+ }
+
+ JpegComponentInfo *compptr = &info.compInfo [ci];
+
+ info.curCompInfo [i] = compptr;
+
+ compptr->dcTblNo = (int16) ((c >> 4) & 15);
+
+ }
+
+ // Get the PSV, skip Se, and get the point transform parameter.
+
+ info.Ss = GetJpegChar ();
+
+ (void) GetJpegChar ();
+
+ info.Pt = GetJpegChar () & 0x0F;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GetSoi --
+ *
+ * Process an SOI marker
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ * Exits on error.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::GetSoi ()
+ {
+
+ // Reset all parameters that are defined to be reset by SOI
+
+ info.restartInterval = 0;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * NextMarker --
+ *
+ * Find the next JPEG marker Note that the output might not
+ * be a valid marker code but it will never be 0 or FF
+ *
+ * Results:
+ * The marker found.
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+
+int32 dng_lossless_decoder::NextMarker ()
+ {
+
+ int32 c;
+
+ do
+ {
+
+ // skip any non-FF bytes
+
+ do
+ {
+ c = GetJpegChar ();
+ }
+ while (c != 0xFF);
+
+ // skip any duplicate FFs, since extra FFs are legal
+
+ do
+ {
+ c = GetJpegChar();
+ }
+ while (c == 0xFF);
+
+ }
+ while (c == 0); // repeat if it was a stuffed FF/00
+
+ return c;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ProcessTables --
+ *
+ * Scan and process JPEG markers that can appear in any order
+ * Return when an SOI, EOI, SOFn, or SOS is found
+ *
+ * Results:
+ * The marker found.
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+
+JpegMarker dng_lossless_decoder::ProcessTables ()
+ {
+
+ while (true)
+ {
+
+ int32 c = NextMarker ();
+
+ switch (c)
+ {
+
+ case M_SOF0:
+ case M_SOF1:
+ case M_SOF2:
+ case M_SOF3:
+ case M_SOF5:
+ case M_SOF6:
+ case M_SOF7:
+ case M_JPG:
+ case M_SOF9:
+ case M_SOF10:
+ case M_SOF11:
+ case M_SOF13:
+ case M_SOF14:
+ case M_SOF15:
+ case M_SOI:
+ case M_EOI:
+ case M_SOS:
+ return (JpegMarker) c;
+
+ case M_DHT:
+ GetDht ();
+ break;
+
+ case M_DQT:
+ break;
+
+ case M_DRI:
+ GetDri ();
+ break;
+
+ case M_APP0:
+ GetApp0 ();
+ break;
+
+ case M_RST0: // these are all parameterless
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+ break;
+
+ default: // must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn
+ SkipVariable ();
+ break;
+
+ }
+
+ }
+
+ return M_ERROR;
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ReadFileHeader --
+ *
+ * Initialize and read the stream header (everything through
+ * the SOF marker).
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Exit on error.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::ReadFileHeader ()
+ {
+
+ // Demand an SOI marker at the start of the stream --- otherwise it's
+ // probably not a JPEG stream at all.
+
+ int32 c = GetJpegChar ();
+ int32 c2 = GetJpegChar ();
+
+ if ((c != 0xFF) || (c2 != M_SOI))
+ {
+ ThrowBadFormat ();
+ }
+
+ // OK, process SOI
+
+ GetSoi ();
+
+ // Process markers until SOF
+
+ c = ProcessTables ();
+
+ switch (c)
+ {
+
+ case M_SOF0:
+ case M_SOF1:
+ case M_SOF3:
+ GetSof (c);
+ break;
+
+ default:
+ ThrowBadFormat ();
+ break;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ReadScanHeader --
+ *
+ * Read the start of a scan (everything through the SOS marker).
+ *
+ * Results:
+ * 1 if find SOS, 0 if find EOI
+ *
+ * Side effects:
+ * Bitstream is parsed, may exit on errors.
+ *
+ *--------------------------------------------------------------
+ */
+
+int32 dng_lossless_decoder::ReadScanHeader ()
+ {
+
+ // Process markers until SOS or EOI
+
+ int32 c = ProcessTables ();
+
+ switch (c)
+ {
+
+ case M_SOS:
+ GetSos ();
+ return 1;
+
+ case M_EOI:
+ return 0;
+
+ default:
+ ThrowBadFormat ();
+ break;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * DecoderStructInit --
+ *
+ * Initalize the rest of the fields in the decompression
+ * structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::DecoderStructInit ()
+ {
+
+ int32 ci;
+
+ #if qSupportCanon_sRAW
+
+ bool canon_sRAW = (info.numComponents == 3) &&
+ (info.compInfo [0].hSampFactor == 2) &&
+ (info.compInfo [1].hSampFactor == 1) &&
+ (info.compInfo [2].hSampFactor == 1) &&
+ (info.compInfo [0].vSampFactor == 1) &&
+ (info.compInfo [1].vSampFactor == 1) &&
+ (info.compInfo [2].vSampFactor == 1) &&
+ (info.dataPrecision == 15) &&
+ (info.Ss == 1) &&
+ ((info.imageWidth & 1) == 0);
+
+ bool canon_sRAW2 = (info.numComponents == 3) &&
+ (info.compInfo [0].hSampFactor == 2) &&
+ (info.compInfo [1].hSampFactor == 1) &&
+ (info.compInfo [2].hSampFactor == 1) &&
+ (info.compInfo [0].vSampFactor == 2) &&
+ (info.compInfo [1].vSampFactor == 1) &&
+ (info.compInfo [2].vSampFactor == 1) &&
+ (info.dataPrecision == 15) &&
+ (info.Ss == 1) &&
+ ((info.imageWidth & 1) == 0) &&
+ ((info.imageHeight & 1) == 0);
+
+ if (!canon_sRAW && !canon_sRAW2)
+
+ #endif
+
+ {
+
+ // Check sampling factor validity.
+
+ for (ci = 0; ci < info.numComponents; ci++)
+ {
+
+ JpegComponentInfo *compPtr = &info.compInfo [ci];
+
+ if (compPtr->hSampFactor != 1 ||
+ compPtr->vSampFactor != 1)
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ }
+
+ // Prepare array describing MCU composition.
+
+ if (info.compsInScan > 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ for (ci = 0; ci < info.compsInScan; ci++)
+ {
+ info.MCUmembership [ci] = (int16) ci;
+ }
+
+ // Initialize mucROW1 and mcuROW2 which buffer two rows of
+ // pixels for predictor calculation.
+
+ int32 mcuSize = info.compsInScan * (uint32) sizeof (ComponentType);
+
+ mcuBuffer1.Allocate (info.imageWidth * (uint32) sizeof (MCU));
+ mcuBuffer2.Allocate (info.imageWidth * (uint32) sizeof (MCU));
+
+ mcuROW1 = (MCU *) mcuBuffer1.Buffer ();
+ mcuROW2 = (MCU *) mcuBuffer2.Buffer ();
+
+ mcuBuffer3.Allocate (info.imageWidth * mcuSize);
+ mcuBuffer4.Allocate (info.imageWidth * mcuSize);
+
+ mcuROW1 [0] = (ComponentType *) mcuBuffer3.Buffer ();
+ mcuROW2 [0] = (ComponentType *) mcuBuffer4.Buffer ();
+
+ for (int32 j = 1; j < info.imageWidth; j++)
+ {
+
+ mcuROW1 [j] = mcuROW1 [j - 1] + info.compsInScan;
+ mcuROW2 [j] = mcuROW2 [j - 1] + info.compsInScan;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * HuffDecoderInit --
+ *
+ * Initialize for a Huffman-compressed scan.
+ * This is invoked after reading the SOS marker.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::HuffDecoderInit ()
+ {
+
+ // Initialize bit parser state
+
+ getBuffer = 0;
+ bitsLeft = 0;
+
+ // Prepare Huffman tables.
+
+ for (int16 ci = 0; ci < info.compsInScan; ci++)
+ {
+
+ JpegComponentInfo *compptr = info.curCompInfo [ci];
+
+ // Make sure requested tables are present
+
+ if (compptr->dcTblNo < 0 || compptr->dcTblNo > 3)
+ {
+ ThrowBadFormat ();
+ }
+
+ if (info.dcHuffTblPtrs [compptr->dcTblNo] == NULL)
+ {
+ ThrowBadFormat ();
+ }
+
+ // Compute derived values for Huffman tables.
+ // We may do this more than once for same table, but it's not a
+ // big deal
+
+ FixHuffTbl (info.dcHuffTblPtrs [compptr->dcTblNo]);
+
+ }
+
+ // Initialize restart stuff
+
+ info.restartInRows = info.restartInterval / info.imageWidth;
+ info.restartRowsToGo = info.restartInRows;
+ info.nextRestartNum = 0;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ProcessRestart --
+ *
+ * Check for a restart marker & resynchronize decoder.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * BitStream is parsed, bit buffer is reset, etc.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::ProcessRestart ()
+ {
+
+ // Throw away and unused odd bits in the bit buffer.
+
+ fStream->SetReadPosition (fStream->Position () - bitsLeft / 8);
+
+ bitsLeft = 0;
+ getBuffer = 0;
+
+ // Scan for next JPEG marker
+
+ int32 c;
+
+ do
+ {
+
+ // skip any non-FF bytes
+
+ do
+ {
+ c = GetJpegChar ();
+ }
+ while (c != 0xFF);
+
+ // skip any duplicate FFs
+
+ do
+ {
+ c = GetJpegChar ();
+ }
+ while (c == 0xFF);
+
+ }
+ while (c == 0); // repeat if it was a stuffed FF/00
+
+ // Verify correct restart code.
+
+ if (c != (M_RST0 + info.nextRestartNum))
+ {
+ ThrowBadFormat ();
+ }
+
+ // Update restart state.
+
+ info.restartRowsToGo = info.restartInRows;
+ info.nextRestartNum = (info.nextRestartNum + 1) & 7;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * QuickPredict --
+ *
+ * Calculate the predictor for sample curRowBuf[col][curComp].
+ * It does not handle the special cases at image edges, such
+ * as first row and first column of a scan. We put the special
+ * case checkings outside so that the computations in main
+ * loop can be simpler. This has enhenced the performance
+ * significantly.
+ *
+ * Results:
+ * predictor is passed out.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline int32 dng_lossless_decoder::QuickPredict (int32 col,
+ int32 curComp,
+ MCU *curRowBuf,
+ MCU *prevRowBuf)
+ {
+
+ int32 diag = prevRowBuf [col - 1] [curComp];
+ int32 upper = prevRowBuf [col ] [curComp];
+ int32 left = curRowBuf [col - 1] [curComp];
+
+ switch (info.Ss)
+ {
+
+ case 0:
+ return 0;
+
+ case 1:
+ return left;
+
+ case 2:
+ return upper;
+
+ case 3:
+ return diag;
+
+ case 4:
+ return left + upper - diag;
+
+ case 5:
+ return left + ((upper - diag) >> 1);
+
+ case 6:
+ return upper + ((left - diag) >> 1);
+
+ case 7:
+ return (left + upper) >> 1;
+
+ default:
+ {
+ ThrowBadFormat ();
+ return 0;
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * FillBitBuffer --
+ *
+ * Load up the bit buffer with at least nbits
+ * Process any stuffed bytes at this time.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * The bitwise global variables are updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline void dng_lossless_decoder::FillBitBuffer (int32 nbits)
+ {
+
+ const int32 kMinGetBits = sizeof (uint32) * 8 - 7;
+
+ #if qSupportHasselblad_3FR
+
+ if (fHasselblad3FR)
+ {
+
+ while (bitsLeft < kMinGetBits)
+ {
+
+ int32 c0 = GetJpegChar ();
+ int32 c1 = GetJpegChar ();
+ int32 c2 = GetJpegChar ();
+ int32 c3 = GetJpegChar ();
+
+ getBuffer = (getBuffer << 8) | c3;
+ getBuffer = (getBuffer << 8) | c2;
+ getBuffer = (getBuffer << 8) | c1;
+ getBuffer = (getBuffer << 8) | c0;
+
+ bitsLeft += 32;
+
+ }
+
+ return;
+
+ }
+
+ #endif
+
+ while (bitsLeft < kMinGetBits)
+ {
+
+ int32 c = GetJpegChar ();
+
+ // If it's 0xFF, check and discard stuffed zero byte
+
+ if (c == 0xFF)
+ {
+
+ int32 c2 = GetJpegChar ();
+
+ if (c2 != 0)
+ {
+
+ // Oops, it's actually a marker indicating end of
+ // compressed data. Better put it back for use later.
+
+ UnGetJpegChar ();
+ UnGetJpegChar ();
+
+ // There should be enough bits still left in the data
+ // segment; if so, just break out of the while loop.
+
+ if (bitsLeft >= nbits)
+ break;
+
+ // Uh-oh. Corrupted data: stuff zeroes into the data
+ // stream, since this sometimes occurs when we are on the
+ // last show_bits8 during decoding of the Huffman
+ // segment.
+
+ c = 0;
+
+ }
+
+ }
+
+ getBuffer = (getBuffer << 8) | c;
+
+ bitsLeft += 8;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+inline int32 dng_lossless_decoder::show_bits8 ()
+ {
+
+ if (bitsLeft < 8)
+ FillBitBuffer (8);
+
+ return (int32) ((getBuffer >> (bitsLeft - 8)) & 0xff);
+
+ }
+
+/*****************************************************************************/
+
+inline void dng_lossless_decoder::flush_bits (int32 nbits)
+ {
+
+ bitsLeft -= nbits;
+
+ }
+
+/*****************************************************************************/
+
+inline int32 dng_lossless_decoder::get_bits (int32 nbits)
+ {
+
+ if (bitsLeft < nbits)
+ FillBitBuffer (nbits);
+
+ return (int32) ((getBuffer >> (bitsLeft -= nbits)) & (0x0FFFF >> (16 - nbits)));
+
+ }
+
+/*****************************************************************************/
+
+inline int32 dng_lossless_decoder::get_bit ()
+ {
+
+ if (!bitsLeft)
+ FillBitBuffer (1);
+
+ return (int32) ((getBuffer >> (--bitsLeft)) & 1);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * HuffDecode --
+ *
+ * Taken from Figure F.16: extract next coded symbol from
+ * input stream. This should becode a macro.
+ *
+ * Results:
+ * Next coded symbol
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline int32 dng_lossless_decoder::HuffDecode (HuffmanTable *htbl)
+ {
+
+ // If the huffman code is less than 8 bits, we can use the fast
+ // table lookup to get its value. It's more than 8 bits about
+ // 3-4% of the time.
+
+ int32 code = show_bits8 ();
+
+ if (htbl->numbits [code])
+ {
+
+ flush_bits (htbl->numbits [code]);
+
+ return htbl->value [code];
+
+ }
+
+ else
+ {
+
+ flush_bits (8);
+
+ int32 l = 8;
+
+ while (code > htbl->maxcode [l])
+ {
+ code = (code << 1) | get_bit ();
+ l++;
+ }
+
+ // With garbage input we may reach the sentinel value l = 17.
+
+ if (l > 16)
+ {
+ return 0; // fake a zero as the safest result
+ }
+ else
+ {
+ return htbl->huffval [htbl->valptr [l] +
+ ((int32) (code - htbl->mincode [l]))];
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * HuffExtend --
+ *
+ * Code and table for Figure F.12: extend sign bit
+ *
+ * Results:
+ * The extended value.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline void dng_lossless_decoder::HuffExtend (int32 &x, int32 s)
+ {
+
+ if (x < (0x08000 >> (16 - s)))
+ {
+ x += -(1 << s) + 1;
+ }
+
+ }
+
+/*****************************************************************************/
+
+// Called from DecodeImage () to write one row.
+
+void dng_lossless_decoder::PmPutRow (MCU *buf,
+ int32 numComp,
+ int32 numCol,
+ int32 /* row */)
+ {
+
+ uint16 *sPtr = &buf [0] [0];
+
+ uint32 pixels = numCol * numComp;
+
+ fSpooler->Spool (sPtr, pixels * (uint32) sizeof (uint16));
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * DecodeFirstRow --
+ *
+ * Decode the first raster line of samples at the start of
+ * the scan and at the beginning of each restart interval.
+ * This includes modifying the component value so the real
+ * value, not the difference is returned.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::DecodeFirstRow (MCU *curRowBuf)
+ {
+
+ int32 compsInScan = info.compsInScan;
+
+ // Process the first column in the row.
+
+ for (int32 curComp = 0; curComp < compsInScan; curComp++)
+ {
+
+ int32 ci = info.MCUmembership [curComp];
+
+ JpegComponentInfo *compptr = info.curCompInfo [ci];
+
+ HuffmanTable *dctbl = info.dcHuffTblPtrs [compptr->dcTblNo];
+
+ // Section F.2.2.1: decode the difference
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (dctbl);
+
+ if (s)
+ {
+
+ if (s == 16 && !fBug16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ // Add the predictor to the difference.
+
+ int32 Pr = info.dataPrecision;
+ int32 Pt = info.Pt;
+
+ curRowBuf [0] [curComp] = (ComponentType) (d + (1 << (Pr-Pt-1)));
+
+ }
+
+ // Process the rest of the row.
+
+ int32 numCOL = info.imageWidth;
+
+ for (int32 col = 1; col < numCOL; col++)
+ {
+
+ for (int32 curComp = 0; curComp < compsInScan; curComp++)
+ {
+
+ int32 ci = info.MCUmembership [curComp];
+
+ JpegComponentInfo *compptr = info.curCompInfo [ci];
+
+ HuffmanTable *dctbl = info.dcHuffTblPtrs [compptr->dcTblNo];
+
+ // Section F.2.2.1: decode the difference
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (dctbl);
+
+ if (s)
+ {
+
+ if (s == 16 && !fBug16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ // Add the predictor to the difference.
+
+ curRowBuf [col] [curComp] = (ComponentType) (d + curRowBuf [col-1] [curComp]);
+
+ }
+
+ }
+
+ // Update the restart counter
+
+ if (info.restartInRows)
+ {
+ info.restartRowsToGo--;
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * DecodeImage --
+ *
+ * Decode the input stream. This includes modifying
+ * the component value so the real value, not the
+ * difference is returned.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Bitstream is parsed.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_decoder::DecodeImage ()
+ {
+
+ #define swap(type,a,b) {type c; c=(a); (a)=(b); (b)=c;}
+
+ int32 numCOL = info.imageWidth;
+ int32 numROW = info.imageHeight;
+ int32 compsInScan = info.compsInScan;
+
+ // Precompute the decoding table for each table.
+
+ HuffmanTable *ht [4];
+
+ for (int32 curComp = 0; curComp < compsInScan; curComp++)
+ {
+
+ int32 ci = info.MCUmembership [curComp];
+
+ JpegComponentInfo *compptr = info.curCompInfo [ci];
+
+ ht [curComp] = info.dcHuffTblPtrs [compptr->dcTblNo];
+
+ }
+
+ MCU *prevRowBuf = mcuROW1;
+ MCU *curRowBuf = mcuROW2;
+
+ #if qSupportCanon_sRAW
+
+ // Canon sRAW support
+
+ if (info.compInfo [0].hSampFactor == 2 &&
+ info.compInfo [0].vSampFactor == 1)
+ {
+
+ for (int32 row = 0; row < numROW; row++)
+ {
+
+ // Initialize predictors.
+
+ int32 p0;
+ int32 p1;
+ int32 p2;
+
+ if (row == 0)
+ {
+ p0 = 1 << 14;
+ p1 = 1 << 14;
+ p2 = 1 << 14;
+ }
+
+ else
+ {
+ p0 = prevRowBuf [0] [0];
+ p1 = prevRowBuf [0] [1];
+ p2 = prevRowBuf [0] [2];
+ }
+
+ for (int32 col = 0; col < numCOL; col += 2)
+ {
+
+ // Read first luminance component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p0 += d;
+
+ curRowBuf [col] [0] = (ComponentType) p0;
+
+ }
+
+ // Read second luminance component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p0 += d;
+
+ curRowBuf [col + 1] [0] = (ComponentType) p0;
+
+ }
+
+ // Read first chroma component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [1]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p1 += d;
+
+ curRowBuf [col ] [1] = (ComponentType) p1;
+ curRowBuf [col + 1] [1] = (ComponentType) p1;
+
+ }
+
+ // Read second chroma component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [2]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p2 += d;
+
+ curRowBuf [col ] [2] = (ComponentType) p2;
+ curRowBuf [col + 1] [2] = (ComponentType) p2;
+
+ }
+
+ }
+
+ PmPutRow (curRowBuf, compsInScan, numCOL, row);
+
+ swap (MCU *, prevRowBuf, curRowBuf);
+
+ }
+
+ return;
+
+ }
+
+ if (info.compInfo [0].hSampFactor == 2 &&
+ info.compInfo [0].vSampFactor == 2)
+ {
+
+ for (int32 row = 0; row < numROW; row += 2)
+ {
+
+ // Initialize predictors.
+
+ int32 p0;
+ int32 p1;
+ int32 p2;
+
+ if (row == 0)
+ {
+ p0 = 1 << 14;
+ p1 = 1 << 14;
+ p2 = 1 << 14;
+ }
+
+ else
+ {
+ p0 = prevRowBuf [0] [0];
+ p1 = prevRowBuf [0] [1];
+ p2 = prevRowBuf [0] [2];
+ }
+
+ for (int32 col = 0; col < numCOL; col += 2)
+ {
+
+ // Read first luminance component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p0 += d;
+
+ prevRowBuf [col] [0] = (ComponentType) p0;
+
+ }
+
+ // Read second luminance component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p0 += d;
+
+ prevRowBuf [col + 1] [0] = (ComponentType) p0;
+
+ }
+
+ // Read third luminance component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p0 += d;
+
+ curRowBuf [col] [0] = (ComponentType) p0;
+
+ }
+
+ // Read fourth luminance component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p0 += d;
+
+ curRowBuf [col + 1] [0] = (ComponentType) p0;
+
+ }
+
+ // Read first chroma component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [1]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p1 += d;
+
+ prevRowBuf [col ] [1] = (ComponentType) p1;
+ prevRowBuf [col + 1] [1] = (ComponentType) p1;
+
+ curRowBuf [col ] [1] = (ComponentType) p1;
+ curRowBuf [col + 1] [1] = (ComponentType) p1;
+
+ }
+
+ // Read second chroma component.
+
+ {
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [2]);
+
+ if (s)
+ {
+
+ if (s == 16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ p2 += d;
+
+ prevRowBuf [col ] [2] = (ComponentType) p2;
+ prevRowBuf [col + 1] [2] = (ComponentType) p2;
+
+ curRowBuf [col ] [2] = (ComponentType) p2;
+ curRowBuf [col + 1] [2] = (ComponentType) p2;
+
+ }
+
+ }
+
+ PmPutRow (prevRowBuf, compsInScan, numCOL, row);
+ PmPutRow (curRowBuf, compsInScan, numCOL, row);
+
+ }
+
+ return;
+
+ }
+
+ #endif
+
+ #if qSupportHasselblad_3FR
+
+ if (info.Ss == 8)
+ {
+
+ fHasselblad3FR = true;
+
+ for (int32 row = 0; row < numROW; row++)
+ {
+
+ int32 p0 = 32768;
+ int32 p1 = 32768;
+
+ for (int32 col = 0; col < numCOL; col += 2)
+ {
+
+ int32 s0 = HuffDecode (ht [0]);
+ int32 s1 = HuffDecode (ht [0]);
+
+ if (s0)
+ {
+ int32 d = get_bits (s0);
+ if (s0 == 16)
+ {
+ d = -32768;
+ }
+ else
+ {
+ HuffExtend (d, s0);
+ }
+ p0 += d;
+ }
+
+ if (s1)
+ {
+ int32 d = get_bits (s1);
+ if (s1 == 16)
+ {
+ d = -32768;
+ }
+ else
+ {
+ HuffExtend (d, s1);
+ }
+ p1 += d;
+ }
+
+ curRowBuf [col ] [0] = (ComponentType) p0;
+ curRowBuf [col + 1] [0] = (ComponentType) p1;
+
+ }
+
+ PmPutRow (curRowBuf, compsInScan, numCOL, row);
+
+ }
+
+ return;
+
+ }
+
+ #endif
+
+ // Decode the first row of image. Output the row and
+ // turn this row into a previous row for later predictor
+ // calculation.
+
+ DecodeFirstRow (mcuROW1);
+
+ PmPutRow (mcuROW1, compsInScan, numCOL, 0);
+
+ // Process each row.
+
+ for (int32 row = 1; row < numROW; row++)
+ {
+
+ // Account for restart interval, process restart marker if needed.
+
+ if (info.restartInRows)
+ {
+
+ if (info.restartRowsToGo == 0)
+ {
+
+ ProcessRestart ();
+
+ // Reset predictors at restart.
+
+ DecodeFirstRow (curRowBuf);
+
+ PmPutRow (curRowBuf, compsInScan, numCOL, row);
+
+ swap (MCU *, prevRowBuf, curRowBuf);
+
+ continue;
+
+ }
+
+ info.restartRowsToGo--;
+
+ }
+
+ // The upper neighbors are predictors for the first column.
+
+ for (int32 curComp = 0; curComp < compsInScan; curComp++)
+ {
+
+ // Section F.2.2.1: decode the difference
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [curComp]);
+
+ if (s)
+ {
+
+ if (s == 16 && !fBug16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ // First column of row above is predictor for first column.
+
+ curRowBuf [0] [curComp] = (ComponentType) (d + prevRowBuf [0] [curComp]);
+
+ }
+
+ // For the rest of the column on this row, predictor
+ // calculations are based on PSV.
+
+ if (compsInScan == 2 && info.Ss == 1)
+ {
+
+ // This is the combination used by both the Canon and Kodak raw formats.
+ // Unrolling the general case logic results in a significant speed increase.
+
+ uint16 *dPtr = &curRowBuf [1] [0];
+
+ int32 prev0 = dPtr [-2];
+ int32 prev1 = dPtr [-1];
+
+ for (int32 col = 1; col < numCOL; col++)
+ {
+
+ int32 s = HuffDecode (ht [0]);
+
+ if (s)
+ {
+
+ int32 d;
+
+ if (s == 16 && !fBug16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ prev0 += d;
+
+ }
+
+ s = HuffDecode (ht [1]);
+
+ if (s)
+ {
+
+ int32 d;
+
+ if (s == 16 && !fBug16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ prev1 += d;
+
+ }
+
+ dPtr [0] = (uint16) prev0;
+ dPtr [1] = (uint16) prev1;
+
+ dPtr += 2;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (int32 col = 1; col < numCOL; col++)
+ {
+
+ for (int32 curComp = 0; curComp < compsInScan; curComp++)
+ {
+
+ // Section F.2.2.1: decode the difference
+
+ int32 d = 0;
+
+ int32 s = HuffDecode (ht [curComp]);
+
+ if (s)
+ {
+
+ if (s == 16 && !fBug16)
+ {
+ d = -32768;
+ }
+
+ else
+ {
+ d = get_bits (s);
+ HuffExtend (d, s);
+ }
+
+ }
+
+ // Predict the pixel value.
+
+ int32 predictor = QuickPredict (col,
+ curComp,
+ curRowBuf,
+ prevRowBuf);
+
+ // Save the difference.
+
+ curRowBuf [col] [curComp] = (ComponentType) (d + predictor);
+
+ }
+
+ }
+
+ }
+
+ PmPutRow (curRowBuf, compsInScan, numCOL, row);
+
+ swap (MCU *, prevRowBuf, curRowBuf);
+
+ }
+
+ #undef swap
+
+ }
+
+/*****************************************************************************/
+
+void dng_lossless_decoder::StartRead (uint32 &imageWidth,
+ uint32 &imageHeight,
+ uint32 &imageChannels)
+ {
+
+ ReadFileHeader ();
+ ReadScanHeader ();
+ DecoderStructInit ();
+ HuffDecoderInit ();
+
+ imageWidth = info.imageWidth;
+ imageHeight = info.imageHeight;
+ imageChannels = info.compsInScan;
+
+ }
+
+/*****************************************************************************/
+
+void dng_lossless_decoder::FinishRead ()
+ {
+
+ DecodeImage ();
+
+ }
+
+/*****************************************************************************/
+
+void DecodeLosslessJPEG (dng_stream &stream,
+ dng_spooler &spooler,
+ uint32 minDecodedSize,
+ uint32 maxDecodedSize,
+ bool bug16)
+ {
+
+ dng_lossless_decoder decoder (&stream,
+ &spooler,
+ bug16);
+
+ uint32 imageWidth;
+ uint32 imageHeight;
+ uint32 imageChannels;
+
+ decoder.StartRead (imageWidth,
+ imageHeight,
+ imageChannels);
+
+ uint32 decodedSize = imageWidth *
+ imageHeight *
+ imageChannels *
+ (uint32) sizeof (uint16);
+
+ if (decodedSize < minDecodedSize ||
+ decodedSize > maxDecodedSize)
+ {
+ ThrowBadFormat ();
+ }
+
+ decoder.FinishRead ();
+
+ }
+
+/*****************************************************************************/
+
+class dng_lossless_encoder
+ {
+
+ private:
+
+ const uint16 *fSrcData;
+
+ uint32 fSrcRows;
+ uint32 fSrcCols;
+ uint32 fSrcChannels;
+ uint32 fSrcBitDepth;
+
+ int32 fSrcRowStep;
+ int32 fSrcColStep;
+
+ dng_stream &fStream;
+
+ HuffmanTable huffTable [4];
+
+ uint32 freqCount [4] [257];
+
+ // Current bit-accumulation buffer
+
+ int32 huffPutBuffer;
+ int32 huffPutBits;
+
+ // Lookup table for number of bits in an 8 bit value.
+
+ int numBitsTable [256];
+
+ public:
+
+ dng_lossless_encoder (const uint16 *srcData,
+ uint32 srcRows,
+ uint32 srcCols,
+ uint32 srcChannels,
+ uint32 srcBitDepth,
+ int32 srcRowStep,
+ int32 srcColStep,
+ dng_stream &stream);
+
+ void Encode ();
+
+ private:
+
+ void EmitByte (uint8 value);
+
+ void EmitBits (int code, int size);
+
+ void FlushBits ();
+
+ void CountOneDiff (int diff, uint32 *countTable);
+
+ void EncodeOneDiff (int diff, HuffmanTable *dctbl);
+
+ void FreqCountSet ();
+
+ void HuffEncode ();
+
+ void GenHuffCoding (HuffmanTable *htbl, uint32 *freq);
+
+ void HuffOptimize ();
+
+ void EmitMarker (JpegMarker mark);
+
+ void Emit2bytes (int value);
+
+ void EmitDht (int index);
+
+ void EmitSof (JpegMarker code);
+
+ void EmitSos ();
+
+ void WriteFileHeader ();
+
+ void WriteScanHeader ();
+
+ void WriteFileTrailer ();
+
+ };
+
+/*****************************************************************************/
+
+dng_lossless_encoder::dng_lossless_encoder (const uint16 *srcData,
+ uint32 srcRows,
+ uint32 srcCols,
+ uint32 srcChannels,
+ uint32 srcBitDepth,
+ int32 srcRowStep,
+ int32 srcColStep,
+ dng_stream &stream)
+
+ : fSrcData (srcData )
+ , fSrcRows (srcRows )
+ , fSrcCols (srcCols )
+ , fSrcChannels (srcChannels)
+ , fSrcBitDepth (srcBitDepth)
+ , fSrcRowStep (srcRowStep )
+ , fSrcColStep (srcColStep )
+ , fStream (stream )
+
+ , huffPutBuffer (0)
+ , huffPutBits (0)
+
+ {
+
+ // Initialize number of bits lookup table.
+
+ numBitsTable [0] = 0;
+
+ for (int i = 1; i < 256; i++)
+ {
+
+ int temp = i;
+ int nbits = 1;
+
+ while (temp >>= 1)
+ {
+ nbits++;
+ }
+
+ numBitsTable [i] = nbits;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+inline void dng_lossless_encoder::EmitByte (uint8 value)
+ {
+
+ fStream.Put_uint8 (value);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmitBits --
+ *
+ * Code for outputting bits to the file
+ *
+ * Only the right 24 bits of huffPutBuffer are used; the valid
+ * bits are left-justified in this part. At most 16 bits can be
+ * passed to EmitBits in one call, and we never retain more than 7
+ * bits in huffPutBuffer between calls, so 24 bits are
+ * sufficient.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * huffPutBuffer and huffPutBits are updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline void dng_lossless_encoder::EmitBits (int code, int size)
+ {
+
+ DNG_ASSERT (size != 0, "Bad Huffman table entry");
+
+ int putBits = size;
+ int putBuffer = code;
+
+ putBits += huffPutBits;
+
+ putBuffer <<= 24 - putBits;
+ putBuffer |= huffPutBuffer;
+
+ while (putBits >= 8)
+ {
+
+ uint8 c = (uint8) (putBuffer >> 16);
+
+ // Output whole bytes we've accumulated with byte stuffing
+
+ EmitByte (c);
+
+ if (c == 0xFF)
+ {
+ EmitByte (0);
+ }
+
+ putBuffer <<= 8;
+ putBits -= 8;
+
+ }
+
+ huffPutBuffer = putBuffer;
+ huffPutBits = putBits;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * FlushBits --
+ *
+ * Flush any remaining bits in the bit buffer. Used before emitting
+ * a marker.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * huffPutBuffer and huffPutBits are reset
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::FlushBits ()
+ {
+
+ // The first call forces output of any partial bytes.
+
+ EmitBits (0x007F, 7);
+
+ // We can then zero the buffer.
+
+ huffPutBuffer = 0;
+ huffPutBits = 0;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * CountOneDiff --
+ *
+ * Count the difference value in countTable.
+ *
+ * Results:
+ * diff is counted in countTable.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline void dng_lossless_encoder::CountOneDiff (int diff, uint32 *countTable)
+ {
+
+ // Encode the DC coefficient difference per section F.1.2.1
+
+ int temp = diff;
+
+ if (temp < 0)
+ {
+
+ temp = -temp;
+
+ }
+
+ // Find the number of bits needed for the magnitude of the coefficient
+
+ int nbits = temp >= 256 ? numBitsTable [temp >> 8 ] + 8
+ : numBitsTable [temp & 0xFF];
+
+ // Update count for this bit length
+
+ countTable [nbits] ++;
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EncodeOneDiff --
+ *
+ * Encode a single difference value.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+inline void dng_lossless_encoder::EncodeOneDiff (int diff, HuffmanTable *dctbl)
+ {
+
+ // Encode the DC coefficient difference per section F.1.2.1
+
+ int temp = diff;
+ int temp2 = diff;
+
+ if (temp < 0)
+ {
+
+ temp = -temp;
+
+ // For a negative input, want temp2 = bitwise complement of
+ // abs (input). This code assumes we are on a two's complement
+ // machine.
+
+ temp2--;
+
+ }
+
+ // Find the number of bits needed for the magnitude of the coefficient
+
+ int nbits = temp >= 256 ? numBitsTable [temp >> 8 ] + 8
+ : numBitsTable [temp & 0xFF];
+
+ // Emit the Huffman-coded symbol for the number of bits
+
+ EmitBits (dctbl->ehufco [nbits],
+ dctbl->ehufsi [nbits]);
+
+ // Emit that number of bits of the value, if positive,
+ // or the complement of its magnitude, if negative.
+
+ // If the number of bits is 16, there is only one possible difference
+ // value (-32786), so the lossless JPEG spec says not to output anything
+ // in that case. So we only need to output the diference value if
+ // the number of bits is between 1 and 15.
+
+ if (nbits & 15)
+ {
+
+ EmitBits (temp2 & (0x0FFFF >> (16 - nbits)),
+ nbits);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * FreqCountSet --
+ *
+ * Count the times each category symbol occurs in this image.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The freqCount has counted all category
+ * symbols appeared in the image.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::FreqCountSet ()
+ {
+
+ memset (freqCount, 0, sizeof (freqCount));
+
+ DNG_ASSERT ((int32)fSrcRows >= 0, "dng_lossless_encoder::FreqCountSet: fSrcRpws too large.");
+
+ for (int32 row = 0; row < (int32)fSrcRows; row++)
+ {
+
+ const uint16 *sPtr = fSrcData + row * fSrcRowStep;
+
+ // Initialize predictors for this row.
+
+ int32 predictor [4];
+
+ for (int32 channel = 0; channel < (int32)fSrcChannels; channel++)
+ {
+
+ if (row == 0)
+ predictor [channel] = 1 << (fSrcBitDepth - 1);
+
+ else
+ predictor [channel] = sPtr [channel - fSrcRowStep];
+
+ }
+
+ // Unroll most common case of two channels
+
+ if (fSrcChannels == 2)
+ {
+
+ int32 pred0 = predictor [0];
+ int32 pred1 = predictor [1];
+
+ uint32 srcCols = fSrcCols;
+ int32 srcColStep = fSrcColStep;
+
+ for (uint32 col = 0; col < srcCols; col++)
+ {
+
+ int32 pixel0 = sPtr [0];
+ int32 pixel1 = sPtr [1];
+
+ int16 diff0 = (int16) (pixel0 - pred0);
+ int16 diff1 = (int16) (pixel1 - pred1);
+
+ CountOneDiff (diff0, freqCount [0]);
+ CountOneDiff (diff1, freqCount [1]);
+
+ pred0 = pixel0;
+ pred1 = pixel1;
+
+ sPtr += srcColStep;
+
+ }
+
+ }
+
+ // General case.
+
+ else
+ {
+
+ for (uint32 col = 0; col < fSrcCols; col++)
+ {
+
+ for (uint32 channel = 0; channel < fSrcChannels; channel++)
+ {
+
+ int32 pixel = sPtr [channel];
+
+ int16 diff = (int16) (pixel - predictor [channel]);
+
+ CountOneDiff (diff, freqCount [channel]);
+
+ predictor [channel] = pixel;
+
+ }
+
+ sPtr += fSrcColStep;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * HuffEncode --
+ *
+ * Encode and output Huffman-compressed image data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::HuffEncode ()
+ {
+
+ DNG_ASSERT ((int32)fSrcRows >= 0, "dng_lossless_encoder::HuffEncode: fSrcRows too large.");
+
+ for (int32 row = 0; row < (int32)fSrcRows; row++)
+ {
+
+ const uint16 *sPtr = fSrcData + row * fSrcRowStep;
+
+ // Initialize predictors for this row.
+
+ int32 predictor [4];
+
+ for (int32 channel = 0; channel < (int32)fSrcChannels; channel++)
+ {
+
+ if (row == 0)
+ predictor [channel] = 1 << (fSrcBitDepth - 1);
+
+ else
+ predictor [channel] = sPtr [channel - fSrcRowStep];
+
+ }
+
+ // Unroll most common case of two channels
+
+ if (fSrcChannels == 2)
+ {
+
+ int32 pred0 = predictor [0];
+ int32 pred1 = predictor [1];
+
+ uint32 srcCols = fSrcCols;
+ int32 srcColStep = fSrcColStep;
+
+ for (uint32 col = 0; col < srcCols; col++)
+ {
+
+ int32 pixel0 = sPtr [0];
+ int32 pixel1 = sPtr [1];
+
+ int16 diff0 = (int16) (pixel0 - pred0);
+ int16 diff1 = (int16) (pixel1 - pred1);
+
+ EncodeOneDiff (diff0, &huffTable [0]);
+ EncodeOneDiff (diff1, &huffTable [1]);
+
+ pred0 = pixel0;
+ pred1 = pixel1;
+
+ sPtr += srcColStep;
+
+ }
+
+ }
+
+ // General case.
+
+ else
+ {
+
+ for (uint32 col = 0; col < fSrcCols; col++)
+ {
+
+ for (uint32 channel = 0; channel < fSrcChannels; channel++)
+ {
+
+ int32 pixel = sPtr [channel];
+
+ int16 diff = (int16) (pixel - predictor [channel]);
+
+ EncodeOneDiff (diff, &huffTable [channel]);
+
+ predictor [channel] = pixel;
+
+ }
+
+ sPtr += fSrcColStep;
+
+ }
+
+ }
+
+ }
+
+ FlushBits ();
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * GenHuffCoding --
+ *
+ * Generate the optimal coding for the given counts.
+ * This algorithm is explained in section K.2 of the
+ * JPEG standard.
+ *
+ * Results:
+ * htbl->bits and htbl->huffval are constructed.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::GenHuffCoding (HuffmanTable *htbl, uint32 *freq)
+ {
+
+ int i;
+ int j;
+
+ const int MAX_CLEN = 32; // assumed maximum initial code length
+
+ uint8 bits [MAX_CLEN + 1]; // bits [k] = # of symbols with code length k
+ short codesize [257]; // codesize [k] = code length of symbol k
+ short others [257]; // next symbol in current branch of tree
+
+ memset (bits , 0, sizeof (bits ));
+ memset (codesize, 0, sizeof (codesize));
+
+ for (i = 0; i < 257; i++)
+ others [i] = -1; // init links to empty
+
+ // Including the pseudo-symbol 256 in the Huffman procedure guarantees
+ // that no real symbol is given code-value of all ones, because 256
+ // will be placed in the largest codeword category.
+
+ freq [256] = 1; // make sure there is a nonzero count
+
+ // Huffman's basic algorithm to assign optimal code lengths to symbols
+
+ while (true)
+ {
+
+ // Find the smallest nonzero frequency, set c1 = its symbol.
+ // In case of ties, take the larger symbol number.
+
+ int c1 = -1;
+
+ uint32 v = 0xFFFFFFFF;
+
+ for (i = 0; i <= 256; i++)
+ {
+
+ if (freq [i] && freq [i] <= v)
+ {
+ v = freq [i];
+ c1 = i;
+ }
+
+ }
+
+ // Find the next smallest nonzero frequency, set c2 = its symbol.
+ // In case of ties, take the larger symbol number.
+
+ int c2 = -1;
+
+ v = 0xFFFFFFFF;
+
+ for (i = 0; i <= 256; i++)
+ {
+
+ if (freq [i] && freq [i] <= v && i != c1)
+ {
+ v = freq [i];
+ c2 = i;
+ }
+
+ }
+
+ // Done if we've merged everything into one frequency.
+
+ if (c2 < 0)
+ break;
+
+ // Else merge the two counts/trees.
+
+ freq [c1] += freq [c2];
+ freq [c2] = 0;
+
+ // Increment the codesize of everything in c1's tree branch.
+
+ codesize [c1] ++;
+
+ while (others [c1] >= 0)
+ {
+ c1 = others [c1];
+ codesize [c1] ++;
+ }
+
+ // chain c2 onto c1's tree branch
+
+ others [c1] = (short) c2;
+
+ // Increment the codesize of everything in c2's tree branch.
+
+ codesize [c2] ++;
+
+ while (others [c2] >= 0)
+ {
+ c2 = others [c2];
+ codesize [c2] ++;
+ }
+
+ }
+
+ // Now count the number of symbols of each code length.
+
+ for (i = 0; i <= 256; i++)
+ {
+
+ if (codesize [i])
+ {
+
+ // The JPEG standard seems to think that this can't happen,
+ // but I'm paranoid...
+
+ if (codesize [i] > MAX_CLEN)
+ {
+
+ DNG_REPORT ("Huffman code size table overflow");
+
+ ThrowProgramError ();
+
+ }
+
+ bits [codesize [i]]++;
+
+ }
+
+ }
+
+ // JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
+ // Huffman procedure assigned any such lengths, we must adjust the coding.
+ // Here is what the JPEG spec says about how this next bit works:
+ // Since symbols are paired for the longest Huffman code, the symbols are
+ // removed from this length category two at a time. The prefix for the pair
+ // (which is one bit shorter) is allocated to one of the pair; then,
+ // skipping the BITS entry for that prefix length, a code word from the next
+ // shortest nonzero BITS entry is converted into a prefix for two code words
+ // one bit longer.
+
+ for (i = MAX_CLEN; i > 16; i--)
+ {
+
+ while (bits [i] > 0)
+ {
+
+ // Kludge: I have never been able to test this logic, and there
+ // are comments on the web that this encoder has bugs with 16-bit
+ // data, so just throw an error if we get here and revert to a
+ // default table. - tknoll 12/1/03.
+
+ DNG_REPORT ("Info: Optimal huffman table bigger than 16 bits");
+
+ ThrowProgramError ();
+
+ // Original logic:
+
+ j = i - 2; // find length of new prefix to be used
+
+ while (bits [j] == 0)
+ j--;
+
+ bits [i ] -= 2; // remove two symbols
+ bits [i - 1] ++; // one goes in this length
+ bits [j + 1] += 2; // two new symbols in this length
+ bits [j ] --; // symbol of this length is now a prefix
+
+ }
+
+ }
+
+ // Remove the count for the pseudo-symbol 256 from
+ // the largest codelength.
+
+ while (bits [i] == 0) // find largest codelength still in use
+ i--;
+
+ bits [i] --;
+
+ // Return final symbol counts (only for lengths 0..16).
+
+ memcpy (htbl->bits, bits, sizeof (htbl->bits));
+
+ // Return a list of the symbols sorted by code length.
+ // It's not real clear to me why we don't need to consider the codelength
+ // changes made above, but the JPEG spec seems to think this works.
+
+ int p = 0;
+
+ for (i = 1; i <= MAX_CLEN; i++)
+ {
+
+ for (j = 0; j <= 255; j++)
+ {
+
+ if (codesize [j] == i)
+ {
+ htbl->huffval [p] = (uint8) j;
+ p++;
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * HuffOptimize --
+ *
+ * Find the best coding parameters for a Huffman-coded scan.
+ * When called, the scan data has already been converted to
+ * a sequence of MCU groups of source image samples, which
+ * are stored in a "big" array, mcuTable.
+ *
+ * It counts the times each category symbol occurs. Based on
+ * this counting, optimal Huffman tables are built. Then it
+ * uses this optimal Huffman table and counting table to find
+ * the best PSV.
+ *
+ * Results:
+ * Optimal Huffman tables are retured in cPtr->dcHuffTblPtrs[tbl].
+ * Best PSV is retured in cPtr->Ss.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::HuffOptimize ()
+ {
+
+ // Collect the frequency counts.
+
+ FreqCountSet ();
+
+ // Generate Huffman encoding tables.
+
+ for (uint32 channel = 0; channel < fSrcChannels; channel++)
+ {
+
+ try
+ {
+
+ GenHuffCoding (&huffTable [channel], freqCount [channel]);
+
+ }
+
+ catch (...)
+ {
+
+ DNG_REPORT ("Info: Reverting to default huffman table");
+
+ for (uint32 j = 0; j <= 256; j++)
+ {
+
+ freqCount [channel] [j] = (j <= 16 ? 1 : 0);
+
+ }
+
+ GenHuffCoding (&huffTable [channel], freqCount [channel]);
+
+ }
+
+ FixHuffTbl (&huffTable [channel]);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmitMarker --
+ *
+ * Emit a marker code into the output stream.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::EmitMarker (JpegMarker mark)
+ {
+
+ EmitByte (0xFF);
+ EmitByte ((uint8) mark);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Emit2bytes --
+ *
+ * Emit a 2-byte integer; these are always MSB first in JPEG
+ * files
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::Emit2bytes (int value)
+ {
+
+ EmitByte ((value >> 8) & 0xFF);
+ EmitByte (value & 0xFF);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmitDht --
+ *
+ * Emit a DHT marker, follwed by the huffman data.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::EmitDht (int index)
+ {
+
+ int i;
+
+ HuffmanTable *htbl = &huffTable [index];
+
+ EmitMarker (M_DHT);
+
+ int length = 0;
+
+ for (i = 1; i <= 16; i++)
+ length += htbl->bits [i];
+
+ Emit2bytes (length + 2 + 1 + 16);
+
+ EmitByte ((uint8) index);
+
+ for (i = 1; i <= 16; i++)
+ EmitByte (htbl->bits [i]);
+
+ for (i = 0; i < length; i++)
+ EmitByte (htbl->huffval [i]);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmitSof --
+ *
+ * Emit a SOF marker plus data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::EmitSof (JpegMarker code)
+ {
+
+ EmitMarker (code);
+
+ Emit2bytes (3 * fSrcChannels + 2 + 5 + 1); // length
+
+ EmitByte ((uint8) fSrcBitDepth);
+
+ Emit2bytes (fSrcRows);
+ Emit2bytes (fSrcCols);
+
+ EmitByte ((uint8) fSrcChannels);
+
+ for (uint32 i = 0; i < fSrcChannels; i++)
+ {
+
+ EmitByte ((uint8) i);
+
+ EmitByte ((uint8) ((1 << 4) + 1)); // Not subsampled.
+
+ EmitByte (0); // Tq shall be 0 for lossless.
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmitSos --
+ *
+ * Emit a SOS marker plus data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::EmitSos ()
+ {
+
+ EmitMarker (M_SOS);
+
+ Emit2bytes (2 * fSrcChannels + 2 + 1 + 3); // length
+
+ EmitByte ((uint8) fSrcChannels); // Ns
+
+ for (uint32 i = 0; i < fSrcChannels; i++)
+ {
+
+ // Cs,Td,Ta
+
+ EmitByte ((uint8) i);
+ EmitByte ((uint8) (i << 4));
+
+ }
+
+ EmitByte (1); // PSV - hardcoded - tknoll
+ EmitByte (0); // Spectral selection end - Se
+ EmitByte (0); // The point transform parameter
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * WriteFileHeader --
+ *
+ * Write the file header.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::WriteFileHeader ()
+ {
+
+ EmitMarker (M_SOI); // first the SOI
+
+ EmitSof (M_SOF3);
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * WriteScanHeader --
+ *
+ * Write the start of a scan (everything through the SOS marker).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::WriteScanHeader ()
+ {
+
+ // Emit Huffman tables.
+
+ for (uint32 i = 0; i < fSrcChannels; i++)
+ {
+
+ EmitDht (i);
+
+ }
+
+ EmitSos ();
+
+ }
+
+/*****************************************************************************/
+
+/*
+ *--------------------------------------------------------------
+ *
+ * WriteFileTrailer --
+ *
+ * Write the End of image marker at the end of a JPEG file.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+void dng_lossless_encoder::WriteFileTrailer ()
+ {
+
+ EmitMarker (M_EOI);
+
+ }
+
+/*****************************************************************************/
+
+void dng_lossless_encoder::Encode ()
+ {
+
+ DNG_ASSERT (fSrcChannels <= 4, "Too many components in scan");
+
+ // Count the times each difference category occurs.
+ // Construct the optimal Huffman table.
+
+ HuffOptimize ();
+
+ // Write the frame and scan headers.
+
+ WriteFileHeader ();
+
+ WriteScanHeader ();
+
+ // Encode the image.
+
+ HuffEncode ();
+
+ // Clean up everything.
+
+ WriteFileTrailer ();
+
+ }
+
+/*****************************************************************************/
+
+void EncodeLosslessJPEG (const uint16 *srcData,
+ uint32 srcRows,
+ uint32 srcCols,
+ uint32 srcChannels,
+ uint32 srcBitDepth,
+ int32 srcRowStep,
+ int32 srcColStep,
+ dng_stream &stream)
+ {
+
+ dng_lossless_encoder encoder (srcData,
+ srcRows,
+ srcCols,
+ srcChannels,
+ srcBitDepth,
+ srcRowStep,
+ srcColStep,
+ stream);
+
+ encoder.Encode ();
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_lossless_jpeg.h b/gpr/source/lib/dng_sdk/dng_lossless_jpeg.h
new file mode 100644
index 0000000..be8bb50
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_lossless_jpeg.h
@@ -0,0 +1,69 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_lossless_jpeg.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Functions for encoding and decoding lossless JPEG format.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_lossless_jpeg__
+#define __dng_lossless_jpeg__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_spooler
+ {
+
+ protected:
+
+ virtual ~dng_spooler ()
+ {
+ }
+
+ public:
+
+ virtual void Spool (const void *data,
+ uint32 count) = 0;
+
+ };
+
+/*****************************************************************************/
+
+void DecodeLosslessJPEG (dng_stream &stream,
+ dng_spooler &spooler,
+ uint32 minDecodedSize,
+ uint32 maxDecodedSize,
+ bool bug16);
+
+/*****************************************************************************/
+
+void EncodeLosslessJPEG (const uint16 *srcData,
+ uint32 srcRows,
+ uint32 srcCols,
+ uint32 srcChannels,
+ uint32 srcBitDepth,
+ int32 srcRowStep,
+ int32 srcColStep,
+ dng_stream &stream);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_matrix.cpp b/gpr/source/lib/dng_sdk/dng_matrix.cpp
new file mode 100644
index 0000000..b96f80b
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_matrix.cpp
@@ -0,0 +1,1080 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_matrix.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_matrix.h"
+
+#include "dng_exceptions.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_matrix::dng_matrix ()
+
+ : fRows (0)
+ , fCols (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix::dng_matrix (uint32 rows,
+ uint32 cols)
+
+ : fRows (0)
+ , fCols (0)
+
+ {
+
+ if (rows < 1 || rows > kMaxColorPlanes ||
+ cols < 1 || cols > kMaxColorPlanes)
+ {
+
+ ThrowProgramError ();
+
+ }
+
+ fRows = rows;
+ fCols = cols;
+
+ for (uint32 row = 0; row < fRows; row++)
+ for (uint32 col = 0; col < fCols; col++)
+ {
+
+ fData [row] [col] = 0.0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix::dng_matrix (const dng_matrix &m)
+
+ : fRows (m.fRows)
+ , fCols (m.fCols)
+
+ {
+
+ for (uint32 row = 0; row < fRows; row++)
+ for (uint32 col = 0; col < fCols; col++)
+ {
+
+ fData [row] [col] = m.fData [row] [col];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_matrix::Clear ()
+ {
+
+ fRows = 0;
+ fCols = 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_matrix::SetIdentity (uint32 count)
+ {
+
+ *this = dng_matrix (count, count);
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ fData [j] [j] = 1.0;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+bool dng_matrix::operator== (const dng_matrix &m) const
+ {
+
+ if (Rows () != m.Rows () ||
+ Cols () != m.Cols ())
+ {
+
+ return false;
+
+ }
+
+ for (uint32 j = 0; j < Rows (); j++)
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ if (fData [j] [k] != m.fData [j] [k])
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+bool dng_matrix::IsDiagonal () const
+ {
+
+ if (IsEmpty ())
+ {
+ return false;
+ }
+
+ if (Rows () != Cols ())
+ {
+ return false;
+ }
+
+ for (uint32 j = 0; j < Rows (); j++)
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ if (j != k)
+ {
+
+ if (fData [j] [k] != 0.0)
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+real64 dng_matrix::MaxEntry () const
+ {
+
+ if (IsEmpty ())
+ {
+
+ return 0.0;
+
+ }
+
+ real64 m = fData [0] [0];
+
+ for (uint32 j = 0; j < Rows (); j++)
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ m = Max_real64 (m, fData [j] [k]);
+
+ }
+
+ return m;
+
+ }
+
+/******************************************************************************/
+
+real64 dng_matrix::MinEntry () const
+ {
+
+ if (IsEmpty ())
+ {
+
+ return 0.0;
+
+ }
+
+ real64 m = fData [0] [0];
+
+ for (uint32 j = 0; j < Rows (); j++)
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ m = Min_real64 (m, fData [j] [k]);
+
+ }
+
+ return m;
+
+ }
+
+/*****************************************************************************/
+
+void dng_matrix::Scale (real64 factor)
+ {
+
+ for (uint32 j = 0; j < Rows (); j++)
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ fData [j] [k] *= factor;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_matrix::Round (real64 factor)
+ {
+
+ real64 invFactor = 1.0 / factor;
+
+ for (uint32 j = 0; j < Rows (); j++)
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ fData [j] [k] = Round_int32 (fData [j] [k] * factor) * invFactor;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_matrix::SafeRound (real64 factor)
+ {
+
+ real64 invFactor = 1.0 / factor;
+
+ for (uint32 j = 0; j < Rows (); j++)
+ {
+
+ // Round each row to the specified accuracy, but make sure the
+ // a rounding does not affect the total of the elements in a row
+ // more than necessary.
+
+ real64 error = 0.0;
+
+ for (uint32 k = 0; k < Cols (); k++)
+ {
+
+ fData [j] [k] += error;
+
+ real64 rounded = Round_int32 (fData [j] [k] * factor) * invFactor;
+
+ error = fData [j] [k] - rounded;
+
+ fData [j] [k] = rounded;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix_3by3::dng_matrix_3by3 ()
+
+ : dng_matrix (3, 3)
+
+ {
+ }
+
+/*****************************************************************************/
+
+dng_matrix_3by3::dng_matrix_3by3 (const dng_matrix &m)
+
+ : dng_matrix (m)
+
+ {
+
+ if (Rows () != 3 ||
+ Cols () != 3)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a01, real64 a02,
+ real64 a10, real64 a11, real64 a12,
+ real64 a20, real64 a21, real64 a22)
+
+
+ : dng_matrix (3, 3)
+
+ {
+
+ fData [0] [0] = a00;
+ fData [0] [1] = a01;
+ fData [0] [2] = a02;
+
+ fData [1] [0] = a10;
+ fData [1] [1] = a11;
+ fData [1] [2] = a12;
+
+ fData [2] [0] = a20;
+ fData [2] [1] = a21;
+ fData [2] [2] = a22;
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a11, real64 a22)
+
+ : dng_matrix (3, 3)
+
+ {
+
+ fData [0] [0] = a00;
+ fData [1] [1] = a11;
+ fData [2] [2] = a22;
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix_4by3::dng_matrix_4by3 ()
+
+ : dng_matrix (4, 3)
+
+ {
+ }
+
+/*****************************************************************************/
+
+dng_matrix_4by3::dng_matrix_4by3 (const dng_matrix &m)
+
+ : dng_matrix (m)
+
+ {
+
+ if (Rows () != 4 ||
+ Cols () != 3)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix_4by3::dng_matrix_4by3 (real64 a00, real64 a01, real64 a02,
+ real64 a10, real64 a11, real64 a12,
+ real64 a20, real64 a21, real64 a22,
+ real64 a30, real64 a31, real64 a32)
+
+
+ : dng_matrix (4, 3)
+
+ {
+
+ fData [0] [0] = a00;
+ fData [0] [1] = a01;
+ fData [0] [2] = a02;
+
+ fData [1] [0] = a10;
+ fData [1] [1] = a11;
+ fData [1] [2] = a12;
+
+ fData [2] [0] = a20;
+ fData [2] [1] = a21;
+ fData [2] [2] = a22;
+
+ fData [3] [0] = a30;
+ fData [3] [1] = a31;
+ fData [3] [2] = a32;
+
+ }
+
+/*****************************************************************************/
+
+dng_vector::dng_vector ()
+
+ : fCount (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_vector::dng_vector (uint32 count)
+
+ : fCount (0)
+
+ {
+
+ if (count < 1 || count > kMaxColorPlanes)
+ {
+
+ ThrowProgramError ();
+
+ }
+
+ fCount = count;
+
+ for (uint32 index = 0; index < fCount; index++)
+ {
+
+ fData [index] = 0.0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_vector::dng_vector (const dng_vector &v)
+
+ : fCount (v.fCount)
+
+ {
+
+ for (uint32 index = 0; index < fCount; index++)
+ {
+
+ fData [index] = v.fData [index];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_vector::Clear ()
+ {
+
+ fCount = 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_vector::SetIdentity (uint32 count)
+ {
+
+ *this = dng_vector (count);
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ fData [j] = 1.0;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+bool dng_vector::operator== (const dng_vector &v) const
+ {
+
+ if (Count () != v.Count ())
+ {
+
+ return false;
+
+ }
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ if (fData [j] != v.fData [j])
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+real64 dng_vector::MaxEntry () const
+ {
+
+ if (IsEmpty ())
+ {
+
+ return 0.0;
+
+ }
+
+ real64 m = fData [0];
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ m = Max_real64 (m, fData [j]);
+
+ }
+
+ return m;
+
+ }
+
+/******************************************************************************/
+
+real64 dng_vector::MinEntry () const
+ {
+
+ if (IsEmpty ())
+ {
+
+ return 0.0;
+
+ }
+
+ real64 m = fData [0];
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ m = Min_real64 (m, fData [j]);
+
+ }
+
+ return m;
+
+ }
+
+/*****************************************************************************/
+
+void dng_vector::Scale (real64 factor)
+ {
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ fData [j] *= factor;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_vector::Round (real64 factor)
+ {
+
+ real64 invFactor = 1.0 / factor;
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ fData [j] = Round_int32 (fData [j] * factor) * invFactor;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix dng_vector::AsDiagonal () const
+ {
+
+ dng_matrix M (Count (), Count ());
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ M [j] [j] = fData [j];
+
+ }
+
+ return M;
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix dng_vector::AsColumn () const
+ {
+
+ dng_matrix M (Count (), 1);
+
+ for (uint32 j = 0; j < Count (); j++)
+ {
+
+ M [j] [0] = fData [j];
+
+ }
+
+ return M;
+
+ }
+
+/******************************************************************************/
+
+dng_vector_3::dng_vector_3 ()
+
+ : dng_vector (3)
+
+ {
+ }
+
+/******************************************************************************/
+
+dng_vector_3::dng_vector_3 (const dng_vector &v)
+
+ : dng_vector (v)
+
+ {
+
+ if (Count () != 3)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ }
+
+/******************************************************************************/
+
+dng_vector_3::dng_vector_3 (real64 a0,
+ real64 a1,
+ real64 a2)
+
+ : dng_vector (3)
+
+ {
+
+ fData [0] = a0;
+ fData [1] = a1;
+ fData [2] = a2;
+
+ }
+
+/******************************************************************************/
+
+dng_vector_4::dng_vector_4 ()
+
+ : dng_vector (4)
+
+ {
+ }
+
+/******************************************************************************/
+
+dng_vector_4::dng_vector_4 (const dng_vector &v)
+
+ : dng_vector (v)
+
+ {
+
+ if (Count () != 4)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ }
+
+/******************************************************************************/
+
+dng_vector_4::dng_vector_4 (real64 a0,
+ real64 a1,
+ real64 a2,
+ real64 a3)
+
+ : dng_vector (4)
+
+ {
+
+ fData [0] = a0;
+ fData [1] = a1;
+ fData [2] = a2;
+ fData [3] = a3;
+
+ }
+
+/******************************************************************************/
+
+dng_matrix operator* (const dng_matrix &A,
+ const dng_matrix &B)
+ {
+
+ if (A.Cols () != B.Rows ())
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ dng_matrix C (A.Rows (), B.Cols ());
+
+ for (uint32 j = 0; j < C.Rows (); j++)
+ for (uint32 k = 0; k < C.Cols (); k++)
+ {
+
+ C [j] [k] = 0.0;
+
+ for (uint32 m = 0; m < A.Cols (); m++)
+ {
+
+ real64 aa = A [j] [m];
+
+ real64 bb = B [m] [k];
+
+ C [j] [k] += aa * bb;
+
+ }
+
+ }
+
+ return C;
+
+ }
+
+/******************************************************************************/
+
+dng_vector operator* (const dng_matrix &A,
+ const dng_vector &B)
+ {
+
+ if (A.Cols () != B.Count ())
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ dng_vector C (A.Rows ());
+
+ for (uint32 j = 0; j < C.Count (); j++)
+ {
+
+ C [j] = 0.0;
+
+ for (uint32 m = 0; m < A.Cols (); m++)
+ {
+
+ real64 aa = A [j] [m];
+
+ real64 bb = B [m];
+
+ C [j] += aa * bb;
+
+ }
+
+ }
+
+ return C;
+
+ }
+
+/******************************************************************************/
+
+dng_matrix operator* (real64 scale,
+ const dng_matrix &A)
+ {
+
+ dng_matrix B (A);
+
+ B.Scale (scale);
+
+ return B;
+
+ }
+
+/******************************************************************************/
+
+dng_vector operator* (real64 scale,
+ const dng_vector &A)
+ {
+
+ dng_vector B (A);
+
+ B.Scale (scale);
+
+ return B;
+
+ }
+
+/******************************************************************************/
+
+dng_matrix operator+ (const dng_matrix &A,
+ const dng_matrix &B)
+ {
+
+ if (A.Cols () != B.Cols () ||
+ A.Rows () != B.Rows ())
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ dng_matrix C (A);
+
+ for (uint32 j = 0; j < C.Rows (); j++)
+ for (uint32 k = 0; k < C.Cols (); k++)
+ {
+
+ C [j] [k] += B [j] [k];
+
+ }
+
+ return C;
+
+ }
+
+/******************************************************************************/
+
+const real64 kNearZero = 1.0E-10;
+
+/******************************************************************************/
+
+// Work around bug #1294195, which may be a hardware problem on a specific machine.
+// This pragma turns on "improved" floating-point consistency.
+#ifdef _MSC_VER
+#pragma optimize ("p", on)
+#endif
+
+static dng_matrix Invert3by3 (const dng_matrix &A)
+ {
+
+ real64 a00 = A [0] [0];
+ real64 a01 = A [0] [1];
+ real64 a02 = A [0] [2];
+ real64 a10 = A [1] [0];
+ real64 a11 = A [1] [1];
+ real64 a12 = A [1] [2];
+ real64 a20 = A [2] [0];
+ real64 a21 = A [2] [1];
+ real64 a22 = A [2] [2];
+
+ real64 temp [3] [3];
+
+ temp [0] [0] = a11 * a22 - a21 * a12;
+ temp [0] [1] = a21 * a02 - a01 * a22;
+ temp [0] [2] = a01 * a12 - a11 * a02;
+ temp [1] [0] = a20 * a12 - a10 * a22;
+ temp [1] [1] = a00 * a22 - a20 * a02;
+ temp [1] [2] = a10 * a02 - a00 * a12;
+ temp [2] [0] = a10 * a21 - a20 * a11;
+ temp [2] [1] = a20 * a01 - a00 * a21;
+ temp [2] [2] = a00 * a11 - a10 * a01;
+
+ real64 det = (a00 * temp [0] [0] +
+ a01 * temp [1] [0] +
+ a02 * temp [2] [0]);
+
+ if (Abs_real64 (det) < kNearZero)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ dng_matrix B (3, 3);
+
+ for (uint32 j = 0; j < 3; j++)
+ for (uint32 k = 0; k < 3; k++)
+ {
+
+ B [j] [k] = temp [j] [k] / det;
+
+ }
+
+ return B;
+
+ }
+
+// Reset floating-point optimization. See comment above.
+#ifdef _MSC_VER
+#pragma optimize ("p", off)
+#endif
+
+/******************************************************************************/
+
+static dng_matrix InvertNbyN (const dng_matrix &A)
+ {
+
+ uint32 i;
+ uint32 j;
+ uint32 k;
+
+ uint32 n = A.Rows ();
+
+ real64 temp [kMaxColorPlanes] [kMaxColorPlanes * 2];
+
+ for (i = 0; i < n; i++)
+ for (j = 0; j < n; j++)
+ {
+
+ temp [i] [j ] = A [i] [j];
+
+ temp [i] [j + n] = (i == j ? 1.0 : 0.0);
+
+ }
+
+ for (i = 0; i < n; i++)
+ {
+
+ real64 alpha = temp [i] [i];
+
+ if (Abs_real64 (alpha) < kNearZero)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ for (j = 0; j < n * 2; j++)
+ {
+
+ temp [i] [j] /= alpha;
+
+ }
+
+ for (k = 0; k < n; k++)
+ {
+
+ if (i != k)
+ {
+
+ real64 beta = temp [k] [i];
+
+ for (j = 0; j < n * 2; j++)
+ {
+
+ temp [k] [j] -= beta * temp [i] [j];
+
+ }
+
+ }
+
+ }
+
+ }
+
+ dng_matrix B (n, n);
+
+ for (i = 0; i < n; i++)
+ for (j = 0; j < n; j++)
+ {
+
+ B [i] [j] = temp [i] [j + n];
+
+ }
+
+ return B;
+
+ }
+
+/******************************************************************************/
+
+dng_matrix Transpose (const dng_matrix &A)
+ {
+
+ dng_matrix B (A.Cols (), A.Rows ());
+
+ for (uint32 j = 0; j < B.Rows (); j++)
+ for (uint32 k = 0; k < B.Cols (); k++)
+ {
+
+ B [j] [k] = A [k] [j];
+
+ }
+
+ return B;
+
+ }
+
+/******************************************************************************/
+
+dng_matrix Invert (const dng_matrix &A)
+ {
+
+ if (A.Rows () < 2 || A.Cols () < 2)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ if (A.Rows () == A.Cols ())
+ {
+
+ if (A.Rows () == 3)
+ {
+
+ return Invert3by3 (A);
+
+ }
+
+ return InvertNbyN (A);
+
+ }
+
+ else
+ {
+
+ // Compute the pseudo inverse.
+
+ dng_matrix B = Transpose (A);
+
+ return Invert (B * A) * B;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+dng_matrix Invert (const dng_matrix &A,
+ const dng_matrix &hint)
+ {
+
+ if (A.Rows () == A .Cols () ||
+ A.Rows () != hint.Cols () ||
+ A.Cols () != hint.Rows ())
+ {
+
+ return Invert (A);
+
+ }
+
+ else
+ {
+
+ // Use the specified hint matrix.
+
+ return Invert (hint * A) * hint;
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_matrix.h b/gpr/source/lib/dng_sdk/dng_matrix.h
new file mode 100644
index 0000000..cdac55a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_matrix.h
@@ -0,0 +1,326 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_matrix.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Matrix and vector classes, including specialized 3x3 and 4x3 versions as
+ * well as length 3 vectors.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_matrix__
+#define __dng_matrix__
+
+/*****************************************************************************/
+
+#include "dng_sdk_limits.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Class to represent 2D matrix up to kMaxColorPlanes x kMaxColorPlanes
+/// in size.
+
+class dng_matrix
+ {
+
+ protected:
+
+ uint32 fRows;
+ uint32 fCols;
+
+ real64 fData [kMaxColorPlanes] [kMaxColorPlanes];
+
+ public:
+
+ dng_matrix ();
+
+ dng_matrix (uint32 rows,
+ uint32 cols);
+
+ dng_matrix (const dng_matrix &m);
+
+ virtual ~dng_matrix ()
+ {
+ }
+
+ void Clear ();
+
+ void SetIdentity (uint32 count);
+
+ uint32 Rows () const
+ {
+ return fRows;
+ }
+
+ uint32 Cols () const
+ {
+ return fCols;
+ }
+
+ real64 * operator [] (uint32 row)
+ {
+ return fData [row];
+ }
+
+ const real64 * operator [] (uint32 row) const
+ {
+ return fData [row];
+ }
+
+ bool operator== (const dng_matrix &m) const;
+
+ bool operator!= (const dng_matrix &m) const
+ {
+ return !(*this == m);
+ }
+
+ bool IsEmpty () const
+ {
+ return fRows == 0 || fCols == 0;
+ }
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ bool IsDiagonal () const;
+
+ real64 MaxEntry () const;
+
+ real64 MinEntry () const;
+
+ void Scale (real64 factor);
+
+ void Round (real64 factor);
+
+ void SafeRound (real64 factor);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A 3x3 matrix.
+
+class dng_matrix_3by3: public dng_matrix
+ {
+
+ public:
+
+ dng_matrix_3by3 ();
+
+ dng_matrix_3by3 (const dng_matrix &m);
+
+ dng_matrix_3by3 (real64 a00, real64 a01, real64 a02,
+ real64 a10, real64 a11, real64 a12,
+ real64 a20, real64 a21, real64 a22);
+
+ dng_matrix_3by3 (real64 a00, real64 a11, real64 a22);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A 4x3 matrix. Handy for working with 4-color cameras.
+
+class dng_matrix_4by3: public dng_matrix
+ {
+
+ public:
+
+ dng_matrix_4by3 ();
+
+ dng_matrix_4by3 (const dng_matrix &m);
+
+ dng_matrix_4by3 (real64 a00, real64 a01, real64 a02,
+ real64 a10, real64 a11, real64 a12,
+ real64 a20, real64 a21, real64 a22,
+ real64 a30, real64 a31, real64 a32);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to represent 1-dimensional vector with up to kMaxColorPlanes
+/// components.
+
+class dng_vector
+ {
+
+ protected:
+
+ uint32 fCount;
+
+ real64 fData [kMaxColorPlanes];
+
+ public:
+
+ dng_vector ();
+
+ dng_vector (uint32 count);
+
+ dng_vector (const dng_vector &v);
+
+ virtual ~dng_vector ()
+ {
+ }
+
+ void Clear ();
+
+ void SetIdentity (uint32 count);
+
+ uint32 Count () const
+ {
+ return fCount;
+ }
+
+ real64 & operator [] (uint32 index)
+ {
+ return fData [index];
+ }
+
+ const real64 & operator [] (uint32 index) const
+ {
+ return fData [index];
+ }
+
+ bool operator== (const dng_vector &v) const;
+
+ bool operator!= (const dng_vector &v) const
+ {
+ return !(*this == v);
+ }
+
+ bool IsEmpty () const
+ {
+ return fCount == 0;
+ }
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ real64 MaxEntry () const;
+
+ real64 MinEntry () const;
+
+ void Scale (real64 factor);
+
+ void Round (real64 factor);
+
+ dng_matrix AsDiagonal () const;
+
+ dng_matrix AsColumn () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A 3-element vector.
+
+class dng_vector_3: public dng_vector
+ {
+
+ public:
+
+ dng_vector_3 ();
+
+ dng_vector_3 (const dng_vector &v);
+
+ dng_vector_3 (real64 a0,
+ real64 a1,
+ real64 a2);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A 4-element vector.
+
+class dng_vector_4: public dng_vector
+ {
+
+ public:
+
+ dng_vector_4 ();
+
+ dng_vector_4 (const dng_vector &v);
+
+ dng_vector_4 (real64 a0,
+ real64 a1,
+ real64 a2,
+ real64 a3);
+
+ };
+
+/*****************************************************************************/
+
+dng_matrix operator* (const dng_matrix &A,
+ const dng_matrix &B);
+
+dng_vector operator* (const dng_matrix &A,
+ const dng_vector &B);
+
+dng_matrix operator* (real64 scale,
+ const dng_matrix &A);
+
+dng_vector operator* (real64 scale,
+ const dng_vector &A);
+
+/*****************************************************************************/
+
+dng_matrix operator+ (const dng_matrix &A,
+ const dng_matrix &B);
+
+/*****************************************************************************/
+
+dng_matrix Transpose (const dng_matrix &A);
+
+/*****************************************************************************/
+
+dng_matrix Invert (const dng_matrix &A);
+
+dng_matrix Invert (const dng_matrix &A,
+ const dng_matrix &hint);
+
+/*****************************************************************************/
+
+inline real64 MaxEntry (const dng_matrix &A)
+ {
+ return A.MaxEntry ();
+ }
+
+inline real64 MaxEntry (const dng_vector &A)
+ {
+ return A.MaxEntry ();
+ }
+
+/*****************************************************************************/
+
+inline real64 MinEntry (const dng_matrix &A)
+ {
+ return A.MinEntry ();
+ }
+
+inline real64 MinEntry (const dng_vector &A)
+ {
+ return A.MinEntry ();
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_memory.cpp b/gpr/source/lib/dng_sdk/dng_memory.cpp
new file mode 100644
index 0000000..8934e89
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_memory.cpp
@@ -0,0 +1,204 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_memory.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_memory.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+
+#include "gpr_allocator.h"
+
+/*****************************************************************************/
+
+dng_memory_data::dng_memory_data ()
+
+ : fBuffer (NULL)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_data::dng_memory_data (uint32 size)
+
+ : fBuffer (NULL)
+
+ {
+
+ Allocate (size);
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_data::~dng_memory_data ()
+ {
+
+ Clear ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_data::Allocate (uint32 size)
+ {
+
+ Clear ();
+
+ if (size)
+ {
+
+ fBuffer = (char*)gpr_global_malloc(size);
+
+ if (!fBuffer)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_data::Clear ()
+ {
+
+ if (fBuffer)
+ {
+ gpr_global_free(fBuffer);
+
+ fBuffer = NULL;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_memory_block::Clone (dng_memory_allocator &allocator) const
+ {
+
+ uint32 size = LogicalSize ();
+
+ dng_memory_block * result = allocator.Allocate (size);
+
+ DoCopyBytes (Buffer (), result->Buffer (), size);
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+class dng_malloc_block : public dng_memory_block
+ {
+
+ private:
+
+ void *fMalloc;
+
+ public:
+
+ dng_malloc_block (uint32 logicalSize);
+
+ virtual ~dng_malloc_block ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_malloc_block (const dng_malloc_block &block);
+
+ dng_malloc_block & operator= (const dng_malloc_block &block);
+
+ };
+
+/*****************************************************************************/
+
+dng_malloc_block::dng_malloc_block (uint32 logicalSize)
+
+ : dng_memory_block (logicalSize)
+
+ , fMalloc (NULL)
+
+ {
+
+#if qLinux
+
+ int err = ::posix_memalign( (void **) &fMalloc, 16, (size_t) PhysicalSize() );
+
+ if (err)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+#else
+
+ fMalloc = (char*)gpr_global_malloc( PhysicalSize ());
+
+ if (!fMalloc)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+#endif // qLinux
+
+ SetBuffer (fMalloc);
+
+ }
+
+/*****************************************************************************/
+
+dng_malloc_block::~dng_malloc_block ()
+ {
+
+ if (fMalloc)
+ {
+ gpr_global_free( fMalloc );
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_memory_allocator::Allocate (uint32 size)
+ {
+
+ dng_memory_block *result = new dng_malloc_block (size);
+
+ if (!result)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_allocator gDefaultDNGMemoryAllocator;
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_memory.h b/gpr/source/lib/dng_sdk/dng_memory.h
new file mode 100644
index 0000000..809e68a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_memory.h
@@ -0,0 +1,515 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_memory.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** Support for memory allocation.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_memory__
+#define __dng_memory__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Class to provide resource acquisition is instantiation discipline
+/// for small memory allocations.
+///
+/// This class does not use dng_memory_allocator for memory allocation.
+
+class dng_memory_data
+ {
+
+ private:
+
+ char *fBuffer;
+
+ public:
+
+ /// Construct an empty memory buffer using malloc.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ dng_memory_data ();
+
+ /// Construct memory buffer of size bytes using malloc.
+ /// \param size Number of bytes of memory needed.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ dng_memory_data (uint32 size);
+
+ /// Release memory buffer using free.
+
+ ~dng_memory_data ();
+
+ /// Clear existing memory buffer and allocate new memory of size bytes.
+ /// \param size Number of bytes of memory needed.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ void Allocate (uint32 size);
+
+ /// Release any allocated memory using free. Object is still valid and
+ /// Allocate can be called again.
+
+ void Clear ();
+
+ /// Return pointer to allocated memory as a void *..
+ /// \retval void * valid for as many bytes as were allocated.
+
+ void * Buffer ()
+ {
+ return fBuffer;
+ }
+
+ /// Return pointer to allocated memory as a const void *.
+ /// \retval const void * valid for as many bytes as were allocated.
+
+ const void * Buffer () const
+ {
+ return fBuffer;
+ }
+
+ /// Return pointer to allocated memory as a char *.
+ /// \retval char * valid for as many bytes as were allocated.
+
+ char * Buffer_char ()
+ {
+ return (char *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const char *.
+ /// \retval const char * valid for as many bytes as were allocated.
+
+ const char * Buffer_char () const
+ {
+ return (const char *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint8 *.
+ /// \retval uint8 * valid for as many bytes as were allocated.
+
+ uint8 * Buffer_uint8 ()
+ {
+ return (uint8 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint8 *.
+ /// \retval const uint8 * valid for as many bytes as were allocated.
+
+ const uint8 * Buffer_uint8 () const
+ {
+ return (const uint8 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint16 *.
+ /// \retval uint16 * valid for as many bytes as were allocated.
+
+ uint16 * Buffer_uint16 ()
+ {
+ return (uint16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint16 *.
+ /// \retval const uint16 * valid for as many bytes as were allocated.
+
+ const uint16 * Buffer_uint16 () const
+ {
+ return (const uint16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a int16 *.
+ /// \retval int16 * valid for as many bytes as were allocated.
+
+ int16 * Buffer_int16 ()
+ {
+ return (int16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int16 *.
+ /// \retval const int16 * valid for as many bytes as were allocated.
+
+ const int16 * Buffer_int16 () const
+ {
+ return (const int16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint32 *.
+ /// \retval uint32 * valid for as many bytes as were allocated.
+
+ uint32 * Buffer_uint32 ()
+ {
+ return (uint32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint32 *.
+ /// \retval uint32 * valid for as many bytes as were allocated.
+
+ const uint32 * Buffer_uint32 () const
+ {
+ return (const uint32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int32 *.
+ /// \retval const int32 * valid for as many bytes as were allocated.
+
+ int32 * Buffer_int32 ()
+ {
+ return (int32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int32 *.
+ /// \retval const int32 * valid for as many bytes as were allocated.
+
+ const int32 * Buffer_int32 () const
+ {
+ return (const int32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint64 *.
+ /// \retval uint64 * valid for as many bytes as were allocated.
+
+ uint64 * Buffer_uint64 ()
+ {
+ return (uint64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint64 *.
+ /// \retval uint64 * valid for as many bytes as were allocated.
+
+ const uint64 * Buffer_uint64 () const
+ {
+ return (const uint64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int64 *.
+ /// \retval const int64 * valid for as many bytes as were allocated.
+
+ int64 * Buffer_int64 ()
+ {
+ return (int64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int64 *.
+ /// \retval const int64 * valid for as many bytes as were allocated.
+
+ const int64 * Buffer_int64 () const
+ {
+ return (const int64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a real32 *.
+ /// \retval real32 * valid for as many bytes as were allocated.
+
+ real32 * Buffer_real32 ()
+ {
+ return (real32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const real32 *.
+ /// \retval const real32 * valid for as many bytes as were allocated.
+
+ const real32 * Buffer_real32 () const
+ {
+ return (const real32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a real64 *.
+ /// \retval real64 * valid for as many bytes as were allocated.
+
+ real64 * Buffer_real64 ()
+ {
+ return (real64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const real64 *.
+ /// \retval const real64 * valid for as many bytes as were allocated.
+
+ const real64 * Buffer_real64 () const
+ {
+ return (const real64 *) Buffer ();
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_memory_data (const dng_memory_data &data);
+
+ dng_memory_data & operator= (const dng_memory_data &data);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to provide resource acquisition is instantiation discipline for
+/// image buffers and other larger memory allocations.
+///
+/// This class requires a dng_memory_allocator for allocation.
+
+class dng_memory_block
+ {
+
+ private:
+
+ uint32 fLogicalSize;
+
+ char *fBuffer;
+
+ protected:
+
+ dng_memory_block (uint32 logicalSize)
+ : fLogicalSize (logicalSize)
+ , fBuffer (NULL)
+ {
+ }
+
+ uint32 PhysicalSize ()
+ {
+
+ // This size is padded for TWO reasons! The first is allow alignment
+ // to 16-byte boundaries if the allocator does not do that already. The
+ // second, which is very important, so to provide safe overread areas for
+ // SSE2-type bottlenecks, which can often be written faster by allowing them
+ // to reading slightly block. Someone on the image core them did not
+ // understand this and removed this padding. I'm undoing this removal
+ // and restoring this padding, since removing it might lead to memory
+ // access crashes in some cases.
+
+ // This padding is throwing off all of our allocations (f.e. dng_string, pixel buffers, etc)
+ // that uses dng_memory_block on iOS/Android that is memory limited. Imagecore carefully
+ // allocates pow2 tile buffers, but this bumps us to the next ssd block (+4K).
+ // This also makes it difficult to identify memory reports in Instruments since all
+ // numbers are off by 64. Imagecore never crashed from the removal of the padding.
+ // The allocator on Win64/Mac64 is 16-byte aligned already. iOS is too.
+ // Linux is 8 byte, but it's using mem_align.
+ // We should fix the SIMD routines and revisit removing this padding - Alec.
+
+ return fLogicalSize + 64;
+
+ }
+
+ void SetBuffer (void *p)
+ {
+ fBuffer = (char *) ((((uintptr) p) + 15) & ~((uintptr) 15));
+ }
+
+ public:
+
+ virtual ~dng_memory_block ()
+ {
+ }
+
+ dng_memory_block * Clone (dng_memory_allocator &allocator) const;
+
+ /// Getter for available size, in bytes, of memory block.
+ /// \retval size in bytes of available memory in memory block.
+
+ uint32 LogicalSize () const
+ {
+ return fLogicalSize;
+ }
+
+ /// Return pointer to allocated memory as a void *..
+ /// \retval void * valid for as many bytes as were allocated.
+
+ void * Buffer ()
+ {
+ return fBuffer;
+ }
+
+ /// Return pointer to allocated memory as a const void *.
+ /// \retval const void * valid for as many bytes as were allocated.
+
+ const void * Buffer () const
+ {
+ return fBuffer;
+ }
+
+ /// Return pointer to allocated memory as a char *.
+ /// \retval char * valid for as many bytes as were allocated.
+
+ char * Buffer_char ()
+ {
+ return (char *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const char *.
+ /// \retval const char * valid for as many bytes as were allocated.
+
+ const char * Buffer_char () const
+ {
+ return (const char *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint8 *.
+ /// \retval uint8 * valid for as many bytes as were allocated.
+
+ uint8 * Buffer_uint8 ()
+ {
+ return (uint8 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint8 *.
+ /// \retval const uint8 * valid for as many bytes as were allocated.
+
+ const uint8 * Buffer_uint8 () const
+ {
+ return (const uint8 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint16 *.
+ /// \retval uint16 * valid for as many bytes as were allocated.
+
+ uint16 * Buffer_uint16 ()
+ {
+ return (uint16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint16 *.
+ /// \retval const uint16 * valid for as many bytes as were allocated.
+
+ const uint16 * Buffer_uint16 () const
+ {
+ return (const uint16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a int16 *.
+ /// \retval int16 * valid for as many bytes as were allocated.
+
+ int16 * Buffer_int16 ()
+ {
+ return (int16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int16 *.
+ /// \retval const int16 * valid for as many bytes as were allocated.
+
+ const int16 * Buffer_int16 () const
+ {
+ return (const int16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint32 *.
+ /// \retval uint32 * valid for as many bytes as were allocated.
+
+ uint32 * Buffer_uint32 ()
+ {
+ return (uint32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint32 *.
+ /// \retval const uint32 * valid for as many bytes as were allocated.
+
+ const uint32 * Buffer_uint32 () const
+ {
+ return (const uint32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a int32 *.
+ /// \retval int32 * valid for as many bytes as were allocated.
+
+ int32 * Buffer_int32 ()
+ {
+ return (int32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int32 *.
+ /// \retval const int32 * valid for as many bytes as were allocated.
+
+ const int32 * Buffer_int32 () const
+ {
+ return (const int32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a real32 *.
+ /// \retval real32 * valid for as many bytes as were allocated.
+
+ real32 * Buffer_real32 ()
+ {
+ return (real32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const real32 *.
+ /// \retval const real32 * valid for as many bytes as were allocated.
+
+ const real32 * Buffer_real32 () const
+ {
+ return (const real32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a real64 *.
+ /// \retval real64 * valid for as many bytes as were allocated.
+
+ real64 * Buffer_real64 ()
+ {
+ return (real64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const real64 *.
+ /// \retval const real64 * valid for as many bytes as were allocated.
+
+ const real64 * Buffer_real64 () const
+ {
+ return (const real64 *) Buffer ();
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_memory_block (const dng_memory_block &data);
+
+ dng_memory_block & operator= (const dng_memory_block &data);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Interface for dng_memory_block allocator.
+
+class dng_memory_allocator
+ {
+
+ public:
+
+ virtual ~dng_memory_allocator ()
+ {
+ }
+
+ /// Allocate a dng_memory block.
+ /// \param size Number of bytes in memory block.
+ /// \retval A dng_memory_block with at least size bytes of valid storage.
+ /// \exception dng_exception with fErrorCode equal to dng_error_memory.
+
+ virtual dng_memory_block * Allocate (uint32 size);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Default memory allocator used if NULL is passed in for allocator
+/// when constructing a dng_host.
+///
+/// Uses new and delete for memory block object and malloc/free for underlying
+/// buffer.
+
+extern dng_memory_allocator gDefaultDNGMemoryAllocator;
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_memory_stream.cpp b/gpr/source/lib/dng_sdk/dng_memory_stream.cpp
new file mode 100644
index 0000000..9368d67
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_memory_stream.cpp
@@ -0,0 +1,253 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_memory_stream.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_memory_stream.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_utils.h"
+
+#include "gpr_allocator.h"
+
+/*****************************************************************************/
+
+dng_memory_stream::dng_memory_stream (dng_memory_allocator &allocator,
+ dng_abort_sniffer *sniffer,
+ uint32 pageSize)
+
+ : dng_stream (sniffer,
+ kDefaultBufferSize,
+ kDNGStreamInvalidOffset)
+
+ , fAllocator (allocator)
+ , fPageSize (pageSize )
+
+ , fPageCount (0)
+ , fPagesAllocated (0)
+ , fPageList (NULL)
+
+ , fMemoryStreamLength (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_stream::~dng_memory_stream ()
+ {
+
+ if (fPageList)
+ {
+
+ for (uint32 index = 0; index < fPageCount; index++)
+ {
+
+ delete fPageList [index];
+
+ }
+
+ gpr_global_free( fPageList );
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_memory_stream::DoGetLength ()
+ {
+
+ return fMemoryStreamLength;
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_stream::DoRead (void *data,
+ uint32 count,
+ uint64 offset)
+ {
+
+ if (offset + count > fMemoryStreamLength)
+ {
+
+ ThrowEndOfFile ();
+
+ }
+
+ uint64 baseOffset = offset;
+
+ while (count)
+ {
+
+ uint32 pageIndex = (uint32) (offset / fPageSize);
+ uint32 pageOffset = (uint32) (offset % fPageSize);
+
+ uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count);
+
+ const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () +
+ pageOffset;
+
+ uint8 *dPtr = ((uint8 *) data) + (uint32) (offset - baseOffset);
+
+ DoCopyBytes (sPtr, dPtr, blockCount);
+
+ offset += blockCount;
+ count -= blockCount;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_stream::DoSetLength (uint64 length)
+ {
+
+ while (length > fPageCount * (uint64) fPageSize)
+ {
+
+ if (fPageCount == fPagesAllocated)
+ {
+
+ uint32 newSize = Max_uint32 (fPagesAllocated + 32,
+ fPagesAllocated * 2);
+
+ dng_memory_block **list = (dng_memory_block **) gpr_global_malloc( newSize * sizeof (dng_memory_block *) );
+
+ if (!list)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ if (fPageCount)
+ {
+
+ DoCopyBytes (fPageList,
+ list,
+ fPageCount * (uint32) sizeof (dng_memory_block *));
+
+ }
+
+ if (fPageList)
+ {
+ gpr_global_free( fPageList );
+ }
+
+ fPageList = list;
+
+ fPagesAllocated = newSize;
+
+ }
+
+ fPageList [fPageCount] = fAllocator.Allocate (fPageSize);
+
+ fPageCount++;
+
+ }
+
+ fMemoryStreamLength = length;
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_stream::DoWrite (const void *data,
+ uint32 count,
+ uint64 offset)
+ {
+
+ DoSetLength (Max_uint64 (fMemoryStreamLength,
+ offset + count));
+
+ uint64 baseOffset = offset;
+
+ while (count)
+ {
+
+ uint32 pageIndex = (uint32) (offset / fPageSize);
+ uint32 pageOffset = (uint32) (offset % fPageSize);
+
+ uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count);
+
+ const uint8 *sPtr = ((const uint8 *) data) + (uint32) (offset - baseOffset);
+
+ uint8 *dPtr = fPageList [pageIndex]->Buffer_uint8 () +
+ pageOffset;
+
+ DoCopyBytes (sPtr, dPtr, blockCount);
+
+ offset += blockCount;
+ count -= blockCount;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_stream::CopyToStream (dng_stream &dstStream,
+ uint64 count)
+ {
+
+ if (count < kBigBufferSize)
+ {
+
+ dng_stream::CopyToStream (dstStream, count);
+
+ }
+
+ else
+ {
+
+ Flush ();
+
+ uint64 offset = Position ();
+
+ if (offset + count > Length ())
+ {
+
+ ThrowEndOfFile ();
+
+ }
+
+ while (count)
+ {
+
+ uint32 pageIndex = (uint32) (offset / fPageSize);
+ uint32 pageOffset = (uint32) (offset % fPageSize);
+
+ uint32 blockCount = (uint32) Min_uint64 (fPageSize - pageOffset, count);
+
+ const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () +
+ pageOffset;
+
+ dstStream.Put (sPtr, blockCount);
+
+ offset += blockCount;
+ count -= blockCount;
+
+ }
+
+ SetReadPosition (offset);
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_memory_stream.h b/gpr/source/lib/dng_sdk/dng_memory_stream.h
new file mode 100644
index 0000000..4477936
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_memory_stream.h
@@ -0,0 +1,97 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_memory_stream.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Stream abstraction to/from in-memory data.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_memory_stream__
+#define __dng_memory_stream__
+
+/*****************************************************************************/
+
+#include "dng_stream.h"
+
+/*****************************************************************************/
+
+/// \brief A dng_stream which can be read from or written to memory.
+///
+/// Stream is populated via writing and either read or accessed by asking for contents as a pointer.
+
+class dng_memory_stream: public dng_stream
+ {
+
+ protected:
+
+ dng_memory_allocator &fAllocator;
+
+ uint32 fPageSize;
+
+ uint32 fPageCount;
+ uint32 fPagesAllocated;
+
+ dng_memory_block **fPageList;
+
+ uint64 fMemoryStreamLength;
+
+ public:
+
+ /// Construct a new memory-based stream.
+ /// \param allocator Allocator to use to allocate memory in stream as needed.
+ /// \param sniffer If non-NULL used to check for user cancellation.
+ /// \param pageSize Unit of allocation for data stored in stream.
+
+ dng_memory_stream (dng_memory_allocator &allocator,
+ dng_abort_sniffer *sniffer = NULL,
+ uint32 pageSize = 64 * 1024);
+
+ virtual ~dng_memory_stream ();
+
+ /// Copy a specified number of bytes to a target stream.
+ /// \param dstStream The target stream.
+ /// \param count The number of bytes to copy.
+
+ virtual void CopyToStream (dng_stream &dstStream,
+ uint64 count);
+
+ protected:
+
+ virtual uint64 DoGetLength ();
+
+ virtual void DoRead (void *data,
+ uint32 count,
+ uint64 offset);
+
+ virtual void DoSetLength (uint64 length);
+
+ virtual void DoWrite (const void *data,
+ uint32 count,
+ uint64 offset);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_memory_stream (const dng_memory_stream &stream);
+
+ dng_memory_stream & operator= (const dng_memory_stream &stream);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_misc_opcodes.cpp b/gpr/source/lib/dng_sdk/dng_misc_opcodes.cpp
new file mode 100644
index 0000000..139b79f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_misc_opcodes.cpp
@@ -0,0 +1,1578 @@
+/*****************************************************************************/
+// Copyright 2008-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_misc_opcodes.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_misc_opcodes.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_rect.h"
+#include "dng_stream.h"
+#include "dng_tag_values.h"
+
+/*****************************************************************************/
+
+dng_opcode_TrimBounds::dng_opcode_TrimBounds (const dng_rect &bounds)
+
+ : dng_opcode (dngOpcode_TrimBounds,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fBounds (bounds)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_TrimBounds::dng_opcode_TrimBounds (dng_stream &stream)
+
+ : dng_opcode (dngOpcode_TrimBounds,
+ stream,
+ "TrimBounds")
+
+ , fBounds ()
+
+ {
+
+ if (stream.Get_uint32 () != 16)
+ {
+ ThrowBadFormat ();
+ }
+
+ fBounds.t = stream.Get_int32 ();
+ fBounds.l = stream.Get_int32 ();
+ fBounds.b = stream.Get_int32 ();
+ fBounds.r = stream.Get_int32 ();
+
+ if (fBounds.IsEmpty ())
+ {
+ ThrowBadFormat ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Bounds: t=%d, l=%d, b=%d, r=%d\n",
+ (int) fBounds.t,
+ (int) fBounds.l,
+ (int) fBounds.b,
+ (int) fBounds.r);
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_TrimBounds::PutData (dng_stream &stream) const
+ {
+
+ stream.Put_uint32 (16);
+
+ stream.Put_int32 (fBounds.t);
+ stream.Put_int32 (fBounds.l);
+ stream.Put_int32 (fBounds.b);
+ stream.Put_int32 (fBounds.r);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_TrimBounds::Apply (dng_host & /* host */,
+ dng_negative & /* negative */,
+ AutoPtr<dng_image> &image)
+ {
+
+ if (fBounds.IsEmpty () || (fBounds & image->Bounds ()) != fBounds)
+ {
+ ThrowBadFormat ();
+ }
+
+ image->Trim (fBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_area_spec::GetData (dng_stream &stream)
+ {
+
+ fArea.t = stream.Get_int32 ();
+ fArea.l = stream.Get_int32 ();
+ fArea.b = stream.Get_int32 ();
+ fArea.r = stream.Get_int32 ();
+
+ fPlane = stream.Get_uint32 ();
+ fPlanes = stream.Get_uint32 ();
+
+ fRowPitch = stream.Get_uint32 ();
+ fColPitch = stream.Get_uint32 ();
+
+ if (fPlanes < 1)
+ {
+ ThrowBadFormat ();
+ }
+
+ if (fRowPitch < 1 || fColPitch < 1)
+ {
+ ThrowBadFormat ();
+ }
+
+ if (fArea.IsEmpty () && (fRowPitch != 1 || fColPitch != 1))
+ {
+ ThrowBadFormat ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AreaSpec: t=%d, l=%d, b=%d, r=%d, p=%u:%u, rp=%u, cp=%u\n",
+ (int) fArea.t,
+ (int) fArea.l,
+ (int) fArea.b,
+ (int) fArea.r,
+ (unsigned) fPlane,
+ (unsigned) fPlanes,
+ (unsigned) fRowPitch,
+ (unsigned) fColPitch);
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_area_spec::PutData (dng_stream &stream) const
+ {
+
+ stream.Put_int32 (fArea.t);
+ stream.Put_int32 (fArea.l);
+ stream.Put_int32 (fArea.b);
+ stream.Put_int32 (fArea.r);
+
+ stream.Put_uint32 (fPlane);
+ stream.Put_uint32 (fPlanes);
+
+ stream.Put_uint32 (fRowPitch);
+ stream.Put_uint32 (fColPitch);
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_area_spec::Overlap (const dng_rect &tile) const
+ {
+
+ // Special case - if the fArea is empty, then dng_area_spec covers
+ // the entire image, no matter how large it is.
+
+ if (fArea.IsEmpty ())
+ {
+ return tile;
+ }
+
+ dng_rect overlap = fArea & tile;
+
+ if (overlap.NotEmpty ())
+ {
+
+ overlap.t = fArea.t + ((overlap.t - fArea.t + fRowPitch - 1) / fRowPitch) * fRowPitch;
+ overlap.l = fArea.l + ((overlap.l - fArea.l + fColPitch - 1) / fColPitch) * fColPitch;
+
+ if (overlap.NotEmpty ())
+ {
+
+ overlap.b = overlap.t + ((overlap.H () - 1) / fRowPitch) * fRowPitch + 1;
+ overlap.r = overlap.l + ((overlap.W () - 1) / fColPitch) * fColPitch + 1;
+
+ return overlap;
+
+ }
+
+ }
+
+ return dng_rect ();
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_MapTable::dng_opcode_MapTable (dng_host &host,
+ const dng_area_spec &areaSpec,
+ const uint16 *table,
+ uint32 count)
+
+ : dng_inplace_opcode (dngOpcode_MapTable,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+ , fTable ()
+ , fCount (count)
+
+ {
+
+ if (count == 0 || count > 0x10000)
+ {
+ ThrowProgramError ();
+ }
+
+ fTable.Reset (host.Allocate (0x10000 * sizeof (uint16)));
+
+ DoCopyBytes (table,
+ fTable->Buffer (),
+ count * (uint32) sizeof (uint16));
+
+ ReplicateLastEntry ();
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_MapTable::dng_opcode_MapTable (dng_host &host,
+ dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_MapTable,
+ stream,
+ "MapTable")
+
+ , fAreaSpec ()
+ , fTable ()
+ , fCount (0)
+
+ {
+
+ uint32 dataSize = stream.Get_uint32 ();
+
+ fAreaSpec.GetData (stream);
+
+ fCount = stream.Get_uint32 ();
+
+ if (dataSize != dng_area_spec::kDataSize + 4 + fCount * 2)
+ {
+ ThrowBadFormat ();
+ }
+
+ if (fCount == 0 || fCount > 0x10000)
+ {
+ ThrowBadFormat ();
+ }
+
+ fTable.Reset (host.Allocate (0x10000 * sizeof (uint16)));
+
+ uint16 *table = fTable->Buffer_uint16 ();
+
+ for (uint32 index = 0; index < fCount; index++)
+ {
+ table [index] = stream.Get_uint16 ();
+ }
+
+ ReplicateLastEntry ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Count: %u\n", (unsigned) fCount);
+
+ for (uint32 j = 0; j < fCount && j < gDumpLineLimit; j++)
+ {
+ printf (" Table [%5u] = %5u\n", (unsigned) j, (unsigned) table [j]);
+ }
+
+ if (fCount > gDumpLineLimit)
+ {
+ printf (" ... %u table entries skipped\n", (unsigned) (fCount - gDumpLineLimit));
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_MapTable::ReplicateLastEntry ()
+ {
+
+ uint16 *table = fTable->Buffer_uint16 ();
+
+ uint16 lastEntry = table [fCount];
+
+ for (uint32 index = fCount; index < 0x10000; index++)
+ {
+ table [index] = lastEntry;
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_MapTable::PutData (dng_stream &stream) const
+ {
+
+ stream.Put_uint32 (dng_area_spec::kDataSize + 4 + fCount * 2);
+
+ fAreaSpec.PutData (stream);
+
+ stream.Put_uint32 (fCount);
+
+ uint16 *table = fTable->Buffer_uint16 ();
+
+ for (uint32 index = 0; index < fCount; index++)
+ {
+ stream.Put_uint16 (table [index]);
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_MapTable::BufferPixelType (uint32 /* imagePixelType */)
+ {
+
+ return ttShort;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_MapTable::ModifiedBounds (const dng_rect &imageBounds)
+ {
+
+ return fAreaSpec.Overlap (imageBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_MapTable::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ DoMapArea16 (buffer.DirtyPixel_uint16 (overlap.t, overlap.l, plane),
+ 1,
+ (overlap.H () + fAreaSpec.RowPitch () - 1) / fAreaSpec.RowPitch (),
+ (overlap.W () + fAreaSpec.ColPitch () - 1) / fAreaSpec.ColPitch (),
+ 0,
+ fAreaSpec.RowPitch () * buffer.RowStep (),
+ fAreaSpec.ColPitch (),
+ fTable->Buffer_uint16 ());
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (const dng_area_spec &areaSpec,
+ uint32 degree,
+ const real64 *coefficient)
+
+ : dng_inplace_opcode (dngOpcode_MapPolynomial,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+ , fDegree (degree)
+
+ {
+
+ for (uint32 j = 0; j <= kMaxDegree; j++)
+ {
+
+ if (j <= fDegree)
+ {
+ fCoefficient [j] = coefficient [j];
+ }
+
+ else
+ {
+ fCoefficient [j] = 0.0;
+ }
+
+ }
+
+ // Reduce degree if possible.
+
+ while (fDegree > 0 && fCoefficient [fDegree] == 0.0)
+ {
+ fDegree--;
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_MapPolynomial,
+ stream,
+ "MapPolynomial")
+
+ , fAreaSpec ()
+ , fDegree (0)
+
+ {
+
+ uint32 dataSize = stream.Get_uint32 ();
+
+ fAreaSpec.GetData (stream);
+
+ fDegree = stream.Get_uint32 ();
+
+ if (dataSize != dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8)
+ {
+ ThrowBadFormat ();
+ }
+
+ if (fDegree > kMaxDegree)
+ {
+ ThrowBadFormat ();
+ }
+
+ for (uint32 j = 0; j <= kMaxDegree; j++)
+ {
+
+ if (j <= fDegree)
+ {
+ fCoefficient [j] = stream.Get_real64 ();
+ }
+ else
+ {
+ fCoefficient [j] = 0.0;
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ for (uint32 k = 0; k <= fDegree; k++)
+ {
+ printf (" Coefficient [%u] = %f\n", (unsigned) k, fCoefficient [k]);
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_MapPolynomial::PutData (dng_stream &stream) const
+ {
+
+ stream.Put_uint32 (dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8);
+
+ fAreaSpec.PutData (stream);
+
+ stream.Put_uint32 (fDegree);
+
+ for (uint32 j = 0; j <= fDegree; j++)
+ {
+ stream.Put_real64 (fCoefficient [j]);
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_MapPolynomial::BufferPixelType (uint32 imagePixelType)
+ {
+
+ // If we are operating on the stage 1 image, then we need
+ // to adjust the coefficients to convert from the image
+ // values to the 32-bit floating point values that this
+ // opcode operates on.
+
+ // If we are operating on the stage 2 or 3 image, the logical
+ // range of the image is already 0.0 to 1.0, so we don't
+ // need to adjust the values.
+
+ real64 scale32 = 1.0;
+
+ if (Stage () == 1)
+ {
+
+ switch (imagePixelType)
+ {
+
+ case ttFloat:
+ break;
+
+ case ttShort:
+ {
+ scale32 = (real64) 0xFFFF;
+ break;
+ }
+
+ case ttLong:
+ {
+ scale32 = (real64) 0xFFFFFFFF;
+ break;
+ }
+
+ default:
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+ real64 factor32 = 1.0 / scale32;
+
+ for (uint32 j = 0; j <= kMaxDegree; j++)
+ {
+
+ fCoefficient32 [j] = (real32) (fCoefficient [j] * factor32);
+
+ factor32 *= scale32;
+
+ }
+
+ return ttFloat;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_MapPolynomial::ModifiedBounds (const dng_rect &imageBounds)
+ {
+
+ return fAreaSpec.Overlap (imageBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_MapPolynomial::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ uint32 cols = overlap.W ();
+
+ uint32 colPitch = fAreaSpec.ColPitch ();
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
+ {
+
+ real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
+
+ switch (fDegree)
+ {
+
+ case 0:
+ {
+
+ real32 y = Pin_real32 (0.0f,
+ fCoefficient32 [0],
+ 1.0f);
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = y;
+
+ }
+
+ break;
+
+ }
+
+ case 1:
+ {
+
+ real32 c0 = fCoefficient32 [0];
+ real32 c1 = fCoefficient32 [1];
+
+ if (c0 == 0.0f)
+ {
+
+ if (c1 > 0.0f)
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = c1 * x;
+
+ dPtr [col] = Min_real32 (y, 1.0f);
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = 0.0f;
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = c0 +
+ c1 * x;
+
+ dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case 2:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = fCoefficient32 [0] + x *
+ (fCoefficient32 [1] + x *
+ (fCoefficient32 [2]));
+
+ dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ case 3:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = fCoefficient32 [0] + x *
+ (fCoefficient32 [1] + x *
+ (fCoefficient32 [2] + x *
+ (fCoefficient32 [3])));
+
+ dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = fCoefficient32 [0] + x *
+ (fCoefficient32 [1] + x *
+ (fCoefficient32 [2] + x *
+ (fCoefficient32 [3] + x *
+ (fCoefficient32 [4]))));
+
+ dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = fCoefficient32 [0];
+
+ real32 xx = x;
+
+ for (uint32 j = 1; j <= fDegree; j++)
+ {
+
+ y += fCoefficient32 [j] * xx;
+
+ xx *= x;
+
+ }
+
+ dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_DeltaPerRow::dng_opcode_DeltaPerRow (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table)
+
+ : dng_inplace_opcode (dngOpcode_DeltaPerRow,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+ , fTable ()
+ , fScale (1.0f)
+
+ {
+
+ fTable.Reset (table.Release ());
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_DeltaPerRow::dng_opcode_DeltaPerRow (dng_host &host,
+ dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_DeltaPerRow,
+ stream,
+ "DeltaPerRow")
+
+ , fAreaSpec ()
+ , fTable ()
+ , fScale (1.0f)
+
+ {
+
+ uint32 dataSize = stream.Get_uint32 ();
+
+ fAreaSpec.GetData (stream);
+
+ uint32 deltas = (fAreaSpec.Area ().H () +
+ fAreaSpec.RowPitch () - 1) /
+ fAreaSpec.RowPitch ();
+
+ if (deltas != stream.Get_uint32 ())
+ {
+ ThrowBadFormat ();
+ }
+
+ if (dataSize != dng_area_spec::kDataSize + 4 + deltas * 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ fTable.Reset (host.Allocate (deltas * (uint32) sizeof (real32)));
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < deltas; j++)
+ {
+ table [j] = stream.Get_real32 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Count: %u\n", (unsigned) deltas);
+
+ for (uint32 k = 0; k < deltas && k < gDumpLineLimit; k++)
+ {
+ printf (" Delta [%u] = %f\n", (unsigned) k, table [k]);
+ }
+
+ if (deltas > gDumpLineLimit)
+ {
+ printf (" ... %u deltas skipped\n", (unsigned) (deltas - gDumpLineLimit));
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_DeltaPerRow::PutData (dng_stream &stream) const
+ {
+
+ uint32 deltas = (fAreaSpec.Area ().H () +
+ fAreaSpec.RowPitch () - 1) /
+ fAreaSpec.RowPitch ();
+
+ stream.Put_uint32 (dng_area_spec::kDataSize + 4 + deltas * 4);
+
+ fAreaSpec.PutData (stream);
+
+ stream.Put_uint32 (deltas);
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < deltas; j++)
+ {
+ stream.Put_real32 (table [j]);
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_DeltaPerRow::BufferPixelType (uint32 imagePixelType)
+ {
+
+ real64 scale32 = 1.0;
+
+ switch (imagePixelType)
+ {
+
+ case ttFloat:
+ break;
+
+ case ttShort:
+ {
+ scale32 = (real64) 0xFFFF;
+ break;
+ }
+
+ case ttLong:
+ {
+ scale32 = (real64) 0xFFFFFFFF;
+ break;
+ }
+
+ default:
+ ThrowBadFormat ();
+
+ }
+
+ fScale = (real32) (1.0 / scale32);
+
+ return ttFloat;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_DeltaPerRow::ModifiedBounds (const dng_rect &imageBounds)
+ {
+
+ return fAreaSpec.Overlap (imageBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_DeltaPerRow::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ uint32 cols = overlap.W ();
+
+ uint32 colPitch = fAreaSpec.ColPitch ();
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ const real32 *table = fTable->Buffer_real32 () +
+ ((overlap.t - fAreaSpec.Area ().t) /
+ fAreaSpec.RowPitch ());
+
+ for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
+ {
+
+ real32 rowDelta = *(table++) * fScale;
+
+ real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = x + rowDelta;
+
+ dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_DeltaPerColumn::dng_opcode_DeltaPerColumn (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table)
+
+ : dng_inplace_opcode (dngOpcode_DeltaPerColumn,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+ , fTable ()
+ , fScale (1.0f)
+
+ {
+
+ fTable.Reset (table.Release ());
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_DeltaPerColumn::dng_opcode_DeltaPerColumn (dng_host &host,
+ dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_DeltaPerColumn,
+ stream,
+ "DeltaPerColumn")
+
+ , fAreaSpec ()
+ , fTable ()
+ , fScale (1.0f)
+
+ {
+
+ uint32 dataSize = stream.Get_uint32 ();
+
+ fAreaSpec.GetData (stream);
+
+ uint32 deltas = (fAreaSpec.Area ().W () +
+ fAreaSpec.ColPitch () - 1) /
+ fAreaSpec.ColPitch ();
+
+ if (deltas != stream.Get_uint32 ())
+ {
+ ThrowBadFormat ();
+ }
+
+ if (dataSize != dng_area_spec::kDataSize + 4 + deltas * 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ fTable.Reset (host.Allocate (deltas * (uint32) sizeof (real32)));
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < deltas; j++)
+ {
+ table [j] = stream.Get_real32 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Count: %u\n", (unsigned) deltas);
+
+ for (uint32 k = 0; k < deltas && k < gDumpLineLimit; k++)
+ {
+ printf (" Delta [%u] = %f\n", (unsigned) k, table [k]);
+ }
+
+ if (deltas > gDumpLineLimit)
+ {
+ printf (" ... %u deltas skipped\n", (unsigned) (deltas - gDumpLineLimit));
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_DeltaPerColumn::PutData (dng_stream &stream) const
+ {
+
+ uint32 deltas = (fAreaSpec.Area ().W () +
+ fAreaSpec.ColPitch () - 1) /
+ fAreaSpec.ColPitch ();
+
+ stream.Put_uint32 (dng_area_spec::kDataSize + 4 + deltas * 4);
+
+ fAreaSpec.PutData (stream);
+
+ stream.Put_uint32 (deltas);
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < deltas; j++)
+ {
+ stream.Put_real32 (table [j]);
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_DeltaPerColumn::BufferPixelType (uint32 imagePixelType)
+ {
+
+ real64 scale32 = 1.0;
+
+ switch (imagePixelType)
+ {
+
+ case ttFloat:
+ break;
+
+ case ttShort:
+ {
+ scale32 = (real64) 0xFFFF;
+ break;
+ }
+
+ case ttLong:
+ {
+ scale32 = (real64) 0xFFFFFFFF;
+ break;
+ }
+
+ default:
+ ThrowBadFormat ();
+
+ }
+
+ fScale = (real32) (1.0 / scale32);
+
+ return ttFloat;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_DeltaPerColumn::ModifiedBounds (const dng_rect &imageBounds)
+ {
+
+ return fAreaSpec.Overlap (imageBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_DeltaPerColumn::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ uint32 rows = (overlap.H () + fAreaSpec.RowPitch () - 1) /
+ fAreaSpec.RowPitch ();
+
+ int32 rowStep = buffer.RowStep () * fAreaSpec.RowPitch ();
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ const real32 *table = fTable->Buffer_real32 () +
+ ((overlap.l - fAreaSpec.Area ().l) /
+ fAreaSpec.ColPitch ());
+
+ for (int32 col = overlap.l; col < overlap.r; col += fAreaSpec.ColPitch ())
+ {
+
+ real32 colDelta = *(table++) * fScale;
+
+ real32 *dPtr = buffer.DirtyPixel_real32 (overlap.t, col, plane);
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ real32 x = dPtr [0];
+
+ real32 y = x + colDelta;
+
+ dPtr [0] = Pin_real32 (0.0f, y, 1.0f);
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_ScalePerRow::dng_opcode_ScalePerRow (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table)
+
+ : dng_inplace_opcode (dngOpcode_ScalePerRow,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+ , fTable ()
+
+ {
+
+ fTable.Reset (table.Release ());
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_ScalePerRow::dng_opcode_ScalePerRow (dng_host &host,
+ dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_ScalePerRow,
+ stream,
+ "ScalePerRow")
+
+ , fAreaSpec ()
+ , fTable ()
+
+ {
+
+ uint32 dataSize = stream.Get_uint32 ();
+
+ fAreaSpec.GetData (stream);
+
+ uint32 scales = (fAreaSpec.Area ().H () +
+ fAreaSpec.RowPitch () - 1) /
+ fAreaSpec.RowPitch ();
+
+ if (scales != stream.Get_uint32 ())
+ {
+ ThrowBadFormat ();
+ }
+
+ if (dataSize != dng_area_spec::kDataSize + 4 + scales * 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ fTable.Reset (host.Allocate (scales * (uint32) sizeof (real32)));
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < scales; j++)
+ {
+ table [j] = stream.Get_real32 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Count: %u\n", (unsigned) scales);
+
+ for (uint32 k = 0; k < scales && k < gDumpLineLimit; k++)
+ {
+ printf (" Scale [%u] = %f\n", (unsigned) k, table [k]);
+ }
+
+ if (scales > gDumpLineLimit)
+ {
+ printf (" ... %u scales skipped\n", (unsigned) (scales - gDumpLineLimit));
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_ScalePerRow::PutData (dng_stream &stream) const
+ {
+
+ uint32 scales = (fAreaSpec.Area ().H () +
+ fAreaSpec.RowPitch () - 1) /
+ fAreaSpec.RowPitch ();
+
+ stream.Put_uint32 (dng_area_spec::kDataSize + 4 + scales * 4);
+
+ fAreaSpec.PutData (stream);
+
+ stream.Put_uint32 (scales);
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < scales; j++)
+ {
+ stream.Put_real32 (table [j]);
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_ScalePerRow::BufferPixelType (uint32 /* imagePixelType */)
+ {
+
+ return ttFloat;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_ScalePerRow::ModifiedBounds (const dng_rect &imageBounds)
+ {
+
+ return fAreaSpec.Overlap (imageBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_ScalePerRow::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ uint32 cols = overlap.W ();
+
+ uint32 colPitch = fAreaSpec.ColPitch ();
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ const real32 *table = fTable->Buffer_real32 () +
+ ((overlap.t - fAreaSpec.Area ().t) /
+ fAreaSpec.RowPitch ());
+
+ for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
+ {
+
+ real32 rowScale = *(table++);
+
+ real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = x * rowScale;
+
+ dPtr [col] = Min_real32 (y, 1.0f);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_ScalePerColumn::dng_opcode_ScalePerColumn (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table)
+
+ : dng_inplace_opcode (dngOpcode_ScalePerColumn,
+ dngVersion_1_3_0_0,
+ kFlag_None)
+
+ , fAreaSpec (areaSpec)
+ , fTable ()
+
+ {
+
+ fTable.Reset (table.Release ());
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_ScalePerColumn::dng_opcode_ScalePerColumn (dng_host &host,
+ dng_stream &stream)
+
+ : dng_inplace_opcode (dngOpcode_ScalePerColumn,
+ stream,
+ "ScalePerColumn")
+
+ , fAreaSpec ()
+ , fTable ()
+
+ {
+
+ uint32 dataSize = stream.Get_uint32 ();
+
+ fAreaSpec.GetData (stream);
+
+ uint32 scales = (fAreaSpec.Area ().W () +
+ fAreaSpec.ColPitch () - 1) /
+ fAreaSpec.ColPitch ();
+
+ if (scales != stream.Get_uint32 ())
+ {
+ ThrowBadFormat ();
+ }
+
+ if (dataSize != dng_area_spec::kDataSize + 4 + scales * 4)
+ {
+ ThrowBadFormat ();
+ }
+
+ fTable.Reset (host.Allocate (scales * (uint32) sizeof (real32)));
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < scales; j++)
+ {
+ table [j] = stream.Get_real32 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Count: %u\n", (unsigned) scales);
+
+ for (uint32 k = 0; k < scales && k < gDumpLineLimit; k++)
+ {
+ printf (" Scale [%u] = %f\n", (unsigned) k, table [k]);
+ }
+
+ if (scales > gDumpLineLimit)
+ {
+ printf (" ... %u deltas skipped\n", (unsigned) (scales - gDumpLineLimit));
+ }
+
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_ScalePerColumn::PutData (dng_stream &stream) const
+ {
+
+ uint32 scales = (fAreaSpec.Area ().W () +
+ fAreaSpec.ColPitch () - 1) /
+ fAreaSpec.ColPitch ();
+
+ stream.Put_uint32 (dng_area_spec::kDataSize + 4 + scales * 4);
+
+ fAreaSpec.PutData (stream);
+
+ stream.Put_uint32 (scales);
+
+ real32 *table = fTable->Buffer_real32 ();
+
+ for (uint32 j = 0; j < scales; j++)
+ {
+ stream.Put_real32 (table [j]);
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_opcode_ScalePerColumn::BufferPixelType (uint32 /* imagePixelType */)
+ {
+
+ return ttFloat;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_opcode_ScalePerColumn::ModifiedBounds (const dng_rect &imageBounds)
+ {
+
+ return fAreaSpec.Overlap (imageBounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_ScalePerColumn::ProcessArea (dng_negative & /* negative */,
+ uint32 /* threadIndex */,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+
+ dng_rect overlap = fAreaSpec.Overlap (dstArea);
+
+ if (overlap.NotEmpty ())
+ {
+
+ uint32 rows = (overlap.H () + fAreaSpec.RowPitch () - 1) /
+ fAreaSpec.RowPitch ();
+
+ int32 rowStep = buffer.RowStep () * fAreaSpec.RowPitch ();
+
+ for (uint32 plane = fAreaSpec.Plane ();
+ plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
+ plane < buffer.Planes ();
+ plane++)
+ {
+
+ const real32 *table = fTable->Buffer_real32 () +
+ ((overlap.l - fAreaSpec.Area ().l) /
+ fAreaSpec.ColPitch ());
+
+ for (int32 col = overlap.l; col < overlap.r; col += fAreaSpec.ColPitch ())
+ {
+
+ real32 colScale = *(table++);
+
+ real32 *dPtr = buffer.DirtyPixel_real32 (overlap.t, col, plane);
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ real32 x = dPtr [0];
+
+ real32 y = x * colScale;
+
+ dPtr [0] = Min_real32 (y, 1.0f);
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_misc_opcodes.h b/gpr/source/lib/dng_sdk/dng_misc_opcodes.h
new file mode 100644
index 0000000..7a1268a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_misc_opcodes.h
@@ -0,0 +1,417 @@
+/*****************************************************************************/
+// Copyright 2008-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_misc_opcodes.h#2 $ */
+/* $DateTime: 2012/08/02 06:09:06 $ */
+/* $Change: 841096 $ */
+/* $Author: erichan $ */
+
+/** \file
+ * Miscellaneous DNG opcodes.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_misc_opcodes__
+#define __dng_misc_opcodes__
+
+/*****************************************************************************/
+
+#include "dng_opcodes.h"
+
+/*****************************************************************************/
+
+/// \brief Opcode to trim image to a specified rectangle.
+
+class dng_opcode_TrimBounds: public dng_opcode
+ {
+
+ private:
+
+ dng_rect fBounds;
+
+ public:
+
+ /// Create opcode to trim image to the specified bounds.
+
+ dng_opcode_TrimBounds (const dng_rect &bounds);
+
+ dng_opcode_TrimBounds (dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief A class to describe an area of an image, including a pixel subrectangle,
+/// plane range, and row/column pitch (e.g., for mosaic images). Useful for
+/// specifying opcodes that only apply to specific color planes or pixel types (e.g.,
+/// only one of the two green Bayer pixels).
+
+class dng_area_spec
+ {
+
+ public:
+
+ enum
+ {
+ kDataSize = 32
+ };
+
+ private:
+
+ dng_rect fArea;
+
+ uint32 fPlane;
+ uint32 fPlanes;
+
+ uint32 fRowPitch;
+ uint32 fColPitch;
+
+ public:
+
+ /// Create an empty area.
+
+ dng_area_spec (const dng_rect &area = dng_rect (),
+ uint32 plane = 0,
+ uint32 planes = 1,
+ uint32 rowPitch = 1,
+ uint32 colPitch = 1)
+
+ : fArea (area)
+ , fPlane (plane)
+ , fPlanes (planes)
+ , fRowPitch (rowPitch)
+ , fColPitch (colPitch)
+
+ {
+ }
+
+ /// The pixel area.
+
+ const dng_rect & Area () const
+ {
+ return fArea;
+ }
+
+ /// The first plane.
+
+ uint32 Plane () const
+ {
+ return fPlane;
+ }
+
+ /// The total number of planes.
+
+ uint32 Planes () const
+ {
+ return fPlanes;
+ }
+
+ /// The row pitch (i.e., stride). A pitch of 1 means all rows.
+
+ uint32 RowPitch () const
+ {
+ return fRowPitch;
+ }
+
+ /// The column pitch (i.e., stride). A pitch of 1 means all columns.
+
+ uint32 ColPitch () const
+ {
+ return fColPitch;
+ }
+
+ /// Read area data from the specified stream.
+
+ void GetData (dng_stream &stream);
+
+ /// Write area data to the specified stream.
+
+ void PutData (dng_stream &stream) const;
+
+ /// Compute and return pixel area overlap (i.e., intersection) between this
+ /// area and the specified tile.
+
+ dng_rect Overlap (const dng_rect &tile) const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to apply a 1D function (represented as a 16-bit table) to an
+/// image area.
+
+class dng_opcode_MapTable: public dng_inplace_opcode
+ {
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ AutoPtr<dng_memory_block> fTable;
+
+ uint32 fCount;
+
+ public:
+
+ /// Create a MapTable opcode with the specified area, table, and number of
+ /// table entries.
+
+ dng_opcode_MapTable (dng_host &host,
+ const dng_area_spec &areaSpec,
+ const uint16 *table,
+ uint32 count = 0x10000);
+
+ dng_opcode_MapTable (dng_host &host,
+ dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType);
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ private:
+
+ void ReplicateLastEntry ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to apply a 1D function (represented as a polynomial) to an
+/// image area.
+
+class dng_opcode_MapPolynomial: public dng_inplace_opcode
+ {
+
+ public:
+
+ enum
+ {
+ kMaxDegree = 8
+ };
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ uint32 fDegree;
+
+ real64 fCoefficient [kMaxDegree + 1];
+
+ real32 fCoefficient32 [kMaxDegree + 1];
+
+ public:
+
+ /// Create a MapPolynomial opcode with the specified area, polynomial
+ /// degree, and polynomial coefficients. The function that will be
+ /// applied to each pixel x is:
+ ///
+ /// f (x) = coefficient [0] + ((x * coefficient [1]) +
+ /// (x^2 * coefficient [2]) +
+ /// (x^3 * coefficient [3]) +
+ /// (x^4 * coefficient [4]) ...
+
+ dng_opcode_MapPolynomial (const dng_area_spec &areaSpec,
+ uint32 degree,
+ const real64 *coefficient);
+
+ dng_opcode_MapPolynomial (dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType);
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to apply a delta (i.e., offset) that varies per row. Within
+/// a row, the same delta value is applied to all specified pixels.
+
+class dng_opcode_DeltaPerRow: public dng_inplace_opcode
+ {
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ AutoPtr<dng_memory_block> fTable;
+
+ real32 fScale;
+
+ public:
+
+ /// Create a DeltaPerRow opcode with the specified area and row deltas
+ /// (specified as a table of 32-bit floats).
+
+ dng_opcode_DeltaPerRow (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table);
+
+ dng_opcode_DeltaPerRow (dng_host &host,
+ dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType);
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to apply a delta (i.e., offset) that varies per column.
+/// Within a column, the same delta value is applied to all specified pixels.
+
+class dng_opcode_DeltaPerColumn: public dng_inplace_opcode
+ {
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ AutoPtr<dng_memory_block> fTable;
+
+ real32 fScale;
+
+ public:
+
+ /// Create a DeltaPerColumn opcode with the specified area and column
+ /// deltas (specified as a table of 32-bit floats).
+
+ dng_opcode_DeltaPerColumn (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table);
+
+ dng_opcode_DeltaPerColumn (dng_host &host,
+ dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType);
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to apply a scale factor that varies per row. Within a row,
+/// the same scale factor is applied to all specified pixels.
+
+class dng_opcode_ScalePerRow: public dng_inplace_opcode
+ {
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ AutoPtr<dng_memory_block> fTable;
+
+ public:
+
+ /// Create a ScalePerRow opcode with the specified area and row scale
+ /// factors (specified as a table of 32-bit floats).
+
+ dng_opcode_ScalePerRow (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table);
+
+ dng_opcode_ScalePerRow (dng_host &host,
+ dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType);
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief An opcode to apply a scale factor that varies per column. Within a
+/// column, the same scale factor is applied to all specified pixels.
+
+class dng_opcode_ScalePerColumn: public dng_inplace_opcode
+ {
+
+ private:
+
+ dng_area_spec fAreaSpec;
+
+ AutoPtr<dng_memory_block> fTable;
+
+ public:
+
+ /// Create a ScalePerColumn opcode with the specified area and column
+ /// scale factors (specified as a table of 32-bit floats).
+
+ dng_opcode_ScalePerColumn (const dng_area_spec &areaSpec,
+ AutoPtr<dng_memory_block> &table);
+
+ dng_opcode_ScalePerColumn (dng_host &host,
+ dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType);
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds);
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_mosaic_info.cpp b/gpr/source/lib/dng_sdk/dng_mosaic_info.cpp
new file mode 100644
index 0000000..a98a59f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_mosaic_info.cpp
@@ -0,0 +1,1991 @@
+/*****************************************************************************/
+// Copyright 2006-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_mosaic_info.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_mosaic_info.h"
+
+#include "dng_area_task.h"
+#include "dng_assertions.h"
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_filter_task.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image.h"
+#include "dng_info.h"
+#include "dng_negative.h"
+#include "dng_pixel_buffer.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_tile_iterator.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+// A interpolation kernel for a single pixel of a single plane.
+
+class dng_bilinear_kernel
+ {
+
+ public:
+
+ enum
+ {
+ kMaxCount = 8
+ };
+
+ uint32 fCount;
+
+ dng_point fDelta [kMaxCount];
+
+ real32 fWeight32 [kMaxCount];
+ uint16 fWeight16 [kMaxCount];
+
+ int32 fOffset [kMaxCount];
+
+ public:
+
+ dng_bilinear_kernel ()
+ : fCount (0)
+ {
+ }
+
+ void Add (const dng_point &delta,
+ real32 weight);
+
+ void Finalize (const dng_point &scale,
+ uint32 patRow,
+ uint32 patCol,
+ int32 rowStep,
+ int32 colStep);
+
+ };
+
+/*****************************************************************************/
+
+void dng_bilinear_kernel::Add (const dng_point &delta,
+ real32 weight)
+ {
+
+ // Don't add zero weight elements.
+
+ if (weight <= 0.0f)
+ {
+ return;
+ }
+
+ // If the delta already matches an existing element, just combine the
+ // weights.
+
+ for (uint32 j = 0; j < fCount; j++)
+ {
+
+ if (fDelta [j] == delta)
+ {
+
+ fWeight32 [j] += weight;
+
+ return;
+
+ }
+
+ }
+
+ // Add element to list.
+
+ DNG_ASSERT (fCount < kMaxCount, "Too many kernel entries")
+
+ fDelta [fCount] = delta;
+ fWeight32 [fCount] = weight;
+
+ fCount++;
+
+ }
+
+/*****************************************************************************/
+
+void dng_bilinear_kernel::Finalize (const dng_point &scale,
+ uint32 patRow,
+ uint32 patCol,
+ int32 rowStep,
+ int32 colStep)
+ {
+
+ uint32 j;
+
+ // Adjust deltas to compensate for interpolation upscaling.
+
+ for (j = 0; j < fCount; j++)
+ {
+
+ dng_point &delta = fDelta [j];
+
+ if (scale.v == 2)
+ {
+
+ delta.v = (delta.v + (int32) (patRow & 1)) >> 1;
+
+ }
+
+ if (scale.h == 2)
+ {
+
+ delta.h = (delta.h + (int32) (patCol & 1)) >> 1;
+
+ }
+
+ }
+
+ // Sort entries into row-column scan order.
+
+ while (true)
+ {
+
+ bool didSwap = false;
+
+ for (j = 1; j < fCount; j++)
+ {
+
+ dng_point &delta0 = fDelta [j - 1];
+ dng_point &delta1 = fDelta [j ];
+
+ if (delta0.v > delta1.v ||
+ (delta0.v == delta1.v &&
+ delta0.h > delta1.h))
+ {
+
+ didSwap = true;
+
+ dng_point tempDelta = delta0;
+
+ delta0 = delta1;
+ delta1 = tempDelta;
+
+ real32 tempWeight = fWeight32 [j - 1];
+
+ fWeight32 [j - 1] = fWeight32 [j];
+ fWeight32 [j ] = tempWeight;
+
+ }
+
+ }
+
+ if (!didSwap)
+ {
+ break;
+ }
+
+ }
+
+ // Calculate offsets.
+
+ for (j = 0; j < fCount; j++)
+ {
+
+ fOffset [j] = rowStep * fDelta [j].v +
+ colStep * fDelta [j].h;
+
+ }
+
+ // Calculate 16-bit weights.
+
+ uint16 total = 0;
+ uint32 biggest = 0;
+
+ for (j = 0; j < fCount; j++)
+ {
+
+ // Round weights to 8 fractional bits.
+
+ fWeight16 [j] = (uint16) Round_uint32 (fWeight32 [j] * 256.0);
+
+ // Keep track of total of weights.
+
+ total += fWeight16 [j];
+
+ // Keep track of which weight is biggest.
+
+ if (fWeight16 [biggest] < fWeight16 [j])
+ {
+
+ biggest = j;
+
+ }
+
+ }
+
+ // Adjust largest entry so total of weights is exactly 256.
+
+ fWeight16 [biggest] += (256 - total);
+
+ // Recompute the floating point weights from the rounded integer weights
+ // so results match more closely.
+
+ for (j = 0; j < fCount; j++)
+ {
+
+ fWeight32 [j] = fWeight16 [j] * (1.0f / 256.0f);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_bilinear_pattern
+ {
+
+ public:
+
+ enum
+ {
+ kMaxPattern = kMaxCFAPattern * 2
+ };
+
+ dng_point fScale;
+
+ uint32 fPatRows;
+ uint32 fPatCols;
+
+ dng_bilinear_kernel fKernel [kMaxPattern]
+ [kMaxPattern];
+
+ uint32 fCounts [kMaxPattern]
+ [kMaxPattern];
+
+ int32 *fOffsets [kMaxPattern]
+ [kMaxPattern];
+
+ uint16 *fWeights16 [kMaxPattern]
+ [kMaxPattern];
+
+ real32 *fWeights32 [kMaxPattern]
+ [kMaxPattern];
+
+ public:
+
+ dng_bilinear_pattern ()
+
+ : fScale ()
+ , fPatRows (0)
+ , fPatCols (0)
+
+ {
+ }
+
+ private:
+
+ uint32 DeltaRow (uint32 row, int32 delta)
+ {
+ return (row + fPatRows + delta) % fPatRows;
+ }
+
+ uint32 DeltaCol (uint32 col, int32 delta)
+ {
+ return (col + fPatCols + delta) % fPatCols;
+ }
+
+ real32 LinearWeight1 (int32 d1, int32 d2)
+ {
+ if (d1 == d2)
+ return 1.0f;
+ else
+ return d2 / (real32) (d2 - d1);
+ }
+
+ real32 LinearWeight2 (int32 d1, int32 d2)
+ {
+ if (d1 == d2)
+ return 0.0f;
+ else
+ return -d1 / (real32) (d2 - d1);
+ }
+
+ public:
+
+ void Calculate (const dng_mosaic_info &info,
+ uint32 dstPlane,
+ int32 rowStep,
+ int32 colStep);
+
+ };
+
+/*****************************************************************************/
+
+void dng_bilinear_pattern::Calculate (const dng_mosaic_info &info,
+ uint32 dstPlane,
+ int32 rowStep,
+ int32 colStep)
+ {
+
+ uint32 j;
+ uint32 k;
+ uint32 patRow;
+ uint32 patCol;
+
+ // Find destination pattern size.
+
+ fScale = info.FullScale ();
+
+ fPatRows = info.fCFAPatternSize.v * fScale.v;
+ fPatCols = info.fCFAPatternSize.h * fScale.h;
+
+ // See if we need to scale up just while computing the kernels.
+
+ dng_point tempScale (1, 1);
+
+ if (info.fCFALayout >= 6)
+ {
+
+ tempScale = dng_point (2, 2);
+
+ fPatRows *= tempScale.v;
+ fPatCols *= tempScale.h;
+
+ }
+
+ // Find a boolean map for this plane color and layout.
+
+ bool map [kMaxPattern]
+ [kMaxPattern];
+
+ uint8 planeColor = info.fCFAPlaneColor [dstPlane];
+
+ switch (info.fCFALayout)
+ {
+
+ case 1: // Rectangular (or square) layout
+ {
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ map [j] [k] = (info.fCFAPattern [j] [k] == planeColor);
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ // Note that when the descriptions of the staggered patterns refer to even rows or
+ // columns, this mean the second, fourth, etc. (i.e. using one-based numbering).
+ // This needs to be clarified in the DNG specification.
+
+ case 2: // Staggered layout A: even (1-based) columns are offset down by 1/2 row
+ {
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ if ((j & 1) != (k & 1))
+ {
+
+ map [j] [k] = false;
+
+ }
+
+ else
+ {
+
+ map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor);
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case 3: // Staggered layout B: even (1-based) columns are offset up by 1/2 row
+ {
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ if ((j & 1) == (k & 1))
+ {
+
+ map [j] [k] = false;
+
+ }
+
+ else
+ {
+
+ map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor);
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case 4: // Staggered layout C: even (1-based) rows are offset right by 1/2 column
+ {
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ if ((j & 1) != (k & 1))
+ {
+
+ map [j] [k] = false;
+
+ }
+
+ else
+ {
+
+ map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor);
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case 5: // Staggered layout D: even (1-based) rows are offset left by 1/2 column
+ {
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ if ((j & 1) == (k & 1))
+ {
+
+ map [j] [k] = false;
+
+ }
+
+ else
+ {
+
+ map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor);
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case 6: // Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column
+ case 7: // Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column
+ case 8: // Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column
+ case 9: // Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column
+ {
+
+ uint32 eRow = (info.fCFALayout == 6 ||
+ info.fCFALayout == 7) ? 1 : 3;
+
+ uint32 eCol = (info.fCFALayout == 6 ||
+ info.fCFALayout == 8) ? 1 : 3;
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ uint32 jj = j & 3;
+ uint32 kk = k & 3;
+
+ if ((jj != 0 && jj != eRow) ||
+ (kk != 0 && kk != eCol))
+ {
+
+ map [j] [k] = false;
+
+ }
+
+ else
+ {
+
+ map [j] [k] = (info.fCFAPattern [((j >> 1) & ~1) + Min_uint32 (jj, 1)]
+ [((k >> 1) & ~1) + Min_uint32 (kk, 1)] == planeColor);
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ default:
+ ThrowProgramError ();
+
+ }
+
+ // Find projections of maps.
+
+ bool mapH [kMaxPattern];
+ bool mapV [kMaxPattern];
+
+ for (j = 0; j < kMaxPattern; j++)
+ {
+
+ mapH [j] = false;
+ mapV [j] = false;
+
+ }
+
+ for (j = 0; j < fPatRows; j++)
+ {
+
+ for (k = 0; k < fPatCols; k++)
+ {
+
+ if (map [j] [k])
+ {
+
+ mapV [j] = true;
+ mapH [k] = true;
+
+ }
+
+ }
+
+ }
+
+ // Find kernel for each patten entry.
+
+ for (patRow = 0; patRow < fPatRows; patRow += tempScale.v)
+ {
+
+ for (patCol = 0; patCol < fPatCols; patCol += tempScale.h)
+ {
+
+ dng_bilinear_kernel &kernel = fKernel [patRow] [patCol];
+
+ // Special case no interpolation case.
+
+ if (map [patRow] [patCol])
+ {
+
+ kernel.Add (dng_point (0, 0), 1.0f);
+
+ continue;
+
+ }
+
+ // Special case common patterns in 3 by 3 neighborhood.
+
+ uint32 n = DeltaRow (patRow, -1);
+ uint32 s = DeltaRow (patRow, 1);
+ uint32 w = DeltaCol (patCol, -1);
+ uint32 e = DeltaCol (patCol, 1);
+
+ bool mapNW = map [n] [w];
+ bool mapN = map [n] [patCol];
+ bool mapNE = map [n] [e];
+
+ bool mapW = map [patRow] [w];
+ bool mapE = map [patRow] [e];
+
+ bool mapSW = map [s] [w];
+ bool mapS = map [s] [patCol];
+ bool mapSE = map [s] [e];
+
+ // All sides.
+
+ if (mapN && mapS && mapW && mapW)
+ {
+
+ kernel.Add (dng_point (-1, 0), 0.25f);
+ kernel.Add (dng_point ( 0, -1), 0.25f);
+ kernel.Add (dng_point ( 0, 1), 0.25f);
+ kernel.Add (dng_point ( 1, 0), 0.25f);
+
+ continue;
+
+ }
+
+ // N & S.
+
+ if (mapN && mapS)
+ {
+
+ kernel.Add (dng_point (-1, 0), 0.5f);
+ kernel.Add (dng_point ( 1, 0), 0.5f);
+
+ continue;
+
+ }
+
+ // E & W.
+
+ if (mapW && mapE)
+ {
+
+ kernel.Add (dng_point ( 0, -1), 0.5f);
+ kernel.Add (dng_point ( 0, 1), 0.5f);
+
+ continue;
+
+ }
+
+ // N & SW & SE.
+
+ if (mapN && mapSW && mapSE)
+ {
+
+ kernel.Add (dng_point (-1, 0), 0.50f);
+ kernel.Add (dng_point ( 1, -1), 0.25f);
+ kernel.Add (dng_point ( 1, 1), 0.25f);
+
+ continue;
+
+ }
+
+ // S & NW & NE.
+
+ if (mapS && mapNW && mapNE)
+ {
+
+ kernel.Add (dng_point (-1, -1), 0.25f);
+ kernel.Add (dng_point (-1, 1), 0.25f);
+ kernel.Add (dng_point ( 1, 0), 0.50f);
+
+ continue;
+
+ }
+
+ // W & NE & SE.
+
+ if (mapW && mapNE && mapSE)
+ {
+
+ kernel.Add (dng_point (-1, 1), 0.25f);
+ kernel.Add (dng_point ( 0, -1), 0.50f);
+ kernel.Add (dng_point ( 1, 1), 0.25f);
+
+ continue;
+
+ }
+
+ // E & NW & SW.
+
+ if (mapE && mapNW && mapSW)
+ {
+
+ kernel.Add (dng_point (-1, -1), 0.25f);
+ kernel.Add (dng_point ( 0, 1), 0.50f);
+ kernel.Add (dng_point ( 1, -1), 0.25f);
+
+ continue;
+
+ }
+
+ // Four corners.
+
+ if (mapNW && mapNE && mapSE && mapSW)
+ {
+
+ kernel.Add (dng_point (-1, -1), 0.25f);
+ kernel.Add (dng_point (-1, 1), 0.25f);
+ kernel.Add (dng_point ( 1, -1), 0.25f);
+ kernel.Add (dng_point ( 1, 1), 0.25f);
+
+ continue;
+
+ }
+
+ // NW & SE
+
+ if (mapNW && mapSE)
+ {
+
+ kernel.Add (dng_point (-1, -1), 0.50f);
+ kernel.Add (dng_point ( 1, 1), 0.50f);
+
+ continue;
+
+ }
+
+ // NE & SW
+
+ if (mapNE && mapSW)
+ {
+
+ kernel.Add (dng_point (-1, 1), 0.50f);
+ kernel.Add (dng_point ( 1, -1), 0.50f);
+
+ continue;
+
+ }
+
+ // Else use double-bilinear kernel.
+
+ int32 dv1 = 0;
+ int32 dv2 = 0;
+
+ while (!mapV [DeltaRow (patRow, dv1)])
+ {
+ dv1--;
+ }
+
+ while (!mapV [DeltaRow (patRow, dv2)])
+ {
+ dv2++;
+ }
+
+ real32 w1 = LinearWeight1 (dv1, dv2) * 0.5f;
+ real32 w2 = LinearWeight2 (dv1, dv2) * 0.5f;
+
+ int32 v1 = DeltaRow (patRow, dv1);
+ int32 v2 = DeltaRow (patRow, dv2);
+
+ int32 dh1 = 0;
+ int32 dh2 = 0;
+
+ while (!map [v1] [DeltaCol (patCol, dh1)])
+ {
+ dh1--;
+ }
+
+ while (!map [v1] [DeltaCol (patCol, dh2)])
+ {
+ dh2++;
+ }
+
+ kernel.Add (dng_point (dv1, dh1),
+ LinearWeight1 (dh1, dh2) * w1);
+
+ kernel.Add (dng_point (dv1, dh2),
+ LinearWeight2 (dh1, dh2) * w1);
+
+ dh1 = 0;
+ dh2 = 0;
+
+ while (!map [v2] [DeltaCol (patCol, dh1)])
+ {
+ dh1--;
+ }
+
+ while (!map [v2] [DeltaCol (patCol, dh2)])
+ {
+ dh2++;
+ }
+
+ kernel.Add (dng_point (dv2, dh1),
+ LinearWeight1 (dh1, dh2) * w2);
+
+ kernel.Add (dng_point (dv2, dh2),
+ LinearWeight2 (dh1, dh2) * w2);
+
+ dh1 = 0;
+ dh2 = 0;
+
+ while (!mapH [DeltaCol (patCol, dh1)])
+ {
+ dh1--;
+ }
+
+ while (!mapH [DeltaCol (patCol, dh2)])
+ {
+ dh2++;
+ }
+
+ w1 = LinearWeight1 (dh1, dh2) * 0.5f;
+ w2 = LinearWeight2 (dh1, dh2) * 0.5f;
+
+ int32 h1 = DeltaCol (patCol, dh1);
+ int32 h2 = DeltaCol (patCol, dh2);
+
+ dv1 = 0;
+ dv2 = 0;
+
+ while (!map [DeltaRow (patRow, dv1)] [h1])
+ {
+ dv1--;
+ }
+
+ while (!map [DeltaRow (patRow, dv2)] [h1])
+ {
+ dv2++;
+ }
+
+ kernel.Add (dng_point (dv1, dh1),
+ LinearWeight1 (dv1, dv2) * w1);
+
+ kernel.Add (dng_point (dv2, dh1),
+ LinearWeight2 (dv1, dv2) * w1);
+
+ dv1 = 0;
+ dv2 = 0;
+
+ while (!map [DeltaRow (patRow, dv1)] [h2])
+ {
+ dv1--;
+ }
+
+ while (!map [DeltaRow (patRow, dv2)] [h2])
+ {
+ dv2++;
+ }
+
+ kernel.Add (dng_point (dv1, dh2),
+ LinearWeight1 (dv1, dv2) * w2);
+
+ kernel.Add (dng_point (dv2, dh2),
+ LinearWeight2 (dv1, dv2) * w2);
+
+ }
+
+ }
+
+ // Deal with temp scale case.
+
+ if (tempScale == dng_point (2, 2))
+ {
+
+ fPatRows /= tempScale.v;
+ fPatCols /= tempScale.h;
+
+ for (patRow = 0; patRow < fPatRows; patRow++)
+ {
+
+ for (patCol = 0; patCol < fPatCols; patCol++)
+ {
+
+ int32 patRow2 = patRow << 1;
+ int32 patCol2 = patCol << 1;
+
+ dng_bilinear_kernel &kernel = fKernel [patRow2] [patCol2];
+
+ for (j = 0; j < kernel.fCount; j++)
+ {
+
+ int32 x = patRow2 + kernel.fDelta [j].v;
+
+ if ((x & 3) != 0)
+ {
+ x = (x & ~3) + 2;
+ }
+
+ kernel.fDelta [j].v = ((x - patRow2) >> 1);
+
+ x = patCol2 + kernel.fDelta [j].h;
+
+ if ((x & 3) != 0)
+ {
+ x = (x & ~3) + 2;
+ }
+
+ kernel.fDelta [j].h = ((x - patCol2) >> 1);
+
+ }
+
+ kernel.Finalize (fScale,
+ patRow,
+ patCol,
+ rowStep,
+ colStep);
+
+ fCounts [patRow] [patCol] = kernel.fCount;
+ fOffsets [patRow] [patCol] = kernel.fOffset;
+ fWeights16 [patRow] [patCol] = kernel.fWeight16;
+ fWeights32 [patRow] [patCol] = kernel.fWeight32;
+
+ }
+
+ }
+
+ }
+
+ // Non-temp scale case.
+
+ else
+ {
+
+ for (patRow = 0; patRow < fPatRows; patRow++)
+ {
+
+ for (patCol = 0; patCol < fPatCols; patCol++)
+ {
+
+ dng_bilinear_kernel &kernel = fKernel [patRow] [patCol];
+
+ kernel.Finalize (fScale,
+ patRow,
+ patCol,
+ rowStep,
+ colStep);
+
+ fCounts [patRow] [patCol] = kernel.fCount;
+ fOffsets [patRow] [patCol] = kernel.fOffset;
+ fWeights16 [patRow] [patCol] = kernel.fWeight16;
+ fWeights32 [patRow] [patCol] = kernel.fWeight32;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_bilinear_interpolator
+ {
+
+ private:
+
+ dng_bilinear_pattern fPattern [kMaxColorPlanes];
+
+ public:
+
+ dng_bilinear_interpolator (const dng_mosaic_info &info,
+ int32 rowStep,
+ int32 colStep);
+
+ void Interpolate (dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer);
+
+ };
+
+/*****************************************************************************/
+
+dng_bilinear_interpolator::dng_bilinear_interpolator (const dng_mosaic_info &info,
+ int32 rowStep,
+ int32 colStep)
+ {
+
+ for (uint32 dstPlane = 0; dstPlane < info.fColorPlanes; dstPlane++)
+ {
+
+ fPattern [dstPlane] . Calculate (info,
+ dstPlane,
+ rowStep,
+ colStep);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_bilinear_interpolator::Interpolate (dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer)
+ {
+
+ uint32 patCols = fPattern [0] . fPatCols;
+ uint32 patRows = fPattern [0] . fPatRows;
+
+ dng_point scale = fPattern [0] . fScale;
+
+ uint32 sRowShift = scale.v - 1;
+ uint32 sColShift = scale.h - 1;
+
+ int32 dstCol = dstBuffer.fArea.l;
+
+ int32 srcCol = dstCol >> sColShift;
+
+ uint32 patPhase = dstCol % patCols;
+
+ for (int32 dstRow = dstBuffer.fArea.t;
+ dstRow < dstBuffer.fArea.b;
+ dstRow++)
+ {
+
+ int32 srcRow = dstRow >> sRowShift;
+
+ uint32 patRow = dstRow % patRows;
+
+ for (uint32 dstPlane = 0;
+ dstPlane < dstBuffer.fPlanes;
+ dstPlane++)
+ {
+
+ const void *sPtr = srcBuffer.ConstPixel (srcRow,
+ srcCol,
+ srcBuffer.fPlane);
+
+ void *dPtr = dstBuffer.DirtyPixel (dstRow,
+ dstCol,
+ dstPlane);
+
+ if (dstBuffer.fPixelType == ttShort)
+ {
+
+ DoBilinearRow16 ((const uint16 *) sPtr,
+ (uint16 *) dPtr,
+ dstBuffer.fArea.W (),
+ patPhase,
+ patCols,
+ fPattern [dstPlane].fCounts [patRow],
+ fPattern [dstPlane].fOffsets [patRow],
+ fPattern [dstPlane].fWeights16 [patRow],
+ sColShift);
+
+ }
+
+ else
+ {
+
+ DoBilinearRow32 ((const real32 *) sPtr,
+ (real32 *) dPtr,
+ dstBuffer.fArea.W (),
+ patPhase,
+ patCols,
+ fPattern [dstPlane].fCounts [patRow],
+ fPattern [dstPlane].fOffsets [patRow],
+ fPattern [dstPlane].fWeights32 [patRow],
+ sColShift);
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_fast_interpolator: public dng_filter_task
+ {
+
+ protected:
+
+ const dng_mosaic_info &fInfo;
+
+ dng_point fDownScale;
+
+ uint32 fFilterColor [kMaxCFAPattern] [kMaxCFAPattern];
+
+ public:
+
+ dng_fast_interpolator (const dng_mosaic_info &info,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_point &downScale,
+ uint32 srcPlane);
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea);
+
+ virtual void ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer);
+
+ };
+
+/*****************************************************************************/
+
+dng_fast_interpolator::dng_fast_interpolator (const dng_mosaic_info &info,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_point &downScale,
+ uint32 srcPlane)
+
+ : dng_filter_task (srcImage,
+ dstImage)
+
+ , fInfo (info )
+ , fDownScale (downScale)
+
+ {
+
+ fSrcPlane = srcPlane;
+ fSrcPlanes = 1;
+
+ fSrcPixelType = ttShort;
+ fDstPixelType = ttShort;
+
+ fSrcRepeat = fInfo.fCFAPatternSize;
+
+ fUnitCell = fInfo.fCFAPatternSize;
+
+ fMaxTileSize = dng_point (256 / fDownScale.v,
+ 256 / fDownScale.h);
+
+ fMaxTileSize.h = Max_int32 (fMaxTileSize.h, fUnitCell.h);
+ fMaxTileSize.v = Max_int32 (fMaxTileSize.v, fUnitCell.v);
+
+ // Find color map.
+
+ {
+
+ for (int32 r = 0; r < fInfo.fCFAPatternSize.v; r++)
+ {
+
+ for (int32 c = 0; c < fInfo.fCFAPatternSize.h; c++)
+ {
+
+ uint8 key = fInfo.fCFAPattern [r] [c];
+
+ for (uint32 index = 0; index < fInfo.fColorPlanes; index++)
+ {
+
+ if (key == fInfo.fCFAPlaneColor [index])
+ {
+
+ fFilterColor [r] [c] = index;
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_fast_interpolator::SrcArea (const dng_rect &dstArea)
+ {
+
+ return dng_rect (dstArea.t * fDownScale.v,
+ dstArea.l * fDownScale.h,
+ dstArea.b * fDownScale.v,
+ dstArea.r * fDownScale.h);
+
+ }
+
+/*****************************************************************************/
+
+void dng_fast_interpolator::ProcessArea (uint32 /* threadIndex */,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer)
+ {
+
+ dng_rect srcArea = srcBuffer.fArea;
+ dng_rect dstArea = dstBuffer.fArea;
+
+ // Downsample buffer.
+
+ int32 srcRow = srcArea.t;
+
+ uint32 srcRowPhase1 = 0;
+ uint32 srcRowPhase2 = 0;
+
+ uint32 patRows = fInfo.fCFAPatternSize.v;
+ uint32 patCols = fInfo.fCFAPatternSize.h;
+
+ uint32 cellRows = fDownScale.v;
+ uint32 cellCols = fDownScale.h;
+
+ uint32 plane;
+ uint32 planes = fInfo.fColorPlanes;
+
+ int32 dstPlaneStep = dstBuffer.fPlaneStep;
+
+ uint32 total [kMaxColorPlanes];
+ uint32 count [kMaxColorPlanes];
+
+ for (plane = 0; plane < planes; plane++)
+ {
+ total [plane] = 0;
+ count [plane] = 0;
+ }
+
+ for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
+ {
+
+ const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (srcRow,
+ srcArea.l,
+ fSrcPlane);
+
+ uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow,
+ dstArea.l,
+ 0);
+
+ uint32 srcColPhase1 = 0;
+ uint32 srcColPhase2 = 0;
+
+ for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++)
+ {
+
+ const uint16 *ssPtr = sPtr;
+
+ srcRowPhase2 = srcRowPhase1;
+
+ for (uint32 cellRow = 0; cellRow < cellRows; cellRow++)
+ {
+
+ const uint32 *filterRow = fFilterColor [srcRowPhase2];
+
+ if (++srcRowPhase2 == patRows)
+ {
+ srcRowPhase2 = 0;
+ }
+
+ srcColPhase2 = srcColPhase1;
+
+ for (uint32 cellCol = 0; cellCol < cellCols; cellCol++)
+ {
+
+ uint32 color = filterRow [srcColPhase2];
+
+ if (++srcColPhase2 == patCols)
+ {
+ srcColPhase2 = 0;
+ }
+
+ total [color] += (uint32) ssPtr [cellCol];
+ count [color] ++;
+
+ }
+
+ ssPtr += srcBuffer.fRowStep;
+
+ }
+
+ for (plane = 0; plane < planes; plane++)
+ {
+
+ uint32 t = total [plane];
+ uint32 c = count [plane];
+
+ dPtr [plane * dstPlaneStep] = (uint16) ((t + (c >> 1)) / c);
+
+ total [plane] = 0;
+ count [plane] = 0;
+
+ }
+
+ srcColPhase1 = srcColPhase2;
+
+ sPtr += cellCols;
+
+ dPtr ++;
+
+ }
+
+ srcRowPhase1 = srcRowPhase2;
+
+ srcRow += cellRows;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_mosaic_info::dng_mosaic_info ()
+
+ : fCFAPatternSize ()
+ , fColorPlanes (0)
+ , fCFALayout (1)
+ , fBayerGreenSplit (0)
+ , fSrcSize ()
+ , fCroppedSize ()
+ , fAspectRatio (1.0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_mosaic_info::~dng_mosaic_info ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_mosaic_info::Parse (dng_host & /* host */,
+ dng_stream & /* stream */,
+ dng_info &info)
+ {
+
+ // Find main image IFD.
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
+
+ // This information only applies to CFA images.
+
+ if (rawIFD.fPhotometricInterpretation != piCFA)
+ {
+ return;
+ }
+
+ // Copy CFA pattern.
+
+ fCFAPatternSize.v = rawIFD.fCFARepeatPatternRows;
+ fCFAPatternSize.h = rawIFD.fCFARepeatPatternCols;
+
+ for (int32 j = 0; j < fCFAPatternSize.v; j++)
+ {
+ for (int32 k = 0; k < fCFAPatternSize.h; k++)
+ {
+ fCFAPattern [j] [k] = rawIFD.fCFAPattern [j] [k];
+ }
+ }
+
+ // Copy CFA plane information.
+
+ fColorPlanes = info.fShared->fCameraProfile.fColorPlanes;
+
+ for (uint32 n = 0; n < fColorPlanes; n++)
+ {
+ fCFAPlaneColor [n] = rawIFD.fCFAPlaneColor [n];
+ }
+
+ // Copy CFA layout information.
+
+ fCFALayout = rawIFD.fCFALayout;
+
+ // Green split value for Bayer patterns.
+
+ fBayerGreenSplit = rawIFD.fBayerGreenSplit;
+
+ }
+
+/*****************************************************************************/
+
+void dng_mosaic_info::PostParse (dng_host & /* host */,
+ dng_negative &negative)
+ {
+
+ // Keep track of source image size.
+
+ fSrcSize = negative.Stage2Image ()->Size ();
+
+ // Default cropped size.
+
+ fCroppedSize.v = Round_int32 (negative.DefaultCropSizeV ().As_real64 ());
+ fCroppedSize.h = Round_int32 (negative.DefaultCropSizeH ().As_real64 ());
+
+ // Pixel aspect ratio.
+
+ fAspectRatio = negative.DefaultScaleH ().As_real64 () /
+ negative.DefaultScaleV ().As_real64 ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_mosaic_info::SetFourColorBayer ()
+ {
+
+ if (fCFAPatternSize != dng_point (2, 2))
+ {
+ return false;
+ }
+
+ if (fColorPlanes != 3)
+ {
+ return false;
+ }
+
+ uint8 color0 = fCFAPlaneColor [0];
+ uint8 color1 = fCFAPlaneColor [1];
+ uint8 color2 = fCFAPlaneColor [2];
+
+ // Look for color 1 repeated twice in a diagonal.
+
+ if ((fCFAPattern [0] [0] == color1 && fCFAPattern [1] [1] == color1) ||
+ (fCFAPattern [0] [1] == color1 && fCFAPattern [1] [0] == color1))
+ {
+
+ // OK, this looks like a Bayer pattern.
+
+ // Find unused color code.
+
+ uint8 color3 = 0;
+
+ while (color3 == color0 ||
+ color3 == color1 ||
+ color3 == color2)
+ {
+ color3++;
+ }
+
+ // Switch the four color mosaic.
+
+ fColorPlanes = 4;
+
+ fCFAPlaneColor [3] = color3;
+
+ // Replace the "green" in the "blue" rows with the new color.
+
+ if (fCFAPattern [0] [0] == color0)
+ {
+ fCFAPattern [1] [0] = color3;
+ }
+
+ else if (fCFAPattern [0] [1] == color0)
+ {
+ fCFAPattern [1] [1] = color3;
+ }
+
+ else if (fCFAPattern [1] [0] == color0)
+ {
+ fCFAPattern [0] [0] = color3;
+ }
+
+ else
+ {
+ fCFAPattern [0] [1] = color3;
+ }
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_mosaic_info::FullScale () const
+ {
+
+ switch (fCFALayout)
+ {
+
+ // Staggered layouts with offset columns double the row count
+ // during interpolation.
+
+ case 2:
+ case 3:
+ return dng_point (2, 1);
+
+ // Staggered layouts with offset rows double the column count
+ // during interpolation.
+
+ case 4:
+ case 5:
+ return dng_point (1, 2);
+
+ // Otherwise there is no size change during interpolation.
+
+ default:
+ break;
+
+ }
+
+ return dng_point (1, 1);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_mosaic_info::IsSafeDownScale (const dng_point &downScale) const
+ {
+
+ if (downScale.v >= fCFAPatternSize.v &&
+ downScale.h >= fCFAPatternSize.h)
+ {
+
+ return true;
+
+ }
+
+ dng_point test;
+
+ test.v = Min_int32 (downScale.v, fCFAPatternSize.v);
+ test.h = Min_int32 (downScale.h, fCFAPatternSize.h);
+
+ for (int32 phaseV = 0; phaseV <= fCFAPatternSize.v - test.v; phaseV++)
+ {
+
+ for (int32 phaseH = 0; phaseH <= fCFAPatternSize.h - test.h; phaseH++)
+ {
+
+ uint32 plane;
+
+ bool contains [kMaxColorPlanes];
+
+ for (plane = 0; plane < fColorPlanes; plane++)
+ {
+
+ contains [plane] = false;
+
+ }
+
+ for (int32 srcRow = 0; srcRow < test.v; srcRow++)
+ {
+
+ for (int32 srcCol = 0; srcCol < test.h; srcCol++)
+ {
+
+ uint8 srcKey = fCFAPattern [srcRow + phaseV]
+ [srcCol + phaseH];
+
+ for (plane = 0; plane < fColorPlanes; plane++)
+ {
+
+ if (srcKey == fCFAPlaneColor [plane])
+ {
+
+ contains [plane] = true;
+
+ }
+
+ }
+
+
+ }
+
+ }
+
+ for (plane = 0; plane < fColorPlanes; plane++)
+ {
+
+ if (!contains [plane])
+ {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_mosaic_info::SizeForDownScale (const dng_point &downScale) const
+ {
+
+ uint32 sizeV = Max_uint32 (1, (fCroppedSize.v + (downScale.v >> 1)) / downScale.v);
+ uint32 sizeH = Max_uint32 (1, (fCroppedSize.h + (downScale.h >> 1)) / downScale.h);
+
+ return Max_int32 (sizeV, sizeH);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_mosaic_info::ValidSizeDownScale (const dng_point &downScale,
+ uint32 minSize) const
+ {
+
+ const int32 kMaxDownScale = 64;
+
+ if (downScale.h > kMaxDownScale ||
+ downScale.v > kMaxDownScale)
+ {
+
+ return false;
+
+ }
+
+ return SizeForDownScale (downScale) >= minSize;
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_mosaic_info::DownScale (uint32 minSize,
+ uint32 prefSize,
+ real64 cropFactor) const
+ {
+
+ dng_point bestScale (1, 1);
+
+ if (prefSize && IsColorFilterArray ())
+ {
+
+ // Adjust sizes for crop factor.
+
+ minSize = Round_uint32 (minSize / cropFactor);
+ prefSize = Round_uint32 (prefSize / cropFactor);
+
+ prefSize = Max_uint32 (prefSize, minSize);
+
+ // Start by assuming we need the full size image.
+
+ int32 bestSize = SizeForDownScale (bestScale);
+
+ // Find size of nearly square cell.
+
+ dng_point squareCell (1, 1);
+
+ if (fAspectRatio < 1.0 / 1.8)
+ {
+
+ squareCell.h = Min_int32 (4, Round_int32 (1.0 / fAspectRatio));
+
+ }
+
+ if (fAspectRatio > 1.8)
+ {
+
+ squareCell.v = Min_int32 (4, Round_int32 (fAspectRatio));
+
+ }
+
+ // Find minimum safe cell size.
+
+ dng_point testScale = squareCell;
+
+ while (!IsSafeDownScale (testScale))
+ {
+
+ testScale.v += squareCell.v;
+ testScale.h += squareCell.h;
+
+ }
+
+ // See if this scale is usable.
+
+ if (!ValidSizeDownScale (testScale, minSize))
+ {
+
+ // We cannot downsample at all...
+
+ return bestScale;
+
+ }
+
+ // See if this is closer to the preferred size.
+
+ int32 testSize = SizeForDownScale (testScale);
+
+ if (Abs_int32 (testSize - (int32) prefSize) <=
+ Abs_int32 (bestSize - (int32) prefSize))
+ {
+ bestScale = testScale;
+ bestSize = testSize;
+ }
+
+ else
+ {
+ return bestScale;
+ }
+
+ // Now keep adding square cells as long as possible.
+
+ while (true)
+ {
+
+ testScale.v += squareCell.v;
+ testScale.h += squareCell.h;
+
+ if (IsSafeDownScale (testScale))
+ {
+
+ if (!ValidSizeDownScale (testScale, minSize))
+ {
+ return bestScale;
+ }
+
+ // See if this is closer to the preferred size.
+
+ testSize = SizeForDownScale (testScale);
+
+ if (Abs_int32 (testSize - (int32) prefSize) <=
+ Abs_int32 (bestSize - (int32) prefSize))
+ {
+ bestScale = testScale;
+ bestSize = testSize;
+ }
+
+ else
+ {
+ return bestScale;
+ }
+
+ }
+
+ }
+
+ }
+
+ return bestScale;
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_mosaic_info::DstSize (const dng_point &downScale) const
+ {
+
+ if (downScale == dng_point (1, 1))
+ {
+
+ dng_point scale = FullScale ();
+
+ return dng_point (fSrcSize.v * scale.v,
+ fSrcSize.h * scale.h);
+
+ }
+
+ const int32 kMaxDownScale = 64;
+
+ if (downScale.h > kMaxDownScale ||
+ downScale.v > kMaxDownScale)
+ {
+
+ return dng_point (0, 0);
+
+ }
+
+ dng_point size;
+
+ size.v = Max_int32 (1, (fSrcSize.v + (downScale.v >> 1)) / downScale.v);
+ size.h = Max_int32 (1, (fSrcSize.h + (downScale.h >> 1)) / downScale.h);
+
+ return size;
+
+ }
+
+/*****************************************************************************/
+
+void dng_mosaic_info::InterpolateGeneric (dng_host &host,
+ dng_negative & /* negative */,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 srcPlane) const
+ {
+
+ // Find destination to source bit shifts.
+
+ dng_point scale = FullScale ();
+
+ uint32 srcShiftV = scale.v - 1;
+ uint32 srcShiftH = scale.h - 1;
+
+ // Find tile sizes.
+
+ const uint32 kMaxDstTileRows = 128;
+ const uint32 kMaxDstTileCols = 128;
+
+ dng_point dstTileSize = dstImage.RepeatingTile ().Size ();
+
+ dstTileSize.v = Min_int32 (dstTileSize.v, kMaxDstTileRows);
+ dstTileSize.h = Min_int32 (dstTileSize.h, kMaxDstTileCols);
+
+ dng_point srcTileSize = dstTileSize;
+
+ srcTileSize.v >>= srcShiftV;
+ srcTileSize.h >>= srcShiftH;
+
+ srcTileSize.v += fCFAPatternSize.v * 2;
+ srcTileSize.h += fCFAPatternSize.h * 2;
+
+ // Allocate source buffer.
+
+ dng_pixel_buffer srcBuffer;
+
+ srcBuffer.fPlane = srcPlane;
+
+ srcBuffer.fRowStep = srcTileSize.h;
+
+ srcBuffer.fPixelType = srcImage.PixelType ();
+ srcBuffer.fPixelSize = srcImage.PixelSize ();
+
+ uint32 srcBufferSize = srcBuffer.fPixelSize *
+ srcBuffer.fRowStep *
+ srcTileSize.v;
+
+ AutoPtr<dng_memory_block> srcData (host.Allocate (srcBufferSize));
+
+ srcBuffer.fData = srcData->Buffer ();
+
+ // Allocate destination buffer.
+
+ dng_pixel_buffer dstBuffer;
+
+ dstBuffer.fPlanes = fColorPlanes;
+
+ dstBuffer.fRowStep = dstTileSize.h * fColorPlanes;
+ dstBuffer.fPlaneStep = dstTileSize.h;
+
+ dstBuffer.fPixelType = dstImage.PixelType ();
+ dstBuffer.fPixelSize = dstImage.PixelSize ();
+
+ uint32 dstBufferSize = dstBuffer.fPixelSize *
+ dstBuffer.fRowStep *
+ dstTileSize.v;
+
+ AutoPtr<dng_memory_block> dstData (host.Allocate (dstBufferSize));
+
+ dstBuffer.fData = dstData->Buffer ();
+
+ // Create interpolator.
+
+ AutoPtr<dng_bilinear_interpolator> interpolator (new dng_bilinear_interpolator (*this,
+ srcBuffer.fRowStep,
+ srcBuffer.fColStep));
+
+ // Iterate over destination tiles.
+
+ dng_rect dstArea;
+
+ dng_tile_iterator iter1 (dstImage, dstImage.Bounds ());
+
+ while (iter1.GetOneTile (dstArea))
+ {
+
+ // Break into buffer sized tiles.
+
+ dng_rect dstTile;
+
+ dng_tile_iterator iter2 (dstTileSize, dstArea);
+
+ while (iter2.GetOneTile (dstTile))
+ {
+
+ host.SniffForAbort ();
+
+ // Setup buffers for this tile.
+
+ dng_rect srcTile (dstTile);
+
+ srcTile.t >>= srcShiftV;
+ srcTile.b >>= srcShiftV;
+
+ srcTile.l >>= srcShiftH;
+ srcTile.r >>= srcShiftH;
+
+ srcTile.t -= fCFAPatternSize.v;
+ srcTile.b += fCFAPatternSize.v;
+
+ srcTile.l -= fCFAPatternSize.h;
+ srcTile.r += fCFAPatternSize.h;
+
+ srcBuffer.fArea = srcTile;
+ dstBuffer.fArea = dstTile;
+
+ // Get source data.
+
+ srcImage.Get (srcBuffer,
+ dng_image::edge_repeat,
+ fCFAPatternSize.v,
+ fCFAPatternSize.h);
+
+ // Process data.
+
+ interpolator->Interpolate (srcBuffer,
+ dstBuffer);
+
+ // Save results.
+
+ dstImage.Put (dstBuffer);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_mosaic_info::InterpolateFast (dng_host &host,
+ dng_negative & /* negative */,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_point &downScale,
+ uint32 srcPlane) const
+ {
+
+ // Create fast interpolator task.
+
+ dng_fast_interpolator interpolator (*this,
+ srcImage,
+ dstImage,
+ downScale,
+ srcPlane);
+
+ // Find area to process.
+
+ dng_rect bounds = dstImage.Bounds ();
+
+ // Do the interpolation.
+
+ host.PerformAreaTask (interpolator,
+ bounds);
+
+ }
+
+/*****************************************************************************/
+
+void dng_mosaic_info::Interpolate (dng_host &host,
+ dng_negative &negative,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_point &downScale,
+ uint32 srcPlane) const
+ {
+
+ if (downScale == dng_point (1, 1))
+ {
+
+ InterpolateGeneric (host,
+ negative,
+ srcImage,
+ dstImage,
+ srcPlane);
+
+ }
+
+ else
+ {
+
+ InterpolateFast (host,
+ negative,
+ srcImage,
+ dstImage,
+ downScale,
+ srcPlane);
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_mosaic_info.h b/gpr/source/lib/dng_sdk/dng_mosaic_info.h
new file mode 100644
index 0000000..477c105
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_mosaic_info.h
@@ -0,0 +1,200 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_mosaic_info.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for descriptive information about color filter array patterns.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_mosaic_info__
+#define __dng_mosaic_info__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_rect.h"
+#include "dng_sdk_limits.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief Support for describing color filter array patterns and manipulating mosaic sample data.
+///
+/// See CFAPattern tag in \ref spec_tiff_ep "TIFF/EP specification" and CFAPlaneColor, CFALayout, and BayerGreenSplit
+/// tags in the \ref spec_dng "DNG 1.1.0 specification".
+
+class dng_mosaic_info
+ {
+
+ public:
+
+ /// Size of fCFAPattern.
+
+ dng_point fCFAPatternSize;
+
+ /// CFA pattern from CFAPattern tag in the \ref spec_tiff_ep "TIFF/EP specification."
+
+ uint8 fCFAPattern [kMaxCFAPattern] [kMaxCFAPattern];
+
+ /// Number of color planes in DNG input.
+
+ uint32 fColorPlanes;
+
+ uint8 fCFAPlaneColor [kMaxColorPlanes];
+
+ /// Value of CFALayout tag in the \ref spec_dng "DNG 1.3 specification."
+ /// CFALayout describes the spatial layout of the CFA. The currently defined values are:
+ /// - 1 = Rectangular (or square) layout.
+ /// - 2 = Staggered layout A: even columns are offset down by 1/2 row.
+ /// - 3 = Staggered layout B: even columns are offset up by 1/2 row.
+ /// - 4 = Staggered layout C: even rows are offset right by 1/2 column.
+ /// - 5 = Staggered layout D: even rows are offset left by 1/2 column.
+ /// - 6 = Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column.
+ /// - 7 = Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column.
+ /// - 8 = Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column.
+ /// - 9 = Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column.
+
+ uint32 fCFALayout;
+
+ /// Value of BayerGreeSplit tag in DNG file.
+ /// BayerGreenSplit only applies to CFA images using a Bayer pattern filter array. This tag
+ /// specifies, in arbitrary units, how closely the values of the green pixels in the blue/green rows
+ /// track the values of the green pixels in the red/green rows.
+ ///
+ /// A value of zero means the two kinds of green pixels track closely, while a non-zero value
+ /// means they sometimes diverge. The useful range for this tag is from 0 (no divergence) to about
+ /// 5000 (large divergence).
+
+ uint32 fBayerGreenSplit;
+
+ protected:
+
+ dng_point fSrcSize;
+
+ dng_point fCroppedSize;
+
+ real64 fAspectRatio;
+
+ public:
+
+ dng_mosaic_info ();
+
+ virtual ~dng_mosaic_info ();
+
+ virtual void Parse (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ virtual void PostParse (dng_host &host,
+ dng_negative &negative);
+
+ /// Returns whether the RAW data in this DNG file from a color filter array (mosaiced) source.
+ /// \retval true if this DNG file is from a color filter array (mosiaced) source.
+
+ bool IsColorFilterArray () const
+ {
+ return fCFAPatternSize != dng_point (0, 0);
+ }
+
+ /// Enable generating four-plane output from three-plane Bayer input.
+ /// Extra plane is a second version of the green channel. First green is produced
+ /// using green mosaic samples from one set of rows/columns (even/odd) and the second
+ /// green channel is produced using the other set of rows/columns. One can compare the
+ /// two versions to judge whether BayerGreenSplit needs to be set for a given input source.
+
+ virtual bool SetFourColorBayer ();
+
+ /// Returns scaling factor relative to input size needed to capture output data.
+ /// Staggered (or rotated) sensing arrays are produced to a larger output than the number of input samples.
+ /// This method indicates how much larger.
+ /// \retval a point with integer scaling factors for the horizotal and vertical dimensions.
+
+ virtual dng_point FullScale () const;
+
+ /// Returns integer factors by which mosaic data must be downsampled to produce an image which is as close
+ /// to prefSize as possible in longer dimension, but no smaller than minSize.
+ /// \param minSize Number of pixels as minium for longer dimension of downsampled image.
+ /// \param prefSize Number of pixels as target for longer dimension of downsampled image.
+ /// \param cropFactor Faction of the image to be used after cropping.
+ /// \retval Point containing integer factors by which image must be downsampled.
+
+ virtual dng_point DownScale (uint32 minSize,
+ uint32 prefSize,
+ real64 cropFactor) const;
+
+ /// Return size of demosaiced image for passed in downscaling factor.
+ /// \param downScale Integer downsampling factor obtained from DownScale method.
+ /// \retval Size of resulting demosaiced image.
+
+ virtual dng_point DstSize (const dng_point &downScale) const;
+
+ /// Demosaic interpolation of a single plane for non-downsampled case.
+ /// \param host dng_host to use for buffer allocation requests, user cancellation testing, and progress updates.
+ /// \param negative DNG negative of mosaiced data.
+ /// \param srcImage Source image for mosaiced data.
+ /// \param dstImage Destination image for resulting interpolated data.
+ /// \param srcPlane Which plane to interpolate.
+
+ virtual void InterpolateGeneric (dng_host &host,
+ dng_negative &negative,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 srcPlane = 0) const;
+
+ /// Demosaic interpolation of a single plane for downsampled case.
+ /// \param host dng_host to use for buffer allocation requests, user cancellation testing, and progress updates.
+ /// \param negative DNG negative of mosaiced data.
+ /// \param srcImage Source image for mosaiced data.
+ /// \param dstImage Destination image for resulting interpolated data.
+ /// \param downScale Amount (in horizontal and vertical) by which to subsample image.
+ /// \param srcPlane Which plane to interpolate.
+
+ virtual void InterpolateFast (dng_host &host,
+ dng_negative &negative,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_point &downScale,
+ uint32 srcPlane = 0) const;
+
+ /// Demosaic interpolation of a single plane. Chooses between generic and fast interpolators based on parameters.
+ /// \param host dng_host to use for buffer allocation requests, user cancellation testing, and progress updates.
+ /// \param negative DNG negative of mosaiced data.
+ /// \param srcImage Source image for mosaiced data.
+ /// \param dstImage Destination image for resulting interpolated data.
+ /// \param downScale Amount (in horizontal and vertical) by which to subsample image.
+ /// \param srcPlane Which plane to interpolate.
+
+ virtual void Interpolate (dng_host &host,
+ dng_negative &negative,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_point &downScale,
+ uint32 srcPlane = 0) const;
+
+ protected:
+
+ virtual bool IsSafeDownScale (const dng_point &downScale) const;
+
+ uint32 SizeForDownScale (const dng_point &downScale) const;
+
+ virtual bool ValidSizeDownScale (const dng_point &downScale,
+ uint32 minSize) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_mutex.cpp b/gpr/source/lib/dng_sdk/dng_mutex.cpp
new file mode 100644
index 0000000..7451c7c
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_mutex.cpp
@@ -0,0 +1,394 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_mutex.cpp#3 $ */
+/* $DateTime: 2012/09/05 12:31:51 $ */
+/* $Change: 847652 $ */
+/* $Author: tknoll $ */
+
+#include "dng_mutex.h"
+
+#include "dng_assertions.h"
+#include "dng_exceptions.h"
+
+#include <stdlib.h>
+
+/*****************************************************************************/
+
+#if qDNGThreadSafe
+
+namespace
+ {
+
+ class InnermostMutexHolder
+ {
+
+ private:
+
+ pthread_key_t fInnermostMutexKey;
+
+ public:
+
+ InnermostMutexHolder ()
+
+ : fInnermostMutexKey ()
+
+ {
+
+ int result = pthread_key_create (&fInnermostMutexKey, NULL);
+
+ DNG_ASSERT (result == 0, "pthread_key_create failed.");
+
+ if (result != 0)
+ ThrowProgramError ();
+
+ }
+
+ ~InnermostMutexHolder ()
+ {
+
+ pthread_key_delete (fInnermostMutexKey);
+
+ }
+
+ void SetInnermostMutex (dng_mutex *mutex)
+ {
+
+ int result;
+
+ result = pthread_setspecific (fInnermostMutexKey, (void *)mutex);
+
+ DNG_ASSERT (result == 0, "pthread_setspecific failed.");
+
+ #if 0 // Hard failure here was causing crash on quit.
+
+ if (result != 0)
+ ThrowProgramError ();
+
+ #endif
+
+ }
+
+ dng_mutex *GetInnermostMutex ()
+ {
+
+ void *result = pthread_getspecific (fInnermostMutexKey);
+
+ return reinterpret_cast<dng_mutex *> (result);
+
+ }
+
+ };
+
+ InnermostMutexHolder gInnermostMutexHolder;
+
+ }
+
+#endif
+
+/*****************************************************************************/
+
+dng_mutex::dng_mutex (const char *mutexName, uint32 mutexLevel)
+
+ #if qDNGThreadSafe
+
+ : fPthreadMutex ()
+ , fMutexLevel (mutexLevel)
+ , fRecursiveLockCount (0)
+ , fPrevHeldMutex (NULL)
+ , fMutexName (mutexName)
+
+ #endif
+
+ {
+
+ #if qDNGThreadSafe
+
+ if (pthread_mutex_init (&fPthreadMutex, NULL) != 0)
+ {
+ ThrowMemoryFull ();
+ }
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+dng_mutex::~dng_mutex ()
+ {
+
+ #if qDNGThreadSafe
+
+ pthread_mutex_destroy (&fPthreadMutex);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_mutex::Lock ()
+ {
+
+ #if qDNGThreadSafe
+
+ dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
+
+ if (innermostMutex != NULL)
+ {
+
+ if (innermostMutex == this)
+ {
+
+ fRecursiveLockCount++;
+
+ return;
+
+ }
+
+ bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel /* ||
+ (fMutexLevel == innermostMutex->fMutexLevel && innermostMutex < this) */;
+
+ if (!lockOrderPreserved)
+ {
+
+ DNG_REPORT ("Lock ordering violation.");
+
+ #if qDNGDebug
+
+ dng_show_message_f ("This mutex: %s v Innermost mutex: %s",
+ this->MutexName (),
+ innermostMutex->MutexName ());
+
+ #endif
+
+ }
+
+ }
+
+ pthread_mutex_lock (&fPthreadMutex);
+
+ fPrevHeldMutex = innermostMutex;
+
+ gInnermostMutexHolder.SetInnermostMutex (this);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_mutex::Unlock ()
+ {
+
+ #if qDNGThreadSafe
+
+ DNG_ASSERT (gInnermostMutexHolder.GetInnermostMutex () == this, "Mutexes unlocked out of order!!!");
+
+ if (fRecursiveLockCount > 0)
+ {
+
+ fRecursiveLockCount--;
+
+ return;
+
+ }
+
+ gInnermostMutexHolder.SetInnermostMutex (fPrevHeldMutex);
+
+ fPrevHeldMutex = NULL;
+
+ pthread_mutex_unlock (&fPthreadMutex);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+const char *dng_mutex::MutexName () const
+ {
+
+ #if qDNGThreadSafe
+
+ if (fMutexName)
+ return fMutexName;
+
+ #endif
+
+ return "< unknown >";
+
+ }
+
+/*****************************************************************************/
+
+dng_lock_mutex::dng_lock_mutex (dng_mutex *mutex)
+
+ : fMutex (mutex)
+
+ {
+
+ if (fMutex)
+ fMutex->Lock ();
+
+ }
+
+/*****************************************************************************/
+
+dng_lock_mutex::~dng_lock_mutex ()
+ {
+
+ if (fMutex)
+ fMutex->Unlock ();
+
+ }
+
+/*****************************************************************************/
+
+dng_unlock_mutex::dng_unlock_mutex (dng_mutex *mutex)
+
+ : fMutex (mutex)
+
+ {
+
+ if (fMutex)
+ fMutex->Unlock ();
+
+ }
+
+/*****************************************************************************/
+
+dng_unlock_mutex::~dng_unlock_mutex ()
+ {
+
+ if (fMutex)
+ fMutex->Lock ();
+
+ }
+
+/*****************************************************************************/
+
+#if qDNGThreadSafe
+
+/*****************************************************************************/
+
+dng_condition::dng_condition ()
+
+ : fPthreadCondition ()
+
+ {
+
+ int result;
+
+ result = pthread_cond_init (&fPthreadCondition, NULL);
+
+ DNG_ASSERT (result == 0, "pthread_cond_init failed.");
+
+ if (result != 0)
+ {
+ ThrowProgramError ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_condition::~dng_condition ()
+ {
+
+ pthread_cond_destroy (&fPthreadCondition);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_condition::Wait (dng_mutex &mutex, double timeoutSecs)
+ {
+
+ bool timedOut = false;
+
+ dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
+
+ DNG_ASSERT (innermostMutex == &mutex, "Attempt to wait on non-innermost mutex.");
+
+ innermostMutex = mutex.fPrevHeldMutex;
+
+ gInnermostMutexHolder.SetInnermostMutex (innermostMutex);
+
+ mutex.fPrevHeldMutex = NULL;
+
+ if (timeoutSecs < 0)
+ {
+
+ pthread_cond_wait (&fPthreadCondition, &mutex.fPthreadMutex);
+
+ }
+
+ else
+ {
+
+ struct timespec now;
+
+ dng_pthread_now (&now);
+
+ timeoutSecs += now.tv_sec;
+ timeoutSecs += now.tv_nsec / 1000000000.0;
+
+ now.tv_sec = (long) timeoutSecs;
+ now.tv_nsec = (long) ((timeoutSecs - now.tv_sec) * 1000000000);
+
+ timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &now) == ETIMEDOUT);
+
+ }
+
+ mutex.fPrevHeldMutex = innermostMutex;
+
+ gInnermostMutexHolder.SetInnermostMutex (&mutex);
+
+ return !timedOut;
+
+ }
+
+/*****************************************************************************/
+
+void dng_condition::Signal ()
+ {
+
+ int result;
+
+ result = pthread_cond_signal (&fPthreadCondition);
+
+ DNG_ASSERT (result == 0, "pthread_cond_signal failed.");
+
+ if (result != 0)
+ ThrowProgramError ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_condition::Broadcast ()
+ {
+
+ int result;
+
+ result = pthread_cond_broadcast (&fPthreadCondition);
+
+ DNG_ASSERT (result == 0, "pthread_cond_broadcast failed.");
+
+ if (result != 0)
+ ThrowProgramError ();
+
+ }
+
+/*****************************************************************************/
+
+#endif // qDNGThreadSafe
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_mutex.h b/gpr/source/lib/dng_sdk/dng_mutex.h
new file mode 100644
index 0000000..b067728
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_mutex.h
@@ -0,0 +1,177 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_mutex.h#2 $ */
+/* $DateTime: 2012/09/05 12:31:51 $ */
+/* $Change: 847652 $ */
+/* $Author: tknoll $ */
+
+/******************************************************************************/
+
+#ifndef __dng_mutex__
+#define __dng_mutex__
+
+/******************************************************************************/
+
+#include "dng_flags.h"
+
+/******************************************************************************/
+
+#include "dng_types.h"
+
+#if qDNGThreadSafe
+
+#include "dng_pthread.h"
+
+#endif
+
+/******************************************************************************/
+
+class dng_mutex
+ {
+
+ public:
+
+ enum
+ {
+ kDNGMutexLevelLeaf = 0x70000000u
+ };
+
+ dng_mutex (const char *mutexName,
+ uint32 mutexLevel = kDNGMutexLevelLeaf);
+
+ virtual ~dng_mutex ();
+
+ void Lock ();
+
+ void Unlock ();
+
+ const char *MutexName () const;
+
+ protected:
+
+ #if qDNGThreadSafe
+
+ pthread_mutex_t fPthreadMutex;
+
+ const uint32 fMutexLevel;
+
+ uint32 fRecursiveLockCount;
+
+ dng_mutex *fPrevHeldMutex;
+
+ const char * const fMutexName;
+
+ friend class dng_condition;
+
+ #endif
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_mutex (const dng_mutex &mutex);
+
+ dng_mutex & operator= (const dng_mutex &mutex);
+
+ };
+
+/*****************************************************************************/
+
+class dng_lock_mutex
+ {
+
+ private:
+
+ dng_mutex *fMutex;
+
+ public:
+
+ dng_lock_mutex (dng_mutex *mutex);
+
+ ~dng_lock_mutex ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_lock_mutex (const dng_lock_mutex &lock);
+
+ dng_lock_mutex & operator= (const dng_lock_mutex &lock);
+
+ };
+
+/*****************************************************************************/
+
+class dng_unlock_mutex
+ {
+
+ private:
+
+ dng_mutex *fMutex;
+
+ public:
+
+ dng_unlock_mutex (dng_mutex *mutex);
+
+ ~dng_unlock_mutex ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_unlock_mutex (const dng_unlock_mutex &unlock);
+
+ dng_unlock_mutex & operator= (const dng_unlock_mutex &unlock);
+
+ };
+
+/*****************************************************************************/
+
+#if qDNGThreadSafe
+
+/*****************************************************************************/
+
+class dng_condition
+ {
+
+ public:
+
+ dng_condition ();
+
+ ~dng_condition ();
+
+ bool Wait (dng_mutex &mutex, double timeoutSecs = -1.0);
+
+ void Signal ();
+
+ void Broadcast ();
+
+ protected:
+
+ pthread_cond_t fPthreadCondition;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_condition (const dng_condition &condition);
+
+ dng_condition & operator= (const dng_condition &condition);
+
+ };
+
+/*****************************************************************************/
+
+#endif // qDNGThreadSafe
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_negative.cpp b/gpr/source/lib/dng_sdk/dng_negative.cpp
new file mode 120000
index 0000000..cab9efc
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_negative.cpp
@@ -0,0 +1 @@
+../../../../.git/annex/objects/PJ/j0/SHA256E-s109388--4890b5bbb5069f009ef424b6472f31f528a8dc0b67209dc9e3bdbe9854ed4b6e.cpp/SHA256E-s109388--4890b5bbb5069f009ef424b6472f31f528a8dc0b67209dc9e3bdbe9854ed4b6e.cpp \ No newline at end of file
diff --git a/gpr/source/lib/dng_sdk/dng_negative.h b/gpr/source/lib/dng_sdk/dng_negative.h
new file mode 100644
index 0000000..1304292
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_negative.h
@@ -0,0 +1,2397 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_negative.h#4 $ */
+/* $DateTime: 2012/08/02 06:09:06 $ */
+/* $Change: 841096 $ */
+/* $Author: erichan $ */
+
+/** \file
+ * Functions and classes for working with a digital negative (image data and
+ * corresponding metadata).
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_negative__
+#define __dng_negative__
+
+/*****************************************************************************/
+
+#include "dng_1d_function.h"
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_fingerprint.h"
+#include "dng_image.h"
+#include "dng_linearization_info.h"
+#include "dng_matrix.h"
+#include "dng_mosaic_info.h"
+#include "dng_opcode_list.h"
+#include "dng_orientation.h"
+#include "dng_rational.h"
+#include "dng_sdk_limits.h"
+#include "dng_string.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_types.h"
+#include "dng_utils.h"
+#include "dng_xy_coord.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+// To prevent using the internal metadata when we meant to use override
+// metadata, the following definitions allow us to only allow access to
+// the internal metadata on non-const negatives. This allows the old API
+// to keep working essentially unchanged provided one does not use const
+// negatives, but will prevent access to the embedded data on const
+// negatives.
+
+#if 1
+
+#define qMetadataOnConst 0
+#define METACONST
+
+#else
+
+#define qMetadataOnConst 1
+#define METACONST const
+
+#endif
+
+/*****************************************************************************/
+
+#if GPR_READING
+ typedef bool (*Vc5DecodeCallback)(dng_stream &stream, dng_image &image );
+#endif
+
+/// \brief Noise model for photon and sensor read noise, assuming that they are
+/// independent random variables and spatially invariant.
+///
+/// The noise model is N (x) = sqrt (scale*x + offset), where x represents a linear
+/// signal value in the range [0,1], and N (x) is the standard deviation (i.e.,
+/// noise). The parameters scale and offset are both sensor-dependent and
+/// ISO-dependent. scale must be positive, and offset must be non-negative.
+
+class dng_noise_function: public dng_1d_function
+ {
+
+ protected:
+
+ real64 fScale;
+ real64 fOffset;
+
+ public:
+
+ /// Create empty and invalid noise function.
+
+ dng_noise_function ()
+
+ : fScale (0.0)
+ , fOffset (0.0)
+
+ {
+
+ }
+
+ /// Create noise function with the specified scale and offset.
+
+ dng_noise_function (real64 scale,
+ real64 offset)
+
+ : fScale (scale)
+ , fOffset (offset)
+
+ {
+
+ }
+
+ /// Compute noise (standard deviation) at the specified average signal level
+ /// x.
+
+ virtual real64 Evaluate (real64 x) const
+ {
+ return sqrt (fScale * x + fOffset);
+ }
+
+ /// The scale (slope, gain) of the noise function.
+
+ real64 Scale () const
+ {
+ return fScale;
+ }
+
+ /// The offset (square of the noise floor) of the noise function.
+
+ real64 Offset () const
+ {
+ return fOffset;
+ }
+
+ /// Set the scale (slope, gain) of the noise function.
+
+ void SetScale (real64 scale)
+ {
+ fScale = scale;
+ }
+
+ /// Set the offset (square of the noise floor) of the noise function.
+
+ void SetOffset (real64 offset)
+ {
+ fOffset = offset;
+ }
+
+ /// Is the noise function valid?
+
+ bool IsValid () const
+ {
+ return (fScale > 0.0 && fOffset >= 0.0);
+ }
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Noise profile for a negative.
+///
+/// For mosaiced negatives, the noise profile describes the approximate noise
+/// characteristics of a mosaic negative after linearization, but prior to
+/// demosaicing. For demosaiced negatives (i.e., linear DNGs), the noise profile
+/// describes the approximate noise characteristics of the image data immediately
+/// following the demosaic step, prior to the processing of opcode list 3.
+///
+/// A noise profile may contain 1 or N noise functions, where N is the number of
+/// color planes for the negative. Otherwise the noise profile is considered to be
+/// invalid for that negative. If the noise profile contains 1 noise function, then
+/// it is assumed that this single noise function applies to all color planes of the
+/// negative. Otherwise, the N noise functions map to the N planes of the negative in
+/// order specified in the CFAPlaneColor tag.
+
+class dng_noise_profile
+ {
+
+ protected:
+
+ std::vector<dng_noise_function> fNoiseFunctions;
+
+ public:
+
+ /// Create empty (invalid) noise profile.
+
+ dng_noise_profile ();
+
+ /// Create noise profile with the specified noise functions (1 per plane).
+
+ explicit dng_noise_profile (const std::vector<dng_noise_function> &functions);
+
+ /// Is the noise profile valid?
+
+ bool IsValid () const;
+
+ /// Is the noise profile valid for the specified negative?
+
+ bool IsValidForNegative (const dng_negative &negative) const;
+
+ /// The noise function for the specified plane.
+
+ const dng_noise_function & NoiseFunction (uint32 plane) const;
+
+ /// The number of noise functions in this profile.
+
+ uint32 NumFunctions () const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Main class for holding metadata.
+
+class dng_metadata
+ {
+
+ private:
+
+ // Base orientation of both the thumbnail and raw data. This is
+ // generally based on the EXIF values.
+
+ bool fHasBaseOrientation;
+
+ dng_orientation fBaseOrientation;
+
+ // Is the maker note safe to copy from file to file? Defaults to false
+ // because many maker notes are not safe.
+
+ bool fIsMakerNoteSafe;
+
+ // MakerNote binary data block.
+
+ AutoPtr<dng_memory_block> fMakerNote;
+
+ // EXIF data.
+
+ AutoPtr<dng_exif> fExif;
+
+ // A copy of the EXIF data before is was synchronized with other metadata sources.
+
+ AutoPtr<dng_exif> fOriginalExif;
+
+ // IPTC binary data block and offset in original file.
+
+ AutoPtr<dng_memory_block> fIPTCBlock;
+
+ uint64 fIPTCOffset;
+
+ // XMP data.
+
+ AutoPtr<dng_xmp> fXMP;
+
+ // If there a valid embedded XMP block, has is its digest? NULL if no valid
+ // embedded XMP.
+
+ dng_fingerprint fEmbeddedXMPDigest;
+
+ // Is the XMP data from a sidecar file?
+
+ bool fXMPinSidecar;
+
+ // If the XMP data is from a sidecar file, is the sidecar file newer
+ // than the raw file?
+
+ bool fXMPisNewer;
+
+ // Source file mimi-type, if known.
+
+ dng_string fSourceMIMI;
+
+ public:
+
+ dng_metadata (dng_host &host);
+
+ dng_metadata (const dng_metadata &rhs,
+ dng_memory_allocator &allocator);
+
+ virtual ~dng_metadata ();
+
+ /// Copy this metadata.
+
+ virtual dng_metadata * Clone (dng_memory_allocator &allocator) const;
+
+ /// Setter for BaseOrientation.
+
+ void SetBaseOrientation (const dng_orientation &orientation);
+
+ /// Has BaseOrientation been set?
+
+ bool HasBaseOrientation () const
+ {
+ return fHasBaseOrientation;
+ }
+
+ /// Getter for BaseOrientation.
+
+ const dng_orientation & BaseOrientation () const
+ {
+ return fBaseOrientation;
+ }
+
+ /// Logically rotates the image by changing the orientation values.
+ /// This will also update the XMP data.
+
+ void ApplyOrientation (const dng_orientation &orientation);
+
+ // API for IPTC metadata:
+
+ void SetIPTC (AutoPtr<dng_memory_block> &block,
+ uint64 offset);
+
+ void SetIPTC (AutoPtr<dng_memory_block> &block);
+
+ void ClearIPTC ();
+
+ const void * IPTCData () const;
+
+ uint32 IPTCLength () const;
+
+ uint64 IPTCOffset () const;
+
+ dng_fingerprint IPTCDigest (bool includePadding = true) const;
+
+ void RebuildIPTC (dng_memory_allocator &allocator,
+ bool padForTIFF);
+
+ // API for MakerNote data:
+
+ void SetMakerNoteSafety (bool safe)
+ {
+ fIsMakerNoteSafe = safe;
+ }
+
+ bool IsMakerNoteSafe () const
+ {
+ return fIsMakerNoteSafe;
+ }
+
+ void SetMakerNote (AutoPtr<dng_memory_block> &block)
+ {
+ fMakerNote.Reset (block.Release ());
+ }
+
+ void ClearMakerNote ()
+ {
+ fIsMakerNoteSafe = false;
+ fMakerNote.Reset ();
+ }
+
+ const void * MakerNoteData () const
+ {
+ return fMakerNote.Get () ? fMakerNote->Buffer ()
+ : NULL;
+ }
+
+ uint32 MakerNoteLength () const
+ {
+ return fMakerNote.Get () ? fMakerNote->LogicalSize ()
+ : 0;
+ }
+
+ // API for EXIF metadata:
+
+ dng_exif * GetExif ()
+ {
+ return fExif.Get ();
+ }
+
+ const dng_exif * GetExif () const
+ {
+ return fExif.Get ();
+ }
+
+ template< class E >
+ E & Exif ();
+
+ template< class E >
+ const E & Exif () const;
+
+ void ResetExif (dng_exif * newExif);
+
+ dng_memory_block * BuildExifBlock (dng_memory_allocator &allocator,
+ const dng_resolution *resolution = NULL,
+ bool includeIPTC = false,
+ const dng_jpeg_preview *thumbnail = NULL) const;
+
+ // API for original EXIF metadata.
+
+ dng_exif * GetOriginalExif ()
+ {
+ return fOriginalExif.Get ();
+ }
+
+ const dng_exif * GetOriginalExif () const
+ {
+ return fOriginalExif.Get ();
+ }
+
+ // API for XMP metadata:
+
+ bool SetXMP (dng_host &host,
+ const void *buffer,
+ uint32 count,
+ bool xmpInSidecar = false,
+ bool xmpIsNewer = false);
+
+ void SetEmbeddedXMP (dng_host &host,
+ const void *buffer,
+ uint32 count);
+
+ dng_xmp * GetXMP ()
+ {
+ return fXMP.Get ();
+ }
+
+ const dng_xmp * GetXMP () const
+ {
+ return fXMP.Get ();
+ }
+
+ template< class X >
+ X & XMP ();
+
+ template< class X >
+ const X & XMP () const;
+
+ bool XMPinSidecar () const
+ {
+ return fXMPinSidecar;
+ }
+
+ const dng_fingerprint & EmbeddedXMPDigest () const
+ {
+ return fEmbeddedXMPDigest;
+ }
+
+ bool HaveValidEmbeddedXMP () const
+ {
+ return fEmbeddedXMPDigest.IsValid ();
+ }
+
+ void ResetXMP (dng_xmp * newXMP);
+
+ void ResetXMPSidecarNewer (dng_xmp * newXMP, bool inSidecar, bool isNewer );
+
+ // Synchronize metadata sources.
+
+ void SynchronizeMetadata ();
+
+ // Routines to update the date/time field in the EXIF and XMP
+ // metadata.
+
+ void UpdateDateTime (const dng_date_time_info &dt);
+
+ void UpdateDateTimeToNow ();
+
+ void UpdateMetadataDateTimeToNow ();
+
+ // Routines to set and get the source file MIMI type.
+
+ void SetSourceMIMI (const char *s)
+ {
+ fSourceMIMI.Set (s);
+ }
+
+ const dng_string & SourceMIMI () const
+ {
+ return fSourceMIMI;
+ }
+
+ };
+
+/*****************************************************************************/
+
+template< class E >
+E & dng_metadata::Exif ()
+ {
+ dng_exif * exif = GetExif ();
+ if (!exif) ThrowProgramError ("EXIF object is NULL.");
+ return dynamic_cast< E & > (*exif);
+ }
+
+/*****************************************************************************/
+
+template< class E >
+const E & dng_metadata::Exif () const
+ {
+ const dng_exif * exif = GetExif ();
+ if (!exif) ThrowProgramError ("EXIF object is NULL.");
+ return dynamic_cast< const E & > (*exif);
+ }
+
+/*****************************************************************************/
+
+template< class X >
+X & dng_metadata::XMP ()
+ {
+ dng_xmp * xmp = GetXMP ();
+ if (!xmp) ThrowProgramError ("XMP object is NULL.");
+ return dynamic_cast< X & > (*xmp);
+ }
+
+/*****************************************************************************/
+
+template< class X >
+const X & dng_metadata::XMP () const
+ {
+ const dng_xmp * xmp = GetXMP ();
+ if (!xmp) ThrowProgramError ("XMP object is NULL.");
+ return dynamic_cast< const X & > (*xmp);
+ }
+
+/*****************************************************************************/
+
+/// \brief Main class for holding DNG image data and associated metadata.
+
+class dng_negative
+ {
+
+ public:
+
+ enum RawImageStageEnum
+ {
+ rawImageStagePreOpcode1,
+ rawImageStagePostOpcode1,
+ rawImageStagePostOpcode2,
+ rawImageStagePreOpcode3,
+ rawImageStagePostOpcode3,
+ rawImageStageNone
+ };
+
+ protected:
+
+ // The negative stores an associated allocator. It does not do
+ // anything to keep it alive or to release it when the object destructs.
+ // Hence, clients will need to make sure that the allocator's lifespan
+ // encompasses that of the dng_factory object which is generally
+ // directly bound to the dng_negative object.
+
+ dng_memory_allocator &fAllocator;
+
+ // Non-localized ASCII model name.
+
+ dng_string fModelName;
+
+ // Localized UTF-8 model name.
+
+ dng_string fLocalName;
+
+ // The area of raw image that should be included in the final converted
+ // image. This stems from extra pixels around the edges of the sensor
+ // including both the black mask and some additional padding.
+
+ // The default crop can be smaller than the "active" area which includes
+ // the padding but not the black masked pixels.
+
+ dng_urational fDefaultCropSizeH;
+ dng_urational fDefaultCropSizeV;
+
+ dng_urational fDefaultCropOriginH;
+ dng_urational fDefaultCropOriginV;
+
+ // Default user crop, in relative coordinates.
+
+ dng_urational fDefaultUserCropT;
+ dng_urational fDefaultUserCropL;
+ dng_urational fDefaultUserCropB;
+ dng_urational fDefaultUserCropR;
+
+ // Default scale factors. Generally, 1.0 for square pixel cameras. They
+ // can compensate for non-square pixels. The choice of exact values will
+ // generally depend on what the camera does. These are particularly
+ // interesting for the Nikon D1X and the Fuji diamond mosaic.
+
+ dng_urational fDefaultScaleH;
+ dng_urational fDefaultScaleV;
+
+ // Best quality scale factor. Used for the Nikon D1X and Fuji cameras
+ // to force everything to be a scale up rather than scale down. So,
+ // generally this is 1.0 / min (fDefaultScaleH, fDefaultScaleV) but
+ // this isn't used if the scale factors are only slightly different
+ // from 1.0.
+
+ dng_urational fBestQualityScale;
+
+ // Proxy image support. Remember certain sizes for the original image
+ // this proxy was derived from.
+
+ dng_point fOriginalDefaultFinalSize;
+ dng_point fOriginalBestQualityFinalSize;
+
+ dng_urational fOriginalDefaultCropSizeH;
+ dng_urational fOriginalDefaultCropSizeV;
+
+ // Scale factors used in demosaic algorithm (calculated).
+ // Maps raw image coordinates to full image coordinates -- i.e.,
+ // original image coordinates on raw sensor data to coordinates
+ // in fStage3Image which is the output of the interpolation step.
+ // So, if we downsample when interpolating, these numbers get
+ // smaller.
+
+ real64 fRawToFullScaleH;
+ real64 fRawToFullScaleV;
+
+ // Relative amount of noise at ISO 100. This is measured per camera model
+ // based on looking at flat areas of color.
+
+ dng_urational fBaselineNoise;
+
+ // How much noise reduction has already been applied (0.0 to 1.0) to the
+ // the raw image data? 0.0 = none, 1.0 = "ideal" amount--i.e. don't apply any
+ // more by default. 0/0 for unknown.
+
+ dng_urational fNoiseReductionApplied;
+
+ // Amount of noise for this negative (see dng_noise_profile for details).
+
+ dng_noise_profile fNoiseProfile;
+
+ // Zero point for the exposure compensation slider. This reflects how
+ // the manufacturer sets up the camera and its conversions.
+
+ dng_srational fBaselineExposure;
+
+ // Relative amount of sharpening required. This is chosen per camera
+ // model based on how strong the anti-alias filter is on the camera
+ // and the quality of the lenses. This scales the sharpness slider
+ // value.
+
+ dng_urational fBaselineSharpness;
+
+ // Chroma blur radius (or 0/0 for auto). Set to 0/1 to disable
+ // chroma blurring.
+
+ dng_urational fChromaBlurRadius;
+
+ // Anti-alias filter strength (0.0 to 1.0). Used as a hint
+ // to the demosaic algorithms.
+
+ dng_urational fAntiAliasStrength;
+
+ // Linear response limit. The point at which the sensor goes
+ // non-linear and color information becomes unreliable. Used in
+ // the highlight-recovery logic.
+
+ dng_urational fLinearResponseLimit;
+
+ // Scale factor for shadows slider. The Fuji HDR cameras, for example,
+ // need a more sensitive shadow slider.
+
+ dng_urational fShadowScale;
+
+ // Colormetric reference.
+
+ uint32 fColorimetricReference;
+
+ // Number of color channels for this image (e.g. 1, 3, or 4).
+
+ uint32 fColorChannels;
+
+ // Amount by which each channel has already been scaled. Some cameras
+ // have analog amplifiers on the color channels and these can result
+ // in different scalings per channel. This provides some level of
+ // analog white balancing. The Nikon D1 also did digital scaling but
+ // this caused problems with highlight recovery.
+
+ dng_vector fAnalogBalance;
+
+ // The "As Shot" neutral color coordinates in native camera space.
+ // This overrides fCameraWhiteXY if both are specified. This
+ // specifies the values per channel that would result in a neutral
+ // color for the "As Shot" case. This is generally supplied by
+ // the camera.
+
+ dng_vector fCameraNeutral;
+
+ // The "As Shot" white balance xy coordinates. Sometimes this is
+ // supplied by the camera. Sometimes the camera just supplies a name
+ // for the white balance.
+
+ dng_xy_coord fCameraWhiteXY;
+
+ // Individual camera calibrations.
+
+ // Camera data --> camera calibration --> "inverse" of color matrix
+
+ // This will be a 4x4 matrix for a 4-color camera. The defaults are
+ // almost always the identity matrix and for the cases where they
+ // aren't, they are diagonal matrices.
+
+ dng_matrix fCameraCalibration1;
+ dng_matrix fCameraCalibration2;
+
+ // Signature which allows a profile to announce that it is compatible
+ // with these calibration matrices.
+
+ dng_string fCameraCalibrationSignature;
+
+ // List of camera profiles.
+
+ std::vector<dng_camera_profile *> fCameraProfile;
+
+ // "As shot" camera profile name.
+
+ dng_string fAsShotProfileName;
+
+ // Raw image data digests. These are MD5 fingerprints of the raw image data
+ // in the file, computed using a specific algorithms. They can be used
+ // verify the raw data has not been corrupted. The new version is faster
+ // to compute on MP machines, and is used starting with DNG version 1.4.
+
+ mutable dng_fingerprint fRawImageDigest;
+
+ mutable dng_fingerprint fNewRawImageDigest;
+
+ // Raw data unique ID. This is an unique identifer for the actual
+ // raw image data in the file. It can be used to index into caches
+ // for this data.
+
+ mutable dng_fingerprint fRawDataUniqueID;
+
+ // Original raw file name. Just the file name, not the full path.
+
+ dng_string fOriginalRawFileName;
+
+ // Is the original raw file data availaible?
+
+ bool fHasOriginalRawFileData;
+
+ // The compressed original raw file data.
+
+ AutoPtr<dng_memory_block> fOriginalRawFileData;
+
+ // MD5 digest of original raw file data block.
+
+ mutable dng_fingerprint fOriginalRawFileDigest;
+
+ // DNG private data block.
+
+ AutoPtr<dng_memory_block> fDNGPrivateData;
+
+ // Metadata information (XMP, IPTC, EXIF, orientation)
+
+ dng_metadata fMetadata;
+
+ // Information required to linearize and range map the raw data.
+
+ AutoPtr<dng_linearization_info> fLinearizationInfo;
+
+ // Information required to demoasic the raw data.
+
+ AutoPtr<dng_mosaic_info> fMosaicInfo;
+
+ // Opcode list 1. (Applied to stored data)
+
+ dng_opcode_list fOpcodeList1;
+
+ // Opcode list 2. (Applied to range mapped data)
+
+ dng_opcode_list fOpcodeList2;
+
+ // Opcode list 3. (Post demosaic)
+
+ dng_opcode_list fOpcodeList3;
+
+ // Stage 1 image, which is image data stored in a DNG file.
+
+ AutoPtr<dng_image> fStage1Image;
+
+ // Stage 2 image, which is the stage 1 image after it has been
+ // linearized and range mapped.
+
+ AutoPtr<dng_image> fStage2Image;
+
+ // Stage 3 image, which is the stage 2 image after it has been
+ // demosaiced.
+
+ AutoPtr<dng_image> fStage3Image;
+
+ // Additiona gain applied when building the stage 3 image.
+
+ real64 fStage3Gain;
+
+ // Were any approximations (e.g. downsampling, etc.) applied
+ // file reading this image?
+
+ bool fIsPreview;
+
+ // Does the file appear to be damaged?
+
+ bool fIsDamaged;
+
+ // At what processing stage did we grab a copy of raw image data?
+
+ RawImageStageEnum fRawImageStage;
+
+ // The raw image data that we grabbed, if any.
+
+ AutoPtr<dng_image> fRawImage;
+
+ // The floating point bit depth of the raw file, if any.
+
+ uint32 fRawFloatBitDepth;
+
+ // The raw image JPEG data that we grabbed, if any.
+
+ AutoPtr<dng_jpeg_image> fRawJPEGImage;
+
+ // Keep a separate digest for the compressed JPEG data, if any.
+
+ mutable dng_fingerprint fRawJPEGImageDigest;
+
+ // Transparency mask image, if any.
+
+ AutoPtr<dng_image> fTransparencyMask;
+
+ // Grabbed transparency mask, if we are not saving the current mask.
+
+ AutoPtr<dng_image> fRawTransparencyMask;
+
+ // The bit depth for the raw transparancy mask, if known.
+
+ uint32 fRawTransparencyMaskBitDepth;
+
+ // We sometimes need to keep of copy of the stage3 image before
+ // flattening the transparency.
+
+ AutoPtr<dng_image> fUnflattenedStage3Image;
+
+ public:
+
+ virtual ~dng_negative ();
+
+ static dng_negative * Make (dng_host &host);
+
+ /// Provide access to the memory allocator used for this object.
+
+ dng_memory_allocator & Allocator () const
+ {
+ return fAllocator;
+ }
+
+ bool IsVc5Image(dng_info &info);
+
+ void ReadVc5Image (dng_host &host,
+ dng_stream &stream,
+ dng_info &info,
+ dng_read_image &imageReader );
+
+ /// Getter for ModelName.
+
+ void SetModelName (const char *name)
+ {
+ fModelName.Set_ASCII (name);
+ }
+
+ /// Setter for ModelName.
+
+ const dng_string & ModelName () const
+ {
+ return fModelName;
+ }
+
+ /// Setter for LocalName.
+
+ void SetLocalName (const char *name)
+ {
+ fLocalName.Set (name);
+ }
+
+ /// Getter for LocalName.
+
+ const dng_string & LocalName () const
+ {
+ return fLocalName;
+ }
+
+ /// Getter for metadata
+
+ dng_metadata &Metadata ()
+ {
+ return fMetadata;
+ }
+
+ #if qMetadataOnConst
+
+ const dng_metadata &Metadata () const
+ {
+ return fMetadata;
+ }
+
+ #endif // qMetadataOnConst
+
+ /// Make a copy of the internal metadata generally as a basis for further
+ /// changes.
+
+ dng_metadata * CloneInternalMetadata () const;
+
+ protected:
+
+ /// An accessor for the internal metadata that works even when we
+ /// have general access turned off. This is needed to provide
+ /// access to EXIF ISO information.
+
+ const dng_metadata &InternalMetadata () const
+ {
+ return fMetadata;
+ }
+
+ public:
+
+ /// Setter for BaseOrientation.
+
+ void SetBaseOrientation (const dng_orientation &orientation)
+ {
+ Metadata ().SetBaseOrientation (orientation);
+ }
+
+ /// Has BaseOrientation been set?
+
+ bool HasBaseOrientation () METACONST
+ {
+ return Metadata ().HasBaseOrientation ();
+ }
+
+ /// Getter for BaseOrientation.
+
+ const dng_orientation & BaseOrientation () METACONST
+ {
+ return Metadata ().BaseOrientation ();
+ }
+
+ /// Hook to allow SDK host code to add additional rotations.
+
+ virtual dng_orientation ComputeOrientation (const dng_metadata &metadata) const;
+
+ /// For non-const negatives, we simply default to using the metadata attached to the negative.
+
+ dng_orientation Orientation ()
+ {
+ return ComputeOrientation (Metadata ());
+ }
+
+ /// Logically rotates the image by changing the orientation values.
+ /// This will also update the XMP data.
+
+ void ApplyOrientation (const dng_orientation &orientation)
+ {
+ Metadata ().ApplyOrientation (orientation);
+ }
+
+ /// Setter for DefaultCropSize.
+
+ void SetDefaultCropSize (const dng_urational &sizeH,
+ const dng_urational &sizeV)
+ {
+ fDefaultCropSizeH = sizeH;
+ fDefaultCropSizeV = sizeV;
+ }
+
+ /// Setter for DefaultCropSize.
+
+ void SetDefaultCropSize (uint32 sizeH,
+ uint32 sizeV)
+ {
+ SetDefaultCropSize (dng_urational (sizeH, 1),
+ dng_urational (sizeV, 1));
+ }
+
+ /// Getter for DefaultCropSize horizontal.
+
+ const dng_urational & DefaultCropSizeH () const
+ {
+ return fDefaultCropSizeH;
+ }
+
+ /// Getter for DefaultCropSize vertical.
+
+ const dng_urational & DefaultCropSizeV () const
+ {
+ return fDefaultCropSizeV;
+ }
+
+ /// Setter for DefaultCropOrigin.
+
+ void SetDefaultCropOrigin (const dng_urational &originH,
+ const dng_urational &originV)
+ {
+ fDefaultCropOriginH = originH;
+ fDefaultCropOriginV = originV;
+ }
+
+ /// Setter for DefaultCropOrigin.
+
+ void SetDefaultCropOrigin (uint32 originH,
+ uint32 originV)
+ {
+ SetDefaultCropOrigin (dng_urational (originH, 1),
+ dng_urational (originV, 1));
+ }
+
+ /// Set default crop around center of image.
+
+ void SetDefaultCropCentered (const dng_point &rawSize)
+ {
+
+ uint32 sizeH = Round_uint32 (fDefaultCropSizeH.As_real64 ());
+ uint32 sizeV = Round_uint32 (fDefaultCropSizeV.As_real64 ());
+
+ SetDefaultCropOrigin ((rawSize.h - sizeH) >> 1,
+ (rawSize.v - sizeV) >> 1);
+
+ }
+
+ /// Get default crop origin horizontal value.
+
+ const dng_urational & DefaultCropOriginH () const
+ {
+ return fDefaultCropOriginH;
+ }
+
+ /// Get default crop origin vertical value.
+
+ const dng_urational & DefaultCropOriginV () const
+ {
+ return fDefaultCropOriginV;
+ }
+
+ /// Getter for top coordinate of default user crop.
+
+ const dng_urational & DefaultUserCropT () const
+ {
+ return fDefaultUserCropT;
+ }
+
+ /// Getter for left coordinate of default user crop.
+
+ const dng_urational & DefaultUserCropL () const
+ {
+ return fDefaultUserCropL;
+ }
+
+ /// Getter for bottom coordinate of default user crop.
+
+ const dng_urational & DefaultUserCropB () const
+ {
+ return fDefaultUserCropB;
+ }
+
+ /// Getter for right coordinate of default user crop.
+
+ const dng_urational & DefaultUserCropR () const
+ {
+ return fDefaultUserCropR;
+ }
+
+ /// Reset default user crop to default crop area.
+
+ void ResetDefaultUserCrop ()
+ {
+ fDefaultUserCropT = dng_urational (0, 1);
+ fDefaultUserCropL = dng_urational (0, 1);
+ fDefaultUserCropB = dng_urational (1, 1);
+ fDefaultUserCropR = dng_urational (1, 1);
+ }
+
+ /// Setter for all 4 coordinates of default user crop.
+
+ void SetDefaultUserCrop (const dng_urational &t,
+ const dng_urational &l,
+ const dng_urational &b,
+ const dng_urational &r)
+ {
+ fDefaultUserCropT = t;
+ fDefaultUserCropL = l;
+ fDefaultUserCropB = b;
+ fDefaultUserCropR = r;
+ }
+
+ /// Setter for top coordinate of default user crop.
+
+ void SetDefaultUserCropT (const dng_urational &value)
+ {
+ fDefaultUserCropT = value;
+ }
+
+ /// Setter for left coordinate of default user crop.
+
+ void SetDefaultUserCropL (const dng_urational &value)
+ {
+ fDefaultUserCropL = value;
+ }
+
+ /// Setter for bottom coordinate of default user crop.
+
+ void SetDefaultUserCropB (const dng_urational &value)
+ {
+ fDefaultUserCropB = value;
+ }
+
+ /// Setter for right coordinate of default user crop.
+
+ void SetDefaultUserCropR (const dng_urational &value)
+ {
+ fDefaultUserCropR = value;
+ }
+
+ /// Setter for DefaultScale.
+
+ void SetDefaultScale (const dng_urational &scaleH,
+ const dng_urational &scaleV)
+ {
+ fDefaultScaleH = scaleH;
+ fDefaultScaleV = scaleV;
+ }
+
+ /// Get default scale horizontal value.
+
+ const dng_urational & DefaultScaleH () const
+ {
+ return fDefaultScaleH;
+ }
+
+ /// Get default scale vertical value.
+
+ const dng_urational & DefaultScaleV () const
+ {
+ return fDefaultScaleV;
+ }
+
+ /// Setter for BestQualityScale.
+
+ void SetBestQualityScale (const dng_urational &scale)
+ {
+ fBestQualityScale = scale;
+ }
+
+ /// Getter for BestQualityScale.
+
+ const dng_urational & BestQualityScale () const
+ {
+ return fBestQualityScale;
+ }
+
+ /// API for raw to full image scaling factors horizontal.
+
+ real64 RawToFullScaleH () const
+ {
+ return fRawToFullScaleH;
+ }
+
+ /// API for raw to full image scaling factors vertical.
+
+ real64 RawToFullScaleV () const
+ {
+ return fRawToFullScaleV;
+ }
+
+ /// Setter for raw to full scales.
+
+ void SetRawToFullScale (real64 scaleH,
+ real64 scaleV)
+ {
+ fRawToFullScaleH = scaleH;
+ fRawToFullScaleV = scaleV;
+ }
+
+ /// Get default scale factor.
+ /// When specifing a single scale factor, we use the horizontal
+ /// scale factor, and let the vertical scale factor be calculated
+ /// based on the pixel aspect ratio.
+
+ real64 DefaultScale () const
+ {
+ return DefaultScaleH ().As_real64 ();
+ }
+
+ /// Default cropped image size (at scale == 1.0) width.
+
+ real64 SquareWidth () const
+ {
+ return DefaultCropSizeH ().As_real64 ();
+ }
+
+ /// Default cropped image size (at scale == 1.0) height.
+
+ real64 SquareHeight () const
+ {
+ return DefaultCropSizeV ().As_real64 () *
+ DefaultScaleV ().As_real64 () /
+ DefaultScaleH ().As_real64 ();
+ }
+
+ /// Default cropped image aspect ratio.
+
+ real64 AspectRatio () const
+ {
+ return SquareWidth () /
+ SquareHeight ();
+ }
+
+ /// Pixel aspect ratio of stage 3 image.
+
+ real64 PixelAspectRatio () const
+ {
+ return (DefaultScaleH ().As_real64 () / RawToFullScaleH ()) /
+ (DefaultScaleV ().As_real64 () / RawToFullScaleV ());
+ }
+
+ /// Default cropped image size at given scale factor width.
+
+ uint32 FinalWidth (real64 scale) const
+ {
+ return Round_uint32 (SquareWidth () * scale);
+ }
+
+ /// Default cropped image size at given scale factor height.
+
+ uint32 FinalHeight (real64 scale) const
+ {
+ return Round_uint32 (SquareHeight () * scale);
+ }
+
+ /// Default cropped image size at default scale factor width.
+
+ uint32 DefaultFinalWidth () const
+ {
+ return FinalWidth (DefaultScale ());
+ }
+
+ /// Default cropped image size at default scale factor height.
+
+ uint32 DefaultFinalHeight () const
+ {
+ return FinalHeight (DefaultScale ());
+ }
+
+ /// Get best quality width.
+ /// For a naive conversion, one could use either the default size,
+ /// or the best quality size.
+
+ uint32 BestQualityFinalWidth () const
+ {
+ return FinalWidth (DefaultScale () * BestQualityScale ().As_real64 ());
+ }
+
+ /// Get best quality height.
+ /// For a naive conversion, one could use either the default size,
+ /// or the best quality size.
+
+ uint32 BestQualityFinalHeight () const
+ {
+ return FinalHeight (DefaultScale () * BestQualityScale ().As_real64 ());
+ }
+
+ /// Default size of original (non-proxy) image. For non-proxy images, this
+ /// is equal to DefaultFinalWidth/DefaultFinalHight. For proxy images, this
+ /// is equal to the DefaultFinalWidth/DefaultFinalHeight of the image this
+ /// proxy was derived from.
+
+ const dng_point & OriginalDefaultFinalSize () const
+ {
+ return fOriginalDefaultFinalSize;
+ }
+
+ /// Setter for OriginalDefaultFinalSize.
+
+ void SetOriginalDefaultFinalSize (const dng_point &size)
+ {
+ fOriginalDefaultFinalSize = size;
+ }
+
+ /// Best quality size of original (non-proxy) image. For non-proxy images, this
+ /// is equal to BestQualityFinalWidth/BestQualityFinalHeight. For proxy images, this
+ /// is equal to the BestQualityFinalWidth/BestQualityFinalHeight of the image this
+ /// proxy was derived from.
+
+ const dng_point & OriginalBestQualityFinalSize () const
+ {
+ return fOriginalBestQualityFinalSize;
+ }
+
+ /// Setter for OriginalBestQualityFinalSize.
+
+ void SetOriginalBestQualityFinalSize (const dng_point &size)
+ {
+ fOriginalBestQualityFinalSize = size;
+ }
+
+ /// DefaultCropSize for original (non-proxy) image. For non-proxy images,
+ /// this is equal to the DefaultCropSize. for proxy images, this is
+ /// equal size of the DefaultCropSize of the image this proxy was derived from.
+
+ const dng_urational & OriginalDefaultCropSizeH () const
+ {
+ return fOriginalDefaultCropSizeH;
+ }
+
+ const dng_urational & OriginalDefaultCropSizeV () const
+ {
+ return fOriginalDefaultCropSizeV;
+ }
+
+ /// Setter for OriginalDefaultCropSize.
+
+ void SetOriginalDefaultCropSize (const dng_urational &sizeH,
+ const dng_urational &sizeV)
+ {
+ fOriginalDefaultCropSizeH = sizeH;
+ fOriginalDefaultCropSizeV = sizeV;
+ }
+
+ /// If the original size fields are undefined, set them to the
+ /// current sizes.
+
+ void SetDefaultOriginalSizes ();
+
+ /// The default crop area in the stage 3 image coordinates.
+
+ dng_rect DefaultCropArea () const;
+
+ /// Setter for BaselineNoise.
+
+ void SetBaselineNoise (real64 noise)
+ {
+ fBaselineNoise.Set_real64 (noise, 100);
+ }
+
+ /// Getter for BaselineNoise as dng_urational.
+
+ const dng_urational & BaselineNoiseR () const
+ {
+ return fBaselineNoise;
+ }
+
+ /// Getter for BaselineNoise as real64.
+
+ real64 BaselineNoise () const
+ {
+ return fBaselineNoise.As_real64 ();
+ }
+
+ /// Setter for NoiseReductionApplied.
+
+ void SetNoiseReductionApplied (const dng_urational &value)
+ {
+ fNoiseReductionApplied = value;
+ }
+
+ /// Getter for NoiseReductionApplied.
+
+ const dng_urational & NoiseReductionApplied () const
+ {
+ return fNoiseReductionApplied;
+ }
+
+ /// Setter for noise profile.
+
+ void SetNoiseProfile (const dng_noise_profile &noiseProfile)
+ {
+ fNoiseProfile = noiseProfile;
+ }
+
+ /// Does this negative have a valid noise profile?
+
+ bool HasNoiseProfile () const
+ {
+ return fNoiseProfile.IsValidForNegative (*this);
+ }
+
+ /// Getter for noise profile.
+
+ const dng_noise_profile & NoiseProfile () const
+ {
+ return fNoiseProfile;
+ }
+
+ /// Setter for BaselineExposure.
+
+ void SetBaselineExposure (real64 exposure)
+ {
+ fBaselineExposure.Set_real64 (exposure, 100);
+ }
+
+ /// Getter for BaselineExposure as dng_urational.
+
+ const dng_srational & BaselineExposureR () const
+ {
+ return fBaselineExposure;
+ }
+
+ /// Getter for BaselineExposure as real64.
+
+ real64 BaselineExposure () const
+ {
+ return BaselineExposureR ().As_real64 ();
+ }
+
+ /// Compute total baseline exposure (sum of negative's BaselineExposure and
+ /// profile's BaselineExposureOffset).
+
+ real64 TotalBaselineExposure (const dng_camera_profile_id &profileID) const;
+
+ /// Setter for BaselineSharpness.
+
+ void SetBaselineSharpness (real64 sharpness)
+ {
+ fBaselineSharpness.Set_real64 (sharpness, 100);
+ }
+
+ /// Getter for BaselineSharpness as dng_urational.
+
+ const dng_urational & BaselineSharpnessR () const
+ {
+ return fBaselineSharpness;
+ }
+
+ /// Getter for BaselineSharpness as real64.
+
+ real64 BaselineSharpness () const
+ {
+ return BaselineSharpnessR ().As_real64 ();
+ }
+
+ /// Setter for ChromaBlurRadius.
+
+ void SetChromaBlurRadius (const dng_urational &radius)
+ {
+ fChromaBlurRadius = radius;
+ }
+
+ /// Getter for ChromaBlurRadius as dng_urational.
+
+ const dng_urational & ChromaBlurRadius () const
+ {
+ return fChromaBlurRadius;
+ }
+
+ /// Setter for AntiAliasStrength.
+
+ void SetAntiAliasStrength (const dng_urational &strength)
+ {
+ fAntiAliasStrength = strength;
+ }
+
+ /// Getter for AntiAliasStrength as dng_urational.
+
+ const dng_urational & AntiAliasStrength () const
+ {
+ return fAntiAliasStrength;
+ }
+
+ /// Setter for LinearResponseLimit.
+
+ void SetLinearResponseLimit (real64 limit)
+ {
+ fLinearResponseLimit.Set_real64 (limit, 100);
+ }
+
+ /// Getter for LinearResponseLimit as dng_urational.
+
+ const dng_urational & LinearResponseLimitR () const
+ {
+ return fLinearResponseLimit;
+ }
+
+ /// Getter for LinearResponseLimit as real64.
+
+ real64 LinearResponseLimit () const
+ {
+ return LinearResponseLimitR ().As_real64 ();
+ }
+
+ /// Setter for ShadowScale.
+
+ void SetShadowScale (const dng_urational &scale);
+
+ /// Getter for ShadowScale as dng_urational.
+
+ const dng_urational & ShadowScaleR () const
+ {
+ return fShadowScale;
+ }
+
+ /// Getter for ShadowScale as real64.
+
+ real64 ShadowScale () const
+ {
+ return ShadowScaleR ().As_real64 ();
+ }
+
+ // API for ColorimetricReference.
+
+ void SetColorimetricReference (uint32 ref)
+ {
+ fColorimetricReference = ref;
+ }
+
+ uint32 ColorimetricReference () const
+ {
+ return fColorimetricReference;
+ }
+
+ /// Setter for ColorChannels.
+
+ void SetColorChannels (uint32 channels)
+ {
+ fColorChannels = channels;
+ }
+
+ /// Getter for ColorChannels.
+
+ uint32 ColorChannels () const
+ {
+ return fColorChannels;
+ }
+
+ /// Setter for Monochrome.
+
+ void SetMonochrome ()
+ {
+ SetColorChannels (1);
+ }
+
+ /// Getter for Monochrome.
+
+ bool IsMonochrome () const
+ {
+ return ColorChannels () == 1;
+ }
+
+ /// Setter for AnalogBalance.
+
+ void SetAnalogBalance (const dng_vector &b);
+
+ /// Getter for AnalogBalance as dng_urational.
+
+ dng_urational AnalogBalanceR (uint32 channel) const;
+
+ /// Getter for AnalogBalance as real64.
+
+ real64 AnalogBalance (uint32 channel) const;
+
+ /// Setter for CameraNeutral.
+
+ void SetCameraNeutral (const dng_vector &n);
+
+ /// Clear CameraNeutral.
+
+ void ClearCameraNeutral ()
+ {
+ fCameraNeutral.Clear ();
+ }
+
+ /// Determine if CameraNeutral has been set but not cleared.
+
+ bool HasCameraNeutral () const
+ {
+ return fCameraNeutral.NotEmpty ();
+ }
+
+ /// Getter for CameraNeutral.
+
+ const dng_vector & CameraNeutral () const
+ {
+ return fCameraNeutral;
+ }
+
+ dng_urational CameraNeutralR (uint32 channel) const;
+
+ /// Setter for CameraWhiteXY.
+
+ void SetCameraWhiteXY (const dng_xy_coord &coord);
+
+ bool HasCameraWhiteXY () const
+ {
+ return fCameraWhiteXY.IsValid ();
+ }
+
+ const dng_xy_coord & CameraWhiteXY () const;
+
+ void GetCameraWhiteXY (dng_urational &x,
+ dng_urational &y) const;
+
+ // API for camera calibration:
+
+ /// Setter for first of up to two color matrices used for individual camera calibrations.
+ ///
+ /// The sequence of matrix transforms is:
+ /// Camera data --> camera calibration --> "inverse" of color matrix
+ ///
+ /// This will be a 4x4 matrix for a four-color camera. The defaults are
+ /// almost always the identity matrix, and for the cases where they
+ /// aren't, they are diagonal matrices.
+
+ void SetCameraCalibration1 (const dng_matrix &m);
+
+ /// Setter for second of up to two color matrices used for individual camera calibrations.
+ ///
+ /// The sequence of matrix transforms is:
+ /// Camera data --> camera calibration --> "inverse" of color matrix
+ ///
+ /// This will be a 4x4 matrix for a four-color camera. The defaults are
+ /// almost always the identity matrix, and for the cases where they
+ /// aren't, they are diagonal matrices.
+
+ void SetCameraCalibration2 (const dng_matrix &m);
+
+ /// Getter for first of up to two color matrices used for individual camera calibrations.
+
+ const dng_matrix & CameraCalibration1 () const
+ {
+ return fCameraCalibration1;
+ }
+
+ /// Getter for second of up to two color matrices used for individual camera calibrations.
+
+ const dng_matrix & CameraCalibration2 () const
+ {
+ return fCameraCalibration2;
+ }
+
+ void SetCameraCalibrationSignature (const char *signature)
+ {
+ fCameraCalibrationSignature.Set (signature);
+ }
+
+ const dng_string & CameraCalibrationSignature () const
+ {
+ return fCameraCalibrationSignature;
+ }
+
+ // Camera Profile API:
+
+ void AddProfile (AutoPtr<dng_camera_profile> &profile);
+
+ void ClearProfiles ();
+
+ void ClearProfiles (bool clearBuiltinMatrixProfiles,
+ bool clearReadFromDisk);
+
+ uint32 ProfileCount () const;
+
+ const dng_camera_profile & ProfileByIndex (uint32 index) const;
+
+ virtual const dng_camera_profile * ProfileByID (const dng_camera_profile_id &id,
+ bool useDefaultIfNoMatch = true) const;
+
+ bool HasProfileID (const dng_camera_profile_id &id) const
+ {
+ return ProfileByID (id, false) != NULL;
+ }
+
+ // Returns the camera profile to embed when saving to DNG:
+
+ virtual const dng_camera_profile * ComputeCameraProfileToEmbed
+ (const dng_metadata &metadata) const;
+
+ // For non-const negatives, we can use the embedded metadata.
+
+ const dng_camera_profile * CameraProfileToEmbed ()
+ {
+ return ComputeCameraProfileToEmbed (Metadata ());
+ }
+
+ // API for AsShotProfileName.
+
+ void SetAsShotProfileName (const char *name)
+ {
+ fAsShotProfileName.Set (name);
+ }
+
+ const dng_string & AsShotProfileName () const
+ {
+ return fAsShotProfileName;
+ }
+
+ // Makes a dng_color_spec object for this negative.
+
+ virtual dng_color_spec * MakeColorSpec (const dng_camera_profile_id &id) const;
+
+ // Compute a MD5 hash on an image, using a fixed algorithm.
+ // The results must be stable across different hardware, OSes,
+ // and software versions.
+
+ dng_fingerprint FindImageDigest (dng_host &host,
+ const dng_image &image) const;
+
+ // API for RawImageDigest and NewRawImageDigest:
+
+ void SetRawImageDigest (const dng_fingerprint &digest)
+ {
+ fRawImageDigest = digest;
+ }
+
+ void SetNewRawImageDigest (const dng_fingerprint &digest)
+ {
+ fNewRawImageDigest = digest;
+ }
+
+ void ClearRawImageDigest () const
+ {
+ fRawImageDigest .Clear ();
+ fNewRawImageDigest.Clear ();
+ }
+
+ const dng_fingerprint & RawImageDigest () const
+ {
+ return fRawImageDigest;
+ }
+
+ const dng_fingerprint & NewRawImageDigest () const
+ {
+ return fNewRawImageDigest;
+ }
+
+ void FindRawImageDigest (dng_host &host) const;
+
+ void FindNewRawImageDigest (dng_host &host) const;
+
+ void ValidateRawImageDigest (dng_host &host);
+
+ // API for RawDataUniqueID:
+
+ void SetRawDataUniqueID (const dng_fingerprint &id)
+ {
+ fRawDataUniqueID = id;
+ }
+
+ const dng_fingerprint & RawDataUniqueID () const
+ {
+ return fRawDataUniqueID;
+ }
+
+ void FindRawDataUniqueID (dng_host &host) const;
+
+ void RecomputeRawDataUniqueID (dng_host &host);
+
+ // API for original raw file name:
+
+ void SetOriginalRawFileName (const char *name)
+ {
+ fOriginalRawFileName.Set (name);
+ }
+
+ bool HasOriginalRawFileName () const
+ {
+ return fOriginalRawFileName.NotEmpty ();
+ }
+
+ const dng_string & OriginalRawFileName () const
+ {
+ return fOriginalRawFileName;
+ }
+
+ // API for original raw file data:
+
+ void SetHasOriginalRawFileData (bool hasData)
+ {
+ fHasOriginalRawFileData = hasData;
+ }
+
+ bool CanEmbedOriginalRaw () const
+ {
+ return fHasOriginalRawFileData && HasOriginalRawFileName ();
+ }
+
+ void SetOriginalRawFileData (AutoPtr<dng_memory_block> &data)
+ {
+ fOriginalRawFileData.Reset (data.Release ());
+ }
+
+ const void * OriginalRawFileData () const
+ {
+ return fOriginalRawFileData.Get () ? fOriginalRawFileData->Buffer ()
+ : NULL;
+ }
+
+ uint32 OriginalRawFileDataLength () const
+ {
+ return fOriginalRawFileData.Get () ? fOriginalRawFileData->LogicalSize ()
+ : 0;
+ }
+
+ // API for original raw file data digest.
+
+ void SetOriginalRawFileDigest (const dng_fingerprint &digest)
+ {
+ fOriginalRawFileDigest = digest;
+ }
+
+ const dng_fingerprint & OriginalRawFileDigest () const
+ {
+ return fOriginalRawFileDigest;
+ }
+
+ void FindOriginalRawFileDigest () const;
+
+ void ValidateOriginalRawFileDigest ();
+
+ // API for DNG private data:
+
+ void SetPrivateData (AutoPtr<dng_memory_block> &block)
+ {
+ fDNGPrivateData.Reset (block.Release ());
+ }
+
+ void ClearPrivateData ()
+ {
+ fDNGPrivateData.Reset ();
+ }
+
+ const uint8 * PrivateData () const
+ {
+ return fDNGPrivateData.Get () ? fDNGPrivateData->Buffer_uint8 ()
+ : NULL;
+ }
+
+ uint32 PrivateLength () const
+ {
+ return fDNGPrivateData.Get () ? fDNGPrivateData->LogicalSize ()
+ : 0;
+ }
+
+ // API for MakerNote data:
+
+ void SetMakerNoteSafety (bool safe)
+ {
+ Metadata ().SetMakerNoteSafety (safe);
+ }
+
+ bool IsMakerNoteSafe () METACONST
+ {
+ return Metadata ().IsMakerNoteSafe ();
+ }
+
+ void SetMakerNote (AutoPtr<dng_memory_block> &block)
+ {
+ Metadata ().SetMakerNote (block);
+ }
+
+ void ClearMakerNote ()
+ {
+ Metadata ().ClearMakerNote ();
+ }
+
+ const void * MakerNoteData () METACONST
+ {
+ return Metadata ().MakerNoteData ();
+ }
+
+ uint32 MakerNoteLength () METACONST
+ {
+ return Metadata ().MakerNoteLength ();
+ }
+
+ // API for EXIF metadata:
+
+ dng_exif * GetExif ()
+ {
+ return Metadata ().GetExif ();
+ }
+
+ #if qMetadataOnConst
+
+ const dng_exif * GetExif () const
+ {
+ return Metadata ().GetExif ();
+ }
+
+ #endif // qMetadataOnConst
+
+ void ResetExif (dng_exif * newExif)
+ {
+ Metadata ().ResetExif (newExif);
+ }
+
+ // API for original EXIF metadata.
+
+ dng_exif * GetOriginalExif ()
+ {
+ return Metadata ().GetOriginalExif ();
+ }
+
+ #if qMetadataOnConst
+
+ const dng_exif * GetOriginalExif () const
+ {
+ return Metadata ().GetOriginalExif ();
+ }
+
+ #endif // qMetadataOnConst
+
+ // API for IPTC metadata:
+
+ void SetIPTC (AutoPtr<dng_memory_block> &block,
+ uint64 offset)
+ {
+ Metadata ().SetIPTC (block, offset);
+ }
+
+ void SetIPTC (AutoPtr<dng_memory_block> &block)
+ {
+ Metadata ().SetIPTC (block);
+ }
+
+ void ClearIPTC ()
+ {
+ Metadata ().ClearIPTC ();
+ }
+
+ const void * IPTCData () METACONST
+ {
+ return Metadata ().IPTCData ();
+ }
+
+ uint32 IPTCLength () METACONST
+ {
+ return Metadata ().IPTCLength ();
+ }
+
+ uint64 IPTCOffset () METACONST
+ {
+ return Metadata ().IPTCOffset ();
+ }
+
+ dng_fingerprint IPTCDigest (bool includePadding = true) METACONST
+ {
+ return Metadata ().IPTCDigest (includePadding);
+ }
+
+ void RebuildIPTC (bool padForTIFF)
+ {
+ Metadata ().RebuildIPTC (Allocator (), padForTIFF);
+ }
+
+ // API for XMP metadata:
+
+ bool SetXMP (dng_host &host,
+ const void *buffer,
+ uint32 count,
+ bool xmpInSidecar = false,
+ bool xmpIsNewer = false)
+ {
+ return Metadata ().SetXMP (host,
+ buffer,
+ count,
+ xmpInSidecar,
+ xmpIsNewer);
+ }
+
+ dng_xmp * GetXMP ()
+ {
+ return Metadata ().GetXMP ();
+ }
+
+ #if qMetadataOnConst
+
+ const dng_xmp * GetXMP () const
+ {
+ return Metadata ().GetXMP ();
+ }
+
+ #endif // qMetadataOnConst
+
+ bool XMPinSidecar () METACONST
+ {
+ return Metadata ().XMPinSidecar ();
+ }
+
+ void ResetXMP (dng_xmp * newXMP)
+ {
+ Metadata ().ResetXMP (newXMP);
+ }
+
+ void ResetXMPSidecarNewer (dng_xmp * newXMP, bool inSidecar, bool isNewer )
+ {
+ Metadata ().ResetXMPSidecarNewer (newXMP, inSidecar, isNewer);
+ }
+
+ bool HaveValidEmbeddedXMP () METACONST
+ {
+ return Metadata ().HaveValidEmbeddedXMP ();
+ }
+
+ // API for source MIMI type.
+
+ void SetSourceMIMI (const char *s)
+ {
+ Metadata ().SetSourceMIMI (s);
+ }
+
+ // API for linearization information:
+
+ const dng_linearization_info * GetLinearizationInfo () const
+ {
+ return fLinearizationInfo.Get ();
+ }
+
+ void ClearLinearizationInfo ()
+ {
+ fLinearizationInfo.Reset ();
+ }
+
+ // Linearization curve. Usually used to increase compression ratios
+ // by storing the compressed data in a more visually uniform space.
+ // This is a 16-bit LUT that maps the stored data back to linear.
+
+ void SetLinearization (AutoPtr<dng_memory_block> &curve);
+
+ // Active area (non-black masked pixels). These pixels are trimmed
+ // during linearization step.
+
+ void SetActiveArea (const dng_rect &area);
+
+ // Areas that are known to contain black masked pixels that can
+ // be used to estimate black levels.
+
+ void SetMaskedAreas (uint32 count,
+ const dng_rect *area);
+
+ void SetMaskedArea (const dng_rect &area)
+ {
+ SetMaskedAreas (1, &area);
+ }
+
+ // Sensor black level information.
+
+ void SetBlackLevel (real64 black,
+ int32 plane = -1);
+
+ void SetQuadBlacks (real64 black0,
+ real64 black1,
+ real64 black2,
+ real64 black3,
+ int32 plane = -1);
+
+ void SetRowBlacks (const real64 *blacks,
+ uint32 count);
+
+ void SetColumnBlacks (const real64 *blacks,
+ uint32 count);
+
+ // Sensor white level information.
+
+ uint32 WhiteLevel (uint32 plane = 0) const;
+
+ void SetWhiteLevel (uint32 white,
+ int32 plane = -1);
+
+ // API for mosaic information:
+
+ const dng_mosaic_info * GetMosaicInfo () const
+ {
+ return fMosaicInfo.Get ();
+ }
+
+ void ClearMosaicInfo ()
+ {
+ fMosaicInfo.Reset ();
+ }
+
+ // ColorKeys APIs:
+
+ void SetColorKeys (ColorKeyCode color0,
+ ColorKeyCode color1,
+ ColorKeyCode color2,
+ ColorKeyCode color3 = colorKeyMaxEnum);
+
+ void SetRGB ()
+ {
+
+ SetColorChannels (3);
+
+ SetColorKeys (colorKeyRed,
+ colorKeyGreen,
+ colorKeyBlue);
+
+ }
+
+ void SetCMY ()
+ {
+
+ SetColorChannels (3);
+
+ SetColorKeys (colorKeyCyan,
+ colorKeyMagenta,
+ colorKeyYellow);
+
+ }
+
+ void SetGMCY ()
+ {
+
+ SetColorChannels (4);
+
+ SetColorKeys (colorKeyGreen,
+ colorKeyMagenta,
+ colorKeyCyan,
+ colorKeyYellow);
+
+ }
+
+ // APIs to set mosaic patterns.
+
+ void SetBayerMosaic (uint32 phase);
+
+ void SetFujiMosaic (uint32 phase);
+
+ void SetFujiMosaic6x6 (uint32 phase);
+
+ void SetQuadMosaic (uint32 pattern);
+
+ // BayerGreenSplit.
+
+ void SetGreenSplit (uint32 split);
+
+ // APIs for opcode lists.
+
+ const dng_opcode_list & OpcodeList1 () const
+ {
+ return fOpcodeList1;
+ }
+
+ dng_opcode_list & OpcodeList1 ()
+ {
+ return fOpcodeList1;
+ }
+
+ const dng_opcode_list & OpcodeList2 () const
+ {
+ return fOpcodeList2;
+ }
+
+ dng_opcode_list & OpcodeList2 ()
+ {
+ return fOpcodeList2;
+ }
+
+ const dng_opcode_list & OpcodeList3 () const
+ {
+ return fOpcodeList3;
+ }
+
+ dng_opcode_list & OpcodeList3 ()
+ {
+ return fOpcodeList3;
+ }
+
+ // First part of parsing logic.
+
+ virtual void Parse (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ // Second part of parsing logic. This is split off from the
+ // first part because these operations are useful when extending
+ // this sdk to support non-DNG raw formats.
+
+ virtual void PostParse (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ // Synchronize metadata sources.
+
+ void SynchronizeMetadata ()
+ {
+ Metadata ().SynchronizeMetadata ();
+ }
+
+ // Routines to update the date/time field in the EXIF and XMP
+ // metadata.
+
+ void UpdateDateTime (const dng_date_time_info &dt)
+ {
+ Metadata ().UpdateDateTime (dt);
+ }
+
+ void UpdateDateTimeToNow ()
+ {
+ Metadata ().UpdateDateTimeToNow ();
+ }
+
+ // Developer's utility function to switch to four color Bayer
+ // interpolation. This is useful for evaluating how much green
+ // split a Bayer pattern sensor has.
+
+ virtual bool SetFourColorBayer ();
+
+ // Access routines for the image stages.
+
+ const dng_image * Stage1Image () const
+ {
+ return fStage1Image.Get ();
+ }
+
+ const dng_image * Stage2Image () const
+ {
+ return fStage2Image.Get ();
+ }
+
+ const dng_image * Stage3Image () const
+ {
+ return fStage3Image.Get ();
+ }
+
+ // Returns the processing stage of the raw image data.
+
+ RawImageStageEnum RawImageStage () const
+ {
+ return fRawImageStage;
+ }
+
+ // Returns the raw image data.
+
+ const dng_image & RawImage () const;
+
+ // API for raw floating point bit depth.
+
+ uint32 RawFloatBitDepth () const
+ {
+ return fRawFloatBitDepth;
+ }
+
+ void SetRawFloatBitDepth (uint32 bitDepth)
+ {
+ fRawFloatBitDepth = bitDepth;
+ }
+
+ // API for raw jpeg image.
+
+ const dng_jpeg_image * RawJPEGImage () const;
+
+ void SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage);
+
+ void ClearRawJPEGImage ();
+
+ // API for RawJPEGImageDigest:
+
+ void SetRawJPEGImageDigest (const dng_fingerprint &digest)
+ {
+ fRawJPEGImageDigest = digest;
+ }
+
+ void ClearRawJPEGImageDigest () const
+ {
+ fRawJPEGImageDigest.Clear ();
+ }
+
+ const dng_fingerprint & RawJPEGImageDigest () const
+ {
+ return fRawJPEGImageDigest;
+ }
+
+ void FindRawJPEGImageDigest (dng_host &host) const;
+
+ // Read the stage 1 image.
+
+ virtual void ReadStage1Image (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ // Assign the stage 1 image.
+
+ void SetStage1Image (AutoPtr<dng_image> &image);
+
+ // Assign the stage 2 image.
+
+ void SetStage2Image (AutoPtr<dng_image> &image);
+
+ // Assign the stage 3 image.
+
+ void SetStage3Image (AutoPtr<dng_image> &image);
+
+ // Build the stage 2 (linearized and range mapped) image.
+
+ void BuildStage2Image (dng_host &host);
+
+ // Build the stage 3 (demosaiced) image.
+
+ void BuildStage3Image (dng_host &host,
+ int32 srcPlane = -1);
+
+ // Additional gain applied when building the stage 3 image.
+
+ void SetStage3Gain (real64 gain)
+ {
+ fStage3Gain = gain;
+ }
+
+ real64 Stage3Gain () const
+ {
+ return fStage3Gain;
+ }
+
+ // Adaptively encode a proxy image down to 8-bits/channel.
+
+ dng_image * EncodeRawProxy (dng_host &host,
+ const dng_image &srcImage,
+ dng_opcode_list &opcodeList) const;
+
+ // Convert to a proxy negative.
+
+ void ConvertToProxy (dng_host &host,
+ dng_image_writer &writer,
+ uint32 proxySize = 0,
+ uint64 proxyCount = 0);
+
+ // IsPreview API:
+
+ void SetIsPreview (bool preview)
+ {
+ fIsPreview = preview;
+ }
+
+ bool IsPreview () const
+ {
+ return fIsPreview;
+ }
+
+ // IsDamaged API:
+
+ void SetIsDamaged (bool damaged)
+ {
+ fIsDamaged = damaged;
+ }
+
+ bool IsDamaged () const
+ {
+ return fIsDamaged;
+ }
+
+ // Transparancy Mask API:
+
+ void SetTransparencyMask (AutoPtr<dng_image> &image,
+ uint32 bitDepth = 0);
+
+ const dng_image * TransparencyMask () const;
+
+ const dng_image * RawTransparencyMask () const;
+
+ uint32 RawTransparencyMaskBitDepth () const;
+
+ void ReadTransparencyMask (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ virtual bool NeedFlattenTransparency (dng_host &host);
+
+ virtual void FlattenTransparency (dng_host &host);
+
+ const dng_image * UnflattenedStage3Image () const;
+
+ protected:
+
+ dng_negative (dng_host &host);
+
+ virtual void Initialize ();
+
+ virtual dng_linearization_info * MakeLinearizationInfo ();
+
+ void NeedLinearizationInfo ();
+
+ virtual dng_mosaic_info * MakeMosaicInfo ();
+
+ void NeedMosaicInfo ();
+
+ virtual void DoBuildStage2 (dng_host &host);
+
+ virtual void DoPostOpcodeList2 (dng_host &host);
+
+ virtual bool NeedDefloatStage2 (dng_host &host);
+
+ virtual void DefloatStage2 (dng_host &host);
+
+ virtual void DoInterpolateStage3 (dng_host &host,
+ int32 srcPlane);
+
+ virtual void DoMergeStage3 (dng_host &host);
+
+ virtual void DoBuildStage3 (dng_host &host,
+ int32 srcPlane);
+
+ virtual void AdjustProfileForStage3 ();
+
+ virtual void ResizeTransparencyToMatchStage3 (dng_host &host,
+ bool convertTo8Bit = false);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_opcode_list.cpp b/gpr/source/lib/dng_sdk/dng_opcode_list.cpp
new file mode 100644
index 0000000..a5af89a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_opcode_list.cpp
@@ -0,0 +1,274 @@
+/*****************************************************************************/
+// Copyright 2008-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_opcode_list.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_opcode_list.h"
+
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_memory_stream.h"
+#include "dng_negative.h"
+#include "dng_tag_values.h"
+#include "dng_utils.h"
+
+#include <algorithm>
+
+/*****************************************************************************/
+
+dng_opcode_list::dng_opcode_list (uint32 stage)
+
+ : fList ()
+ , fAlwaysApply (false)
+ , fStage (stage)
+
+ {
+
+ }
+
+/******************************************************************************/
+
+dng_opcode_list::~dng_opcode_list ()
+ {
+
+ Clear ();
+
+ }
+
+/******************************************************************************/
+
+void dng_opcode_list::Clear ()
+ {
+
+ for (size_t index = 0; index < fList.size (); index++)
+ {
+
+ if (fList [index])
+ {
+
+ delete fList [index];
+
+ fList [index] = NULL;
+
+ }
+
+ }
+
+ fList.clear ();
+
+ fAlwaysApply = false;
+
+ }
+
+/******************************************************************************/
+
+void dng_opcode_list::Swap (dng_opcode_list &otherList)
+ {
+
+ fList.swap (otherList.fList);
+
+ std::swap (fAlwaysApply, otherList.fAlwaysApply);
+
+ std::swap (fStage, otherList.fStage);
+
+ }
+
+/******************************************************************************/
+
+uint32 dng_opcode_list::MinVersion (bool includeOptional) const
+ {
+
+ uint32 result = dngVersion_None;
+
+ for (size_t index = 0; index < fList.size (); index++)
+ {
+
+ if (includeOptional || !fList [index]->Optional ())
+ {
+
+ result = Max_uint32 (result, fList [index]->MinVersion ());
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_list::Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image)
+ {
+
+ for (uint32 index = 0; index < Count (); index++)
+ {
+
+ dng_opcode &opcode (Entry (index));
+
+ if (opcode.AboutToApply (host, negative))
+ {
+
+ opcode.Apply (host,
+ negative,
+ image);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_list::Append (AutoPtr<dng_opcode> &opcode)
+ {
+
+ if (opcode->OpcodeID () == dngOpcode_Private)
+ {
+ SetAlwaysApply ();
+ }
+
+ opcode->SetStage (fStage);
+
+ fList.push_back (NULL);
+
+ fList [fList.size () - 1] = opcode.Release ();
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_opcode_list::Spool (dng_host &host) const
+ {
+
+ if (IsEmpty ())
+ {
+ return NULL;
+ }
+
+ if (AlwaysApply ())
+ {
+ ThrowProgramError ();
+ }
+
+ dng_memory_stream stream (host.Allocator ());
+
+ stream.SetBigEndian ();
+
+ stream.Put_uint32 ((uint32) fList.size ());
+
+ for (size_t index = 0; index < fList.size (); index++)
+ {
+
+ stream.Put_uint32 (fList [index]->OpcodeID ());
+ stream.Put_uint32 (fList [index]->MinVersion ());
+ stream.Put_uint32 (fList [index]->Flags ());
+
+ fList [index]->PutData (stream);
+
+ }
+
+ return stream.AsMemoryBlock (host.Allocator ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_list::FingerprintToStream (dng_stream &stream) const
+ {
+
+ if (IsEmpty ())
+ {
+ return;
+ }
+
+ stream.Put_uint32 ((uint32) fList.size ());
+
+ for (size_t index = 0; index < fList.size (); index++)
+ {
+
+ stream.Put_uint32 (fList [index]->OpcodeID ());
+ stream.Put_uint32 (fList [index]->MinVersion ());
+ stream.Put_uint32 (fList [index]->Flags ());
+
+ if (fList [index]->OpcodeID () != dngOpcode_Private)
+ {
+
+ fList [index]->PutData (stream);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_list::Parse (dng_host &host,
+ dng_stream &stream,
+ uint32 byteCount,
+ uint64 streamOffset)
+ {
+
+ Clear ();
+
+ TempBigEndian tempBigEndian (stream);
+
+ stream.SetReadPosition (streamOffset);
+
+ uint32 count = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ if (count == 1)
+ {
+ printf ("1 opcode\n");
+ }
+
+ else
+ {
+ printf ("%u opcodes\n", (unsigned) count);
+ }
+
+ }
+
+ #endif
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ uint32 opcodeID = stream.Get_uint32 ();
+
+ AutoPtr<dng_opcode> opcode (host.Make_dng_opcode (opcodeID,
+ stream));
+
+ Append (opcode);
+
+ }
+
+ if (stream.Position () != streamOffset + byteCount)
+ {
+
+ ThrowBadFormat ("Error parsing opcode list");
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_opcode_list.h b/gpr/source/lib/dng_sdk/dng_opcode_list.h
new file mode 100644
index 0000000..84813fb
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_opcode_list.h
@@ -0,0 +1,165 @@
+/*****************************************************************************/
+// Copyright 2008-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_opcode_list.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * List of opcodes.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_opcode_list__
+#define __dng_opcode_list__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_opcodes.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+/// A list of opcodes.
+
+class dng_opcode_list
+ {
+
+ private:
+
+ std::vector<dng_opcode *> fList;
+
+ bool fAlwaysApply;
+
+ uint32 fStage;
+
+ public:
+
+ /// Create an empty opcode list for the specific image stage (1, 2, or 3).
+
+ dng_opcode_list (uint32 stage);
+
+ ~dng_opcode_list ();
+
+ /// Is the opcode list empty?
+
+ bool IsEmpty () const
+ {
+ return fList.size () == 0;
+ }
+
+ /// Does the list contain at least 1 opcode?
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ /// Should the opcode list always be applied to the image?
+
+ bool AlwaysApply () const
+ {
+ return fAlwaysApply && NotEmpty ();
+ }
+
+ /// Set internal flag to indicate this opcode list should always be
+ /// applied.
+
+ void SetAlwaysApply ()
+ {
+ fAlwaysApply = true;
+ }
+
+ /// The number of opcodes in this list.
+
+ uint32 Count () const
+ {
+ return (uint32) fList.size ();
+ }
+
+ /// Retrieve read/write opcode by index (must be in the range 0 to Count
+ /// () - 1).
+
+ dng_opcode & Entry (uint32 index)
+ {
+ return *fList [index];
+ }
+
+ /// Retrieve read-only opcode by index (must be in the range 0 to Count
+ /// () - 1).
+
+ const dng_opcode & Entry (uint32 index) const
+ {
+ return *fList [index];
+ }
+
+ /// Remove all opcodes from the list.
+
+ void Clear ();
+
+ /// Swap two opcode lists.
+
+ void Swap (dng_opcode_list &otherList);
+
+ /// Return minimum DNG version required to support all opcodes in this
+ /// list. If includeOptional is set to true, then this calculation will
+ /// include optional opcodes.
+
+ uint32 MinVersion (bool includeOptional) const;
+
+ /// Apply this opcode list to the specified image with corresponding
+ /// negative.
+
+ void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ /// Append the specified opcode to this list.
+
+ void Append (AutoPtr<dng_opcode> &opcode);
+
+ /// Serialize this opcode list to a block of memory. The caller is
+ /// responsible for deleting this block.
+
+ dng_memory_block * Spool (dng_host &host) const;
+
+ /// Write a fingerprint of this opcode list to the specified stream.
+
+ void FingerprintToStream (dng_stream &stream) const;
+
+ /// Read an opcode list from the specified stream, starting at the
+ /// specified offset (streamOffset, in bytes). byteCount is provided for
+ /// error checking purposes. A bad format exception
+ /// will be thrown if the length of the opcode stream does not exactly
+ /// match byteCount.
+
+ void Parse (dng_host &host,
+ dng_stream &stream,
+ uint32 byteCount,
+ uint64 streamOffset);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_opcode_list (const dng_opcode_list &list);
+
+ dng_opcode_list & operator= (const dng_opcode_list &list);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_opcodes.cpp b/gpr/source/lib/dng_sdk/dng_opcodes.cpp
new file mode 100644
index 0000000..dedf097
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_opcodes.cpp
@@ -0,0 +1,572 @@
+/*****************************************************************************/
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_opcodes.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_opcodes.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_filter_task.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_negative.h"
+#include "dng_parse_utils.h"
+#include "dng_stream.h"
+#include "dng_tag_values.h"
+
+/*****************************************************************************/
+
+dng_opcode::dng_opcode (uint32 opcodeID,
+ uint32 minVersion,
+ uint32 flags)
+
+ : fOpcodeID (opcodeID)
+ , fMinVersion (minVersion)
+ , fFlags (flags)
+ , fWasReadFromStream (false)
+ , fStage (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode::dng_opcode (uint32 opcodeID,
+ dng_stream &stream,
+ const char *name)
+
+ : fOpcodeID (opcodeID)
+ , fMinVersion (0)
+ , fFlags (0)
+ , fWasReadFromStream (true)
+ , fStage (0)
+
+ {
+
+ fMinVersion = stream.Get_uint32 ();
+ fFlags = stream.Get_uint32 ();
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("\nOpcode: ");
+
+ if (name)
+ {
+ printf ("%s", name);
+ }
+ else
+ {
+ printf ("Unknown (%u)", (unsigned) opcodeID);
+ }
+
+ printf (", minVersion = %u.%u.%u.%u",
+ (unsigned) ((fMinVersion >> 24) & 0x0FF),
+ (unsigned) ((fMinVersion >> 16) & 0x0FF),
+ (unsigned) ((fMinVersion >> 8) & 0x0FF),
+ (unsigned) ((fMinVersion ) & 0x0FF));
+
+ printf (", flags = %u\n", (unsigned) fFlags);
+
+ }
+
+ #else
+
+ (void) name;
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode::~dng_opcode ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode::PutData (dng_stream &stream) const
+ {
+
+ // No data by default
+
+ stream.Put_uint32 (0);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_opcode::AboutToApply (dng_host &host,
+ dng_negative &negative)
+ {
+
+ if (SkipIfPreview () && host.ForPreview ())
+ {
+
+ negative.SetIsPreview (true);
+
+ }
+
+ else if (MinVersion () > dngVersion_Current &&
+ WasReadFromStream ())
+ {
+
+ if (!Optional ())
+ {
+
+ // Somebody screwed up computing the DNGBackwardVersion...
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+ else if (!IsValidForNegative (negative))
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ else if (!IsNOP ())
+ {
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+dng_opcode_Unknown::dng_opcode_Unknown (dng_host &host,
+ uint32 opcodeID,
+ dng_stream &stream)
+
+ : dng_opcode (opcodeID,
+ stream,
+ NULL)
+
+ , fData ()
+
+ {
+
+ uint32 size = stream.Get_uint32 ();
+
+ if (size)
+ {
+
+ fData.Reset (host.Allocate (size));
+
+ stream.Get (fData->Buffer (),
+ fData->LogicalSize ());
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ DumpHexAscii (fData->Buffer_uint8 (),
+ fData->LogicalSize ());
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_Unknown::PutData (dng_stream &stream) const
+ {
+
+ if (fData.Get ())
+ {
+
+ stream.Put_uint32 (fData->LogicalSize ());
+
+ stream.Put (fData->Buffer (),
+ fData->LogicalSize ());
+
+ }
+
+ else
+ {
+
+ stream.Put_uint32 (0);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_opcode_Unknown::Apply (dng_host & /* host */,
+ dng_negative & /* negative */,
+ AutoPtr<dng_image> & /* image */)
+ {
+
+ // We should never need to apply an unknown opcode.
+
+ if (!Optional ())
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_filter_opcode_task: public dng_filter_task
+ {
+
+ private:
+
+ dng_filter_opcode &fOpcode;
+
+ dng_negative &fNegative;
+
+ public:
+
+ dng_filter_opcode_task (dng_filter_opcode &opcode,
+ dng_negative &negative,
+ const dng_image &srcImage,
+ dng_image &dstImage)
+
+ : dng_filter_task (srcImage,
+ dstImage)
+
+ , fOpcode (opcode)
+ , fNegative (negative)
+
+ {
+
+ fSrcPixelType = fOpcode.BufferPixelType (srcImage.PixelType ());
+
+ fDstPixelType = fSrcPixelType;
+
+ fSrcRepeat = opcode.SrcRepeat ();
+
+ }
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea)
+ {
+
+ return fOpcode.SrcArea (dstArea,
+ fDstImage.Bounds ());
+
+ }
+
+ virtual dng_point SrcTileSize (const dng_point &dstTileSize)
+ {
+
+ return fOpcode.SrcTileSize (dstTileSize,
+ fDstImage.Bounds ());
+
+ }
+
+ virtual void ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer)
+ {
+
+ fOpcode.ProcessArea (fNegative,
+ threadIndex,
+ srcBuffer,
+ dstBuffer,
+ dstBuffer.Area (),
+ fDstImage.Bounds ());
+
+ }
+
+ virtual void Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer)
+ {
+
+ dng_filter_task::Start (threadCount,
+ tileSize,
+ allocator,
+ sniffer);
+
+ fOpcode.Prepare (fNegative,
+ threadCount,
+ tileSize,
+ fDstImage.Bounds (),
+ fDstImage.Planes (),
+ fDstPixelType,
+ *allocator);
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+dng_filter_opcode::dng_filter_opcode (uint32 opcodeID,
+ uint32 minVersion,
+ uint32 flags)
+
+ : dng_opcode (opcodeID,
+ minVersion,
+ flags)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_filter_opcode::dng_filter_opcode (uint32 opcodeID,
+ dng_stream &stream,
+ const char *name)
+
+ : dng_opcode (opcodeID,
+ stream,
+ name)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_filter_opcode::Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image)
+ {
+
+ dng_rect modifiedBounds = ModifiedBounds (image->Bounds ());
+
+ if (modifiedBounds.NotEmpty ())
+ {
+
+ // Allocate destination image.
+
+ AutoPtr<dng_image> dstImage;
+
+ // If we are processing the entire image, allocate an
+ // undefined image.
+
+ if (modifiedBounds == image->Bounds ())
+ {
+
+ dstImage.Reset (host.Make_dng_image (image->Bounds (),
+ image->Planes (),
+ image->PixelType ()));
+
+ }
+
+ // Else start with a clone of the existing image.
+
+ else
+ {
+
+ dstImage.Reset (image->Clone ());
+
+ }
+
+ // Filter the image.
+
+ dng_filter_opcode_task task (*this,
+ negative,
+ *image,
+ *dstImage);
+
+ host.PerformAreaTask (task,
+ modifiedBounds);
+
+ // Return the new image.
+
+ image.Reset (dstImage.Release ());
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_inplace_opcode_task: public dng_area_task
+ {
+
+ private:
+
+ dng_inplace_opcode &fOpcode;
+
+ dng_negative &fNegative;
+
+ dng_image &fImage;
+
+ uint32 fPixelType;
+
+ AutoPtr<dng_memory_block> fBuffer [kMaxMPThreads];
+
+ public:
+
+ dng_inplace_opcode_task (dng_inplace_opcode &opcode,
+ dng_negative &negative,
+ dng_image &image)
+
+ : dng_area_task ()
+
+ , fOpcode (opcode)
+ , fNegative (negative)
+ , fImage (image)
+ , fPixelType (opcode.BufferPixelType (image.PixelType ()))
+
+ {
+
+ }
+
+ virtual void Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ uint32 pixelSize = TagTypeSize (fPixelType);
+
+ uint32 bufferSize = tileSize.v *
+ RoundUpForPixelSize (tileSize.h, pixelSize) *
+ pixelSize *
+ fImage.Planes ();
+
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
+ fBuffer [threadIndex] . Reset (allocator->Allocate (bufferSize));
+
+ }
+
+ fOpcode.Prepare (fNegative,
+ threadCount,
+ tileSize,
+ fImage.Bounds (),
+ fImage.Planes (),
+ fPixelType,
+ *allocator);
+
+ }
+
+ virtual void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ // Setup buffer.
+
+ dng_pixel_buffer buffer;
+
+ buffer.fArea = tile;
+
+ buffer.fPlane = 0;
+ buffer.fPlanes = fImage.Planes ();
+
+ buffer.fPixelType = fPixelType;
+ buffer.fPixelSize = TagTypeSize (fPixelType);
+
+ buffer.fPlaneStep = RoundUpForPixelSize (tile.W (),
+ buffer.fPixelSize);
+
+ buffer.fRowStep = buffer.fPlaneStep *
+ buffer.fPlanes;
+
+ buffer.fData = fBuffer [threadIndex]->Buffer ();
+
+ // Get source pixels.
+
+ fImage.Get (buffer);
+
+ // Process area.
+
+ fOpcode.ProcessArea (fNegative,
+ threadIndex,
+ buffer,
+ tile,
+ fImage.Bounds ());
+
+ // Save result pixels.
+
+ fImage.Put (buffer);
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+dng_inplace_opcode::dng_inplace_opcode (uint32 opcodeID,
+ uint32 minVersion,
+ uint32 flags)
+
+ : dng_opcode (opcodeID,
+ minVersion,
+ flags)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_inplace_opcode::dng_inplace_opcode (uint32 opcodeID,
+ dng_stream &stream,
+ const char *name)
+
+ : dng_opcode (opcodeID,
+ stream,
+ name)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_inplace_opcode::Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image)
+ {
+
+ dng_rect modifiedBounds = ModifiedBounds (image->Bounds ());
+
+ if (modifiedBounds.NotEmpty ())
+ {
+
+ dng_inplace_opcode_task task (*this,
+ negative,
+ *image);
+
+ host.PerformAreaTask (task,
+ modifiedBounds);
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_opcodes.h b/gpr/source/lib/dng_sdk/dng_opcodes.h
new file mode 100644
index 0000000..b214540
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_opcodes.h
@@ -0,0 +1,507 @@
+/*****************************************************************************/
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_opcodes.h#2 $ */
+/* $DateTime: 2012/08/02 06:09:06 $ */
+/* $Change: 841096 $ */
+/* $Author: erichan $ */
+
+/** \file
+ * Base class and common data structures for opcodes (introduced in DNG 1.3).
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_opcodes__
+#define __dng_opcodes__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_rect.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// \brief List of supported opcodes (by ID).
+
+enum dng_opcode_id
+ {
+
+ // Internal use only opcode. Never written to DNGs.
+
+ dngOpcode_Private = 0,
+
+ // Warp image to correct distortion and lateral chromatic aberration for
+ // rectilinear lenses.
+
+ dngOpcode_WarpRectilinear = 1,
+
+ // Warp image to correction distortion for fisheye lenses (i.e., map the
+ // fisheye projection to a perspective projection).
+
+ dngOpcode_WarpFisheye = 2,
+
+ // Radial vignette correction.
+
+ dngOpcode_FixVignetteRadial = 3,
+
+ // Patch bad Bayer pixels which are marked with a special value in the image.
+
+ dngOpcode_FixBadPixelsConstant = 4,
+
+ // Patch bad Bayer pixels/rectangles at a list of specified coordinates.
+
+ dngOpcode_FixBadPixelsList = 5,
+
+ // Trim image to specified bounds.
+
+ dngOpcode_TrimBounds = 6,
+
+ // Map an area through a 16-bit LUT.
+
+ dngOpcode_MapTable = 7,
+
+ // Map an area using a polynomial function.
+
+ dngOpcode_MapPolynomial = 8,
+
+ // Apply a gain map to an area.
+
+ dngOpcode_GainMap = 9,
+
+ // Apply a per-row delta to an area.
+
+ dngOpcode_DeltaPerRow = 10,
+
+ // Apply a per-column delta to an area.
+
+ dngOpcode_DeltaPerColumn = 11,
+
+ // Apply a per-row scale to an area.
+
+ dngOpcode_ScalePerRow = 12,
+
+ // Apply a per-column scale to an area.
+
+ dngOpcode_ScalePerColumn = 13
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Virtual base class for opcode.
+
+class dng_opcode
+ {
+
+ public:
+
+ /// Opcode flags.
+
+ enum
+ {
+ kFlag_None = 0, //!< No flag.
+ kFlag_Optional = 1, //!< This opcode is optional.
+ kFlag_SkipIfPreview = 2 //!< May skip opcode for preview images.
+ };
+
+ private:
+
+ uint32 fOpcodeID;
+
+ uint32 fMinVersion;
+
+ uint32 fFlags;
+
+ bool fWasReadFromStream;
+
+ uint32 fStage;
+
+ protected:
+
+ dng_opcode (uint32 opcodeID,
+ uint32 minVersion,
+ uint32 flags);
+
+ dng_opcode (uint32 opcodeID,
+ dng_stream &stream,
+ const char *name);
+
+ public:
+
+ virtual ~dng_opcode ();
+
+ /// The ID of this opcode.
+
+ uint32 OpcodeID () const
+ {
+ return fOpcodeID;
+ }
+
+ /// The first DNG version that supports this opcode.
+
+ uint32 MinVersion () const
+ {
+ return fMinVersion;
+ }
+
+ /// The flags for this opcode.
+
+ uint32 Flags () const
+ {
+ return fFlags;
+ }
+
+ /// Is this opcode optional?
+
+ bool Optional () const
+ {
+ return (Flags () & kFlag_Optional) != 0;
+ }
+
+ /// Should the opcode be skipped when rendering preview images?
+
+ bool SkipIfPreview () const
+ {
+ return (Flags () & kFlag_SkipIfPreview) != 0;
+ }
+
+ /// Was this opcode read from a data stream?
+
+ bool WasReadFromStream () const
+ {
+ return fWasReadFromStream;
+ }
+
+ /// Which image processing stage (1, 2, 3) is associated with this
+ /// opcode?
+
+ uint32 Stage () const
+ {
+ return fStage;
+ }
+
+ /// Set the image processing stage (1, 2, 3) for this opcode. Stage 1 is
+ /// the original image data, including masked areas. Stage 2 is
+ /// linearized image data and trimmed to the active area. Stage 3 is
+ /// demosaiced and trimmed to the active area.
+
+ void SetStage (uint32 stage)
+ {
+ fStage = stage;
+ }
+
+ /// Is the opcode a NOP (i.e., does nothing)? An opcode could be a NOP
+ /// for some specific parameters.
+
+ virtual bool IsNOP () const
+ {
+ return false;
+ }
+
+ /// Is this opcode valid for the specified negative?
+
+ virtual bool IsValidForNegative (const dng_negative & /* negative */) const
+ {
+ return true;
+ }
+
+ /// Write opcode to a stream.
+ /// \param stream The stream to which to write the opcode data.
+
+ virtual void PutData (dng_stream &stream) const;
+
+ /// Perform error checking prior to applying this opcode to the
+ /// specified negative. Returns true if this opcode should be applied to
+ /// the negative, false otherwise.
+
+ bool AboutToApply (dng_host &host,
+ dng_negative &negative);
+
+ /// Apply this opcode to the specified image with associated negative.
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image) = 0;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to represent unknown opcodes (e.g, opcodes defined in future
+/// DNG versions).
+
+class dng_opcode_Unknown: public dng_opcode
+ {
+
+ private:
+
+ AutoPtr<dng_memory_block> fData;
+
+ public:
+
+ dng_opcode_Unknown (dng_host &host,
+ uint32 opcodeID,
+ dng_stream &stream);
+
+ virtual void PutData (dng_stream &stream) const;
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to represent a filter opcode, such as a convolution.
+
+class dng_filter_opcode: public dng_opcode
+ {
+
+ protected:
+
+ dng_filter_opcode (uint32 opcodeID,
+ uint32 minVersion,
+ uint32 flags);
+
+ dng_filter_opcode (uint32 opcodeID,
+ dng_stream &stream,
+ const char *name);
+
+ public:
+
+ /// The pixel data type of this opcode.
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType)
+ {
+ return imagePixelType;
+ }
+
+ /// The adjusted bounds (processing area) of this opcode. It is limited to
+ /// the intersection of the specified image area and the GainMap area.
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds)
+ {
+ return imageBounds;
+ }
+
+ /// Returns the width and height (in pixels) of the repeating mosaic pattern.
+
+ virtual dng_point SrcRepeat ()
+ {
+ return dng_point (1, 1);
+ }
+
+ /// Returns the source pixel area needed to process a destination pixel area
+ /// that lies within the specified bounds.
+ /// \param dstArea The destination pixel area to be computed.
+ /// \param imageBounds The overall image area (dstArea will lie within these
+ /// bounds).
+ /// \retval The source pixel area needed to process the specified dstArea.
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea,
+ const dng_rect & /* imageBounds */)
+ {
+ return dstArea;
+ }
+
+ /// Given a destination tile size, calculate input tile size. Simlar to
+ /// SrcArea, and should seldom be overridden.
+ ///
+ /// \param dstTileSize The destination tile size that is targeted for output.
+ ///
+ /// \param imageBounds The image bounds (the destination tile will
+ /// always lie within these bounds).
+ ///
+ /// \retval The source tile size needed to compute a tile of the destination
+ /// size.
+
+ virtual dng_point SrcTileSize (const dng_point &dstTileSize,
+ const dng_rect &imageBounds)
+ {
+ return SrcArea (dng_rect (dstTileSize),
+ imageBounds).Size ();
+ }
+
+ /// Startup method called before any processing is performed on pixel areas.
+ /// It can be used to allocate (per-thread) memory and setup tasks.
+ ///
+ /// \param negative The negative object to be processed.
+ ///
+ /// \param threadCount The number of threads to be used to perform the
+ /// processing.
+ ///
+ /// \param threadCount Total number of threads that will be used for
+ /// processing. Less than or equal to MaxThreads.
+ ///
+ /// \param tileSize Size of source tiles which will be processed. (Not all
+ /// tiles will be this size due to edge conditions.)
+ ///
+ /// \param imageBounds Total size of image to be processed.
+ ///
+ /// \param imagePlanes Number of planes in the image. Less than or equal to
+ /// kMaxColorPlanes.
+ ///
+ /// \param bufferPixelType Pixel type of image buffer (see dng_tag_types.h).
+ ///
+ /// \param allocator dng_memory_allocator to use for allocating temporary
+ /// buffers, etc.
+
+ virtual void Prepare (dng_negative & /* negative */,
+ uint32 /* threadCount */,
+ const dng_point & /* tileSize */,
+ const dng_rect & /* imageBounds */,
+ uint32 /* imagePlanes */,
+ uint32 /* bufferPixelType */,
+ dng_memory_allocator & /* allocator */)
+ {
+ }
+
+ /// Implements filtering operation from one buffer to another. Source
+ /// and destination pixels are set up in member fields of this class.
+ /// Ideally, no allocation should be done in this routine.
+ ///
+ /// \param negative The negative associated with the pixels to be
+ /// processed.
+ ///
+ /// \param threadIndex The thread on which this routine is being called,
+ /// between 0 and threadCount - 1 for the threadCount passed to Prepare
+ /// method.
+ ///
+ /// \param srcBuffer Input area and source pixels.
+ ///
+ /// \param dstBuffer Destination pixels.
+ ///
+ /// \param dstArea Destination pixel processing area.
+ ///
+ /// \param imageBounds Total image area to be processed; dstArea will
+ /// always lie within these bounds.
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds) = 0;
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class to represent an in-place (i.e., pointwise, per-pixel) opcode,
+/// such as a global tone curve.
+
+class dng_inplace_opcode: public dng_opcode
+ {
+
+ protected:
+
+ dng_inplace_opcode (uint32 opcodeID,
+ uint32 minVersion,
+ uint32 flags);
+
+ dng_inplace_opcode (uint32 opcodeID,
+ dng_stream &stream,
+ const char *name);
+
+ public:
+
+ /// The pixel data type of this opcode.
+
+ virtual uint32 BufferPixelType (uint32 imagePixelType)
+ {
+ return imagePixelType;
+ }
+
+ /// The adjusted bounds (processing area) of this opcode. It is limited to
+ /// the intersection of the specified image area and the GainMap area.
+
+ virtual dng_rect ModifiedBounds (const dng_rect &imageBounds)
+ {
+ return imageBounds;
+ }
+
+ /// Startup method called before any processing is performed on pixel areas.
+ /// It can be used to allocate (per-thread) memory and setup tasks.
+ ///
+ /// \param negative The negative object to be processed.
+ ///
+ /// \param threadCount The number of threads to be used to perform the
+ /// processing.
+ ///
+ /// \param threadCount Total number of threads that will be used for
+ /// processing. Less than or equal to MaxThreads.
+ ///
+ /// \param tileSize Size of source tiles which will be processed. (Not all
+ /// tiles will be this size due to edge conditions.)
+ ///
+ /// \param imageBounds Total size of image to be processed.
+ ///
+ /// \param imagePlanes Number of planes in the image. Less than or equal to
+ /// kMaxColorPlanes.
+ ///
+ /// \param bufferPixelType Pixel type of image buffer (see dng_tag_types.h).
+ ///
+ /// \param allocator dng_memory_allocator to use for allocating temporary
+ /// buffers, etc.
+
+ virtual void Prepare (dng_negative & /* negative */,
+ uint32 /* threadCount */,
+ const dng_point & /* tileSize */,
+ const dng_rect & /* imageBounds */,
+ uint32 /* imagePlanes */,
+ uint32 /* bufferPixelType */,
+ dng_memory_allocator & /* allocator */)
+ {
+ }
+
+ /// Implements image processing operation in a single buffer. The source
+ /// pixels are provided as input to the buffer, and this routine
+ /// calculates and writes the destination pixels to the same buffer.
+ /// Ideally, no allocation should be done in this routine.
+ ///
+ /// \param negative The negative associated with the pixels to be
+ /// processed.
+ ///
+ /// \param threadIndex The thread on which this routine is being called,
+ /// between 0 and threadCount - 1 for the threadCount passed to Prepare
+ /// method.
+ ///
+ /// \param srcBuffer Input area and source pixels.
+ ///
+ /// \param dstBuffer Destination pixels.
+ ///
+ /// \param dstArea Destination pixel processing area.
+ ///
+ /// \param imageBounds Total image area to be processed; dstArea will
+ /// always lie within these bounds.
+
+ virtual void ProcessArea (dng_negative &negative,
+ uint32 threadIndex,
+ dng_pixel_buffer &buffer,
+ const dng_rect &dstArea,
+ const dng_rect &imageBounds) = 0;
+
+ virtual void Apply (dng_host &host,
+ dng_negative &negative,
+ AutoPtr<dng_image> &image);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_orientation.cpp b/gpr/source/lib/dng_sdk/dng_orientation.cpp
new file mode 100644
index 0000000..820ca34
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_orientation.cpp
@@ -0,0 +1,233 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_orientation.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+#include "dng_orientation.h"
+
+/*****************************************************************************/
+
+void dng_orientation::SetTIFF (uint32 tiff)
+ {
+
+ switch (tiff)
+ {
+
+ case 1:
+ {
+ fAdobeOrientation = kNormal;
+ break;
+ }
+
+ case 2:
+ {
+ fAdobeOrientation = kMirror;
+ break;
+ }
+
+ case 3:
+ {
+ fAdobeOrientation = kRotate180;
+ break;
+ }
+
+ case 4:
+ {
+ fAdobeOrientation = kMirror180;
+ break;
+ }
+
+ case 5:
+ {
+ fAdobeOrientation = kMirror90CCW;
+ break;
+ }
+
+ case 6:
+ {
+ fAdobeOrientation = kRotate90CW;
+ break;
+ }
+
+ case 7:
+ {
+ fAdobeOrientation = kMirror90CW;
+ break;
+ }
+
+ case 8:
+ {
+ fAdobeOrientation = kRotate90CCW;
+ break;
+ }
+
+ case 9:
+ {
+ fAdobeOrientation = kUnknown;
+ break;
+ }
+
+ default:
+ {
+ fAdobeOrientation = kNormal;
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_orientation::GetTIFF () const
+ {
+
+ switch (fAdobeOrientation)
+ {
+
+ case kNormal:
+ {
+ return 1;
+ }
+
+ case kMirror:
+ {
+ return 2;
+ }
+
+ case kRotate180:
+ {
+ return 3;
+ }
+
+ case kMirror180:
+ {
+ return 4;
+ }
+
+ case kMirror90CCW:
+ {
+ return 5;
+ }
+
+ case kRotate90CW:
+ {
+ return 6;
+ }
+
+ case kMirror90CW:
+ {
+ return 7;
+ }
+
+ case kRotate90CCW:
+ {
+ return 8;
+ }
+
+ case kUnknown:
+ {
+ return 9;
+ }
+
+ default:
+ break;
+
+ }
+
+ return 1;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_orientation::FlipD () const
+ {
+
+ return (fAdobeOrientation & 1) != 0;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_orientation::FlipH () const
+ {
+
+ if (fAdobeOrientation & 4)
+ return (fAdobeOrientation & 2) == 0;
+
+ else
+ return (fAdobeOrientation & 2) != 0;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_orientation::FlipV () const
+ {
+
+ if (fAdobeOrientation & 4)
+ return FlipD () == FlipH ();
+
+ else
+ return FlipD () != FlipH ();
+
+ }
+
+/*****************************************************************************/
+
+dng_orientation dng_orientation::operator- () const
+ {
+
+ uint32 x = GetAdobe ();
+
+ if ((x & 5) == 5)
+ {
+
+ x ^= 2;
+
+ }
+
+ dng_orientation result;
+
+ result.SetAdobe (((4 - x) & 3) | (x & 4));
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_orientation dng_orientation::operator+ (const dng_orientation &b) const
+ {
+
+ uint32 x = GetAdobe ();
+
+ uint32 y = b.GetAdobe ();
+
+ if (y & 4)
+ {
+
+ if (x & 1)
+ x ^= 6;
+ else
+ x ^= 4;
+
+ }
+
+ dng_orientation result;
+
+ result.SetAdobe (((x + y) & 3) | (x & 4));
+
+ return result;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_orientation.h b/gpr/source/lib/dng_sdk/dng_orientation.h
new file mode 100644
index 0000000..cb23adf
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_orientation.h
@@ -0,0 +1,189 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_orientation.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/******************************************************************************/
+
+#ifndef __dng_orientation__
+#define __dng_orientation__
+
+/******************************************************************************/
+
+#include "dng_types.h"
+
+/******************************************************************************/
+
+class dng_orientation
+ {
+
+ private:
+
+ // We internally use an orientation encoding ("Adobe") that is
+ // different than the TIFF orientation encoding ("TIFF").
+
+ uint32 fAdobeOrientation;
+
+ public:
+ enum
+ {
+ kNormal = 0,
+ kRotate90CW = 1,
+ kRotate180 = 2,
+ kRotate90CCW = 3,
+ kMirror = 4,
+ kMirror90CW = 5,
+ kMirror180 = 6,
+ kMirror90CCW = 7,
+ kUnknown = 8
+ };
+
+
+ dng_orientation ()
+
+ : fAdobeOrientation (kNormal)
+
+ {
+ }
+
+ void SetAdobe (uint32 adobe)
+ {
+ fAdobeOrientation = adobe;
+ }
+
+ uint32 GetAdobe () const
+ {
+ return fAdobeOrientation;
+ }
+
+ void SetTIFF (uint32 tiff);
+
+ uint32 GetTIFF () const;
+
+ static dng_orientation AdobeToDNG (uint32 adobe)
+ {
+
+ dng_orientation result;
+
+ result.SetAdobe (adobe);
+
+ return result;
+
+ }
+
+ static dng_orientation TIFFtoDNG (uint32 tiff)
+ {
+
+ dng_orientation result;
+
+ result.SetTIFF (tiff);
+
+ return result;
+
+ }
+
+ static dng_orientation Normal ()
+ {
+ return AdobeToDNG (kNormal);
+ }
+
+ static dng_orientation Rotate90CW ()
+ {
+ return AdobeToDNG (kRotate90CW);
+ }
+
+ static dng_orientation Rotate180 ()
+ {
+ return AdobeToDNG (kRotate180);
+ }
+
+ static dng_orientation Rotate90CCW ()
+ {
+ return AdobeToDNG (kRotate90CCW);
+ }
+
+ static dng_orientation Mirror ()
+ {
+ return AdobeToDNG (kMirror);
+ }
+
+ static dng_orientation Mirror90CW ()
+ {
+ return AdobeToDNG (kMirror90CW);
+ }
+
+ static dng_orientation Mirror180 ()
+ {
+ return AdobeToDNG (kMirror180);
+ }
+
+ static dng_orientation Mirror90CCW ()
+ {
+ return AdobeToDNG (kMirror90CCW);
+ }
+
+ static dng_orientation Unknown ()
+ {
+ return AdobeToDNG (kUnknown);
+ }
+
+ bool IsValid () const
+ {
+ return fAdobeOrientation < kUnknown;
+ }
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ bool FlipD () const;
+
+ bool FlipH () const;
+
+ bool FlipV () const;
+
+ bool operator== (const dng_orientation &b) const
+ {
+ return fAdobeOrientation == b.fAdobeOrientation;
+ }
+
+ bool operator!= (const dng_orientation &b) const
+ {
+ return !(*this == b);
+ }
+
+ dng_orientation operator- () const;
+
+ dng_orientation operator+ (const dng_orientation &b) const;
+
+ dng_orientation operator- (const dng_orientation &b) const
+ {
+ return (*this) + (-b);
+ }
+
+ void operator+= (const dng_orientation &b)
+ {
+ *this = *this + b;
+ }
+
+ void operator-= (const dng_orientation &b)
+ {
+ *this = *this - b;
+ }
+
+ };
+
+/******************************************************************************/
+
+#endif
+
+/******************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_parse_utils.cpp b/gpr/source/lib/dng_sdk/dng_parse_utils.cpp
new file mode 100644
index 0000000..879efbc
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_parse_utils.cpp
@@ -0,0 +1,3326 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_parse_utils.cpp#3 $ */
+/* $DateTime: 2012/06/06 12:08:58 $ */
+/* $Change: 833617 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_parse_utils.h"
+
+#include "dng_date_time.h"
+#include "dng_globals.h"
+#include "dng_ifd.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_types.h"
+#include "dng_stream.h"
+#include "dng_exceptions.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+#if qDNGValidate
+
+/*****************************************************************************/
+
+struct dng_name_table
+ {
+ uint32 key;
+ const char *name;
+ };
+
+/*****************************************************************************/
+
+static const char * LookupName (uint32 key,
+ const dng_name_table *table,
+ uint32 table_entries)
+ {
+
+ for (uint32 index = 0; index < table_entries; index++)
+ {
+
+ if (key == table [index] . key)
+ {
+
+ return table [index] . name;
+
+ }
+
+ }
+
+ return NULL;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupParentCode (uint32 parentCode)
+ {
+
+ const dng_name_table kParentCodeNames [] =
+ {
+ { 0, "IFD 0" },
+ { tcExifIFD, "Exif IFD" },
+ { tcGPSInfo, "GPS IFD" },
+ { tcInteroperabilityIFD, "Interoperability IFD" },
+ { tcKodakDCRPrivateIFD, "Kodak DCR Private IFD" },
+ { tcKodakKDCPrivateIFD, "Kodak KDC Private IFD" },
+ { tcCanonMakerNote, "Canon MakerNote" },
+ { tcEpsonMakerNote, "Epson MakerNote" },
+ { tcFujiMakerNote, "Fuji MakerNote" },
+ { tcHasselbladMakerNote, "Hasselblad MakerNote" },
+ { tcKodakMakerNote, "Kodak MakerNote" },
+ { tcKodakMakerNote65280, "Kodak MakerNote 65280" },
+ { tcLeicaMakerNote, "Leica MakerNote" },
+ { tcMamiyaMakerNote, "Mamiya MakerNote" },
+ { tcMinoltaMakerNote, "Minolta MakerNote" },
+ { tcNikonMakerNote, "Nikon MakerNote" },
+ { tcOlympusMakerNote, "Olympus MakerNote" },
+ { tcOlympusMakerNote8208, "Olympus MakerNote 8208" },
+ { tcOlympusMakerNote8224, "Olympus MakerNote 8224" },
+ { tcOlympusMakerNote8240, "Olympus MakerNote 8240" },
+ { tcOlympusMakerNote8256, "Olympus MakerNote 8256" },
+ { tcOlympusMakerNote8272, "Olympus MakerNote 8272" },
+ { tcOlympusMakerNote12288, "Olympus MakerNote 12288" },
+ { tcPanasonicMakerNote, "Panasonic MakerNote" },
+ { tcPentaxMakerNote, "Pentax MakerNote" },
+ { tcPhaseOneMakerNote, "Phase One MakerNote" },
+ { tcRicohMakerNote, "Ricoh MakerNote" },
+ { tcRicohMakerNoteCameraInfo, "Ricoh MakerNote Camera Info" },
+ { tcSonyMakerNote, "Sony MakerNote" },
+ { tcSonyMakerNoteSubInfo, "Sony MakerNote SubInfo" },
+ { tcSonyPrivateIFD1, "Sony Private IFD 1" },
+ { tcSonyPrivateIFD2, "Sony Private IFD 2" },
+ { tcSonyPrivateIFD3A, "Sony Private IFD 3A" },
+ { tcSonyPrivateIFD3B, "Sony Private IFD 3B" },
+ { tcSonyPrivateIFD3C, "Sony Private IFD 3C" },
+ { tcCanonCRW, "Canon CRW" },
+ { tcContaxRAW, "Contax RAW" },
+ { tcFujiRAF, "Fuji RAF" },
+ { tcLeafMOS, "Leaf MOS" },
+ { tcMinoltaMRW, "Minolta MRW" },
+ { tcPanasonicRAW, "Panasonic RAW" },
+ { tcFoveonX3F, "Foveon X3F" },
+ { tcJPEG, "JPEG" },
+ { tcAdobePSD, "Adobe PSD" }
+ };
+
+ const char *name = LookupName (parentCode,
+ kParentCodeNames,
+ sizeof (kParentCodeNames ) /
+ sizeof (kParentCodeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ if (parentCode >= tcFirstSubIFD &&
+ parentCode <= tcLastSubIFD)
+ {
+
+ sprintf (s, "SubIFD %u", (unsigned) (parentCode - tcFirstSubIFD + 1));
+
+ }
+
+ else if (parentCode >= tcFirstChainedIFD &&
+ parentCode <= tcLastChainedIFD)
+ {
+
+ sprintf (s, "Chained IFD %u", (unsigned) (parentCode - tcFirstChainedIFD + 1));
+
+ }
+
+ else
+ {
+
+ sprintf (s, "ParentIFD %u", (unsigned) parentCode);
+
+ }
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupTagCode (uint32 parentCode,
+ uint32 tagCode)
+ {
+
+ const dng_name_table kTagNames [] =
+ {
+ { tcNewSubFileType, "NewSubFileType" },
+ { tcSubFileType, "SubFileType" },
+ { tcImageWidth, "ImageWidth" },
+ { tcImageLength, "ImageLength" },
+ { tcBitsPerSample, "BitsPerSample" },
+ { tcCompression, "Compression" },
+ { tcPhotometricInterpretation, "PhotometricInterpretation" },
+ { tcThresholding, "Thresholding" },
+ { tcCellWidth, "CellWidth" },
+ { tcCellLength, "CellLength" },
+ { tcFillOrder, "FillOrder" },
+ { tcImageDescription, "ImageDescription" },
+ { tcMake, "Make" },
+ { tcModel, "Model" },
+ { tcStripOffsets, "StripOffsets" },
+ { tcOrientation, "Orientation" },
+ { tcSamplesPerPixel, "SamplesPerPixel" },
+ { tcRowsPerStrip, "RowsPerStrip" },
+ { tcStripByteCounts, "StripByteCounts" },
+ { tcMinSampleValue, "MinSampleValue" },
+ { tcMaxSampleValue, "MaxSampleValue" },
+ { tcXResolution, "XResolution" },
+ { tcYResolution, "YResolution" },
+ { tcPlanarConfiguration, "PlanarConfiguration" },
+ { tcFreeOffsets, "FreeOffsets" },
+ { tcFreeByteCounts, "FreeByteCounts" },
+ { tcGrayResponseUnit, "GrayResponseUnit" },
+ { tcGrayResponseCurve, "GrayResponseCurve" },
+ { tcResolutionUnit, "ResolutionUnit" },
+ { tcTransferFunction, "TransferFunction" },
+ { tcSoftware, "Software" },
+ { tcDateTime, "DateTime" },
+ { tcArtist, "Artist" },
+ { tcHostComputer, "HostComputer" },
+ { tcWhitePoint, "WhitePoint" },
+ { tcPrimaryChromaticities, "PrimaryChromaticities" },
+ { tcColorMap, "ColorMap" },
+ { tcTileWidth, "TileWidth" },
+ { tcTileLength, "TileLength" },
+ { tcTileOffsets, "TileOffsets" },
+ { tcTileByteCounts, "TileByteCounts" },
+ { tcSubIFDs, "SubIFDs" },
+ { tcExtraSamples, "ExtraSamples" },
+ { tcSampleFormat, "SampleFormat" },
+ { tcJPEGTables, "JPEGTables" },
+ { tcJPEGProc, "JPEGProc" },
+ { tcJPEGInterchangeFormat, "JPEGInterchangeFormat" },
+ { tcJPEGInterchangeFormatLength, "JPEGInterchangeFormatLength" },
+ { tcYCbCrCoefficients, "YCbCrCoefficients" },
+ { tcYCbCrSubSampling, "YCbCrSubSampling" },
+ { tcYCbCrPositioning, "YCbCrPositioning" },
+ { tcReferenceBlackWhite, "ReferenceBlackWhite" },
+ { tcXMP, "XMP" },
+ { tcKodakCameraSerialNumber, "KodakCameraSerialNumber" },
+ { tcCFARepeatPatternDim, "CFARepeatPatternDim" },
+ { tcCFAPattern, "CFAPattern" },
+ { tcBatteryLevel, "BatteryLevel" },
+ { tcKodakDCRPrivateIFD, "KodakDCRPrivateIFD" },
+ { tcCopyright, "Copyright" },
+ { tcExposureTime, "ExposureTime" },
+ { tcFNumber, "FNumber" },
+ { tcIPTC_NAA, "IPTC/NAA" },
+ { tcLeafPKTS, "LeafPKTS" },
+ { tcAdobeData, "AdobeData" },
+ { tcExifIFD, "ExifIFD" },
+ { tcICCProfile, "ICCProfile" },
+ { tcExposureProgram, "ExposureProgram" },
+ { tcSpectralSensitivity, "SpectralSensitivity" },
+ { tcGPSInfo, "GPSInfo" },
+ { tcISOSpeedRatings, "ISOSpeedRatings" },
+ { tcOECF, "OECF" },
+ { tcInterlace, "Interlace" },
+ { tcTimeZoneOffset, "TimeZoneOffset" },
+ { tcSelfTimerMode, "SelfTimerMode" },
+ { tcSensitivityType, "SensitivityType" },
+ { tcStandardOutputSensitivity, "StandardOutputSensitivity" },
+ { tcRecommendedExposureIndex, "RecommendedExposureIndex" },
+ { tcISOSpeed, "ISOSpeed" },
+ { tcISOSpeedLatitudeyyy, "ISOSpeedLatitudeyyy" },
+ { tcISOSpeedLatitudezzz, "ISOSpeedLatitudezzz" },
+ { tcExifVersion, "ExifVersion" },
+ { tcDateTimeOriginal, "DateTimeOriginal" },
+ { tcDateTimeDigitized, "DateTimeDigitized" },
+ { tcComponentsConfiguration, "ComponentsConfiguration" },
+ { tcCompressedBitsPerPixel, "CompressedBitsPerPixel" },
+ { tcShutterSpeedValue, "ShutterSpeedValue" },
+ { tcApertureValue, "ApertureValue" },
+ { tcBrightnessValue, "BrightnessValue" },
+ { tcExposureBiasValue, "ExposureBiasValue" },
+ { tcMaxApertureValue, "MaxApertureValue" },
+ { tcSubjectDistance, "SubjectDistance" },
+ { tcMeteringMode, "MeteringMode" },
+ { tcLightSource, "LightSource" },
+ { tcFlash, "Flash" },
+ { tcFocalLength, "FocalLength" },
+ { tcFlashEnergy, "FlashEnergy" },
+ { tcSpatialFrequencyResponse, "SpatialFrequencyResponse" },
+ { tcNoise, "Noise" },
+ { tcFocalPlaneXResolution, "FocalPlaneXResolution" },
+ { tcFocalPlaneYResolution, "FocalPlaneYResolution" },
+ { tcFocalPlaneResolutionUnit, "FocalPlaneResolutionUnit" },
+ { tcImageNumber, "ImageNumber" },
+ { tcSecurityClassification, "SecurityClassification" },
+ { tcImageHistory, "ImageHistory" },
+ { tcSubjectArea, "SubjectArea" },
+ { tcExposureIndex, "ExposureIndex" },
+ { tcTIFF_EP_StandardID, "TIFF/EPStandardID" },
+ { tcSensingMethod, "SensingMethod" },
+ { tcMakerNote, "MakerNote" },
+ { tcUserComment, "UserComment" },
+ { tcSubsecTime, "SubsecTime" },
+ { tcSubsecTimeOriginal, "SubsecTimeOriginal" },
+ { tcSubsecTimeDigitized, "SubsecTimeDigitized" },
+ { tcAdobeLayerData, "AdobeLayerData" },
+ { tcFlashPixVersion, "FlashPixVersion" },
+ { tcColorSpace, "ColorSpace" },
+ { tcPixelXDimension, "PixelXDimension" },
+ { tcPixelYDimension, "PixelYDimension" },
+ { tcRelatedSoundFile, "RelatedSoundFile" },
+ { tcInteroperabilityIFD, "InteroperabilityIFD" },
+ { tcFlashEnergyExif, "FlashEnergyExif" },
+ { tcSpatialFrequencyResponseExif, "SpatialFrequencyResponseExif" },
+ { tcFocalPlaneXResolutionExif, "FocalPlaneXResolutionExif" },
+ { tcFocalPlaneYResolutionExif, "FocalPlaneYResolutionExif" },
+ { tcFocalPlaneResolutionUnitExif, "FocalPlaneResolutionUnitExif" },
+ { tcSubjectLocation, "SubjectLocation" },
+ { tcExposureIndexExif, "ExposureIndexExif" },
+ { tcSensingMethodExif, "SensingMethodExif" },
+ { tcFileSource, "FileSource" },
+ { tcSceneType, "SceneType" },
+ { tcCFAPatternExif, "CFAPatternExif" },
+ { tcCustomRendered, "CustomRendered" },
+ { tcExposureMode, "ExposureMode" },
+ { tcWhiteBalance, "WhiteBalance" },
+ { tcDigitalZoomRatio, "DigitalZoomRatio" },
+ { tcFocalLengthIn35mmFilm, "FocalLengthIn35mmFilm" },
+ { tcSceneCaptureType, "SceneCaptureType" },
+ { tcGainControl, "GainControl" },
+ { tcContrast, "Contrast" },
+ { tcSaturation, "Saturation" },
+ { tcSharpness, "Sharpness" },
+ { tcDeviceSettingDescription, "DeviceSettingDescription" },
+ { tcSubjectDistanceRange, "SubjectDistanceRange" },
+ { tcImageUniqueID, "ImageUniqueID" },
+ { tcCameraOwnerNameExif, "CameraOwnerNameExif" },
+ { tcCameraSerialNumberExif, "CameraSerialNumberExif" },
+ { tcLensSpecificationExif, "LensSpecificationExif" },
+ { tcLensMakeExif, "LensMakeExif" },
+ { tcLensModelExif, "LensModelExif" },
+ { tcLensSerialNumberExif, "LensSerialNumberExif" },
+ { tcGamma, "Gamma" },
+ { tcPrintImageMatchingInfo, "PrintImageMatchingInfo" },
+ { tcDNGVersion, "DNGVersion" },
+ { tcDNGBackwardVersion, "DNGBackwardVersion" },
+ { tcUniqueCameraModel, "UniqueCameraModel" },
+ { tcLocalizedCameraModel, "LocalizedCameraModel" },
+ { tcCFAPlaneColor, "CFAPlaneColor" },
+ { tcCFALayout, "CFALayout" },
+ { tcLinearizationTable, "LinearizationTable" },
+ { tcBlackLevelRepeatDim, "BlackLevelRepeatDim" },
+ { tcBlackLevel, "BlackLevel" },
+ { tcBlackLevelDeltaH, "BlackLevelDeltaH" },
+ { tcBlackLevelDeltaV, "BlackLevelDeltaV" },
+ { tcWhiteLevel, "WhiteLevel" },
+ { tcDefaultScale, "DefaultScale" },
+ { tcDefaultCropOrigin, "DefaultCropOrigin" },
+ { tcDefaultCropSize, "DefaultCropSize" },
+ { tcDefaultUserCrop, "DefaultUserCrop" },
+ { tcColorMatrix1, "ColorMatrix1" },
+ { tcColorMatrix2, "ColorMatrix2" },
+ { tcCameraCalibration1, "CameraCalibration1" },
+ { tcCameraCalibration2, "CameraCalibration2" },
+ { tcReductionMatrix1, "ReductionMatrix1" },
+ { tcReductionMatrix2, "ReductionMatrix2" },
+ { tcAnalogBalance, "AnalogBalance" },
+ { tcAsShotNeutral, "AsShotNeutral" },
+ { tcAsShotWhiteXY, "AsShotWhiteXY" },
+ { tcBaselineExposure, "BaselineExposure" },
+ { tcBaselineNoise, "BaselineNoise" },
+ { tcBaselineSharpness, "BaselineSharpness" },
+ { tcBayerGreenSplit, "BayerGreenSplit" },
+ { tcLinearResponseLimit, "LinearResponseLimit" },
+ { tcCameraSerialNumber, "CameraSerialNumber" },
+ { tcLensInfo, "LensInfo" },
+ { tcChromaBlurRadius, "ChromaBlurRadius" },
+ { tcAntiAliasStrength, "AntiAliasStrength" },
+ { tcShadowScale, "ShadowScale" },
+ { tcDNGPrivateData, "DNGPrivateData" },
+ { tcMakerNoteSafety, "MakerNoteSafety" },
+ { tcCalibrationIlluminant1, "CalibrationIlluminant1" },
+ { tcCalibrationIlluminant2, "CalibrationIlluminant2" },
+ { tcBestQualityScale, "BestQualityScale" },
+ { tcRawDataUniqueID, "RawDataUniqueID" },
+ { tcOriginalRawFileName, "OriginalRawFileName" },
+ { tcOriginalRawFileData, "OriginalRawFileData" },
+ { tcActiveArea, "ActiveArea" },
+ { tcMaskedAreas, "MaskedAreas" },
+ { tcAsShotICCProfile, "AsShotICCProfile" },
+ { tcAsShotPreProfileMatrix, "AsShotPreProfileMatrix" },
+ { tcCurrentICCProfile, "CurrentICCProfile" },
+ { tcCurrentPreProfileMatrix, "CurrentPreProfileMatrix" },
+ { tcColorimetricReference, "ColorimetricReference" },
+ { tcCameraCalibrationSignature, "CameraCalibrationSignature" },
+ { tcProfileCalibrationSignature, "ProfileCalibrationSignature" },
+ { tcExtraCameraProfiles, "ExtraCameraProfiles" },
+ { tcAsShotProfileName, "AsShotProfileName" },
+ { tcNoiseReductionApplied, "NoiseReductionApplied" },
+ { tcProfileName, "ProfileName" },
+ { tcProfileHueSatMapDims, "ProfileHueSatMapDims" },
+ { tcProfileHueSatMapData1, "ProfileHueSatMapData1" },
+ { tcProfileHueSatMapData2, "ProfileHueSatMapData2" },
+ { tcProfileHueSatMapEncoding, "ProfileHueSatMapEncoding" },
+ { tcProfileToneCurve, "ProfileToneCurve" },
+ { tcProfileEmbedPolicy, "ProfileEmbedPolicy" },
+ { tcProfileCopyright, "ProfileCopyright" },
+ { tcForwardMatrix1, "ForwardMatrix1" },
+ { tcForwardMatrix2, "ForwardMatrix2" },
+ { tcPreviewApplicationName, "PreviewApplicationName" },
+ { tcPreviewApplicationVersion, "PreviewApplicationVersion" },
+ { tcPreviewSettingsName, "PreviewSettingsName" },
+ { tcPreviewSettingsDigest, "PreviewSettingsDigest" },
+ { tcPreviewColorSpace, "PreviewColorSpace" },
+ { tcPreviewDateTime, "PreviewDateTime" },
+ { tcRawImageDigest, "RawImageDigest" },
+ { tcOriginalRawFileDigest, "OriginalRawFileDigest" },
+ { tcSubTileBlockSize, "SubTileBlockSize" },
+ { tcRowInterleaveFactor, "RowInterleaveFactor" },
+ { tcProfileLookTableDims, "ProfileLookTableDims" },
+ { tcProfileLookTableData, "ProfileLookTableData" },
+ { tcProfileLookTableEncoding, "ProfileLookTableEncoding" },
+ { tcBaselineExposureOffset, "BaselineExposureOffset" },
+ { tcDefaultBlackRender, "DefaultBlackRender" },
+ { tcOpcodeList1, "OpcodeList1" },
+ { tcOpcodeList2, "OpcodeList2" },
+ { tcOpcodeList3, "OpcodeList3" },
+ { tcNoiseProfile, "NoiseProfile" },
+ { tcOriginalDefaultFinalSize, "OriginalDefaultFinalSize" },
+ { tcOriginalBestQualityFinalSize, "OriginalBestQualityFinalSize" },
+ { tcOriginalDefaultCropSize, "OriginalDefaultCropSize" },
+ { tcProfileHueSatMapEncoding, "ProfileHueSatMapEncoding" },
+ { tcProfileLookTableEncoding, "ProfileLookTableEncoding" },
+ { tcBaselineExposureOffset, "BaselineExposureOffset" },
+ { tcDefaultBlackRender, "DefaultBlackRender" },
+ { tcNewRawImageDigest, "NewRawImageDigest" },
+ { tcRawToPreviewGain, "RawToPreviewGain" },
+ { tcCacheBlob, "CacheBlob" },
+ { tcKodakKDCPrivateIFD, "KodakKDCPrivateIFD" }
+ };
+
+ const dng_name_table kGPSTagNames [] =
+ {
+ { tcGPSVersionID, "GPSVersionID" },
+ { tcGPSLatitudeRef, "GPSLatitudeRef" },
+ { tcGPSLatitude, "GPSLatitude" },
+ { tcGPSLongitudeRef, "GPSLongitudeRef" },
+ { tcGPSLongitude, "GPSLongitude" },
+ { tcGPSAltitudeRef, "GPSAltitudeRef" },
+ { tcGPSAltitude, "GPSAltitude" },
+ { tcGPSTimeStamp, "GPSTimeStamp" },
+ { tcGPSSatellites, "GPSSatellites" },
+ { tcGPSStatus, "GPSStatus" },
+ { tcGPSMeasureMode, "GPSMeasureMode" },
+ { tcGPSDOP, "GPSDOP" },
+ { tcGPSSpeedRef, "GPSSpeedRef" },
+ { tcGPSSpeed, "GPSSpeed" },
+ { tcGPSTrackRef, "GPSTrackRef" },
+ { tcGPSTrack, "GPSTrack" },
+ { tcGPSImgDirectionRef, "GPSImgDirectionRef" },
+ { tcGPSImgDirection, "GPSImgDirection" },
+ { tcGPSMapDatum, "GPSMapDatum" },
+ { tcGPSDestLatitudeRef, "GPSDestLatitudeRef" },
+ { tcGPSDestLatitude, "GPSDestLatitude" },
+ { tcGPSDestLongitudeRef, "GPSDestLongitudeRef" },
+ { tcGPSDestLongitude, "GPSDestLongitude" },
+ { tcGPSDestBearingRef, "GPSDestBearingRef" },
+ { tcGPSDestBearing, "GPSDestBearing" },
+ { tcGPSDestDistanceRef, "GPSDestDistanceRef" },
+ { tcGPSDestDistance, "GPSDestDistance" },
+ { tcGPSProcessingMethod, "GPSProcessingMethod" },
+ { tcGPSAreaInformation, "GPSAreaInformation" },
+ { tcGPSDateStamp, "GPSDateStamp" },
+ { tcGPSDifferential, "GPSDifferential" },
+ { tcGPSHPositioningError, "GPSHPositioningError" },
+ };
+
+ const dng_name_table kInteroperabilityTagNames [] =
+ {
+ { tcInteroperabilityIndex, "InteroperabilityIndex" },
+ { tcInteroperabilityVersion, "InteroperabilityVersion" },
+ { tcRelatedImageFileFormat, "RelatedImageFileFormat" },
+ { tcRelatedImageWidth, "RelatedImageWidth" },
+ { tcRelatedImageLength, "RelatedImageLength" }
+ };
+
+ const dng_name_table kFujiTagNames [] =
+ {
+ { tcFujiHeader, "FujiHeader" },
+ { tcFujiRawInfo1, "FujiRawInfo1" },
+ { tcFujiRawInfo2, "FujiRawInfo2" }
+ };
+
+ const dng_name_table kContaxTagNames [] =
+ {
+ { tcContaxHeader, "ContaxHeader" }
+ };
+
+ const char *name = NULL;
+
+ if (parentCode == 0 ||
+ parentCode == tcExifIFD ||
+ parentCode == tcLeafMOS ||
+ (parentCode >= tcFirstSubIFD && parentCode <= tcLastSubIFD) ||
+ (parentCode >= tcFirstChainedIFD && parentCode <= tcLastChainedIFD))
+ {
+
+ name = LookupName (tagCode,
+ kTagNames,
+ sizeof (kTagNames ) /
+ sizeof (kTagNames [0]));
+
+ }
+
+ else if (parentCode == tcGPSInfo)
+ {
+
+ name = LookupName (tagCode,
+ kGPSTagNames,
+ sizeof (kGPSTagNames ) /
+ sizeof (kGPSTagNames [0]));
+
+ }
+
+ else if (parentCode == tcInteroperabilityIFD)
+ {
+
+ name = LookupName (tagCode,
+ kInteroperabilityTagNames,
+ sizeof (kInteroperabilityTagNames ) /
+ sizeof (kInteroperabilityTagNames [0]));
+
+ }
+
+ else if (parentCode == tcFujiRAF)
+ {
+
+ name = LookupName (tagCode,
+ kFujiTagNames,
+ sizeof (kFujiTagNames ) /
+ sizeof (kFujiTagNames [0]));
+
+ }
+
+ else if (parentCode == tcContaxRAW)
+ {
+
+ name = LookupName (tagCode,
+ kContaxTagNames,
+ sizeof (kContaxTagNames ) /
+ sizeof (kContaxTagNames [0]));
+
+ }
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ if (parentCode == tcCanonCRW)
+ {
+ sprintf (s, "CRW_%04X", (unsigned) tagCode);
+ }
+
+ else if (parentCode == tcMinoltaMRW)
+ {
+
+ char c1 = (char) ((tagCode >> 24) & 0xFF);
+ char c2 = (char) ((tagCode >> 16) & 0xFF);
+ char c3 = (char) ((tagCode >> 8) & 0xFF);
+ char c4 = (char) ((tagCode ) & 0xFF);
+
+ if (c1 < ' ') c1 = '_';
+ if (c2 < ' ') c2 = '_';
+ if (c3 < ' ') c3 = '_';
+ if (c4 < ' ') c4 = '_';
+
+ sprintf (s, "MRW%c%c%c%c", c1, c2, c3, c4);
+
+ }
+
+ else if (parentCode == tcFujiRawInfo1)
+ {
+ sprintf (s, "RAF1_%04X", (unsigned) tagCode);
+ }
+
+ else if (parentCode == tcFujiRawInfo2)
+ {
+ sprintf (s, "RAF2_%04X", (unsigned) tagCode);
+ }
+
+ else
+ {
+ sprintf (s, "Tag%u", (unsigned) tagCode);
+ }
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupTagType (uint32 tagType)
+ {
+
+ const dng_name_table kTagTypeNames [] =
+ {
+ { ttByte, "Byte" },
+ { ttAscii, "ASCII" },
+ { ttShort, "Short" },
+ { ttLong, "Long" },
+ { ttRational, "Rational" },
+ { ttSByte, "SByte" },
+ { ttUndefined, "Undefined" },
+ { ttSShort, "SShort" },
+ { ttSLong, "SLong" },
+ { ttSRational, "SRational" },
+ { ttFloat, "Float" },
+ { ttDouble, "Double" },
+ { ttIFD, "IFD" },
+ { ttUnicode, "Unicode" },
+ { ttComplex, "Complex" }
+ };
+
+ const char *name = LookupName (tagType,
+ kTagTypeNames,
+ sizeof (kTagTypeNames ) /
+ sizeof (kTagTypeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "Type%u", (unsigned) tagType);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupNewSubFileType (uint32 key)
+ {
+
+ const dng_name_table kNewSubFileTypeNames [] =
+ {
+ { sfMainImage , "Main Image" },
+ { sfPreviewImage , "Preview Image" },
+ { sfTransparencyMask , "Transparency Mask" },
+ { sfPreviewMask , "Preview Mask" },
+ { sfAltPreviewImage , "Alt Preview Image" }
+ };
+
+ const char *name = LookupName (key,
+ kNewSubFileTypeNames,
+ sizeof (kNewSubFileTypeNames ) /
+ sizeof (kNewSubFileTypeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupCompression (uint32 key)
+ {
+
+ const dng_name_table kCompressionNames [] =
+ {
+ { ccUncompressed, "Uncompressed" },
+ { ccLZW, "LZW" },
+ { ccOldJPEG, "Old JPEG" },
+ { ccJPEG, "JPEG" },
+ { ccDeflate, "Deflate" },
+ { ccPackBits, "PackBits" },
+ { ccOldDeflate, "OldDeflate" },
+ { ccLossyJPEG, "Lossy JPEG" }
+ };
+
+ const char *name = LookupName (key,
+ kCompressionNames,
+ sizeof (kCompressionNames ) /
+ sizeof (kCompressionNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupPredictor (uint32 key)
+ {
+
+ const dng_name_table kPredictorNames [] =
+ {
+ { cpNullPredictor, "NullPredictor" },
+ { cpHorizontalDifference, "HorizontalDifference" },
+ { cpFloatingPoint, "FloatingPoint" },
+ { cpHorizontalDifferenceX2, "HorizontalDifferenceX2" },
+ { cpHorizontalDifferenceX4, "HorizontalDifferenceX4" },
+ { cpFloatingPointX2, "FloatingPointX2" },
+ { cpFloatingPointX4, "FloatingPointX4" }
+ };
+
+ const char *name = LookupName (key,
+ kPredictorNames,
+ sizeof (kPredictorNames ) /
+ sizeof (kPredictorNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSampleFormat (uint32 key)
+ {
+
+ const dng_name_table kSampleFormatNames [] =
+ {
+ { sfUnsignedInteger, "UnsignedInteger" },
+ { sfSignedInteger, "SignedInteger" },
+ { sfFloatingPoint, "FloatingPoint" },
+ { sfUndefined, "Undefined" }
+ };
+
+ const char *name = LookupName (key,
+ kSampleFormatNames,
+ sizeof (kSampleFormatNames ) /
+ sizeof (kSampleFormatNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupPhotometricInterpretation (uint32 key)
+ {
+
+ const dng_name_table kPhotometricInterpretationNames [] =
+ {
+ { piWhiteIsZero, "WhiteIsZero" },
+ { piBlackIsZero, "BlackIsZero" },
+ { piRGB, "RGB" },
+ { piRGBPalette, "RGBPalette" },
+ { piTransparencyMask, "TransparencyMask" },
+ { piCMYK, "CMYK" },
+ { piYCbCr, "YCbCr" },
+ { piCIELab, "CIELab" },
+ { piICCLab, "ICCLab" },
+ { piCFA, "CFA" },
+ { piLinearRaw, "LinearRaw" }
+ };
+
+ const char *name = LookupName (key,
+ kPhotometricInterpretationNames,
+ sizeof (kPhotometricInterpretationNames ) /
+ sizeof (kPhotometricInterpretationNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupOrientation (uint32 key)
+ {
+
+ const dng_name_table kOrientationNames [] =
+ {
+ { 1, "1 - 0th row is top, 0th column is left" },
+ { 2, "2 - 0th row is top, 0th column is right" },
+ { 3, "3 - 0th row is bottom, 0th column is right" },
+ { 4, "4 - 0th row is bottom, 0th column is left" },
+ { 5, "5 - 0th row is left, 0th column is top" },
+ { 6, "6 - 0th row is right, 0th column is top" },
+ { 7, "7 - 0th row is right, 0th column is bottom" },
+ { 8, "8 - 0th row is left, 0th column is bottom" },
+ { 9, "9 - unknown" }
+ };
+
+ const char *name = LookupName (key,
+ kOrientationNames,
+ sizeof (kOrientationNames ) /
+ sizeof (kOrientationNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupResolutionUnit (uint32 key)
+ {
+
+ const dng_name_table kResolutionUnitNames [] =
+ {
+ { ruNone, "None" },
+ { ruInch, "Inch" },
+ { ruCM, "cm" },
+ { ruMM, "mm" },
+ { ruMicroM, "Micrometer" }
+ };
+
+ const char *name = LookupName (key,
+ kResolutionUnitNames,
+ sizeof (kResolutionUnitNames ) /
+ sizeof (kResolutionUnitNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupCFAColor (uint32 key)
+ {
+
+ const dng_name_table kCFAColorNames [] =
+ {
+ { 0, "Red" },
+ { 1, "Green" },
+ { 2, "Blue" },
+ { 3, "Cyan" },
+ { 4, "Magenta" },
+ { 5, "Yellow" },
+ { 6, "White" }
+ };
+
+ const char *name = LookupName (key,
+ kCFAColorNames,
+ sizeof (kCFAColorNames ) /
+ sizeof (kCFAColorNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "Color%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSensingMethod (uint32 key)
+ {
+
+ const dng_name_table kSensingMethodNames [] =
+ {
+ { 0, "Undefined" },
+ { 1, "MonochromeArea" },
+ { 2, "OneChipColorArea" },
+ { 3, "TwoChipColorArea" },
+ { 4, "ThreeChipColorArea" },
+ { 5, "ColorSequentialArea" },
+ { 6, "MonochromeLinear" },
+ { 7, "TriLinear" },
+ { 8, "ColorSequentialLinear" }
+ };
+
+ const char *name = LookupName (key,
+ kSensingMethodNames,
+ sizeof (kSensingMethodNames ) /
+ sizeof (kSensingMethodNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupExposureProgram (uint32 key)
+ {
+
+ const dng_name_table kExposureProgramNames [] =
+ {
+ { epUnidentified, "Unidentified" },
+ { epManual, "Manual" },
+ { epProgramNormal, "Program Normal" },
+ { epAperturePriority, "Aperture Priority" },
+ { epShutterPriority, "Shutter Priority" },
+ { epProgramCreative, "Program Creative" },
+ { epProgramAction, "Program Action" },
+ { epPortraitMode, "Portrait Mode" },
+ { epLandscapeMode, "Landscape Mode" }
+ };
+
+ const char *name = LookupName (key,
+ kExposureProgramNames,
+ sizeof (kExposureProgramNames ) /
+ sizeof (kExposureProgramNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupMeteringMode (uint32 key)
+ {
+
+ const dng_name_table kMeteringModeNames [] =
+ {
+ { mmUnidentified, "Unknown" },
+ { mmAverage, "Average" },
+ { mmCenterWeightedAverage, "CenterWeightedAverage" },
+ { mmSpot, "Spot" },
+ { mmMultiSpot, "MultiSpot" },
+ { mmPattern, "Pattern" },
+ { mmPartial, "Partial" },
+ { mmOther, "Other" }
+ };
+
+ const char *name = LookupName (key,
+ kMeteringModeNames,
+ sizeof (kMeteringModeNames ) /
+ sizeof (kMeteringModeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupLightSource (uint32 key)
+ {
+
+ const dng_name_table kLightSourceNames [] =
+ {
+ { lsUnknown, "Unknown" },
+ { lsDaylight, "Daylight" },
+ { lsFluorescent, "Fluorescent" },
+ { lsTungsten, "Tungsten (incandescent light)" },
+ { lsFlash, "Flash" },
+ { lsFineWeather, "Fine weather" },
+ { lsCloudyWeather, "Cloudy weather" },
+ { lsShade, "Shade" },
+ { lsDaylightFluorescent, "Daylight fluorescent (D 5700 - 7100K)" },
+ { lsDayWhiteFluorescent, "Day white fluorescent (N 4600 - 5500K)" },
+ { lsCoolWhiteFluorescent, "Cool white fluorescent (W 3800 - 4500K)" },
+ { lsWhiteFluorescent, "White fluorescent (WW 3250 - 3800K)" },
+ { lsWarmWhiteFluorescent, "Warm white fluorescent (L 2600 - 3250K)" },
+ { lsStandardLightA, "Standard light A" },
+ { lsStandardLightB, "Standard light B" },
+ { lsStandardLightC, "Standard light C" },
+ { lsD55, "D55" },
+ { lsD65, "D65" },
+ { lsD75, "D75" },
+ { lsD50, "D50" },
+ { lsISOStudioTungsten, "ISO studio tungsten" },
+ { lsOther, "Other" }
+ };
+
+ const char *name = LookupName (key,
+ kLightSourceNames,
+ sizeof (kLightSourceNames ) /
+ sizeof (kLightSourceNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ if (key & 0x08000)
+ {
+
+ sprintf (s, "%uK", (unsigned) (key & 0x7FFF));
+
+ }
+
+ else
+ {
+
+ sprintf (s, "%u", (unsigned) key);
+
+ }
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupColorSpace (uint32 key)
+ {
+
+ const dng_name_table kColorSpaceNames [] =
+ {
+ { 1, "sRGB" },
+ { 0xFFFF, "Uncalibrated" }
+ };
+
+ const char *name = LookupName (key,
+ kColorSpaceNames,
+ sizeof (kColorSpaceNames ) /
+ sizeof (kColorSpaceNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupFileSource (uint32 key)
+ {
+
+ const dng_name_table kFileSourceNames [] =
+ {
+ { 3, "DSC" }
+ };
+
+ const char *name = LookupName (key,
+ kFileSourceNames,
+ sizeof (kFileSourceNames ) /
+ sizeof (kFileSourceNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSceneType (uint32 key)
+ {
+
+ const dng_name_table kSceneTypeNames [] =
+ {
+ { 1, "A directly photographed image" }
+ };
+
+ const char *name = LookupName (key,
+ kSceneTypeNames,
+ sizeof (kSceneTypeNames ) /
+ sizeof (kSceneTypeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupCustomRendered (uint32 key)
+ {
+
+ const dng_name_table kCustomRenderedNames [] =
+ {
+ { 0, "Normal process" },
+ { 1, "Custom process" }
+ };
+
+ const char *name = LookupName (key,
+ kCustomRenderedNames,
+ sizeof (kCustomRenderedNames ) /
+ sizeof (kCustomRenderedNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupExposureMode (uint32 key)
+ {
+
+ const dng_name_table kExposureModeNames [] =
+ {
+ { 0, "Auto exposure" },
+ { 1, "Manual exposure" },
+ { 2, "Auto bracket" }
+ };
+
+ const char *name = LookupName (key,
+ kExposureModeNames,
+ sizeof (kExposureModeNames ) /
+ sizeof (kExposureModeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupWhiteBalance (uint32 key)
+ {
+
+ const dng_name_table kWhiteBalanceNames [] =
+ {
+ { 0, "Auto white balance" },
+ { 1, "Manual white balance" }
+ };
+
+ const char *name = LookupName (key,
+ kWhiteBalanceNames,
+ sizeof (kWhiteBalanceNames ) /
+ sizeof (kWhiteBalanceNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSceneCaptureType (uint32 key)
+ {
+
+ const dng_name_table kSceneCaptureTypeNames [] =
+ {
+ { 0, "Standard" },
+ { 1, "Landscape" },
+ { 2, "Portrait" },
+ { 3, "Night scene" }
+ };
+
+ const char *name = LookupName (key,
+ kSceneCaptureTypeNames,
+ sizeof (kSceneCaptureTypeNames ) /
+ sizeof (kSceneCaptureTypeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupGainControl (uint32 key)
+ {
+
+ const dng_name_table kGainControlNames [] =
+ {
+ { 0, "None" },
+ { 1, "Low gain up" },
+ { 2, "High gain up" },
+ { 3, "Low gain down" },
+ { 4, "High gain down" }
+ };
+
+ const char *name = LookupName (key,
+ kGainControlNames,
+ sizeof (kGainControlNames ) /
+ sizeof (kGainControlNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupContrast (uint32 key)
+ {
+
+ const dng_name_table kContrastNames [] =
+ {
+ { 0, "Normal" },
+ { 1, "Soft" },
+ { 2, "Hard" }
+ };
+
+ const char *name = LookupName (key,
+ kContrastNames,
+ sizeof (kContrastNames ) /
+ sizeof (kContrastNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSaturation (uint32 key)
+ {
+
+ const dng_name_table kSaturationNames [] =
+ {
+ { 0, "Normal" },
+ { 1, "Low saturation" },
+ { 2, "High saturation" }
+ };
+
+ const char *name = LookupName (key,
+ kSaturationNames,
+ sizeof (kSaturationNames ) /
+ sizeof (kSaturationNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSharpness (uint32 key)
+ {
+
+ const dng_name_table kSharpnessNames [] =
+ {
+ { 0, "Normal" },
+ { 1, "Soft" },
+ { 2, "Hard" }
+ };
+
+ const char *name = LookupName (key,
+ kSharpnessNames,
+ sizeof (kSharpnessNames ) /
+ sizeof (kSharpnessNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSubjectDistanceRange (uint32 key)
+ {
+
+ const dng_name_table kSubjectDistanceRangeNames [] =
+ {
+ { 0, "Unknown" },
+ { 1, "Macro" },
+ { 2, "Close view" },
+ { 3, "Distant view" }
+ };
+
+ const char *name = LookupName (key,
+ kSubjectDistanceRangeNames,
+ sizeof (kSubjectDistanceRangeNames ) /
+ sizeof (kSubjectDistanceRangeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupComponent (uint32 key)
+ {
+
+ const dng_name_table kComponentNames [] =
+ {
+ { 0, "-" },
+ { 1, "Y" },
+ { 2, "Cb" },
+ { 3, "Cr" },
+ { 4, "R" },
+ { 5, "G" },
+ { 6, "B" }
+ };
+
+ const char *name = LookupName (key,
+ kComponentNames,
+ sizeof (kComponentNames ) /
+ sizeof (kComponentNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupCFALayout (uint32 key)
+ {
+
+ const dng_name_table kCFALayoutNames [] =
+ {
+ { 1, "Rectangular (or square) layout" },
+ { 2, "Staggered layout A: even columns are offset down by 1/2 row" },
+ { 3, "Staggered layout B: even columns are offset up by 1/2 row" },
+ { 4, "Staggered layout C: even rows are offset right by 1/2 column" },
+ { 5, "Staggered layout D: even rows are offset left by 1/2 column" },
+ { 6, "Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column" },
+ { 7, "Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column" },
+ { 8, "Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column" },
+ { 9, "Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column" }
+ };
+
+ const char *name = LookupName (key,
+ kCFALayoutNames,
+ sizeof (kCFALayoutNames ) /
+ sizeof (kCFALayoutNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupMakerNoteSafety (uint32 key)
+ {
+
+ const dng_name_table kMakerNoteSafetyNames [] =
+ {
+ { 0, "Unsafe" },
+ { 1, "Safe" }
+ };
+
+ const char *name = LookupName (key,
+ kMakerNoteSafetyNames,
+ sizeof (kMakerNoteSafetyNames ) /
+ sizeof (kMakerNoteSafetyNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupColorimetricReference (uint32 key)
+ {
+
+ const dng_name_table kColorimetricReferenceNames [] =
+ {
+ { crSceneReferred, "Scene Referred" },
+ { crICCProfilePCS, "ICC Profile PCS" }
+ };
+
+ const char *name = LookupName (key,
+ kColorimetricReferenceNames,
+ sizeof (kColorimetricReferenceNames ) /
+ sizeof (kColorimetricReferenceNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupPreviewColorSpace (uint32 key)
+ {
+
+ const dng_name_table kPreviewColorSpaceNames [] =
+ {
+ { previewColorSpace_Unknown , "Unknown" },
+ { previewColorSpace_GrayGamma22, "Gray Gamma 2.2" },
+ { previewColorSpace_sRGB , "sRGB" },
+ { previewColorSpace_AdobeRGB , "Adobe RGB (1998)" },
+ { previewColorSpace_ProPhotoRGB, "Pro Photo RGB" }
+ };
+
+ const char *name = LookupName (key,
+ kPreviewColorSpaceNames,
+ sizeof (kPreviewColorSpaceNames ) /
+ sizeof (kPreviewColorSpaceNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupJPEGMarker (uint32 key)
+ {
+
+ const dng_name_table kJPEGMarkerNames [] =
+ {
+ { M_TEM, "TEM" },
+ { M_SOF0, "SOF0" },
+ { M_SOF1, "SOF1" },
+ { M_SOF2, "SOF2" },
+ { M_SOF3, "SOF3" },
+ { M_DHT, "DHT" },
+ { M_SOF5, "SOF5" },
+ { M_SOF6, "SOF6" },
+ { M_SOF7, "SOF7" },
+ { M_JPG, "JPG" },
+ { M_SOF9, "SOF9" },
+ { M_SOF10, "SOF10" },
+ { M_SOF11, "SOF11" },
+ { M_DAC, "DAC" },
+ { M_SOF13, "SOF13" },
+ { M_SOF14, "SOF14" },
+ { M_SOF15, "SOF15" },
+ { M_RST0, "RST0" },
+ { M_RST1, "RST1" },
+ { M_RST2, "RST2" },
+ { M_RST3, "RST3" },
+ { M_RST4, "RST4" },
+ { M_RST5, "RST5" },
+ { M_RST6, "RST6" },
+ { M_RST7, "RST7" },
+ { M_SOI, "SOI" },
+ { M_EOI, "EOI" },
+ { M_SOS, "SOS" },
+ { M_DQT, "DQT" },
+ { M_DNL, "DNL" },
+ { M_DRI, "DRI" },
+ { M_DHP, "DHP" },
+ { M_EXP, "EXP" },
+ { M_APP0, "APP0" },
+ { M_APP1, "APP1" },
+ { M_APP2, "APP2" },
+ { M_APP3, "APP3" },
+ { M_APP4, "APP4" },
+ { M_APP5, "APP5" },
+ { M_APP6, "APP6" },
+ { M_APP7, "APP7" },
+ { M_APP8, "APP8" },
+ { M_APP9, "APP9" },
+ { M_APP10, "APP10" },
+ { M_APP11, "APP11" },
+ { M_APP12, "APP12" },
+ { M_APP13, "APP13" },
+ { M_APP14, "APP14" },
+ { M_APP15, "APP15" },
+ { M_JPG0, "JPG0" },
+ { M_JPG1, "JPG1" },
+ { M_JPG2, "JPG2" },
+ { M_JPG3, "JPG3" },
+ { M_JPG4, "JPG4" },
+ { M_JPG5, "JPG5" },
+ { M_JPG6, "JPG6" },
+ { M_JPG7, "JPG7" },
+ { M_JPG8, "JPG8" },
+ { M_JPG9, "JPG9" },
+ { M_JPG10, "JPG10" },
+ { M_JPG11, "JPG11" },
+ { M_JPG12, "JPG12" },
+ { M_JPG13, "JPG13" },
+ { M_COM, "COM" },
+ { M_ERROR, "ERROR" }
+ };
+
+ const char *name = LookupName (key,
+ kJPEGMarkerNames,
+ sizeof (kJPEGMarkerNames ) /
+ sizeof (kJPEGMarkerNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "0x%02X", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupSensitivityType (uint32 key)
+ {
+
+ const dng_name_table kSensitivityTypeNames [] =
+ {
+ { stUnknown, "Unknown" },
+ { stStandardOutputSensitivity, "Standard Output Sensitivity (SOS)" },
+ { stRecommendedExposureIndex, "Recommended Exposure Index (REI)" },
+ { stISOSpeed, "ISO Speed" },
+ { stSOSandREI, "Standard Output Sensitivity (SOS) and Recommended Exposure Index (REI)" },
+ { stSOSandISOSpeed, "Standard Output Sensitivity (SOS) and ISO Speed" },
+ { stREIandISOSpeed, "Recommended Exposure Index (REI) and ISO Speed" },
+ { stSOSandREIandISOSpeed, "Standard Output Sensitivity (SOS) and Recommended Exposure Index (REI) and ISO Speed" },
+ };
+
+ const char *name = LookupName (key,
+ kSensitivityTypeNames,
+ sizeof (kSensitivityTypeNames ) /
+ sizeof (kSensitivityTypeNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+void DumpHexAscii (dng_stream &stream,
+ uint32 count)
+ {
+
+ uint32 rows = (count + 15) >> 4;
+
+ if (rows > gDumpLineLimit)
+ rows = gDumpLineLimit;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ printf (" ");
+
+ uint32 col;
+
+ uint32 cols = count - (row << 4);
+
+ if (cols > 16)
+ cols = 16;
+
+ uint8 x [16];
+
+ for (col = 0; col < 16; col++)
+ {
+
+ x [col] = ' ';
+
+ if (col < cols)
+ {
+
+ x [col] = stream.Get_uint8 ();
+
+ printf ("%02x ", x [col]);
+
+ }
+
+ else
+ {
+ printf (" ");
+ }
+
+ }
+
+ printf (" ");
+
+ for (col = 0; col < 16; col++)
+ {
+
+ if (x [col] >= (uint8) ' ' && x [col] <= (uint8) '~')
+ {
+ printf ("%c", x [col]);
+ }
+
+ else
+ {
+ printf (".");
+ }
+
+ }
+
+ printf ("\n");
+
+ }
+
+ if (count > rows * 16)
+ {
+ printf (" ... %u more bytes\n", (unsigned) (count - rows * 16));
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpHexAscii (const uint8 *buf,
+ uint32 count)
+ {
+
+ uint32 rows = (count + 15) >> 4;
+
+ if (rows > gDumpLineLimit)
+ rows = gDumpLineLimit;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ printf (" ");
+
+ uint32 col;
+
+ uint32 cols = count - (row << 4);
+
+ if (cols > 16)
+ cols = 16;
+
+ uint8 x [16];
+
+ for (col = 0; col < 16; col++)
+ {
+
+ x [col] = ' ';
+
+ if (col < cols)
+ {
+
+ x [col] = *(buf++);
+
+ printf ("%02x ", x [col]);
+
+ }
+
+ else
+ {
+ printf (" ");
+ }
+
+ }
+
+ printf (" ");
+
+ for (col = 0; col < 16; col++)
+ {
+
+ if (x [col] >= (uint8) ' ' && x [col] <= (uint8) '~')
+ {
+ printf ("%c", x [col]);
+ }
+
+ else
+ {
+ printf (".");
+ }
+
+ }
+
+ printf ("\n");
+
+ }
+
+ if (count > rows * 16)
+ {
+ printf (" ... %u more bytes\n", (unsigned) (count - rows * 16));
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpXMP (dng_stream &stream,
+ uint32 count)
+ {
+
+ uint32 lineLength = 0;
+
+ while (count > 0)
+ {
+
+ uint32 x = stream.Get_uint8 ();
+
+ if (x == 0) break;
+
+ count--;
+
+ if (lineLength == 0)
+ {
+
+ printf ("XMP: ");
+
+ lineLength = 5;
+
+ }
+
+ if (x == '\n' ||
+ x == '\r')
+ {
+
+ printf ("\n");
+
+ lineLength = 0;
+
+ }
+
+ else
+ {
+
+ if (lineLength >= 128)
+ {
+
+ printf ("\nXMP: ");
+
+ lineLength = 5;
+
+ }
+
+ if (x >= ' ' && x <= '~')
+ {
+
+ printf ("%c", (char) x);
+
+ lineLength += 1;
+
+ }
+
+ else
+ {
+
+ printf ("\\%03o", (unsigned) x);
+
+ lineLength += 4;
+
+ }
+
+ }
+
+ }
+
+ if (lineLength != 0)
+ {
+
+ printf ("\n");
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpString (const dng_string &s)
+ {
+
+ const uint32 kMaxDumpString = gDumpLineLimit * 64;
+
+ printf ("\"");
+
+ const char *ss = s.Get ();
+
+ uint32 total = 0;
+
+ while (*ss != 0 && total++ < kMaxDumpString)
+ {
+
+ uint32 c = dng_string::DecodeUTF8 (ss);
+
+ if (c >= ' ' && c <= '~')
+ {
+ printf ("%c", (char) c);
+ }
+
+ else switch (c)
+ {
+
+ case '\t':
+ {
+ printf ("\\t");
+ break;
+ }
+
+ case '\n':
+ {
+ printf ("\\n");
+ break;
+ }
+
+ case '\r':
+ {
+ printf ("\\r");
+ break;
+ }
+
+ default:
+ {
+ printf ("[%X]", (unsigned) c);
+ }
+
+ }
+
+ }
+
+ uint32 extra = (uint32) strlen (ss);
+
+ if (extra > 0)
+ {
+ printf ("...\" (%u more bytes)", (unsigned) extra);
+ }
+
+ else
+ {
+ printf ("\"");
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpTagValues (dng_stream &stream,
+ const char *entry_name,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ const char *tag_name)
+ {
+
+ const uint32 kMaxDumpSingleLine = 4;
+
+ const uint32 kMaxDumpArray = Max_uint32 (gDumpLineLimit, kMaxDumpSingleLine);
+
+ printf ("%s:", tag_name ? tag_name
+ : LookupTagCode (parentCode, tagCode));
+
+ switch (tagType)
+ {
+
+ case ttShort:
+ case ttLong:
+ case ttIFD:
+ case ttSByte:
+ case ttSShort:
+ case ttSLong:
+ case ttRational:
+ case ttSRational:
+ case ttFloat:
+ case ttDouble:
+ {
+
+ if (tagCount > kMaxDumpSingleLine)
+ {
+
+ printf (" %u entries", (unsigned) tagCount);
+
+ }
+
+ for (uint32 j = 0; j < tagCount && j < kMaxDumpArray; j++)
+ {
+
+ if (tagCount <= kMaxDumpSingleLine)
+ {
+
+ if (j == 0)
+ {
+
+ printf (" %s =", entry_name);
+
+ }
+
+ printf (" ");
+
+ }
+
+ else
+ {
+
+ printf ("\n %s [%u] = ", entry_name, (unsigned) j);
+
+ }
+
+ switch (tagType)
+ {
+
+ case ttByte:
+ case ttShort:
+ case ttLong:
+ case ttIFD:
+ {
+
+ uint32 x = stream.TagValue_uint32 (tagType);
+
+ printf ("%u", (unsigned) x);
+
+ break;
+
+ }
+
+ case ttSByte:
+ case ttSShort:
+ case ttSLong:
+ {
+
+ int32 x = stream.TagValue_int32 (tagType);
+
+ printf ("%d", (int) x);
+
+ break;
+
+ }
+
+ case ttRational:
+ {
+
+ dng_urational x = stream.TagValue_urational (tagType);
+
+ printf ("%u/%u", (unsigned) x.n, (unsigned) x.d);
+
+ break;
+
+ }
+
+ case ttSRational:
+ {
+
+ dng_srational x = stream.TagValue_srational (tagType);
+
+ printf ("%d/%d", (int) x.n, (int) x.d);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ real64 x = stream.TagValue_real64 (tagType);
+
+ printf ("%f", x);
+
+ }
+
+ }
+
+ }
+
+ printf ("\n");
+
+ if (tagCount > kMaxDumpArray)
+ {
+
+ printf (" ... %u more entries\n", (unsigned) (tagCount - kMaxDumpArray));
+
+ }
+
+ break;
+
+ }
+
+ case ttAscii:
+ {
+
+ dng_string s;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ s,
+ false);
+
+ printf (" ");
+
+ DumpString (s);
+
+ printf ("\n");
+
+ break;
+
+ }
+
+ default:
+ {
+
+ uint32 tagSize = tagCount * TagTypeSize (tagType);
+
+ if (tagCount == 1 && (tagType == ttByte ||
+ tagType == ttUndefined))
+ {
+
+ uint8 x = stream.Get_uint8 ();
+
+ printf (" %s = %u\n", LookupTagType (tagType), x);
+
+ }
+
+ else
+ {
+
+ printf (" %s, size = %u\n", LookupTagType (tagType), (unsigned) tagSize);
+
+ DumpHexAscii (stream, tagSize);
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpMatrix (const dng_matrix &m)
+ {
+
+ for (uint32 row = 0; row < m.Rows (); row++)
+ {
+
+ for (uint32 col = 0; col < m.Cols (); col++)
+ {
+
+ if (col == 0)
+ printf (" ");
+ else
+ printf (" ");
+
+ printf ("%8.4f", m [row] [col]);
+
+ }
+
+ printf ("\n");
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpVector (const dng_vector &v)
+ {
+
+ for (uint32 index = 0; index < v.Count (); index++)
+ {
+
+ printf (" %0.4f", v [index]);
+
+ }
+
+ printf ("\n");
+
+ }
+
+/*****************************************************************************/
+
+void DumpDateTime (const dng_date_time &dt)
+ {
+
+ printf ("%04d:%02d:%02d %02d:%02d:%02d",
+ (int) dt.fYear,
+ (int) dt.fMonth,
+ (int) dt.fDay,
+ (int) dt.fHour,
+ (int) dt.fMinute,
+ (int) dt.fSecond);
+
+ }
+
+/*****************************************************************************/
+
+void DumpExposureTime (real64 x)
+ {
+
+ if (x > 0.0)
+ {
+
+ if (x >= 0.25)
+ {
+ printf ("%0.2f sec", x);
+ }
+
+ else if (x >= 0.01)
+ {
+ printf ("1/%0.1f sec", 1.0 / x);
+ }
+
+ else
+ {
+ printf ("1/%0.0f sec", 1.0 / x);
+ }
+
+ }
+
+ else
+ {
+
+ printf ("<invalid>");
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void DumpFingerprint (const dng_fingerprint &p)
+ {
+
+ printf ("<");
+
+ for (uint32 j = 0; j < 16; j++)
+ {
+ printf ("%02x", p.data [j]);
+ }
+
+ printf (">");
+
+ }
+
+/*****************************************************************************/
+
+void DumpHueSatMap (dng_stream &stream,
+ uint32 hues,
+ uint32 sats,
+ uint32 vals,
+ bool skipSat0)
+ {
+
+ uint32 doneLines = 0;
+ uint32 skipLines = 0;
+
+ for (uint32 v = 0; v < vals; v++)
+ {
+
+ for (uint32 h = 0; h < hues; h++)
+ {
+
+ for (uint32 s = skipSat0 ? 1 : 0; s < sats; s++)
+ {
+
+ real32 dh = stream.Get_real32 ();
+ real32 ds = stream.Get_real32 ();
+ real32 dv = stream.Get_real32 ();
+
+ if (gDumpLineLimit == 0 ||
+ gDumpLineLimit > doneLines)
+ {
+
+ doneLines++;
+
+ if (vals == 1)
+ {
+
+ printf (" h [%2u] s [%2u]: h=%8.4f s=%6.4f v=%6.4f\n",
+ (unsigned) h,
+ (unsigned) s,
+ (double) dh,
+ (double) ds,
+ (double) dv);
+
+ }
+
+ else
+ {
+
+ printf (" v [%2u] h [%2u] s [%2u]: h=%8.4f s=%6.4f v=%6.4f\n",
+ (unsigned) v,
+ (unsigned) h,
+ (unsigned) s,
+ (double) dh,
+ (double) ds,
+ (double) dv);
+
+ }
+
+ }
+
+ else
+ {
+
+ skipLines++;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ if (skipLines > 0)
+ {
+
+ printf (" ... %u more entries\n", (unsigned) skipLines);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+bool CheckTagType (uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint16 validType0,
+ uint16 validType1,
+ uint16 validType2,
+ uint16 validType3)
+ {
+
+ if (tagType != validType0 &&
+ tagType != validType1 &&
+ tagType != validType2 &&
+ tagType != validType3)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has unexpected type (%s)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode),
+ LookupTagType (tagType));
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool CheckTagCount (uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ uint32 minCount,
+ uint32 maxCount)
+ {
+
+ if (maxCount < minCount)
+ maxCount = minCount;
+
+ if (tagCount < minCount ||
+ tagCount > maxCount)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has unexpected count (%u)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode),
+ (unsigned) tagCount);
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool CheckColorImage (uint32 parentCode,
+ uint32 tagCode,
+ uint32 colorPlanes)
+ {
+
+ if (colorPlanes == 0)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed with unknown color plane count "
+ " (missing ColorMatrix1 tag?)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ return false;
+
+ }
+
+ if (colorPlanes == 1)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed with monochrome images",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool CheckMainIFD (uint32 parentCode,
+ uint32 tagCode,
+ uint32 newSubFileType)
+ {
+
+ if (newSubFileType != sfMainImage)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed IFDs with NewSubFileType != 0",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool CheckRawIFD (uint32 parentCode,
+ uint32 tagCode,
+ uint32 photometricInterpretation)
+ {
+
+ if (photometricInterpretation != piCFA &&
+ photometricInterpretation != piLinearRaw)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed in IFDs with a non-raw PhotometricInterpretation",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool CheckCFA (uint32 parentCode,
+ uint32 tagCode,
+ uint32 photometricInterpretation)
+ {
+
+ if (photometricInterpretation != piCFA)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed in IFDs with a non-CFA PhotometricInterpretation",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void ParseStringTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ dng_string &s,
+ bool trimBlanks)
+ {
+
+ if (tagCount == 0 ||
+ tagCount == 0xFFFFFFFF)
+ {
+
+ s.Clear ();
+
+ return;
+
+ }
+
+ dng_memory_data temp_buffer (tagCount + 1);
+
+ char *buffer = temp_buffer.Buffer_char ();
+
+ stream.Get (buffer, tagCount);
+
+ // Make sure the string is null terminated.
+
+ if (buffer [tagCount - 1] != 0)
+ {
+
+ buffer [tagCount] = 0;
+
+ #if qDNGValidate
+
+ {
+
+ bool hasNull = false;
+
+ for (uint32 j = 0; j < tagCount; j++)
+ {
+
+ if (buffer [j] == 0)
+ {
+
+ hasNull = true;
+
+ break;
+
+ }
+
+ }
+
+ if (!hasNull && parentCode < tcFirstMakerNoteIFD)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not NULL terminated",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ }
+
+ // Medata working group - Allow UTF-8
+
+ s.Set_UTF8_or_System (buffer);
+
+ if (trimBlanks)
+ {
+
+ s.TrimTrailingBlanks ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void ParseDualStringTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ dng_string &s1,
+ dng_string &s2)
+ {
+
+ if (tagCount == 0 ||
+ tagCount == 0xFFFFFFFF)
+ {
+
+ s1.Clear ();
+ s2.Clear ();
+
+ return;
+
+ }
+
+ dng_memory_data temp_buffer (tagCount + 1);
+
+ char *buffer = temp_buffer.Buffer_char ();
+
+ stream.Get (buffer, tagCount);
+
+ // Make sure the string is null terminated.
+
+ if (buffer [tagCount - 1] != 0)
+ {
+
+ buffer [tagCount] = 0;
+
+ #if qDNGValidate
+
+ {
+
+ uint32 nullCount = 0;
+
+ for (uint32 j = 0; j < tagCount; j++)
+ {
+
+ if (buffer [j] == 0)
+ {
+
+ nullCount++;
+
+ }
+
+ }
+
+ if (nullCount < 2 && parentCode < tcFirstMakerNoteIFD)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not NULL terminated",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ }
+
+ // Medata working group - Allow UTF-8
+
+ s1.Set_UTF8_or_System (buffer);
+
+ s2.Set_ASCII (NULL);
+
+ for (uint32 j = 1; j < tagCount - 1; j++)
+ {
+
+ if (buffer [j - 1] != 0 &&
+ buffer [j ] == 0)
+ {
+
+ // Medata working group - Allow UTF-8
+
+ s2.Set_UTF8_or_System (buffer + j + 1);
+
+ break;
+
+ }
+
+ }
+
+ s1.TrimTrailingBlanks ();
+ s2.TrimTrailingBlanks ();
+
+ }
+
+/*****************************************************************************/
+
+void ParseEncodedStringTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ dng_string &s)
+ {
+
+ if (tagCount < 8)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has unexpected count (%u)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode),
+ (unsigned) tagCount);
+
+ ReportWarning (message);
+
+ }
+
+ #else
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
+ #endif
+
+ s.Clear ();
+
+ return;
+
+ }
+
+ char label [8];
+
+ stream.Get (label, 8);
+
+ // Sometimes lowercase is used by mistake. Accept this, but issue
+ // warning.
+
+ {
+
+ bool hadLower = false;
+
+ for (uint32 j = 0; j < 8; j++)
+ {
+
+ if (label [j] >= 'a' && label [j] <= 'z')
+ {
+
+ label [j] = 'A' + (label [j] - 'a');
+
+ hadLower = true;
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (hadLower)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s text encoding label not all uppercase",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ }
+
+ if (memcmp (label, "UNICODE\000", 8) == 0)
+ {
+
+ uint32 uChars = (tagCount - 8) >> 1;
+
+ dng_memory_data temp_buffer ((uChars + 1) * 2);
+
+ uint16 *buffer = temp_buffer.Buffer_uint16 ();
+
+ for (uint32 j = 0; j < uChars; j++)
+ {
+
+ buffer [j] = stream.Get_uint16 ();
+
+ }
+
+ buffer [uChars] = 0;
+
+ #if qDNGValidate
+
+ {
+
+ // If the writer used UTF-8 rather than UTF-16, and padded
+ // the string with blanks, then there will be lots of 0x2020
+ // (unicode dagger symbol) characters in the string.
+
+ uint32 count2020 = 0;
+
+ for (uint32 k = 0; buffer [k] != 0; k++)
+ {
+
+ if (buffer [k] == 0x2020)
+ {
+
+ count2020++;
+
+ }
+
+ }
+
+ if (count2020 > 1)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s text appears to be UTF-8 rather than UTF-16",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ #endif
+
+ s.Set_UTF16 (buffer);
+
+ }
+
+ else
+ {
+
+ uint32 aChars = tagCount - 8;
+
+ dng_memory_data temp_buffer (aChars + 1);
+
+ char *buffer = temp_buffer.Buffer_char ();
+
+ stream.Get (buffer, aChars);
+
+ buffer [aChars] = 0;
+
+ enum dng_encoding
+ {
+ dng_encoding_ascii,
+ dng_encoding_jis_x208_1990,
+ dng_encoding_unknown
+ };
+
+ dng_encoding encoding = dng_encoding_unknown;
+
+ if (memcmp (label, "ASCII\000\000\000", 8) == 0)
+ {
+
+ encoding = dng_encoding_ascii;
+
+ }
+
+ else if (memcmp (label, "JIS\000\000\000\000\000\000", 8) == 0)
+ {
+
+ encoding = dng_encoding_jis_x208_1990;
+
+ }
+
+ else
+ {
+
+ // Some Nikon D1 files have UserComment tags with zero encoding bits and
+ // garbage text values. So don't try to parse tags with unknown text
+ // encoding unless all the characters are printing ASCII.
+
+ #if qDNGValidate
+
+ if (memcmp (label, "\000\000\000\000\000\000\000\000\000", 8) == 0)
+ {
+
+ // Many camera makes store null tags with all zero encoding, so
+ // don't report a warning message for null strings.
+
+ if (buffer [0] != 0)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has unknown encoding",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ else
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has unexpected text encoding",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ }
+
+ // If text encoding was unknown, and the text is anything
+ // other than pure ASCII, then ignore it.
+
+ if (encoding == dng_encoding_unknown)
+ {
+
+ encoding = dng_encoding_ascii;
+
+ for (uint32 i = 0; i < aChars && buffer [i] != 0; i++)
+ {
+
+ if (buffer [i] < ' ' ||
+ buffer [i] > '~')
+ {
+
+ buffer [0] = 0;
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ switch (encoding)
+ {
+
+ case dng_encoding_ascii:
+ {
+
+ // Medata working group - allow UTF-8 for ASCII tags.
+
+ s.Set_UTF8_or_System (buffer);
+
+ break;
+
+ }
+
+ case dng_encoding_jis_x208_1990:
+ {
+ s.Set_JIS_X208_1990 (buffer);
+ break;
+ }
+
+ case dng_encoding_unknown:
+ {
+ s.Set_SystemEncoding (buffer);
+ break;
+ }
+
+ default:
+ break;
+
+ }
+
+ #if qDNGValidate
+
+ {
+
+ if (encoding == dng_encoding_ascii && !s.IsASCII ())
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has non-ASCII characters",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ }
+
+ #endif
+
+ }
+
+ s.TrimTrailingBlanks ();
+
+ }
+
+/*****************************************************************************/
+
+bool ParseMatrixTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint32 rows,
+ uint32 cols,
+ dng_matrix &m)
+ {
+
+ if (CheckTagCount (parentCode, tagCode, tagCount, rows * cols))
+ {
+
+ dng_matrix temp (rows, cols);
+
+ for (uint32 row = 0; row < rows; row++)
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ temp [row] [col] = stream.TagValue_real64 (tagType);
+
+ }
+
+ m = temp;
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool ParseVectorTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint32 count,
+ dng_vector &v)
+ {
+
+ if (CheckTagCount (parentCode, tagCode, tagCount, count))
+ {
+
+ dng_vector temp (count);
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ temp [index] = stream.TagValue_real64 (tagType);
+
+ }
+
+ v = temp;
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool ParseDateTimeTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ dng_date_time &dt)
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
+ {
+ return false;
+ }
+
+ // Kludge: Some versions of PaintShop Pro write these fields
+ // with a length of 21 rather than 20. Otherwise they are
+ // correctly formated. So relax this test and allow these
+ // these longer than standard tags to be parsed.
+
+ (void) CheckTagCount (parentCode, tagCode, tagCount, 20);
+
+ if (tagCount < 20)
+ {
+ return false;
+ }
+
+ char s [21];
+
+ stream.Get (s, 20);
+
+ s [20] = 0;
+
+ // See if this is a valid date/time string.
+
+ if (dt.Parse (s))
+ {
+ return true;
+ }
+
+ // Accept strings that contain only blanks, colons, and zeros as
+ // valid "null" dates.
+
+ dt = dng_date_time ();
+
+ for (uint32 index = 0; index < 21; index++)
+ {
+
+ char c = s [index];
+
+ if (c == 0)
+ {
+ return true;
+ }
+
+ if (c != ' ' && c != ':' && c != '0')
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not a valid date/time",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_parse_utils.h b/gpr/source/lib/dng_sdk/dng_parse_utils.h
new file mode 100644
index 0000000..89a082f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_parse_utils.h
@@ -0,0 +1,232 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_parse_utils.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_parse_utils__
+#define __dng_parse_utils__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_flags.h"
+#include "dng_types.h"
+#include "dng_stream.h"
+#include "dng_string.h"
+#include "dng_matrix.h"
+
+/*****************************************************************************/
+
+#if qDNGValidate
+
+/*****************************************************************************/
+
+const char * LookupParentCode (uint32 parentCode);
+
+/*****************************************************************************/
+
+const char * LookupTagCode (uint32 parentCode,
+ uint32 tagCode);
+
+/*****************************************************************************/
+
+const char * LookupTagType (uint32 tagType);
+
+/*****************************************************************************/
+
+const char * LookupNewSubFileType (uint32 key);
+
+const char * LookupCompression (uint32 key);
+
+const char * LookupPredictor (uint32 key);
+
+const char * LookupSampleFormat (uint32 key);
+
+const char * LookupPhotometricInterpretation (uint32 key);
+
+const char * LookupOrientation (uint32 key);
+
+const char * LookupResolutionUnit (uint32 key);
+
+const char * LookupCFAColor (uint32 key);
+
+const char * LookupSensingMethod (uint32 key);
+
+const char * LookupExposureProgram (uint32 key);
+
+const char * LookupMeteringMode (uint32 key);
+
+const char * LookupLightSource (uint32 key);
+
+const char * LookupColorSpace (uint32 key);
+
+const char * LookupFileSource (uint32 key);
+
+const char * LookupSceneType (uint32 key);
+
+const char * LookupCustomRendered (uint32 key);
+
+const char * LookupExposureMode (uint32 key);
+
+const char * LookupWhiteBalance (uint32 key);
+
+const char * LookupSceneCaptureType (uint32 key);
+
+const char * LookupGainControl (uint32 key);
+
+const char * LookupContrast (uint32 key);
+
+const char * LookupSaturation (uint32 key);
+
+const char * LookupSharpness (uint32 key);
+
+const char * LookupSubjectDistanceRange (uint32 key);
+
+const char * LookupComponent (uint32 key);
+
+const char * LookupCFALayout (uint32 key);
+
+const char * LookupMakerNoteSafety (uint32 key);
+
+const char * LookupColorimetricReference (uint32 key);
+
+const char * LookupPreviewColorSpace (uint32 key);
+
+const char * LookupJPEGMarker (uint32 key);
+
+const char * LookupSensitivityType (uint32 key);
+
+/*****************************************************************************/
+
+void DumpHexAscii (dng_stream &stream,
+ uint32 count);
+
+void DumpHexAscii (const uint8 *buf,
+ uint32 count);
+
+void DumpXMP (dng_stream &stream,
+ uint32 count);
+
+void DumpString (const dng_string &s);
+
+void DumpTagValues (dng_stream &stream,
+ const char *entry_name,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ const char *tag_name = NULL);
+
+void DumpMatrix (const dng_matrix &m);
+
+void DumpVector (const dng_vector &v);
+
+void DumpDateTime (const dng_date_time &dt);
+
+void DumpExposureTime (real64 x);
+
+void DumpFingerprint (const dng_fingerprint &p);
+
+void DumpHueSatMap (dng_stream &stream,
+ uint32 hues,
+ uint32 sats,
+ uint32 vals,
+ bool skipSat0);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+bool CheckTagType (uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint16 validType0,
+ uint16 validType1 = 0,
+ uint16 validType2 = 0,
+ uint16 validType3 = 0);
+
+bool CheckTagCount (uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ uint32 minCount,
+ uint32 maxCount = 0);
+
+bool CheckColorImage (uint32 parentCode,
+ uint32 tagCode,
+ uint32 colorPlanes);
+
+bool CheckMainIFD (uint32 parentCode,
+ uint32 tagCode,
+ uint32 newSubFileType);
+
+bool CheckRawIFD (uint32 parentCode,
+ uint32 tagCode,
+ uint32 photometricInterpretation);
+
+bool CheckCFA (uint32 parentCode,
+ uint32 tagCode,
+ uint32 photometricInterpretation);
+
+/*****************************************************************************/
+
+void ParseStringTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ dng_string &s,
+ bool trimBlanks = true);
+
+void ParseDualStringTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ dng_string &s1,
+ dng_string &s2);
+
+void ParseEncodedStringTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagCount,
+ dng_string &s);
+
+bool ParseMatrixTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint32 rows,
+ uint32 cols,
+ dng_matrix &m);
+
+bool ParseVectorTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint32 count,
+ dng_vector &v);
+
+bool ParseDateTimeTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ dng_date_time &dt);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_pixel_buffer.cpp b/gpr/source/lib/dng_sdk/dng_pixel_buffer.cpp
new file mode 100644
index 0000000..354a774
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_pixel_buffer.cpp
@@ -0,0 +1,1819 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pixel_buffer.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_pixel_buffer.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_tag_types.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+void OptimizeOrder (const void *&sPtr,
+ void *&dPtr,
+ uint32 sPixelSize,
+ uint32 dPixelSize,
+ uint32 &count0,
+ uint32 &count1,
+ uint32 &count2,
+ int32 &sStep0,
+ int32 &sStep1,
+ int32 &sStep2,
+ int32 &dStep0,
+ int32 &dStep1,
+ int32 &dStep2)
+ {
+
+ uint32 step0;
+ uint32 step1;
+ uint32 step2;
+
+ // Optimize the order for the data that is most spread out.
+
+ uint32 sRange = Abs_int32 (sStep0) * (count0 - 1) +
+ Abs_int32 (sStep1) * (count1 - 1) +
+ Abs_int32 (sStep2) * (count2 - 1);
+
+ uint32 dRange = Abs_int32 (dStep0) * (count0 - 1) +
+ Abs_int32 (dStep1) * (count1 - 1) +
+ Abs_int32 (dStep2) * (count2 - 1);
+
+ if (dRange >= sRange)
+ {
+
+ if (dStep0 < 0)
+ {
+
+ sPtr = (const void *)
+ (((const uint8 *) sPtr) + (int32)(count0 - 1) * sStep0 * (int32)sPixelSize);
+
+ dPtr = (void *)
+ (((uint8 *) dPtr) + (int32)(count0 - 1) * dStep0 * (int32)dPixelSize);
+
+ sStep0 = -sStep0;
+ dStep0 = -dStep0;
+
+ }
+
+ if (dStep1 < 0)
+ {
+
+ sPtr = (const void *)
+ (((const uint8 *) sPtr) + (int32)(count1 - 1) * sStep1 * (int32)sPixelSize);
+
+ dPtr = (void *)
+ (((uint8 *) dPtr) + (int32)(count1 - 1) * dStep1 * (int32)dPixelSize);
+
+ sStep1 = -sStep1;
+ dStep1 = -dStep1;
+
+ }
+
+ if (dStep2 < 0)
+ {
+
+ sPtr = (const void *)
+ (((const uint8 *) sPtr) + (int32)(count2 - 1) * sStep2 * (int32)sPixelSize);
+
+ dPtr = (void *)
+ (((uint8 *) dPtr) + (int32)(count2 - 1) * dStep2 * (int32)dPixelSize);
+
+ sStep2 = -sStep2;
+ dStep2 = -dStep2;
+
+ }
+
+ step0 = (uint32) dStep0;
+ step1 = (uint32) dStep1;
+ step2 = (uint32) dStep2;
+
+ }
+
+ else
+ {
+
+ if (sStep0 < 0)
+ {
+
+ sPtr = (const void *)
+ (((const uint8 *) sPtr) + (int32)(count0 - 1) * sStep0 * (int32)sPixelSize);
+
+ dPtr = (void *)
+ (((uint8 *) dPtr) + (int32)(count0 - 1) * dStep0 * (int32)dPixelSize);
+
+ sStep0 = -sStep0;
+ dStep0 = -dStep0;
+
+ }
+
+ if (sStep1 < 0)
+ {
+
+ sPtr = (const void *)
+ (((const uint8 *) sPtr) + (int32)(count1 - 1) * sStep1 * (int32)sPixelSize);
+
+ dPtr = (void *)
+ (((uint8 *) dPtr) + (int32)(count1 - 1) * dStep1 * (int32)dPixelSize);
+
+ sStep1 = -sStep1;
+ dStep1 = -dStep1;
+
+ }
+
+ if (sStep2 < 0)
+ {
+
+ sPtr = (const void *)
+ (((const uint8 *) sPtr) + (int32)(count2 - 1) * sStep2 * (int32)sPixelSize);
+
+ dPtr = (void *)
+ (((uint8 *) dPtr) + (int32)(count2 - 1) * dStep2 * (int32)dPixelSize);
+
+ sStep2 = -sStep2;
+ dStep2 = -dStep2;
+
+ }
+
+ step0 = (uint32) sStep0;
+ step1 = (uint32) sStep1;
+ step2 = (uint32) sStep2;
+
+ }
+
+ if (count0 == 1) step0 = 0xFFFFFFFF;
+ if (count1 == 1) step1 = 0xFFFFFFFF;
+ if (count2 == 1) step2 = 0xFFFFFFFF;
+
+ uint32 index0;
+ uint32 index1;
+ uint32 index2;
+
+ if (step0 >= step1)
+ {
+
+ if (step1 >= step2)
+ {
+ index0 = 0;
+ index1 = 1;
+ index2 = 2;
+ }
+
+ else if (step2 >= step0)
+ {
+ index0 = 2;
+ index1 = 0;
+ index2 = 1;
+ }
+
+ else
+ {
+ index0 = 0;
+ index1 = 2;
+ index2 = 1;
+ }
+
+ }
+
+ else
+ {
+
+ if (step0 >= step2)
+ {
+ index0 = 1;
+ index1 = 0;
+ index2 = 2;
+ }
+
+ else if (step2 >= step1)
+ {
+ index0 = 2;
+ index1 = 1;
+ index2 = 0;
+ }
+
+ else
+ {
+ index0 = 1;
+ index1 = 2;
+ index2 = 0;
+ }
+
+ }
+
+ uint32 count [3];
+
+ count [0] = count0;
+ count [1] = count1;
+ count [2] = count2;
+
+ count0 = count [index0];
+ count1 = count [index1];
+ count2 = count [index2];
+
+ int32 step [3];
+
+ step [0] = sStep0;
+ step [1] = sStep1;
+ step [2] = sStep2;
+
+ sStep0 = step [index0];
+ sStep1 = step [index1];
+ sStep2 = step [index2];
+
+ step [0] = dStep0;
+ step [1] = dStep1;
+ step [2] = dStep2;
+
+ dStep0 = step [index0];
+ dStep1 = step [index1];
+ dStep2 = step [index2];
+
+ if (sStep0 == ((int32) count1) * sStep1 &&
+ dStep0 == ((int32) count1) * dStep1)
+ {
+ count1 *= count0;
+ count0 = 1;
+ }
+
+ if (sStep1 == ((int32) count2) * sStep2 &&
+ dStep1 == ((int32) count2) * dStep2)
+ {
+ count2 *= count1;
+ count1 = 1;
+ }
+
+ }
+
+/*****************************************************************************/
+
+void OptimizeOrder (const void *&sPtr,
+ uint32 sPixelSize,
+ uint32 &count0,
+ uint32 &count1,
+ uint32 &count2,
+ int32 &sStep0,
+ int32 &sStep1,
+ int32 &sStep2)
+ {
+
+ void *dPtr = NULL;
+
+ int32 dStep0 = sStep0;
+ int32 dStep1 = sStep1;
+ int32 dStep2 = sStep2;
+
+ OptimizeOrder (sPtr,
+ dPtr,
+ sPixelSize,
+ sPixelSize,
+ count0,
+ count1,
+ count2,
+ sStep0,
+ sStep1,
+ sStep2,
+ dStep0,
+ dStep1,
+ dStep2);
+
+ }
+
+/*****************************************************************************/
+
+void OptimizeOrder (void *&dPtr,
+ uint32 dPixelSize,
+ uint32 &count0,
+ uint32 &count1,
+ uint32 &count2,
+ int32 &dStep0,
+ int32 &dStep1,
+ int32 &dStep2)
+ {
+
+ const void *sPtr = NULL;
+
+ int32 sStep0 = dStep0;
+ int32 sStep1 = dStep1;
+ int32 sStep2 = dStep2;
+
+ OptimizeOrder (sPtr,
+ dPtr,
+ dPixelSize,
+ dPixelSize,
+ count0,
+ count1,
+ count2,
+ sStep0,
+ sStep1,
+ sStep2,
+ dStep0,
+ dStep1,
+ dStep2);
+
+ }
+
+/*****************************************************************************/
+
+dng_pixel_buffer::dng_pixel_buffer ()
+
+ : fArea ()
+ , fPlane (0)
+ , fPlanes (1)
+ , fRowStep (1)
+ , fColStep (1)
+ , fPlaneStep (1)
+ , fPixelType (ttUndefined)
+ , fPixelSize (0)
+ , fData (NULL)
+ , fDirty (true)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_pixel_buffer::dng_pixel_buffer (const dng_pixel_buffer &buffer)
+
+ : fArea (buffer.fArea)
+ , fPlane (buffer.fPlane)
+ , fPlanes (buffer.fPlanes)
+ , fRowStep (buffer.fRowStep)
+ , fColStep (buffer.fColStep)
+ , fPlaneStep (buffer.fPlaneStep)
+ , fPixelType (buffer.fPixelType)
+ , fPixelSize (buffer.fPixelSize)
+ , fData (buffer.fData)
+ , fDirty (buffer.fDirty)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_pixel_buffer & dng_pixel_buffer::operator= (const dng_pixel_buffer &buffer)
+ {
+
+ fArea = buffer.fArea;
+ fPlane = buffer.fPlane;
+ fPlanes = buffer.fPlanes;
+ fRowStep = buffer.fRowStep;
+ fColStep = buffer.fColStep;
+ fPlaneStep = buffer.fPlaneStep;
+ fPixelType = buffer.fPixelType;
+ fPixelSize = buffer.fPixelSize;
+ fPixelType = buffer.fPixelType;
+ fData = buffer.fData;
+ fDirty = buffer.fDirty;
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+dng_pixel_buffer::~dng_pixel_buffer ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+#if qDebugPixelType
+
+void dng_pixel_buffer::CheckPixelType (uint32 pixelType) const
+ {
+
+ if (fPixelType != pixelType)
+ {
+
+ DNG_REPORT ("Pixel type access mismatch");
+
+ }
+
+ }
+
+#endif
+
+/*****************************************************************************/
+
+uint32 dng_pixel_buffer::PixelRange () const
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ case ttSByte:
+ {
+ return 0x0FF;
+ }
+
+ case ttShort:
+ case ttSShort:
+ {
+ return 0x0FFFF;
+ }
+
+ case ttLong:
+ case ttSLong:
+ {
+ return 0xFFFFFFFF;
+ }
+
+ default:
+ break;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::SetConstant (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint32 value)
+ {
+
+ uint32 rows = area.H ();
+ uint32 cols = area.W ();
+
+ void *dPtr = DirtyPixel (area.t,
+ area.l,
+ plane);
+
+ int32 dRowStep = fRowStep;
+ int32 dColStep = fColStep;
+ int32 dPlaneStep = fPlaneStep;
+
+ OptimizeOrder (dPtr,
+ fPixelSize,
+ rows,
+ cols,
+ planes,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ switch (fPixelSize)
+ {
+
+ case 1:
+ {
+
+ if (rows == 1 && cols == 1 && dPlaneStep == 1 && value == 0)
+ {
+
+ DoZeroBytes (dPtr, planes);
+
+ }
+
+ else
+ {
+
+ DoSetArea8 ((uint8 *) dPtr,
+ (uint8) value,
+ rows,
+ cols,
+ planes,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+ break;
+
+ }
+
+ case 2:
+ {
+
+ if (rows == 1 && cols == 1 && dPlaneStep == 1 && value == 0)
+ {
+
+ DoZeroBytes (dPtr, planes << 1);
+
+ }
+
+ else
+ {
+
+ DoSetArea16 ((uint16 *) dPtr,
+ (uint16) value,
+ rows,
+ cols,
+ planes,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ if (rows == 1 && cols == 1 && dPlaneStep == 1 && value == 0)
+ {
+
+ DoZeroBytes (dPtr, planes << 2);
+
+ }
+
+ else
+ {
+
+ DoSetArea32 ((uint32 *) dPtr,
+ value,
+ rows,
+ cols,
+ planes,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::SetZero (const dng_rect &area,
+ uint32 plane,
+ uint32 planes)
+ {
+
+ uint32 value = 0;
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ case ttShort:
+ case ttLong:
+ case ttFloat:
+ {
+ break;
+ }
+
+ case ttSShort:
+ {
+ value = 0x8000;
+ break;
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ SetConstant (area,
+ plane,
+ planes,
+ value);
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::CopyArea (const dng_pixel_buffer &src,
+ const dng_rect &area,
+ uint32 srcPlane,
+ uint32 dstPlane,
+ uint32 planes)
+ {
+
+ uint32 rows = area.H ();
+ uint32 cols = area.W ();
+
+ const void *sPtr = src.ConstPixel (area.t,
+ area.l,
+ srcPlane);
+
+ void *dPtr = DirtyPixel (area.t,
+ area.l,
+ dstPlane);
+
+ int32 sRowStep = src.fRowStep;
+ int32 sColStep = src.fColStep;
+ int32 sPlaneStep = src.fPlaneStep;
+
+ int32 dRowStep = fRowStep;
+ int32 dColStep = fColStep;
+ int32 dPlaneStep = fPlaneStep;
+
+ OptimizeOrder (sPtr,
+ dPtr,
+ src.fPixelSize,
+ fPixelSize,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ if (fPixelType == src.fPixelType)
+ {
+
+ if (rows == 1 && cols == 1 && sPlaneStep == 1 && dPlaneStep == 1)
+ {
+
+ DoCopyBytes (sPtr,
+ dPtr,
+ planes * fPixelSize);
+
+ }
+
+ else switch (fPixelSize)
+ {
+
+ case 1:
+ {
+
+ DoCopyArea8 ((const uint8 *) sPtr,
+ (uint8 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case 2:
+ {
+
+ DoCopyArea16 ((const uint16 *) sPtr,
+ (uint16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ DoCopyArea32 ((const uint32 *) sPtr,
+ (uint32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+ else if (src.fPixelType == ttByte)
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttShort:
+ {
+
+ DoCopyArea8_16 ((const uint8 *) sPtr,
+ (uint16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttSShort:
+ {
+
+ DoCopyArea8_S16 ((const uint8 *) sPtr,
+ (int16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttLong:
+ {
+
+ DoCopyArea8_32 ((const uint8 *) sPtr,
+ (uint32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttFloat:
+ {
+
+ DoCopyArea8_R32 ((const uint8 *) sPtr,
+ (real32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ src.PixelRange ());
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+ else if (src.fPixelType == ttShort)
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ {
+
+ DoCopyArea8 (((const uint8 *) sPtr) + (qDNGBigEndian ? 1 : 0),
+ (uint8 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep << 1,
+ sColStep << 1,
+ sPlaneStep << 1,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttSShort:
+ {
+
+ DoCopyArea16_S16 ((const uint16 *) sPtr,
+ (int16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttLong:
+ {
+
+ DoCopyArea16_32 ((const uint16 *) sPtr,
+ (uint32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttFloat:
+ {
+
+ DoCopyArea16_R32 ((const uint16 *) sPtr,
+ (real32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ src.PixelRange ());
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+ else if (src.fPixelType == ttSShort)
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ {
+
+ DoCopyArea8 (((const uint8 *) sPtr) + (qDNGBigEndian ? 1 : 0),
+ (uint8 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep << 1,
+ sColStep << 1,
+ sPlaneStep << 1,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttShort:
+ {
+
+ // Moving between signed 16 bit values and unsigned 16
+ // bit values just requires toggling the sign bit. So
+ // we can use the "backwards" bottleneck.
+
+ DoCopyArea16_S16 ((const uint16 *) sPtr,
+ (int16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttFloat:
+ {
+
+ DoCopyAreaS16_R32 ((const int16 *) sPtr,
+ (real32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ src.PixelRange ());
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+ else if (src.fPixelType == ttLong)
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ {
+
+ DoCopyArea8 (((const uint8 *) sPtr) + (qDNGBigEndian ? 3 : 0),
+ (uint8 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep << 2,
+ sColStep << 2,
+ sPlaneStep << 2,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case ttShort:
+ {
+
+ DoCopyArea16 (((const uint16 *) sPtr) + (qDNGBigEndian ? 1 : 0),
+ (uint16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep << 1,
+ sColStep << 1,
+ sPlaneStep << 1,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+ else if (src.fPixelType == ttFloat)
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ {
+
+ DoCopyAreaR32_8 ((const real32 *) sPtr,
+ (uint8 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ PixelRange ());
+
+ break;
+
+ }
+
+ case ttShort:
+ {
+
+ DoCopyAreaR32_16 ((const real32 *) sPtr,
+ (uint16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ PixelRange ());
+
+ break;
+
+ }
+
+ case ttSShort:
+ {
+
+ DoCopyAreaR32_S16 ((const real32 *) sPtr,
+ (int16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ PixelRange ());
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_pixel_buffer::RepeatPhase (const dng_rect &srcArea,
+ const dng_rect &dstArea)
+ {
+
+ int32 repeatV = srcArea.H ();
+ int32 repeatH = srcArea.W ();
+
+ int32 phaseV;
+ int32 phaseH;
+
+ if (srcArea.t >= dstArea.t)
+ {
+ phaseV = (repeatV - ((srcArea.t - dstArea.t) % repeatV)) % repeatV;
+ }
+ else
+ {
+ phaseV = (dstArea.t - srcArea.t) % repeatV;
+ }
+
+ if (srcArea.l >= dstArea.l)
+ {
+ phaseH = (repeatH - ((srcArea.l - dstArea.l) % repeatH)) % repeatH;
+ }
+ else
+ {
+ phaseH = (dstArea.l - srcArea.l) % repeatH;
+ }
+
+ return dng_point (phaseV, phaseH);
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::RepeatArea (const dng_rect &srcArea,
+ const dng_rect &dstArea)
+ {
+
+ dng_point repeat = srcArea.Size ();
+
+ dng_point phase = RepeatPhase (srcArea,
+ dstArea);
+
+ const void *sPtr = ConstPixel (srcArea.t,
+ srcArea.l,
+ fPlane);
+
+ void *dPtr = DirtyPixel (dstArea.t,
+ dstArea.l,
+ fPlane);
+
+ uint32 rows = dstArea.H ();
+ uint32 cols = dstArea.W ();
+
+ switch (fPixelSize)
+ {
+
+ case 1:
+ {
+
+ DoRepeatArea8 ((const uint8 *) sPtr,
+ (uint8 *) dPtr,
+ rows,
+ cols,
+ fPlanes,
+ fRowStep,
+ fColStep,
+ fPlaneStep,
+ repeat.v,
+ repeat.h,
+ phase.v,
+ phase.h);
+
+ break;
+
+ }
+
+ case 2:
+ {
+
+ DoRepeatArea16 ((const uint16 *) sPtr,
+ (uint16 *) dPtr,
+ rows,
+ cols,
+ fPlanes,
+ fRowStep,
+ fColStep,
+ fPlaneStep,
+ repeat.v,
+ repeat.h,
+ phase.v,
+ phase.h);
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ DoRepeatArea32 ((const uint32 *) sPtr,
+ (uint32 *) dPtr,
+ rows,
+ cols,
+ fPlanes,
+ fRowStep,
+ fColStep,
+ fPlaneStep,
+ repeat.v,
+ repeat.h,
+ phase.v,
+ phase.h);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::RepeatSubArea (const dng_rect subArea,
+ uint32 repeatV,
+ uint32 repeatH)
+ {
+
+ if (fArea.t < subArea.t)
+ {
+
+ RepeatArea (dng_rect (subArea.t , fArea.l,
+ subArea.t + repeatV, fArea.r),
+ dng_rect (fArea.t , fArea.l,
+ subArea.t , fArea.r));
+
+ }
+
+ if (fArea.b > subArea.b)
+ {
+
+ RepeatArea (dng_rect (subArea.b - repeatV, fArea.l,
+ subArea.b , fArea.r),
+ dng_rect (subArea.b , fArea.l,
+ fArea.b , fArea.r));
+
+ }
+
+ if (fArea.l < subArea.l)
+ {
+
+ RepeatArea (dng_rect (fArea.t, subArea.l ,
+ fArea.b, subArea.l + repeatH),
+ dng_rect (fArea.t, fArea.l ,
+ fArea.b, subArea.l ));
+
+ }
+
+ if (fArea.r > subArea.r)
+ {
+
+ RepeatArea (dng_rect (fArea.t, subArea.r - repeatH,
+ fArea.b, subArea.r ),
+ dng_rect (fArea.t, subArea.r ,
+ fArea.b, fArea.r ));
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::ShiftRight (uint32 shift)
+ {
+
+ if (fPixelType != ttShort)
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+ uint32 rows = fArea.H ();
+ uint32 cols = fArea.W ();
+
+ uint32 planes = fPlanes;
+
+ void *dPtr = DirtyPixel (fArea.t,
+ fArea.l,
+ fPlane);
+
+ const void *sPtr = dPtr;
+
+ int32 sRowStep = fRowStep;
+ int32 sColStep = fColStep;
+ int32 sPlaneStep = fPlaneStep;
+
+ int32 dRowStep = fRowStep;
+ int32 dColStep = fColStep;
+ int32 dPlaneStep = fPlaneStep;
+
+ OptimizeOrder (sPtr,
+ dPtr,
+ fPixelSize,
+ fPixelSize,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ DoShiftRight16 ((uint16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ dRowStep,
+ dColStep,
+ dPlaneStep,
+ shift);
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::FlipH ()
+ {
+
+ fData = InternalPixel (fArea.t, fArea.r - 1);
+
+ fColStep = -fColStep;
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::FlipV ()
+ {
+
+ fData = InternalPixel (fArea.b - 1, fArea.l);
+
+ fRowStep = -fRowStep;
+
+ }
+
+/*****************************************************************************/
+
+void dng_pixel_buffer::FlipZ ()
+ {
+
+ fData = InternalPixel (fArea.t, fArea.l, fPlanes - 1);
+
+ fPlaneStep = -fPlaneStep;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_pixel_buffer::EqualArea (const dng_pixel_buffer &src,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes) const
+ {
+
+ uint32 rows = area.H ();
+ uint32 cols = area.W ();
+
+ const void *sPtr = src.ConstPixel (area.t,
+ area.l,
+ plane);
+
+ const void *dPtr = ConstPixel (area.t,
+ area.l,
+ plane);
+
+ int32 sRowStep = src.fRowStep;
+ int32 sColStep = src.fColStep;
+ int32 sPlaneStep = src.fPlaneStep;
+
+ int32 dRowStep = fRowStep;
+ int32 dColStep = fColStep;
+ int32 dPlaneStep = fPlaneStep;
+
+ if (fPixelType == src.fPixelType)
+ {
+
+ if (rows == 1 && cols == 1 && sPlaneStep == 1 && dPlaneStep == 1)
+ {
+
+ return DoEqualBytes (sPtr,
+ dPtr,
+ planes * fPixelSize);
+
+ }
+
+ else switch (fPixelSize)
+ {
+
+ case 1:
+ {
+
+ return DoEqualArea8 ((const uint8 *) sPtr,
+ (const uint8 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case 2:
+ {
+
+ return DoEqualArea16 ((const uint16 *) sPtr,
+ (const uint16 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ return DoEqualArea32 ((const uint32 *) sPtr,
+ (const uint32 *) dPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sColStep,
+ sPlaneStep,
+ dRowStep,
+ dColStep,
+ dPlaneStep);
+
+ break;
+
+ }
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ else
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+namespace
+ {
+
+ template <typename T>
+ real64 MaxDiff (const T *src1,
+ int32 s1RowStep,
+ int32 s1PlaneStep,
+ const T *src2,
+ int32 s2RowStep,
+ int32 s2PlaneStep,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes)
+ {
+
+ real64 result = 0.0;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ const T *src1Save = src1;
+ const T *src2Save = src2;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+ real64 diff = fabs ((real64)src1 [col] - src2 [col]);
+
+ if (diff > result)
+ result = diff;
+
+ }
+
+ src1 += s1RowStep;
+ src2 += s2RowStep;
+
+ }
+
+ src1 = src1Save + s1PlaneStep;
+ src2 = src2Save + s2PlaneStep;
+
+ }
+
+ return result;
+
+ }
+
+ template <typename T>
+ real64 MaxDiff (const T *src1,
+ int32 s1ColStep,
+ int32 s1RowStep,
+ int32 s1PlaneStep,
+ const T *src2,
+ int32 s2ColStep,
+ int32 s2RowStep,
+ int32 s2PlaneStep,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes)
+ {
+
+ if (s1ColStep == s2ColStep &&
+ s1ColStep == 1)
+ return MaxDiff (src1,
+ s1RowStep,
+ s1PlaneStep,
+ src2,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ real64 result = 0.0;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ const T *src1Save = src1;
+ const T *src2Save = src2;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+ real64 diff = fabs ((real64)src1 [col * s1ColStep] - src2 [col * s2ColStep]);
+
+ if (diff > result)
+ result = diff;
+
+ }
+
+ src1 += s1RowStep;
+ src2 += s2RowStep;
+
+ }
+
+ src1 = src1Save + s1PlaneStep;
+ src2 = src2Save + s2PlaneStep;
+
+ }
+
+
+ return result;
+
+ }
+ }
+
+real64 dng_pixel_buffer::MaximumDifference (const dng_pixel_buffer &rhs,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes) const
+ {
+
+ uint32 rows = area.H ();
+ uint32 cols = area.W ();
+
+ const void *s1Ptr = rhs.ConstPixel (area.t,
+ area.l,
+ plane);
+
+ const void *s2Ptr = ConstPixel (area.t,
+ area.l,
+ plane);
+
+ int32 s1RowStep = rhs.fRowStep;
+ int32 s1ColStep = rhs.fColStep;
+ int32 s1PlaneStep = rhs.fPlaneStep;
+
+ int32 s2RowStep = fRowStep;
+ int32 s2ColStep = fColStep;
+ int32 s2PlaneStep = fPlaneStep;
+
+ if (fPixelType == rhs.fPixelType)
+ {
+
+ switch (fPixelType)
+ {
+
+ case ttByte:
+ return MaxDiff ((const uint8 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const uint8 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttShort:
+ return MaxDiff ((const uint16 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const uint16 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttLong:
+ return MaxDiff ((const uint32 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const uint32 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttSByte:
+ return MaxDiff ((const int8 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const int8 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttSShort:
+ return MaxDiff ((const int16 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const int16 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttSLong:
+ return MaxDiff ((const int32 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const int32 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttFloat:
+ return MaxDiff ((const real32 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const real32 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+ case ttDouble:
+ return MaxDiff ((const real64 *)s1Ptr,
+ s1ColStep,
+ s1RowStep,
+ s1PlaneStep,
+ (const real64 *)s2Ptr,
+ s2ColStep,
+ s2RowStep,
+ s2PlaneStep,
+ rows,
+ cols,
+ planes);
+
+ break;
+
+
+ default:
+ {
+
+ ThrowNotYetImplemented ();
+
+ return 0.0;
+
+ }
+
+ }
+
+ }
+
+ else
+ ThrowProgramError ("attempt to difference pixel buffers of different formats.");
+
+ return 0.0;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_pixel_buffer.h b/gpr/source/lib/dng_sdk/dng_pixel_buffer.h
new file mode 100644
index 0000000..346d5be
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_pixel_buffer.h
@@ -0,0 +1,680 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pixel_buffer.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for holding buffers of sample data.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_pixel_buffer__
+#define __dng_pixel_buffer__
+
+/*****************************************************************************/
+
+#include "dng_assertions.h"
+#include "dng_rect.h"
+#include "dng_tag_types.h"
+
+/*****************************************************************************/
+
+/// Compute best set of step values for a given source and destination area and stride.
+
+void OptimizeOrder (const void *&sPtr,
+ void *&dPtr,
+ uint32 sPixelSize,
+ uint32 dPixelSize,
+ uint32 &count0,
+ uint32 &count1,
+ uint32 &count2,
+ int32 &sStep0,
+ int32 &sStep1,
+ int32 &sStep2,
+ int32 &dStep0,
+ int32 &dStep1,
+ int32 &dStep2);
+
+void OptimizeOrder (const void *&sPtr,
+ uint32 sPixelSize,
+ uint32 &count0,
+ uint32 &count1,
+ uint32 &count2,
+ int32 &sStep0,
+ int32 &sStep1,
+ int32 &sStep2);
+
+void OptimizeOrder (void *&dPtr,
+ uint32 dPixelSize,
+ uint32 &count0,
+ uint32 &count1,
+ uint32 &count2,
+ int32 &dStep0,
+ int32 &dStep1,
+ int32 &dStep2);
+
+/*****************************************************************************/
+
+#define qDebugPixelType 0
+
+#if qDebugPixelType
+
+#define ASSERT_PIXEL_TYPE(typeVal) CheckPixelType (typeVal)
+
+#else
+
+#define ASSERT_PIXEL_TYPE(typeVal) DNG_ASSERT (fPixelType == typeVal, "Pixel type access mismatch")
+
+#endif
+
+/*****************************************************************************/
+
+/// \brief Holds a buffer of pixel data with "pixel geometry" metadata.
+///
+/// The pixel geometry describes the layout in terms of how many planes, rows and columns
+/// plus the steps (in bytes) between each column, row and plane.
+
+class dng_pixel_buffer
+ {
+
+ public:
+
+ // Area this buffer holds.
+
+ dng_rect fArea;
+
+ // Range of planes this buffer holds.
+
+ uint32 fPlane;
+ uint32 fPlanes;
+
+ // Steps between pixels.
+
+ int32 fRowStep;
+ int32 fColStep;
+ int32 fPlaneStep;
+
+ // Basic pixel type (TIFF tag type code).
+
+ uint32 fPixelType;
+
+ // Size of pixel type in bytes.
+
+ uint32 fPixelSize;
+
+ // Pointer to buffer's data.
+
+ void *fData;
+
+ // Do we have write-access to this data?
+
+ bool fDirty;
+
+ private:
+
+ void * InternalPixel (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ return (void *)
+ (((uint8 *) fData) + (int32)fPixelSize *
+ (fRowStep * (row - fArea.t) +
+ fColStep * (col - fArea.l) +
+ fPlaneStep * (int32)(plane - fPlane )));
+
+ }
+
+ #if qDebugPixelType
+
+ void CheckPixelType (uint32 pixelType) const;
+
+ #endif
+
+ public:
+
+ dng_pixel_buffer ();
+
+ dng_pixel_buffer (const dng_pixel_buffer &buffer);
+
+ dng_pixel_buffer & operator= (const dng_pixel_buffer &buffer);
+
+ virtual ~dng_pixel_buffer ();
+
+ /// Get the range of pixel values.
+ /// \retval Range of value a pixel can take. (Meaning [0, max] for unsigned case. Signed case is biased so [-32768, max - 32768].)
+
+ uint32 PixelRange () const;
+
+ /// Get extent of pixels in buffer
+ /// \retval Rectangle giving valid extent of buffer.
+
+ const dng_rect & Area () const
+ {
+ return fArea;
+ }
+
+ /// Number of planes of image data.
+ /// \retval Number of planes held in buffer.
+
+ uint32 Planes () const
+ {
+ return fPlanes;
+ }
+
+ /// Step, in pixels not bytes, between rows of data in buffer.
+ /// \retval row step in pixels. May be negative.
+
+ int32 RowStep () const
+ {
+ return fRowStep;
+ }
+
+ /// Step, in pixels not bytes, between planes of data in buffer.
+ /// \retval plane step in pixels. May be negative.
+
+ int32 PlaneStep () const
+ {
+ return fPlaneStep;
+ }
+
+ /// Get read-only untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as void *.
+
+ const void * ConstPixel (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ return InternalPixel (row, col, plane);
+
+ }
+
+ /// Get a writable untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as void *.
+
+ void * DirtyPixel (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ DNG_ASSERT (fDirty, "Dirty access to const pixel buffer");
+
+ return InternalPixel (row, col, plane);
+
+ }
+
+ /// Get read-only uint8 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as uint8 *.
+
+ const uint8 * ConstPixel_uint8 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttByte);
+
+ return (const uint8 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable uint8 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as uint8 *.
+
+ uint8 * DirtyPixel_uint8 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttByte);
+
+ return (uint8 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Get read-only int8 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as int8 *.
+
+ const int8 * ConstPixel_int8 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttSByte);
+
+ return (const int8 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable int8 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as int8 *.
+
+ int8 * DirtyPixel_int8 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttSByte);
+
+ return (int8 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Get read-only uint16 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as uint16 *.
+
+ const uint16 * ConstPixel_uint16 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttShort);
+
+ return (const uint16 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable uint16 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as uint16 *.
+
+ uint16 * DirtyPixel_uint16 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttShort);
+
+ return (uint16 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Get read-only int16 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as int16 *.
+
+ const int16 * ConstPixel_int16 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttSShort);
+
+ return (const int16 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable int16 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as int16 *.
+
+ int16 * DirtyPixel_int16 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttSShort);
+
+ return (int16 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Get read-only uint32 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as uint32 *.
+
+ const uint32 * ConstPixel_uint32 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttLong);
+
+ return (const uint32 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable uint32 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as uint32 *.
+
+ uint32 * DirtyPixel_uint32 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttLong);
+
+ return (uint32 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Get read-only int32 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as int32 *.
+
+ const int32 * ConstPixel_int32 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttSLong);
+
+ return (const int32 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable int32 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as int32 *.
+
+ int32 * DirtyPixel_int32 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttSLong);
+
+ return (int32 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Get read-only real32 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as real32 *.
+
+ const real32 * ConstPixel_real32 (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ ASSERT_PIXEL_TYPE (ttFloat);
+
+ return (const real32 *) ConstPixel (row, col, plane);
+
+ }
+
+ /// Get a writable real32 * to pixel data starting at a specific pixel in the buffer.
+ /// \param row Start row for buffer pointer.
+ /// \param col Start column for buffer pointer.
+ /// \param plane Start plane for buffer pointer.
+ /// \retval Pointer to pixel data as real32 *.
+
+ real32 * DirtyPixel_real32 (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ ASSERT_PIXEL_TYPE (ttFloat);
+
+ return (real32 *) DirtyPixel (row, col, plane);
+
+ }
+
+ /// Initialize a rectangular area of pixel buffer to a constant.
+ /// \param area Rectangle of pixel buffer to set.
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+ /// \param value Constant value to set pixels to.
+
+ void SetConstant (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint32 value);
+
+ /// Initialize a rectangular area of pixel buffer to a constant unsigned 8-bit value.
+ /// \param area Rectangle of pixel buffer to set.
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+ /// \param value Constant uint8 value to set pixels to.
+
+ void SetConstant_uint8 (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint8 value)
+ {
+
+ DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");
+
+ SetConstant (area, plane, planes, (uint32) value);
+
+ }
+
+ /// Initialize a rectangular area of pixel buffer to a constant unsigned 16-bit value.
+ /// \param area Rectangle of pixel buffer to set.
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+ /// \param value Constant uint16 value to set pixels to.
+
+ void SetConstant_uint16 (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint16 value)
+ {
+
+ DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");
+
+ SetConstant (area, plane, planes, (uint32) value);
+
+ }
+
+ /// Initialize a rectangular area of pixel buffer to a constant signed 16-bit value.
+ /// \param area Rectangle of pixel buffer to set.
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+ /// \param value Constant int16 value to set pixels to.
+
+ void SetConstant_int16 (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ int16 value)
+ {
+
+ DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");
+
+ SetConstant (area, plane, planes, (uint32) (uint16) value);
+
+ }
+
+ /// Initialize a rectangular area of pixel buffer to a constant unsigned 32-bit value.
+ /// \param area Rectangle of pixel buffer to set.
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+ /// \param value Constant uint32 value to set pixels to.
+
+ void SetConstant_uint32 (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint32 value)
+ {
+
+ DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");
+
+ SetConstant (area, plane, planes, value);
+
+ }
+
+ /// Initialize a rectangular area of pixel buffer to a constant real 32-bit value.
+ /// \param area Rectangle of pixel buffer to set.
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+ /// \param value Constant real32 value to set pixels to.
+
+ void SetConstant_real32 (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ real32 value)
+ {
+
+ DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");
+
+ union
+ {
+ uint32 i;
+ real32 f;
+ } x;
+
+ x.f = value;
+
+ SetConstant (area, plane, planes, x.i);
+
+ }
+
+ /// Initialize a rectangular area of pixel buffer to zeros.
+ /// \param area Rectangle of pixel buffer to zero.
+ /// \param area Area to zero
+ /// \param plane Plane to start filling on.
+ /// \param planes Number of planes to fill.
+
+ void SetZero (const dng_rect &area,
+ uint32 plane,
+ uint32 planes);
+
+ /// Copy image data from an area of one pixel buffer to same area of another.
+ /// \param src Buffer to copy from.
+ /// \param area Rectangle of pixel buffer to copy.
+ /// \param srcPlane Plane to start copy in src.
+ /// \param dstPlane Plane to start copy in dst.
+ /// \param planes Number of planes to copy.
+
+ void CopyArea (const dng_pixel_buffer &src,
+ const dng_rect &area,
+ uint32 srcPlane,
+ uint32 dstPlane,
+ uint32 planes);
+
+ /// Copy image data from an area of one pixel buffer to same area of another.
+ /// \param src Buffer to copy from.
+ /// \param area Rectangle of pixel buffer to copy.
+ /// \param plane Plane to start copy in src and this.
+ /// \param planes Number of planes to copy.
+
+ void CopyArea (const dng_pixel_buffer &src,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes)
+ {
+
+ CopyArea (src, area, plane, plane, planes);
+
+ }
+
+ /// Calculate the offset phase of destination rectangle relative to source rectangle.
+ /// Phase is based on a 0,0 origin and the notion of repeating srcArea across dstArea.
+ /// It is the number of pixels into srcArea to start repeating from when tiling dstArea.
+ /// \retval dng_point containing horizontal and vertical phase.
+
+ static dng_point RepeatPhase (const dng_rect &srcArea,
+ const dng_rect &dstArea);
+
+ /// Repeat the image data in srcArea across dstArea.
+ /// (Generally used for padding operations.)
+ /// \param srcArea Area to repeat from.
+ /// \param dstArea Area to fill with data from srcArea.
+
+ void RepeatArea (const dng_rect &srcArea,
+ const dng_rect &dstArea);
+
+ /// Replicates a sub-area of a buffer to fill the entire buffer.
+
+ void RepeatSubArea (const dng_rect subArea,
+ uint32 repeatV = 1,
+ uint32 repeatH = 1);
+
+ /// Apply a right shift (C++ oerpator >>) to all pixel values. Only implemented for 16-bit (signed or unsigned) pixel buffers.
+ /// \param shift Number of bits by which to right shift each pixel value.
+
+ void ShiftRight (uint32 shift);
+
+ /// Change metadata so pixels are iterated in opposite horizontal order.
+ /// This operation does not require movement of actual pixel data.
+
+ void FlipH ();
+
+ /// Change metadata so pixels are iterated in opposite vertical order.
+ /// This operation does not require movement of actual pixel data.
+
+ void FlipV ();
+
+ /// Change metadata so pixels are iterated in opposite plane order.
+ /// This operation does not require movement of actual pixel data.
+
+ void FlipZ (); // Flip planes
+
+ /// Return true if the contents of an area of the pixel buffer area are the same as those of another.
+ /// \param rhs Buffer to compare against.
+ /// \param area Rectangle of pixel buffer to test.
+ /// \param plane Plane to start comparing.
+ /// \param planes Number of planes to compare.
+ /// \retval bool true if areas are equal, false otherwise.
+
+ bool EqualArea (const dng_pixel_buffer &rhs,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes) const;
+
+ /// Return the absolute value of the maximum difference between two pixel buffers. Used for comparison testing with tolerance
+ /// \param rhs Buffer to compare against.
+ /// \param area Rectangle of pixel buffer to test.
+ /// \param plane Plane to start comparing.
+ /// \param planes Number of planes to compare.
+ /// \retval larges absolute value difference between the corresponding pixels each buffer across area.
+
+ real64 MaximumDifference (const dng_pixel_buffer &rhs,
+ const dng_rect &area,
+ uint32 plane,
+ uint32 planes) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_point.cpp b/gpr/source/lib/dng_sdk/dng_point.cpp
new file mode 100644
index 0000000..abfd7dd
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_point.cpp
@@ -0,0 +1,22 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_point.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_point.h"
+
+/*****************************************************************************/
+
+// Currently all inlined.
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_point.h b/gpr/source/lib/dng_sdk/dng_point.h
new file mode 100644
index 0000000..476a71d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_point.h
@@ -0,0 +1,198 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_point.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_point__
+#define __dng_point__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+class dng_point
+ {
+
+ public:
+
+ int32 v;
+ int32 h;
+
+ public:
+
+ dng_point ()
+ : v (0)
+ , h (0)
+ {
+ }
+
+ dng_point (int32 vv, int32 hh)
+ : v (vv)
+ , h (hh)
+ {
+ }
+
+ bool operator== (const dng_point &pt) const
+ {
+ return (v == pt.v) &&
+ (h == pt.h);
+ }
+
+ bool operator!= (const dng_point &pt) const
+ {
+ return !(*this == pt);
+ }
+
+ };
+
+/*****************************************************************************/
+
+class dng_point_real64
+ {
+
+ public:
+
+ real64 v;
+ real64 h;
+
+ public:
+
+ dng_point_real64 ()
+ : v (0.0)
+ , h (0.0)
+ {
+ }
+
+ dng_point_real64 (real64 vv, real64 hh)
+ : v (vv)
+ , h (hh)
+ {
+ }
+
+ dng_point_real64 (const dng_point &pt)
+ : v ((real64) pt.v)
+ , h ((real64) pt.h)
+ {
+ }
+
+ bool operator== (const dng_point_real64 &pt) const
+ {
+ return (v == pt.v) &&
+ (h == pt.h);
+ }
+
+ bool operator!= (const dng_point_real64 &pt) const
+ {
+ return !(*this == pt);
+ }
+
+ dng_point Round () const
+ {
+ return dng_point (Round_int32 (v),
+ Round_int32 (h));
+ }
+
+ };
+
+/*****************************************************************************/
+
+inline dng_point operator+ (const dng_point &a,
+ const dng_point &b)
+
+
+ {
+
+ return dng_point (a.v + b.v,
+ a.h + b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point_real64 operator+ (const dng_point_real64 &a,
+ const dng_point_real64 &b)
+
+
+ {
+
+ return dng_point_real64 (a.v + b.v,
+ a.h + b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point operator- (const dng_point &a,
+ const dng_point &b)
+
+
+ {
+
+ return dng_point (a.v - b.v,
+ a.h - b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point_real64 operator- (const dng_point_real64 &a,
+ const dng_point_real64 &b)
+
+
+ {
+
+ return dng_point_real64 (a.v - b.v,
+ a.h - b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline real64 DistanceSquared (const dng_point_real64 &a,
+ const dng_point_real64 &b)
+
+
+ {
+
+ dng_point_real64 diff = a - b;
+
+ return (diff.v * diff.v) + (diff.h * diff.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point Transpose (const dng_point &a)
+ {
+
+ return dng_point (a.h, a.v);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point_real64 Transpose (const dng_point_real64 &a)
+ {
+
+ return dng_point_real64 (a.h, a.v);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_preview.cpp b/gpr/source/lib/dng_sdk/dng_preview.cpp
new file mode 100644
index 0000000..1a65cb0
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_preview.cpp
@@ -0,0 +1,709 @@
+/*****************************************************************************/
+// Copyright 2007-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_preview.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_preview.h"
+
+#include "dng_assertions.h"
+#include "dng_image.h"
+#include "dng_image_writer.h"
+#include "dng_memory.h"
+#include "dng_stream.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_values.h"
+
+/*****************************************************************************/
+
+class dng_preview_tag_set: public dng_basic_tag_set
+ {
+
+ private:
+
+ tag_string fApplicationNameTag;
+
+ tag_string fApplicationVersionTag;
+
+ tag_string fSettingsNameTag;
+
+ dng_fingerprint fSettingsDigest;
+
+ tag_uint8_ptr fSettingsDigestTag;
+
+ tag_uint32 fColorSpaceTag;
+
+ tag_string fDateTimeTag;
+
+ tag_real64 fRawToPreviewGainTag;
+
+ tag_uint32 fCacheVersionTag;
+
+ public:
+
+ dng_preview_tag_set (dng_tiff_directory &directory,
+ const dng_preview &preview,
+ const dng_ifd &ifd);
+
+ virtual ~dng_preview_tag_set ();
+
+ };
+
+/*****************************************************************************/
+
+dng_preview_tag_set::dng_preview_tag_set (dng_tiff_directory &directory,
+ const dng_preview &preview,
+ const dng_ifd &ifd)
+
+ : dng_basic_tag_set (directory, ifd)
+
+ , fApplicationNameTag (tcPreviewApplicationName,
+ preview.fInfo.fApplicationName,
+ false)
+
+ , fApplicationVersionTag (tcPreviewApplicationVersion,
+ preview.fInfo.fApplicationVersion,
+ false)
+
+ , fSettingsNameTag (tcPreviewSettingsName,
+ preview.fInfo.fSettingsName,
+ false)
+
+ , fSettingsDigest (preview.fInfo.fSettingsDigest)
+
+ , fSettingsDigestTag (tcPreviewSettingsDigest,
+ fSettingsDigest.data,
+ 16)
+
+ , fColorSpaceTag (tcPreviewColorSpace,
+ preview.fInfo.fColorSpace)
+
+ , fDateTimeTag (tcPreviewDateTime,
+ preview.fInfo.fDateTime,
+ true)
+
+ , fRawToPreviewGainTag (tcRawToPreviewGain,
+ preview.fInfo.fRawToPreviewGain)
+
+ , fCacheVersionTag (tcCacheVersion,
+ preview.fInfo.fCacheVersion)
+
+ {
+
+ if (preview.fInfo.fApplicationName.NotEmpty ())
+ {
+
+ directory.Add (&fApplicationNameTag);
+
+ }
+
+ if (preview.fInfo.fApplicationVersion.NotEmpty ())
+ {
+
+ directory.Add (&fApplicationVersionTag);
+
+ }
+
+ if (preview.fInfo.fSettingsName.NotEmpty ())
+ {
+
+ directory.Add (&fSettingsNameTag);
+
+ }
+
+ if (preview.fInfo.fSettingsDigest.IsValid ())
+ {
+
+ directory.Add (&fSettingsDigestTag);
+
+ }
+
+ if (preview.fInfo.fColorSpace != previewColorSpace_MaxEnum)
+ {
+
+ directory.Add (&fColorSpaceTag);
+
+ }
+
+ if (preview.fInfo.fDateTime.NotEmpty ())
+ {
+
+ directory.Add (&fDateTimeTag);
+
+ }
+
+ if (preview.fInfo.fRawToPreviewGain != 1.0)
+ {
+
+ directory.Add (&fRawToPreviewGainTag);
+
+ }
+
+ if (preview.fInfo.fCacheVersion != 0)
+ {
+
+ directory.Add (&fCacheVersionTag);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_preview_tag_set::~dng_preview_tag_set ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_preview::dng_preview ()
+
+ : fInfo ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_preview::~dng_preview ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_image_preview::dng_image_preview ()
+
+ : fImage ()
+ , fIFD ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_image_preview::~dng_image_preview ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_basic_tag_set * dng_image_preview::AddTagSet (dng_tiff_directory &directory) const
+ {
+
+ fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage
+ : sfAltPreviewImage;
+
+ fIFD.fImageWidth = fImage->Width ();
+ fIFD.fImageLength = fImage->Height ();
+
+ fIFD.fSamplesPerPixel = fImage->Planes ();
+
+ fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero
+ : piRGB;
+
+ fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8;
+
+ for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++)
+ {
+ fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0];
+ }
+
+ fIFD.SetSingleStrip ();
+
+ return new dng_preview_tag_set (directory, *this, fIFD);
+
+ }
+
+/*****************************************************************************/
+
+void dng_image_preview::WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const
+ {
+
+ writer.WriteImage (host,
+ fIFD,
+ basic,
+ stream,
+ *fImage.Get ());
+
+ }
+
+/*****************************************************************************/
+
+class dng_jpeg_preview_tag_set: public dng_preview_tag_set
+ {
+
+ private:
+
+ dng_urational fCoefficientsData [3];
+
+ tag_urational_ptr fCoefficientsTag;
+
+ uint16 fSubSamplingData [2];
+
+ tag_uint16_ptr fSubSamplingTag;
+
+ tag_uint16 fPositioningTag;
+
+ dng_urational fReferenceData [6];
+
+ tag_urational_ptr fReferenceTag;
+
+ public:
+
+ dng_jpeg_preview_tag_set (dng_tiff_directory &directory,
+ const dng_jpeg_preview &preview,
+ const dng_ifd &ifd);
+
+ virtual ~dng_jpeg_preview_tag_set ();
+
+ };
+
+/******************************************************************************/
+
+dng_jpeg_preview_tag_set::dng_jpeg_preview_tag_set (dng_tiff_directory &directory,
+ const dng_jpeg_preview &preview,
+ const dng_ifd &ifd)
+
+ : dng_preview_tag_set (directory, preview, ifd)
+
+ , fCoefficientsTag (tcYCbCrCoefficients, fCoefficientsData, 3)
+
+ , fSubSamplingTag (tcYCbCrSubSampling, fSubSamplingData, 2)
+
+ , fPositioningTag (tcYCbCrPositioning, preview.fYCbCrPositioning)
+
+ , fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6)
+
+ {
+
+ if (preview.fPhotometricInterpretation == piYCbCr)
+ {
+
+ fCoefficientsData [0] = dng_urational (299, 1000);
+ fCoefficientsData [1] = dng_urational (587, 1000);
+ fCoefficientsData [2] = dng_urational (114, 1000);
+
+ directory.Add (&fCoefficientsTag);
+
+ fSubSamplingData [0] = (uint16) preview.fYCbCrSubSampling.h;
+ fSubSamplingData [1] = (uint16) preview.fYCbCrSubSampling.v;
+
+ directory.Add (&fSubSamplingTag);
+
+ directory.Add (&fPositioningTag);
+
+ fReferenceData [0] = dng_urational ( 0, 1);
+ fReferenceData [1] = dng_urational (255, 1);
+ fReferenceData [2] = dng_urational (128, 1);
+ fReferenceData [3] = dng_urational (255, 1);
+ fReferenceData [4] = dng_urational (128, 1);
+ fReferenceData [5] = dng_urational (255, 1);
+
+ directory.Add (&fReferenceTag);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_jpeg_preview::dng_jpeg_preview ()
+
+ : fPreviewSize ()
+ , fPhotometricInterpretation (piYCbCr)
+ , fYCbCrSubSampling (1, 1)
+ , fYCbCrPositioning (2)
+ , fCompressedData ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_jpeg_preview::~dng_jpeg_preview ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_tiff_directory &directory) const
+ {
+
+ dng_ifd ifd;
+
+ ifd.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage
+ : sfAltPreviewImage;
+
+ ifd.fImageWidth = fPreviewSize.h;
+ ifd.fImageLength = fPreviewSize.v;
+
+ ifd.fPhotometricInterpretation = fPhotometricInterpretation;
+
+ ifd.fBitsPerSample [0] = 8;
+ ifd.fBitsPerSample [1] = 8;
+ ifd.fBitsPerSample [2] = 8;
+
+ ifd.fSamplesPerPixel = (fPhotometricInterpretation == piBlackIsZero ? 1 : 3);
+
+ ifd.fCompression = ccJPEG;
+ ifd.fPredictor = cpNullPredictor;
+
+ ifd.SetSingleStrip ();
+
+ return new dng_jpeg_preview_tag_set (directory, *this, ifd);
+
+ }
+
+/*****************************************************************************/
+
+void dng_jpeg_preview::WriteData (dng_host & /* host */,
+ dng_image_writer & /* writer */,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const
+ {
+
+ basic.SetTileOffset (0, (uint32) stream.Position ());
+
+ basic.SetTileByteCount (0, fCompressedData->LogicalSize ());
+
+ stream.Put (fCompressedData->Buffer (),
+ fCompressedData->LogicalSize ());
+
+ if (fCompressedData->LogicalSize () & 1)
+ {
+ stream.Put_uint8 (0);
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const
+ {
+
+ DNG_ASSERT (fCompressedData.Get (),
+ "SpoolAdobeThumbnail: no data");
+
+ DNG_ASSERT (fPhotometricInterpretation == piYCbCr,
+ "SpoolAdobeThumbnail: Non-YCbCr");
+
+ uint32 compressedSize = fCompressedData->LogicalSize ();
+
+ stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
+ stream.Put_uint16 (1036);
+ stream.Put_uint16 (0);
+
+ stream.Put_uint32 (compressedSize + 28);
+
+ uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4;
+
+ stream.Put_uint32 (1);
+ stream.Put_uint32 (fPreviewSize.h);
+ stream.Put_uint32 (fPreviewSize.v);
+ stream.Put_uint32 (widthBytes);
+ stream.Put_uint32 (widthBytes * fPreviewSize.v);
+ stream.Put_uint32 (compressedSize);
+ stream.Put_uint16 (24);
+ stream.Put_uint16 (1);
+
+ stream.Put (fCompressedData->Buffer (),
+ compressedSize);
+
+ if (compressedSize & 1)
+ {
+ stream.Put_uint8 (0);
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_raw_preview_tag_set: public dng_preview_tag_set
+ {
+
+ private:
+
+ tag_data_ptr fOpcodeList2Tag;
+
+ tag_uint32_ptr fWhiteLevelTag;
+
+ uint32 fWhiteLevelData [kMaxColorPlanes];
+
+ public:
+
+ dng_raw_preview_tag_set (dng_tiff_directory &directory,
+ const dng_raw_preview &preview,
+ const dng_ifd &ifd);
+
+ virtual ~dng_raw_preview_tag_set ();
+
+ };
+
+/*****************************************************************************/
+
+dng_raw_preview_tag_set::dng_raw_preview_tag_set (dng_tiff_directory &directory,
+ const dng_raw_preview &preview,
+ const dng_ifd &ifd)
+
+ : dng_preview_tag_set (directory, preview, ifd)
+
+ , fOpcodeList2Tag (tcOpcodeList2,
+ ttUndefined,
+ 0,
+ NULL)
+
+ , fWhiteLevelTag (tcWhiteLevel,
+ fWhiteLevelData,
+ preview.fImage->Planes ())
+
+ {
+
+ if (preview.fOpcodeList2Data.Get ())
+ {
+
+ fOpcodeList2Tag.SetData (preview.fOpcodeList2Data->Buffer ());
+ fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ());
+
+ directory.Add (&fOpcodeList2Tag);
+
+ }
+
+ if (preview.fImage->PixelType () == ttFloat)
+ {
+
+ for (uint32 j = 0; j < kMaxColorPlanes; j++)
+ {
+ fWhiteLevelData [j] = 32768;
+ }
+
+ directory.Add (&fWhiteLevelTag);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_raw_preview_tag_set::~dng_raw_preview_tag_set ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_raw_preview::dng_raw_preview ()
+
+ : fImage ()
+ , fOpcodeList2Data ()
+ , fCompressionQuality (-1)
+ , fIFD ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_raw_preview::~dng_raw_preview ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_tiff_directory &directory) const
+ {
+
+ fIFD.fNewSubFileType = sfPreviewImage;
+
+ fIFD.fImageWidth = fImage->Width ();
+ fIFD.fImageLength = fImage->Height ();
+
+ fIFD.fSamplesPerPixel = fImage->Planes ();
+
+ fIFD.fPhotometricInterpretation = piLinearRaw;
+
+ if (fImage->PixelType () == ttFloat)
+ {
+
+ fIFD.fCompression = ccDeflate;
+
+ fIFD.fCompressionQuality = fCompressionQuality;
+
+ fIFD.fPredictor = cpFloatingPoint;
+
+ for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++)
+ {
+ fIFD.fBitsPerSample [j] = 16;
+ fIFD.fSampleFormat [j] = sfFloatingPoint;
+ }
+
+ fIFD.FindTileSize (512 * 1024);
+
+ }
+
+ else
+ {
+
+ fIFD.fCompression = ccLossyJPEG;
+
+ fIFD.fCompressionQuality = fCompressionQuality;
+
+ fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8;
+
+ for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++)
+ {
+ fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0];
+ }
+
+ fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
+
+ }
+
+ return new dng_raw_preview_tag_set (directory, *this, fIFD);
+
+ }
+
+/*****************************************************************************/
+
+void dng_raw_preview::WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const
+ {
+
+ writer.WriteImage (host,
+ fIFD,
+ basic,
+ stream,
+ *fImage.Get ());
+
+ }
+
+/*****************************************************************************/
+
+dng_mask_preview::dng_mask_preview ()
+
+ : fImage ()
+ , fCompressionQuality (-1)
+ , fIFD ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_mask_preview::~dng_mask_preview ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_tiff_directory &directory) const
+ {
+
+ fIFD.fNewSubFileType = sfPreviewMask;
+
+ fIFD.fImageWidth = fImage->Width ();
+ fIFD.fImageLength = fImage->Height ();
+
+ fIFD.fSamplesPerPixel = 1;
+
+ fIFD.fPhotometricInterpretation = piTransparencyMask;
+
+ fIFD.fCompression = ccDeflate;
+ fIFD.fPredictor = cpHorizontalDifference;
+
+ fIFD.fCompressionQuality = fCompressionQuality;
+
+ fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8;
+
+ fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
+
+ return new dng_basic_tag_set (directory, fIFD);
+
+ }
+
+/*****************************************************************************/
+
+void dng_mask_preview::WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const
+ {
+
+ writer.WriteImage (host,
+ fIFD,
+ basic,
+ stream,
+ *fImage.Get ());
+
+ }
+
+/*****************************************************************************/
+
+dng_preview_list::dng_preview_list ()
+
+ : fCount (0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_preview_list::~dng_preview_list ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_preview_list::Append (AutoPtr<dng_preview> &preview)
+ {
+
+ if (preview.Get ())
+ {
+
+ DNG_ASSERT (fCount < kMaxDNGPreviews, "DNG preview list overflow");
+
+ if (fCount < kMaxDNGPreviews)
+ {
+
+ fPreview [fCount++] . Reset (preview.Release ());
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_preview.h b/gpr/source/lib/dng_sdk/dng_preview.h
new file mode 100644
index 0000000..2b616e3
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_preview.h
@@ -0,0 +1,245 @@
+/*****************************************************************************/
+// Copyright 2007-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_preview.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_preview__
+#define __dng_preview__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_ifd.h"
+#include "dng_opcode_list.h"
+#include "dng_point.h"
+#include "dng_sdk_limits.h"
+
+/*****************************************************************************/
+
+class dng_preview
+ {
+
+ public:
+
+ dng_preview_info fInfo;
+
+ protected:
+
+ dng_preview ();
+
+ public:
+
+ virtual ~dng_preview ();
+
+ virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const = 0;
+
+ virtual void WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const = 0;
+
+ };
+
+/*****************************************************************************/
+
+class dng_image_preview: public dng_preview
+ {
+
+ public:
+
+ AutoPtr<dng_image> fImage;
+
+ private:
+
+ mutable dng_ifd fIFD;
+
+ public:
+
+ dng_image_preview ();
+
+ virtual ~dng_image_preview ();
+
+ virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
+
+ virtual void WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_image_preview (const dng_image_preview &preview);
+
+ dng_image_preview & operator= (const dng_image_preview &preview);
+
+ };
+
+/*****************************************************************************/
+
+class dng_jpeg_preview: public dng_preview
+ {
+
+ public:
+
+ dng_point fPreviewSize;
+
+ uint16 fPhotometricInterpretation;
+
+ dng_point fYCbCrSubSampling;
+
+ uint16 fYCbCrPositioning;
+
+ AutoPtr<dng_memory_block> fCompressedData;
+
+ public:
+
+ dng_jpeg_preview ();
+
+ virtual ~dng_jpeg_preview ();
+
+ virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
+
+ virtual void WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const;
+
+ void SpoolAdobeThumbnail (dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_jpeg_preview (const dng_jpeg_preview &preview);
+
+ dng_jpeg_preview & operator= (const dng_jpeg_preview &preview);
+
+ };
+
+/*****************************************************************************/
+
+class dng_raw_preview: public dng_preview
+ {
+
+ public:
+
+ AutoPtr<dng_image> fImage;
+
+ AutoPtr<dng_memory_block> fOpcodeList2Data;
+
+ int32 fCompressionQuality;
+
+ private:
+
+ mutable dng_ifd fIFD;
+
+ public:
+
+ dng_raw_preview ();
+
+ virtual ~dng_raw_preview ();
+
+ virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
+
+ virtual void WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_raw_preview (const dng_raw_preview &preview);
+
+ dng_raw_preview & operator= (const dng_raw_preview &preview);
+
+ };
+
+/*****************************************************************************/
+
+class dng_mask_preview: public dng_preview
+ {
+
+ public:
+
+ AutoPtr<dng_image> fImage;
+
+ int32 fCompressionQuality;
+
+ private:
+
+ mutable dng_ifd fIFD;
+
+ public:
+
+ dng_mask_preview ();
+
+ virtual ~dng_mask_preview ();
+
+ virtual dng_basic_tag_set * AddTagSet (dng_tiff_directory &directory) const;
+
+ virtual void WriteData (dng_host &host,
+ dng_image_writer &writer,
+ dng_basic_tag_set &basic,
+ dng_stream &stream) const;
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_mask_preview (const dng_mask_preview &preview);
+
+ dng_mask_preview & operator= (const dng_mask_preview &preview);
+
+ };
+
+/*****************************************************************************/
+
+class dng_preview_list
+ {
+
+ private:
+
+ uint32 fCount;
+
+ AutoPtr<dng_preview> fPreview [kMaxDNGPreviews];
+
+ public:
+
+ dng_preview_list ();
+
+ ~dng_preview_list ();
+
+ uint32 Count () const
+ {
+ return fCount;
+ }
+
+ const dng_preview & Preview (uint32 index) const
+ {
+ return *(fPreview [index]);
+ }
+
+ void Append (AutoPtr<dng_preview> &preview);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_pthread.cpp b/gpr/source/lib/dng_sdk/dng_pthread.cpp
new file mode 100644
index 0000000..16005cd
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_pthread.cpp
@@ -0,0 +1,1141 @@
+/*****************************************************************************/
+// Copyright 2002-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pthread.cpp#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+#include "dng_pthread.h"
+
+/*****************************************************************************/
+
+#if qDNGThreadSafe
+
+/*****************************************************************************/
+
+#include "dng_assertions.h"
+
+/*****************************************************************************/
+
+#if qWinOS
+
+#pragma warning(disable : 4786)
+
+// Nothing in this file requires Unicode,
+// However, CreateSemaphore has a path parameter
+// (which is NULL always in this code) and thus
+// does not work on Win98 if UNICODE is defined.
+// So we force it off here.
+
+#undef UNICODE
+#undef _UNICODE
+
+#include <windows.h>
+#include <process.h>
+#include <errno.h>
+#include <memory>
+#include <new>
+#include <map>
+
+#else
+
+#include <sys/time.h>
+
+#endif
+
+/*****************************************************************************/
+
+#if qWinOS
+
+/*****************************************************************************/
+
+namespace {
+ struct waiter {
+ struct waiter *prev;
+ struct waiter *next;
+ HANDLE semaphore;
+ bool chosen_by_signal;
+ };
+}
+
+/*****************************************************************************/
+
+struct dng_pthread_mutex_impl
+{
+ CRITICAL_SECTION lock;
+
+ dng_pthread_mutex_impl() { ::InitializeCriticalSection(&lock); }
+ ~dng_pthread_mutex_impl() { ::DeleteCriticalSection(&lock); }
+ void Lock() { ::EnterCriticalSection(&lock); }
+ void Unlock() { ::LeaveCriticalSection(&lock); }
+private:
+ dng_pthread_mutex_impl &operator=(const dng_pthread_mutex_impl &) { }
+ dng_pthread_mutex_impl(const dng_pthread_mutex_impl &) { }
+};
+
+/*****************************************************************************/
+
+struct dng_pthread_cond_impl
+{
+ dng_pthread_mutex_impl lock; // Mutual exclusion on next two variables
+ waiter *head_waiter; // List of threads waiting on this condition
+ waiter *tail_waiter; // Used to get FIFO, rather than LIFO, behavior for pthread_cond_signal
+ unsigned int broadcast_generation; // Used as sort of a separator on broadcasts
+ // saves having to walk the waiters list setting
+ // each one's "chosen_by_signal" flag while the condition is locked
+
+ dng_pthread_cond_impl() : head_waiter(NULL), tail_waiter(NULL), broadcast_generation(0) { }
+ ~dng_pthread_cond_impl() { } ;
+
+// Non copyable
+private:
+ dng_pthread_cond_impl &operator=(const dng_pthread_cond_impl &) { }
+ dng_pthread_cond_impl(const dng_pthread_cond_impl &) { }
+
+};
+
+/*****************************************************************************/
+
+namespace
+{
+
+ struct ScopedLock
+ {
+ dng_pthread_mutex_impl *mutex;
+
+ ScopedLock(dng_pthread_mutex_impl *arg) : mutex(arg)
+ {
+ mutex->Lock();
+ }
+ ScopedLock(dng_pthread_mutex_impl &arg) : mutex(&arg)
+ {
+ mutex->Lock();
+ }
+ ~ScopedLock()
+ {
+ mutex->Unlock();
+ }
+ private:
+ ScopedLock &operator=(const ScopedLock &) { }
+ ScopedLock(const ScopedLock &) { }
+ };
+
+ dng_pthread_mutex_impl validationLock;
+
+ void ValidateMutex(dng_pthread_mutex_t *mutex)
+ {
+ if (*mutex != DNG_PTHREAD_MUTEX_INITIALIZER)
+ return;
+
+ ScopedLock lock(validationLock);
+
+ if (*mutex == DNG_PTHREAD_MUTEX_INITIALIZER)
+ dng_pthread_mutex_init(mutex, NULL);
+ }
+
+ void ValidateCond(dng_pthread_cond_t *cond)
+ {
+ if (*cond != DNG_PTHREAD_COND_INITIALIZER)
+ return;
+
+ ScopedLock lock(validationLock);
+
+ if (*cond == DNG_PTHREAD_COND_INITIALIZER)
+ dng_pthread_cond_init(cond, NULL);
+ }
+
+ DWORD thread_wait_sema_TLS_index;
+ bool thread_wait_sema_inited = false;
+ dng_pthread_once_t once_thread_TLS = DNG_PTHREAD_ONCE_INIT;
+
+ void init_thread_TLS()
+ {
+ thread_wait_sema_TLS_index = ::TlsAlloc();
+ thread_wait_sema_inited = true;
+ }
+
+ void finalize_thread_TLS()
+ {
+ if (thread_wait_sema_inited)
+ {
+ ::TlsFree(thread_wait_sema_TLS_index);
+ thread_wait_sema_inited = false;
+ }
+ }
+
+ dng_pthread_mutex_impl primaryHandleMapLock;
+
+ typedef std::map<DWORD, std::pair<HANDLE, void **> > ThreadMapType;
+
+ // A map to make sure handles are freed and to allow returning a pointer sized result
+ // even on 64-bit Windows.
+ ThreadMapType primaryHandleMap;
+
+ HANDLE GetThreadSemaphore()
+ {
+ dng_pthread_once(&once_thread_TLS, init_thread_TLS);
+
+ HANDLE semaphore = ::TlsGetValue(thread_wait_sema_TLS_index);
+ if (semaphore == NULL)
+ {
+ semaphore = ::CreateSemaphore(NULL, 0, 1, NULL);
+ ::TlsSetValue(thread_wait_sema_TLS_index, semaphore);
+ }
+
+ return semaphore;
+ }
+
+ void FreeThreadSemaphore()
+ {
+ if (thread_wait_sema_inited)
+ {
+ HANDLE semaphore = (HANDLE)::TlsGetValue(thread_wait_sema_TLS_index);
+
+ if (semaphore != NULL)
+ {
+ ::TlsSetValue(thread_wait_sema_TLS_index, NULL);
+ ::CloseHandle(semaphore);
+ }
+ }
+ }
+
+ struct trampoline_args
+ {
+ void *(*func)(void *);
+ void *arg;
+ };
+
+ // This trampoline takes care of the return type being different
+ // between pthreads thread funcs and Windows C lib thread funcs
+ unsigned __stdcall trampoline(void *arg_arg)
+ {
+ trampoline_args *args_ptr = (trampoline_args *)arg_arg;
+ trampoline_args args = *args_ptr;
+
+ delete args_ptr;
+
+ GetThreadSemaphore();
+
+ void *result = args.func(args.arg);
+
+ {
+ ScopedLock lockMap(primaryHandleMapLock);
+
+ ThreadMapType::iterator iter = primaryHandleMap.find(pthread_self());
+ if (iter != primaryHandleMap.end())
+ *iter->second.second = result;
+ }
+
+ FreeThreadSemaphore();
+
+ return S_OK;
+ }
+
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+/*****************************************************************************/
+
+struct dng_pthread_attr_impl
+ {
+ size_t stacksize;
+ };
+
+/*****************************************************************************/
+
+int dng_pthread_attr_init(pthread_attr_t *attr)
+ {
+ dng_pthread_attr_impl *newAttrs;
+
+ newAttrs = new (std::nothrow) dng_pthread_attr_impl;
+ if (newAttrs == NULL)
+ return -1; // ENOMEM;
+
+ newAttrs->stacksize = 0;
+
+ *attr = newAttrs;
+
+ return 0;
+ }
+
+/*****************************************************************************/
+
+int dng_pthread_attr_destroy(pthread_attr_t *attr)
+ {
+ if (*attr == NULL)
+ return -1; // EINVAL
+
+ delete *attr;
+
+ *attr = NULL;
+
+ return 0;
+ }
+
+/*****************************************************************************/
+
+int dng_pthread_attr_setstacksize(dng_pthread_attr_t *attr, size_t stacksize)
+ {
+ if (attr == NULL || (*attr) == NULL)
+ return -1; // EINVAL
+
+ (*attr)->stacksize = stacksize;
+
+ return 0;
+ }
+
+/*****************************************************************************/
+
+int dng_pthread_attr_getstacksize(const dng_pthread_attr_t *attr, size_t *stacksize)
+ {
+ if (attr == NULL || (*attr) == NULL || stacksize == NULL)
+ return -1; // EINVAL
+
+ *stacksize = (*attr)->stacksize;
+
+ return 0;
+ }
+
+/*****************************************************************************/
+
+int dng_pthread_create(dng_pthread_t *thread, const pthread_attr_t *attrs, void * (*func)(void *), void *arg)
+{
+ try
+ {
+ uintptr_t result;
+ unsigned threadID;
+ std::auto_ptr<trampoline_args> args(new (std::nothrow) trampoline_args);
+ std::auto_ptr<void *> resultHolder(new (std::nothrow) (void *));
+
+ if (args.get() == NULL || resultHolder.get () == NULL)
+ return -1; // ENOMEM
+
+ args->func = func;
+ args->arg = arg;
+
+ size_t stacksize = 0;
+
+ if (attrs != NULL)
+ dng_pthread_attr_getstacksize (attrs, &stacksize);
+
+ {
+ ScopedLock lockMap(primaryHandleMapLock);
+
+ result = _beginthreadex(NULL, (unsigned)stacksize, trampoline, args.get(), 0, &threadID);
+ if (result == NULL)
+ return -1; // ENOMEM
+ args.release();
+
+ std::pair<DWORD, std::pair<HANDLE, void **> > newMapEntry(threadID,
+ std::pair<HANDLE, void **>((HANDLE)result, resultHolder.get ()));
+ std::pair<ThreadMapType::iterator, bool> insertion = primaryHandleMap.insert(newMapEntry);
+
+ // If there is a handle open on the thread, its ID should not be reused so assert that an insertion was made.
+ DNG_ASSERT(insertion.second, "pthread emulation logic error");
+ }
+
+
+ resultHolder.release ();
+
+ *thread = (dng_pthread_t)threadID;
+ return 0;
+ }
+ catch (const std::bad_alloc &)
+ {
+ return -1;
+ }
+}
+
+/*****************************************************************************/
+
+int dng_pthread_detach(dng_pthread_t thread)
+{
+ HANDLE primaryHandle;
+ void **resultHolder = NULL;
+
+ {
+ ScopedLock lockMap(primaryHandleMapLock);
+
+ ThreadMapType::iterator iter = primaryHandleMap.find(thread);
+ if (iter == primaryHandleMap.end())
+ return -1;
+
+ primaryHandle = iter->second.first;
+
+ // A join is waiting on the thread.
+ if (primaryHandle == NULL)
+ return -1;
+
+ resultHolder = iter->second.second;
+
+ primaryHandleMap.erase(iter);
+ }
+
+ delete resultHolder;
+
+ if (!::CloseHandle(primaryHandle))
+ return -1;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_join(dng_pthread_t thread, void **result)
+{
+ bool found = false;
+ HANDLE primaryHandle = NULL;
+ void **resultHolder = NULL;
+
+ ThreadMapType::iterator iter;
+
+ {
+ ScopedLock lockMap(primaryHandleMapLock);
+
+ iter = primaryHandleMap.find(thread);
+ found = iter != primaryHandleMap.end();
+ if (found)
+ {
+ primaryHandle = iter->second.first;
+ resultHolder = iter->second.second;
+
+ // Set HANDLE to NULL to force any later join or detach to fail.
+ iter->second.first = NULL;
+ }
+ }
+
+ // This case can happens when joining a thread not created with pthread_create,
+ // which is a bad idea, but it gets mapped to doing the join, but always returns NULL.
+ if (!found)
+ primaryHandle = ::OpenThread(SYNCHRONIZE|THREAD_QUERY_INFORMATION, FALSE, thread);
+
+ if (primaryHandle == NULL)
+ return -1;
+
+ DWORD err;
+ if (::WaitForSingleObject(primaryHandle, INFINITE) != WAIT_OBJECT_0)
+ {
+ err = ::GetLastError();
+ return -1;
+ }
+
+ {
+ ScopedLock lockMap(primaryHandleMapLock);
+
+ if (iter != primaryHandleMap.end())
+ primaryHandleMap.erase(iter);
+ }
+
+ ::CloseHandle(primaryHandle);
+ if (result != NULL && resultHolder != NULL)
+ *result = *resultHolder;
+
+ delete resultHolder;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+dng_pthread_t dng_pthread_self()
+{
+ return (dng_pthread_t)::GetCurrentThreadId();
+}
+
+/*****************************************************************************/
+
+void dng_pthread_exit(void *result)
+{
+ {
+ ScopedLock lockMap(primaryHandleMapLock);
+
+ ThreadMapType::iterator iter = primaryHandleMap.find(pthread_self());
+ if (iter != primaryHandleMap.end())
+ *iter->second.second = result;
+ }
+
+ FreeThreadSemaphore();
+
+ _endthreadex(S_OK);
+}
+
+/*****************************************************************************/
+
+int dng_pthread_mutex_init(dng_pthread_mutex_t *mutex, void * /* attrs */)
+{
+ dng_pthread_mutex_t result;
+ try {
+ result = new(dng_pthread_mutex_impl);
+ } catch (const std::bad_alloc &)
+ {
+ return -1;
+ }
+
+ if (result == NULL)
+ return -1;
+ *mutex = result;
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_mutex_destroy(dng_pthread_mutex_t *mutex)
+{
+ if (*mutex == DNG_PTHREAD_MUTEX_INITIALIZER)
+ {
+ *mutex = NULL;
+ return 0;
+ }
+
+ delete *mutex;
+ *mutex = NULL;
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_cond_init(dng_pthread_cond_t *cond, void * /* attrs */)
+{
+ dng_pthread_cond_t result;
+ try {
+ result = new(dng_pthread_cond_impl);
+ } catch (const std::bad_alloc &)
+ {
+ return -1;
+ }
+
+ if (result == NULL)
+ return -1;
+ *cond = result;
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_cond_destroy(dng_pthread_cond_t *cond)
+{
+ if (*cond == DNG_PTHREAD_COND_INITIALIZER)
+ {
+ *cond = NULL;
+ return 0;
+ }
+
+ delete *cond;
+ *cond = NULL;
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_mutexattr_init(dng_pthread_mutexattr_t* mutexattr)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t* mutexattr, int type)
+{
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_mutex_lock(dng_pthread_mutex_t *mutex)
+{
+ ValidateMutex(mutex);
+ (*mutex)->Lock();
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_mutex_unlock(dng_pthread_mutex_t *mutex)
+{
+ ValidateMutex(mutex);
+ (*mutex)->Unlock();
+ return 0;
+}
+
+/*****************************************************************************/
+
+static int cond_wait_internal(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, int timeout_milliseconds)
+{
+ dng_pthread_cond_impl &real_cond = **cond;
+ dng_pthread_mutex_impl &real_mutex = **mutex;
+
+ waiter this_wait;
+ HANDLE semaphore = GetThreadSemaphore();
+ int my_generation; // The broadcast generation this waiter is in
+
+ {
+ this_wait.next = NULL;
+ this_wait.semaphore = semaphore;
+ this_wait.chosen_by_signal = 0;
+
+ ScopedLock lock1(real_cond.lock);
+
+ // Add this waiter to the end of the list.
+ this_wait.prev = real_cond.tail_waiter;
+ if (real_cond.tail_waiter != NULL)
+ real_cond.tail_waiter->next = &this_wait;
+ real_cond.tail_waiter = &this_wait;
+
+ // If the list was empty, set the head of the list to this waiter.
+ if (real_cond.head_waiter == NULL)
+ real_cond.head_waiter = &this_wait;
+
+ // Note which broadcast generation this waiter belongs to.
+ my_generation = real_cond.broadcast_generation;
+ }
+
+ real_mutex.Unlock();
+
+ DWORD result = ::WaitForSingleObject(semaphore, timeout_milliseconds);
+
+ if (result == WAIT_TIMEOUT)
+ {
+ // If the wait timed out, this thread is likely still on the waiters list
+ // of the condition. However, there is a race in that the thread may have been
+ // signaled or broadcast between when WaitForSingleObject decided
+ // we had timed out and this code running.
+
+ bool mustConsumeSemaphore = false;
+ {
+ ScopedLock lock2(real_cond.lock);
+
+ bool chosen_by_signal = this_wait.chosen_by_signal;
+ bool chosen_by_broadcast = my_generation != real_cond.broadcast_generation;
+
+ if (chosen_by_signal || chosen_by_broadcast)
+ mustConsumeSemaphore = true;
+ else
+ {
+ // Still on waiters list. Remove this waiter from list.
+ if (this_wait.next != NULL)
+ this_wait.next->prev = this_wait.prev;
+ else
+ real_cond.tail_waiter = this_wait.prev;
+
+ if (this_wait.prev != NULL)
+ this_wait.prev->next = this_wait.next;
+ else
+ real_cond.head_waiter = this_wait.next;
+ }
+ }
+
+ if (mustConsumeSemaphore)
+ {
+ ::WaitForSingleObject(semaphore, INFINITE);
+ result = WAIT_OBJECT_0;
+ }
+ }
+ else
+ DNG_ASSERT (result == WAIT_OBJECT_0, "pthread emulation logic error");
+
+ // reacquire the mutex
+ real_mutex.Lock();
+
+ return (result == WAIT_TIMEOUT) ? DNG_ETIMEDOUT : 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_cond_wait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex)
+{
+ ValidateCond(cond);
+
+ return cond_wait_internal(cond, mutex, INFINITE);
+}
+
+/*****************************************************************************/
+
+int dng_pthread_cond_timedwait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, timespec *latest_time)
+{
+ ValidateCond(cond);
+
+ struct timespec sys_timespec;
+
+ dng_pthread_now (&sys_timespec);
+
+ __int64 sys_time = (__int64)sys_timespec.tv_sec * 1000000000 + sys_timespec.tv_nsec;
+ __int64 lock_time = (__int64)latest_time->tv_sec * 1000000000 + latest_time->tv_nsec;
+
+ int wait_millisecs = (int)((lock_time - sys_time + 500000) / 1000000);
+
+ if (wait_millisecs < 0)
+ wait_millisecs = 0;
+
+ return cond_wait_internal(cond, mutex, wait_millisecs);
+}
+
+/*****************************************************************************/
+
+int dng_pthread_cond_signal(dng_pthread_cond_t *cond)
+{
+ ValidateCond(cond);
+
+ waiter *first;
+ dng_pthread_cond_impl &real_cond = **cond;
+
+ {
+ ScopedLock lock(real_cond.lock);
+
+ first = real_cond.head_waiter;
+ if (first != NULL)
+ {
+ if (first->next != NULL)
+ first->next->prev = NULL;
+ else
+ real_cond.tail_waiter = NULL; // Or first->prev, which is always NULL in this case
+
+ first->chosen_by_signal = true;
+
+ real_cond.head_waiter = first->next;
+ }
+ }
+
+ if (first != NULL)
+ ::ReleaseSemaphore(first->semaphore, 1, NULL);
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_cond_broadcast(dng_pthread_cond_t *cond)
+{
+ ValidateCond(cond);
+
+ waiter *first;
+ dng_pthread_cond_impl &real_cond = **cond;
+
+ {
+ ScopedLock lock(real_cond.lock);
+
+ first = real_cond.head_waiter;
+ real_cond.head_waiter = NULL;
+ real_cond.tail_waiter = NULL;
+
+ real_cond.broadcast_generation++;
+ }
+
+ while (first != NULL)
+ {
+ waiter *next = first->next;
+ ::ReleaseSemaphore(first->semaphore, 1, NULL);
+ first = next;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_once(dng_pthread_once_t *once, void (*init_func)())
+{
+ if (once == NULL || init_func == NULL)
+ return EINVAL;
+
+ if (once->inited)
+ return 0;
+
+ if (::InterlockedIncrement(&once->semaphore) == 0)
+ {
+ init_func();
+ once->inited = 1;
+ }
+ else
+ {
+ while (!once->inited)
+ Sleep(0);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_key_create(dng_pthread_key_t * key, void (*destructor) (void *))
+{
+ if (destructor != NULL)
+ return -1;
+
+ DWORD result = ::TlsAlloc();
+ if (result == TLS_OUT_OF_INDEXES)
+ return -1;
+ *key = (unsigned long)result;
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_key_delete(dng_pthread_key_t key)
+{
+ if (::TlsFree((DWORD)key))
+ return 0;
+ return -1;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_setspecific(dng_pthread_key_t key, const void *value)
+{
+ if (::TlsSetValue((DWORD)key, const_cast<void *>(value)))
+ return 0;
+ return -1;
+}
+
+/*****************************************************************************/
+
+void *dng_pthread_getspecific(dng_pthread_key_t key)
+{
+ return ::TlsGetValue((DWORD)key);
+}
+
+/*****************************************************************************/
+
+namespace {
+ struct rw_waiter {
+ struct rw_waiter *prev;
+ struct rw_waiter *next;
+ HANDLE semaphore;
+ bool is_writer;
+ };
+}
+
+struct dng_pthread_rwlock_impl
+{
+ dng_pthread_mutex_impl mutex;
+
+ rw_waiter *head_waiter;
+ rw_waiter *tail_waiter;
+
+ unsigned long readers_active;
+ unsigned long writers_waiting;
+ bool writer_active;
+
+ dng_pthread_cond_impl read_wait;
+ dng_pthread_cond_impl write_wait;
+
+ dng_pthread_rwlock_impl ()
+ : mutex ()
+ , head_waiter (NULL)
+ , tail_waiter (NULL)
+ , readers_active (0)
+ , writers_waiting (0)
+ , read_wait ()
+ , write_wait ()
+ , writer_active (false)
+ {
+ }
+
+ ~dng_pthread_rwlock_impl ()
+ {
+ }
+
+ void WakeHeadWaiter ()
+ {
+ HANDLE semaphore = head_waiter->semaphore;
+
+ head_waiter = head_waiter->next;
+ if (head_waiter == NULL)
+ tail_waiter = NULL;
+
+ ::ReleaseSemaphore(semaphore, 1, NULL);
+ }
+
+};
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_init(dng_pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attrs)
+{
+ dng_pthread_rwlock_impl *newRWLock;
+
+ newRWLock = new (std::nothrow) dng_pthread_rwlock_impl;
+ if (newRWLock == NULL)
+ return -1; // ENOMEM;
+
+ *rwlock = newRWLock;
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_destroy(dng_pthread_rwlock_t *rwlock)
+{
+ dng_pthread_rwlock_impl &real_rwlock = **rwlock;
+
+ {
+ ScopedLock lock (real_rwlock.mutex);
+
+ if (real_rwlock.head_waiter != NULL ||
+ real_rwlock.readers_active != 0 ||
+ real_rwlock.writers_waiting != 0 ||
+ real_rwlock.writer_active)
+ return -1; // EBUSY
+ }
+
+ delete *rwlock;
+ *rwlock = NULL;
+ return 0;
+}
+
+/*****************************************************************************/
+
+#define CHECK_RWLOCK_STATE(real_rwlock) \
+ DNG_ASSERT (!real_rwlock.writer_active || real_rwlock.readers_active == 0, "dng_pthread_rwlock_t logic error")
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t *rwlock)
+{
+ dng_pthread_rwlock_impl &real_rwlock = **rwlock;
+
+ struct rw_waiter this_wait;
+ bool doWait = false;;
+ int result = 0;
+ HANDLE semaphore=NULL;
+
+ {
+
+ ScopedLock lock (real_rwlock.mutex);
+
+ CHECK_RWLOCK_STATE (real_rwlock);
+
+ if (real_rwlock.writers_waiting > 0 || real_rwlock.writer_active)
+ {
+ semaphore = GetThreadSemaphore();
+
+ this_wait.next = NULL;
+ this_wait.semaphore = semaphore;
+ this_wait.is_writer = false;
+
+ // Add this waiter to the end of the list.
+ this_wait.prev = real_rwlock.tail_waiter;
+ if (real_rwlock.tail_waiter != NULL)
+ real_rwlock.tail_waiter->next = &this_wait;
+ real_rwlock.tail_waiter = &this_wait;
+
+ // If the list was empty, set the head of the list to this waiter.
+ if (real_rwlock.head_waiter == NULL)
+ real_rwlock.head_waiter = &this_wait;
+
+ doWait = true;
+ }
+ else
+ real_rwlock.readers_active++;
+ }
+
+ if (result == 0 && doWait)
+ result = (WaitForSingleObject(semaphore, INFINITE) == WAIT_OBJECT_0) ? 0 : -1;
+
+ return result;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t *rwlock)
+{
+ dng_pthread_rwlock_impl &real_rwlock = **rwlock;
+
+ ScopedLock lock (real_rwlock.mutex);
+
+ CHECK_RWLOCK_STATE (real_rwlock);
+
+ if (real_rwlock.writers_waiting == 0 && !real_rwlock.writer_active)
+ {
+ real_rwlock.readers_active++;
+ return 0;
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t *rwlock)
+{
+ dng_pthread_rwlock_impl &real_rwlock = **rwlock;
+
+ ScopedLock lock (real_rwlock.mutex);
+
+ CHECK_RWLOCK_STATE (real_rwlock);
+
+ if (real_rwlock.readers_active == 0 &&
+ real_rwlock.writers_waiting == 0 &&
+ !real_rwlock.writer_active)
+ {
+ real_rwlock.writer_active = true;
+ return 0;
+ }
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_unlock(dng_pthread_rwlock_t *rwlock)
+ {
+ dng_pthread_rwlock_impl &real_rwlock = **rwlock;
+
+ int result = 0;
+
+ ScopedLock lock (real_rwlock.mutex);
+
+ CHECK_RWLOCK_STATE (real_rwlock);
+
+ if (real_rwlock.readers_active > 0)
+ --real_rwlock.readers_active;
+ else
+ real_rwlock.writer_active = false;
+
+ while (real_rwlock.head_waiter != NULL)
+ {
+ if (real_rwlock.head_waiter->is_writer)
+ {
+ if (real_rwlock.readers_active == 0)
+ {
+ real_rwlock.writers_waiting--;
+ real_rwlock.writer_active = true;
+ real_rwlock.WakeHeadWaiter ();
+ }
+
+ break;
+ }
+ else
+ {
+ ++real_rwlock.readers_active;
+ real_rwlock.WakeHeadWaiter ();
+ }
+ }
+
+ return result;
+ }
+
+/*****************************************************************************/
+
+int dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t *rwlock)
+ {
+ dng_pthread_rwlock_impl &real_rwlock = **rwlock;
+
+ int result = 0;
+ struct rw_waiter this_wait;
+ HANDLE semaphore=NULL;
+ bool doWait = false;
+
+ {
+ ScopedLock lock (real_rwlock.mutex);
+
+ CHECK_RWLOCK_STATE (real_rwlock);
+
+ if (real_rwlock.readers_active ||
+ real_rwlock.writers_waiting ||
+ real_rwlock.writer_active)
+ {
+ semaphore = GetThreadSemaphore();
+
+ this_wait.next = NULL;
+ this_wait.semaphore = semaphore;
+ this_wait.is_writer = true;
+
+ // Add this waiter to the end of the list.
+ this_wait.prev = real_rwlock.tail_waiter;
+ if (real_rwlock.tail_waiter != NULL)
+ real_rwlock.tail_waiter->next = &this_wait;
+ real_rwlock.tail_waiter = &this_wait;
+
+ // If the list was empty, set the head of the list to this waiter.
+ if (real_rwlock.head_waiter == NULL)
+ real_rwlock.head_waiter = &this_wait;
+
+ real_rwlock.writers_waiting++;
+
+ doWait = true;
+ }
+ else
+ real_rwlock.writer_active = true;
+ }
+
+ if (result == 0 && doWait)
+ result = (WaitForSingleObject(semaphore, INFINITE) == WAIT_OBJECT_0) ? 0 : -1;
+
+ return result;
+ }
+
+/*****************************************************************************/
+
+void dng_pthread_disassociate()
+{
+ FreeThreadSemaphore();
+}
+
+void dng_pthread_terminate()
+ {
+ finalize_thread_TLS();
+ }
+
+/*****************************************************************************/
+
+} // extern "C"
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+int dng_pthread_now (struct timespec *now)
+ {
+
+ if (now == NULL)
+ return -1; // EINVAL
+
+ #if qWinOS
+
+ FILETIME ft;
+ ::GetSystemTimeAsFileTime(&ft);
+
+ __int64 sys_time = ((__int64)ft.dwHighDateTime << 32) + ft.dwLowDateTime;
+
+ #define SecsFrom1601To1970 11644473600
+
+ sys_time -= SecsFrom1601To1970 * 10000000LL;
+
+ sys_time *= 100; // Convert from 100ns to 1ns units
+
+ now->tv_sec = (long)(sys_time / 1000000000);
+ now->tv_nsec = (long)(sys_time % 1000000000);
+
+ #else
+
+ struct timeval tv;
+
+ if (gettimeofday (&tv, NULL) != 0)
+ return errno;
+
+ now->tv_sec = tv.tv_sec;
+ now->tv_nsec = tv.tv_usec * 1000;
+
+ #endif
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+#endif // qDNGThreadSafe
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_pthread.h b/gpr/source/lib/dng_sdk/dng_pthread.h
new file mode 100644
index 0000000..21958c5
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_pthread.h
@@ -0,0 +1,267 @@
+/*****************************************************************************/
+// Copyright 2002-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pthread.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_pthread__
+#define __dng_pthread__
+
+/*****************************************************************************/
+
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+#if qDNGThreadSafe
+
+/*****************************************************************************/
+
+#if !qWinOS
+
+/*****************************************************************************/
+
+/* Try generic POSIX compile */
+
+#include <errno.h>
+#include <pthread.h>
+
+#define dng_pthread_disassociate()
+#define dng_pthread_terminate()
+
+/*****************************************************************************/
+
+#else
+
+/*****************************************************************************/
+
+#include <stdlib.h>
+#include <time.h>
+
+#if _MSC_VER >= 1600
+
+// Get this included so ETIMEDOUT is predefined.
+#include <errno.h>
+
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************/
+
+#define DNG_ETIMEDOUT 60 /* Operation timed out */
+
+struct dng_timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+
+#if !defined(_MSC_VER) || _MSC_VER < 1900
+#define timespec dng_timespec
+#endif
+typedef unsigned long dng_pthread_t;
+
+typedef struct dng_pthread_mutex_impl *dng_pthread_mutex_t;
+typedef struct dng_pthread_cond_impl *dng_pthread_cond_t;
+typedef unsigned long dng_pthread_key_t;
+
+
+#define DNG_PTHREAD_MUTEX_INITIALIZER ((struct dng_pthread_mutex_impl *)-1)
+#define DNG_PTHREAD_COND_INITIALIZER ((struct dng_pthread_cond_impl *)-1)
+
+struct _dng_pthread_once_t {
+ int inited;
+ long semaphore;
+};
+
+typedef struct _dng_pthread_once_t dng_pthread_once_t;
+#define DNG_PTHREAD_ONCE_INIT { 0, -1 }
+
+#define dng_pthread_equal(t1, t2) ((t1) == (t2))
+
+typedef struct dng_pthread_attr_impl *dng_pthread_attr_t;
+
+int dng_pthread_attr_init(dng_pthread_attr_t *attr);
+int dng_pthread_attr_destroy(dng_pthread_attr_t *attr);
+
+int dng_pthread_attr_setstacksize(dng_pthread_attr_t *attr, size_t stacksize);
+int dng_pthread_attr_getstacksize(const dng_pthread_attr_t *attr, size_t *stacksize);
+
+int dng_pthread_create(dng_pthread_t *thread, const dng_pthread_attr_t * /* attrs */, void * (*func)(void *), void *arg);
+int dng_pthread_detach(dng_pthread_t thread);
+int dng_pthread_join(dng_pthread_t thread, void **result);
+dng_pthread_t dng_pthread_self();
+void dng_pthread_exit(void *result);
+
+#define DNG_PTHREAD_MUTEX_RECURSIVE 0
+typedef unsigned long dng_pthread_mutexattr_t;
+
+int dng_pthread_mutexattr_init(dng_pthread_mutexattr_t *mutexattr);
+int dng_pthread_mutexattr_settype(dng_pthread_mutexattr_t *mutexattr, int /*the options*/);
+
+int dng_pthread_mutex_init(dng_pthread_mutex_t *mutex, void * /* attrs */);
+int dng_pthread_mutex_destroy(dng_pthread_mutex_t *mutex);
+int dng_pthread_mutex_lock(dng_pthread_mutex_t *mutex);
+int dng_pthread_mutex_unlock(dng_pthread_mutex_t *mutex);
+
+int dng_pthread_cond_init(dng_pthread_cond_t *cond, void * /* attrs */);
+int dng_pthread_cond_destroy(dng_pthread_cond_t *cond);
+int dng_pthread_cond_wait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex);
+int dng_pthread_cond_timedwait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, timespec *latest_time);
+int dng_pthread_cond_signal(dng_pthread_cond_t *cond);
+int dng_pthread_cond_broadcast(dng_pthread_cond_t *cond);
+
+int dng_pthread_once(dng_pthread_once_t *once, void (*init_func)());
+
+int dng_pthread_key_create(dng_pthread_key_t * key, void (*destructor) (void *));
+int dng_pthread_key_delete(dng_pthread_key_t key);
+int dng_pthread_setspecific(dng_pthread_key_t key, const void *value);
+void *dng_pthread_getspecific(dng_pthread_key_t key);
+
+typedef struct dng_pthread_rwlock_impl *dng_pthread_rwlock_t;
+typedef void *pthread_rwlockattr_t;
+
+int dng_pthread_rwlock_destroy(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_init(dng_pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attrs);
+int dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_unlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t * rwlock);
+
+typedef struct dng_pthread_rwlock_impl *dng_pthread_rwlock_t;
+typedef void *pthread_rwlockattr_t;
+
+int dng_pthread_rwlock_destroy(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_init(dng_pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attrs);
+int dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_unlock(dng_pthread_rwlock_t * rwlock);
+int dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t * rwlock);
+
+// dng_pthread may maintain per-thread global state. This routine frees that global state.
+// there is no need to call this for threads created by dng_pthread and one can call
+// dng_pthread routines of a thread after dng_pthread_disassociate as the global state will
+// be recreated as necessary. However dng_pthread_disassociate will need to be called again
+// and there is a slight performance cost. Do not call this routine while holding a mutex, etc.
+void dng_pthread_disassociate();
+
+void dng_pthread_terminate();
+
+/*****************************************************************************/
+
+// Map symbols back to plain pthread names. This whole mechanism is so the DNG pthreads library
+// symbols do not collide with another pthread emulation library
+// that may be in use in the same linked entity. However if that is the case, it would be far better
+// to have the DNG code use the same pthread library as the rest of the code.
+
+#define pthread_t dng_pthread_t
+#define pthread_mutex_t dng_pthread_mutex_t
+#define pthread_cond_t dng_pthread_cond_t
+#define pthread_once_t dng_pthread_once_t
+#define pthread_key_t dng_pthread_key_t
+
+#undef PTHREAD_MUTEX_INITIALIZER
+#define PTHREAD_MUTEX_INITIALIZER DNG_PTHREAD_MUTEX_INITIALIZER
+#undef PTHREAD_COND_INITIALIZER
+#define PTHREAD_COND_INITIALIZER DNG_PTHREAD_COND_INITIALIZER
+
+#undef PTHREAD_ONCE_INIT
+#define PTHREAD_ONCE_INIT DNG_PTHREAD_ONCE_INIT
+
+/* If it is defined on Windows, it probably has the wrong value... */
+#if defined(WIN32) || !defined(ETIMEDOUT)
+#undef ETIMEDOUT
+#define ETIMEDOUT DNG_ETIMEDOUT
+#endif
+
+#define pthread_equal dng_pthread_equal
+
+#define pthread_attr_t dng_pthread_attr_t
+
+#define pthread_attr_init dng_pthread_attr_init
+#define pthread_attr_destroy dng_pthread_attr_destroy
+
+#define pthread_attr_setstacksize dng_pthread_attr_setstacksize
+#define pthread_attr_getstacksize dng_pthread_attr_getstacksize
+
+#define pthread_create dng_pthread_create
+#define pthread_detach dng_pthread_detach
+#define pthread_join dng_pthread_join
+#define pthread_self dng_pthread_self
+#define pthread_exit dng_pthread_exit
+
+#define pthread_mutex_init dng_pthread_mutex_init
+#define pthread_mutex_destroy dng_pthread_mutex_destroy
+#define pthread_mutex_lock dng_pthread_mutex_lock
+#define pthread_mutex_unlock dng_pthread_mutex_unlock
+
+#define pthread_cond_init dng_pthread_cond_init
+#define pthread_cond_destroy dng_pthread_cond_destroy
+#define pthread_cond_wait dng_pthread_cond_wait
+#define pthread_cond_timedwait dng_pthread_cond_timedwait
+#define pthread_cond_signal dng_pthread_cond_signal
+#define pthread_cond_broadcast dng_pthread_cond_broadcast
+
+#define pthread_once dng_pthread_once
+
+#define pthread_key_create dng_pthread_key_create
+#define pthread_key_delete dng_pthread_key_delete
+#define pthread_setspecific dng_pthread_setspecific
+#define pthread_getspecific dng_pthread_getspecific
+
+#define pthread_rwlock_t dng_pthread_rwlock_t
+
+#define pthread_rwlock_destroy dng_pthread_rwlock_destroy
+#define pthread_rwlock_init dng_pthread_rwlock_init
+#define pthread_rwlock_rdlock dng_pthread_rwlock_rdlock
+#define pthread_rwlock_tryrdlock dng_pthread_rwlock_tryrdlock
+#define pthread_rwlock_trywrlock dng_pthread_rwlock_trywrlock
+#define pthread_rwlock_unlock dng_pthread_rwlock_unlock
+#define pthread_rwlock_wrlock dng_pthread_rwlock_wrlock
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int dng_pthread_now (struct timespec *now);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+
+#endif // qDNGThreadSafe
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_rational.cpp b/gpr/source/lib/dng_sdk/dng_rational.cpp
new file mode 100644
index 0000000..c366b46
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_rational.cpp
@@ -0,0 +1,150 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_rational.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_rational.h"
+
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+real64 dng_srational::As_real64 () const
+ {
+
+ if (d)
+ return (real64) n / (real64) d;
+
+ else
+ return 0.0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_srational::Set_real64 (real64 x, int32 dd)
+ {
+
+ if (x == 0.0)
+ {
+
+ *this = dng_srational (0, 1);
+
+ }
+
+ if (dd == 0)
+ {
+
+ real64 y = Abs_real64 (x);
+
+ if (y >= 32768.0)
+ {
+ dd = 1;
+ }
+
+ else if (y >= 1.0)
+ {
+ dd = 32768;
+ }
+
+ else
+ {
+ dd = 32768 * 32768;
+ }
+
+ }
+
+ *this = dng_srational (Round_int32 (x * dd), dd);
+
+ }
+
+/*****************************************************************************/
+
+void dng_srational::ReduceByFactor (int32 factor)
+ {
+
+ while (n % factor == 0 &&
+ d % factor == 0 &&
+ d >= factor)
+ {
+ n /= factor;
+ d /= factor;
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_urational::As_real64 () const
+ {
+
+ if (d)
+ return (real64) n / (real64) d;
+
+ else
+ return 0.0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_urational::Set_real64 (real64 x, uint32 dd)
+ {
+
+ if (x <= 0.0)
+ {
+
+ *this = dng_urational (0, 1);
+
+ }
+
+ if (dd == 0)
+ {
+
+ if (x >= 32768.0)
+ {
+ dd = 1;
+ }
+
+ else if (x >= 1.0)
+ {
+ dd = 32768;
+ }
+
+ else
+ {
+ dd = 32768 * 32768;
+ }
+
+ }
+
+ *this = dng_urational (Round_uint32 (x * dd), dd);
+
+ }
+
+/*****************************************************************************/
+
+void dng_urational::ReduceByFactor (uint32 factor)
+ {
+
+ while (n % factor == 0 &&
+ d % factor == 0 &&
+ d >= factor)
+ {
+ n /= factor;
+ d /= factor;
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_rational.h b/gpr/source/lib/dng_sdk/dng_rational.h
new file mode 100644
index 0000000..9080a63
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_rational.h
@@ -0,0 +1,149 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_rational.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Signed and unsigned rational data types.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_rational__
+#define __dng_rational__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_srational
+ {
+
+ public:
+
+ int32 n; // Numerator
+ int32 d; // Denominator
+
+ public:
+
+ dng_srational ()
+ : n (0)
+ , d (0)
+ {
+ }
+
+ dng_srational (int32 nn, int32 dd)
+ : n (nn)
+ , d (dd)
+ {
+ }
+
+ void Clear ()
+ {
+ n = 0;
+ d = 0;
+ }
+
+ bool IsValid () const
+ {
+ return d != 0;
+ }
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ bool operator== (const dng_srational &r) const
+ {
+ return (n == r.n) &&
+ (d == r.d);
+ }
+
+ bool operator!= (const dng_srational &r) const
+ {
+ return !(*this == r);
+ }
+
+ real64 As_real64 () const;
+
+ void Set_real64 (real64 x, int32 dd = 0);
+
+ void ReduceByFactor (int32 factor);
+
+ };
+
+/*****************************************************************************/
+
+class dng_urational
+ {
+
+ public:
+
+ uint32 n; // Numerator
+ uint32 d; // Denominator
+
+ public:
+
+ dng_urational ()
+ : n (0)
+ , d (0)
+ {
+ }
+
+ dng_urational (uint32 nn, uint32 dd)
+ : n (nn)
+ , d (dd)
+ {
+ }
+
+ void Clear ()
+ {
+ n = 0;
+ d = 0;
+ }
+
+ bool IsValid () const
+ {
+ return d != 0;
+ }
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ bool operator== (const dng_urational &r) const
+ {
+ return (n == r.n) &&
+ (d == r.d);
+ }
+
+ bool operator!= (const dng_urational &r) const
+ {
+ return !(*this == r);
+ }
+
+ real64 As_real64 () const;
+
+ void Set_real64 (real64 x, uint32 dd = 0);
+
+ void ReduceByFactor (uint32 factor);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_read_image.cpp b/gpr/source/lib/dng_sdk/dng_read_image.cpp
new file mode 100644
index 0000000..4b83d8c
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_read_image.cpp
@@ -0,0 +1,3194 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_read_image.cpp#7 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_read_image.h"
+
+#include "dng_abort_sniffer.h"
+#include "dng_area_task.h"
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_ifd.h"
+#include "dng_jpeg_image.h"
+#include "dng_lossless_jpeg.h"
+#include "dng_mutex.h"
+#include "dng_memory.h"
+#include "dng_pixel_buffer.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_utils.h"
+
+/******************************************************************************/
+
+static void DecodeDelta8 (uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 channels)
+ {
+
+ const uint32 dRowStep = cols * channels;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 1; col < cols; col++)
+ {
+
+ for (uint32 channel = 0; channel < channels; channel++)
+ {
+
+ dPtr [col * channels + channel] += dPtr [(col - 1) * channels + channel];
+
+ }
+
+ }
+
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+static void DecodeDelta16 (uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 channels)
+ {
+
+ const uint32 dRowStep = cols * channels;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 1; col < cols; col++)
+ {
+
+ for (uint32 channel = 0; channel < channels; channel++)
+ {
+
+ dPtr [col * channels + channel] += dPtr [(col - 1) * channels + channel];
+
+ }
+
+ }
+
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+static void DecodeDelta32 (uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 channels)
+ {
+
+ const uint32 dRowStep = cols * channels;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 1; col < cols; col++)
+ {
+
+ for (uint32 channel = 0; channel < channels; channel++)
+ {
+
+ dPtr [col * channels + channel] += dPtr [(col - 1) * channels + channel];
+
+ }
+
+ }
+
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+inline void DecodeDeltaBytes (uint8 *bytePtr, int32 cols, int32 channels)
+ {
+
+ if (channels == 1)
+ {
+
+ uint8 b0 = bytePtr [0];
+
+ bytePtr += 1;
+
+ for (int32 col = 1; col < cols; ++col)
+ {
+
+ b0 += bytePtr [0];
+
+ bytePtr [0] = b0;
+
+ bytePtr += 1;
+
+ }
+
+ }
+
+ else if (channels == 3)
+ {
+
+ uint8 b0 = bytePtr [0];
+ uint8 b1 = bytePtr [1];
+ uint8 b2 = bytePtr [2];
+
+ bytePtr += 3;
+
+ for (int32 col = 1; col < cols; ++col)
+ {
+
+ b0 += bytePtr [0];
+ b1 += bytePtr [1];
+ b2 += bytePtr [2];
+
+ bytePtr [0] = b0;
+ bytePtr [1] = b1;
+ bytePtr [2] = b2;
+
+ bytePtr += 3;
+
+ }
+
+ }
+
+ else if (channels == 4)
+ {
+
+ uint8 b0 = bytePtr [0];
+ uint8 b1 = bytePtr [1];
+ uint8 b2 = bytePtr [2];
+ uint8 b3 = bytePtr [3];
+
+ bytePtr += 4;
+
+ for (int32 col = 1; col < cols; ++col)
+ {
+
+ b0 += bytePtr [0];
+ b1 += bytePtr [1];
+ b2 += bytePtr [2];
+ b3 += bytePtr [3];
+
+ bytePtr [0] = b0;
+ bytePtr [1] = b1;
+ bytePtr [2] = b2;
+ bytePtr [3] = b3;
+
+ bytePtr += 4;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (int32 col = 1; col < cols; ++col)
+ {
+
+ for (int32 chan = 0; chan < channels; ++chan)
+ {
+
+ bytePtr [chan + channels] += bytePtr [chan];
+
+ }
+
+ bytePtr += channels;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+static void DecodeFPDelta (uint8 *input,
+ uint8 *output,
+ int32 cols,
+ int32 channels,
+ int32 bytesPerSample)
+ {
+
+ DecodeDeltaBytes (input, cols * bytesPerSample, channels);
+
+ int32 rowIncrement = cols * channels;
+
+ if (bytesPerSample == 2)
+ {
+
+ #if qDNGBigEndian
+ const uint8 *input0 = input;
+ const uint8 *input1 = input + rowIncrement;
+ #else
+ const uint8 *input1 = input;
+ const uint8 *input0 = input + rowIncrement;
+ #endif
+
+ for (int32 col = 0; col < rowIncrement; ++col)
+ {
+
+ output [0] = input0 [col];
+ output [1] = input1 [col];
+
+ output += 2;
+
+ }
+
+ }
+
+ else if (bytesPerSample == 3)
+ {
+
+ const uint8 *input0 = input;
+ const uint8 *input1 = input + rowIncrement;
+ const uint8 *input2 = input + rowIncrement * 2;
+
+ for (int32 col = 0; col < rowIncrement; ++col)
+ {
+
+ output [0] = input0 [col];
+ output [1] = input1 [col];
+ output [2] = input2 [col];
+
+ output += 3;
+
+ }
+
+ }
+
+ else
+ {
+
+ #if qDNGBigEndian
+ const uint8 *input0 = input;
+ const uint8 *input1 = input + rowIncrement;
+ const uint8 *input2 = input + rowIncrement * 2;
+ const uint8 *input3 = input + rowIncrement * 3;
+ #else
+ const uint8 *input3 = input;
+ const uint8 *input2 = input + rowIncrement;
+ const uint8 *input1 = input + rowIncrement * 2;
+ const uint8 *input0 = input + rowIncrement * 3;
+ #endif
+
+ for (int32 col = 0; col < rowIncrement; ++col)
+ {
+
+ output [0] = input0 [col];
+ output [1] = input1 [col];
+ output [2] = input2 [col];
+ output [3] = input3 [col];
+
+ output += 4;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool DecodePackBits (dng_stream &stream,
+ uint8 *dPtr,
+ int32 dstCount)
+ {
+
+ while (dstCount > 0)
+ {
+
+ int32 runCount = (int8) stream.Get_uint8 ();
+
+ if (runCount >= 0)
+ {
+
+ ++runCount;
+
+ dstCount -= runCount;
+
+ if (dstCount < 0)
+ return false;
+
+ stream.Get (dPtr, runCount);
+
+ dPtr += runCount;
+
+ }
+
+ else
+ {
+
+ runCount = -runCount + 1;
+
+ dstCount -= runCount;
+
+ if (dstCount < 0)
+ return false;
+
+ uint8 x = stream.Get_uint8 ();
+
+ while (runCount--)
+ {
+
+ *(dPtr++) = x;
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+class dng_lzw_expander
+ {
+
+ private:
+
+ enum
+ {
+ kResetCode = 256,
+ kEndCode = 257,
+ kTableSize = 4096
+ };
+
+ struct LZWExpanderNode
+ {
+ int16 prefix;
+ int16 final;
+ int16 depth;
+ int16 fake_for_padding;
+ };
+
+ dng_memory_data fBuffer;
+
+ LZWExpanderNode *fTable;
+
+ const uint8 *fSrcPtr;
+
+ int32 fSrcCount;
+
+ int32 fByteOffset;
+
+ uint32 fBitBuffer;
+ int32 fBitBufferCount;
+
+ int32 fNextCode;
+
+ int32 fCodeSize;
+
+ public:
+
+ dng_lzw_expander ();
+
+ bool Expand (const uint8 *sPtr,
+ uint8 *dPtr,
+ int32 sCount,
+ int32 dCount);
+
+ private:
+
+ void InitTable ();
+
+ void AddTable (int32 w, int32 k);
+
+ bool GetCodeWord (int32 &code);
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_lzw_expander (const dng_lzw_expander &expander);
+
+ dng_lzw_expander & operator= (const dng_lzw_expander &expander);
+
+ };
+
+/******************************************************************************/
+
+dng_lzw_expander::dng_lzw_expander ()
+
+ : fBuffer ()
+ , fTable (NULL)
+ , fSrcPtr (NULL)
+ , fSrcCount (0)
+ , fByteOffset (0)
+ , fBitBuffer (0)
+ , fBitBufferCount (0)
+ , fNextCode (0)
+ , fCodeSize (0)
+
+ {
+
+ fBuffer.Allocate (kTableSize * sizeof (LZWExpanderNode));
+
+ fTable = (LZWExpanderNode *) fBuffer.Buffer ();
+
+ }
+
+/******************************************************************************/
+
+void dng_lzw_expander::InitTable ()
+ {
+
+ fCodeSize = 9;
+
+ fNextCode = 258;
+
+ LZWExpanderNode *node = &fTable [0];
+
+ for (int32 code = 0; code < 256; code++)
+ {
+
+ node->prefix = -1;
+ node->final = (int16) code;
+ node->depth = 1;
+
+ node++;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_lzw_expander::AddTable (int32 w, int32 k)
+ {
+
+ DNG_ASSERT ((w >= 0) && (w <= kTableSize),
+ "bad w value in dng_lzw_expander::AddTable");
+
+ LZWExpanderNode *parentNode = &fTable [w];
+
+ int32 nextCode = fNextCode;
+
+ fNextCode++;
+
+ DNG_ASSERT ((nextCode >= 0) && (nextCode <= kTableSize),
+ "bad fNextCode value in dng_lzw_expander::AddTable");
+
+ LZWExpanderNode *node = &fTable [nextCode];
+
+ node->prefix = (int16) w;
+ node->final = (int16) k;
+ node->depth = 1 + parentNode->depth;
+
+ if (nextCode + 1 == (1 << fCodeSize) - 1)
+ {
+ if (fCodeSize != 12)
+ fCodeSize++;
+ }
+
+ }
+
+/******************************************************************************/
+
+bool dng_lzw_expander::GetCodeWord (int32 &code)
+ {
+
+ // The bit buffer has the current code in the most significant bits,
+ // so shift off the low orders.
+
+ int32 codeSize = fCodeSize;
+
+ code = fBitBuffer >> (32 - codeSize);
+
+ if (fBitBufferCount >= codeSize)
+ {
+
+ // Typical case; get the code from the bit buffer.
+
+ fBitBuffer <<= codeSize;
+ fBitBufferCount -= codeSize;
+
+ }
+
+ else
+ {
+
+ // The buffer needs to be refreshed.
+
+ const int32 bitsSoFar = fBitBufferCount;
+
+ if (fByteOffset >= fSrcCount)
+ return false;
+
+ // Buffer a long word
+
+ const uint8 *ptr = fSrcPtr + fByteOffset;
+
+ #if qDNGBigEndian
+
+ fBitBuffer = *((const uint32 *) ptr);
+
+ #else
+
+ {
+
+ uint32 b0 = ptr [0];
+ uint32 b1 = ptr [1];
+ uint32 b2 = ptr [2];
+ uint32 b3 = ptr [3];
+
+ fBitBuffer = (((((b0 << 8) | b1) << 8) | b2) << 8) | b3;
+
+ }
+
+ #endif
+
+ fBitBufferCount = 32;
+
+ fByteOffset += 4;
+
+ // Number of additional bits we need
+
+ const int32 bitsUsed = codeSize - bitsSoFar;
+
+ // Number of low order bits in the current buffer we don't care about
+
+ const int32 bitsNotUsed = 32 - bitsUsed;
+
+ code |= fBitBuffer >> bitsNotUsed;
+
+ fBitBuffer <<= bitsUsed;
+ fBitBufferCount -= bitsUsed;
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+bool dng_lzw_expander::Expand (const uint8 *sPtr,
+ uint8 *dPtr,
+ int32 sCount,
+ int32 dCount)
+ {
+
+ void *dStartPtr = dPtr;
+
+ fSrcPtr = sPtr;
+
+ fSrcCount = sCount;
+
+ fByteOffset = 0;
+
+ /* the master decode loop */
+
+ while (true)
+ {
+
+ InitTable ();
+
+ int32 code;
+
+ do
+ {
+
+ if (!GetCodeWord (code))
+ return false;
+
+ DNG_ASSERT (code <= fNextCode,
+ "Unexpected LZW code in dng_lzw_expander::Expand");
+
+ }
+ while (code == kResetCode);
+
+ if (code == kEndCode)
+ return true;
+
+ if (code > kEndCode)
+ return false;
+
+ int32 oldCode = code;
+ int32 inChar = code;
+
+ *(dPtr++) = (uint8) code;
+
+ if (--dCount == 0)
+ return true;
+
+ while (true)
+ {
+
+ if (!GetCodeWord (code))
+ return false;
+
+ if (code == kResetCode)
+ break;
+
+ if (code == kEndCode)
+ return true;
+
+ const int32 inCode = code;
+
+ bool repeatLastPixel = false;
+
+ if (code >= fNextCode)
+ {
+
+ // This is either a bad file or our code table is not big enough; we
+ // are going to repeat the last code seen and attempt to muddle thru.
+
+ code = oldCode;
+
+ repeatLastPixel = true;
+
+ }
+
+ // this can only happen if we hit 2 bad codes in a row
+
+ if (code > fNextCode)
+ return false;
+
+ const int32 depth = fTable [code].depth;
+
+ if (depth < dCount)
+ {
+
+ dCount -= depth;
+
+ dPtr += depth;
+
+ uint8 *ptr = dPtr;
+
+ // give the compiler an extra hint to optimize these as registers
+
+ const LZWExpanderNode *localTable = fTable;
+
+ int32 localCode = code;
+
+ // this is usually the hottest loop in LZW expansion
+
+ while (localCode >= kResetCode)
+ {
+
+ if (ptr <= dStartPtr)
+ return false; // about to trash memory
+
+ const LZWExpanderNode &node = localTable [localCode];
+
+ uint8 tempFinal = (uint8) node.final;
+
+ localCode = node.prefix;
+
+ // Check for bogus table entry
+
+ if (localCode < 0 || localCode > kTableSize)
+ return false;
+
+ *(--ptr) = tempFinal;
+
+ }
+
+ code = localCode;
+
+ inChar = localCode;
+
+ if (ptr <= dStartPtr)
+ return false; // about to trash memory
+
+ *(--ptr) = (uint8) inChar;
+
+ }
+
+ else
+ {
+
+ // There might not be enough room for the full code
+ // so skip the end of it.
+
+ const int32 skip = depth - dCount;
+
+ for (int32 i = 0; i < skip ; i++)
+ {
+ const LZWExpanderNode &node = fTable [code];
+ code = node.prefix;
+ }
+
+ int32 depthUsed = depth - skip;
+
+ dCount -= depthUsed;
+
+ dPtr += depthUsed;
+
+ uint8 *ptr = dPtr;
+
+ while (code >= 0)
+ {
+
+ if (ptr <= dStartPtr)
+ return false; // about to trash memory
+
+ const LZWExpanderNode &node = fTable [code];
+
+ *(--ptr) = (uint8) node.final;
+
+ code = node.prefix;
+
+ // Check for bogus table entry
+
+ if (code > kTableSize)
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+ if (repeatLastPixel)
+ {
+
+ *(dPtr++) = (uint8) inChar;
+
+ if (--dCount == 0)
+ return true;
+
+ }
+
+ if (fNextCode < kTableSize)
+ {
+
+ AddTable (oldCode, code);
+
+ }
+
+ oldCode = inCode;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+dng_row_interleaved_image::dng_row_interleaved_image (dng_image &image,
+ uint32 factor)
+
+ : dng_image (image.Bounds (),
+ image.Planes (),
+ image.PixelType ())
+
+ , fImage (image )
+ , fFactor (factor)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+int32 dng_row_interleaved_image::MapRow (int32 row) const
+ {
+
+ uint32 rows = Height ();
+
+ int32 top = Bounds ().t;
+
+ uint32 fieldRow = row - top;
+
+ for (uint32 field = 0; true; field++)
+ {
+
+ uint32 fieldRows = (rows - field + fFactor - 1) / fFactor;
+
+ if (fieldRow < fieldRows)
+ {
+
+ return fieldRow * fFactor + field + top;
+
+ }
+
+ fieldRow -= fieldRows;
+
+ }
+
+ ThrowProgramError ();
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_row_interleaved_image::DoGet (dng_pixel_buffer &buffer) const
+ {
+
+ dng_pixel_buffer tempBuffer (buffer);
+
+ for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
+ {
+
+ tempBuffer.fArea.t = MapRow (row);
+
+ tempBuffer.fArea.b = tempBuffer.fArea.t + 1;
+
+ tempBuffer.fData = (void *) buffer.DirtyPixel (row,
+ buffer.fArea.l,
+ buffer.fPlane);
+
+ fImage.Get (tempBuffer);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_row_interleaved_image::DoPut (const dng_pixel_buffer &buffer)
+ {
+
+ dng_pixel_buffer tempBuffer (buffer);
+
+ for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
+ {
+
+ tempBuffer.fArea.t = MapRow (row);
+
+ tempBuffer.fArea.b = tempBuffer.fArea.t + 1;
+
+ tempBuffer.fData = (void *) buffer.ConstPixel (row,
+ buffer.fArea.l,
+ buffer.fPlane);
+
+ fImage.Put (tempBuffer);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+static void ReorderSubTileBlocks (dng_host &host,
+ const dng_ifd &ifd,
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &tempBuffer)
+ {
+
+ uint32 tempBufferSize = buffer.fArea.W () *
+ buffer.fArea.H () *
+ buffer.fPlanes *
+ buffer.fPixelSize;
+
+ if (!tempBuffer.Get () || tempBuffer->LogicalSize () < tempBufferSize)
+ {
+
+ tempBuffer.Reset (host.Allocate (tempBufferSize));
+
+ }
+
+ uint32 blockRows = ifd.fSubTileBlockRows;
+ uint32 blockCols = ifd.fSubTileBlockCols;
+
+ uint32 rowBlocks = buffer.fArea.H () / blockRows;
+ uint32 colBlocks = buffer.fArea.W () / blockCols;
+
+ int32 rowStep = buffer.fRowStep * buffer.fPixelSize;
+ int32 colStep = buffer.fColStep * buffer.fPixelSize;
+
+ int32 rowBlockStep = rowStep * blockRows;
+ int32 colBlockStep = colStep * blockCols;
+
+ uint32 blockColBytes = blockCols * buffer.fPlanes * buffer.fPixelSize;
+
+ const uint8 *s0 = (const uint8 *) buffer.fData;
+ uint8 *d0 = tempBuffer->Buffer_uint8 ();
+
+ for (uint32 rowBlock = 0; rowBlock < rowBlocks; rowBlock++)
+ {
+
+ uint8 *d1 = d0;
+
+ for (uint32 colBlock = 0; colBlock < colBlocks; colBlock++)
+ {
+
+ uint8 *d2 = d1;
+
+ for (uint32 blockRow = 0; blockRow < blockRows; blockRow++)
+ {
+
+ for (uint32 j = 0; j < blockColBytes; j++)
+ {
+
+ d2 [j] = s0 [j];
+
+ }
+
+ s0 += blockColBytes;
+
+ d2 += rowStep;
+
+ }
+
+ d1 += colBlockStep;
+
+ }
+
+ d0 += rowBlockStep;
+
+ }
+
+ // Copy back reordered pixels.
+
+ DoCopyBytes (tempBuffer->Buffer (),
+ buffer.fData,
+ tempBufferSize);
+
+ }
+
+/*****************************************************************************/
+
+class dng_image_spooler: public dng_spooler
+ {
+
+ private:
+
+ dng_host &fHost;
+
+ const dng_ifd &fIFD;
+
+ dng_image &fImage;
+
+ dng_rect fTileArea;
+
+ uint32 fPlane;
+ uint32 fPlanes;
+
+ dng_memory_block &fBlock;
+
+ AutoPtr<dng_memory_block> &fSubTileBuffer;
+
+ dng_rect fTileStrip;
+
+ uint8 *fBuffer;
+
+ uint32 fBufferCount;
+ uint32 fBufferSize;
+
+ public:
+
+ dng_image_spooler (dng_host &host,
+ const dng_ifd &ifd,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ dng_memory_block &block,
+ AutoPtr<dng_memory_block> &subTileBuffer);
+
+ virtual ~dng_image_spooler ();
+
+ virtual void Spool (const void *data,
+ uint32 count);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_image_spooler (const dng_image_spooler &spooler);
+
+ dng_image_spooler & operator= (const dng_image_spooler &spooler);
+
+ };
+
+/*****************************************************************************/
+
+dng_image_spooler::dng_image_spooler (dng_host &host,
+ const dng_ifd &ifd,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ dng_memory_block &block,
+ AutoPtr<dng_memory_block> &subTileBuffer)
+
+ : fHost (host)
+ , fIFD (ifd)
+ , fImage (image)
+ , fTileArea (tileArea)
+ , fPlane (plane)
+ , fPlanes (planes)
+ , fBlock (block)
+ , fSubTileBuffer (subTileBuffer)
+
+ , fTileStrip ()
+ , fBuffer (NULL)
+ , fBufferCount (0)
+ , fBufferSize (0)
+
+ {
+
+ uint32 bytesPerRow = fTileArea.W () * fPlanes * (uint32) sizeof (uint16);
+
+ uint32 stripLength = Pin_uint32 (ifd.fSubTileBlockRows,
+ fBlock.LogicalSize () / bytesPerRow,
+ fTileArea.H ());
+
+ stripLength = stripLength / ifd.fSubTileBlockRows
+ * ifd.fSubTileBlockRows;
+
+ fTileStrip = fTileArea;
+ fTileStrip.b = fTileArea.t + stripLength;
+
+ fBuffer = (uint8 *) fBlock.Buffer ();
+
+ fBufferCount = 0;
+ fBufferSize = bytesPerRow * stripLength;
+
+ }
+
+/*****************************************************************************/
+
+dng_image_spooler::~dng_image_spooler ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_image_spooler::Spool (const void *data,
+ uint32 count)
+ {
+
+ while (count)
+ {
+
+ uint32 block = Min_uint32 (count, fBufferSize - fBufferCount);
+
+ if (block == 0)
+ {
+ return;
+ }
+
+ DoCopyBytes (data,
+ fBuffer + fBufferCount,
+ block);
+
+ data = ((const uint8 *) data) + block;
+
+ count -= block;
+
+ fBufferCount += block;
+
+ if (fBufferCount == fBufferSize)
+ {
+
+ fHost.SniffForAbort ();
+
+ dng_pixel_buffer buffer;
+
+ buffer.fArea = fTileStrip;
+
+ buffer.fPlane = fPlane;
+ buffer.fPlanes = fPlanes;
+
+ buffer.fRowStep = fPlanes * fTileStrip.W ();
+ buffer.fColStep = fPlanes;
+ buffer.fPlaneStep = 1;
+
+ buffer.fData = fBuffer;
+
+ buffer.fPixelType = ttShort;
+ buffer.fPixelSize = 2;
+
+ if (fIFD.fSubTileBlockRows > 1)
+ {
+
+ ReorderSubTileBlocks (fHost,
+ fIFD,
+ buffer,
+ fSubTileBuffer);
+
+ }
+
+ fImage.Put (buffer);
+
+ uint32 stripLength = fTileStrip.H ();
+
+ fTileStrip.t = fTileStrip.b;
+
+ fTileStrip.b = Min_int32 (fTileStrip.t + stripLength,
+ fTileArea.b);
+
+ fBufferCount = 0;
+
+ fBufferSize = fTileStrip.W () *
+ fTileStrip.H () *
+ fPlanes * (uint32) sizeof (uint16);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_read_image::dng_read_image ()
+
+ : fJPEGTables ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_read_image::~dng_read_image ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_read_image::ReadUncompressed (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
+ {
+
+ uint32 rows = tileArea.H ();
+ uint32 samplesPerRow = tileArea.W ();
+
+ if (ifd.fPlanarConfiguration == pcRowInterleaved)
+ {
+ rows *= planes;
+ }
+ else
+ {
+ samplesPerRow *= planes;
+ }
+
+ uint32 samplesPerTile = samplesPerRow * rows;
+
+ dng_pixel_buffer buffer;
+
+ buffer.fArea = tileArea;
+
+ buffer.fPlane = plane;
+ buffer.fPlanes = planes;
+
+ buffer.fRowStep = planes * tileArea.W ();
+
+ if (ifd.fPlanarConfiguration == pcRowInterleaved)
+ {
+ buffer.fColStep = 1;
+ buffer.fPlaneStep = tileArea.W ();
+ }
+
+ else
+ {
+ buffer.fColStep = planes;
+ buffer.fPlaneStep = 1;
+ }
+
+ if (uncompressedBuffer.Get () == NULL)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("Fuzz: Missing uncompressed buffer");
+
+ #endif
+
+ ThrowBadFormat ();
+
+ }
+
+ buffer.fData = uncompressedBuffer->Buffer ();
+
+ uint32 bitDepth = ifd.fBitsPerSample [plane];
+
+ if (bitDepth == 8)
+ {
+
+ buffer.fPixelType = ttByte;
+ buffer.fPixelSize = 1;
+
+ stream.Get (buffer.fData, samplesPerTile);
+
+ }
+
+ else if (bitDepth == 16 && ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+
+ buffer.fPixelType = ttFloat;
+ buffer.fPixelSize = 4;
+
+ uint32 *p_uint32 = (uint32 *) buffer.fData;
+
+ for (uint32 j = 0; j < samplesPerTile; j++)
+ {
+
+ p_uint32 [j] = DNG_HalfToFloat (stream.Get_uint16 ());
+
+ }
+
+ }
+
+ else if (bitDepth == 24 && ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+
+ buffer.fPixelType = ttFloat;
+ buffer.fPixelSize = 4;
+
+ uint32 *p_uint32 = (uint32 *) buffer.fData;
+
+ for (uint32 j = 0; j < samplesPerTile; j++)
+ {
+
+ uint8 input [3];
+
+ if (stream.LittleEndian ())
+ {
+ input [2] = stream.Get_uint8 ();
+ input [1] = stream.Get_uint8 ();
+ input [0] = stream.Get_uint8 ();
+ }
+
+ else
+ {
+ input [0] = stream.Get_uint8 ();
+ input [1] = stream.Get_uint8 ();
+ input [2] = stream.Get_uint8 ();
+ }
+
+ p_uint32 [j] = DNG_FP24ToFloat (input);
+
+ }
+
+ }
+
+ else if (bitDepth == 16)
+ {
+
+ buffer.fPixelType = ttShort;
+ buffer.fPixelSize = 2;
+
+ stream.Get (buffer.fData, samplesPerTile * 2);
+
+ if (stream.SwapBytes ())
+ {
+
+ DoSwapBytes16 ((uint16 *) buffer.fData,
+ samplesPerTile);
+
+ }
+
+ }
+
+ else if (bitDepth == 32)
+ {
+
+ buffer.fPixelType = image.PixelType ();
+ buffer.fPixelSize = 4;
+
+ stream.Get (buffer.fData, samplesPerTile * 4);
+
+ if (stream.SwapBytes ())
+ {
+
+ DoSwapBytes32 ((uint32 *) buffer.fData,
+ samplesPerTile);
+
+ }
+
+ }
+
+ else if (bitDepth == 12)
+ {
+
+ buffer.fPixelType = ttShort;
+ buffer.fPixelSize = 2;
+
+ uint16 *p = (uint16 *) buffer.fData;
+
+ uint32 evenSamples = samplesPerRow >> 1;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 j = 0; j < evenSamples; j++)
+ {
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+
+ p [0] = (uint16) ((b0 << 4) | (b1 >> 4));
+ p [1] = (uint16) (((b1 << 8) | b2) & 0x0FFF);
+
+ p += 2;
+
+ }
+
+ if (samplesPerRow & 1)
+ {
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+
+ p [0] = (uint16) ((b0 << 4) | (b1 >> 4));
+
+ p += 1;
+
+ }
+
+ }
+
+ }
+
+ else if (bitDepth > 8 && bitDepth < 16)
+ {
+
+ buffer.fPixelType = ttShort;
+ buffer.fPixelSize = 2;
+
+ uint16 *p = (uint16 *) buffer.fData;
+
+ uint32 bitMask = (1 << bitDepth) - 1;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint32 bitBuffer = 0;
+ uint32 bufferBits = 0;
+
+ for (uint32 j = 0; j < samplesPerRow; j++)
+ {
+
+ while (bufferBits < bitDepth)
+ {
+
+ bitBuffer = (bitBuffer << 8) | stream.Get_uint8 ();
+
+ bufferBits += 8;
+
+ }
+
+ p [j] = (uint16) ((bitBuffer >> (bufferBits - bitDepth)) & bitMask);
+
+ bufferBits -= bitDepth;
+
+ }
+
+ p += samplesPerRow;
+
+ }
+
+ }
+
+ else if (bitDepth > 16 && bitDepth < 32)
+ {
+
+ buffer.fPixelType = ttLong;
+ buffer.fPixelSize = 4;
+
+ uint32 *p = (uint32 *) buffer.fData;
+
+ uint32 bitMask = (1 << bitDepth) - 1;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint64 bitBuffer = 0;
+ uint32 bufferBits = 0;
+
+ for (uint32 j = 0; j < samplesPerRow; j++)
+ {
+
+ while (bufferBits < bitDepth)
+ {
+
+ bitBuffer = (bitBuffer << 8) | stream.Get_uint8 ();
+
+ bufferBits += 8;
+
+ }
+
+ p [j] = ((uint32) (bitBuffer >> (bufferBits - bitDepth))) & bitMask;
+
+ bufferBits -= bitDepth;
+
+ }
+
+ p += samplesPerRow;
+
+ }
+
+ }
+
+ else
+ {
+
+ return false;
+
+ }
+
+ if (ifd.fSampleBitShift)
+ {
+
+ buffer.ShiftRight (ifd.fSampleBitShift);
+
+ }
+
+ if (ifd.fSubTileBlockRows > 1)
+ {
+
+ ReorderSubTileBlocks (host,
+ ifd,
+ buffer,
+ subTileBlockBuffer);
+
+ }
+
+ image.Put (buffer);
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_read_image::DecodeLossyJPEG (dng_host &host,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 /* photometricInterpretation */,
+ uint32 jpegDataSize,
+ uint8 *jpegDataInMemory)
+ {
+
+ // The dng_sdk does not include a lossy JPEG decoder. Override this
+ // this method to add lossy JPEG support.
+
+ (void) host;
+ (void) image;
+ (void) tileArea;
+ (void) plane;
+ (void) planes;
+ (void) jpegDataSize;
+ (void) jpegDataInMemory;
+
+ ThrowProgramError ("Missing lossy JPEG decoder");
+
+ }
+
+/*****************************************************************************/
+
+static dng_memory_block * ReadJPEGDataToBlock (dng_host &host,
+ dng_stream &stream,
+ dng_memory_block *tablesBlock,
+ uint64 tileOffset,
+ uint32 tileByteCount,
+ bool patchFirstByte)
+ {
+
+ if (tileByteCount <= 2)
+ {
+ ThrowEndOfFile ();
+ }
+
+ uint32 tablesByteCount = tablesBlock ? tablesBlock->LogicalSize () : 0;
+
+ if (tablesByteCount && tablesByteCount < 4)
+ {
+ ThrowEndOfFile ();
+ }
+
+ // The JPEG tables start with a two byte SOI marker, and
+ // and end with a two byte EOI marker. The JPEG tile
+ // data also starts with a two byte SOI marker. We can
+ // convert this combination a normal JPEG stream removing
+ // the last two bytes of the JPEG tables and the first two
+ // bytes of the tile data, and then concatenating them.
+
+ if (tablesByteCount)
+ {
+
+ tablesByteCount -= 2;
+
+ tileOffset += 2;
+ tileByteCount -= 2;
+
+ }
+
+ // Allocate buffer.
+
+ AutoPtr<dng_memory_block> buffer (host.Allocate (tablesByteCount + tileByteCount));
+
+ // Read in table.
+
+ if (tablesByteCount)
+ {
+
+ DoCopyBytes (tablesBlock->Buffer (),
+ buffer->Buffer (),
+ tablesByteCount);
+
+ }
+
+ // Read in tile data.
+
+ stream.SetReadPosition (tileOffset);
+
+ stream.Get (buffer->Buffer_uint8 () + tablesByteCount, tileByteCount);
+
+ // Patch first byte, if required.
+
+ if (patchFirstByte)
+ {
+
+ buffer->Buffer_uint8 () [0] = 0xFF;
+
+ }
+
+ // Return buffer.
+
+ return buffer.Release ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_read_image::ReadBaselineJPEG (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ uint8 *jpegDataInMemory)
+ {
+
+ // Setup the data source.
+
+ if (fJPEGTables.Get () || !jpegDataInMemory)
+ {
+
+ AutoPtr<dng_memory_block> jpegDataBlock;
+
+ jpegDataBlock.Reset (ReadJPEGDataToBlock (host,
+ stream,
+ fJPEGTables.Get (),
+ stream.Position (),
+ tileByteCount,
+ ifd.fPatchFirstJPEGByte));
+
+ DecodeLossyJPEG (host,
+ image,
+ tileArea,
+ plane,
+ planes,
+ ifd.fPhotometricInterpretation,
+ jpegDataBlock->LogicalSize (),
+ jpegDataBlock->Buffer_uint8 ());
+
+ }
+
+ else
+ {
+
+ if (ifd.fPatchFirstJPEGByte && tileByteCount)
+ {
+ jpegDataInMemory [0] = 0xFF;
+ }
+
+ DecodeLossyJPEG (host,
+ image,
+ tileArea,
+ plane,
+ planes,
+ ifd.fPhotometricInterpretation,
+ tileByteCount,
+ jpegDataInMemory);
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_read_image::ReadLosslessJPEG (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
+ {
+
+ uint32 bytesPerRow = tileArea.W () * planes * (uint32) sizeof (uint16);
+
+ uint32 rowsPerStrip = Pin_uint32 (ifd.fSubTileBlockRows,
+ kImageBufferSize / bytesPerRow,
+ tileArea.H ());
+
+ rowsPerStrip = rowsPerStrip / ifd.fSubTileBlockRows
+ * ifd.fSubTileBlockRows;
+
+ uint32 bufferSize = bytesPerRow * rowsPerStrip;
+
+ if (uncompressedBuffer.Get () &&
+ uncompressedBuffer->LogicalSize () < bufferSize)
+ {
+
+ uncompressedBuffer.Reset ();
+
+ }
+
+ if (uncompressedBuffer.Get () == NULL)
+ {
+
+ uncompressedBuffer.Reset (host.Allocate (bufferSize));
+
+ }
+
+ dng_image_spooler spooler (host,
+ ifd,
+ image,
+ tileArea,
+ plane,
+ planes,
+ *uncompressedBuffer.Get (),
+ subTileBlockBuffer);
+
+ uint32 decodedSize = tileArea.W () *
+ tileArea.H () *
+ planes * (uint32) sizeof (uint16);
+
+ bool bug16 = ifd.fLosslessJPEGBug16;
+
+ uint64 tileOffset = stream.Position ();
+
+ DecodeLosslessJPEG (stream,
+ spooler,
+ decodedSize,
+ decodedSize,
+ bug16);
+
+ if (stream.Position () > tileOffset + tileByteCount)
+ {
+ ThrowBadFormat ();
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_read_image::CanReadTile (const dng_ifd &ifd)
+ {
+
+ if (ifd.fSampleFormat [0] != sfUnsignedInteger &&
+ ifd.fSampleFormat [0] != sfFloatingPoint)
+ {
+ return false;
+ }
+
+ switch (ifd.fCompression)
+ {
+
+ case ccUncompressed:
+ {
+
+ if (ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+
+ return (ifd.fBitsPerSample [0] == 16 ||
+ ifd.fBitsPerSample [0] == 24 ||
+ ifd.fBitsPerSample [0] == 32);
+
+ }
+
+ return ifd.fBitsPerSample [0] >= 8 &&
+ ifd.fBitsPerSample [0] <= 32;
+
+ }
+
+ case ccJPEG:
+ {
+
+ if (ifd.fSampleFormat [0] != sfUnsignedInteger)
+ {
+ return false;
+ }
+
+ if (ifd.IsBaselineJPEG ())
+ {
+
+ // Baseline JPEG.
+
+ return true;
+
+ }
+
+ else
+ {
+
+ // Lossless JPEG.
+
+ return ifd.fBitsPerSample [0] >= 8 &&
+ ifd.fBitsPerSample [0] <= 16;
+
+ }
+
+ break;
+
+ }
+
+ case ccLZW:
+ case ccDeflate:
+ case ccOldDeflate:
+ case ccPackBits:
+ {
+
+ if (ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+
+ if (ifd.fCompression == ccPackBits)
+ {
+ return false;
+ }
+
+ if (ifd.fPredictor != cpNullPredictor &&
+ ifd.fPredictor != cpFloatingPoint &&
+ ifd.fPredictor != cpFloatingPointX2 &&
+ ifd.fPredictor != cpFloatingPointX4)
+ {
+ return false;
+ }
+
+ if (ifd.fBitsPerSample [0] != 16 &&
+ ifd.fBitsPerSample [0] != 24 &&
+ ifd.fBitsPerSample [0] != 32)
+ {
+ return false;
+ }
+
+ }
+
+ else
+ {
+
+ if (ifd.fPredictor != cpNullPredictor &&
+ ifd.fPredictor != cpHorizontalDifference &&
+ ifd.fPredictor != cpHorizontalDifferenceX2 &&
+ ifd.fPredictor != cpHorizontalDifferenceX4)
+ {
+ return false;
+ }
+
+ if (ifd.fBitsPerSample [0] != 8 &&
+ ifd.fBitsPerSample [0] != 16 &&
+ ifd.fBitsPerSample [0] != 32)
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+ default:
+ {
+ break;
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_read_image::NeedsCompressedBuffer (const dng_ifd &ifd)
+ {
+
+ if (ifd.fCompression == ccLZW ||
+ ifd.fCompression == ccDeflate ||
+ ifd.fCompression == ccOldDeflate ||
+ ifd.fCompression == ccPackBits)
+ {
+ return true;
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_read_image::ByteSwapBuffer (dng_host & /* host */,
+ dng_pixel_buffer &buffer)
+ {
+
+ uint32 pixels = buffer.fRowStep * buffer.fArea.H ();
+
+ switch (buffer.fPixelSize)
+ {
+
+ case 2:
+ {
+
+ DoSwapBytes16 ((uint16 *) buffer.fData,
+ pixels);
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ DoSwapBytes32 ((uint32 *) buffer.fData,
+ pixels);
+
+ break;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_read_image::DecodePredictor (dng_host & /* host */,
+ const dng_ifd &ifd,
+ dng_pixel_buffer &buffer)
+ {
+
+ switch (ifd.fPredictor)
+ {
+
+ case cpNullPredictor:
+ {
+
+ return;
+
+ }
+
+ case cpHorizontalDifference:
+ case cpHorizontalDifferenceX2:
+ case cpHorizontalDifferenceX4:
+ {
+
+ int32 xFactor = 1;
+
+ if (ifd.fPredictor == cpHorizontalDifferenceX2)
+ {
+ xFactor = 2;
+ }
+
+ else if (ifd.fPredictor == cpHorizontalDifferenceX4)
+ {
+ xFactor = 4;
+ }
+
+ switch (buffer.fPixelType)
+ {
+
+ case ttByte:
+ {
+
+ DecodeDelta8 ((uint8 *) buffer.fData,
+ buffer.fArea.H (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor);
+
+ return;
+
+ }
+
+ case ttShort:
+ {
+
+ DecodeDelta16 ((uint16 *) buffer.fData,
+ buffer.fArea.H (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor);
+
+ return;
+
+ }
+
+ case ttLong:
+ {
+
+ DecodeDelta32 ((uint32 *) buffer.fData,
+ buffer.fArea.H (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor);
+
+ return;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ break;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ ThrowBadFormat ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_read_image::ReadTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
+ {
+
+ switch (ifd.fCompression)
+ {
+ case ccLZW:
+ case ccDeflate:
+ case ccOldDeflate:
+ case ccPackBits:
+ {
+
+ // Figure out uncompressed size.
+
+ uint32 bytesPerSample = (ifd.fBitsPerSample [0] >> 3);
+
+ uint32 sampleCount = planes * tileArea.W () * tileArea.H ();
+
+ uint32 uncompressedSize = sampleCount * bytesPerSample;
+
+ // Setup pixel buffer to hold uncompressed data.
+
+ dng_pixel_buffer buffer;
+
+ if (ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+ buffer.fPixelType = ttFloat;
+ }
+
+ else if (ifd.fBitsPerSample [0] == 8)
+ {
+ buffer.fPixelType = ttByte;
+ }
+
+ else if (ifd.fBitsPerSample [0] == 16)
+ {
+ buffer.fPixelType = ttShort;
+ }
+
+ else if (ifd.fBitsPerSample [0] == 32)
+ {
+ buffer.fPixelType = ttLong;
+ }
+
+ else
+ {
+ ThrowBadFormat ();
+ }
+
+ buffer.fPixelSize = bytesPerSample;
+
+ buffer.fArea = tileArea;
+
+ buffer.fPlane = plane;
+ buffer.fPlanes = planes;
+
+ buffer.fPlaneStep = 1;
+
+ buffer.fColStep = planes;
+ buffer.fRowStep = planes * tileArea.W ();
+
+ uint32 bufferSize = uncompressedSize;
+
+ // If we are using the floating point predictor, we need an extra
+ // buffer row.
+
+ if (ifd.fPredictor == cpFloatingPoint ||
+ ifd.fPredictor == cpFloatingPointX2 ||
+ ifd.fPredictor == cpFloatingPointX4)
+ {
+ bufferSize += buffer.fRowStep * buffer.fPixelSize;
+ }
+
+ // If are processing less than full size floating point data,
+ // we need space to expand the data to full floating point size.
+
+ if (buffer.fPixelType == ttFloat)
+ {
+ bufferSize = Max_uint32 (bufferSize, sampleCount * 4);
+ }
+
+ // Sometimes with multi-threading and planar image using strips,
+ // we can process a small tile before a large tile on a thread.
+ // Simple fix is to just reallocate the buffer if it is too small.
+
+ if (uncompressedBuffer.Get () &&
+ uncompressedBuffer->LogicalSize () < bufferSize)
+ {
+
+ uncompressedBuffer.Reset ();
+
+ }
+
+ if (uncompressedBuffer.Get () == NULL)
+ {
+
+ uncompressedBuffer.Reset (host.Allocate (bufferSize));
+
+ }
+
+ buffer.fData = uncompressedBuffer->Buffer ();
+
+ // If using floating point predictor, move buffer pointer to second row.
+
+ if (ifd.fPredictor == cpFloatingPoint ||
+ ifd.fPredictor == cpFloatingPointX2 ||
+ ifd.fPredictor == cpFloatingPointX4)
+ {
+
+ buffer.fData = (uint8 *) buffer.fData +
+ buffer.fRowStep * buffer.fPixelSize;
+
+ }
+
+ // Decompress the data.
+
+ if (ifd.fCompression == ccLZW)
+ {
+
+ dng_lzw_expander expander;
+
+ if (!expander.Expand (compressedBuffer->Buffer_uint8 (),
+ (uint8 *) buffer.fData,
+ tileByteCount,
+ uncompressedSize))
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ else if (ifd.fCompression == ccPackBits)
+ {
+
+ dng_stream subStream (compressedBuffer->Buffer_uint8 (),
+ tileByteCount);
+
+ if (!DecodePackBits (subStream,
+ (uint8 *) buffer.fData,
+ uncompressedSize))
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ else
+ {
+ // Not supported currently
+ ThrowProgramError();
+ }
+
+ // The floating point predictor is byte order independent.
+
+ if (ifd.fPredictor == cpFloatingPoint ||
+ ifd.fPredictor == cpFloatingPointX2 ||
+ ifd.fPredictor == cpFloatingPointX4)
+ {
+
+ int32 xFactor = 1;
+
+ if (ifd.fPredictor == cpFloatingPointX2)
+ {
+ xFactor = 2;
+ }
+
+ else if (ifd.fPredictor == cpFloatingPointX4)
+ {
+ xFactor = 4;
+ }
+
+ for (int32 row = tileArea.t; row < tileArea.b; row++)
+ {
+
+ uint8 *srcPtr = (uint8 *) buffer.DirtyPixel (row , tileArea.l, plane);
+ uint8 *dstPtr = (uint8 *) buffer.DirtyPixel (row - 1, tileArea.l, plane);
+
+ DecodeFPDelta (srcPtr,
+ dstPtr,
+ tileArea.W () / xFactor,
+ planes * xFactor,
+ bytesPerSample);
+
+ }
+
+ buffer.fData = (uint8 *) buffer.fData -
+ buffer.fRowStep * buffer.fPixelSize;
+
+ }
+
+ else
+ {
+
+ // Both these compression algorithms are byte based.
+
+ if (stream.SwapBytes ())
+ {
+
+ ByteSwapBuffer (host,
+ buffer);
+
+ }
+
+ // Undo the predictor.
+
+ DecodePredictor (host,
+ ifd,
+ buffer);
+
+ }
+
+ // Expand floating point data, if needed.
+
+ if (buffer.fPixelType == ttFloat && buffer.fPixelSize == 2)
+ {
+
+ uint16 *srcPtr = (uint16 *) buffer.fData;
+ uint32 *dstPtr = (uint32 *) buffer.fData;
+
+ for (int32 index = sampleCount - 1; index >= 0; index--)
+ {
+
+ dstPtr [index] = DNG_HalfToFloat (srcPtr [index]);
+
+ }
+
+ buffer.fPixelSize = 4;
+
+ }
+
+ else if (buffer.fPixelType == ttFloat && buffer.fPixelSize == 3)
+ {
+
+ uint8 *srcPtr = ((uint8 *) buffer.fData) + (sampleCount - 1) * 3;
+ uint32 *dstPtr = ((uint32 *) buffer.fData) + (sampleCount - 1);
+
+ if (stream.BigEndian () || ifd.fPredictor == cpFloatingPoint ||
+ ifd.fPredictor == cpFloatingPointX2 ||
+ ifd.fPredictor == cpFloatingPointX4)
+ {
+
+ for (uint32 index = 0; index < sampleCount; index++)
+ {
+
+ *(dstPtr--) = DNG_FP24ToFloat (srcPtr);
+
+ srcPtr -= 3;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 index = 0; index < sampleCount; index++)
+ {
+
+ uint8 input [3];
+
+ input [2] = srcPtr [0];
+ input [1] = srcPtr [1];
+ input [0] = srcPtr [2];
+
+ *(dstPtr--) = DNG_FP24ToFloat (input);
+
+ srcPtr -= 3;
+
+ }
+
+ }
+
+ buffer.fPixelSize = 4;
+
+ }
+
+ // Save the data.
+
+ image.Put (buffer);
+
+ return;
+
+ }
+
+ case ccUncompressed:
+ {
+
+ if (ReadUncompressed (host,
+ ifd,
+ stream,
+ image,
+ tileArea,
+ plane,
+ planes,
+ uncompressedBuffer,
+ subTileBlockBuffer))
+ {
+
+ return;
+
+ }
+
+ break;
+
+ }
+
+ case ccJPEG:
+ {
+
+ if (ifd.IsBaselineJPEG ())
+ {
+
+ // Baseline JPEG.
+
+ if (ReadBaselineJPEG (host,
+ ifd,
+ stream,
+ image,
+ tileArea,
+ plane,
+ planes,
+ tileByteCount,
+ compressedBuffer.Get () ? compressedBuffer->Buffer_uint8 () : NULL))
+ {
+
+ return;
+
+ }
+
+ }
+
+ else
+ {
+
+ // Otherwise is should be lossless JPEG.
+
+ if (ReadLosslessJPEG (host,
+ ifd,
+ stream,
+ image,
+ tileArea,
+ plane,
+ planes,
+ tileByteCount,
+ uncompressedBuffer,
+ subTileBlockBuffer))
+ {
+
+ return;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case ccLossyJPEG:
+ {
+
+ if (ReadBaselineJPEG (host,
+ ifd,
+ stream,
+ image,
+ tileArea,
+ plane,
+ planes,
+ tileByteCount,
+ compressedBuffer.Get () ? compressedBuffer->Buffer_uint8 () : NULL))
+ {
+
+ return;
+
+ }
+
+ break;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ ThrowBadFormat ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_read_image::CanRead (const dng_ifd &ifd)
+ {
+
+ if (ifd.fImageWidth < 1 ||
+ ifd.fImageLength < 1)
+ {
+ return false;
+ }
+
+ if (ifd.fSamplesPerPixel < 1)
+ {
+ return false;
+ }
+
+ if (ifd.fBitsPerSample [0] < 1)
+ {
+ return false;
+ }
+
+ for (uint32 j = 1; j < Min_uint32 (ifd.fSamplesPerPixel,
+ kMaxSamplesPerPixel); j++)
+ {
+
+ if (ifd.fBitsPerSample [j] !=
+ ifd.fBitsPerSample [0])
+ {
+ return false;
+ }
+
+ if (ifd.fSampleFormat [j] !=
+ ifd.fSampleFormat [0])
+ {
+ return false;
+ }
+
+ }
+
+ if ((ifd.fPlanarConfiguration != pcInterleaved ) &&
+ (ifd.fPlanarConfiguration != pcPlanar ) &&
+ (ifd.fPlanarConfiguration != pcRowInterleaved))
+ {
+ return false;
+ }
+
+ if (ifd.fUsesStrips == ifd.fUsesTiles)
+ {
+ return false;
+ }
+
+ uint32 tileCount = ifd.TilesPerImage ();
+
+ if (tileCount < 1)
+ {
+ return false;
+ }
+
+ bool needTileByteCounts = (ifd.TileByteCount (ifd.TileArea (0, 0)) == 0);
+
+ if (tileCount == 1)
+ {
+
+ if (needTileByteCounts)
+ {
+
+ if (ifd.fTileByteCount [0] < 1)
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ if (ifd.fTileOffsetsCount != tileCount)
+ {
+ return false;
+ }
+
+ if (needTileByteCounts)
+ {
+
+ if (ifd.fTileByteCountsCount != tileCount)
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ if (!CanReadTile (ifd))
+ {
+ return false;
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+class dng_read_tiles_task : public dng_area_task
+ {
+
+ private:
+
+ dng_read_image &fReadImage;
+
+ dng_host &fHost;
+
+ const dng_ifd &fIFD;
+
+ dng_stream &fStream;
+
+ dng_image &fImage;
+
+ dng_jpeg_image *fJPEGImage;
+
+ dng_fingerprint *fJPEGTileDigest;
+
+ uint32 fOuterSamples;
+
+ uint32 fInnerSamples;
+
+ uint32 fTilesDown;
+
+ uint32 fTilesAcross;
+
+ uint64 *fTileOffset;
+
+ uint32 *fTileByteCount;
+
+ uint32 fCompressedSize;
+
+ uint32 fUncompressedSize;
+
+ dng_mutex fMutex;
+
+ uint32 fNextTileIndex;
+
+ public:
+
+ dng_read_tiles_task (dng_read_image &readImage,
+ dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ dng_jpeg_image *jpegImage,
+ dng_fingerprint *jpegTileDigest,
+ uint32 outerSamples,
+ uint32 innerSamples,
+ uint32 tilesDown,
+ uint32 tilesAcross,
+ uint64 *tileOffset,
+ uint32 *tileByteCount,
+ uint32 compressedSize,
+ uint32 uncompressedSize)
+
+ : fReadImage (readImage)
+ , fHost (host)
+ , fIFD (ifd)
+ , fStream (stream)
+ , fImage (image)
+ , fJPEGImage (jpegImage)
+ , fJPEGTileDigest (jpegTileDigest)
+ , fOuterSamples (outerSamples)
+ , fInnerSamples (innerSamples)
+ , fTilesDown (tilesDown)
+ , fTilesAcross (tilesAcross)
+ , fTileOffset (tileOffset)
+ , fTileByteCount (tileByteCount)
+ , fCompressedSize (compressedSize)
+ , fUncompressedSize (uncompressedSize)
+ , fMutex ("dng_read_tiles_task")
+ , fNextTileIndex (0)
+
+ {
+
+ fMinTaskArea = 16 * 16;
+ fUnitCell = dng_point (16, 16);
+ fMaxTileSize = dng_point (16, 16);
+
+ }
+
+ void Process (uint32 /* threadIndex */,
+ const dng_rect & /* tile */,
+ dng_abort_sniffer *sniffer)
+ {
+
+ AutoPtr<dng_memory_block> compressedBuffer;
+ AutoPtr<dng_memory_block> uncompressedBuffer;
+ AutoPtr<dng_memory_block> subTileBlockBuffer;
+
+ if (!fJPEGImage)
+ {
+ compressedBuffer.Reset (fHost.Allocate (fCompressedSize));
+ }
+
+ if (fUncompressedSize)
+ {
+ uncompressedBuffer.Reset (fHost.Allocate (fUncompressedSize));
+ }
+
+ while (true)
+ {
+
+ uint32 tileIndex;
+ uint32 byteCount;
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ if (fNextTileIndex == fOuterSamples * fTilesDown * fTilesAcross)
+ {
+ return;
+ }
+
+ tileIndex = fNextTileIndex++;
+
+ TempStreamSniffer noSniffer (fStream, NULL);
+
+ fStream.SetReadPosition (fTileOffset [tileIndex]);
+
+ byteCount = fTileByteCount [tileIndex];
+
+ if (fJPEGImage)
+ {
+
+ fJPEGImage->fJPEGData [tileIndex] . Reset (fHost.Allocate (byteCount));
+
+ }
+
+ fStream.Get (fJPEGImage ? fJPEGImage->fJPEGData [tileIndex]->Buffer ()
+ : compressedBuffer->Buffer (),
+ byteCount);
+
+ }
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ if (fJPEGTileDigest)
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (compressedBuffer->Buffer (),
+ byteCount);
+
+ fJPEGTileDigest [tileIndex] = printer.Result ();
+
+ }
+
+ dng_stream tileStream (fJPEGImage ? fJPEGImage->fJPEGData [tileIndex]->Buffer ()
+ : compressedBuffer->Buffer (),
+ byteCount);
+
+ tileStream.SetLittleEndian (fStream.LittleEndian ());
+
+ uint32 plane = tileIndex / (fTilesDown * fTilesAcross);
+
+ uint32 rowIndex = (tileIndex - plane * fTilesDown * fTilesAcross) / fTilesAcross;
+
+ uint32 colIndex = tileIndex - (plane * fTilesDown + rowIndex) * fTilesAcross;
+
+ dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
+
+ dng_host host (&fHost.Allocator (),
+ sniffer); // Cannot use sniffer attached to main host
+
+ fReadImage.ReadTile (host,
+ fIFD,
+ tileStream,
+ fImage,
+ tileArea,
+ plane,
+ fInnerSamples,
+ byteCount,
+ fJPEGImage ? fJPEGImage->fJPEGData [tileIndex]
+ : compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer);
+
+ }
+
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_read_tiles_task (const dng_read_tiles_task &);
+
+ dng_read_tiles_task & operator= (const dng_read_tiles_task &);
+
+ };
+
+/*****************************************************************************/
+
+void dng_read_image::Read (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ dng_jpeg_image *jpegImage,
+ dng_fingerprint *jpegDigest)
+ {
+
+ uint32 tileIndex;
+
+ // Deal with row interleaved images.
+
+ if (ifd.fRowInterleaveFactor > 1 &&
+ ifd.fRowInterleaveFactor < ifd.fImageLength)
+ {
+
+ dng_ifd tempIFD (ifd);
+
+ tempIFD.fRowInterleaveFactor = 1;
+
+ dng_row_interleaved_image tempImage (image,
+ ifd.fRowInterleaveFactor);
+
+ Read (host,
+ tempIFD,
+ stream,
+ tempImage,
+ jpegImage,
+ jpegDigest);
+
+ return;
+
+ }
+
+ // Figure out inner and outer samples.
+
+ uint32 innerSamples = 1;
+ uint32 outerSamples = 1;
+
+ if (ifd.fPlanarConfiguration == pcPlanar)
+ {
+ outerSamples = ifd.fSamplesPerPixel;
+ }
+ else
+ {
+ innerSamples = ifd.fSamplesPerPixel;
+ }
+
+ // Calculate number of tiles to read.
+
+ uint32 tilesAcross = ifd.TilesAcross ();
+ uint32 tilesDown = ifd.TilesDown ();
+
+ uint32 tileCount = tilesAcross * tilesDown * outerSamples;
+
+ // Find the tile offsets.
+
+ dng_memory_data tileOffsetData (tileCount * (uint32) sizeof (uint64));
+
+ uint64 *tileOffset = tileOffsetData.Buffer_uint64 ();
+
+ if (tileCount <= dng_ifd::kMaxTileInfo)
+ {
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ tileOffset [tileIndex] = ifd.fTileOffset [tileIndex];
+
+ }
+
+ }
+
+ else
+ {
+
+ stream.SetReadPosition (ifd.fTileOffsetsOffset);
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ tileOffset [tileIndex] = stream.TagValue_uint32 (ifd.fTileOffsetsType);
+
+ }
+
+ }
+
+ // Quick validity check on tile offsets.
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ #if qDNGValidate
+
+ if (tileOffset [tileIndex] < 8)
+ {
+
+ ReportWarning ("Tile/Strip offset less than 8");
+
+ }
+
+ #endif
+
+ if (tileOffset [tileIndex] >= stream.Length ())
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+ // Buffer to hold the tile byte counts, if needed.
+
+ dng_memory_data tileByteCountData;
+
+ uint32 *tileByteCount = NULL;
+
+ // If we can compute the number of bytes needed to store the
+ // data, we can split the read for each tile into sub-tiles.
+
+ uint32 uncompressedSize = 0;
+
+ uint32 subTileLength = ifd.fTileLength;
+
+ if (ifd.TileByteCount (ifd.TileArea (0, 0)) != 0)
+ {
+
+ uint32 bytesPerPixel = TagTypeSize (ifd.PixelType ());
+
+ uint32 bytesPerRow = ifd.fTileWidth * innerSamples * bytesPerPixel;
+
+ subTileLength = Pin_uint32 (ifd.fSubTileBlockRows,
+ kImageBufferSize / bytesPerRow,
+ ifd.fTileLength);
+
+ subTileLength = subTileLength / ifd.fSubTileBlockRows
+ * ifd.fSubTileBlockRows;
+
+ uncompressedSize = subTileLength * bytesPerRow;
+
+ }
+
+ // Else we need to know the byte counts.
+
+ else
+ {
+
+ tileByteCountData.Allocate (tileCount * (uint32) sizeof (uint32));
+
+ tileByteCount = tileByteCountData.Buffer_uint32 ();
+
+ if (tileCount <= dng_ifd::kMaxTileInfo)
+ {
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ tileByteCount [tileIndex] = ifd.fTileByteCount [tileIndex];
+
+ }
+
+ }
+
+ else
+ {
+
+ stream.SetReadPosition (ifd.fTileByteCountsOffset);
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ tileByteCount [tileIndex] = stream.TagValue_uint32 (ifd.fTileByteCountsType);
+
+ }
+
+ }
+
+ // Quick validity check on tile byte counts.
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ if (tileByteCount [tileIndex] < 1 ||
+ tileByteCount [tileIndex] > stream.Length ())
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+ }
+
+ // Find maximum tile size, if possible.
+
+ uint32 maxTileByteCount = 0;
+
+ if (tileByteCount)
+ {
+
+ for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ maxTileByteCount = Max_uint32 (maxTileByteCount,
+ tileByteCount [tileIndex]);
+
+ }
+
+ }
+
+ // Do we need a compressed data buffer?
+
+ uint32 compressedSize = 0;
+
+ bool needsCompressedBuffer = NeedsCompressedBuffer (ifd);
+
+ if (needsCompressedBuffer)
+ {
+
+ if (!tileByteCount)
+ {
+ ThrowBadFormat ();
+ }
+
+ compressedSize = maxTileByteCount;
+
+ }
+
+ // Are we keeping the compressed JPEG image data?
+
+ if (jpegImage)
+ {
+
+ if (ifd.IsBaselineJPEG ())
+ {
+
+ jpegImage->fImageSize.h = ifd.fImageWidth;
+ jpegImage->fImageSize.v = ifd.fImageLength;
+
+ jpegImage->fTileSize.h = ifd.fTileWidth;
+ jpegImage->fTileSize.v = ifd.fTileLength;
+
+ jpegImage->fUsesStrips = ifd.fUsesStrips;
+
+ jpegImage->fJPEGData.Reset (new dng_jpeg_image_tile_ptr [tileCount]);
+
+ }
+
+ else
+ {
+
+ jpegImage = NULL;
+
+ }
+
+ }
+
+ // Do we need to read the JPEG tables?
+
+ if (ifd.fJPEGTablesOffset && ifd.fJPEGTablesCount)
+ {
+
+ if (ifd.IsBaselineJPEG ())
+ {
+
+ fJPEGTables.Reset (host.Allocate (ifd.fJPEGTablesCount));
+
+ stream.SetReadPosition (ifd.fJPEGTablesOffset);
+
+ stream.Get (fJPEGTables->Buffer (),
+ fJPEGTables->LogicalSize ());
+
+ }
+
+ }
+
+ AutoArray<dng_fingerprint> jpegTileDigest;
+
+ if (jpegDigest)
+ {
+
+ jpegTileDigest.Reset (new dng_fingerprint [tileCount + (fJPEGTables.Get () ? 1 : 0)]);
+
+ }
+
+ // Don't read planes we are not actually saving.
+
+ outerSamples = Min_uint32 (image.Planes (), outerSamples);
+
+ // See if we can do this read using multiple threads.
+
+ bool useMultipleThreads = (outerSamples * tilesDown * tilesAcross >= 2) &&
+ (host.PerformAreaTaskThreads () > 1) &&
+ (maxTileByteCount > 0 && maxTileByteCount <= 1024 * 1024) &&
+ (subTileLength == ifd.fTileLength) &&
+ (ifd.fCompression != ccUncompressed);
+
+#if qImagecore
+ useMultipleThreads = false;
+#endif
+
+ if (useMultipleThreads)
+ {
+
+ uint32 threadCount = Min_uint32 (outerSamples * tilesDown * tilesAcross,
+ host.PerformAreaTaskThreads ());
+
+ dng_read_tiles_task task (*this,
+ host,
+ ifd,
+ stream,
+ image,
+ jpegImage,
+ jpegTileDigest.Get (),
+ outerSamples,
+ innerSamples,
+ tilesDown,
+ tilesAcross,
+ tileOffset,
+ tileByteCount,
+ maxTileByteCount,
+ uncompressedSize);
+
+ host.PerformAreaTask (task,
+ dng_rect (0, 0, 16, 16 * threadCount));
+
+ }
+
+ // Else use a single thread to read all the tiles.
+
+ else
+ {
+
+ AutoPtr<dng_memory_block> compressedBuffer;
+ AutoPtr<dng_memory_block> uncompressedBuffer;
+ AutoPtr<dng_memory_block> subTileBlockBuffer;
+
+ if (uncompressedSize)
+ {
+ uncompressedBuffer.Reset (host.Allocate (uncompressedSize));
+ }
+
+ if (compressedSize && !jpegImage)
+ {
+ compressedBuffer.Reset (host.Allocate (compressedSize));
+ }
+
+ else if (jpegDigest)
+ {
+ compressedBuffer.Reset (host.Allocate (maxTileByteCount));
+ }
+
+ tileIndex = 0;
+
+ for (uint32 plane = 0; plane < outerSamples; plane++)
+ {
+
+ for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
+ {
+
+ for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
+ {
+
+ stream.SetReadPosition (tileOffset [tileIndex]);
+
+ dng_rect tileArea = ifd.TileArea (rowIndex, colIndex);
+
+ uint32 subTileCount = (tileArea.H () + subTileLength - 1) /
+ subTileLength;
+
+ for (uint32 subIndex = 0; subIndex < subTileCount; subIndex++)
+ {
+
+ host.SniffForAbort ();
+
+ dng_rect subArea (tileArea);
+
+ subArea.t = tileArea.t + subIndex * subTileLength;
+
+ subArea.b = Min_int32 (subArea.t + subTileLength,
+ tileArea.b);
+
+ uint32 subByteCount;
+
+ if (tileByteCount)
+ {
+ subByteCount = tileByteCount [tileIndex];
+ }
+ else
+ {
+ subByteCount = ifd.TileByteCount (subArea);
+ }
+
+ if (jpegImage)
+ {
+
+ jpegImage->fJPEGData [tileIndex].Reset (host.Allocate (subByteCount));
+
+ stream.Get (jpegImage->fJPEGData [tileIndex]->Buffer (), subByteCount);
+
+ stream.SetReadPosition (tileOffset [tileIndex]);
+
+ }
+
+ else if ((needsCompressedBuffer || jpegDigest) && subByteCount)
+ {
+
+ stream.Get (compressedBuffer->Buffer (), subByteCount);
+
+ if (jpegDigest)
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (compressedBuffer->Buffer (),
+ subByteCount);
+
+ jpegTileDigest [tileIndex] = printer.Result ();
+
+ }
+
+ }
+
+ ReadTile (host,
+ ifd,
+ stream,
+ image,
+ subArea,
+ plane,
+ innerSamples,
+ subByteCount,
+ jpegImage ? jpegImage->fJPEGData [tileIndex] : compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer);
+
+ }
+
+ tileIndex++;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Finish up JPEG digest computation, if needed.
+
+ if (jpegDigest)
+ {
+
+ if (fJPEGTables.Get ())
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (fJPEGTables->Buffer (),
+ fJPEGTables->LogicalSize ());
+
+ jpegTileDigest [tileCount] = printer.Result ();
+
+ }
+
+ dng_md5_printer printer2;
+
+ for (uint32 j = 0; j < tileCount + (fJPEGTables.Get () ? 1 : 0); j++)
+ {
+
+ printer2.Process (jpegTileDigest [j].data,
+ dng_fingerprint::kDNGFingerprintSize);
+
+ }
+
+ *jpegDigest = printer2.Result ();
+
+ }
+
+ // Keep the JPEG table in the jpeg image, if any.
+
+ if (jpegImage)
+ {
+
+ jpegImage->fJPEGTables.Reset (fJPEGTables.Release ());
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_read_image.h b/gpr/source/lib/dng_sdk/dng_read_image.h
new file mode 100644
index 0000000..bd79e55
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_read_image.h
@@ -0,0 +1,182 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_read_image.h#2 $ */
+/* $DateTime: 2012/06/05 11:05:39 $ */
+/* $Change: 833352 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Support for DNG image reading.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_read_image__
+#define __dng_read_image__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_image.h"
+#include "dng_memory.h"
+#include "dng_types.h"
+
+/******************************************************************************/
+
+bool DecodePackBits (dng_stream &stream,
+ uint8 *dPtr,
+ int32 dstCount);
+
+/*****************************************************************************/
+
+class dng_row_interleaved_image: public dng_image
+ {
+
+ private:
+
+ dng_image &fImage;
+
+ uint32 fFactor;
+
+ public:
+
+ dng_row_interleaved_image (dng_image &image,
+ uint32 factor);
+
+ virtual void DoGet (dng_pixel_buffer &buffer) const;
+
+ virtual void DoPut (const dng_pixel_buffer &buffer);
+
+ private:
+
+ int32 MapRow (int32 row) const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief
+///
+///
+
+class dng_read_image
+ {
+
+ friend class dng_read_tiles_task;
+
+ protected:
+
+ enum
+ {
+
+ // Target size for buffer used to copy data to the image.
+
+ kImageBufferSize = 128 * 1024
+
+ };
+
+ AutoPtr<dng_memory_block> fJPEGTables;
+
+ public:
+
+ dng_read_image ();
+
+ virtual ~dng_read_image ();
+
+ ///
+ /// \param
+
+ virtual bool CanRead (const dng_ifd &ifd);
+
+ ///
+ /// \param host Host used for memory allocation, progress updating, and abort testing.
+ /// \param ifd
+ /// \param stream Stream to read image data from.
+ /// \param image Result image to populate.
+
+ virtual void Read (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ dng_jpeg_image *jpegImage,
+ dng_fingerprint *jpegDigest);
+
+ protected:
+
+ virtual bool ReadUncompressed (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer);
+
+ virtual void DecodeLossyJPEG (dng_host &host,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 photometricInterpretation,
+ uint32 jpegDataSize,
+ uint8 *jpegDataInMemory);
+
+ virtual bool ReadBaselineJPEG (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ uint8 *jpegDataInMemory);
+
+ virtual bool ReadLosslessJPEG (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer);
+
+ virtual bool CanReadTile (const dng_ifd &ifd);
+
+ virtual bool NeedsCompressedBuffer (const dng_ifd &ifd);
+
+ virtual void ByteSwapBuffer (dng_host &host,
+ dng_pixel_buffer &buffer);
+
+ virtual void DecodePredictor (dng_host &host,
+ const dng_ifd &ifd,
+ dng_pixel_buffer &buffer);
+
+ virtual void ReadTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_rect.cpp b/gpr/source/lib/dng_sdk/dng_rect.cpp
new file mode 100644
index 0000000..c45e03f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_rect.cpp
@@ -0,0 +1,168 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_rect.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_rect.h"
+
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+bool dng_rect::operator== (const dng_rect &rect) const
+ {
+
+ return (rect.t == t) &&
+ (rect.l == l) &&
+ (rect.b == b) &&
+ (rect.r == r);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_rect::IsZero () const
+ {
+
+ return (t == 0) && (l == 0) && (b == 0) && (r == 0);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_rect_real64::operator== (const dng_rect_real64 &rect) const
+ {
+
+ return (rect.t == t) &&
+ (rect.l == l) &&
+ (rect.b == b) &&
+ (rect.r == r);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_rect_real64::IsZero () const
+ {
+
+ return (t == 0.0) && (l == 0.0) && (b == 0.0) && (r == 0.0);
+
+ }
+
+/*****************************************************************************/
+
+dng_rect operator& (const dng_rect &a,
+ const dng_rect &b)
+ {
+
+ dng_rect c;
+
+ c.t = Max_int32 (a.t, b.t);
+ c.l = Max_int32 (a.l, b.l);
+
+ c.b = Min_int32 (a.b, b.b);
+ c.r = Min_int32 (a.r, b.r);
+
+ if (c.IsEmpty ())
+ {
+
+ c = dng_rect ();
+
+ }
+
+ return c;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect operator| (const dng_rect &a,
+ const dng_rect &b)
+ {
+
+ if (a.IsEmpty ())
+ {
+ return b;
+ }
+
+ if (b.IsEmpty ())
+ {
+ return a;
+ }
+
+ dng_rect c;
+
+ c.t = Min_int32 (a.t, b.t);
+ c.l = Min_int32 (a.l, b.l);
+
+ c.b = Max_int32 (a.b, b.b);
+ c.r = Max_int32 (a.r, b.r);
+
+ return c;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect_real64 operator& (const dng_rect_real64 &a,
+ const dng_rect_real64 &b)
+ {
+
+ dng_rect_real64 c;
+
+ c.t = Max_real64 (a.t, b.t);
+ c.l = Max_real64 (a.l, b.l);
+
+ c.b = Min_real64 (a.b, b.b);
+ c.r = Min_real64 (a.r, b.r);
+
+ if (c.IsEmpty ())
+ {
+
+ c = dng_rect_real64 ();
+
+ }
+
+ return c;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect_real64 operator| (const dng_rect_real64 &a,
+ const dng_rect_real64 &b)
+ {
+
+ if (a.IsEmpty ())
+ {
+ return b;
+ }
+
+ if (b.IsEmpty ())
+ {
+ return a;
+ }
+
+ dng_rect_real64 c;
+
+ c.t = Min_real64 (a.t, b.t);
+ c.l = Min_real64 (a.l, b.l);
+
+ c.b = Max_real64 (a.b, b.b);
+ c.r = Max_real64 (a.r, b.r);
+
+ return c;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_rect.h b/gpr/source/lib/dng_sdk/dng_rect.h
new file mode 100644
index 0000000..16c4b29
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_rect.h
@@ -0,0 +1,494 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_rect.h#2 $ */
+/* $DateTime: 2012/06/01 07:28:57 $ */
+/* $Change: 832715 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_rect__
+#define __dng_rect__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+#include "dng_point.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+class dng_rect
+ {
+
+ public:
+
+ int32 t;
+ int32 l;
+ int32 b;
+ int32 r;
+
+ public:
+
+ dng_rect ()
+ : t (0)
+ , l (0)
+ , b (0)
+ , r (0)
+ {
+ }
+
+ dng_rect (int32 tt, int32 ll, int32 bb, int32 rr)
+ : t (tt)
+ , l (ll)
+ , b (bb)
+ , r (rr)
+ {
+ }
+
+ dng_rect (uint32 h, uint32 w)
+ : t (0)
+ , l (0)
+ , b ((int32) h)
+ , r ((int32) w)
+ {
+ }
+
+ dng_rect (const dng_point &size)
+ : t (0)
+ , l (0)
+ , b (size.v)
+ , r (size.h)
+ {
+ }
+
+ void Clear ()
+ {
+ *this = dng_rect ();
+ }
+
+ bool operator== (const dng_rect &rect) const;
+
+ bool operator!= (const dng_rect &rect) const
+ {
+ return !(*this == rect);
+ }
+
+ bool IsZero () const;
+
+ bool NotZero () const
+ {
+ return !IsZero ();
+ }
+
+ bool IsEmpty () const
+ {
+ return (t >= b) || (l >= r);
+ }
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ uint32 W () const
+ {
+ return (r >= l ? (uint32) (r - l) : 0);
+ }
+
+ uint32 H () const
+ {
+ return (b >= t ? (uint32) (b - t) : 0);
+ }
+
+ dng_point TL () const
+ {
+ return dng_point (t, l);
+ }
+
+ dng_point TR () const
+ {
+ return dng_point (t, r);
+ }
+
+ dng_point BL () const
+ {
+ return dng_point (b, l);
+ }
+
+ dng_point BR () const
+ {
+ return dng_point (b, r);
+ }
+
+ dng_point Size () const
+ {
+ return dng_point ((int32) H (), (int32) W ());
+ }
+
+ real64 Diagonal () const
+ {
+ return hypot ((real64) W (),
+ (real64) H ());
+ }
+
+ };
+
+/*****************************************************************************/
+
+class dng_rect_real64
+ {
+
+ public:
+
+ real64 t;
+ real64 l;
+ real64 b;
+ real64 r;
+
+ public:
+
+ dng_rect_real64 ()
+ : t (0.0)
+ , l (0.0)
+ , b (0.0)
+ , r (0.0)
+ {
+ }
+
+ dng_rect_real64 (real64 tt, real64 ll, real64 bb, real64 rr)
+ : t (tt)
+ , l (ll)
+ , b (bb)
+ , r (rr)
+ {
+ }
+
+ dng_rect_real64 (real64 h, real64 w)
+ : t (0)
+ , l (0)
+ , b (h)
+ , r (w)
+ {
+ }
+
+ dng_rect_real64 (const dng_point_real64 &size)
+ : t (0)
+ , l (0)
+ , b (size.v)
+ , r (size.h)
+ {
+ }
+
+ dng_rect_real64 (const dng_point_real64 &pt1,
+ const dng_point_real64 &pt2)
+ : t (Min_real64 (pt1.v, pt2.v))
+ , l (Min_real64 (pt1.h, pt2.h))
+ , b (Max_real64 (pt1.v, pt2.v))
+ , r (Max_real64 (pt1.h, pt2.h))
+ {
+ }
+
+ dng_rect_real64 (const dng_rect &rect)
+ : t ((real64) rect.t)
+ , l ((real64) rect.l)
+ , b ((real64) rect.b)
+ , r ((real64) rect.r)
+ {
+ }
+
+ void Clear ()
+ {
+ *this = dng_point_real64 ();
+ }
+
+ bool operator== (const dng_rect_real64 &rect) const;
+
+ bool operator!= (const dng_rect_real64 &rect) const
+ {
+ return !(*this == rect);
+ }
+
+ bool IsZero () const;
+
+ bool NotZero () const
+ {
+ return !IsZero ();
+ }
+
+ bool IsEmpty () const
+ {
+ return (t >= b) || (l >= r);
+ }
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ real64 W () const
+ {
+ return Max_real64 (r - l, 0.0);
+ }
+
+ real64 H () const
+ {
+ return Max_real64 (b - t, 0.0);
+ }
+
+ dng_point_real64 TL () const
+ {
+ return dng_point_real64 (t, l);
+ }
+
+ dng_point_real64 TR () const
+ {
+ return dng_point_real64 (t, r);
+ }
+
+ dng_point_real64 BL () const
+ {
+ return dng_point_real64 (b, l);
+ }
+
+ dng_point_real64 BR () const
+ {
+ return dng_point_real64 (b, r);
+ }
+
+ dng_point_real64 Size () const
+ {
+ return dng_point_real64 (H (), W ());
+ }
+
+ dng_rect Round () const
+ {
+ return dng_rect (Round_int32 (t),
+ Round_int32 (l),
+ Round_int32 (b),
+ Round_int32 (r));
+ }
+
+ real64 Diagonal () const
+ {
+ return hypot (W (), H ());
+ }
+
+ };
+
+/*****************************************************************************/
+
+dng_rect operator& (const dng_rect &a,
+ const dng_rect &b);
+
+dng_rect operator| (const dng_rect &a,
+ const dng_rect &b);
+
+/*****************************************************************************/
+
+dng_rect_real64 operator& (const dng_rect_real64 &a,
+ const dng_rect_real64 &b);
+
+dng_rect_real64 operator| (const dng_rect_real64 &a,
+ const dng_rect_real64 &b);
+
+/*****************************************************************************/
+
+inline dng_rect operator+ (const dng_rect &a,
+ const dng_point &b)
+ {
+
+ return dng_rect (a.t + b.v,
+ a.l + b.h,
+ a.b + b.v,
+ a.r + b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect_real64 operator+ (const dng_rect_real64 &a,
+ const dng_point_real64 &b)
+ {
+
+ return dng_rect_real64 (a.t + b.v,
+ a.l + b.h,
+ a.b + b.v,
+ a.r + b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect operator- (const dng_rect &a,
+ const dng_point &b)
+ {
+
+ return dng_rect (a.t - b.v,
+ a.l - b.h,
+ a.b - b.v,
+ a.r - b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect_real64 operator- (const dng_rect_real64 &a,
+ const dng_point_real64 &b)
+ {
+
+ return dng_rect_real64 (a.t - b.v,
+ a.l - b.h,
+ a.b - b.v,
+ a.r - b.h);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect Transpose (const dng_rect &a)
+ {
+
+ return dng_rect (a.l, a.t, a.r, a.b);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect_real64 Transpose (const dng_rect_real64 &a)
+ {
+
+ return dng_rect_real64 (a.l, a.t, a.r, a.b);
+
+ }
+
+/*****************************************************************************/
+
+inline void HalfRect (dng_rect &rect)
+ {
+
+ rect.r = rect.l + (int32) (rect.W () >> 1);
+ rect.b = rect.t + (int32) (rect.H () >> 1);
+
+ }
+
+/*****************************************************************************/
+
+inline void DoubleRect (dng_rect &rect)
+ {
+
+ rect.r = rect.l + (int32) (rect.W () << 1);
+ rect.b = rect.t + (int32) (rect.H () << 1);
+
+ }
+
+/*****************************************************************************/
+
+inline void InnerPadRect (dng_rect &rect,
+ int32 pad)
+ {
+
+ rect.l += pad;
+ rect.r -= pad;
+ rect.t += pad;
+ rect.b -= pad;
+
+ }
+
+/*****************************************************************************/
+
+inline void OuterPadRect (dng_rect &rect,
+ int32 pad)
+ {
+
+ InnerPadRect (rect, -pad);
+
+ }
+
+/*****************************************************************************/
+
+inline void InnerPadRectH (dng_rect &rect,
+ int32 pad)
+ {
+
+ rect.l += pad;
+ rect.r -= pad;
+
+ }
+
+/*****************************************************************************/
+
+inline void InnerPadRectV (dng_rect &rect,
+ int32 pad)
+ {
+
+ rect.t += pad;
+ rect.b -= pad;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect MakeHalfRect (const dng_rect &rect)
+ {
+
+ dng_rect out = rect;
+
+ HalfRect (out);
+
+ return out;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect MakeDoubleRect (const dng_rect &rect)
+ {
+
+ dng_rect out = rect;
+
+ DoubleRect (out);
+
+ return out;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect MakeInnerPadRect (const dng_rect &rect,
+ int32 pad)
+ {
+
+ dng_rect out = rect;
+
+ InnerPadRect (out, pad);
+
+ return out;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect MakeOuterPadRect (const dng_rect &rect,
+ int32 pad)
+ {
+
+ dng_rect out = rect;
+
+ OuterPadRect (out, pad);
+
+ return out;
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_ref_counted_block.cpp b/gpr/source/lib/dng_sdk/dng_ref_counted_block.cpp
new file mode 100644
index 0000000..32df295
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_ref_counted_block.cpp
@@ -0,0 +1,190 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_ref_counted_block.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include <new>
+
+#include "dng_ref_counted_block.h"
+
+#include "dng_exceptions.h"
+
+#include "gpr_allocator.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+dng_ref_counted_block::dng_ref_counted_block ()
+
+ : fBuffer (NULL)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_ref_counted_block::dng_ref_counted_block (uint32 size)
+
+ : fBuffer (NULL)
+
+ {
+
+ Allocate (size);
+
+ }
+
+/*****************************************************************************/
+
+dng_ref_counted_block::~dng_ref_counted_block ()
+ {
+
+ Clear ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_ref_counted_block::Allocate (uint32 size)
+ {
+
+ Clear ();
+
+ if (size)
+ {
+ fBuffer = gpr_global_malloc(size + sizeof (header));
+
+ if (!fBuffer)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ new (fBuffer) header (size);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_ref_counted_block::Clear ()
+ {
+
+ if (fBuffer)
+ {
+
+
+ bool doFree = false;
+
+ header *blockHeader = (struct header *)fBuffer;
+
+ {
+
+ dng_lock_mutex lock (&blockHeader->fMutex);
+
+ if (--blockHeader->fRefCount == 0)
+ doFree = true;
+ }
+
+ if (doFree)
+ {
+
+ blockHeader->~header ();
+
+ gpr_global_free( fBuffer );
+
+ }
+
+ fBuffer = NULL;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_ref_counted_block::dng_ref_counted_block (const dng_ref_counted_block &data)
+ : fBuffer (NULL)
+ {
+
+ header *blockHeader = (struct header *)data.fBuffer;
+
+ dng_lock_mutex lock (&blockHeader->fMutex);
+
+ blockHeader->fRefCount++;
+
+ fBuffer = blockHeader;
+
+ }
+
+/*****************************************************************************/
+
+dng_ref_counted_block & dng_ref_counted_block::operator= (const dng_ref_counted_block &data)
+ {
+
+ if (this != &data)
+ {
+ Clear ();
+
+ header *blockHeader = (struct header *)data.fBuffer;
+
+ dng_lock_mutex lock (&blockHeader->fMutex);
+
+ blockHeader->fRefCount++;
+
+ fBuffer = blockHeader;
+
+ }
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+void dng_ref_counted_block::EnsureWriteable ()
+ {
+
+ if (fBuffer)
+ {
+
+ header *possiblySharedHeader = (header *)fBuffer;
+
+ {
+
+ dng_lock_mutex lock (&possiblySharedHeader->fMutex);
+
+ if (possiblySharedHeader->fRefCount > 1)
+ {
+
+ fBuffer = NULL;
+
+ Allocate ((uint32)possiblySharedHeader->fSize);
+
+ memcpy (Buffer (),
+ ((char *)possiblySharedHeader) + sizeof (struct header), // could just do + 1 w/o cast, but this makes the type mixing more explicit
+ possiblySharedHeader->fSize);
+
+ possiblySharedHeader->fRefCount--;
+
+ }
+
+ }
+
+ }
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_ref_counted_block.h b/gpr/source/lib/dng_sdk/dng_ref_counted_block.h
new file mode 100644
index 0000000..cdda745
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_ref_counted_block.h
@@ -0,0 +1,291 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_ref_counted_block.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** Support for a refcounted block, with optional copy-on-write
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_ref_counted_block__
+#define __dng_ref_counted_block__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+#include "dng_mutex.h"
+
+/*****************************************************************************/
+
+/// \brief Class to provide resource acquisition is instantiation discipline
+/// for small memory allocations.
+///
+/// This class does not use dng_memory_allocator for memory allocation.
+
+class dng_ref_counted_block
+ {
+
+ private:
+
+ struct header
+ {
+
+ dng_mutex fMutex;
+
+ uint32 fRefCount;
+
+ uint32 fSize;
+
+ header (uint32 size)
+ : fMutex ("dng_ref_counted_block")
+ , fRefCount (1)
+ , fSize (size)
+ {
+ }
+
+ ~header ()
+ {
+ }
+
+ };
+
+ void *fBuffer;
+
+ public:
+
+
+ /// Construct an empty memory buffer using malloc.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ dng_ref_counted_block ();
+
+ /// Construct memory buffer of size bytes using malloc.
+ /// \param size Number of bytes of memory needed.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ dng_ref_counted_block (uint32 size);
+
+ /// Release memory buffer using free.
+
+ ~dng_ref_counted_block ();
+
+ /// Copy constructore, which takes a reference to data and does not copy the block.
+
+ dng_ref_counted_block (const dng_ref_counted_block &data);
+
+ /// Assignment operatore takes a reference to right hand side and does not copy the data.
+
+ dng_ref_counted_block & operator= (const dng_ref_counted_block &data);
+
+ /// Clear existing memory buffer and allocate new memory of size bytes.
+ /// \param size Number of bytes of memory needed.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ void Allocate (uint32 size);
+
+ /// Release any allocated memory using free. Object is still valid and
+ /// Allocate can be called again.
+
+ void Clear ();
+
+ /// If there is only one reference, do nothing, otherwise copy the data into a new block and return an object with that block as the data.
+
+ void EnsureWriteable ();
+
+ /// Return pointer to allocated memory as a void *..
+ /// \retval void * valid for as many bytes as were allocated.
+
+ uint32 LogicalSize ()
+ {
+ return ((header *)fBuffer)->fSize;
+ }
+
+ void * Buffer ()
+ {
+ return (void *)((char *)fBuffer + sizeof (header));
+ }
+
+ /// Return pointer to allocated memory as a const void *.
+ /// \retval const void * valid for as many bytes as were allocated.
+
+ const void * Buffer () const
+ {
+ return (const void *)((char *)fBuffer + sizeof (header));
+ }
+
+ /// Return pointer to allocated memory as a char *.
+ /// \retval char * valid for as many bytes as were allocated.
+
+ char * Buffer_char ()
+ {
+ return (char *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const char *.
+ /// \retval const char * valid for as many bytes as were allocated.
+
+ const char * Buffer_char () const
+ {
+ return (const char *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint8 *.
+ /// \retval uint8 * valid for as many bytes as were allocated.
+
+ uint8 * Buffer_uint8 ()
+ {
+ return (uint8 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint8 *.
+ /// \retval const uint8 * valid for as many bytes as were allocated.
+
+ const uint8 * Buffer_uint8 () const
+ {
+ return (const uint8 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint16 *.
+ /// \retval uint16 * valid for as many bytes as were allocated.
+
+ uint16 * Buffer_uint16 ()
+ {
+ return (uint16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const uint16 *.
+ /// \retval const uint16 * valid for as many bytes as were allocated.
+
+ const uint16 * Buffer_uint16 () const
+ {
+ return (const uint16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a int16 *.
+ /// \retval int16 * valid for as many bytes as were allocated.
+
+ int16 * Buffer_int16 ()
+ {
+ return (int16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int16 *.
+ /// \retval const int16 * valid for as many bytes as were allocated.
+
+ const int16 * Buffer_int16 () const
+ {
+ return (const int16 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint32 *.
+ /// \retval uint32 * valid for as many bytes as were allocated.
+
+ uint32 * Buffer_uint32 ()
+ {
+ return (uint32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint32 *.
+ /// \retval uint32 * valid for as many bytes as were allocated.
+
+ const uint32 * Buffer_uint32 () const
+ {
+ return (const uint32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int32 *.
+ /// \retval const int32 * valid for as many bytes as were allocated.
+
+ int32 * Buffer_int32 ()
+ {
+ return (int32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int32 *.
+ /// \retval const int32 * valid for as many bytes as were allocated.
+
+ const int32 * Buffer_int32 () const
+ {
+ return (const int32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint64 *.
+ /// \retval uint64 * valid for as many bytes as were allocated.
+
+ uint64 * Buffer_uint64 ()
+ {
+ return (uint64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a uint64 *.
+ /// \retval uint64 * valid for as many bytes as were allocated.
+
+ const uint64 * Buffer_uint64 () const
+ {
+ return (const uint64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int64 *.
+ /// \retval const int64 * valid for as many bytes as were allocated.
+
+ int64 * Buffer_int64 ()
+ {
+ return (int64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const int64 *.
+ /// \retval const int64 * valid for as many bytes as were allocated.
+
+ const int64 * Buffer_int64 () const
+ {
+ return (const int64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a real32 *.
+ /// \retval real32 * valid for as many bytes as were allocated.
+
+ real32 * Buffer_real32 ()
+ {
+ return (real32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const real32 *.
+ /// \retval const real32 * valid for as many bytes as were allocated.
+
+ const real32 * Buffer_real32 () const
+ {
+ return (const real32 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a real64 *.
+ /// \retval real64 * valid for as many bytes as were allocated.
+
+ real64 * Buffer_real64 ()
+ {
+ return (real64 *) Buffer ();
+ }
+
+ /// Return pointer to allocated memory as a const real64 *.
+ /// \retval const real64 * valid for as many bytes as were allocated.
+
+ const real64 * Buffer_real64 () const
+ {
+ return (const real64 *) Buffer ();
+ }
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_reference.cpp b/gpr/source/lib/dng_sdk/dng_reference.cpp
new file mode 100644
index 0000000..5d35378
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_reference.cpp
@@ -0,0 +1,2783 @@
+/*****************************************************************************/
+// Copyright 2006-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_reference.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_reference.h"
+
+#include "dng_1d_table.h"
+#include "dng_hue_sat_map.h"
+#include "dng_matrix.h"
+#include "dng_resample.h"
+#include "dng_utils.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+// This module contains routines that should be as fast as possible, even
+// at the expense of slight code size increases.
+
+#include "dng_fast_module.h"
+
+/*****************************************************************************/
+
+void RefZeroBytes (void *dPtr,
+ uint32 count)
+ {
+
+ memset (dPtr, 0, count);
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyBytes (const void *sPtr,
+ void *dPtr,
+ uint32 count)
+ {
+
+ memcpy (dPtr, sPtr, count);
+
+ }
+
+/*****************************************************************************/
+
+void RefSwapBytes16 (uint16 *dPtr,
+ uint32 count)
+ {
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ dPtr [j] = SwapBytes16 (dPtr [j]);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefSwapBytes32 (uint32 *dPtr,
+ uint32 count)
+ {
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ dPtr [j] = SwapBytes32 (dPtr [j]);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefSetArea8 (uint8 *dPtr,
+ uint8 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint8 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint8 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = value;
+
+ dPtr2 += planeStep;
+
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefSetArea16 (uint16 *dPtr,
+ uint16 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = value;
+
+ dPtr2 += planeStep;
+
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefSetArea32 (uint32 *dPtr,
+ uint32 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = value;
+
+ dPtr2 += planeStep;
+
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea8 (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr;
+ uint8 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ uint8 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint16 *sPtr1 = sPtr;
+ uint16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint16 *sPtr2 = sPtr1;
+ uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea32 (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint32 *sPtr1 = sPtr;
+ uint32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint32 *sPtr2 = sPtr1;
+ uint32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea8_16 (const uint8 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr;
+ uint16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea8_S16 (const uint8 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr;
+ int16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ int16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ int16 x = *sPtr;
+
+ *dPtr2 = x ^ 0x8000;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea8_32 (const uint8 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr;
+ uint32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ uint32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea16_S16 (const uint16 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint16 *sPtr1 = sPtr;
+ int16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint16 *sPtr2 = sPtr1;
+ int16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2 ^ 0x8000;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea16_32 (const uint16 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint16 *sPtr1 = sPtr;
+ uint32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint16 *sPtr2 = sPtr1;
+ uint32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea8_R32 (const uint8 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ real32 scale = 1.0f / (real32) pixelRange;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr;
+ real32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ real32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = scale * (real32) *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyArea16_R32 (const uint16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ real32 scale = 1.0f / (real32) pixelRange;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint16 *sPtr1 = sPtr;
+ real32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint16 *sPtr2 = sPtr1;
+ real32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = scale * (real32) *sPtr2;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyAreaS16_R32 (const int16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ real32 scale = 1.0f / (real32) pixelRange;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const int16 *sPtr1 = sPtr;
+ real32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const int16 *sPtr2 = sPtr1;
+ real32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ int32 x = (*sPtr ^ 0x8000);
+
+ *dPtr2 = scale * (real32) x;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyAreaR32_8 (const real32 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ real32 scale = (real32) pixelRange;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const real32 *sPtr1 = sPtr;
+ uint8 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const real32 *sPtr2 = sPtr1;
+ uint8 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = (uint8) (Pin_Overrange (*sPtr2) * scale + 0.5f);
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyAreaR32_16 (const real32 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ real32 scale = (real32) pixelRange;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const real32 *sPtr1 = sPtr;
+ uint16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const real32 *sPtr2 = sPtr1;
+ uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = (uint16) (Pin_Overrange (*sPtr2) * scale + 0.5f);
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefCopyAreaR32_S16 (const real32 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange)
+ {
+
+ real32 scale = (real32) pixelRange;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const real32 *sPtr1 = sPtr;
+ int16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const real32 *sPtr2 = sPtr1;
+ int16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ int32 x = (int32) (Pin_Overrange (*sPtr2) * scale + 0.5f);
+
+ *dPtr2 = (int16) (x ^ 0x8000);
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefRepeatArea8 (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH)
+ {
+
+ const uint8 *sPtr0 = sPtr + phaseV * rowStep +
+ phaseH * colStep;
+
+ int32 backStepV = (repeatV - 1) * rowStep;
+ int32 backStepH = (repeatH - 1) * colStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr0;
+ uint8 *dPtr1 = dPtr;
+
+ uint32 colPhase = phaseH;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ uint8 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += planeStep;
+ dPtr2 += planeStep;
+
+ }
+
+ if (++colPhase == repeatH)
+ {
+ colPhase = 0;
+ sPtr1 -= backStepH;
+ }
+ else
+ {
+ sPtr1 += colStep;
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ if (++phaseV == repeatV)
+ {
+ phaseV = 0;
+ sPtr0 -= backStepV;
+ }
+ else
+ {
+ sPtr0 += rowStep;
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefRepeatArea16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH)
+ {
+
+ const uint16 *sPtr0 = sPtr + phaseV * rowStep +
+ phaseH * colStep;
+
+ int32 backStepV = (repeatV - 1) * rowStep;
+ int32 backStepH = (repeatH - 1) * colStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint16 *sPtr1 = sPtr0;
+ uint16 *dPtr1 = dPtr;
+
+ uint32 colPhase = phaseH;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint16 *sPtr2 = sPtr1;
+ uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += planeStep;
+ dPtr2 += planeStep;
+
+ }
+
+ if (++colPhase == repeatH)
+ {
+ colPhase = 0;
+ sPtr1 -= backStepH;
+ }
+ else
+ {
+ sPtr1 += colStep;
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ if (++phaseV == repeatV)
+ {
+ phaseV = 0;
+ sPtr0 -= backStepV;
+ }
+ else
+ {
+ sPtr0 += rowStep;
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefRepeatArea32 (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH)
+ {
+
+ const uint32 *sPtr0 = sPtr + phaseV * rowStep +
+ phaseH * colStep;
+
+ int32 backStepV = (repeatV - 1) * rowStep;
+ int32 backStepH = (repeatH - 1) * colStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint32 *sPtr1 = sPtr0;
+ uint32 *dPtr1 = dPtr;
+
+ uint32 colPhase = phaseH;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint32 *sPtr2 = sPtr1;
+ uint32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2;
+
+ sPtr2 += planeStep;
+ dPtr2 += planeStep;
+
+ }
+
+ if (++colPhase == repeatH)
+ {
+ colPhase = 0;
+ sPtr1 -= backStepH;
+ }
+ else
+ {
+ sPtr1 += colStep;
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ if (++phaseV == repeatV)
+ {
+ phaseV = 0;
+ sPtr0 -= backStepV;
+ }
+ else
+ {
+ sPtr0 += rowStep;
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefShiftRight16 (uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 shift)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ uint16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 >>= shift;
+
+ dPtr2 += planeStep;
+
+ }
+
+ dPtr1 += colStep;
+
+ }
+
+ dPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBilinearRow16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const uint16 * const * kernWeights,
+ uint32 sShift)
+ {
+
+ for (uint32 j = 0; j < cols; j++)
+ {
+
+ const uint16 *p = sPtr + (j >> sShift);
+
+ uint32 count = kernCounts [patPhase];
+
+ const int32 *offsets = kernOffsets [patPhase];
+ const uint16 *weights = kernWeights [patPhase];
+
+ if (++patPhase == patCount)
+ {
+ patPhase = 0;
+ }
+
+ uint32 total = 128;
+
+ for (uint32 k = 0; k < count; k++)
+ {
+
+ int32 offset = offsets [k];
+ uint32 weight = weights [k];
+
+ uint32 pixel = p [offset];
+
+ total += pixel * weight;
+
+ }
+
+ dPtr [j] = (uint16) (total >> 8);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBilinearRow32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const real32 * const * kernWeights,
+ uint32 sShift)
+ {
+
+ for (uint32 j = 0; j < cols; j++)
+ {
+
+ const real32 *p = sPtr + (j >> sShift);
+
+ uint32 count = kernCounts [patPhase];
+
+ const int32 *offsets = kernOffsets [patPhase];
+ const real32 *weights = kernWeights [patPhase];
+
+ if (++patPhase == patCount)
+ {
+ patPhase = 0;
+ }
+
+ real32 total = 0.0f;
+
+ for (uint32 k = 0; k < count; k++)
+ {
+
+ int32 offset = offsets [k];
+ real32 weight = weights [k];
+
+ real32 pixel = p [offset];
+
+ total += pixel * weight;
+
+ }
+
+ dPtr [j] = total;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineABCtoRGB (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB)
+ {
+
+ real32 clipA = (real32) cameraWhite [0];
+ real32 clipB = (real32) cameraWhite [1];
+ real32 clipC = (real32) cameraWhite [2];
+
+ real32 m00 = (real32) cameraToRGB [0] [0];
+ real32 m01 = (real32) cameraToRGB [0] [1];
+ real32 m02 = (real32) cameraToRGB [0] [2];
+
+ real32 m10 = (real32) cameraToRGB [1] [0];
+ real32 m11 = (real32) cameraToRGB [1] [1];
+ real32 m12 = (real32) cameraToRGB [1] [2];
+
+ real32 m20 = (real32) cameraToRGB [2] [0];
+ real32 m21 = (real32) cameraToRGB [2] [1];
+ real32 m22 = (real32) cameraToRGB [2] [2];
+
+ for (uint32 col = 0; col < count; col++)
+ {
+
+ real32 A = sPtrA [col];
+ real32 B = sPtrB [col];
+ real32 C = sPtrC [col];
+
+ A = Min_real32 (A, clipA);
+ B = Min_real32 (B, clipB);
+ C = Min_real32 (C, clipC);
+
+ real32 r = m00 * A + m01 * B + m02 * C;
+ real32 g = m10 * A + m11 * B + m12 * C;
+ real32 b = m20 * A + m21 * B + m22 * C;
+
+ r = Pin_real32 (0.0f, r, 1.0f);
+ g = Pin_real32 (0.0f, g, 1.0f);
+ b = Pin_real32 (0.0f, b, 1.0f);
+
+ dPtrR [col] = r;
+ dPtrG [col] = g;
+ dPtrB [col] = b;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineABCDtoRGB (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ const real32 *sPtrD,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB)
+ {
+
+ real32 clipA = (real32) cameraWhite [0];
+ real32 clipB = (real32) cameraWhite [1];
+ real32 clipC = (real32) cameraWhite [2];
+ real32 clipD = (real32) cameraWhite [3];
+
+ real32 m00 = (real32) cameraToRGB [0] [0];
+ real32 m01 = (real32) cameraToRGB [0] [1];
+ real32 m02 = (real32) cameraToRGB [0] [2];
+ real32 m03 = (real32) cameraToRGB [0] [3];
+
+ real32 m10 = (real32) cameraToRGB [1] [0];
+ real32 m11 = (real32) cameraToRGB [1] [1];
+ real32 m12 = (real32) cameraToRGB [1] [2];
+ real32 m13 = (real32) cameraToRGB [1] [3];
+
+ real32 m20 = (real32) cameraToRGB [2] [0];
+ real32 m21 = (real32) cameraToRGB [2] [1];
+ real32 m22 = (real32) cameraToRGB [2] [2];
+ real32 m23 = (real32) cameraToRGB [2] [3];
+
+ for (uint32 col = 0; col < count; col++)
+ {
+
+ real32 A = sPtrA [col];
+ real32 B = sPtrB [col];
+ real32 C = sPtrC [col];
+ real32 D = sPtrD [col];
+
+ A = Min_real32 (A, clipA);
+ B = Min_real32 (B, clipB);
+ C = Min_real32 (C, clipC);
+ D = Min_real32 (D, clipD);
+
+ real32 r = m00 * A + m01 * B + m02 * C + m03 * D;
+ real32 g = m10 * A + m11 * B + m12 * C + m13 * D;
+ real32 b = m20 * A + m21 * B + m22 * C + m23 * D;
+
+ r = Pin_real32 (0.0f, r, 1.0f);
+ g = Pin_real32 (0.0f, g, 1.0f);
+ b = Pin_real32 (0.0f, b, 1.0f);
+
+ dPtrR [col] = r;
+ dPtrG [col] = g;
+ dPtrB [col] = b;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineHueSatMap (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_hue_sat_map &lut,
+ const dng_1d_table *encodeTable,
+ const dng_1d_table *decodeTable)
+ {
+
+ uint32 hueDivisions;
+ uint32 satDivisions;
+ uint32 valDivisions;
+
+ lut.GetDivisions (hueDivisions,
+ satDivisions,
+ valDivisions);
+
+ real32 hScale = (hueDivisions < 2) ? 0.0f : (hueDivisions * (1.0f / 6.0f));
+ real32 sScale = (real32) (satDivisions - 1);
+ real32 vScale = (real32) (valDivisions - 1);
+
+ int32 maxHueIndex0 = hueDivisions - 1;
+ int32 maxSatIndex0 = satDivisions - 2;
+ int32 maxValIndex0 = valDivisions - 2;
+
+ const bool hasEncodeTable = ((encodeTable != NULL) && (encodeTable->Table () != NULL));
+ const bool hasDecodeTable = ((decodeTable != NULL) && (decodeTable->Table () != NULL));
+
+ const bool hasTable = hasEncodeTable && hasDecodeTable;
+
+ const dng_hue_sat_map::HSBModify *tableBase = lut.GetConstDeltas ();
+
+ int32 hueStep = satDivisions;
+ int32 valStep = hueDivisions * hueStep;
+
+ #if 0 // Not required with "2.5D" table optimization.
+
+ if (valDivisions < 2)
+ {
+ valStep = 0;
+ maxValIndex0 = 0;
+ }
+
+ #endif
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ real32 r = sPtrR [j];
+ real32 g = sPtrG [j];
+ real32 b = sPtrB [j];
+
+ real32 h, s, v;
+
+ DNG_RGBtoHSV (r, g, b, h, s, v);
+
+ real32 vEncoded = v;
+
+ real32 hueShift;
+ real32 satScale;
+ real32 valScale;
+
+ if (valDivisions < 2) // Optimize most common case of "2.5D" table.
+ {
+
+ real32 hScaled = h * hScale;
+ real32 sScaled = s * sScale;
+
+ int32 hIndex0 = (int32) hScaled;
+ int32 sIndex0 = (int32) sScaled;
+
+ sIndex0 = Min_int32 (sIndex0, maxSatIndex0);
+
+ int32 hIndex1 = hIndex0 + 1;
+
+ if (hIndex0 >= maxHueIndex0)
+ {
+ hIndex0 = maxHueIndex0;
+ hIndex1 = 0;
+ }
+
+ real32 hFract1 = hScaled - (real32) hIndex0;
+ real32 sFract1 = sScaled - (real32) sIndex0;
+
+ real32 hFract0 = 1.0f - hFract1;
+ real32 sFract0 = 1.0f - sFract1;
+
+ const dng_hue_sat_map::HSBModify *entry00 = tableBase + hIndex0 * hueStep +
+ sIndex0;
+
+ const dng_hue_sat_map::HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * hueStep;
+
+ real32 hueShift0 = hFract0 * entry00->fHueShift +
+ hFract1 * entry01->fHueShift;
+
+ real32 satScale0 = hFract0 * entry00->fSatScale +
+ hFract1 * entry01->fSatScale;
+
+ real32 valScale0 = hFract0 * entry00->fValScale +
+ hFract1 * entry01->fValScale;
+
+ entry00++;
+ entry01++;
+
+ real32 hueShift1 = hFract0 * entry00->fHueShift +
+ hFract1 * entry01->fHueShift;
+
+ real32 satScale1 = hFract0 * entry00->fSatScale +
+ hFract1 * entry01->fSatScale;
+
+ real32 valScale1 = hFract0 * entry00->fValScale +
+ hFract1 * entry01->fValScale;
+
+ hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
+ satScale = sFract0 * satScale0 + sFract1 * satScale1;
+ valScale = sFract0 * valScale0 + sFract1 * valScale1;
+
+ }
+
+ else
+ {
+
+ if (hasTable)
+ {
+ vEncoded = encodeTable->Interpolate (Pin_real32 (v));
+ }
+
+ real32 hScaled = h * hScale;
+ real32 sScaled = s * sScale;
+ real32 vScaled = vEncoded * vScale;
+
+ int32 hIndex0 = (int32) hScaled;
+ int32 sIndex0 = (int32) sScaled;
+ int32 vIndex0 = (int32) vScaled;
+
+ sIndex0 = Min_int32 (sIndex0, maxSatIndex0);
+ vIndex0 = Min_int32 (vIndex0, maxValIndex0);
+
+ int32 hIndex1 = hIndex0 + 1;
+
+ if (hIndex0 >= maxHueIndex0)
+ {
+ hIndex0 = maxHueIndex0;
+ hIndex1 = 0;
+ }
+
+ real32 hFract1 = hScaled - (real32) hIndex0;
+ real32 sFract1 = sScaled - (real32) sIndex0;
+ real32 vFract1 = vScaled - (real32) vIndex0;
+
+ real32 hFract0 = 1.0f - hFract1;
+ real32 sFract0 = 1.0f - sFract1;
+ real32 vFract0 = 1.0f - vFract1;
+
+ const dng_hue_sat_map::HSBModify *entry00 = tableBase + vIndex0 * valStep +
+ hIndex0 * hueStep +
+ sIndex0;
+
+ const dng_hue_sat_map::HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * hueStep;
+
+ const dng_hue_sat_map::HSBModify *entry10 = entry00 + valStep;
+ const dng_hue_sat_map::HSBModify *entry11 = entry01 + valStep;
+
+ real32 hueShift0 = vFract0 * (hFract0 * entry00->fHueShift +
+ hFract1 * entry01->fHueShift) +
+ vFract1 * (hFract0 * entry10->fHueShift +
+ hFract1 * entry11->fHueShift);
+
+ real32 satScale0 = vFract0 * (hFract0 * entry00->fSatScale +
+ hFract1 * entry01->fSatScale) +
+ vFract1 * (hFract0 * entry10->fSatScale +
+ hFract1 * entry11->fSatScale);
+
+ real32 valScale0 = vFract0 * (hFract0 * entry00->fValScale +
+ hFract1 * entry01->fValScale) +
+ vFract1 * (hFract0 * entry10->fValScale +
+ hFract1 * entry11->fValScale);
+
+ entry00++;
+ entry01++;
+ entry10++;
+ entry11++;
+
+ real32 hueShift1 = vFract0 * (hFract0 * entry00->fHueShift +
+ hFract1 * entry01->fHueShift) +
+ vFract1 * (hFract0 * entry10->fHueShift +
+ hFract1 * entry11->fHueShift);
+
+ real32 satScale1 = vFract0 * (hFract0 * entry00->fSatScale +
+ hFract1 * entry01->fSatScale) +
+ vFract1 * (hFract0 * entry10->fSatScale +
+ hFract1 * entry11->fSatScale);
+
+ real32 valScale1 = vFract0 * (hFract0 * entry00->fValScale +
+ hFract1 * entry01->fValScale) +
+ vFract1 * (hFract0 * entry10->fValScale +
+ hFract1 * entry11->fValScale);
+
+ hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
+ satScale = sFract0 * satScale0 + sFract1 * satScale1;
+ valScale = sFract0 * valScale0 + sFract1 * valScale1;
+
+ }
+
+ hueShift *= (6.0f / 360.0f); // Convert to internal hue range.
+
+ h += hueShift;
+
+ s = Min_real32 (s * satScale, 1.0f);
+
+ vEncoded = Pin_real32 (vEncoded * valScale);
+
+ v = hasTable ? decodeTable->Interpolate (vEncoded) : vEncoded;
+
+ DNG_HSVtoRGB (h, s, v, r, g, b);
+
+ dPtrR [j] = r;
+ dPtrG [j] = g;
+ dPtrB [j] = b;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineRGBtoGray (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrG,
+ uint32 count,
+ const dng_matrix &matrix)
+ {
+
+ real32 m00 = (real32) matrix [0] [0];
+ real32 m01 = (real32) matrix [0] [1];
+ real32 m02 = (real32) matrix [0] [2];
+
+ for (uint32 col = 0; col < count; col++)
+ {
+
+ real32 R = sPtrR [col];
+ real32 G = sPtrG [col];
+ real32 B = sPtrB [col];
+
+ real32 g = m00 * R + m01 * G + m02 * B;
+
+ g = Pin_real32 (0.0f, g, 1.0f);
+
+ dPtrG [col] = g;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineRGBtoRGB (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_matrix &matrix)
+ {
+
+ real32 m00 = (real32) matrix [0] [0];
+ real32 m01 = (real32) matrix [0] [1];
+ real32 m02 = (real32) matrix [0] [2];
+
+ real32 m10 = (real32) matrix [1] [0];
+ real32 m11 = (real32) matrix [1] [1];
+ real32 m12 = (real32) matrix [1] [2];
+
+ real32 m20 = (real32) matrix [2] [0];
+ real32 m21 = (real32) matrix [2] [1];
+ real32 m22 = (real32) matrix [2] [2];
+
+ for (uint32 col = 0; col < count; col++)
+ {
+
+ real32 R = sPtrR [col];
+ real32 G = sPtrG [col];
+ real32 B = sPtrB [col];
+
+ real32 r = m00 * R + m01 * G + m02 * B;
+ real32 g = m10 * R + m11 * G + m12 * B;
+ real32 b = m20 * R + m21 * G + m22 * B;
+
+ r = Pin_real32 (0.0f, r, 1.0f);
+ g = Pin_real32 (0.0f, g, 1.0f);
+ b = Pin_real32 (0.0f, b, 1.0f);
+
+ dPtrR [col] = r;
+ dPtrG [col] = g;
+ dPtrB [col] = b;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaseline1DTable (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 count,
+ const dng_1d_table &table)
+ {
+
+ for (uint32 col = 0; col < count; col++)
+ {
+
+ real32 x = sPtr [col];
+
+ real32 y = table.Interpolate (x);
+
+ dPtr [col] = y;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineRGBTone (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_1d_table &table)
+ {
+
+ for (uint32 col = 0; col < count; col++)
+ {
+
+ real32 r = sPtrR [col];
+ real32 g = sPtrG [col];
+ real32 b = sPtrB [col];
+
+ real32 rr;
+ real32 gg;
+ real32 bb;
+
+ #define RGBTone(r, g, b, rr, gg, bb)\
+ {\
+ \
+ DNG_ASSERT (r >= g && g >= b && r > b, "Logic Error RGBTone");\
+ \
+ rr = table.Interpolate (r);\
+ bb = table.Interpolate (b);\
+ \
+ gg = bb + ((rr - bb) * (g - b) / (r - b));\
+ \
+ }
+
+ if (r >= g)
+ {
+
+ if (g > b)
+ {
+
+ // Case 1: r >= g > b
+
+ RGBTone (r, g, b, rr, gg, bb);
+
+ }
+
+ else if (b > r)
+ {
+
+ // Case 2: b > r >= g
+
+ RGBTone (b, r, g, bb, rr, gg);
+
+ }
+
+ else if (b > g)
+ {
+
+ // Case 3: r >= b > g
+
+ RGBTone (r, b, g, rr, bb, gg);
+
+ }
+
+ else
+ {
+
+ // Case 4: r >= g == b
+
+ DNG_ASSERT (r >= g && g == b, "Logic Error 2");
+
+ rr = table.Interpolate (r);
+ gg = table.Interpolate (g);
+ bb = gg;
+
+ }
+
+ }
+
+ else
+ {
+
+ if (r >= b)
+ {
+
+ // Case 5: g > r >= b
+
+ RGBTone (g, r, b, gg, rr, bb);
+
+ }
+
+ else if (b > g)
+ {
+
+ // Case 6: b > g > r
+
+ RGBTone (b, g, r, bb, gg, rr);
+
+ }
+
+ else
+ {
+
+ // Case 7: g >= b > r
+
+ RGBTone (g, b, r, gg, bb, rr);
+
+ }
+
+ }
+
+ #undef RGBTone
+
+ dPtrR [col] = rr;
+ dPtrG [col] = gg;
+ dPtrB [col] = bb;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefResampleDown16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 pixelRange)
+ {
+
+ for (uint32 j = 0; j < sCount; j++)
+ {
+
+ int32 total = 8192;
+
+ const uint16 *s = sPtr + j;
+
+ for (uint32 k = 0; k < wCount; k++)
+ {
+
+ total += wPtr [k] * (int32) s [0];
+
+ s += sRowStep;
+
+ }
+
+ dPtr [j] = (uint16) Pin_int32 (0,
+ total >> 14,
+ pixelRange);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefResampleDown32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const real32 *wPtr,
+ uint32 wCount)
+ {
+
+ uint32 col;
+
+ // Process first row.
+
+ real32 w = wPtr [0];
+
+ for (col = 0; col < sCount; col++)
+ {
+
+ dPtr [col] = w * sPtr [col];
+
+ }
+
+ sPtr += sRowStep;
+
+ // Process middle rows.
+
+ for (uint32 j = 1; j < wCount - 1; j++)
+ {
+
+ w = wPtr [j];
+
+ for (col = 0; col < sCount; col++)
+ {
+
+ dPtr [col] += w * sPtr [col];
+
+ }
+
+ sPtr += sRowStep;
+
+ }
+
+ // Process last row.
+
+ w = wPtr [wCount - 1];
+
+ for (col = 0; col < sCount; col++)
+ {
+
+ dPtr [col] = Pin_real32 (0.0f,
+ dPtr [col] + w * sPtr [col],
+ 1.0f);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void RefResampleAcross16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 wStep,
+ uint32 pixelRange)
+ {
+
+ for (uint32 j = 0; j < dCount; j++)
+ {
+
+ int32 sCoord = coord [j];
+
+ int32 sFract = sCoord & kResampleSubsampleMask;
+ int32 sPixel = sCoord >> kResampleSubsampleBits;
+
+ const int16 *w = wPtr + sFract * wStep;
+ const uint16 *s = sPtr + sPixel;
+
+ int32 total = w [0] * (int32) s [0];
+
+ for (uint32 k = 1; k < wCount; k++)
+ {
+
+ total += w [k] * (int32) s [k];
+
+ }
+
+ dPtr [j] = (uint16) Pin_int32 (0,
+ (total + 8192) >> 14,
+ pixelRange);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void RefResampleAcross32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const real32 *wPtr,
+ uint32 wCount,
+ uint32 wStep)
+ {
+
+ for (uint32 j = 0; j < dCount; j++)
+ {
+
+ int32 sCoord = coord [j];
+
+ int32 sFract = sCoord & kResampleSubsampleMask;
+ int32 sPixel = sCoord >> kResampleSubsampleBits;
+
+ const real32 *w = wPtr + sFract * wStep;
+ const real32 *s = sPtr + sPixel;
+
+ real32 total = w [0] * s [0];
+
+ for (uint32 k = 1; k < wCount; k++)
+ {
+
+ total += w [k] * s [k];
+
+ }
+
+ dPtr [j] = Pin_real32 (0.0f, total, 1.0f);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool RefEqualBytes (const void *sPtr,
+ const void *dPtr,
+ uint32 count)
+ {
+
+ return memcmp (dPtr, sPtr, count) == 0;
+
+ }
+
+/*****************************************************************************/
+
+bool RefEqualArea8 (const uint8 *sPtr,
+ const uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint8 *sPtr1 = sPtr;
+ const uint8 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint8 *sPtr2 = sPtr1;
+ const uint8 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ if (*dPtr2 != *sPtr2)
+ return false;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool RefEqualArea16 (const uint16 *sPtr,
+ const uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint16 *sPtr1 = sPtr;
+ const uint16 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint16 *sPtr2 = sPtr1;
+ const uint16 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ if (*dPtr2 != *sPtr2)
+ return false;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool RefEqualArea32 (const uint32 *sPtr,
+ const uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ const uint32 *sPtr1 = sPtr;
+ const uint32 *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ const uint32 *sPtr2 = sPtr1;
+ const uint32 *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ if (*dPtr2 != *sPtr2)
+ return false;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
+
+ sPtr1 += sColStep;
+ dPtr1 += dColStep;
+
+ }
+
+ sPtr += sRowStep;
+ dPtr += dRowStep;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void RefVignetteMask16 (uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ int32 rowStep,
+ int64 offsetH,
+ int64 offsetV,
+ int64 stepH,
+ int64 stepV,
+ uint32 tBits,
+ const uint16 *table)
+ {
+
+ uint32 tShift = 32 - tBits;
+ uint32 tRound = (1 << (tShift - 1));
+ uint32 tLimit = 1 << tBits;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ int64 baseDelta = (offsetV + 32768) >> 16;
+
+ baseDelta = baseDelta * baseDelta + tRound;
+
+ int64 deltaH = offsetH + 32768;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ int64 temp = deltaH >> 16;
+
+ int64 delta = baseDelta + (temp * temp);
+
+ uint32 index = Min_uint32 ((uint32) (delta >> tShift), tLimit);
+
+ mPtr [col] = table [index];
+
+ deltaH += stepH;
+
+ }
+
+ offsetV += stepV;
+
+ mPtr += rowStep;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefVignette16 (int16 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits)
+ {
+
+ const uint32 mRound = 1 << (mBits - 1);
+
+ switch (planes)
+ {
+
+ case 1:
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint32 s = sPtr [col] + 32768;
+
+ uint32 m = mPtr [col];
+
+ s = (s * m + mRound) >> mBits;
+
+ s = Min_uint32 (s, 65535);
+
+ sPtr [col] = (int16) (s - 32768);
+
+ }
+
+ sPtr += sRowStep;
+
+ mPtr += mRowStep;
+
+ }
+
+ break;
+
+ }
+
+ case 3:
+ {
+
+ int16 *rPtr = sPtr;
+ int16 *gPtr = rPtr + sPlaneStep;
+ int16 *bPtr = gPtr + sPlaneStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint32 r = rPtr [col] + 32768;
+ uint32 g = gPtr [col] + 32768;
+ uint32 b = bPtr [col] + 32768;
+
+ uint32 m = mPtr [col];
+
+ r = (r * m + mRound) >> mBits;
+ g = (g * m + mRound) >> mBits;
+ b = (b * m + mRound) >> mBits;
+
+ r = Min_uint32 (r, 65535);
+ g = Min_uint32 (g, 65535);
+ b = Min_uint32 (b, 65535);
+
+ rPtr [col] = (int16) (r - 32768);
+ gPtr [col] = (int16) (g - 32768);
+ bPtr [col] = (int16) (b - 32768);
+
+ }
+
+ rPtr += sRowStep;
+ gPtr += sRowStep;
+ bPtr += sRowStep;
+
+ mPtr += mRowStep;
+
+ }
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ int16 *aPtr = sPtr;
+ int16 *bPtr = aPtr + sPlaneStep;
+ int16 *cPtr = bPtr + sPlaneStep;
+ int16 *dPtr = cPtr + sPlaneStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint32 a = aPtr [col] + 32768;
+ uint32 b = bPtr [col] + 32768;
+ uint32 c = cPtr [col] + 32768;
+ uint32 d = dPtr [col] + 32768;
+
+ uint32 m = mPtr [col];
+
+ a = (a * m + mRound) >> mBits;
+ b = (b * m + mRound) >> mBits;
+ c = (c * m + mRound) >> mBits;
+ d = (d * m + mRound) >> mBits;
+
+ a = Min_uint32 (a, 65535);
+ b = Min_uint32 (b, 65535);
+ c = Min_uint32 (c, 65535);
+ d = Min_uint32 (d, 65535);
+
+ aPtr [col] = (int16) (a - 32768);
+ bPtr [col] = (int16) (b - 32768);
+ cPtr [col] = (int16) (c - 32768);
+ dPtr [col] = (int16) (d - 32768);
+
+ }
+
+ aPtr += sRowStep;
+ bPtr += sRowStep;
+ cPtr += sRowStep;
+ dPtr += sRowStep;
+
+ mPtr += mRowStep;
+
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ int16 *planePtr = sPtr;
+
+ const uint16 *maskPtr = mPtr;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ uint32 s = planePtr [col] + 32768;
+
+ uint32 m = maskPtr [col];
+
+ s = (s * m + mRound) >> mBits;
+
+ s = Min_uint32 (s, 65535);
+
+ planePtr [col] = (int16) (s - 32768);
+
+ }
+
+ planePtr += sRowStep;
+
+ maskPtr += mRowStep;
+
+ }
+
+ sPtr += sPlaneStep;
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefVignette32 (real32 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits)
+ {
+
+ const real32 kNorm = 1.0f / (1 << mBits);
+
+ switch (planes)
+ {
+
+ case 1:
+ {
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ real32 s = sPtr [col];
+
+ uint16 m = mPtr [col];
+
+ real32 scale = m * kNorm;
+
+ s = Min_real32 (s * scale, 1.0f);
+
+ sPtr [col] = s;
+
+ }
+
+ sPtr += sRowStep;
+
+ mPtr += mRowStep;
+
+ }
+
+ break;
+
+ }
+
+ case 3:
+ {
+
+ real32 *rPtr = sPtr;
+ real32 *gPtr = rPtr + sPlaneStep;
+ real32 *bPtr = gPtr + sPlaneStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ real32 r = rPtr [col];
+ real32 g = gPtr [col];
+ real32 b = bPtr [col];
+
+ uint16 m = mPtr [col];
+
+ real32 scale = m * kNorm;
+
+ r = Min_real32 (r * scale, 1.0f);
+ g = Min_real32 (g * scale, 1.0f);
+ b = Min_real32 (b * scale, 1.0f);
+
+ rPtr [col] = r;
+ gPtr [col] = g;
+ bPtr [col] = b;
+
+ }
+
+ rPtr += sRowStep;
+ gPtr += sRowStep;
+ bPtr += sRowStep;
+
+ mPtr += mRowStep;
+
+ }
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ real32 *aPtr = sPtr;
+ real32 *bPtr = aPtr + sPlaneStep;
+ real32 *cPtr = bPtr + sPlaneStep;
+ real32 *dPtr = cPtr + sPlaneStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ real32 a = aPtr [col];
+ real32 b = bPtr [col];
+ real32 c = cPtr [col];
+ real32 d = dPtr [col];
+
+ uint16 m = mPtr [col];
+
+ real32 scale = m * kNorm;
+
+ a = Min_real32 (a * scale, 1.0f);
+ b = Min_real32 (b * scale, 1.0f);
+ c = Min_real32 (c * scale, 1.0f);
+ d = Min_real32 (d * scale, 1.0f);
+
+ aPtr [col] = a;
+ bPtr [col] = b;
+ cPtr [col] = c;
+ dPtr [col] = d;
+
+ }
+
+ aPtr += sRowStep;
+ bPtr += sRowStep;
+ cPtr += sRowStep;
+ dPtr += sRowStep;
+
+ mPtr += mRowStep;
+
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ real32 *planePtr = sPtr;
+
+ const uint16 *maskPtr = mPtr;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ real32 s = planePtr [col];
+
+ uint16 m = maskPtr [col];
+
+ real32 scale = m * kNorm;
+
+ s = Min_real32 (s * scale, 1.0f);
+
+ planePtr [col] = s;
+
+ }
+
+ planePtr += sRowStep;
+
+ maskPtr += mRowStep;
+
+ }
+
+ sPtr += sPlaneStep;
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void RefMapArea16 (uint16 *dPtr,
+ uint32 count0,
+ uint32 count1,
+ uint32 count2,
+ int32 step0,
+ int32 step1,
+ int32 step2,
+ const uint16 *map)
+ {
+
+ if (step2 == 1 && count2 >= 32)
+ {
+
+ for (uint32 index0 = 0; index0 < count0; index0++)
+ {
+
+ uint16 *d1 = dPtr;
+
+ for (uint32 index1 = 0; index1 < count1; index1++)
+ {
+
+ uint16 *d2 = d1;
+
+ uint32 count = count2;
+
+ // Get the data 32-bit aligned if it is not.
+
+ if (!IsAligned32 (dPtr))
+ {
+
+ d2 [0] = map [d2 [0]];
+
+ count--;
+
+ d2++;
+
+ }
+
+ // Use 32-bit reads and writes for bulk processing.
+
+ uint32 *dPtr32 = (uint32 *) d2;
+
+ // Process in blocks of 16 pixels.
+
+ uint32 blocks = count >> 4;
+
+ count -= blocks << 4;
+ d2 += blocks << 4;
+
+ while (blocks--)
+ {
+
+ uint32 x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32 p0, p1, p2, p3, p4, p5, p6, p7;
+
+ // Use 32 bit reads & writes, and pack and unpack the 16-bit values.
+ // This results in slightly higher performance.
+
+ // Note that this code runs on both little-endian and big-endian systems,
+ // since the pixels are either never swapped or double swapped.
+
+ x0 = dPtr32 [0];
+ x1 = dPtr32 [1];
+ x2 = dPtr32 [2];
+ x3 = dPtr32 [3];
+
+ p0 = map [x0 >> 16 ];
+ p1 = map [x0 & 0x0FFFF];
+ p2 = map [x1 >> 16 ];
+ p3 = map [x1 & 0x0FFFF];
+ p4 = map [x2 >> 16 ];
+ p5 = map [x2 & 0x0FFFF];
+ p6 = map [x3 >> 16 ];
+ p7 = map [x3 & 0x0FFFF];
+
+ x0 = (p0 << 16) | p1;
+ x1 = (p2 << 16) | p3;
+ x2 = (p4 << 16) | p5;
+ x3 = (p6 << 16) | p7;
+
+ x4 = dPtr32 [4];
+ x5 = dPtr32 [5];
+ x6 = dPtr32 [6];
+ x7 = dPtr32 [7];
+
+ dPtr32 [0] = x0;
+ dPtr32 [1] = x1;
+ dPtr32 [2] = x2;
+ dPtr32 [3] = x3;
+
+ p0 = map [x4 >> 16 ];
+ p1 = map [x4 & 0x0FFFF];
+ p2 = map [x5 >> 16 ];
+ p3 = map [x5 & 0x0FFFF];
+ p4 = map [x6 >> 16 ];
+ p5 = map [x6 & 0x0FFFF];
+ p6 = map [x7 >> 16 ];
+ p7 = map [x7 & 0x0FFFF];
+
+ x4 = (p0 << 16) | p1;
+ x5 = (p2 << 16) | p3;
+ x6 = (p4 << 16) | p5;
+ x7 = (p6 << 16) | p7;
+
+ dPtr32 [4] = x4;
+ dPtr32 [5] = x5;
+ dPtr32 [6] = x6;
+ dPtr32 [7] = x7;
+
+ dPtr32 += 8;
+
+ }
+
+ // Process remaining columns.
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ d2 [j] = map [d2 [j]];
+
+ }
+
+ d1 += step1;
+
+ }
+
+ dPtr += step0;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 index0 = 0; index0 < count0; index0++)
+ {
+
+ uint16 *d1 = dPtr;
+
+ for (uint32 index1 = 0; index1 < count1; index1++)
+ {
+
+ uint16 *d2 = d1;
+
+ for (uint32 index2 = 0; index2 < count2; index2++)
+ {
+
+ d2 [0] = map [d2 [0]];
+
+ d2 += step2;
+
+ }
+
+ d1 += step1;
+
+ }
+
+ dPtr += step0;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_reference.h b/gpr/source/lib/dng_sdk/dng_reference.h
new file mode 100644
index 0000000..d75dcec
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_reference.h
@@ -0,0 +1,521 @@
+/*****************************************************************************/
+// Copyright 2006-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_reference.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_reference__
+#define __dng_reference__
+
+/*****************************************************************************/
+
+#include "dng_bottlenecks.h"
+
+/*****************************************************************************/
+
+void RefZeroBytes (void *dPtr,
+ uint32 count);
+
+void RefCopyBytes (const void *sPtr,
+ void *dPtr,
+ uint32 count);
+
+/*****************************************************************************/
+
+void RefSwapBytes16 (uint16 *dPtr,
+ uint32 count);
+
+void RefSwapBytes32 (uint32 *dPtr,
+ uint32 count);
+
+/*****************************************************************************/
+
+void RefSetArea8 (uint8 *dPtr,
+ uint8 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+
+void RefSetArea16 (uint16 *dPtr,
+ uint16 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+
+void RefSetArea32 (uint32 *dPtr,
+ uint32 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+
+/*****************************************************************************/
+
+void RefCopyArea8 (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea32 (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea8_16 (const uint8 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea8_S16 (const uint8 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea8_32 (const uint8 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea16_S16 (const uint16 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea16_32 (const uint16 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+void RefCopyArea8_R32 (const uint8 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+void RefCopyArea16_R32 (const uint16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+void RefCopyAreaS16_R32 (const int16 *sPtr,
+ real32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+void RefCopyAreaR32_8 (const real32 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+void RefCopyAreaR32_16 (const real32 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+void RefCopyAreaR32_S16 (const real32 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep,
+ uint32 pixelRange);
+
+/*****************************************************************************/
+
+void RefRepeatArea8 (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH);
+
+void RefRepeatArea16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH);
+
+void RefRepeatArea32 (const uint32 *sPtr,
+ uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 repeatV,
+ uint32 repeatH,
+ uint32 phaseV,
+ uint32 phaseH);
+
+/*****************************************************************************/
+
+void RefShiftRight16 (uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep,
+ uint32 shift);
+
+/*****************************************************************************/
+
+void RefBilinearRow16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const uint16 * const * kernWeights,
+ uint32 sShift);
+
+void RefBilinearRow32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 cols,
+ uint32 patPhase,
+ uint32 patCount,
+ const uint32 * kernCounts,
+ const int32 * const * kernOffsets,
+ const real32 * const * kernWeights,
+ uint32 sShift);
+
+/*****************************************************************************/
+
+void RefBaselineABCtoRGB (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB);
+
+void RefBaselineABCDtoRGB (const real32 *sPtrA,
+ const real32 *sPtrB,
+ const real32 *sPtrC,
+ const real32 *sPtrD,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_vector &cameraWhite,
+ const dng_matrix &cameraToRGB);
+
+/*****************************************************************************/
+
+void RefBaselineHueSatMap (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_hue_sat_map &lut,
+ const dng_1d_table *encodeTable,
+ const dng_1d_table *decodeTable);
+
+/*****************************************************************************/
+
+void RefBaselineRGBtoGray (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrG,
+ uint32 count,
+ const dng_matrix &matrix);
+
+void RefBaselineRGBtoRGB (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_matrix &matrix);
+
+/*****************************************************************************/
+
+void RefBaseline1DTable (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 count,
+ const dng_1d_table &table);
+
+/*****************************************************************************/
+
+void RefBaselineRGBTone (const real32 *sPtrR,
+ const real32 *sPtrG,
+ const real32 *sPtrB,
+ real32 *dPtrR,
+ real32 *dPtrG,
+ real32 *dPtrB,
+ uint32 count,
+ const dng_1d_table &table);
+
+/*****************************************************************************/
+
+void RefResampleDown16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 pixelRange);
+
+void RefResampleDown32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 sCount,
+ int32 sRowStep,
+ const real32 *wPtr,
+ uint32 wCount);
+
+/*****************************************************************************/
+
+void RefResampleAcross16 (const uint16 *sPtr,
+ uint16 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const int16 *wPtr,
+ uint32 wCount,
+ uint32 wStep,
+ uint32 pixelRange);
+
+void RefResampleAcross32 (const real32 *sPtr,
+ real32 *dPtr,
+ uint32 dCount,
+ const int32 *coord,
+ const real32 *wPtr,
+ uint32 wCount,
+ uint32 wStep);
+
+/*****************************************************************************/
+
+bool RefEqualBytes (const void *sPtr,
+ const void *dPtr,
+ uint32 count);
+
+bool RefEqualArea8 (const uint8 *sPtr,
+ const uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+bool RefEqualArea16 (const uint16 *sPtr,
+ const uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+bool RefEqualArea32 (const uint32 *sPtr,
+ const uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+
+/*****************************************************************************/
+
+void RefVignetteMask16 (uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ int32 rowStep,
+ int64 offsetH,
+ int64 offsetV,
+ int64 stepH,
+ int64 stepV,
+ uint32 tBits,
+ const uint16 *table);
+
+/*****************************************************************************/
+
+void RefVignette16 (int16 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits);
+
+/*****************************************************************************/
+
+void RefVignette32 (real32 *sPtr,
+ const uint16 *mPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sPlaneStep,
+ int32 mRowStep,
+ uint32 mBits);
+
+/*****************************************************************************/
+
+void RefMapArea16 (uint16 *dPtr,
+ uint32 count0,
+ uint32 count1,
+ uint32 count2,
+ int32 step0,
+ int32 step1,
+ int32 step2,
+ const uint16 *map);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_render.cpp b/gpr/source/lib/dng_sdk/dng_render.cpp
new file mode 100644
index 0000000..1751363
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_render.cpp
@@ -0,0 +1,1328 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_render.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_render.h"
+
+#include "dng_1d_table.h"
+#include "dng_bottlenecks.h"
+#include "dng_camera_profile.h"
+#include "dng_color_space.h"
+#include "dng_color_spec.h"
+#include "dng_filter_task.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_negative.h"
+#include "dng_resample.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_function_exposure_ramp::dng_function_exposure_ramp (real64 white,
+ real64 black,
+ real64 minBlack)
+
+ : fSlope (1.0 / (white - black))
+ , fBlack (black)
+
+ , fRadius (0.0)
+ , fQScale (0.0)
+
+ {
+
+ const real64 kMaxCurveX = 0.5; // Fraction of minBlack.
+
+ const real64 kMaxCurveY = 1.0 / 16.0; // Fraction of white.
+
+ fRadius = Min_real64 (kMaxCurveX * minBlack,
+ kMaxCurveY / fSlope);
+
+ if (fRadius > 0.0)
+ fQScale= fSlope / (4.0 * fRadius);
+ else
+ fQScale = 0.0;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_exposure_ramp::Evaluate (real64 x) const
+ {
+
+ if (x <= fBlack - fRadius)
+ return 0.0;
+
+ if (x >= fBlack + fRadius)
+ return Min_real64 ((x - fBlack) * fSlope, 1.0);
+
+ real64 y = x - (fBlack - fRadius);
+
+ return fQScale * y * y;
+
+ }
+
+/*****************************************************************************/
+
+dng_function_exposure_tone::dng_function_exposure_tone (real64 exposure)
+
+ : fIsNOP (exposure >= 0.0)
+
+ , fSlope (0.0)
+
+ , a (0.0)
+ , b (0.0)
+ , c (0.0)
+
+ {
+
+ if (!fIsNOP)
+ {
+
+ // Find slope to use for the all except the highest two f-stops.
+
+ fSlope = pow (2.0, exposure);
+
+ // Find quadradic parameters that match this darking at the crossover
+ // point, yet still map pure white to pure white.
+
+ a = 16.0 / 9.0 * (1.0 - fSlope);
+
+ b = fSlope - 0.5 * a;
+
+ c = 1.0 - a - b;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_exposure_tone::Evaluate (real64 x) const
+ {
+
+ if (!fIsNOP)
+ {
+
+ if (x <= 0.25)
+ x = x * fSlope;
+
+ else
+ x = (a * x + b) * x + c;
+
+ }
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_tone_curve_acr3_default::Evaluate (real64 x) const
+ {
+
+ static const real32 kTable [] =
+ {
+ 0.00000f, 0.00078f, 0.00160f, 0.00242f,
+ 0.00314f, 0.00385f, 0.00460f, 0.00539f,
+ 0.00623f, 0.00712f, 0.00806f, 0.00906f,
+ 0.01012f, 0.01122f, 0.01238f, 0.01359f,
+ 0.01485f, 0.01616f, 0.01751f, 0.01890f,
+ 0.02033f, 0.02180f, 0.02331f, 0.02485f,
+ 0.02643f, 0.02804f, 0.02967f, 0.03134f,
+ 0.03303f, 0.03475f, 0.03648f, 0.03824f,
+ 0.04002f, 0.04181f, 0.04362f, 0.04545f,
+ 0.04730f, 0.04916f, 0.05103f, 0.05292f,
+ 0.05483f, 0.05675f, 0.05868f, 0.06063f,
+ 0.06259f, 0.06457f, 0.06655f, 0.06856f,
+ 0.07057f, 0.07259f, 0.07463f, 0.07668f,
+ 0.07874f, 0.08081f, 0.08290f, 0.08499f,
+ 0.08710f, 0.08921f, 0.09134f, 0.09348f,
+ 0.09563f, 0.09779f, 0.09996f, 0.10214f,
+ 0.10433f, 0.10652f, 0.10873f, 0.11095f,
+ 0.11318f, 0.11541f, 0.11766f, 0.11991f,
+ 0.12218f, 0.12445f, 0.12673f, 0.12902f,
+ 0.13132f, 0.13363f, 0.13595f, 0.13827f,
+ 0.14061f, 0.14295f, 0.14530f, 0.14765f,
+ 0.15002f, 0.15239f, 0.15477f, 0.15716f,
+ 0.15956f, 0.16197f, 0.16438f, 0.16680f,
+ 0.16923f, 0.17166f, 0.17410f, 0.17655f,
+ 0.17901f, 0.18148f, 0.18395f, 0.18643f,
+ 0.18891f, 0.19141f, 0.19391f, 0.19641f,
+ 0.19893f, 0.20145f, 0.20398f, 0.20651f,
+ 0.20905f, 0.21160f, 0.21416f, 0.21672f,
+ 0.21929f, 0.22185f, 0.22440f, 0.22696f,
+ 0.22950f, 0.23204f, 0.23458f, 0.23711f,
+ 0.23963f, 0.24215f, 0.24466f, 0.24717f,
+ 0.24967f, 0.25216f, 0.25465f, 0.25713f,
+ 0.25961f, 0.26208f, 0.26454f, 0.26700f,
+ 0.26945f, 0.27189f, 0.27433f, 0.27676f,
+ 0.27918f, 0.28160f, 0.28401f, 0.28641f,
+ 0.28881f, 0.29120f, 0.29358f, 0.29596f,
+ 0.29833f, 0.30069f, 0.30305f, 0.30540f,
+ 0.30774f, 0.31008f, 0.31241f, 0.31473f,
+ 0.31704f, 0.31935f, 0.32165f, 0.32395f,
+ 0.32623f, 0.32851f, 0.33079f, 0.33305f,
+ 0.33531f, 0.33756f, 0.33981f, 0.34205f,
+ 0.34428f, 0.34650f, 0.34872f, 0.35093f,
+ 0.35313f, 0.35532f, 0.35751f, 0.35969f,
+ 0.36187f, 0.36404f, 0.36620f, 0.36835f,
+ 0.37050f, 0.37264f, 0.37477f, 0.37689f,
+ 0.37901f, 0.38112f, 0.38323f, 0.38533f,
+ 0.38742f, 0.38950f, 0.39158f, 0.39365f,
+ 0.39571f, 0.39777f, 0.39982f, 0.40186f,
+ 0.40389f, 0.40592f, 0.40794f, 0.40996f,
+ 0.41197f, 0.41397f, 0.41596f, 0.41795f,
+ 0.41993f, 0.42191f, 0.42388f, 0.42584f,
+ 0.42779f, 0.42974f, 0.43168f, 0.43362f,
+ 0.43554f, 0.43747f, 0.43938f, 0.44129f,
+ 0.44319f, 0.44509f, 0.44698f, 0.44886f,
+ 0.45073f, 0.45260f, 0.45447f, 0.45632f,
+ 0.45817f, 0.46002f, 0.46186f, 0.46369f,
+ 0.46551f, 0.46733f, 0.46914f, 0.47095f,
+ 0.47275f, 0.47454f, 0.47633f, 0.47811f,
+ 0.47989f, 0.48166f, 0.48342f, 0.48518f,
+ 0.48693f, 0.48867f, 0.49041f, 0.49214f,
+ 0.49387f, 0.49559f, 0.49730f, 0.49901f,
+ 0.50072f, 0.50241f, 0.50410f, 0.50579f,
+ 0.50747f, 0.50914f, 0.51081f, 0.51247f,
+ 0.51413f, 0.51578f, 0.51742f, 0.51906f,
+ 0.52069f, 0.52232f, 0.52394f, 0.52556f,
+ 0.52717f, 0.52878f, 0.53038f, 0.53197f,
+ 0.53356f, 0.53514f, 0.53672f, 0.53829f,
+ 0.53986f, 0.54142f, 0.54297f, 0.54452f,
+ 0.54607f, 0.54761f, 0.54914f, 0.55067f,
+ 0.55220f, 0.55371f, 0.55523f, 0.55673f,
+ 0.55824f, 0.55973f, 0.56123f, 0.56271f,
+ 0.56420f, 0.56567f, 0.56715f, 0.56861f,
+ 0.57007f, 0.57153f, 0.57298f, 0.57443f,
+ 0.57587f, 0.57731f, 0.57874f, 0.58017f,
+ 0.58159f, 0.58301f, 0.58443f, 0.58583f,
+ 0.58724f, 0.58864f, 0.59003f, 0.59142f,
+ 0.59281f, 0.59419f, 0.59556f, 0.59694f,
+ 0.59830f, 0.59966f, 0.60102f, 0.60238f,
+ 0.60373f, 0.60507f, 0.60641f, 0.60775f,
+ 0.60908f, 0.61040f, 0.61173f, 0.61305f,
+ 0.61436f, 0.61567f, 0.61698f, 0.61828f,
+ 0.61957f, 0.62087f, 0.62216f, 0.62344f,
+ 0.62472f, 0.62600f, 0.62727f, 0.62854f,
+ 0.62980f, 0.63106f, 0.63232f, 0.63357f,
+ 0.63482f, 0.63606f, 0.63730f, 0.63854f,
+ 0.63977f, 0.64100f, 0.64222f, 0.64344f,
+ 0.64466f, 0.64587f, 0.64708f, 0.64829f,
+ 0.64949f, 0.65069f, 0.65188f, 0.65307f,
+ 0.65426f, 0.65544f, 0.65662f, 0.65779f,
+ 0.65897f, 0.66013f, 0.66130f, 0.66246f,
+ 0.66362f, 0.66477f, 0.66592f, 0.66707f,
+ 0.66821f, 0.66935f, 0.67048f, 0.67162f,
+ 0.67275f, 0.67387f, 0.67499f, 0.67611f,
+ 0.67723f, 0.67834f, 0.67945f, 0.68055f,
+ 0.68165f, 0.68275f, 0.68385f, 0.68494f,
+ 0.68603f, 0.68711f, 0.68819f, 0.68927f,
+ 0.69035f, 0.69142f, 0.69249f, 0.69355f,
+ 0.69461f, 0.69567f, 0.69673f, 0.69778f,
+ 0.69883f, 0.69988f, 0.70092f, 0.70196f,
+ 0.70300f, 0.70403f, 0.70506f, 0.70609f,
+ 0.70711f, 0.70813f, 0.70915f, 0.71017f,
+ 0.71118f, 0.71219f, 0.71319f, 0.71420f,
+ 0.71520f, 0.71620f, 0.71719f, 0.71818f,
+ 0.71917f, 0.72016f, 0.72114f, 0.72212f,
+ 0.72309f, 0.72407f, 0.72504f, 0.72601f,
+ 0.72697f, 0.72794f, 0.72890f, 0.72985f,
+ 0.73081f, 0.73176f, 0.73271f, 0.73365f,
+ 0.73460f, 0.73554f, 0.73647f, 0.73741f,
+ 0.73834f, 0.73927f, 0.74020f, 0.74112f,
+ 0.74204f, 0.74296f, 0.74388f, 0.74479f,
+ 0.74570f, 0.74661f, 0.74751f, 0.74842f,
+ 0.74932f, 0.75021f, 0.75111f, 0.75200f,
+ 0.75289f, 0.75378f, 0.75466f, 0.75555f,
+ 0.75643f, 0.75730f, 0.75818f, 0.75905f,
+ 0.75992f, 0.76079f, 0.76165f, 0.76251f,
+ 0.76337f, 0.76423f, 0.76508f, 0.76594f,
+ 0.76679f, 0.76763f, 0.76848f, 0.76932f,
+ 0.77016f, 0.77100f, 0.77183f, 0.77267f,
+ 0.77350f, 0.77432f, 0.77515f, 0.77597f,
+ 0.77680f, 0.77761f, 0.77843f, 0.77924f,
+ 0.78006f, 0.78087f, 0.78167f, 0.78248f,
+ 0.78328f, 0.78408f, 0.78488f, 0.78568f,
+ 0.78647f, 0.78726f, 0.78805f, 0.78884f,
+ 0.78962f, 0.79040f, 0.79118f, 0.79196f,
+ 0.79274f, 0.79351f, 0.79428f, 0.79505f,
+ 0.79582f, 0.79658f, 0.79735f, 0.79811f,
+ 0.79887f, 0.79962f, 0.80038f, 0.80113f,
+ 0.80188f, 0.80263f, 0.80337f, 0.80412f,
+ 0.80486f, 0.80560f, 0.80634f, 0.80707f,
+ 0.80780f, 0.80854f, 0.80926f, 0.80999f,
+ 0.81072f, 0.81144f, 0.81216f, 0.81288f,
+ 0.81360f, 0.81431f, 0.81503f, 0.81574f,
+ 0.81645f, 0.81715f, 0.81786f, 0.81856f,
+ 0.81926f, 0.81996f, 0.82066f, 0.82135f,
+ 0.82205f, 0.82274f, 0.82343f, 0.82412f,
+ 0.82480f, 0.82549f, 0.82617f, 0.82685f,
+ 0.82753f, 0.82820f, 0.82888f, 0.82955f,
+ 0.83022f, 0.83089f, 0.83155f, 0.83222f,
+ 0.83288f, 0.83354f, 0.83420f, 0.83486f,
+ 0.83552f, 0.83617f, 0.83682f, 0.83747f,
+ 0.83812f, 0.83877f, 0.83941f, 0.84005f,
+ 0.84069f, 0.84133f, 0.84197f, 0.84261f,
+ 0.84324f, 0.84387f, 0.84450f, 0.84513f,
+ 0.84576f, 0.84639f, 0.84701f, 0.84763f,
+ 0.84825f, 0.84887f, 0.84949f, 0.85010f,
+ 0.85071f, 0.85132f, 0.85193f, 0.85254f,
+ 0.85315f, 0.85375f, 0.85436f, 0.85496f,
+ 0.85556f, 0.85615f, 0.85675f, 0.85735f,
+ 0.85794f, 0.85853f, 0.85912f, 0.85971f,
+ 0.86029f, 0.86088f, 0.86146f, 0.86204f,
+ 0.86262f, 0.86320f, 0.86378f, 0.86435f,
+ 0.86493f, 0.86550f, 0.86607f, 0.86664f,
+ 0.86720f, 0.86777f, 0.86833f, 0.86889f,
+ 0.86945f, 0.87001f, 0.87057f, 0.87113f,
+ 0.87168f, 0.87223f, 0.87278f, 0.87333f,
+ 0.87388f, 0.87443f, 0.87497f, 0.87552f,
+ 0.87606f, 0.87660f, 0.87714f, 0.87768f,
+ 0.87821f, 0.87875f, 0.87928f, 0.87981f,
+ 0.88034f, 0.88087f, 0.88140f, 0.88192f,
+ 0.88244f, 0.88297f, 0.88349f, 0.88401f,
+ 0.88453f, 0.88504f, 0.88556f, 0.88607f,
+ 0.88658f, 0.88709f, 0.88760f, 0.88811f,
+ 0.88862f, 0.88912f, 0.88963f, 0.89013f,
+ 0.89063f, 0.89113f, 0.89163f, 0.89212f,
+ 0.89262f, 0.89311f, 0.89360f, 0.89409f,
+ 0.89458f, 0.89507f, 0.89556f, 0.89604f,
+ 0.89653f, 0.89701f, 0.89749f, 0.89797f,
+ 0.89845f, 0.89892f, 0.89940f, 0.89987f,
+ 0.90035f, 0.90082f, 0.90129f, 0.90176f,
+ 0.90222f, 0.90269f, 0.90316f, 0.90362f,
+ 0.90408f, 0.90454f, 0.90500f, 0.90546f,
+ 0.90592f, 0.90637f, 0.90683f, 0.90728f,
+ 0.90773f, 0.90818f, 0.90863f, 0.90908f,
+ 0.90952f, 0.90997f, 0.91041f, 0.91085f,
+ 0.91130f, 0.91173f, 0.91217f, 0.91261f,
+ 0.91305f, 0.91348f, 0.91392f, 0.91435f,
+ 0.91478f, 0.91521f, 0.91564f, 0.91606f,
+ 0.91649f, 0.91691f, 0.91734f, 0.91776f,
+ 0.91818f, 0.91860f, 0.91902f, 0.91944f,
+ 0.91985f, 0.92027f, 0.92068f, 0.92109f,
+ 0.92150f, 0.92191f, 0.92232f, 0.92273f,
+ 0.92314f, 0.92354f, 0.92395f, 0.92435f,
+ 0.92475f, 0.92515f, 0.92555f, 0.92595f,
+ 0.92634f, 0.92674f, 0.92713f, 0.92753f,
+ 0.92792f, 0.92831f, 0.92870f, 0.92909f,
+ 0.92947f, 0.92986f, 0.93025f, 0.93063f,
+ 0.93101f, 0.93139f, 0.93177f, 0.93215f,
+ 0.93253f, 0.93291f, 0.93328f, 0.93366f,
+ 0.93403f, 0.93440f, 0.93478f, 0.93515f,
+ 0.93551f, 0.93588f, 0.93625f, 0.93661f,
+ 0.93698f, 0.93734f, 0.93770f, 0.93807f,
+ 0.93843f, 0.93878f, 0.93914f, 0.93950f,
+ 0.93986f, 0.94021f, 0.94056f, 0.94092f,
+ 0.94127f, 0.94162f, 0.94197f, 0.94231f,
+ 0.94266f, 0.94301f, 0.94335f, 0.94369f,
+ 0.94404f, 0.94438f, 0.94472f, 0.94506f,
+ 0.94540f, 0.94573f, 0.94607f, 0.94641f,
+ 0.94674f, 0.94707f, 0.94740f, 0.94774f,
+ 0.94807f, 0.94839f, 0.94872f, 0.94905f,
+ 0.94937f, 0.94970f, 0.95002f, 0.95035f,
+ 0.95067f, 0.95099f, 0.95131f, 0.95163f,
+ 0.95194f, 0.95226f, 0.95257f, 0.95289f,
+ 0.95320f, 0.95351f, 0.95383f, 0.95414f,
+ 0.95445f, 0.95475f, 0.95506f, 0.95537f,
+ 0.95567f, 0.95598f, 0.95628f, 0.95658f,
+ 0.95688f, 0.95718f, 0.95748f, 0.95778f,
+ 0.95808f, 0.95838f, 0.95867f, 0.95897f,
+ 0.95926f, 0.95955f, 0.95984f, 0.96013f,
+ 0.96042f, 0.96071f, 0.96100f, 0.96129f,
+ 0.96157f, 0.96186f, 0.96214f, 0.96242f,
+ 0.96271f, 0.96299f, 0.96327f, 0.96355f,
+ 0.96382f, 0.96410f, 0.96438f, 0.96465f,
+ 0.96493f, 0.96520f, 0.96547f, 0.96574f,
+ 0.96602f, 0.96629f, 0.96655f, 0.96682f,
+ 0.96709f, 0.96735f, 0.96762f, 0.96788f,
+ 0.96815f, 0.96841f, 0.96867f, 0.96893f,
+ 0.96919f, 0.96945f, 0.96971f, 0.96996f,
+ 0.97022f, 0.97047f, 0.97073f, 0.97098f,
+ 0.97123f, 0.97149f, 0.97174f, 0.97199f,
+ 0.97223f, 0.97248f, 0.97273f, 0.97297f,
+ 0.97322f, 0.97346f, 0.97371f, 0.97395f,
+ 0.97419f, 0.97443f, 0.97467f, 0.97491f,
+ 0.97515f, 0.97539f, 0.97562f, 0.97586f,
+ 0.97609f, 0.97633f, 0.97656f, 0.97679f,
+ 0.97702f, 0.97725f, 0.97748f, 0.97771f,
+ 0.97794f, 0.97817f, 0.97839f, 0.97862f,
+ 0.97884f, 0.97907f, 0.97929f, 0.97951f,
+ 0.97973f, 0.97995f, 0.98017f, 0.98039f,
+ 0.98061f, 0.98082f, 0.98104f, 0.98125f,
+ 0.98147f, 0.98168f, 0.98189f, 0.98211f,
+ 0.98232f, 0.98253f, 0.98274f, 0.98295f,
+ 0.98315f, 0.98336f, 0.98357f, 0.98377f,
+ 0.98398f, 0.98418f, 0.98438f, 0.98458f,
+ 0.98478f, 0.98498f, 0.98518f, 0.98538f,
+ 0.98558f, 0.98578f, 0.98597f, 0.98617f,
+ 0.98636f, 0.98656f, 0.98675f, 0.98694f,
+ 0.98714f, 0.98733f, 0.98752f, 0.98771f,
+ 0.98789f, 0.98808f, 0.98827f, 0.98845f,
+ 0.98864f, 0.98882f, 0.98901f, 0.98919f,
+ 0.98937f, 0.98955f, 0.98973f, 0.98991f,
+ 0.99009f, 0.99027f, 0.99045f, 0.99063f,
+ 0.99080f, 0.99098f, 0.99115f, 0.99133f,
+ 0.99150f, 0.99167f, 0.99184f, 0.99201f,
+ 0.99218f, 0.99235f, 0.99252f, 0.99269f,
+ 0.99285f, 0.99302f, 0.99319f, 0.99335f,
+ 0.99351f, 0.99368f, 0.99384f, 0.99400f,
+ 0.99416f, 0.99432f, 0.99448f, 0.99464f,
+ 0.99480f, 0.99495f, 0.99511f, 0.99527f,
+ 0.99542f, 0.99558f, 0.99573f, 0.99588f,
+ 0.99603f, 0.99619f, 0.99634f, 0.99649f,
+ 0.99664f, 0.99678f, 0.99693f, 0.99708f,
+ 0.99722f, 0.99737f, 0.99751f, 0.99766f,
+ 0.99780f, 0.99794f, 0.99809f, 0.99823f,
+ 0.99837f, 0.99851f, 0.99865f, 0.99879f,
+ 0.99892f, 0.99906f, 0.99920f, 0.99933f,
+ 0.99947f, 0.99960f, 0.99974f, 0.99987f,
+ 1.00000f
+ };
+
+ const uint32 kTableSize = sizeof (kTable ) /
+ sizeof (kTable [0]);
+
+ real32 y = (real32) x * (real32) (kTableSize - 1);
+
+ int32 index = Pin_int32 (0, (int32) y, kTableSize - 2);
+
+ real32 fract = y - (real32) index;
+
+ return kTable [index ] * (1.0f - fract) +
+ kTable [index + 1] * ( fract);
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_tone_curve_acr3_default::EvaluateInverse (real64 x) const
+ {
+
+ static const real32 kTable [] =
+ {
+ 0.00000f, 0.00121f, 0.00237f, 0.00362f,
+ 0.00496f, 0.00621f, 0.00738f, 0.00848f,
+ 0.00951f, 0.01048f, 0.01139f, 0.01227f,
+ 0.01312f, 0.01393f, 0.01471f, 0.01547f,
+ 0.01620f, 0.01692f, 0.01763f, 0.01831f,
+ 0.01899f, 0.01965f, 0.02030f, 0.02094f,
+ 0.02157f, 0.02218f, 0.02280f, 0.02340f,
+ 0.02399f, 0.02458f, 0.02517f, 0.02574f,
+ 0.02631f, 0.02688f, 0.02744f, 0.02800f,
+ 0.02855f, 0.02910f, 0.02965f, 0.03019f,
+ 0.03072f, 0.03126f, 0.03179f, 0.03232f,
+ 0.03285f, 0.03338f, 0.03390f, 0.03442f,
+ 0.03493f, 0.03545f, 0.03596f, 0.03647f,
+ 0.03698f, 0.03749f, 0.03799f, 0.03849f,
+ 0.03899f, 0.03949f, 0.03998f, 0.04048f,
+ 0.04097f, 0.04146f, 0.04195f, 0.04244f,
+ 0.04292f, 0.04341f, 0.04389f, 0.04437f,
+ 0.04485f, 0.04533f, 0.04580f, 0.04628f,
+ 0.04675f, 0.04722f, 0.04769f, 0.04816f,
+ 0.04863f, 0.04910f, 0.04956f, 0.05003f,
+ 0.05049f, 0.05095f, 0.05141f, 0.05187f,
+ 0.05233f, 0.05278f, 0.05324f, 0.05370f,
+ 0.05415f, 0.05460f, 0.05505f, 0.05551f,
+ 0.05595f, 0.05640f, 0.05685f, 0.05729f,
+ 0.05774f, 0.05818f, 0.05863f, 0.05907f,
+ 0.05951f, 0.05995f, 0.06039f, 0.06083f,
+ 0.06126f, 0.06170f, 0.06214f, 0.06257f,
+ 0.06301f, 0.06344f, 0.06388f, 0.06431f,
+ 0.06474f, 0.06517f, 0.06560f, 0.06602f,
+ 0.06645f, 0.06688f, 0.06731f, 0.06773f,
+ 0.06815f, 0.06858f, 0.06900f, 0.06943f,
+ 0.06985f, 0.07027f, 0.07069f, 0.07111f,
+ 0.07152f, 0.07194f, 0.07236f, 0.07278f,
+ 0.07319f, 0.07361f, 0.07402f, 0.07444f,
+ 0.07485f, 0.07526f, 0.07567f, 0.07608f,
+ 0.07650f, 0.07691f, 0.07732f, 0.07772f,
+ 0.07813f, 0.07854f, 0.07895f, 0.07935f,
+ 0.07976f, 0.08016f, 0.08057f, 0.08098f,
+ 0.08138f, 0.08178f, 0.08218f, 0.08259f,
+ 0.08299f, 0.08339f, 0.08379f, 0.08419f,
+ 0.08459f, 0.08499f, 0.08539f, 0.08578f,
+ 0.08618f, 0.08657f, 0.08697f, 0.08737f,
+ 0.08776f, 0.08816f, 0.08855f, 0.08894f,
+ 0.08934f, 0.08973f, 0.09012f, 0.09051f,
+ 0.09091f, 0.09130f, 0.09169f, 0.09208f,
+ 0.09247f, 0.09286f, 0.09324f, 0.09363f,
+ 0.09402f, 0.09440f, 0.09479f, 0.09518f,
+ 0.09556f, 0.09595f, 0.09633f, 0.09672f,
+ 0.09710f, 0.09749f, 0.09787f, 0.09825f,
+ 0.09863f, 0.09901f, 0.09939f, 0.09978f,
+ 0.10016f, 0.10054f, 0.10092f, 0.10130f,
+ 0.10167f, 0.10205f, 0.10243f, 0.10281f,
+ 0.10319f, 0.10356f, 0.10394f, 0.10432f,
+ 0.10469f, 0.10507f, 0.10544f, 0.10582f,
+ 0.10619f, 0.10657f, 0.10694f, 0.10731f,
+ 0.10768f, 0.10806f, 0.10843f, 0.10880f,
+ 0.10917f, 0.10954f, 0.10991f, 0.11029f,
+ 0.11066f, 0.11103f, 0.11141f, 0.11178f,
+ 0.11215f, 0.11253f, 0.11290f, 0.11328f,
+ 0.11365f, 0.11403f, 0.11440f, 0.11478f,
+ 0.11516f, 0.11553f, 0.11591f, 0.11629f,
+ 0.11666f, 0.11704f, 0.11742f, 0.11780f,
+ 0.11818f, 0.11856f, 0.11894f, 0.11932f,
+ 0.11970f, 0.12008f, 0.12046f, 0.12084f,
+ 0.12122f, 0.12161f, 0.12199f, 0.12237f,
+ 0.12276f, 0.12314f, 0.12352f, 0.12391f,
+ 0.12429f, 0.12468f, 0.12506f, 0.12545f,
+ 0.12583f, 0.12622f, 0.12661f, 0.12700f,
+ 0.12738f, 0.12777f, 0.12816f, 0.12855f,
+ 0.12894f, 0.12933f, 0.12972f, 0.13011f,
+ 0.13050f, 0.13089f, 0.13129f, 0.13168f,
+ 0.13207f, 0.13247f, 0.13286f, 0.13325f,
+ 0.13365f, 0.13404f, 0.13444f, 0.13483f,
+ 0.13523f, 0.13563f, 0.13603f, 0.13642f,
+ 0.13682f, 0.13722f, 0.13762f, 0.13802f,
+ 0.13842f, 0.13882f, 0.13922f, 0.13962f,
+ 0.14003f, 0.14043f, 0.14083f, 0.14124f,
+ 0.14164f, 0.14204f, 0.14245f, 0.14285f,
+ 0.14326f, 0.14366f, 0.14407f, 0.14448f,
+ 0.14489f, 0.14530f, 0.14570f, 0.14611f,
+ 0.14652f, 0.14693f, 0.14734f, 0.14776f,
+ 0.14817f, 0.14858f, 0.14900f, 0.14941f,
+ 0.14982f, 0.15024f, 0.15065f, 0.15107f,
+ 0.15148f, 0.15190f, 0.15232f, 0.15274f,
+ 0.15316f, 0.15357f, 0.15399f, 0.15441f,
+ 0.15483f, 0.15526f, 0.15568f, 0.15610f,
+ 0.15652f, 0.15695f, 0.15737f, 0.15779f,
+ 0.15822f, 0.15864f, 0.15907f, 0.15950f,
+ 0.15992f, 0.16035f, 0.16078f, 0.16121f,
+ 0.16164f, 0.16207f, 0.16250f, 0.16293f,
+ 0.16337f, 0.16380f, 0.16423f, 0.16467f,
+ 0.16511f, 0.16554f, 0.16598f, 0.16641f,
+ 0.16685f, 0.16729f, 0.16773f, 0.16816f,
+ 0.16860f, 0.16904f, 0.16949f, 0.16993f,
+ 0.17037f, 0.17081f, 0.17126f, 0.17170f,
+ 0.17215f, 0.17259f, 0.17304f, 0.17349f,
+ 0.17393f, 0.17438f, 0.17483f, 0.17528f,
+ 0.17573f, 0.17619f, 0.17664f, 0.17709f,
+ 0.17754f, 0.17799f, 0.17845f, 0.17890f,
+ 0.17936f, 0.17982f, 0.18028f, 0.18073f,
+ 0.18119f, 0.18165f, 0.18211f, 0.18257f,
+ 0.18303f, 0.18350f, 0.18396f, 0.18442f,
+ 0.18489f, 0.18535f, 0.18582f, 0.18629f,
+ 0.18676f, 0.18723f, 0.18770f, 0.18817f,
+ 0.18864f, 0.18911f, 0.18958f, 0.19005f,
+ 0.19053f, 0.19100f, 0.19147f, 0.19195f,
+ 0.19243f, 0.19291f, 0.19339f, 0.19387f,
+ 0.19435f, 0.19483f, 0.19531f, 0.19579f,
+ 0.19627f, 0.19676f, 0.19724f, 0.19773f,
+ 0.19821f, 0.19870f, 0.19919f, 0.19968f,
+ 0.20017f, 0.20066f, 0.20115f, 0.20164f,
+ 0.20214f, 0.20263f, 0.20313f, 0.20362f,
+ 0.20412f, 0.20462f, 0.20512f, 0.20561f,
+ 0.20611f, 0.20662f, 0.20712f, 0.20762f,
+ 0.20812f, 0.20863f, 0.20913f, 0.20964f,
+ 0.21015f, 0.21066f, 0.21117f, 0.21168f,
+ 0.21219f, 0.21270f, 0.21321f, 0.21373f,
+ 0.21424f, 0.21476f, 0.21527f, 0.21579f,
+ 0.21631f, 0.21683f, 0.21735f, 0.21787f,
+ 0.21839f, 0.21892f, 0.21944f, 0.21997f,
+ 0.22049f, 0.22102f, 0.22155f, 0.22208f,
+ 0.22261f, 0.22314f, 0.22367f, 0.22420f,
+ 0.22474f, 0.22527f, 0.22581f, 0.22634f,
+ 0.22688f, 0.22742f, 0.22796f, 0.22850f,
+ 0.22905f, 0.22959f, 0.23013f, 0.23068f,
+ 0.23123f, 0.23178f, 0.23232f, 0.23287f,
+ 0.23343f, 0.23398f, 0.23453f, 0.23508f,
+ 0.23564f, 0.23620f, 0.23675f, 0.23731f,
+ 0.23787f, 0.23843f, 0.23899f, 0.23956f,
+ 0.24012f, 0.24069f, 0.24125f, 0.24182f,
+ 0.24239f, 0.24296f, 0.24353f, 0.24410f,
+ 0.24468f, 0.24525f, 0.24582f, 0.24640f,
+ 0.24698f, 0.24756f, 0.24814f, 0.24872f,
+ 0.24931f, 0.24989f, 0.25048f, 0.25106f,
+ 0.25165f, 0.25224f, 0.25283f, 0.25342f,
+ 0.25401f, 0.25460f, 0.25520f, 0.25579f,
+ 0.25639f, 0.25699f, 0.25759f, 0.25820f,
+ 0.25880f, 0.25940f, 0.26001f, 0.26062f,
+ 0.26122f, 0.26183f, 0.26244f, 0.26306f,
+ 0.26367f, 0.26429f, 0.26490f, 0.26552f,
+ 0.26614f, 0.26676f, 0.26738f, 0.26800f,
+ 0.26863f, 0.26925f, 0.26988f, 0.27051f,
+ 0.27114f, 0.27177f, 0.27240f, 0.27303f,
+ 0.27367f, 0.27431f, 0.27495f, 0.27558f,
+ 0.27623f, 0.27687f, 0.27751f, 0.27816f,
+ 0.27881f, 0.27945f, 0.28011f, 0.28076f,
+ 0.28141f, 0.28207f, 0.28272f, 0.28338f,
+ 0.28404f, 0.28470f, 0.28536f, 0.28602f,
+ 0.28669f, 0.28736f, 0.28802f, 0.28869f,
+ 0.28937f, 0.29004f, 0.29071f, 0.29139f,
+ 0.29207f, 0.29274f, 0.29342f, 0.29410f,
+ 0.29479f, 0.29548f, 0.29616f, 0.29685f,
+ 0.29754f, 0.29823f, 0.29893f, 0.29962f,
+ 0.30032f, 0.30102f, 0.30172f, 0.30242f,
+ 0.30312f, 0.30383f, 0.30453f, 0.30524f,
+ 0.30595f, 0.30667f, 0.30738f, 0.30809f,
+ 0.30881f, 0.30953f, 0.31025f, 0.31097f,
+ 0.31170f, 0.31242f, 0.31315f, 0.31388f,
+ 0.31461f, 0.31534f, 0.31608f, 0.31682f,
+ 0.31755f, 0.31829f, 0.31904f, 0.31978f,
+ 0.32053f, 0.32127f, 0.32202f, 0.32277f,
+ 0.32353f, 0.32428f, 0.32504f, 0.32580f,
+ 0.32656f, 0.32732f, 0.32808f, 0.32885f,
+ 0.32962f, 0.33039f, 0.33116f, 0.33193f,
+ 0.33271f, 0.33349f, 0.33427f, 0.33505f,
+ 0.33583f, 0.33662f, 0.33741f, 0.33820f,
+ 0.33899f, 0.33978f, 0.34058f, 0.34138f,
+ 0.34218f, 0.34298f, 0.34378f, 0.34459f,
+ 0.34540f, 0.34621f, 0.34702f, 0.34783f,
+ 0.34865f, 0.34947f, 0.35029f, 0.35111f,
+ 0.35194f, 0.35277f, 0.35360f, 0.35443f,
+ 0.35526f, 0.35610f, 0.35694f, 0.35778f,
+ 0.35862f, 0.35946f, 0.36032f, 0.36117f,
+ 0.36202f, 0.36287f, 0.36372f, 0.36458f,
+ 0.36545f, 0.36631f, 0.36718f, 0.36805f,
+ 0.36891f, 0.36979f, 0.37066f, 0.37154f,
+ 0.37242f, 0.37331f, 0.37419f, 0.37507f,
+ 0.37596f, 0.37686f, 0.37775f, 0.37865f,
+ 0.37955f, 0.38045f, 0.38136f, 0.38227f,
+ 0.38317f, 0.38409f, 0.38500f, 0.38592f,
+ 0.38684f, 0.38776f, 0.38869f, 0.38961f,
+ 0.39055f, 0.39148f, 0.39242f, 0.39335f,
+ 0.39430f, 0.39524f, 0.39619f, 0.39714f,
+ 0.39809f, 0.39904f, 0.40000f, 0.40097f,
+ 0.40193f, 0.40289f, 0.40386f, 0.40483f,
+ 0.40581f, 0.40679f, 0.40777f, 0.40875f,
+ 0.40974f, 0.41073f, 0.41172f, 0.41272f,
+ 0.41372f, 0.41472f, 0.41572f, 0.41673f,
+ 0.41774f, 0.41875f, 0.41977f, 0.42079f,
+ 0.42181f, 0.42284f, 0.42386f, 0.42490f,
+ 0.42594f, 0.42697f, 0.42801f, 0.42906f,
+ 0.43011f, 0.43116f, 0.43222f, 0.43327f,
+ 0.43434f, 0.43540f, 0.43647f, 0.43754f,
+ 0.43862f, 0.43970f, 0.44077f, 0.44186f,
+ 0.44295f, 0.44404f, 0.44514f, 0.44624f,
+ 0.44734f, 0.44845f, 0.44956f, 0.45068f,
+ 0.45179f, 0.45291f, 0.45404f, 0.45516f,
+ 0.45630f, 0.45744f, 0.45858f, 0.45972f,
+ 0.46086f, 0.46202f, 0.46318f, 0.46433f,
+ 0.46550f, 0.46667f, 0.46784f, 0.46901f,
+ 0.47019f, 0.47137f, 0.47256f, 0.47375f,
+ 0.47495f, 0.47615f, 0.47735f, 0.47856f,
+ 0.47977f, 0.48099f, 0.48222f, 0.48344f,
+ 0.48467f, 0.48590f, 0.48714f, 0.48838f,
+ 0.48963f, 0.49088f, 0.49213f, 0.49340f,
+ 0.49466f, 0.49593f, 0.49721f, 0.49849f,
+ 0.49977f, 0.50106f, 0.50236f, 0.50366f,
+ 0.50496f, 0.50627f, 0.50758f, 0.50890f,
+ 0.51023f, 0.51155f, 0.51289f, 0.51422f,
+ 0.51556f, 0.51692f, 0.51827f, 0.51964f,
+ 0.52100f, 0.52237f, 0.52374f, 0.52512f,
+ 0.52651f, 0.52790f, 0.52930f, 0.53070f,
+ 0.53212f, 0.53353f, 0.53495f, 0.53638f,
+ 0.53781f, 0.53925f, 0.54070f, 0.54214f,
+ 0.54360f, 0.54506f, 0.54653f, 0.54800f,
+ 0.54949f, 0.55098f, 0.55247f, 0.55396f,
+ 0.55548f, 0.55699f, 0.55851f, 0.56003f,
+ 0.56156f, 0.56310f, 0.56464f, 0.56621f,
+ 0.56777f, 0.56933f, 0.57091f, 0.57248f,
+ 0.57407f, 0.57568f, 0.57727f, 0.57888f,
+ 0.58050f, 0.58213f, 0.58376f, 0.58541f,
+ 0.58705f, 0.58871f, 0.59037f, 0.59204f,
+ 0.59373f, 0.59541f, 0.59712f, 0.59882f,
+ 0.60052f, 0.60226f, 0.60399f, 0.60572f,
+ 0.60748f, 0.60922f, 0.61099f, 0.61276f,
+ 0.61455f, 0.61635f, 0.61814f, 0.61996f,
+ 0.62178f, 0.62361f, 0.62545f, 0.62730f,
+ 0.62917f, 0.63104f, 0.63291f, 0.63480f,
+ 0.63671f, 0.63862f, 0.64054f, 0.64249f,
+ 0.64443f, 0.64638f, 0.64835f, 0.65033f,
+ 0.65232f, 0.65433f, 0.65633f, 0.65836f,
+ 0.66041f, 0.66245f, 0.66452f, 0.66660f,
+ 0.66868f, 0.67078f, 0.67290f, 0.67503f,
+ 0.67717f, 0.67932f, 0.68151f, 0.68368f,
+ 0.68587f, 0.68809f, 0.69033f, 0.69257f,
+ 0.69482f, 0.69709f, 0.69939f, 0.70169f,
+ 0.70402f, 0.70634f, 0.70869f, 0.71107f,
+ 0.71346f, 0.71587f, 0.71829f, 0.72073f,
+ 0.72320f, 0.72567f, 0.72818f, 0.73069f,
+ 0.73323f, 0.73579f, 0.73838f, 0.74098f,
+ 0.74360f, 0.74622f, 0.74890f, 0.75159f,
+ 0.75429f, 0.75704f, 0.75979f, 0.76257f,
+ 0.76537f, 0.76821f, 0.77109f, 0.77396f,
+ 0.77688f, 0.77982f, 0.78278f, 0.78579f,
+ 0.78883f, 0.79187f, 0.79498f, 0.79809f,
+ 0.80127f, 0.80445f, 0.80767f, 0.81095f,
+ 0.81424f, 0.81757f, 0.82094f, 0.82438f,
+ 0.82782f, 0.83133f, 0.83488f, 0.83847f,
+ 0.84210f, 0.84577f, 0.84951f, 0.85328f,
+ 0.85713f, 0.86103f, 0.86499f, 0.86900f,
+ 0.87306f, 0.87720f, 0.88139f, 0.88566f,
+ 0.89000f, 0.89442f, 0.89891f, 0.90350f,
+ 0.90818f, 0.91295f, 0.91780f, 0.92272f,
+ 0.92780f, 0.93299f, 0.93828f, 0.94369f,
+ 0.94926f, 0.95493f, 0.96082f, 0.96684f,
+ 0.97305f, 0.97943f, 0.98605f, 0.99291f,
+ 1.00000f
+ };
+
+ const uint32 kTableSize = sizeof (kTable ) /
+ sizeof (kTable [0]);
+
+ real32 y = (real32) x * (real32) (kTableSize - 1);
+
+ int32 index = Pin_int32 (0, (int32) y, kTableSize - 2);
+
+ real32 fract = y - (real32) index;
+
+ return kTable [index ] * (1.0f - fract) +
+ kTable [index + 1] * ( fract);
+
+ }
+
+/*****************************************************************************/
+
+const dng_1d_function & dng_tone_curve_acr3_default::Get ()
+ {
+
+ static dng_tone_curve_acr3_default static_dng_tone_curve_acr3_default;
+
+ return static_dng_tone_curve_acr3_default;
+
+ }
+
+/*****************************************************************************/
+
+class dng_render_task: public dng_filter_task
+ {
+
+ protected:
+
+ const dng_negative &fNegative;
+
+ const dng_render &fParams;
+
+ dng_point fSrcOffset;
+
+ dng_vector fCameraWhite;
+ dng_matrix fCameraToRGB;
+
+ AutoPtr<dng_hue_sat_map> fHueSatMap;
+
+ dng_1d_table fExposureRamp;
+
+ AutoPtr<dng_hue_sat_map> fLookTable;
+
+ dng_1d_table fToneCurve;
+
+ dng_matrix fRGBtoFinal;
+
+ dng_1d_table fEncodeGamma;
+
+ AutoPtr<dng_1d_table> fHueSatMapEncode;
+ AutoPtr<dng_1d_table> fHueSatMapDecode;
+
+ AutoPtr<dng_1d_table> fLookTableEncode;
+ AutoPtr<dng_1d_table> fLookTableDecode;
+
+ AutoPtr<dng_memory_block> fTempBuffer [kMaxMPThreads];
+
+ public:
+
+ dng_render_task (const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_negative &negative,
+ const dng_render &params,
+ const dng_point &srcOffset);
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea);
+
+ virtual void Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer);
+
+ virtual void ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer);
+
+ };
+
+/*****************************************************************************/
+
+dng_render_task::dng_render_task (const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_negative &negative,
+ const dng_render &params,
+ const dng_point &srcOffset)
+
+ : dng_filter_task (srcImage,
+ dstImage)
+
+ , fNegative (negative )
+ , fParams (params )
+ , fSrcOffset (srcOffset)
+
+ , fCameraWhite ()
+ , fCameraToRGB ()
+
+ , fHueSatMap ()
+
+ , fExposureRamp ()
+
+ , fLookTable ()
+
+ , fToneCurve ()
+
+ , fRGBtoFinal ()
+
+ , fEncodeGamma ()
+
+ , fHueSatMapEncode ()
+ , fHueSatMapDecode ()
+
+ , fLookTableEncode ()
+ , fLookTableDecode ()
+
+ {
+
+ fSrcPixelType = ttFloat;
+ fDstPixelType = ttFloat;
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_render_task::SrcArea (const dng_rect &dstArea)
+ {
+
+ return dstArea + fSrcOffset;
+
+ }
+
+/*****************************************************************************/
+
+void dng_render_task::Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer)
+ {
+
+ dng_filter_task::Start (threadCount,
+ tileSize,
+ allocator,
+ sniffer);
+
+ // Compute camera space to linear ProPhoto RGB parameters.
+
+ dng_camera_profile_id profileID; // Default profile ID.
+
+ if (!fNegative.IsMonochrome ())
+ {
+
+ AutoPtr<dng_color_spec> spec (fNegative.MakeColorSpec (profileID));
+
+ if (fParams.WhiteXY ().IsValid ())
+ {
+
+ spec->SetWhiteXY (fParams.WhiteXY ());
+
+ }
+
+ else if (fNegative.HasCameraNeutral ())
+ {
+
+ spec->SetWhiteXY (spec->NeutralToXY (fNegative.CameraNeutral ()));
+
+ }
+
+ else if (fNegative.HasCameraWhiteXY ())
+ {
+
+ spec->SetWhiteXY (fNegative.CameraWhiteXY ());
+
+ }
+
+ else
+ {
+
+ spec->SetWhiteXY (D55_xy_coord ());
+
+ }
+
+ fCameraWhite = spec->CameraWhite ();
+
+ fCameraToRGB = dng_space_ProPhoto::Get ().MatrixFromPCS () *
+ spec->CameraToPCS ();
+
+ // Find Hue/Sat table, if any.
+
+ const dng_camera_profile *profile = fNegative.ProfileByID (profileID);
+
+ if (profile)
+ {
+
+ fHueSatMap.Reset (profile->HueSatMapForWhite (spec->WhiteXY ()));
+
+ if (profile->HasLookTable ())
+ {
+
+ fLookTable.Reset (new dng_hue_sat_map (profile->LookTable ()));
+
+ }
+
+ if (profile->HueSatMapEncoding () != encoding_Linear)
+ {
+
+ BuildHueSatMapEncodingTable (*allocator,
+ profile->HueSatMapEncoding (),
+ fHueSatMapEncode,
+ fHueSatMapDecode,
+ false);
+
+ }
+
+ if (profile->LookTableEncoding () != encoding_Linear)
+ {
+
+ BuildHueSatMapEncodingTable (*allocator,
+ profile->LookTableEncoding (),
+ fLookTableEncode,
+ fLookTableDecode,
+ false);
+
+ }
+
+ }
+
+ }
+
+ // Compute exposure/shadows ramp.
+
+ real64 exposure = fParams.Exposure () +
+ fNegative.TotalBaselineExposure (profileID) -
+ (log (fNegative.Stage3Gain ()) / log (2.0));
+
+ {
+
+ real64 white = 1.0 / pow (2.0, Max_real64 (0.0, exposure));
+
+ real64 black = fParams.Shadows () *
+ fNegative.ShadowScale () *
+ fNegative.Stage3Gain () *
+ 0.001;
+
+ black = Min_real64 (black, 0.99 * white);
+
+ dng_function_exposure_ramp rampFunction (white,
+ black,
+ black);
+
+ fExposureRamp.Initialize (*allocator, rampFunction);
+
+ }
+
+ // Compute tone curve.
+
+ {
+
+ // If there is any negative exposure compenation to perform
+ // (beyond what the camera provides for with its baseline exposure),
+ // we fake this by darkening the tone curve.
+
+ dng_function_exposure_tone exposureTone (exposure);
+
+ dng_1d_concatenate totalTone (exposureTone,
+ fParams.ToneCurve ());
+
+ fToneCurve.Initialize (*allocator, totalTone);
+
+ }
+
+ // Compute linear ProPhoto RGB to final space parameters.
+
+ {
+
+ const dng_color_space &finalSpace = fParams.FinalSpace ();
+
+ fRGBtoFinal = finalSpace.MatrixFromPCS () *
+ dng_space_ProPhoto::Get ().MatrixToPCS ();
+
+ fEncodeGamma.Initialize (*allocator, finalSpace.GammaFunction ());
+
+ }
+
+ // Allocate temp buffer to hold one row of RGB data.
+
+ uint32 tempBufferSize = tileSize.h * (uint32) sizeof (real32) * 3;
+
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
+ fTempBuffer [threadIndex] . Reset (allocator->Allocate (tempBufferSize));
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_render_task::ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer)
+ {
+
+ dng_rect srcArea = srcBuffer.fArea;
+ dng_rect dstArea = dstBuffer.fArea;
+
+ uint32 srcCols = srcArea.W ();
+
+ real32 *tPtrR = fTempBuffer [threadIndex]->Buffer_real32 ();
+
+ real32 *tPtrG = tPtrR + srcCols;
+ real32 *tPtrB = tPtrG + srcCols;
+
+ for (int32 srcRow = srcArea.t; srcRow < srcArea.b; srcRow++)
+ {
+
+ // First convert from camera native space to linear PhotoRGB,
+ // applying the white balance and camera profile.
+
+ {
+
+ const real32 *sPtrA = (const real32 *)
+ srcBuffer.ConstPixel (srcRow,
+ srcArea.l,
+ 0);
+
+ if (fSrcPlanes == 1)
+ {
+
+ // For monochrome cameras, this just requires copying
+ // the data into all three color channels.
+
+ DoCopyBytes (sPtrA, tPtrR, srcCols * (uint32) sizeof (real32));
+ DoCopyBytes (sPtrA, tPtrG, srcCols * (uint32) sizeof (real32));
+ DoCopyBytes (sPtrA, tPtrB, srcCols * (uint32) sizeof (real32));
+
+ }
+
+ else
+ {
+
+ const real32 *sPtrB = sPtrA + srcBuffer.fPlaneStep;
+ const real32 *sPtrC = sPtrB + srcBuffer.fPlaneStep;
+
+ if (fSrcPlanes == 3)
+ {
+
+ DoBaselineABCtoRGB (sPtrA,
+ sPtrB,
+ sPtrC,
+ tPtrR,
+ tPtrG,
+ tPtrB,
+ srcCols,
+ fCameraWhite,
+ fCameraToRGB);
+
+ }
+
+ else
+ {
+
+ const real32 *sPtrD = sPtrC + srcBuffer.fPlaneStep;
+
+ DoBaselineABCDtoRGB (sPtrA,
+ sPtrB,
+ sPtrC,
+ sPtrD,
+ tPtrR,
+ tPtrG,
+ tPtrB,
+ srcCols,
+ fCameraWhite,
+ fCameraToRGB);
+
+ }
+
+ // Apply Hue/Sat map, if any.
+
+ if (fHueSatMap.Get ())
+ {
+
+ DoBaselineHueSatMap (tPtrR,
+ tPtrG,
+ tPtrB,
+ tPtrR,
+ tPtrG,
+ tPtrB,
+ srcCols,
+ *fHueSatMap.Get (),
+ fHueSatMapEncode.Get (),
+ fHueSatMapDecode.Get ());
+
+ }
+
+ }
+
+ }
+
+ // Apply exposure curve.
+
+ DoBaseline1DTable (tPtrR,
+ tPtrR,
+ srcCols,
+ fExposureRamp);
+
+ DoBaseline1DTable (tPtrG,
+ tPtrG,
+ srcCols,
+ fExposureRamp);
+
+ DoBaseline1DTable (tPtrB,
+ tPtrB,
+ srcCols,
+ fExposureRamp);
+
+ // Apply look table, if any.
+
+ if (fLookTable.Get ())
+ {
+
+ DoBaselineHueSatMap (tPtrR,
+ tPtrG,
+ tPtrB,
+ tPtrR,
+ tPtrG,
+ tPtrB,
+ srcCols,
+ *fLookTable.Get (),
+ fLookTableEncode.Get (),
+ fLookTableDecode.Get ());
+
+ }
+
+ // Apply baseline tone curve.
+
+ DoBaselineRGBTone (tPtrR,
+ tPtrG,
+ tPtrB,
+ tPtrR,
+ tPtrG,
+ tPtrB,
+ srcCols,
+ fToneCurve);
+
+ // Convert to final color space.
+
+ int32 dstRow = srcRow + (dstArea.t - srcArea.t);
+
+ if (fDstPlanes == 1)
+ {
+
+ real32 *dPtrG = dstBuffer.DirtyPixel_real32 (dstRow,
+ dstArea.l,
+ 0);
+
+ DoBaselineRGBtoGray (tPtrR,
+ tPtrG,
+ tPtrB,
+ dPtrG,
+ srcCols,
+ fRGBtoFinal);
+
+ DoBaseline1DTable (dPtrG,
+ dPtrG,
+ srcCols,
+ fEncodeGamma);
+
+ }
+
+ else
+ {
+
+ real32 *dPtrR = dstBuffer.DirtyPixel_real32 (dstRow,
+ dstArea.l,
+ 0);
+
+ real32 *dPtrG = dPtrR + dstBuffer.fPlaneStep;
+ real32 *dPtrB = dPtrG + dstBuffer.fPlaneStep;
+
+ DoBaselineRGBtoRGB (tPtrR,
+ tPtrG,
+ tPtrB,
+ dPtrR,
+ dPtrG,
+ dPtrB,
+ srcCols,
+ fRGBtoFinal);
+
+ DoBaseline1DTable (dPtrR,
+ dPtrR,
+ srcCols,
+ fEncodeGamma);
+
+ DoBaseline1DTable (dPtrG,
+ dPtrG,
+ srcCols,
+ fEncodeGamma);
+
+ DoBaseline1DTable (dPtrB,
+ dPtrB,
+ srcCols,
+ fEncodeGamma);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_render::dng_render (dng_host &host,
+ const dng_negative &negative)
+
+ : fHost (host)
+ , fNegative (negative)
+
+ , fWhiteXY ()
+
+ , fExposure (0.0)
+ , fShadows (5.0)
+
+ , fToneCurve (&dng_tone_curve_acr3_default::Get ())
+
+ , fFinalSpace (&dng_space_sRGB::Get ())
+ , fFinalPixelType (ttByte)
+
+ , fMaximumSize (0)
+
+ , fProfileToneCurve ()
+
+ {
+
+ // Switch to NOP default parameters for non-scene referred data.
+
+ if (fNegative.ColorimetricReference () != crSceneReferred)
+ {
+
+ fShadows = 0.0;
+
+ fToneCurve = &dng_1d_identity::Get ();
+
+ }
+
+ // Use default tone curve from profile if any.
+
+ const dng_camera_profile *profile = fNegative.ProfileByID (dng_camera_profile_id ());
+
+ if (profile && profile->ToneCurve ().IsValid ())
+ {
+
+ fProfileToneCurve.Reset (new dng_spline_solver);
+
+ profile->ToneCurve ().Solve (*fProfileToneCurve.Get ());
+
+ fToneCurve = fProfileToneCurve.Get ();
+
+ }
+
+ // Turn off default shadow mapping if requested by profile.
+
+ if (profile && (profile->DefaultBlackRender () == defaultBlackRender_None))
+ {
+
+ fShadows = 0.0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_image * dng_render::Render ()
+ {
+
+ const dng_image *srcImage = fNegative.Stage3Image ();
+
+ dng_rect srcBounds = fNegative.DefaultCropArea ();
+
+ dng_point dstSize;
+
+ dstSize.h = fNegative.DefaultFinalWidth ();
+ dstSize.v = fNegative.DefaultFinalHeight ();
+
+ if (MaximumSize ())
+ {
+
+ if (Max_uint32 (dstSize.h, dstSize.v) > MaximumSize ())
+ {
+
+ real64 ratio = fNegative.AspectRatio ();
+
+ if (ratio >= 1.0)
+ {
+ dstSize.h = MaximumSize ();
+ dstSize.v = Max_uint32 (1, Round_uint32 (dstSize.h / ratio));
+ }
+
+ else
+ {
+ dstSize.v = MaximumSize ();
+ dstSize.h = Max_uint32 (1, Round_uint32 (dstSize.v * ratio));
+ }
+
+ }
+
+ }
+
+ AutoPtr<dng_image> tempImage;
+
+ if (srcBounds.Size () != dstSize)
+ {
+
+ tempImage.Reset (fHost.Make_dng_image (dstSize,
+ srcImage->Planes (),
+ srcImage->PixelType ()));
+
+ ResampleImage (fHost,
+ *srcImage,
+ *tempImage.Get (),
+ srcBounds,
+ tempImage->Bounds (),
+ dng_resample_bicubic::Get ());
+
+ srcImage = tempImage.Get ();
+
+ srcBounds = tempImage->Bounds ();
+
+ }
+
+ uint32 dstPlanes = FinalSpace ().IsMonochrome () ? 1 : 3;
+
+ AutoPtr<dng_image> dstImage (fHost.Make_dng_image (srcBounds.Size (),
+ dstPlanes,
+ FinalPixelType ()));
+
+ dng_render_task task (*srcImage,
+ *dstImage.Get (),
+ fNegative,
+ *this,
+ srcBounds.TL ());
+
+ fHost.PerformAreaTask (task,
+ dstImage->Bounds ());
+
+ return dstImage.Release ();
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_render.h b/gpr/source/lib/dng_sdk/dng_render.h
new file mode 100644
index 0000000..4c9aec7
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_render.h
@@ -0,0 +1,312 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_render.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Classes for conversion of RAW data to final image.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_render__
+#define __dng_render__
+
+/*****************************************************************************/
+
+#include "dng_1d_function.h"
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_spline.h"
+#include "dng_xy_coord.h"
+
+/******************************************************************************/
+
+/// \brief Curve for pre-exposure-compensation adjustment based on noise floor,
+/// shadows, and highlight level.
+
+class dng_function_exposure_ramp: public dng_1d_function
+ {
+
+ public:
+
+ real64 fSlope; // Slope of straight segment.
+
+ real64 fBlack; // Intercept of straight segment.
+
+ real64 fRadius; // Rounding radius.
+
+ real64 fQScale; // Quadradic scale.
+
+ public:
+
+ dng_function_exposure_ramp (real64 white,
+ real64 black,
+ real64 minBlack);
+
+ virtual real64 Evaluate (real64 x) const;
+
+ };
+
+/******************************************************************************/
+
+/// \brief Exposure compensation curve for a given compensation amount in stops using
+/// quadric for roll-off.
+
+class dng_function_exposure_tone: public dng_1d_function
+ {
+
+ protected:
+
+ bool fIsNOP; // Is this a NOP function?
+
+ real64 fSlope; // Slope for lower part of curve.
+
+ real64 a; // Quadradic parameters for upper two f-stops.
+ real64 b;
+ real64 c;
+
+ public:
+
+ dng_function_exposure_tone (real64 exposure);
+
+ /// Returns output value for a given input tone.
+
+ virtual real64 Evaluate (real64 x) const;
+
+ };
+
+/*****************************************************************************/
+
+/// Default ACR3 tone curve.
+
+class dng_tone_curve_acr3_default: public dng_1d_function
+ {
+
+ public:
+
+ /// Returns output value for a given input tone.
+
+ virtual real64 Evaluate (real64 x) const;
+
+ /// Returns nearest input value for a given output tone.
+
+ virtual real64 EvaluateInverse (real64 x) const;
+
+ static const dng_1d_function & Get ();
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Encoding gamma curve for a given color space.
+
+class dng_function_gamma_encode: public dng_1d_function
+ {
+
+ protected:
+
+ const dng_color_space &fSpace;
+
+ public:
+
+ dng_function_gamma_encode (const dng_color_space &space);
+
+ virtual real64 Evaluate (real64 x) const;
+
+ };
+
+/*****************************************************************************/
+
+/// \brief Class used to render digital negative to displayable image.
+
+class dng_render
+ {
+
+ protected:
+
+ dng_host &fHost;
+
+ const dng_negative &fNegative;
+
+ dng_xy_coord fWhiteXY;
+
+ real64 fExposure;
+
+ real64 fShadows;
+
+ const dng_1d_function *fToneCurve;
+
+ const dng_color_space *fFinalSpace;
+
+ uint32 fFinalPixelType;
+
+ uint32 fMaximumSize;
+
+ private:
+
+ AutoPtr<dng_spline_solver> fProfileToneCurve;
+
+ public:
+
+ /// Construct a rendering instance that will be used to convert a given digital negative.
+ /// \param host The host to use for memory allocation, progress updates, and abort testing.
+ /// \param negative The digital negative to convert to a displayable image.
+
+ dng_render (dng_host &host,
+ const dng_negative &negative);
+
+ virtual ~dng_render ()
+ {
+ }
+
+ /// Set the white point to be used for conversion.
+ /// \param white White point to use.
+
+ void SetWhiteXY (const dng_xy_coord &white)
+ {
+ fWhiteXY = white;
+ }
+
+ /// Get the white point to be used for conversion.
+ /// \retval White point to use.
+
+ const dng_xy_coord WhiteXY () const
+ {
+ return fWhiteXY;
+ }
+
+ /// Set exposure compensation.
+ /// \param exposure Compensation value in stops, positive or negative.
+
+ void SetExposure (real64 exposure)
+ {
+ fExposure = exposure;
+ }
+
+ /// Get exposure compensation.
+ /// \retval Compensation value in stops, positive or negative.
+
+ real64 Exposure () const
+ {
+ return fExposure;
+ }
+
+ /// Set shadow clip amount.
+ /// \param shadows Shadow clip amount.
+
+ void SetShadows (real64 shadows)
+ {
+ fShadows = shadows;
+ }
+
+ /// Get shadow clip amount.
+ /// \retval Shadow clip amount.
+
+ real64 Shadows () const
+ {
+ return fShadows;
+ }
+
+ /// Set custom tone curve for conversion.
+ /// \param curve 1D function that defines tone mapping to use during conversion.
+
+ void SetToneCurve (const dng_1d_function &curve)
+ {
+ fToneCurve = &curve;
+ }
+
+ /// Get custom tone curve for conversion.
+ /// \retval 1D function that defines tone mapping to use during conversion.
+
+ const dng_1d_function & ToneCurve () const
+ {
+ return *fToneCurve;
+ }
+
+ /// Set final color space in which resulting image data should be represented.
+ /// (See dng_color_space.h for possible values.)
+ /// \param space Color space to use.
+
+ void SetFinalSpace (const dng_color_space &space)
+ {
+ fFinalSpace = &space;
+ }
+
+ /// Get final color space in which resulting image data should be represented.
+ /// \retval Color space to use.
+
+ const dng_color_space & FinalSpace () const
+ {
+ return *fFinalSpace;
+ }
+
+ /// Set pixel type of final image data.
+ /// Can be ttByte (default), ttShort, or ttFloat.
+ /// \param type Pixel type to use.
+
+ void SetFinalPixelType (uint32 type)
+ {
+ fFinalPixelType = type;
+ }
+
+ /// Get pixel type of final image data.
+ /// Can be ttByte (default), ttShort, or ttFloat.
+ /// \retval Pixel type to use.
+
+ uint32 FinalPixelType () const
+ {
+ return fFinalPixelType;
+ }
+
+ /// Set maximum dimension, in pixels, of resulting image.
+ /// If final image would have either dimension larger than maximum, the larger
+ /// of the two dimensions is set to this maximum size and the smaller dimension
+ /// is adjusted to preserve aspect ratio.
+ /// \param size Maximum size to allow.
+
+ void SetMaximumSize (uint32 size)
+ {
+ fMaximumSize = size;
+ }
+
+ /// Get maximum dimension, in pixels, of resulting image.
+ /// If the final image would have either dimension larger than this maximum, the larger
+ /// of the two dimensions is set to this maximum size and the smaller dimension
+ /// is adjusted to preserve the image's aspect ratio.
+ /// \retval Maximum allowed size.
+
+ uint32 MaximumSize () const
+ {
+ return fMaximumSize;
+ }
+
+ /// Actually render a digital negative to a displayable image.
+ /// Input digital negative is passed to the constructor of this dng_render class.
+ /// \retval The final resulting image.
+
+ virtual dng_image * Render ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_render (const dng_render &render);
+
+ dng_render & operator= (const dng_render &render);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_resample.cpp b/gpr/source/lib/dng_sdk/dng_resample.cpp
new file mode 100644
index 0000000..5a06465
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_resample.cpp
@@ -0,0 +1,781 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_resample.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_resample.h"
+
+#include "dng_assertions.h"
+#include "dng_bottlenecks.h"
+#include "dng_filter_task.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_memory.h"
+#include "dng_pixel_buffer.h"
+#include "dng_tag_types.h"
+#include "dng_utils.h"
+
+/******************************************************************************/
+
+real64 dng_resample_bicubic::Extent () const
+ {
+
+ return 2.0;
+
+ }
+
+/******************************************************************************/
+
+real64 dng_resample_bicubic::Evaluate (real64 x) const
+ {
+
+ const real64 A = -0.75;
+
+ x = Abs_real64 (x);
+
+ if (x >= 2.0)
+ return 0.0;
+
+ else if (x >= 1.0)
+ return (((A * x - 5.0 * A) * x + 8.0 * A) * x - 4.0 * A);
+
+ else
+ return (((A + 2.0) * x - (A + 3.0)) * x * x + 1.0);
+
+ }
+
+/******************************************************************************/
+
+const dng_resample_function & dng_resample_bicubic::Get ()
+ {
+
+ static dng_resample_bicubic static_dng_resample_bicubic;
+
+ return static_dng_resample_bicubic;
+
+ }
+
+/*****************************************************************************/
+
+dng_resample_coords::dng_resample_coords ()
+
+ : fOrigin (0)
+ , fCoords ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_resample_coords::~dng_resample_coords ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_resample_coords::Initialize (int32 srcOrigin,
+ int32 dstOrigin,
+ uint32 srcCount,
+ uint32 dstCount,
+ dng_memory_allocator &allocator)
+ {
+
+ fOrigin = dstOrigin;
+
+ uint32 dstEntries = RoundUp8 (dstCount);
+
+ fCoords.Reset (allocator.Allocate (dstEntries * (uint32) sizeof (int32)));
+
+ int32 *coords = fCoords->Buffer_int32 ();
+
+ real64 invScale = (real64) srcCount /
+ (real64) dstCount;
+
+ for (uint32 j = 0; j < dstCount; j++)
+ {
+
+ real64 x = (real64) j + 0.5;
+
+ real64 y = x * invScale - 0.5 + (real64) srcOrigin;
+
+ coords [j] = Round_int32 (y * (real64) kResampleSubsampleCount);
+
+ }
+
+ // Pad out table by replicating last entry.
+
+ for (uint32 k = dstCount; k < dstEntries; k++)
+ {
+
+ coords [k] = coords [dstCount - 1];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_resample_weights::dng_resample_weights ()
+
+ : fRadius (0)
+
+ , fWeightStep (0)
+
+ , fWeights32 ()
+ , fWeights16 ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_resample_weights::~dng_resample_weights ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_resample_weights::Initialize (real64 scale,
+ const dng_resample_function &kernel,
+ dng_memory_allocator &allocator)
+ {
+
+ uint32 j;
+
+ // We only adjust the kernel size for scale factors less than 1.0.
+
+ scale = Min_real64 (scale, 1.0);
+
+ // Find radius of this kernel.
+
+ fRadius = (uint32) (kernel.Extent () / scale + 0.9999);
+
+ // Width is twice the radius.
+
+ uint32 width = fRadius * 2;
+
+ // Round to each set to weights to a multiple of 8 entries.
+
+ fWeightStep = RoundUp8 (width);
+
+ // Allocate and zero weight tables.
+
+ fWeights32.Reset (allocator.Allocate (fWeightStep *
+ kResampleSubsampleCount *
+ (uint32) sizeof (real32)));
+
+ DoZeroBytes (fWeights32->Buffer (),
+ fWeights32->LogicalSize ());
+
+ fWeights16.Reset (allocator.Allocate (fWeightStep *
+ kResampleSubsampleCount *
+ (uint32) sizeof (int16)));
+
+ DoZeroBytes (fWeights16->Buffer (),
+ fWeights16->LogicalSize ());
+
+ // Compute kernel for each subsample values.
+
+ for (uint32 sample = 0; sample < kResampleSubsampleCount; sample++)
+ {
+
+ real64 fract = sample * (1.0 / (real64) kResampleSubsampleCount);
+
+ real32 *w32 = fWeights32->Buffer_real32 () + fWeightStep * sample;
+
+ // Evaluate kernel function for 32 bit weights.
+
+ {
+
+ real64 t32 = 0.0;
+
+ for (j = 0; j < width; j++)
+ {
+
+ int32 k = j - fRadius + 1;
+
+ real64 x = (k - fract) * scale;
+
+ w32 [j] = (real32) kernel.Evaluate (x);
+
+ t32 += w32 [j];
+
+ }
+
+ // Scale 32 bit weights so total of weights is 1.0.
+
+ real32 s32 = (real32) (1.0 / t32);
+
+ for (j = 0; j < width; j++)
+ {
+
+ w32 [j] *= s32;
+
+ }
+
+ }
+
+ // Round off 32 bit weights to 16 bit weights.
+
+ {
+
+ int16 *w16 = fWeights16->Buffer_int16 () + fWeightStep * sample;
+
+ int32 t16 = 0;
+
+ for (j = 0; j < width; j++)
+ {
+
+ w16 [j] = (int16) Round_int32 (w32 [j] * 16384.0);
+
+ t16 += w16 [j];
+
+ }
+
+ // Adjust center entry for any round off error so total is
+ // exactly 16384.
+
+ w16 [fRadius - (fract >= 0.5 ? 0 : 1)] += (int16) (16384 - t16);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_resample_weights_2d::dng_resample_weights_2d ()
+
+ : fRadius (0)
+
+ , fRowStep (0)
+ , fColStep (0)
+
+ , fWeights32 ()
+ , fWeights16 ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_resample_weights_2d::~dng_resample_weights_2d ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_resample_weights_2d::Initialize (const dng_resample_function &kernel,
+ dng_memory_allocator &allocator)
+ {
+
+ // Find radius of this kernel. Unlike with 1d resample weights (see
+ // dng_resample_weights), we never scale up the kernel size.
+
+ fRadius = (uint32) (kernel.Extent () + 0.9999);
+
+ // Width is twice the radius.
+
+ const uint32 width = fRadius * 2;
+ const uint32 widthSqr = width * width;
+
+ const uint32 step = RoundUp8 (width * width);
+
+ fRowStep = step * kResampleSubsampleCount2D;
+ fColStep = step;
+
+ // Allocate and zero weight tables.
+
+ fWeights32.Reset (allocator.Allocate (step *
+ kResampleSubsampleCount2D *
+ kResampleSubsampleCount2D *
+ (uint32) sizeof (real32)));
+
+ DoZeroBytes (fWeights32->Buffer (),
+ fWeights32->LogicalSize ());
+
+ fWeights16.Reset (allocator.Allocate (step *
+ kResampleSubsampleCount2D *
+ kResampleSubsampleCount2D *
+ (uint32) sizeof (int16)));
+
+ DoZeroBytes (fWeights16->Buffer (),
+ fWeights16->LogicalSize ());
+
+ // Compute kernel for each subsample values.
+
+ for (uint32 y = 0; y < kResampleSubsampleCount2D; y++)
+ {
+
+ real64 yFract = y * (1.0 / (real64) kResampleSubsampleCount2D);
+
+ for (uint32 x = 0; x < kResampleSubsampleCount2D; x++)
+ {
+
+ real64 xFract = x * (1.0 / (real64) kResampleSubsampleCount2D);
+
+ real32 *w32 = (real32 *) Weights32 (dng_point ((int32) y,
+ (int32) x));
+
+ // Evaluate kernel function for 32 bit weights.
+
+ {
+
+ real64 t32 = 0.0;
+
+ uint32 index = 0;
+
+ for (uint32 i = 0; i < width; i++)
+ {
+
+ int32 yInt = ((int32) i) - fRadius + 1;
+ real64 yPos = yInt - yFract;
+
+ for (uint32 j = 0; j < width; j++)
+ {
+
+ int32 xInt = ((int32) j) - fRadius + 1;
+ real64 xPos = xInt - xFract;
+
+ #if 0
+
+ // Radial.
+
+ real64 dy2 = yPos * yPos;
+ real64 dx2 = xPos * xPos;
+
+ real64 r = sqrt (dx2 + dy2);
+
+ w32 [index] = (real32) kernel.Evaluate (r);
+
+ #else
+
+ // Separable.
+
+ w32 [index] = (real32) kernel.Evaluate (xPos) *
+ (real32) kernel.Evaluate (yPos);
+
+ #endif
+
+ t32 += w32 [index];
+
+ index++;
+
+ }
+
+ }
+
+ // Scale 32 bit weights so total of weights is 1.0.
+
+ const real32 s32 = (real32) (1.0 / t32);
+
+ for (uint32 i = 0; i < widthSqr; i++)
+ {
+
+ w32 [i] *= s32;
+
+ }
+
+ }
+
+ // Round off 32 bit weights to 16 bit weights.
+
+ {
+
+ int16 *w16 = (int16 *) Weights16 (dng_point ((int32) y,
+ (int32) x));
+
+ int32 t16 = 0;
+
+ for (uint32 j = 0; j < widthSqr; j++)
+ {
+
+ w16 [j] = (int16) Round_int32 (w32 [j] * 16384.0);
+
+ t16 += w16 [j];
+
+ }
+
+ // Adjust one of the center entries for any round off error so total
+ // is exactly 16384.
+
+ const uint32 xOffset = fRadius - ((xFract >= 0.5) ? 0 : 1);
+ const uint32 yOffset = fRadius - ((yFract >= 0.5) ? 0 : 1);
+ const uint32 centerOffset = width * yOffset + xOffset;
+
+ w16 [centerOffset] += (int16) (16384 - t16);
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_resample_task: public dng_filter_task
+ {
+
+ protected:
+
+ dng_rect fSrcBounds;
+ dng_rect fDstBounds;
+
+ const dng_resample_function &fKernel;
+
+ real64 fRowScale;
+ real64 fColScale;
+
+ dng_resample_coords fRowCoords;
+ dng_resample_coords fColCoords;
+
+ dng_resample_weights fWeightsV;
+ dng_resample_weights fWeightsH;
+
+ dng_point fSrcTileSize;
+
+ AutoPtr<dng_memory_block> fTempBuffer [kMaxMPThreads];
+
+ public:
+
+ dng_resample_task (const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_rect &srcBounds,
+ const dng_rect &dstBounds,
+ const dng_resample_function &kernel);
+
+ virtual dng_rect SrcArea (const dng_rect &dstArea);
+
+ virtual dng_point SrcTileSize (const dng_point &dstTileSize);
+
+ virtual void Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer);
+
+ virtual void ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer);
+
+ };
+
+/*****************************************************************************/
+
+dng_resample_task::dng_resample_task (const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_rect &srcBounds,
+ const dng_rect &dstBounds,
+ const dng_resample_function &kernel)
+
+ : dng_filter_task (srcImage,
+ dstImage)
+
+ , fSrcBounds (srcBounds)
+ , fDstBounds (dstBounds)
+
+ , fKernel (kernel)
+
+ , fRowScale (dstBounds.H () / (real64) srcBounds.H ())
+ , fColScale (dstBounds.W () / (real64) srcBounds.W ())
+
+ , fRowCoords ()
+ , fColCoords ()
+
+ , fWeightsV ()
+ , fWeightsH ()
+
+ , fSrcTileSize ()
+
+ {
+
+ if (srcImage.PixelSize () <= 2 &&
+ dstImage.PixelSize () <= 2 &&
+ srcImage.PixelRange () == dstImage.PixelRange ())
+ {
+ fSrcPixelType = ttShort;
+ fDstPixelType = ttShort;
+ }
+
+ else
+ {
+ fSrcPixelType = ttFloat;
+ fDstPixelType = ttFloat;
+ }
+
+ fUnitCell = dng_point (8, 8);
+
+ fMaxTileSize.v = Pin_int32 (fUnitCell.v,
+ Round_int32 (fMaxTileSize.v * fRowScale),
+ fMaxTileSize.v);
+
+ fMaxTileSize.h = Pin_int32 (fUnitCell.h,
+ Round_int32 (fMaxTileSize.h * fColScale),
+ fMaxTileSize.h);
+
+ }
+
+/*****************************************************************************/
+
+dng_rect dng_resample_task::SrcArea (const dng_rect &dstArea)
+ {
+
+ int32 offsetV = fWeightsV.Offset ();
+ int32 offsetH = fWeightsH.Offset ();
+
+ uint32 widthV = fWeightsV.Width ();
+ uint32 widthH = fWeightsH.Width ();
+
+ dng_rect srcArea;
+
+ srcArea.t = fRowCoords.Pixel (dstArea.t) + offsetV;
+ srcArea.l = fColCoords.Pixel (dstArea.l) + offsetH;
+
+ srcArea.b = fRowCoords.Pixel (dstArea.b - 1) + offsetV + widthV;
+ srcArea.r = fColCoords.Pixel (dstArea.r - 1) + offsetH + widthH;
+
+ return srcArea;
+
+ }
+
+/*****************************************************************************/
+
+dng_point dng_resample_task::SrcTileSize (const dng_point & /* dstTileSize */)
+ {
+
+ return fSrcTileSize;
+
+ }
+
+/*****************************************************************************/
+
+void dng_resample_task::Start (uint32 threadCount,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer *sniffer)
+ {
+
+ // Compute sub-pixel resolution coordinates in the source image for
+ // each row and column of the destination area.
+
+ fRowCoords.Initialize (fSrcBounds.t,
+ fDstBounds.t,
+ fSrcBounds.H (),
+ fDstBounds.H (),
+ *allocator);
+
+ fColCoords.Initialize (fSrcBounds.l,
+ fDstBounds.l,
+ fSrcBounds.W (),
+ fDstBounds.W (),
+ *allocator);
+
+ // Compute resampling kernels.
+
+ fWeightsV.Initialize (fRowScale,
+ fKernel,
+ *allocator);
+
+ fWeightsH.Initialize (fColScale,
+ fKernel,
+ *allocator);
+
+ // Find upper bound on source source tile.
+
+ fSrcTileSize.v = Round_int32 (tileSize.v / fRowScale) + fWeightsV.Width () + 2;
+ fSrcTileSize.h = Round_int32 (tileSize.h / fColScale) + fWeightsH.Width () + 2;
+
+ // Allocate temp buffers.
+
+ uint32 tempBufferSize = RoundUp8 (fSrcTileSize.h) * (uint32) sizeof (real32);
+
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
+ fTempBuffer [threadIndex] . Reset (allocator->Allocate (tempBufferSize));
+
+ }
+
+ // Allocate the pixel buffers.
+
+ dng_filter_task::Start (threadCount,
+ tileSize,
+ allocator,
+ sniffer);
+
+ }
+
+/*****************************************************************************/
+
+void dng_resample_task::ProcessArea (uint32 threadIndex,
+ dng_pixel_buffer &srcBuffer,
+ dng_pixel_buffer &dstBuffer)
+ {
+
+ dng_rect srcArea = srcBuffer.fArea;
+ dng_rect dstArea = dstBuffer.fArea;
+
+ uint32 srcCols = srcArea.W ();
+ uint32 dstCols = dstArea.W ();
+
+ uint32 widthV = fWeightsV.Width ();
+ uint32 widthH = fWeightsH.Width ();
+
+ int32 offsetV = fWeightsV.Offset ();
+ int32 offsetH = fWeightsH.Offset ();
+
+ uint32 stepH = fWeightsH.Step ();
+
+ const int32 *rowCoords = fRowCoords.Coords (0 );
+ const int32 *colCoords = fColCoords.Coords (dstArea.l);
+
+ if (fSrcPixelType == ttFloat)
+ {
+
+ const real32 *weightsH = fWeightsH.Weights32 (0);
+
+ real32 *tPtr = fTempBuffer [threadIndex]->Buffer_real32 ();
+
+ real32 *ttPtr = tPtr + offsetH - srcArea.l;
+
+ for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
+ {
+
+ int32 rowCoord = rowCoords [dstRow];
+
+ int32 rowFract = rowCoord & kResampleSubsampleMask;
+
+ const real32 *weightsV = fWeightsV.Weights32 (rowFract);
+
+ int32 srcRow = (rowCoord >> kResampleSubsampleBits) + offsetV;
+
+ for (uint32 plane = 0; plane < dstBuffer.fPlanes; plane++)
+ {
+
+ const real32 *sPtr = srcBuffer.ConstPixel_real32 (srcRow,
+ srcArea.l,
+ plane);
+
+ DoResampleDown32 (sPtr,
+ tPtr,
+ srcCols,
+ srcBuffer.fRowStep,
+ weightsV,
+ widthV);
+
+ real32 *dPtr = dstBuffer.DirtyPixel_real32 (dstRow,
+ dstArea.l,
+ plane);
+
+ DoResampleAcross32 (ttPtr,
+ dPtr,
+ dstCols,
+ colCoords,
+ weightsH,
+ widthH,
+ stepH);
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ const int16 *weightsH = fWeightsH.Weights16 (0);
+
+ uint16 *tPtr = fTempBuffer [threadIndex]->Buffer_uint16 ();
+
+ uint16 *ttPtr = tPtr + offsetH - srcArea.l;
+
+ uint32 pixelRange = fDstImage.PixelRange ();
+
+ for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
+ {
+
+ int32 rowCoord = rowCoords [dstRow];
+
+ int32 rowFract = rowCoord & kResampleSubsampleMask;
+
+ const int16 *weightsV = fWeightsV.Weights16 (rowFract);
+
+ int32 srcRow = (rowCoord >> kResampleSubsampleBits) + offsetV;
+
+ for (uint32 plane = 0; plane < dstBuffer.fPlanes; plane++)
+ {
+
+ const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (srcRow,
+ srcArea.l,
+ plane);
+
+ DoResampleDown16 (sPtr,
+ tPtr,
+ srcCols,
+ srcBuffer.fRowStep,
+ weightsV,
+ widthV,
+ pixelRange);
+
+ uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow,
+ dstArea.l,
+ plane);
+
+ DoResampleAcross16 (ttPtr,
+ dPtr,
+ dstCols,
+ colCoords,
+ weightsH,
+ widthH,
+ stepH,
+ pixelRange);
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void ResampleImage (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_rect &srcBounds,
+ const dng_rect &dstBounds,
+ const dng_resample_function &kernel)
+ {
+
+ dng_resample_task task (srcImage,
+ dstImage,
+ srcBounds,
+ dstBounds,
+ kernel);
+
+ host.PerformAreaTask (task,
+ dstBounds);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_resample.h b/gpr/source/lib/dng_sdk/dng_resample.h
new file mode 100644
index 0000000..c6bc6f9
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_resample.h
@@ -0,0 +1,261 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_resample.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_resample__
+#define __dng_resample__
+
+/*****************************************************************************/
+
+#include "dng_assertions.h"
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_memory.h"
+#include "dng_point.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_resample_function
+ {
+
+ public:
+
+ dng_resample_function ()
+ {
+ }
+
+ virtual ~dng_resample_function ()
+ {
+ }
+
+ virtual real64 Extent () const = 0;
+
+ virtual real64 Evaluate (real64 x) const = 0;
+
+ };
+
+/*****************************************************************************/
+
+class dng_resample_bicubic: public dng_resample_function
+ {
+
+ public:
+
+ virtual real64 Extent () const;
+
+ virtual real64 Evaluate (real64 x) const;
+
+ static const dng_resample_function & Get ();
+
+ };
+
+/******************************************************************************/
+
+const uint32 kResampleSubsampleBits = 7;
+const uint32 kResampleSubsampleCount = 1 << kResampleSubsampleBits;
+const uint32 kResampleSubsampleMask = kResampleSubsampleCount - 1;
+
+/*****************************************************************************/
+
+class dng_resample_coords
+ {
+
+ protected:
+
+ int32 fOrigin;
+
+ AutoPtr<dng_memory_block> fCoords;
+
+ public:
+
+ dng_resample_coords ();
+
+ virtual ~dng_resample_coords ();
+
+ void Initialize (int32 srcOrigin,
+ int32 dstOrigin,
+ uint32 srcCount,
+ uint32 dstCount,
+ dng_memory_allocator &allocator);
+
+ const int32 * Coords (int32 index) const
+ {
+ return fCoords->Buffer_int32 () + (index - fOrigin);
+ }
+
+ int32 Pixel (int32 index) const
+ {
+ return Coords (index) [0] >> kResampleSubsampleBits;
+ }
+
+ };
+
+/*****************************************************************************/
+
+class dng_resample_weights
+ {
+
+ protected:
+
+ uint32 fRadius;
+
+ uint32 fWeightStep;
+
+ AutoPtr<dng_memory_block> fWeights32;
+ AutoPtr<dng_memory_block> fWeights16;
+
+ public:
+
+ dng_resample_weights ();
+
+ virtual ~dng_resample_weights ();
+
+ void Initialize (real64 scale,
+ const dng_resample_function &kernel,
+ dng_memory_allocator &allocator);
+
+ uint32 Radius () const
+ {
+ return fRadius;
+ }
+
+ uint32 Width () const
+ {
+ return fRadius * 2;
+ }
+
+ int32 Offset () const
+ {
+ return 1 - (int32) fRadius;
+ }
+
+ uint32 Step () const
+ {
+ return fWeightStep;
+ }
+
+ const real32 *Weights32 (uint32 fract) const
+ {
+
+ DNG_ASSERT (fWeights32->Buffer (), "Weights32 is NULL");
+
+ return fWeights32->Buffer_real32 () + fract * fWeightStep;
+
+ }
+
+ const int16 *Weights16 (uint32 fract) const
+ {
+
+ DNG_ASSERT (fWeights16->Buffer (), "Weights16 is NULL");
+
+ return fWeights16->Buffer_int16 () + fract * fWeightStep;
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+const uint32 kResampleSubsampleBits2D = 5;
+const uint32 kResampleSubsampleCount2D = 1 << kResampleSubsampleBits2D;
+const uint32 kResampleSubsampleMask2D = kResampleSubsampleCount2D - 1;
+
+/*****************************************************************************/
+
+class dng_resample_weights_2d
+ {
+
+ protected:
+
+ uint32 fRadius;
+
+ uint32 fRowStep;
+ uint32 fColStep;
+
+ AutoPtr<dng_memory_block> fWeights32;
+ AutoPtr<dng_memory_block> fWeights16;
+
+ public:
+
+ dng_resample_weights_2d ();
+
+ virtual ~dng_resample_weights_2d ();
+
+ void Initialize (const dng_resample_function &kernel,
+ dng_memory_allocator &allocator);
+
+ uint32 Radius () const
+ {
+ return fRadius;
+ }
+
+ uint32 Width () const
+ {
+ return fRadius * 2;
+ }
+
+ int32 Offset () const
+ {
+ return 1 - (int32) fRadius;
+ }
+
+ uint32 RowStep () const
+ {
+ return fRowStep;
+ }
+
+ uint32 ColStep () const
+ {
+ return fColStep;
+ }
+
+ const real32 *Weights32 (dng_point fract) const
+ {
+
+ DNG_ASSERT (fWeights32->Buffer (), "Weights32 is NULL");
+
+ const uint32 offset = fract.v * fRowStep + fract.h * fColStep;
+
+ return fWeights32->Buffer_real32 () + offset;
+
+ }
+
+ const int16 *Weights16 (dng_point fract) const
+ {
+
+ DNG_ASSERT (fWeights16->Buffer (), "Weights16 is NULL");
+
+ const uint32 offset = fract.v * fRowStep + fract.h * fColStep;
+
+ return fWeights16->Buffer_int16 () + offset;
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+void ResampleImage (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const dng_rect &srcBounds,
+ const dng_rect &dstBounds,
+ const dng_resample_function &kernel);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_sdk.py b/gpr/source/lib/dng_sdk/dng_sdk.py
new file mode 100755
index 0000000..48d6a23
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_sdk.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+
+# --- Initialization - setup paths
+import sys
+import os
+sys.path.append( os.path.normpath(os.path.join(__file__, "..")) + '/../../SCRIPTS' )
+
+from commonlib import *
+
+gyp_build_object = {
+
+ "targets": [
+
+ {
+ "target_name": "dng_sdk",
+
+ "type": "static_library",
+
+ 'include_dirs': [
+ ],
+
+ 'defines': [ '<@(default_defines)', 'qDNGXMPFiles=0', 'qDNGXMPDocOps=0' ],
+
+ "includes": [
+ "../xmp_sdk/xmp_sdk.gypi",
+ ],
+
+ "sources": [
+
+ "./dng_validate.cpp" ,
+
+ "./dng_1d_function.cpp" ,
+ "./dng_1d_function.h" ,
+ "./dng_1d_table.cpp" ,
+ "./dng_1d_table.h" ,
+ "./dng_abort_sniffer.cpp" ,
+ "./dng_abort_sniffer.h" ,
+ "./dng_area_task.cpp" ,
+ "./dng_area_task.h" ,
+ "./dng_assertions.h" ,
+ "./dng_auto_ptr.h" ,
+ "./dng_bad_pixels.cpp" ,
+ "./dng_bad_pixels.h" ,
+ "./dng_bottlenecks.cpp" ,
+ "./dng_bottlenecks.h" ,
+ "./dng_camera_profile.cpp" ,
+ "./dng_camera_profile.h" ,
+ "./dng_classes.h" ,
+ "./dng_color_space.cpp" ,
+ "./dng_color_space.h" ,
+ "./dng_color_spec.cpp" ,
+ "./dng_color_spec.h" ,
+ "./dng_date_time.cpp" ,
+ "./dng_date_time.h" ,
+ "./dng_errors.h" ,
+ "./dng_exceptions.cpp" ,
+ "./dng_exceptions.h" ,
+ "./dng_exif.cpp" ,
+ "./dng_exif.h" ,
+ "./dng_fast_module.h" ,
+ "./dng_file_stream.cpp" ,
+ "./dng_file_stream.h" ,
+ "./dng_filter_task.cpp" ,
+ "./dng_filter_task.h" ,
+ "./dng_fingerprint.cpp" ,
+ "./dng_fingerprint.h" ,
+ "./dng_flags.h" ,
+ "./dng_gain_map.cpp" ,
+ "./dng_gain_map.h" ,
+ "./dng_globals.cpp" ,
+ "./dng_globals.h" ,
+ "./dng_host.cpp" ,
+ "./dng_host.h" ,
+ "./dng_hue_sat_map.cpp" ,
+ "./dng_hue_sat_map.h" ,
+ "./dng_ifd.cpp" ,
+ "./dng_ifd.h" ,
+ "./dng_image.cpp" ,
+ "./dng_image.h" ,
+ "./dng_image_writer.cpp" ,
+ "./dng_image_writer.h" ,
+ "./dng_info.cpp" ,
+ "./dng_info.h" ,
+ "./dng_iptc.cpp" ,
+ "./dng_iptc.h" ,
+ "./dng_jpeg_image.cpp" ,
+ "./dng_jpeg_image.h" ,
+ "./dng_lens_correction.cpp" ,
+ "./dng_lens_correction.h" ,
+ "./dng_linearization_info.cpp" ,
+ "./dng_linearization_info.h" ,
+ "./dng_lossless_jpeg.cpp" ,
+ "./dng_lossless_jpeg.h" ,
+ "./dng_matrix.cpp" ,
+ "./dng_matrix.h" ,
+ "./dng_memory.cpp" ,
+ "./dng_memory.h" ,
+ "./dng_memory_stream.cpp" ,
+ "./dng_memory_stream.h" ,
+ "./dng_misc_opcodes.cpp" ,
+ "./dng_misc_opcodes.h" ,
+ "./dng_mosaic_info.cpp" ,
+ "./dng_mosaic_info.h" ,
+ "./dng_mutex.cpp" ,
+ "./dng_mutex.h" ,
+ "./dng_negative.cpp" ,
+ "./dng_negative.h" ,
+ "./dng_opcode_list.cpp" ,
+ "./dng_opcode_list.h" ,
+ "./dng_opcodes.cpp" ,
+ "./dng_opcodes.h" ,
+ "./dng_orientation.cpp" ,
+ "./dng_orientation.h" ,
+ "./dng_parse_utils.cpp" ,
+ "./dng_parse_utils.h" ,
+ "./dng_pixel_buffer.cpp" ,
+ "./dng_pixel_buffer.h" ,
+ "./dng_point.cpp" ,
+ "./dng_point.h" ,
+ "./dng_preview.cpp" ,
+ "./dng_preview.h" ,
+ "./dng_pthread.cpp" ,
+ "./dng_pthread.h" ,
+ "./dng_rational.cpp" ,
+ "./dng_rational.h" ,
+ "./dng_read_image.cpp" ,
+ "./dng_read_image.h" ,
+ "./dng_rect.cpp" ,
+ "./dng_rect.h" ,
+ "./dng_ref_counted_block.cpp" ,
+ "./dng_ref_counted_block.h" ,
+ "./dng_reference.cpp" ,
+ "./dng_reference.h" ,
+ "./dng_render.cpp" ,
+ "./dng_render.h" ,
+ "./dng_resample.cpp" ,
+ "./dng_resample.h" ,
+ "./dng_sdk_limits.h" ,
+ "./dng_shared.cpp" ,
+ "./dng_shared.h" ,
+ "./dng_simple_image.cpp" ,
+ "./dng_simple_image.h" ,
+ "./dng_spline.cpp" ,
+ "./dng_spline.h" ,
+ "./dng_stream.cpp" ,
+ "./dng_stream.h" ,
+ "./dng_string.cpp" ,
+ "./dng_string.h" ,
+ "./dng_string_list.cpp" ,
+ "./dng_string_list.h" ,
+ "./dng_tag_codes.h" ,
+ "./dng_tag_types.cpp" ,
+ "./dng_tag_types.h" ,
+ "./dng_tag_values.h" ,
+ "./dng_temperature.cpp" ,
+ "./dng_temperature.h" ,
+ "./dng_tile_iterator.cpp" ,
+ "./dng_tile_iterator.h" ,
+ "./dng_tone_curve.cpp" ,
+ "./dng_tone_curve.h" ,
+ "./dng_types.h" ,
+ "./dng_uncopyable.h" ,
+ "./dng_utils.cpp" ,
+ "./dng_utils.h" ,
+ "./dng_xmp.cpp" ,
+ "./dng_xmp.h" ,
+ "./dng_xmp_sdk.cpp" ,
+ "./dng_xmp_sdk.h" ,
+ "./dng_xy_coord.cpp" ,
+ "./dng_xy_coord.h" ,
+ ]
+ }
+ ]
+}
+
+from argparse import ArgumentParser
+parser = ArgumentParser(conflict_handler='resolve')
+parser.add_argument('-m', '--modules', default="all", help='Modules to include in build step', choices=["gpr_encoding", "gpr_decoding", "all"], )
+
+args = parser.parse_args()
+
+if args.modules == "gpr_encoding" or args.modules == "all":
+ gyp_build_object['targets'][0]['defines'].append( "ENABLE_GPR_ENCODING=1" )
+else:
+ gyp_build_object['targets'][0]['defines'].append( "ENABLE_GPR_ENCODING=0" )
+
+if args.modules == "gpr_decoding" or args.modules == "all":
+ gyp_build_object['targets'][0]['defines'].append( "ENABLE_GPR_DECODING=1" )
+else:
+ gyp_build_object['targets'][0]['defines'].append( "ENABLE_GPR_DECODING=0" )
+
+print( gyp_build_object ) \ No newline at end of file
diff --git a/gpr/source/lib/dng_sdk/dng_sdk_limits.h b/gpr/source/lib/dng_sdk/dng_sdk_limits.h
new file mode 100644
index 0000000..e4feed7
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_sdk_limits.h
@@ -0,0 +1,78 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_sdk_limits.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Collection of constants detailing maximum values used in processing in the DNG SDK.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_sdk_limits__
+#define __dng_sdk_limits__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+/// The maximum number of previews (in addition to the main IFD's thumbnail)
+/// that we support embedded in a DNG.
+
+const uint32 kMaxDNGPreviews = 20;
+
+/// The maximum number of SubIFDs that will be parsed.
+
+const uint32 kMaxSubIFDs = kMaxDNGPreviews + 1;
+
+/// The maximum number of chained IFDs that will be parsed.
+
+const uint32 kMaxChainedIFDs = 10;
+
+/// The maximum number of samples per pixel.
+
+const uint32 kMaxSamplesPerPixel = 4;
+
+/// Maximum number of color planes.
+
+const uint32 kMaxColorPlanes = kMaxSamplesPerPixel;
+
+/// The maximum size of a CFA repeating pattern.
+
+const uint32 kMaxCFAPattern = 8;
+
+/// The maximum size of a black level repeating pattern.
+
+const uint32 kMaxBlackPattern = 8;
+
+/// The maximum number of masked area rectangles.
+
+const uint32 kMaxMaskedAreas = 4;
+
+/// The maximum image size supported (pixels per side).
+
+const uint32 kMaxImageSide = 65000;
+
+/// Maximum number of MP threads for dng_area_task operations.
+
+#if qDNG64Bit
+const uint32 kMaxMPThreads = 32;
+#else
+const uint32 kMaxMPThreads = 8;
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_shared.cpp b/gpr/source/lib/dng_sdk/dng_shared.cpp
new file mode 100644
index 0000000..8c96c81
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_shared.cpp
@@ -0,0 +1,3289 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_shared.cpp#2 $ */
+/* $DateTime: 2012/06/14 20:24:41 $ */
+/* $Change: 835078 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_shared.h"
+
+#include "dng_camera_profile.h"
+#include "dng_exceptions.h"
+#include "dng_globals.h"
+#include "dng_parse_utils.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_camera_profile_info::dng_camera_profile_info ()
+
+ : fBigEndian (false)
+
+ , fColorPlanes (0)
+
+ , fCalibrationIlluminant1 (lsUnknown)
+ , fCalibrationIlluminant2 (lsUnknown)
+
+ , fColorMatrix1 ()
+ , fColorMatrix2 ()
+
+ , fForwardMatrix1 ()
+ , fForwardMatrix2 ()
+
+ , fReductionMatrix1 ()
+ , fReductionMatrix2 ()
+
+ , fProfileCalibrationSignature ()
+
+ , fProfileName ()
+
+ , fProfileCopyright ()
+
+ , fEmbedPolicy (pepAllowCopying)
+
+ , fProfileHues (0)
+ , fProfileSats (0)
+ , fProfileVals (0)
+
+ , fHueSatDeltas1Offset (0)
+ , fHueSatDeltas1Count (0)
+
+ , fHueSatDeltas2Offset (0)
+ , fHueSatDeltas2Count (0)
+
+ , fHueSatMapEncoding (encoding_Linear)
+
+ , fLookTableHues (0)
+ , fLookTableSats (0)
+ , fLookTableVals (0)
+
+ , fLookTableOffset (0)
+ , fLookTableCount (0)
+
+ , fLookTableEncoding (encoding_Linear)
+
+ , fBaselineExposureOffset (0, 100)
+
+ , fDefaultBlackRender (defaultBlackRender_Auto)
+
+ , fToneCurveOffset (0)
+ , fToneCurveCount (0)
+
+ , fUniqueCameraModel ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_camera_profile_info::~dng_camera_profile_info ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_camera_profile_info::ParseTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcCalibrationIlluminant1:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CalibrationIlluminant1: %s\n",
+ LookupLightSource (fCalibrationIlluminant1));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCalibrationIlluminant2:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CalibrationIlluminant2: %s\n",
+ LookupLightSource (fCalibrationIlluminant2));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcColorMatrix1:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (fColorPlanes == 0)
+ {
+
+ fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
+
+ }
+
+ if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ fColorPlanes,
+ 3,
+ fColorMatrix1))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ColorMatrix1:\n");
+
+ DumpMatrix (fColorMatrix1);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcColorMatrix2:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
+ // only have a ColorMatrix2 tag and no ColorMatrix1 tag.
+
+ bool hasselbladHack = (fColorPlanes == 0);
+
+ if (hasselbladHack)
+ {
+
+ fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
+
+ #if qDNGValidate
+
+ ReportWarning ("ColorMatrix2 without ColorMatrix1");
+
+ #endif
+
+ }
+
+ if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ fColorPlanes,
+ 3,
+ fColorMatrix2))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ColorMatrix2:\n");
+
+ DumpMatrix (fColorMatrix2);
+
+ }
+
+ #endif
+
+ if (hasselbladHack)
+ {
+
+ fColorMatrix1 = fColorMatrix2;
+
+ fColorMatrix2 = dng_matrix ();
+
+ }
+
+ break;
+
+ }
+
+ case tcForwardMatrix1:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ 3,
+ fColorPlanes,
+ fForwardMatrix1))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ForwardMatrix1:\n");
+
+ DumpMatrix (fForwardMatrix1);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcForwardMatrix2:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ 3,
+ fColorPlanes,
+ fForwardMatrix2))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ForwardMatrix2:\n");
+
+ DumpMatrix (fForwardMatrix2);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcReductionMatrix1:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ 3,
+ fColorPlanes,
+ fReductionMatrix1))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ReductionMatrix1:\n");
+
+ DumpMatrix (fReductionMatrix1);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcReductionMatrix2:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ 3,
+ fColorPlanes,
+ fReductionMatrix2))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ReductionMatrix2:\n");
+
+ DumpMatrix (fReductionMatrix2);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileCalibrationSignature:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fProfileCalibrationSignature,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileCalibrationSignature: ");
+
+ DumpString (fProfileCalibrationSignature);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileName:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fProfileName,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileName: ");
+
+ DumpString (fProfileName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileCopyright:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fProfileCopyright,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileCopyright: ");
+
+ DumpString (fProfileCopyright);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileEmbedPolicy:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fEmbedPolicy = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ const char *policy;
+
+ switch (fEmbedPolicy)
+ {
+
+ case pepAllowCopying:
+ policy = "Allow copying";
+ break;
+
+ case pepEmbedIfUsed:
+ policy = "Embed if used";
+ break;
+
+ case pepEmbedNever:
+ policy = "Embed never";
+ break;
+
+ case pepNoRestrictions:
+ policy = "No restrictions";
+ break;
+
+ default:
+ policy = "INVALID VALUE";
+
+ }
+
+ printf ("ProfileEmbedPolicy: %s\n", policy);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileHueSatMapDims:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
+
+ fProfileHues = stream.TagValue_uint32 (tagType);
+ fProfileSats = stream.TagValue_uint32 (tagType);
+
+ if (tagCount > 2)
+ fProfileVals = stream.TagValue_uint32 (tagType);
+ else
+ fProfileVals = 1;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n",
+ (unsigned) fProfileHues,
+ (unsigned) fProfileSats,
+ (unsigned) fProfileVals);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileHueSatMapData1:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
+ return false;
+
+ bool skipSat0 = (tagCount == fProfileHues *
+ (fProfileSats - 1) *
+ fProfileVals * 3);
+
+ if (!skipSat0)
+ {
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues *
+ fProfileSats *
+ fProfileVals * 3))
+ return false;
+
+ }
+
+ fBigEndian = stream.BigEndian ();
+
+ fHueSatDeltas1Offset = tagOffset;
+ fHueSatDeltas1Count = tagCount;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileHueSatMapData1:\n");
+
+ DumpHueSatMap (stream,
+ fProfileHues,
+ fProfileSats,
+ fProfileVals,
+ skipSat0);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileHueSatMapData2:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
+ return false;
+
+ bool skipSat0 = (tagCount == fProfileHues *
+ (fProfileSats - 1) *
+ fProfileVals * 3);
+
+ if (!skipSat0)
+ {
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues *
+ fProfileSats *
+ fProfileVals * 3))
+ return false;
+
+ }
+
+ fBigEndian = stream.BigEndian ();
+
+ fHueSatDeltas2Offset = tagOffset;
+ fHueSatDeltas2Count = tagCount;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileHueSatMapData2:\n");
+
+ DumpHueSatMap (stream,
+ fProfileHues,
+ fProfileSats,
+ fProfileVals,
+ skipSat0);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileHueSatMapEncoding:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fHueSatMapEncoding = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ const char *encoding = NULL;
+
+ switch (fHueSatMapEncoding)
+ {
+
+ case encoding_Linear:
+ encoding = "Linear";
+ break;
+
+ case encoding_sRGB:
+ encoding = "sRGB";
+ break;
+
+ default:
+ encoding = "INVALID VALUE";
+
+ }
+
+ printf ("ProfileHueSatMapEncoding: %s\n", encoding);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileLookTableDims:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
+
+ fLookTableHues = stream.TagValue_uint32 (tagType);
+ fLookTableSats = stream.TagValue_uint32 (tagType);
+
+ if (tagCount > 2)
+ fLookTableVals = stream.TagValue_uint32 (tagType);
+ else
+ fLookTableVals = 1;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n",
+ (unsigned) fLookTableHues,
+ (unsigned) fLookTableSats,
+ (unsigned) fLookTableVals);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileLookTableData:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
+ return false;
+
+ bool skipSat0 = (tagCount == fLookTableHues *
+ (fLookTableSats - 1) *
+ fLookTableVals * 3);
+
+ if (!skipSat0)
+ {
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, fLookTableHues *
+ fLookTableSats *
+ fLookTableVals * 3))
+ return false;
+
+ }
+
+ fBigEndian = stream.BigEndian ();
+
+ fLookTableOffset = tagOffset;
+ fLookTableCount = tagCount;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ProfileLookTableData:\n");
+
+ DumpHueSatMap (stream,
+ fLookTableHues,
+ fLookTableSats,
+ fLookTableVals,
+ skipSat0);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileLookTableEncoding:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fLookTableEncoding = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ const char *encoding = NULL;
+
+ switch (fLookTableEncoding)
+ {
+
+ case encoding_Linear:
+ encoding = "Linear";
+ break;
+
+ case encoding_sRGB:
+ encoding = "sRGB";
+ break;
+
+ default:
+ encoding = "INVALID VALUE";
+
+ }
+
+ printf ("ProfileLookTableEncoding: %s\n", encoding);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBaselineExposureOffset:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBaselineExposureOffset = stream.TagValue_srational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BaselineExposureOffset: %+0.2f\n",
+ fBaselineExposureOffset.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDefaultBlackRender:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDefaultBlackRender = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ const char *setting = NULL;
+
+ switch (fDefaultBlackRender)
+ {
+
+ case defaultBlackRender_Auto:
+ setting = "Auto";
+ break;
+
+ case defaultBlackRender_None:
+ setting = "None";
+ break;
+
+ default:
+ setting = "INVALID VALUE";
+
+ }
+
+ printf ("DefaultBlackRender: %s\n",
+ setting);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcProfileToneCurve:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount))
+ return false;
+
+ if ((tagCount & 1) != 0)
+ {
+
+ #if qDNGValidate
+
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s has odd count (%u)",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode),
+ (unsigned) tagCount);
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ return false;
+
+ }
+
+ fBigEndian = stream.BigEndian ();
+
+ fToneCurveOffset = tagOffset;
+ fToneCurveCount = tagCount;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ DumpTagValues (stream,
+ "Coord",
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount);
+
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcUniqueCameraModel:
+ {
+
+ // Note: This code is only used when parsing stand-alone
+ // profiles. The embedded profiles are assumed to be restricted
+ // to the model they are embedded in.
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fUniqueCameraModel,
+ false);
+
+ bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
+
+ #if qDNGValidate
+
+ if (didTrim)
+ {
+
+ ReportWarning ("UniqueCameraModel string has trailing blanks");
+
+ }
+
+ if (gVerbose)
+ {
+
+ printf ("UniqueCameraModel: ");
+
+ DumpString (fUniqueCameraModel);
+
+ printf ("\n");
+
+ }
+
+ #else
+
+ (void) didTrim; // Unused
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_camera_profile_info::ParseExtended (dng_stream &stream)
+ {
+
+ try
+ {
+
+ // Offsets are relative to the start of this structure, not the entire file.
+
+ uint64 startPosition = stream.Position ();
+
+ // Read header. Like a TIFF header, but with different magic number
+ // Plus all offsets are relative to the start of the IFD, not to the
+ // stream or file.
+
+ uint16 byteOrder = stream.Get_uint16 ();
+
+ if (byteOrder == byteOrderMM)
+ fBigEndian = true;
+
+ else if (byteOrder == byteOrderII)
+ fBigEndian = false;
+
+ else
+ return false;
+
+ TempBigEndian setEndianness (stream, fBigEndian);
+
+ uint16 magicNumber = stream.Get_uint16 ();
+
+ if (magicNumber != magicExtendedProfile)
+ {
+ return false;
+ }
+
+ uint32 offset = stream.Get_uint32 ();
+
+ stream.Skip (offset - 8);
+
+ // Start on IFD entries.
+
+ uint32 ifdEntries = stream.Get_uint16 ();
+
+ if (ifdEntries < 1)
+ {
+ return false;
+ }
+
+ for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
+ {
+
+ stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12);
+
+ uint16 tagCode = stream.Get_uint16 ();
+ uint32 tagType = stream.Get_uint16 ();
+ uint32 tagCount = stream.Get_uint32 ();
+
+ uint64 tagOffset = stream.Position ();
+
+ if (TagTypeSize (tagType) * tagCount > 4)
+ {
+
+ tagOffset = startPosition + stream.Get_uint32 ();
+
+ stream.SetReadPosition (tagOffset);
+
+ }
+
+ if (!ParseTag (stream,
+ 0,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ stream.SetReadPosition (tagOffset);
+
+ printf ("*");
+
+ DumpTagValues (stream,
+ LookupTagType (tagType),
+ 0,
+ tagCode,
+ tagType,
+ tagCount);
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ catch (...)
+ {
+
+ // Eat parsing errors.
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+dng_shared::dng_shared ()
+
+ : fExifIFD (0)
+ , fGPSInfo (0)
+ , fInteroperabilityIFD (0)
+ , fKodakDCRPrivateIFD (0)
+ , fKodakKDCPrivateIFD (0)
+
+ , fXMPCount (0)
+ , fXMPOffset (0)
+
+ , fIPTC_NAA_Count (0)
+ , fIPTC_NAA_Offset (0)
+
+ , fMakerNoteCount (0)
+ , fMakerNoteOffset (0)
+ , fMakerNoteSafety (0)
+
+ , fDNGVersion (0)
+ , fDNGBackwardVersion (0)
+
+ , fUniqueCameraModel ()
+ , fLocalizedCameraModel ()
+
+ , fCameraProfile ()
+
+ , fExtraCameraProfiles ()
+
+ , fCameraCalibration1 ()
+ , fCameraCalibration2 ()
+
+ , fCameraCalibrationSignature ()
+
+ , fAnalogBalance ()
+
+ , fAsShotNeutral ()
+
+ , fAsShotWhiteXY ()
+
+ , fBaselineExposure (0, 1)
+ , fBaselineNoise (1, 1)
+ , fNoiseReductionApplied (0, 0)
+ , fBaselineSharpness (1, 1)
+ , fLinearResponseLimit (1, 1)
+ , fShadowScale (1, 1)
+
+ , fHasBaselineExposure (false)
+ , fHasShadowScale (false)
+
+ , fDNGPrivateDataCount (0)
+ , fDNGPrivateDataOffset (0)
+
+ , fRawImageDigest ()
+ , fNewRawImageDigest ()
+
+ , fRawDataUniqueID ()
+
+ , fOriginalRawFileName ()
+
+ , fOriginalRawFileDataCount (0)
+ , fOriginalRawFileDataOffset (0)
+
+ , fOriginalRawFileDigest ()
+
+ , fAsShotICCProfileCount (0)
+ , fAsShotICCProfileOffset (0)
+
+ , fAsShotPreProfileMatrix ()
+
+ , fCurrentICCProfileCount (0)
+ , fCurrentICCProfileOffset (0)
+
+ , fCurrentPreProfileMatrix ()
+
+ , fColorimetricReference (crSceneReferred)
+
+ , fAsShotProfileName ()
+
+ , fNoiseProfile ()
+
+ , fOriginalDefaultFinalSize ()
+ , fOriginalBestQualityFinalSize ()
+
+ , fOriginalDefaultCropSizeH ()
+ , fOriginalDefaultCropSizeV ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_shared::~dng_shared ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_shared::ParseTag (dng_stream &stream,
+ dng_exif &exif,
+ uint32 parentCode,
+ bool /* isMainIFD */,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset,
+ int64 /* offsetDelta */)
+ {
+
+ if (parentCode == 0)
+ {
+
+ if (Parse_ifd0 (stream,
+ exif,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ if (parentCode == 0 ||
+ parentCode == tcExifIFD)
+ {
+
+ if (Parse_ifd0_exif (stream,
+ exif,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in IFD 0.
+
+bool dng_shared::Parse_ifd0 (dng_stream &stream,
+ dng_exif & /* exif */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcXMP:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined);
+
+ fXMPCount = tagCount;
+ fXMPOffset = fXMPCount ? tagOffset : 0;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("XMP: Count = %u, Offset = %u\n",
+ (unsigned) fXMPCount,
+ (unsigned) fXMPOffset);
+
+ if (fXMPCount)
+ {
+
+ DumpXMP (stream, fXMPCount);
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcIPTC_NAA:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined);
+
+ fIPTC_NAA_Count = tagCount * TagTypeSize (tagType);
+ fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("IPTC/NAA: Count = %u, Offset = %u\n",
+ (unsigned) fIPTC_NAA_Count,
+ (unsigned) fIPTC_NAA_Offset);
+
+ if (fIPTC_NAA_Count)
+ {
+
+ DumpHexAscii (stream, fIPTC_NAA_Count);
+
+ }
+
+ // Compute and output the digest.
+
+ dng_memory_data buffer (fIPTC_NAA_Count);
+
+ stream.SetReadPosition (fIPTC_NAA_Offset);
+
+ stream.Get (buffer.Buffer (), fIPTC_NAA_Count);
+
+ const uint8 *data = buffer.Buffer_uint8 ();
+
+ uint32 count = fIPTC_NAA_Count;
+
+ // Method 1: Counting all bytes (this is correct).
+
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (data, count);
+
+ printf ("IPTCDigest: ");
+
+ DumpFingerprint (printer.Result ());
+
+ printf ("\n");
+
+ }
+
+ // Method 2: Ignoring zero padding.
+
+ {
+
+ uint32 removed = 0;
+
+ while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
+ {
+ removed++;
+ count--;
+ }
+
+ if (removed != 0)
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (data, count);
+
+ printf ("IPTCDigest (ignoring zero padding): ");
+
+ DumpFingerprint (printer.Result ());
+
+ printf ("\n");
+
+ }
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExifIFD:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fExifIFD = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("ExifIFD: %u\n", (unsigned) fExifIFD);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcGPSInfo:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fGPSInfo = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("GPSInfo: %u\n", (unsigned) fGPSInfo);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcKodakDCRPrivateIFD:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcKodakKDCPrivateIFD:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDNGVersion:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("DNGVersion: %u.%u.%u.%u\n",
+ (unsigned) b0,
+ (unsigned) b1,
+ (unsigned) b2,
+ (unsigned) b3);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDNGBackwardVersion:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 4);
+
+ uint32 b0 = stream.Get_uint8 ();
+ uint32 b1 = stream.Get_uint8 ();
+ uint32 b2 = stream.Get_uint8 ();
+ uint32 b3 = stream.Get_uint8 ();
+
+ fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("DNGBackwardVersion: %u.%u.%u.%u\n",
+ (unsigned) b0,
+ (unsigned) b1,
+ (unsigned) b2,
+ (unsigned) b3);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcUniqueCameraModel:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fUniqueCameraModel,
+ false);
+
+ bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
+
+ #if qDNGValidate
+
+ if (didTrim)
+ {
+
+ ReportWarning ("UniqueCameraModel string has trailing blanks");
+
+ }
+
+ if (gVerbose)
+ {
+
+ printf ("UniqueCameraModel: ");
+
+ DumpString (fUniqueCameraModel);
+
+ printf ("\n");
+
+ }
+
+ #else
+
+ (void) didTrim; // Unused
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLocalizedCameraModel:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fLocalizedCameraModel,
+ false);
+
+ bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks ();
+
+ #if qDNGValidate
+
+ if (didTrim)
+ {
+
+ ReportWarning ("LocalizedCameraModel string has trailing blanks");
+
+ }
+
+ if (gVerbose)
+ {
+
+ printf ("LocalizedCameraModel: ");
+
+ DumpString (fLocalizedCameraModel);
+
+ printf ("\n");
+
+ }
+
+ #else
+
+ (void) didTrim; // Unused
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraCalibration1:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ fCameraProfile.fColorPlanes,
+ fCameraProfile.fColorPlanes,
+ fCameraCalibration1))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CameraCalibration1:\n");
+
+ DumpMatrix (fCameraCalibration1);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraCalibration2:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ fCameraProfile.fColorPlanes,
+ fCameraProfile.fColorPlanes,
+ fCameraCalibration2))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CameraCalibration2:\n");
+
+ DumpMatrix (fCameraCalibration2);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraCalibrationSignature:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fCameraCalibrationSignature,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CameraCalibrationSignature: ");
+
+ DumpString (fCameraCalibrationSignature);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAnalogBalance:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
+ // they don't have any ColorMatrix tags.
+
+ bool hasselbladHack = (fDNGVersion == 0 &&
+ fCameraProfile.fColorPlanes == 0);
+
+ if (hasselbladHack)
+ {
+
+ fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
+
+ #if qDNGValidate
+
+ ReportWarning ("AnalogBalance without ColorMatrix1");
+
+ #endif
+
+ }
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ if (!ParseVectorTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ fCameraProfile.fColorPlanes,
+ fAnalogBalance))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AnalogBalance:");
+
+ DumpVector (fAnalogBalance);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAsShotNeutral:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
+ // they don't have any ColorMatrix tags.
+
+ bool hasselbladHack = (fDNGVersion == 0 &&
+ fCameraProfile.fColorPlanes == 0);
+
+ if (hasselbladHack)
+ {
+
+ fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
+
+ #if qDNGValidate
+
+ ReportWarning ("AsShotNeutral without ColorMatrix1");
+
+ #endif
+
+ }
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ if (!ParseVectorTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ fCameraProfile.fColorPlanes,
+ fAsShotNeutral))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AsShotNeutral:");
+
+ DumpVector (fAsShotNeutral);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAsShotWhiteXY:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fAsShotWhiteXY.x = stream.TagValue_real64 (tagType);
+ fAsShotWhiteXY.y = stream.TagValue_real64 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AsShotWhiteXY: %0.4f %0.4f\n",
+ fAsShotWhiteXY.x,
+ fAsShotWhiteXY.y);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBaselineExposure:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBaselineExposure = stream.TagValue_srational (tagType);
+
+ fHasBaselineExposure = true;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BaselineExposure: %+0.2f\n",
+ fBaselineExposure.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBaselineNoise:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBaselineNoise = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BaselineNoise: %0.2f\n",
+ fBaselineNoise.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcNoiseReductionApplied:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
+ return false;
+
+ fNoiseReductionApplied = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("NoiseReductionApplied: %u/%u\n",
+ (unsigned) fNoiseReductionApplied.n,
+ (unsigned) fNoiseReductionApplied.d);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcNoiseProfile:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttDouble))
+ return false;
+
+ // Must be an even, positive number of doubles in a noise profile.
+
+ if (!tagCount || (tagCount & 1))
+ return false;
+
+ // Determine number of planes (i.e., half the number of doubles).
+
+ const uint32 numPlanes = Pin_uint32 (0,
+ tagCount >> 1,
+ kMaxColorPlanes);
+
+ // Parse the noise function parameters.
+
+ std::vector<dng_noise_function> noiseFunctions;
+
+ for (uint32 i = 0; i < numPlanes; i++)
+ {
+
+ const real64 scale = stream.TagValue_real64 (tagType);
+ const real64 offset = stream.TagValue_real64 (tagType);
+
+ noiseFunctions.push_back (dng_noise_function (scale, offset));
+
+ }
+
+ // Store the noise profile.
+
+ fNoiseProfile = dng_noise_profile (noiseFunctions);
+
+ // Debug.
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("NoiseProfile:\n");
+
+ printf (" Planes: %u\n", (unsigned) numPlanes);
+
+ for (uint32 plane = 0; plane < numPlanes; plane++)
+ {
+
+ printf (" Noise function for plane %u: scale = %.8lf, offset = %.8lf\n",
+ (unsigned) plane,
+ noiseFunctions [plane].Scale (),
+ noiseFunctions [plane].Offset ());
+
+ }
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBaselineSharpness:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBaselineSharpness = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BaselineSharpness: %0.2f\n",
+ fBaselineSharpness.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcLinearResponseLimit:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fLinearResponseLimit = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("LinearResponseLimit: %0.2f\n",
+ fLinearResponseLimit.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcShadowScale:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fShadowScale = stream.TagValue_urational (tagType);
+
+ fHasShadowScale = true;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ShadowScale: %0.4f\n",
+ fShadowScale.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDNGPrivateData:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttByte);
+
+ fDNGPrivateDataCount = tagCount;
+ fDNGPrivateDataOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DNGPrivateData: Count = %u, Offset = %u\n",
+ (unsigned) fDNGPrivateDataCount,
+ (unsigned) fDNGPrivateDataOffset);
+
+ DumpHexAscii (stream, tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcMakerNoteSafety:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fMakerNoteSafety = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("MakerNoteSafety: %s\n",
+ LookupMakerNoteSafety (fMakerNoteSafety));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRawImageDigest:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
+ return false;
+
+ stream.Get (fRawImageDigest.data, 16);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("RawImageDigest: ");
+
+ DumpFingerprint (fRawImageDigest);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcNewRawImageDigest:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
+ return false;
+
+ stream.Get (fNewRawImageDigest.data, 16);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("NewRawImageDigest: ");
+
+ DumpFingerprint (fNewRawImageDigest);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcRawDataUniqueID:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
+ return false;
+
+ stream.Get (fRawDataUniqueID.data, 16);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("RawDataUniqueID: ");
+
+ DumpFingerprint (fRawDataUniqueID);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOriginalRawFileName:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fOriginalRawFileName,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OriginalRawFileName: ");
+
+ DumpString (fOriginalRawFileName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOriginalRawFileData:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fOriginalRawFileDataCount = tagCount;
+ fOriginalRawFileDataOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OriginalRawFileData: Count = %u, Offset = %u\n",
+ (unsigned) fOriginalRawFileDataCount,
+ (unsigned) fOriginalRawFileDataOffset);
+
+ DumpHexAscii (stream, tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOriginalRawFileDigest:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
+ return false;
+
+ stream.Get (fOriginalRawFileDigest.data, 16);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OriginalRawFileDigest: ");
+
+ DumpFingerprint (fOriginalRawFileDigest);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAsShotICCProfile:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fAsShotICCProfileCount = tagCount;
+ fAsShotICCProfileOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AsShotICCProfile: Count = %u, Offset = %u\n",
+ (unsigned) fAsShotICCProfileCount,
+ (unsigned) fAsShotICCProfileOffset);
+
+ DumpHexAscii (stream, tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAsShotPreProfileMatrix:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ uint32 rows = fCameraProfile.fColorPlanes;
+
+ if (tagCount == fCameraProfile.fColorPlanes * 3)
+ {
+ rows = 3;
+ }
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ rows,
+ fCameraProfile.fColorPlanes,
+ fAsShotPreProfileMatrix))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AsShotPreProfileMatrix:\n");
+
+ DumpMatrix (fAsShotPreProfileMatrix);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCurrentICCProfile:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fCurrentICCProfileCount = tagCount;
+ fCurrentICCProfileOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CurrentICCProfile: Count = %u, Offset = %u\n",
+ (unsigned) fCurrentICCProfileCount,
+ (unsigned) fCurrentICCProfileOffset);
+
+ DumpHexAscii (stream, tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCurrentPreProfileMatrix:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
+ return false;
+
+ uint32 rows = fCameraProfile.fColorPlanes;
+
+ if (tagCount == fCameraProfile.fColorPlanes * 3)
+ {
+ rows = 3;
+ }
+
+ if (!ParseMatrixTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ rows,
+ fCameraProfile.fColorPlanes,
+ fCurrentPreProfileMatrix))
+ return false;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CurrentPreProfileMatrix:\n");
+
+ DumpMatrix (fCurrentPreProfileMatrix);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcColorimetricReference:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fColorimetricReference = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ColorimetricReference: %s\n",
+ LookupColorimetricReference (fColorimetricReference));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcExtraCameraProfiles:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount);
+
+ }
+
+ #endif
+
+ fExtraCameraProfiles.reserve (tagCount);
+
+ for (uint32 index = 0; index < tagCount; index++)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index);
+
+ }
+
+ #endif
+
+ stream.SetReadPosition (tagOffset + index * 4);
+
+ uint32 profileOffset = stream.TagValue_uint32 (tagType);
+
+ dng_camera_profile_info profileInfo;
+
+ stream.SetReadPosition (profileOffset);
+
+ if (profileInfo.ParseExtended (stream))
+ {
+
+ fExtraCameraProfiles.push_back (profileInfo);
+
+ }
+
+ else
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Unable to parse extra camera profile");
+
+ #endif
+
+ }
+
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("\nDone with ExtraCameraProfiles\n\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAsShotProfileName:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fAsShotProfileName,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("AsShotProfileName: ");
+
+ DumpString (fAsShotProfileName);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOriginalDefaultFinalSize:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType);
+ fOriginalDefaultFinalSize.v = stream.TagValue_int32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OriginalDefaultFinalSize: H = %d V = %d\n",
+ (int) fOriginalDefaultFinalSize.h,
+ (int) fOriginalDefaultFinalSize.v);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOriginalBestQualityFinalSize:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType);
+ fOriginalBestQualityFinalSize.v = stream.TagValue_int32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OriginalBestQualityFinalSize: H = %d V = %d\n",
+ (int) fOriginalBestQualityFinalSize.h,
+ (int) fOriginalBestQualityFinalSize.v);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOriginalDefaultCropSize:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
+ return false;
+
+ fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType);
+ fOriginalDefaultCropSizeV = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n",
+ fOriginalDefaultCropSizeH.As_real64 (),
+ fOriginalDefaultCropSizeV.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ // The main camera profile tags also appear in IFD 0
+
+ return fCameraProfile.ParseTag (stream,
+ parentCode,
+ tagCode,
+ tagType,
+ tagCount,
+ tagOffset);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+// Parses tags that should only appear in IFD 0 or EXIF IFD.
+
+bool dng_shared::Parse_ifd0_exif (dng_stream &stream,
+ dng_exif & /* exif */,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset)
+ {
+
+ switch (tagCode)
+ {
+
+ case tcMakerNote:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+
+ fMakerNoteCount = tagCount;
+ fMakerNoteOffset = tagOffset;
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("MakerNote: Count = %u, Offset = %u\n",
+ (unsigned) fMakerNoteCount,
+ (unsigned) fMakerNoteOffset);
+
+ DumpHexAscii (stream, tagCount);
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcInteroperabilityIFD:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fInteroperabilityIFD = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD);
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ default:
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_shared::PostParse (dng_host & /* host */,
+ dng_exif & /* exif */)
+ {
+
+ // Fill in default values for DNG images.
+
+ if (fDNGVersion != 0)
+ {
+
+ // Support for DNG versions before 1.0.0.0.
+
+ if (fDNGVersion < dngVersion_1_0_0_0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("DNGVersion less than 1.0.0.0");
+
+ #endif
+
+ // The CalibrationIlluminant tags were added just before
+ // DNG version 1.0.0.0, and were hardcoded before that.
+
+ fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA;
+ fCameraProfile.fCalibrationIlluminant2 = lsD65;
+
+ fDNGVersion = dngVersion_1_0_0_0;
+
+ }
+
+ // Default value for DNGBackwardVersion tag.
+
+ if (fDNGBackwardVersion == 0)
+ {
+
+ fDNGBackwardVersion = fDNGVersion & 0xFFFF0000;
+
+ }
+
+ // Check DNGBackwardVersion value.
+
+ if (fDNGBackwardVersion < dngVersion_1_0_0_0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("DNGBackwardVersion less than 1.0.0.0");
+
+ #endif
+
+ fDNGBackwardVersion = dngVersion_1_0_0_0;
+
+ }
+
+ if (fDNGBackwardVersion > fDNGVersion)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("DNGBackwardVersion > DNGVersion");
+
+ #endif
+
+ fDNGBackwardVersion = fDNGVersion;
+
+ }
+
+ // Check UniqueCameraModel.
+
+ if (fUniqueCameraModel.IsEmpty ())
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Missing or invalid UniqueCameraModel");
+
+ #endif
+
+ fUniqueCameraModel.Set ("Digital Negative");
+
+ }
+
+ // If we don't know the color depth yet, it must be a monochrome DNG.
+
+ if (fCameraProfile.fColorPlanes == 0)
+ {
+
+ fCameraProfile.fColorPlanes = 1;
+
+ }
+
+ // Check color info.
+
+ if (fCameraProfile.fColorPlanes > 1)
+ {
+
+ // Check illuminant pair.
+
+ if (fCameraProfile.fColorMatrix2.NotEmpty ())
+ {
+
+ if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown ||
+ (fCameraProfile.fCalibrationIlluminant2 == lsUnknown ||
+ (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2)))
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid CalibrationIlluminant pair");
+
+ #endif
+
+ fCameraProfile.fColorMatrix2 = dng_matrix ();
+
+ }
+
+ }
+
+ // If the colorimetric reference is the ICC profile PCS, then the
+ // data must already be white balanced. The "AsShotWhiteXY" is required
+ // to be the ICC Profile PCS white point.
+
+ if (fColorimetricReference == crICCProfilePCS)
+ {
+
+ if (fAsShotNeutral.NotEmpty ())
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("AsShotNeutral not allowed for this "
+ "ColorimetricReference value");
+
+ #endif
+
+ fAsShotNeutral.Clear ();
+
+ }
+
+ dng_xy_coord pcs = PCStoXY ();
+
+ #if qDNGValidate
+
+ if (fAsShotWhiteXY.IsValid ())
+ {
+
+ if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 ||
+ Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01)
+ {
+
+ ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS");
+
+ }
+
+ }
+
+ #endif
+
+ fAsShotWhiteXY = pcs;
+
+ }
+
+ else
+ {
+
+ // Warn if both AsShotNeutral and AsShotWhiteXY are specified.
+
+ if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ())
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included");
+
+ #endif
+
+ fAsShotWhiteXY = dng_xy_coord ();
+
+ }
+
+ // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified.
+
+ #if qDNGValidate
+
+ if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ())
+ {
+
+ ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included",
+ "legal but not recommended");
+
+ }
+
+ #endif
+
+ }
+
+ // Default values of calibration signatures are required for legacy
+ // compatiblity.
+
+ if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA &&
+ fCameraProfile.fCalibrationIlluminant2 == lsD65 &&
+ fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes &&
+ fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes &&
+ fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes &&
+ fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes &&
+ fCameraCalibrationSignature.IsEmpty () &&
+ fCameraProfile.fProfileCalibrationSignature.IsEmpty () )
+ {
+
+ fCameraCalibrationSignature.Set (kAdobeCalibrationSignature);
+
+ fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature);
+
+ }
+
+ }
+
+ // Check BaselineNoise.
+
+ if (fBaselineNoise.As_real64 () <= 0.0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid BaselineNoise");
+
+ #endif
+
+ fBaselineNoise = dng_urational (1, 1);
+
+ }
+
+ // Check BaselineSharpness.
+
+ if (fBaselineSharpness.As_real64 () <= 0.0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid BaselineSharpness");
+
+ #endif
+
+ fBaselineSharpness = dng_urational (1, 1);
+
+ }
+
+ // Check NoiseProfile.
+
+ if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid NoiseProfile");
+
+ #endif
+
+ fNoiseProfile = dng_noise_profile ();
+
+ }
+
+ // Check LinearResponseLimit.
+
+ if (fLinearResponseLimit.As_real64 () < 0.5 ||
+ fLinearResponseLimit.As_real64 () > 1.0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid LinearResponseLimit");
+
+ #endif
+
+ fLinearResponseLimit = dng_urational (1, 1);
+
+ }
+
+ // Check ShadowScale.
+
+ if (fShadowScale.As_real64 () <= 0.0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid ShadowScale");
+
+ #endif
+
+ fShadowScale = dng_urational (1, 1);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_shared::IsValidDNG ()
+ {
+
+ // Check DNGVersion value.
+
+ if (fDNGVersion < dngVersion_1_0_0_0)
+ {
+
+ #if qDNGValidate
+
+ if (fDNGVersion != dngVersion_None)
+ {
+
+ ReportError ("Invalid DNGVersion");
+
+ }
+
+ #if qDNGValidateTarget
+
+ else
+ {
+
+ ReportError ("Missing DNGVersion");
+
+ }
+
+ #endif
+
+ #endif
+
+ return false;
+
+ }
+
+ // Check DNGBackwardVersion value.
+
+ if (fDNGBackwardVersion > dngVersion_Current)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("DNGBackwardVersion (or DNGVersion) is too high");
+
+ #endif
+
+ ThrowUnsupportedDNG ();
+
+ }
+
+ // Check color transform info.
+
+ if (fCameraProfile.fColorPlanes > 1)
+ {
+
+ // CameraCalibration1 is optional, but it must be valid if present.
+
+ if (fCameraCalibration1.Cols () != 0 ||
+ fCameraCalibration1.Rows () != 0)
+ {
+
+ if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes ||
+ fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("CameraCalibration1 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure it is invertable.
+
+ try
+ {
+
+ (void) Invert (fCameraCalibration1);
+
+ }
+
+ catch (...)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("CameraCalibration1 is not invertable");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // CameraCalibration2 is optional, but it must be valid if present.
+
+ if (fCameraCalibration2.Cols () != 0 ||
+ fCameraCalibration2.Rows () != 0)
+ {
+
+ if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes ||
+ fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("CameraCalibration2 is wrong size");
+
+ #endif
+
+ return false;
+
+ }
+
+ // Make sure it is invertable.
+
+ try
+ {
+
+ (void) Invert (fCameraCalibration2);
+
+ }
+
+ catch (...)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("CameraCalibration2 is not invertable");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ // Check analog balance
+
+ dng_matrix analogBalance;
+
+ if (fAnalogBalance.NotEmpty ())
+ {
+
+ analogBalance = fAnalogBalance.AsDiagonal ();
+
+ try
+ {
+
+ (void) Invert (analogBalance);
+
+ }
+
+ catch (...)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("AnalogBalance is not invertable");
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_shared.h b/gpr/source/lib/dng_sdk/dng_shared.h
new file mode 100644
index 0000000..b67d7a6
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_shared.h
@@ -0,0 +1,248 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_shared.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_shared__
+#define __dng_shared__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_fingerprint.h"
+#include "dng_matrix.h"
+#include "dng_negative.h"
+#include "dng_rational.h"
+#include "dng_string.h"
+#include "dng_stream.h"
+#include "dng_sdk_limits.h"
+#include "dng_types.h"
+#include "dng_xy_coord.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+class dng_camera_profile_info
+ {
+
+ public:
+
+ bool fBigEndian;
+
+ uint32 fColorPlanes;
+
+ uint32 fCalibrationIlluminant1;
+ uint32 fCalibrationIlluminant2;
+
+ dng_matrix fColorMatrix1;
+ dng_matrix fColorMatrix2;
+
+ dng_matrix fForwardMatrix1;
+ dng_matrix fForwardMatrix2;
+
+ dng_matrix fReductionMatrix1;
+ dng_matrix fReductionMatrix2;
+
+ dng_string fProfileCalibrationSignature;
+
+ dng_string fProfileName;
+
+ dng_string fProfileCopyright;
+
+ uint32 fEmbedPolicy;
+
+ uint32 fProfileHues;
+ uint32 fProfileSats;
+ uint32 fProfileVals;
+
+ uint64 fHueSatDeltas1Offset;
+ uint32 fHueSatDeltas1Count;
+
+ uint64 fHueSatDeltas2Offset;
+ uint32 fHueSatDeltas2Count;
+
+ uint32 fHueSatMapEncoding;
+
+ uint32 fLookTableHues;
+ uint32 fLookTableSats;
+ uint32 fLookTableVals;
+
+ uint64 fLookTableOffset;
+ uint32 fLookTableCount;
+
+ uint32 fLookTableEncoding;
+
+ dng_srational fBaselineExposureOffset;
+
+ uint32 fDefaultBlackRender;
+
+ uint64 fToneCurveOffset;
+ uint32 fToneCurveCount;
+
+ dng_string fUniqueCameraModel;
+
+ public:
+
+ dng_camera_profile_info ();
+
+ ~dng_camera_profile_info ();
+
+ bool ParseTag (dng_stream &stream,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ bool ParseExtended (dng_stream &stream);
+
+ };
+
+/*****************************************************************************/
+
+class dng_shared
+ {
+
+ public:
+
+ uint64 fExifIFD;
+ uint64 fGPSInfo;
+ uint64 fInteroperabilityIFD;
+ uint64 fKodakDCRPrivateIFD;
+ uint64 fKodakKDCPrivateIFD;
+
+ uint32 fXMPCount;
+ uint64 fXMPOffset;
+
+ uint32 fIPTC_NAA_Count;
+ uint64 fIPTC_NAA_Offset;
+
+ uint32 fMakerNoteCount;
+ uint64 fMakerNoteOffset;
+ uint32 fMakerNoteSafety;
+
+ uint32 fDNGVersion;
+ uint32 fDNGBackwardVersion;
+
+ dng_string fUniqueCameraModel;
+ dng_string fLocalizedCameraModel;
+
+ dng_camera_profile_info fCameraProfile;
+
+ std::vector<dng_camera_profile_info> fExtraCameraProfiles;
+
+ dng_matrix fCameraCalibration1;
+ dng_matrix fCameraCalibration2;
+
+ dng_string fCameraCalibrationSignature;
+
+ dng_vector fAnalogBalance;
+
+ dng_vector fAsShotNeutral;
+
+ dng_xy_coord fAsShotWhiteXY;
+
+ dng_srational fBaselineExposure;
+ dng_urational fBaselineNoise;
+ dng_urational fNoiseReductionApplied;
+ dng_urational fBaselineSharpness;
+ dng_urational fLinearResponseLimit;
+ dng_urational fShadowScale;
+
+ bool fHasBaselineExposure;
+ bool fHasShadowScale;
+
+ uint32 fDNGPrivateDataCount;
+ uint64 fDNGPrivateDataOffset;
+
+ dng_fingerprint fRawImageDigest;
+ dng_fingerprint fNewRawImageDigest;
+
+ dng_fingerprint fRawDataUniqueID;
+
+ dng_string fOriginalRawFileName;
+
+ uint32 fOriginalRawFileDataCount;
+ uint64 fOriginalRawFileDataOffset;
+
+ dng_fingerprint fOriginalRawFileDigest;
+
+ uint32 fAsShotICCProfileCount;
+ uint64 fAsShotICCProfileOffset;
+
+ dng_matrix fAsShotPreProfileMatrix;
+
+ uint32 fCurrentICCProfileCount;
+ uint64 fCurrentICCProfileOffset;
+
+ dng_matrix fCurrentPreProfileMatrix;
+
+ uint32 fColorimetricReference;
+
+ dng_string fAsShotProfileName;
+
+ dng_noise_profile fNoiseProfile;
+
+ dng_point fOriginalDefaultFinalSize;
+ dng_point fOriginalBestQualityFinalSize;
+
+ dng_urational fOriginalDefaultCropSizeH;
+ dng_urational fOriginalDefaultCropSizeV;
+
+ public:
+
+ dng_shared ();
+
+ virtual ~dng_shared ();
+
+ virtual bool ParseTag (dng_stream &stream,
+ dng_exif &exif,
+ uint32 parentCode,
+ bool isMainIFD,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset,
+ int64 offsetDelta);
+
+ virtual void PostParse (dng_host &host,
+ dng_exif &exif);
+
+ virtual bool IsValidDNG ();
+
+ protected:
+
+ virtual bool Parse_ifd0 (dng_stream &stream,
+ dng_exif &exif,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ virtual bool Parse_ifd0_exif (dng_stream &stream,
+ dng_exif &exif,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_simple_image.cpp b/gpr/source/lib/dng_sdk/dng_simple_image.cpp
new file mode 100644
index 0000000..03b5b59
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_simple_image.cpp
@@ -0,0 +1,197 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_simple_image.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_simple_image.h"
+
+#include "dng_memory.h"
+#include "dng_orientation.h"
+#include "dng_tag_types.h"
+
+/*****************************************************************************/
+
+dng_simple_image::dng_simple_image (const dng_rect &bounds,
+ uint32 planes,
+ uint32 pixelType,
+ dng_memory_allocator &allocator)
+
+ : dng_image (bounds,
+ planes,
+ pixelType)
+
+ , fMemory ()
+ , fBuffer ()
+ , fAllocator (allocator)
+
+ {
+
+ uint32 pixelSize = TagTypeSize (pixelType);
+
+ uint32 bytes = bounds.H () * bounds.W () * planes * pixelSize;
+
+ fMemory.Reset (allocator.Allocate (bytes));
+
+ fBuffer.fArea = bounds;
+
+ fBuffer.fPlane = 0;
+ fBuffer.fPlanes = planes;
+
+ fBuffer.fRowStep = planes * bounds.W ();
+ fBuffer.fColStep = planes;
+ fBuffer.fPlaneStep = 1;
+
+ fBuffer.fPixelType = pixelType;
+ fBuffer.fPixelSize = pixelSize;
+
+ fBuffer.fData = fMemory->Buffer ();
+
+ }
+
+/*****************************************************************************/
+
+dng_simple_image::~dng_simple_image ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_image * dng_simple_image::Clone () const
+ {
+
+ AutoPtr<dng_simple_image> result (new dng_simple_image (Bounds (),
+ Planes (),
+ PixelType (),
+ fAllocator));
+
+ result->fBuffer.CopyArea (fBuffer,
+ Bounds (),
+ 0,
+ Planes ());
+
+ return result.Release ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_simple_image::SetPixelType (uint32 pixelType)
+ {
+
+ dng_image::SetPixelType (pixelType);
+
+ fBuffer.fPixelType = pixelType;
+
+ }
+
+/*****************************************************************************/
+
+void dng_simple_image::Trim (const dng_rect &r)
+ {
+
+ fBounds.t = 0;
+ fBounds.l = 0;
+
+ fBounds.b = r.H ();
+ fBounds.r = r.W ();
+
+ fBuffer.fData = fBuffer.DirtyPixel (r.t, r.l);
+
+ fBuffer.fArea = fBounds;
+
+ }
+
+/*****************************************************************************/
+
+void dng_simple_image::Rotate (const dng_orientation &orientation)
+ {
+
+ int32 originH = fBounds.l;
+ int32 originV = fBounds.t;
+
+ int32 colStep = fBuffer.fColStep;
+ int32 rowStep = fBuffer.fRowStep;
+
+ uint32 width = fBounds.W ();
+ uint32 height = fBounds.H ();
+
+ if (orientation.FlipH ())
+ {
+
+ originH += width - 1;
+
+ colStep = -colStep;
+
+ }
+
+ if (orientation.FlipV ())
+ {
+
+ originV += height - 1;
+
+ rowStep = -rowStep;
+
+ }
+
+ if (orientation.FlipD ())
+ {
+
+ int32 temp = colStep;
+
+ colStep = rowStep;
+ rowStep = temp;
+
+ width = fBounds.H ();
+ height = fBounds.W ();
+
+ }
+
+ fBuffer.fData = fBuffer.DirtyPixel (originV, originH);
+
+ fBuffer.fColStep = colStep;
+ fBuffer.fRowStep = rowStep;
+
+ fBounds.r = fBounds.l + width;
+ fBounds.b = fBounds.t + height;
+
+ fBuffer.fArea = fBounds;
+
+ }
+
+/*****************************************************************************/
+
+void dng_simple_image::AcquireTileBuffer (dng_tile_buffer &buffer,
+ const dng_rect &area,
+ bool dirty) const
+ {
+
+ buffer.fArea = area;
+
+ buffer.fPlane = fBuffer.fPlane;
+ buffer.fPlanes = fBuffer.fPlanes;
+ buffer.fRowStep = fBuffer.fRowStep;
+ buffer.fColStep = fBuffer.fColStep;
+ buffer.fPlaneStep = fBuffer.fPlaneStep;
+ buffer.fPixelType = fBuffer.fPixelType;
+ buffer.fPixelSize = fBuffer.fPixelSize;
+
+ buffer.fData = (void *) fBuffer.ConstPixel (buffer.fArea.t,
+ buffer.fArea.l,
+ buffer.fPlane);
+
+ buffer.fDirty = dirty;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_simple_image.h b/gpr/source/lib/dng_sdk/dng_simple_image.h
new file mode 100644
index 0000000..006337d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_simple_image.h
@@ -0,0 +1,82 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_simple_image.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_simple_image__
+#define __dng_simple_image__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_image.h"
+#include "dng_pixel_buffer.h"
+
+/*****************************************************************************/
+
+/// dng_image derived class with simple Trim and Rotate functionality.
+
+class dng_simple_image : public dng_image
+ {
+
+ protected:
+
+ dng_pixel_buffer fBuffer;
+
+ AutoPtr<dng_memory_block> fMemory;
+
+ dng_memory_allocator &fAllocator;
+
+ public:
+
+ dng_simple_image (const dng_rect &bounds,
+ uint32 planes,
+ uint32 pixelType,
+ dng_memory_allocator &allocator);
+
+ virtual ~dng_simple_image ();
+
+ virtual dng_image * Clone () const;
+
+ /// Setter for pixel type.
+
+ virtual void SetPixelType (uint32 pixelType);
+
+ /// Trim image data outside of given bounds. Memory is not reallocated or freed.
+
+ virtual void Trim (const dng_rect &r);
+
+ /// Rotate image according to orientation.
+
+ virtual void Rotate (const dng_orientation &orientation);
+
+ /// Get the buffer for direct processing. (Unique to dng_simple_image.)
+
+ void GetPixelBuffer (dng_pixel_buffer &buffer)
+ {
+ buffer = fBuffer;
+ }
+
+ protected:
+
+ virtual void AcquireTileBuffer (dng_tile_buffer &buffer,
+ const dng_rect &area,
+ bool dirty) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_spline.cpp b/gpr/source/lib/dng_sdk/dng_spline.cpp
new file mode 100644
index 0000000..cd47532
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_spline.cpp
@@ -0,0 +1,233 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_spline.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_spline.h"
+
+#include "dng_assertions.h"
+#include "dng_exceptions.h"
+
+/******************************************************************************/
+
+dng_spline_solver::dng_spline_solver ()
+
+ : X ()
+ , Y ()
+ , S ()
+
+ {
+
+ }
+
+/******************************************************************************/
+
+dng_spline_solver::~dng_spline_solver ()
+ {
+
+ }
+
+/******************************************************************************/
+
+void dng_spline_solver::Reset ()
+ {
+
+ X.clear ();
+ Y.clear ();
+
+ S.clear ();
+
+ }
+
+/******************************************************************************/
+
+void dng_spline_solver::Add (real64 x, real64 y)
+ {
+
+ X.push_back (x);
+ Y.push_back (y);
+
+ }
+
+/******************************************************************************/
+
+void dng_spline_solver::Solve ()
+ {
+
+ // This code computes the unique curve such that:
+ // It is C0, C1, and C2 continuous
+ // The second derivative is zero at the end points
+
+ int32 count = (int32) X.size ();
+
+ DNG_ASSERT (count >= 2, "Too few points");
+
+ int32 start = 0;
+ int32 end = count;
+
+ real64 A = X [start+1] - X [start];
+ real64 B = (Y [start+1] - Y [start]) / A;
+
+ S.resize (count);
+
+ S [start] = B;
+
+ int32 j;
+
+ // Slopes here are a weighted average of the slopes
+ // to each of the adjcent control points.
+
+ for (j = start + 2; j < end; ++j)
+ {
+
+ real64 C = X [j] - X [j-1];
+ real64 D = (Y [j] - Y [j-1]) / C;
+
+ S [j-1] = (B * C + D * A) / (A + C);
+
+ A = C;
+ B = D;
+
+ }
+
+ S [end-1] = 2.0 * B - S [end-2];
+ S [start] = 2.0 * S [start] - S [start+1];
+
+ if ((end - start) > 2)
+ {
+
+ std::vector<real64> E;
+ std::vector<real64> F;
+ std::vector<real64> G;
+
+ E.resize (count);
+ F.resize (count);
+ G.resize (count);
+
+ F [start] = 0.5;
+ E [end-1] = 0.5;
+ G [start] = 0.75 * (S [start] + S [start+1]);
+ G [end-1] = 0.75 * (S [end-2] + S [end-1]);
+
+ for (j = start+1; j < end - 1; ++j)
+ {
+
+ A = (X [j+1] - X [j-1]) * 2.0;
+
+ E [j] = (X [j+1] - X [j]) / A;
+ F [j] = (X [j] - X [j-1]) / A;
+ G [j] = 1.5 * S [j];
+
+ }
+
+ for (j = start+1; j < end; ++j)
+ {
+
+ A = 1.0 - F [j-1] * E [j];
+
+ if (j != end-1) F [j] /= A;
+
+ G [j] = (G [j] - G [j-1] * E [j]) / A;
+
+ }
+
+ for (j = end - 2; j >= start; --j)
+ G [j] = G [j] - F [j] * G [j+1];
+
+ for (j = start; j < end; ++j)
+ S [j] = G [j];
+
+ }
+
+ }
+
+/******************************************************************************/
+
+bool dng_spline_solver::IsIdentity () const
+ {
+
+ int32 count = (int32) X.size ();
+
+ if (count != 2)
+ return false;
+
+ if (X [0] != 0.0 || X [1] != 1.0 ||
+ Y [0] != 0.0 || Y [1] != 1.0)
+ return false;
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+real64 dng_spline_solver::Evaluate (real64 x) const
+ {
+
+ int32 count = (int32) X.size ();
+
+ // Check for off each end of point list.
+
+ if (x <= X [0])
+ return Y [0];
+
+ if (x >= X [count-1])
+ return Y [count-1];
+
+ // Binary search for the index.
+
+ int32 lower = 1;
+ int32 upper = count - 1;
+
+ while (upper > lower)
+ {
+
+ int32 mid = (lower + upper) >> 1;
+
+ if (x == X [mid])
+ {
+ return Y [mid];
+ }
+
+ if (x > X [mid])
+ lower = mid + 1;
+ else
+ upper = mid;
+
+ }
+
+ DNG_ASSERT (upper == lower, "Binary search error in point list");
+
+ int32 j = lower;
+
+ // X [j - 1] < x <= X [j]
+ // A is the distance between the X [j] and X [j - 1]
+ // B and C describe the fractional distance to either side. B + C = 1.
+
+ // We compute a cubic spline between the two points with slopes
+ // S[j-1] and S[j] at either end. Specifically, we compute the 1-D Bezier
+ // with control values:
+ //
+ // Y[j-1], Y[j-1] + S[j-1]*A, Y[j]-S[j]*A, Y[j]
+
+ return EvaluateSplineSegment (x,
+ X [j - 1],
+ Y [j - 1],
+ S [j - 1],
+ X [j ],
+ Y [j ],
+ S [j ]);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_spline.h b/gpr/source/lib/dng_sdk/dng_spline.h
new file mode 100644
index 0000000..d2ccdf3
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_spline.h
@@ -0,0 +1,83 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_spline.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_spline__
+#define __dng_spline__
+
+/*****************************************************************************/
+
+#include "dng_1d_function.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+inline real64 EvaluateSplineSegment (real64 x,
+ real64 x0,
+ real64 y0,
+ real64 s0,
+ real64 x1,
+ real64 y1,
+ real64 s1)
+ {
+
+ real64 A = x1 - x0;
+
+ real64 B = (x - x0) / A;
+
+ real64 C = (x1 - x) / A;
+
+ real64 D = ((y0 * (2.0 - C + B) + (s0 * A * B)) * (C * C)) +
+ ((y1 * (2.0 - B + C) - (s1 * A * C)) * (B * B));
+
+ return D;
+
+ }
+
+/*****************************************************************************/
+
+class dng_spline_solver: public dng_1d_function
+ {
+
+ protected:
+
+ std::vector<real64> X;
+ std::vector<real64> Y;
+
+ std::vector<real64> S;
+
+ public:
+
+ dng_spline_solver ();
+
+ virtual ~dng_spline_solver ();
+
+ void Reset ();
+
+ void Add (real64 x, real64 y);
+
+ virtual void Solve ();
+
+ virtual bool IsIdentity () const;
+
+ virtual real64 Evaluate (real64 x) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_stream.cpp b/gpr/source/lib/dng_sdk/dng_stream.cpp
new file mode 100644
index 0000000..d2d6b96
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_stream.cpp
@@ -0,0 +1,1221 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_stream.cpp#2 $ */
+/* $DateTime: 2012/06/01 07:28:57 $ */
+/* $Change: 832715 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_stream.h"
+
+#include "dng_abort_sniffer.h"
+#include "dng_auto_ptr.h"
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_memory.h"
+#include "dng_tag_types.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+dng_stream::dng_stream (dng_abort_sniffer *sniffer,
+ uint32 bufferSize,
+ uint64 offsetInOriginalFile)
+
+ : fSwapBytes (false)
+ , fHaveLength (false)
+ , fLength (0)
+ , fOffsetInOriginalFile (offsetInOriginalFile)
+ , fPosition (0)
+ , fMemBlock (bufferSize)
+ , fBuffer (fMemBlock.Buffer_uint8 ())
+ , fBufferSize (bufferSize)
+ , fBufferStart (0)
+ , fBufferEnd (0)
+ , fBufferLimit (bufferSize)
+ , fBufferDirty (false)
+ , fSniffer (sniffer)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_stream::dng_stream (const void *data,
+ uint32 count,
+ uint64 offsetInOriginalFile)
+
+ : fSwapBytes (false)
+ , fHaveLength (true)
+ , fLength (count)
+ , fOffsetInOriginalFile (offsetInOriginalFile)
+ , fPosition (0)
+ , fMemBlock ()
+ , fBuffer ((uint8 *) data)
+ , fBufferSize (count)
+ , fBufferStart (0)
+ , fBufferEnd (count)
+ , fBufferLimit (count)
+ , fBufferDirty (false)
+ , fSniffer (NULL)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_stream::~dng_stream ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_stream::DoGetLength ()
+ {
+
+ ThrowProgramError ();
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::DoRead (void * /* data */,
+ uint32 /* count */,
+ uint64 /* offset */)
+ {
+
+ ThrowProgramError ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::DoSetLength (uint64 /* length */)
+ {
+
+ ThrowProgramError ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::DoWrite (const void * /* data */,
+ uint32 /* count */,
+ uint64 /* offset */)
+ {
+
+ ThrowProgramError ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_stream::BigEndian () const
+ {
+
+ return fSwapBytes != (!!qDNGBigEndian);
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::SetBigEndian (bool bigEndian)
+ {
+
+ fSwapBytes = (bigEndian != (!!qDNGBigEndian));
+
+ }
+
+/*****************************************************************************/
+
+const void * dng_stream::Data () const
+ {
+
+ if (fBufferStart == 0 && fHaveLength && fBufferEnd == fLength)
+ {
+
+ return fBuffer;
+
+ }
+
+ return NULL;
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_stream::AsMemoryBlock (dng_memory_allocator &allocator)
+ {
+
+ Flush ();
+
+ uint64 len64 = Length ();
+
+ if (len64 > 0xFFFFFFFF)
+ {
+ ThrowProgramError ();
+ }
+
+ uint32 len = (uint32) len64;
+
+ AutoPtr<dng_memory_block> block (allocator.Allocate (len));
+
+ if (len)
+ {
+
+ SetReadPosition (0);
+
+ Get (block->Buffer (), len);
+
+ }
+
+ return block.Release ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::SetReadPosition (uint64 offset)
+ {
+
+ fPosition = offset;
+
+ if (fPosition > Length ())
+ {
+
+ ThrowEndOfFile ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_stream::OffsetInOriginalFile () const
+ {
+
+ return fOffsetInOriginalFile;
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_stream::PositionInOriginalFile () const
+ {
+
+ if (fOffsetInOriginalFile == kDNGStreamInvalidOffset)
+ return kDNGStreamInvalidOffset;
+
+ return fOffsetInOriginalFile + Position ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Get (void *data, uint32 count)
+ {
+
+ while (count)
+ {
+
+ // See if the request is totally inside buffer.
+
+ if (fPosition >= fBufferStart && fPosition + count <= fBufferEnd)
+ {
+
+ DoCopyBytes (fBuffer + (uint32) (fPosition - fBufferStart),
+ data,
+ count);
+
+ fPosition += count;
+
+ return;
+
+ }
+
+ // See if first part of request is inside buffer.
+
+ if (fPosition >= fBufferStart && fPosition < fBufferEnd)
+ {
+
+ uint32 block = (uint32) (fBufferEnd - fPosition);
+
+ DoCopyBytes (fBuffer + (fPosition - fBufferStart),
+ data,
+ block);
+
+ count -= block;
+
+ data = (void *) (((char *) data) + block);
+
+ fPosition += block;
+
+ }
+
+ // Flush buffer if dirty.
+
+ Flush ();
+
+ // Do large reads unbuffered.
+
+ if (count > fBufferSize)
+ {
+
+ if (fPosition + count > Length ())
+ {
+
+ ThrowEndOfFile ();
+
+ }
+
+ DoRead (data,
+ count,
+ fPosition);
+
+ fPosition += count;
+
+ return;
+
+ }
+
+ // Figure out new buffer range.
+
+ fBufferStart = fPosition;
+
+ if (fBufferSize >= 4096)
+ {
+
+ // Align to a 4K file block.
+
+ fBufferStart &= (uint64) ~((int64) 4095);
+
+ }
+
+ fBufferEnd = Min_uint64 (fBufferStart + fBufferSize, Length ());
+
+ if (fBufferEnd <= fPosition)
+ {
+
+ ThrowEndOfFile ();
+
+ }
+
+ // Read data into buffer.
+
+ dng_abort_sniffer::SniffForAbort (fSniffer);
+
+ DoRead (fBuffer,
+ (uint32) (fBufferEnd - fBufferStart),
+ fBufferStart);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::SetWritePosition (uint64 offset)
+ {
+
+ fPosition = offset;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Flush ()
+ {
+
+ if (fBufferDirty)
+ {
+
+ dng_abort_sniffer::SniffForAbort (fSniffer);
+
+ DoWrite (fBuffer,
+ (uint32) (fBufferEnd - fBufferStart),
+ fBufferStart);
+
+ fBufferStart = 0;
+ fBufferEnd = 0;
+ fBufferLimit = fBufferSize;
+
+ fBufferDirty = false;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::SetLength (uint64 length)
+ {
+
+ Flush ();
+
+ if (Length () != length)
+ {
+
+ DoSetLength (length);
+
+ fLength = length;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Put (const void *data,
+ uint32 count)
+ {
+
+ // See if we can replace or append to the existing buffer.
+
+ uint64 endPosition = fPosition + count;
+
+ if (fBufferDirty &&
+ fPosition >= fBufferStart &&
+ fPosition <= fBufferEnd &&
+ endPosition <= fBufferLimit)
+ {
+
+ DoCopyBytes (data,
+ fBuffer + (uint32) (fPosition - fBufferStart),
+ count);
+
+ if (fBufferEnd < endPosition)
+ fBufferEnd = endPosition;
+
+ }
+
+ // Else we need to write to the file.
+
+ else
+ {
+
+ // Write existing buffer.
+
+ Flush ();
+
+ // Write large blocks unbuffered.
+
+ if (count >= fBufferSize)
+ {
+
+ dng_abort_sniffer::SniffForAbort (fSniffer);
+
+ DoWrite (data, count, fPosition);
+
+ }
+
+ // Start a new buffer with small blocks.
+
+ else
+ {
+
+ fBufferDirty = true;
+
+ fBufferStart = fPosition;
+ fBufferEnd = endPosition;
+ fBufferLimit = fBufferStart + fBufferSize;
+
+ DoCopyBytes (data,
+ fBuffer,
+ count);
+
+ }
+
+ }
+
+ fPosition = endPosition;
+
+ fLength = Max_uint64 (Length (), fPosition);
+
+ }
+
+/*****************************************************************************/
+
+uint16 dng_stream::Get_uint16 ()
+ {
+
+ uint16 x;
+
+ Get (&x, 2);
+
+ if (fSwapBytes)
+ {
+
+ x = SwapBytes16 (x);
+
+ }
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Put_uint16 (uint16 x)
+ {
+
+ if (fSwapBytes)
+ {
+
+ x = SwapBytes16 (x);
+
+ }
+
+ Put (&x, 2);
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_stream::Get_uint32 ()
+ {
+
+ uint32 x;
+
+ Get (&x, 4);
+
+ if (fSwapBytes)
+ {
+
+ x = SwapBytes32 (x);
+
+ }
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Put_uint32 (uint32 x)
+ {
+
+ if (fSwapBytes)
+ {
+
+ x = SwapBytes32 (x);
+
+ }
+
+ Put (&x, 4);
+
+ }
+
+/*****************************************************************************/
+
+uint64 dng_stream::Get_uint64 ()
+ {
+
+ if (fSwapBytes)
+ {
+
+ union
+ {
+ uint32 u32 [2];
+ uint64 u64;
+ } u;
+
+ u.u32 [1] = Get_uint32 ();
+ u.u32 [0] = Get_uint32 ();
+
+ return u.u64;
+
+ }
+
+ uint64 x;
+
+ Get (&x, 8);
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Put_uint64 (uint64 x)
+ {
+
+ if (fSwapBytes)
+ {
+
+ union
+ {
+ uint32 u32 [2];
+ uint64 u64;
+ } u;
+
+ u.u64 = x;
+
+ Put_uint32 (u.u32 [1]);
+ Put_uint32 (u.u32 [0]);
+
+ }
+
+ else
+ {
+
+ Put (&x, 8);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real32 dng_stream::Get_real32 ()
+ {
+
+ union
+ {
+ uint32 i;
+ real32 r;
+ } u;
+
+ u.i = Get_uint32 ();
+
+ return u.r;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Put_real32 (real32 x)
+ {
+
+ if (fSwapBytes)
+ {
+
+ union
+ {
+ uint32 i;
+ real32 r;
+ } u;
+
+ u.r = x;
+
+ Put_uint32 (u.i);
+
+ }
+
+ else
+ {
+
+ Put (&x, 4);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_stream::Get_real64 ()
+ {
+
+ if (fSwapBytes)
+ {
+
+ union
+ {
+ uint32 i [2];
+ real64 r;
+ } u;
+
+ u.i [1] = Get_uint32 ();
+ u.i [0] = Get_uint32 ();
+
+ return u.r;
+
+ }
+
+ real64 x;
+
+ Get (&x, 8);
+
+ return x;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Put_real64 (real64 x)
+ {
+
+ if (fSwapBytes)
+ {
+
+ union
+ {
+ uint32 i [2];
+ real64 r;
+ } u;
+
+ u.r = x;
+
+ Put_uint32 (u.i [1]);
+ Put_uint32 (u.i [0]);
+
+ }
+
+ else
+ {
+
+ Put (&x, 8);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Get_CString (char *data, uint32 maxLength)
+ {
+
+ memset (data, 0, maxLength);
+
+ uint32 index = 0;
+
+ while (true)
+ {
+
+ char c = (char) Get_uint8 ();
+
+ if (index + 1 < maxLength)
+ data [index++] = c;
+
+ if (c == 0)
+ break;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::Get_UString (char *data, uint32 maxLength)
+ {
+
+ memset (data, 0, maxLength);
+
+ uint32 index = 0;
+
+ while (true)
+ {
+
+ char c = (char) Get_uint16 ();
+
+ if (index + 1 < maxLength)
+ data [index++] = (char) c;
+
+ if (c == 0)
+ break;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::PutZeros (uint64 count)
+ {
+
+ const uint32 kZeroBufferSize = 4096;
+
+ if (count >= kZeroBufferSize)
+ {
+
+ dng_memory_data zeroBuffer (kZeroBufferSize);
+
+ DoZeroBytes (zeroBuffer.Buffer (),
+ kZeroBufferSize);
+
+ while (count)
+ {
+
+ uint64 blockSize = Min_uint64 (count, kZeroBufferSize);
+
+ Put (zeroBuffer.Buffer (), (uint32) blockSize);
+
+ count -= blockSize;
+
+ }
+
+ }
+
+ else
+ {
+
+ uint32 count32 = (uint32) count;
+
+ for (uint32 j = 0; j < count32; j++)
+ {
+
+ Put_uint8 (0);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::PadAlign2 ()
+ {
+
+ PutZeros (Position () & 1);
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::PadAlign4 ()
+ {
+
+ PutZeros ((4 - (Position () & 3)) & 3);
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_stream::TagValue_uint32 (uint32 tagType)
+ {
+
+ switch (tagType)
+ {
+
+ case ttByte:
+ return (uint32) Get_uint8 ();
+
+ case ttShort:
+ return (uint32) Get_uint16 ();
+
+ case ttLong:
+ case ttIFD:
+ return Get_uint32 ();
+
+ }
+
+ real64 x = TagValue_real64 (tagType);
+
+ if (x < 0.0)
+ x = 0.0;
+
+ if (x > (real64) 0xFFFFFFFF)
+ x = (real64) 0xFFFFFFFF;
+
+ return (uint32) (x + 0.5);
+
+ }
+
+/*****************************************************************************/
+
+int32 dng_stream::TagValue_int32 (uint32 tagType)
+ {
+
+ switch (tagType)
+ {
+
+ case ttSByte:
+ return (int32) Get_int8 ();
+
+ case ttSShort:
+ return (int32) Get_int16 ();
+
+ case ttSLong:
+ return Get_int32 ();
+
+ }
+
+ real64 x = TagValue_real64 (tagType);
+
+ if (x < 0.0)
+ {
+
+ if (x < -2147483648.0)
+ x = -2147483648.0;
+
+ return (int32) (x - 0.5);
+
+ }
+
+ else
+ {
+
+ if (x > 2147483647.0)
+ x = 2147483647.0;
+
+ return (int32) (x + 0.5);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_urational dng_stream::TagValue_urational (uint32 tagType)
+ {
+
+ dng_urational result;
+
+ result.n = 0;
+ result.d = 1;
+
+ switch (tagType)
+ {
+
+ case ttRational:
+ {
+
+ result.n = Get_uint32 ();
+ result.d = Get_uint32 ();
+
+ break;
+
+ }
+
+ case ttSRational:
+ {
+
+ int32 n = Get_int32 ();
+ int32 d = Get_int32 ();
+
+ if ((n < 0) == (d < 0))
+ {
+
+ if (d < 0)
+ {
+ n = -n;
+ d = -d;
+ }
+
+ result.n = (uint32) n;
+ result.d = (uint32) d;
+
+ }
+
+ break;
+
+ }
+
+ case ttByte:
+ case ttShort:
+ case ttLong:
+ case ttIFD:
+ {
+
+ result.n = TagValue_uint32 (tagType);
+
+ break;
+
+ }
+
+ case ttSByte:
+ case ttSShort:
+ case ttSLong:
+ {
+
+ int32 n = TagValue_int32 (tagType);
+
+ if (n > 0)
+ {
+ result.n = (uint32) n;
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ real64 x = TagValue_real64 (tagType);
+
+ if (x > 0.0)
+ {
+
+ while (result.d < 10000 && x < 1000000)
+ {
+
+ result.d *= 10;
+
+ x *= 10.0;
+
+ }
+
+ result.n = (uint32) (x + 0.5);
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_srational dng_stream::TagValue_srational (uint32 tagType)
+ {
+
+ dng_srational result;
+
+ result.n = 0;
+ result.d = 1;
+
+ switch (tagType)
+ {
+
+ case ttSRational:
+ {
+
+ result.n = Get_int32 ();
+ result.d = Get_int32 ();
+
+ break;
+
+ }
+
+ default:
+ {
+
+ real64 x = TagValue_real64 (tagType);
+
+ if (x > 0.0)
+ {
+
+ while (result.d < 10000 && x < 1000000.0)
+ {
+
+ result.d *= 10;
+
+ x *= 10.0;
+
+ }
+
+ result.n = (int32) (x + 0.5);
+
+ }
+
+ else
+ {
+
+ while (result.d < 10000 && x > -1000000.0)
+ {
+
+ result.d *= 10;
+
+ x *= 10.0;
+
+ }
+
+ result.n = (int32) (x - 0.5);
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_stream::TagValue_real64 (uint32 tagType)
+ {
+
+ switch (tagType)
+ {
+
+ case ttByte:
+ case ttShort:
+ case ttLong:
+ case ttIFD:
+ return (real64) TagValue_uint32 (tagType);
+
+ case ttSByte:
+ case ttSShort:
+ case ttSLong:
+ return (real64) TagValue_int32 (tagType);
+
+ case ttRational:
+ {
+
+ uint32 n = Get_uint32 ();
+ uint32 d = Get_uint32 ();
+
+ if (d == 0)
+ return 0.0;
+ else
+ return (real64) n / (real64) d;
+
+ }
+
+ case ttSRational:
+ {
+
+ int32 n = Get_int32 ();
+ int32 d = Get_int32 ();
+
+ if (d == 0)
+ return 0.0;
+ else
+ return (real64) n / (real64) d;
+
+ }
+
+ case ttFloat:
+ return (real64) Get_real32 ();
+
+ case ttDouble:
+ return Get_real64 ();
+
+ }
+
+ return 0.0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::CopyToStream (dng_stream &dstStream,
+ uint64 count)
+ {
+
+ uint8 smallBuffer [1024];
+
+ if (count <= sizeof (smallBuffer))
+ {
+
+ Get (smallBuffer, (uint32) count);
+
+ dstStream.Put (smallBuffer, (uint32) count);
+
+ }
+
+ else
+ {
+
+ const uint32 bigBufferSize = (uint32) Min_uint64 (kBigBufferSize,
+ count);
+
+ dng_memory_data bigBuffer (bigBufferSize);
+
+ while (count)
+ {
+
+ uint32 blockCount = (uint32) Min_uint64 (bigBufferSize,
+ count);
+
+ Get (bigBuffer.Buffer (),
+ blockCount);
+
+ dstStream.Put (bigBuffer.Buffer (),
+ blockCount);
+
+ count -= blockCount;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_stream::DuplicateStream (dng_stream &dstStream)
+ {
+
+ // Turn off sniffers for this operation.
+
+ TempStreamSniffer noSniffer1 (*this , NULL);
+ TempStreamSniffer noSniffer2 (dstStream, NULL);
+
+ // First grow the destination stream if required, in an attempt to
+ // reserve any needed space before overwriting the existing data.
+
+ if (dstStream.Length () < Length ())
+ {
+ dstStream.SetLength (Length ());
+ }
+
+ SetReadPosition (0);
+
+ dstStream.SetWritePosition (0);
+
+ CopyToStream (dstStream, Length ());
+
+ dstStream.Flush ();
+
+ dstStream.SetLength (Length ());
+
+ }
+
+/*****************************************************************************/
+
+TempBigEndian::TempBigEndian (dng_stream &stream,
+ bool bigEndian)
+
+ : fStream (stream)
+ , fOldSwap (stream.SwapBytes ())
+
+ {
+
+ fStream.SetBigEndian (bigEndian);
+
+ }
+
+/*****************************************************************************/
+
+TempBigEndian::~TempBigEndian ()
+ {
+
+ fStream.SetSwapBytes (fOldSwap);
+
+ }
+
+/*****************************************************************************/
+
+TempStreamSniffer::TempStreamSniffer (dng_stream &stream,
+ dng_abort_sniffer *sniffer)
+
+ : fStream (stream)
+ , fOldSniffer (stream.Sniffer ())
+
+ {
+
+ fStream.SetSniffer (sniffer);
+
+ }
+
+/*****************************************************************************/
+
+TempStreamSniffer::~TempStreamSniffer ()
+ {
+
+ fStream.SetSniffer (fOldSniffer);
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_stream.h b/gpr/source/lib/dng_sdk/dng_stream.h
new file mode 100644
index 0000000..df233ae
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_stream.h
@@ -0,0 +1,698 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_stream.h#2 $ */
+/* $DateTime: 2012/06/01 07:28:57 $ */
+/* $Change: 832715 $ */
+/* $Author: tknoll $ */
+
+/** Data stream abstraction for serializing and deserializing sequences of
+ * basic types and RAW image data.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_stream__
+#define __dng_stream__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+#include "dng_memory.h"
+#include "dng_rational.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+// Constants for invalid offset in streams.
+
+const uint64 kDNGStreamInvalidOffset = (uint64) (int64) -1;
+
+/*****************************************************************************/
+
+/// Base stream abstraction. Has support for going between stream and pointer
+/// abstraction.
+
+class dng_stream
+ {
+
+ public:
+
+ enum
+ {
+
+ kSmallBufferSize = 4 * 1024,
+ kBigBufferSize = 64 * 1024,
+
+ kDefaultBufferSize = kSmallBufferSize
+
+ };
+
+ private:
+
+ bool fSwapBytes;
+
+ bool fHaveLength;
+
+ uint64 fLength;
+
+ const uint64 fOffsetInOriginalFile;
+
+ uint64 fPosition;
+
+ dng_memory_data fMemBlock;
+
+ uint8 *fBuffer;
+
+ uint32 fBufferSize;
+
+ uint64 fBufferStart;
+ uint64 fBufferEnd;
+ uint64 fBufferLimit;
+
+ bool fBufferDirty;
+
+ dng_abort_sniffer *fSniffer;
+
+ protected:
+
+ dng_stream (dng_abort_sniffer *sniffer = NULL,
+ uint32 bufferSize = kDefaultBufferSize,
+ uint64 offsetInOriginalFile = kDNGStreamInvalidOffset);
+
+ virtual uint64 DoGetLength ();
+
+ virtual void DoRead (void *data,
+ uint32 count,
+ uint64 offset);
+
+ virtual void DoSetLength (uint64 length);
+
+ virtual void DoWrite (const void *data,
+ uint32 count,
+ uint64 offset);
+
+ public:
+
+ /// Construct a stream with initial data.
+ /// \param data Pointer to initial contents of stream.
+ /// \param count Number of bytes data is valid for.
+ /// \param offsetInOriginalFile If data came from a file originally,
+ /// offset can be saved here for later use.
+
+ dng_stream (const void *data,
+ uint32 count,
+ uint64 offsetInOriginalFile = kDNGStreamInvalidOffset);
+
+ virtual ~dng_stream ();
+
+ /// Getter for whether stream is swapping byte order on input/output.
+ /// \retval If true, data will be swapped on input/output.
+
+ bool SwapBytes () const
+ {
+ return fSwapBytes;
+ }
+
+ /// Setter for whether stream is swapping byte order on input/output.
+ /// \param swapBytes If true, stream will swap byte order on input or
+ /// output for future reads/writes.
+
+ void SetSwapBytes (bool swapBytes)
+ {
+ fSwapBytes = swapBytes;
+ }
+
+ /// Getter for whether data in stream is big endian.
+ /// \retval If true, data in stream is big endian.
+
+ bool BigEndian () const;
+
+ /// Setter for whether data in stream is big endian.
+ /// \param bigEndian If true, data in stream is big endian.
+
+ void SetBigEndian (bool bigEndian = true);
+
+ /// Getter for whether data in stream is big endian.
+ /// \retval If true, data in stream is big endian.
+
+ bool LittleEndian () const
+ {
+ return !BigEndian ();
+ }
+
+ /// Setter for whether data in stream is big endian.
+ /// \param littleEndian If true, data in stream is big endian.
+
+ void SetLittleEndian (bool littleEndian = true)
+ {
+ SetBigEndian (!littleEndian);
+ }
+
+ /// Returns the size of the buffer used by the stream.
+
+ uint32 BufferSize () const
+ {
+ return fBufferSize;
+ }
+
+ /// Getter for length of data in stream.
+ /// \retval Length of readable data in stream.
+
+ uint64 Length ()
+ {
+
+ if (!fHaveLength)
+ {
+
+ fLength = DoGetLength ();
+
+ fHaveLength = true;
+
+ }
+
+ return fLength;
+
+ }
+
+ /// Getter for current offset in stream.
+ /// \retval current offset from start of stream.
+
+ uint64 Position () const
+ {
+ return fPosition;
+ }
+
+ /// Getter for current position in original file, taking into account
+ /// OffsetInOriginalFile stream data was taken from.
+ /// \retval kInvalidOffset if no offset in original file is set, sum
+ /// of offset in original file and current position otherwise.
+
+ uint64 PositionInOriginalFile () const;
+
+ /// Getter for offset in original file.
+ /// \retval kInvalidOffset if no offset in original file is set,
+ /// offset in original file otherwise.
+
+ uint64 OffsetInOriginalFile () const;
+
+ /// Return pointer to stream contents if the stream is entirely
+ /// available as a single memory block, NULL otherwise.
+
+ const void * Data () const;
+
+ /// Return the entire stream as a single memory block.
+ /// This works for all streams, but requires copying the data to a new buffer.
+ /// \param allocator Allocator used to allocate memory.
+
+ dng_memory_block * AsMemoryBlock (dng_memory_allocator &allocator);
+
+ /// Seek to a new position in stream for reading.
+
+ void SetReadPosition (uint64 offset);
+
+ /// Skip forward in stream.
+ /// \param delta Number of bytes to skip forward.
+
+ void Skip (uint64 delta)
+ {
+ SetReadPosition (Position () + delta);
+ }
+
+ /// Get data from stream. Exception is thrown and no data is read if
+ /// insufficient data available in stream.
+ /// \param data Buffer to put data into. Must be valid for count bytes.
+ /// \param count Bytes of data to read.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ void Get (void *data, uint32 count);
+
+ /// Seek to a new position in stream for writing.
+
+ void SetWritePosition (uint64 offset);
+
+ /// Force any stored data in stream to be written to underlying storage.
+
+ void Flush ();
+
+ /// Set length of available data.
+ /// \param length Number of bytes of avialble data in stream.
+
+ void SetLength (uint64 length);
+
+ /// Write data to stream.
+ /// \param data Buffer of data to write to stream.
+ /// \param count Bytes of in data.
+
+ void Put (const void *data, uint32 count);
+
+ /// Get an unsigned 8-bit integer from stream and advance read position.
+ /// \retval One unsigned 8-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ uint8 Get_uint8 ()
+ {
+
+ // Fast check to see if in buffer
+
+ if (fPosition >= fBufferStart && fPosition < fBufferEnd)
+ {
+
+ return fBuffer [fPosition++ - fBufferStart];
+
+ }
+
+ // Not in buffer, let main routine do the work.
+
+ uint8 x;
+
+ Get (&x, 1);
+
+ return x;
+
+ }
+
+ /// Put an unsigned 8-bit integer to stream and advance write position.
+ /// \param x One unsigned 8-bit integer.
+
+ void Put_uint8 (uint8 x)
+ {
+
+ if (fBufferDirty &&
+ fPosition >= fBufferStart &&
+ fPosition <= fBufferEnd &&
+ fPosition < fBufferLimit)
+ {
+
+ fBuffer [fPosition - fBufferStart] = x;
+
+ fPosition++;
+
+ if (fBufferEnd < fPosition)
+ fBufferEnd = fPosition;
+
+ fLength = Max_uint64 (Length (), fPosition);
+
+ }
+
+ else
+ {
+
+ Put (&x, 1);
+
+ }
+
+ }
+
+ /// Get an unsigned 16-bit integer from stream and advance read position.
+ /// Byte swap if byte swapping is turned on.
+ /// \retval One unsigned 16-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ uint16 Get_uint16 ();
+
+ /// Put an unsigned 16-bit integer to stream and advance write position.
+ /// Byte swap if byte swapping is turned on.
+ /// \param x One unsigned 16-bit integer.
+
+ void Put_uint16 (uint16 x);
+
+ /// Get an unsigned 32-bit integer from stream and advance read position.
+ /// Byte swap if byte swapping is turned on.
+ /// \retval One unsigned 32-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ uint32 Get_uint32 ();
+
+ /// Put an unsigned 32-bit integer to stream and advance write position.
+ /// Byte swap if byte swapping is turned on.
+ /// \param x One unsigned 32-bit integer.
+
+ void Put_uint32 (uint32 x);
+
+ /// Get an unsigned 64-bit integer from stream and advance read position.
+ /// Byte swap if byte swapping is turned on.
+ /// \retval One unsigned 64-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ uint64 Get_uint64 ();
+
+ /// Put an unsigned 64-bit integer to stream and advance write position.
+ /// Byte swap if byte swapping is turned on.
+ /// \param x One unsigned 64-bit integer.
+
+ void Put_uint64 (uint64 x);
+
+ /// Get one 8-bit integer from stream and advance read position.
+ /// \retval One 8-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ int8 Get_int8 ()
+ {
+ return (int8) Get_uint8 ();
+ }
+
+ /// Put one 8-bit integer to stream and advance write position.
+ /// \param x One 8-bit integer.
+
+ void Put_int8 (int8 x)
+ {
+ Put_uint8 ((uint8) x);
+ }
+
+ /// Get one 16-bit integer from stream and advance read position.
+ /// Byte swap if byte swapping is turned on.
+ /// \retval One 16-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ int16 Get_int16 ()
+ {
+ return (int16) Get_uint16 ();
+ }
+
+ /// Put one 16-bit integer to stream and advance write position.
+ /// Byte swap if byte swapping is turned on.
+ /// \param x One 16-bit integer.
+
+ void Put_int16 (int16 x)
+ {
+ Put_uint16 ((uint16) x);
+ }
+
+ /// Get one 32-bit integer from stream and advance read position.
+ /// Byte swap if byte swapping is turned on.
+ /// \retval One 32-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ int32 Get_int32 ()
+ {
+ return (int32) Get_uint32 ();
+ }
+
+ /// Put one 32-bit integer to stream and advance write position.
+ /// Byte swap if byte swapping is turned on.
+ /// \param x One 32-bit integer.
+
+ void Put_int32 (int32 x)
+ {
+ Put_uint32 ((uint32) x);
+ }
+
+ /// Get one 64-bit integer from stream and advance read position.
+ /// Byte swap if byte swapping is turned on.
+ /// \retval One 64-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ int64 Get_int64 ()
+ {
+ return (int64) Get_uint64 ();
+ }
+
+ /// Put one 64-bit integer to stream and advance write position.
+ /// Byte swap if byte swapping is turned on.
+ /// \param x One 64-bit integer.
+
+ void Put_int64 (int64 x)
+ {
+ Put_uint64 ((uint64) x);
+ }
+
+ /// Get one 32-bit IEEE floating-point number from stream and advance
+ /// read position. Byte swap if byte swapping is turned on.
+ /// \retval One 32-bit IEEE floating-point number.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ real32 Get_real32 ();
+
+ /// Put one 32-bit IEEE floating-point number to stream and advance write
+ /// position. Byte swap if byte swapping is turned on.
+ /// \param x One 32-bit IEEE floating-point number.
+
+ void Put_real32 (real32 x);
+
+ /// Get one 64-bit IEEE floating-point number from stream and advance
+ /// read position. Byte swap if byte swapping is turned on.
+ /// \retval One 64-bit IEEE floating-point number .
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ real64 Get_real64 ();
+
+ /// Put one 64-bit IEEE floating-point number to stream and advance write
+ /// position. Byte swap if byte swapping is turned on.
+ /// \param x One64-bit IEEE floating-point number.
+
+ void Put_real64 (real64 x);
+
+ /// Get an 8-bit character string from stream and advance read position.
+ /// Routine always reads until a NUL character (8-bits of zero) is read.
+ /// (That is, only maxLength bytes will be returned in buffer, but the
+ /// stream is always advanced until a NUL is read or EOF is reached.)
+ /// \param data Buffer in which string is returned.
+ /// \param maxLength Maximum number of bytes to place in buffer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if stream runs out before NUL is seen.
+
+ void Get_CString (char *data,
+ uint32 maxLength);
+
+ /// Get a 16-bit character string from stream and advance read position.
+ /// 16-bit characters are truncated to 8-bits.
+ /// Routine always reads until a NUL character (16-bits of zero) is read.
+ /// (That is, only maxLength bytes will be returned in buffer, but the
+ /// stream is always advanced until a NUL is read or EOF is reached.)
+ /// \param data Buffer to place string in.
+ /// \param maxLength Maximum number of bytes to place in buffer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if stream runs out before NUL is seen.
+
+ void Get_UString (char *data,
+ uint32 maxLength);
+
+ /// Writes the specified number of zero bytes to stream.
+ /// \param count Number of zero bytes to write.
+
+ void PutZeros (uint64 count);
+
+ /// Writes zeros to align the stream position to a multiple of 2.
+
+ void PadAlign2 ();
+
+ /// Writes zeros to align the stream position to a multiple of 4.
+
+ void PadAlign4 ();
+
+ /// Get a value of size indicated by tag type from stream and advance
+ /// read position. Byte swap if byte swapping is turned on and tag type
+ /// is larger than a byte. Value is returned as an unsigned 32-bit integer.
+ /// \param tagType Tag type of data stored in stream.
+ /// \retval One unsigned 32-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ uint32 TagValue_uint32 (uint32 tagType);
+
+ /// Get a value of size indicated by tag type from stream and advance read
+ /// position. Byte swap if byte swapping is turned on and tag type is larger
+ /// than a byte. Value is returned as a 32-bit integer.
+ /// \param tagType Tag type of data stored in stream.
+ /// \retval One 32-bit integer.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ int32 TagValue_int32 (uint32 tagType);
+
+ /// Get a value of size indicated by tag type from stream and advance read
+ /// position. Byte swap if byte swapping is turned on and tag type is larger
+ /// than a byte. Value is returned as a dng_urational.
+ /// \param tagType Tag type of data stored in stream.
+ /// \retval One dng_urational.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ dng_urational TagValue_urational (uint32 tagType);
+
+ /// Get a value of size indicated by tag type from stream and advance read
+ /// position. Byte swap if byte swapping is turned on and tag type is larger
+ /// than a byte. Value is returned as a dng_srational.
+ /// \param tagType Tag type of data stored in stream.
+ /// \retval One dng_srational.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ dng_srational TagValue_srational (uint32 tagType);
+
+ /// Get a value of size indicated by tag type from stream and advance read
+ /// position. Byte swap if byte swapping is turned on and tag type is larger
+ /// than a byte. Value is returned as a 64-bit IEEE floating-point number.
+ /// \param tagType Tag type of data stored in stream.
+ /// \retval One 64-bit IEEE floating-point number.
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
+ /// if not enough data in stream.
+
+ real64 TagValue_real64 (uint32 tagType);
+
+ /// Getter for sniffer associated with stream.
+ /// \retval The sniffer for this stream.
+
+ dng_abort_sniffer * Sniffer () const
+ {
+ return fSniffer;
+ }
+
+ /// Putter for sniffer associated with stream.
+ /// \param sniffer The new sniffer to use (or NULL for none).
+
+ void SetSniffer (dng_abort_sniffer *sniffer)
+ {
+ fSniffer = sniffer;
+ }
+
+ /// Copy a specified number of bytes to a target stream.
+ /// \param dstStream The target stream.
+ /// \param count The number of bytes to copy.
+
+ virtual void CopyToStream (dng_stream &dstStream,
+ uint64 count);
+
+ /// Makes the target stream a copy of this stream.
+ /// \param dstStream The target stream.
+
+ void DuplicateStream (dng_stream &dstStream);
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_stream (const dng_stream &stream);
+
+ dng_stream & operator= (const dng_stream &stream);
+
+ };
+
+/*****************************************************************************/
+
+class TempBigEndian
+ {
+
+ private:
+
+ dng_stream & fStream;
+
+ bool fOldSwap;
+
+ public:
+
+ TempBigEndian (dng_stream &stream,
+ bool bigEndian = true);
+
+ virtual ~TempBigEndian ();
+
+ };
+
+/*****************************************************************************/
+
+class TempLittleEndian: public TempBigEndian
+ {
+
+ public:
+
+ TempLittleEndian (dng_stream &stream,
+ bool littleEndian = true)
+
+ : TempBigEndian (stream, !littleEndian)
+
+ {
+ }
+
+ virtual ~TempLittleEndian ()
+ {
+ }
+
+ };
+
+/*****************************************************************************/
+
+class TempStreamSniffer
+ {
+
+ private:
+
+ dng_stream & fStream;
+
+ dng_abort_sniffer *fOldSniffer;
+
+ public:
+
+ TempStreamSniffer (dng_stream &stream,
+ dng_abort_sniffer *sniffer);
+
+ virtual ~TempStreamSniffer ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ TempStreamSniffer (const TempStreamSniffer &temp);
+
+ TempStreamSniffer & operator= (const TempStreamSniffer &temp);
+
+ };
+
+/*****************************************************************************/
+
+class PreserveStreamReadPosition
+ {
+
+ private:
+
+ dng_stream & fStream;
+
+ uint64 fPosition;
+
+ public:
+
+ PreserveStreamReadPosition (dng_stream &stream)
+
+ : fStream (stream)
+ , fPosition (stream.Position ())
+
+ {
+ }
+
+ ~PreserveStreamReadPosition ()
+ {
+ fStream.SetReadPosition (fPosition);
+ }
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ PreserveStreamReadPosition (const PreserveStreamReadPosition &rhs);
+
+ PreserveStreamReadPosition & operator= (const PreserveStreamReadPosition &rhs);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_string.cpp b/gpr/source/lib/dng_sdk/dng_string.cpp
new file mode 100644
index 0000000..2e95f43
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_string.cpp
@@ -0,0 +1,2242 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_string.cpp#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_string.h"
+
+#include "dng_assertions.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_mutex.h"
+#include "dng_utils.h"
+
+#if qMacOS && qEnableCarbon
+#include <CoreServices/CoreServices.h>
+#endif
+
+#if qWinOS
+#include <windows.h>
+#endif
+
+#include <ctype.h> // for isdigit
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+const uint32 kREPLACEMENT_CHARACTER = 0x0000FFFD;
+
+/*****************************************************************************/
+
+#if qMacOS && qEnableCarbon
+
+static void Assign_Multibyte (dng_string &dngString,
+ const char *otherString,
+ TextEncoding encoding)
+ {
+
+ uint32 aSize = (uint32) strlen (otherString);
+
+ if (aSize > 0)
+ {
+
+ uint32 aBufSize = aSize * 6 + 256;
+
+ dng_memory_data aBuf (aBufSize + 1);
+
+ UnicodeMapping aMapping;
+
+ aMapping.unicodeEncoding = ::CreateTextEncoding (kTextEncodingUnicodeV3_0,
+ kUnicodeNoSubset,
+ kUnicodeUTF8Format);
+
+ aMapping.otherEncoding = encoding;
+ aMapping.mappingVersion = kUnicodeUseLatestMapping;
+
+ TextToUnicodeInfo aInfo = NULL;
+
+ if (::CreateTextToUnicodeInfo (&aMapping, &aInfo) == noErr)
+ {
+
+ ByteCount aInput = 0;
+ ByteCount aOutput = 0;
+
+ ::ConvertFromTextToUnicode (aInfo,
+ aSize,
+ otherString,
+ kUnicodeUseFallbacksMask |
+ kUnicodeLooseMappingsMask,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ aBufSize,
+ &aInput,
+ &aOutput,
+ (UniChar *) aBuf.Buffer ());
+
+ ::DisposeTextToUnicodeInfo (&aInfo);
+
+ if (aOutput > 0 && aOutput <= aBufSize)
+ {
+
+ char *aBufChar = aBuf.Buffer_char ();
+
+ aBufChar [aOutput] = 0;
+
+ dngString.Set (aBufChar);
+
+ return;
+
+ }
+
+ }
+
+ }
+
+ dngString.Clear ();
+
+ }
+
+static uint32 Extract_Multibyte (const dng_string &dngString,
+ dng_memory_data &buffer,
+ TextEncoding encoding)
+ {
+
+ uint32 aSize = dngString.Length ();
+
+ if (aSize > 0)
+ {
+
+ uint32 aBufSize = (aSize * 2) + 256;
+
+ dng_memory_data tempBuffer (aBufSize);
+
+ UnicodeMapping aMapping;
+
+ aMapping.unicodeEncoding = ::CreateTextEncoding (kTextEncodingUnicodeV3_0,
+ kUnicodeNoSubset,
+ kUnicodeUTF8Format);
+
+ aMapping.otherEncoding = encoding;
+ aMapping.mappingVersion = kUnicodeUseLatestMapping;
+
+ UnicodeToTextInfo aInfo = NULL;
+
+ if (::CreateUnicodeToTextInfo (&aMapping, &aInfo) == noErr)
+ {
+
+ ByteCount aInput = 0;
+ ByteCount aOutput = 0;
+
+ ::ConvertFromUnicodeToText (aInfo,
+ aSize,
+ (const UniChar *) dngString.Get (),
+ kUnicodeUseFallbacksMask |
+ kUnicodeLooseMappingsMask |
+ kUnicodeDefaultDirectionMask,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ aBufSize,
+ &aInput,
+ &aOutput,
+ tempBuffer.Buffer_char ());
+
+ ::DisposeUnicodeToTextInfo (&aInfo);
+
+ if (aOutput > 0)
+ {
+
+ buffer.Allocate ((uint32) (aOutput + 1));
+
+ memcpy (buffer.Buffer (),
+ tempBuffer.Buffer (),
+ aOutput);
+
+ buffer.Buffer_char () [aOutput] = 0;
+
+ return (uint32) aOutput;
+
+ }
+
+ }
+
+ }
+
+ buffer.Allocate (1);
+
+ buffer.Buffer_char () [0] = 0;
+
+ return 0;
+
+ }
+
+static void Assign_SystemEncoding (dng_string &dngString,
+ const char *otherString)
+ {
+
+ TextEncoding aEncoding;
+
+ ::UpgradeScriptInfoToTextEncoding (smSystemScript,
+ kTextLanguageDontCare,
+ kTextRegionDontCare,
+ NULL,
+ &aEncoding);
+
+ Assign_Multibyte (dngString,
+ otherString,
+ aEncoding);
+
+ }
+
+static uint32 Extract_SystemEncoding (const dng_string &dngString,
+ dng_memory_data &buffer)
+ {
+
+ TextEncoding aEncoding;
+
+ ::UpgradeScriptInfoToTextEncoding (smSystemScript,
+ kTextLanguageDontCare,
+ kTextRegionDontCare,
+ NULL,
+ &aEncoding);
+
+ return Extract_Multibyte (dngString,
+ buffer,
+ aEncoding);
+
+ }
+
+static void Assign_JIS_X208_1990 (dng_string &dngString,
+ const char *otherString)
+ {
+
+ Assign_Multibyte (dngString,
+ otherString,
+ kTextEncodingJIS_X0208_90);
+
+ }
+
+#endif
+
+/*****************************************************************************/
+
+#if qWinOS
+
+static void Assign_Multibyte (dng_string &dngString,
+ const char *otherString,
+ UINT encoding)
+ {
+
+ DNG_ASSERT (sizeof (WCHAR) == 2, "WCHAR must be 2 bytes");
+
+ int aSize = (int) strlen (otherString);
+
+ if (aSize > 0)
+ {
+
+ int aBufChars = aSize * 3 + 128;
+
+ dng_memory_data aBuf ((aBufChars + 1) << 1);
+
+ int aResult = ::MultiByteToWideChar (encoding,
+ 0,
+ otherString,
+ aSize,
+ (WCHAR *) aBuf.Buffer (),
+ aBufChars);
+
+ if (aResult > 0 && aResult <= aBufChars)
+ {
+
+ uint16 * aUTF16 = aBuf.Buffer_uint16 ();
+
+ aUTF16 [aResult] = 0;
+
+ dngString.Set_UTF16 (aUTF16);
+
+ return;
+
+ }
+
+ }
+
+ dngString.Clear ();
+
+ }
+
+static uint32 Extract_Multibyte (const dng_string &dngString,
+ dng_memory_data &buffer,
+ UINT encoding)
+ {
+
+ DNG_ASSERT (sizeof (WCHAR) == 2, "WCHAR must be 2 bytes");
+
+ dng_memory_data sBuffer;
+
+ int aCount = dngString.Get_UTF16 (sBuffer);
+
+ int dBufSize = aCount * 2 + 256;
+
+ dng_memory_data dBuffer (dBufSize);
+
+ int aResult = ::WideCharToMultiByte (encoding,
+ 0,
+ (WCHAR *) sBuffer.Buffer (),
+ aCount,
+ dBuffer.Buffer_char (),
+ dBufSize,
+ NULL,
+ NULL);
+
+ if (aResult < 0)
+ aResult = 0;
+
+ buffer.Allocate (aResult + 1);
+
+ memcpy (buffer.Buffer (),
+ dBuffer.Buffer (),
+ aResult);
+
+ buffer.Buffer_char () [aResult] = 0;
+
+ return (uint32) aResult;
+
+ }
+
+static void Assign_SystemEncoding (dng_string &dngString,
+ const char *otherString)
+ {
+
+ Assign_Multibyte (dngString,
+ otherString,
+ ::GetACP ());
+
+ }
+
+static uint32 Extract_SystemEncoding (const dng_string &dngString,
+ dng_memory_data &buffer)
+ {
+
+ return Extract_Multibyte (dngString,
+ buffer,
+ ::GetACP ());
+
+ }
+
+static void Assign_JIS_X208_1990 (dng_string &dngString,
+ const char *otherString)
+ {
+
+ // From MSDN documentation: 20932 = JIS X 0208-1990 & 0121-1990
+
+ const UINT kJIS = 20932;
+
+ Assign_Multibyte (dngString,
+ otherString,
+ kJIS);
+
+ }
+
+#endif
+
+/*****************************************************************************/
+
+static bool IsASCII (const char *s)
+ {
+
+ if (!s)
+ {
+
+ return true;
+
+ }
+
+ while (true)
+ {
+
+ uint8 c = (uint8) *(s++);
+
+ if (c == 0)
+ {
+
+ break;
+
+ }
+
+ if (c & 0x80)
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+dng_string::dng_string ()
+
+ : fData ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_string::dng_string (const dng_string &s)
+
+ : fData ()
+
+ {
+
+ Set (s.Get ());
+
+ }
+
+/*****************************************************************************/
+
+dng_string & dng_string::operator= (const dng_string &s)
+ {
+
+ if (this != &s)
+ {
+
+ Set (s.Get ());
+
+ }
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+dng_string::~dng_string ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+const char * dng_string::Get () const
+ {
+
+ if (fData.Buffer ())
+ {
+
+ return fData.Buffer_char ();
+
+ }
+
+ return "";
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::IsASCII () const
+ {
+
+ return ::IsASCII (Get ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set (const char *s)
+ {
+
+ // Measure the new length.
+
+ uint32 newLen = (s != NULL ? (uint32) strlen (s) : 0);
+
+ // If it is a NULL string, then clear the buffer.
+
+ if (newLen == 0)
+ {
+
+ fData.Clear ();
+
+ }
+
+ // Else we need to copy the bytes.
+
+ else
+ {
+
+ uint32 oldLen = Length ();
+
+ // We might be setting this string to a sub-string of itself,
+ // so don't reallocate the data unless the string is getting
+ // longer.
+
+ if (newLen > oldLen)
+ {
+
+ fData.Clear ();
+
+ fData.Allocate (newLen + 1);
+
+ }
+
+ char *d = fData.Buffer_char ();
+
+ for (uint32 k = 0; k <= newLen; k++)
+ {
+
+ d [k] = s [k];
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set_ASCII (const char *s)
+ {
+
+ if (::IsASCII (s))
+ {
+
+ Set (s);
+
+ }
+
+ else
+ {
+
+ Set_SystemEncoding (s);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set_UTF8 (const char *s)
+ {
+
+ uint32 len = (uint32) strlen (s);
+
+ const char *sEnd = s + len;
+
+ // Worst case expansion is 1-byte characters expanding to
+ // replacement character, which requires 3 bytes.
+
+ dng_memory_data buffer (len * 3 + 1);
+
+ uint8 *d = buffer.Buffer_uint8 ();
+
+ while (s < sEnd)
+ {
+
+ uint32 aChar = DecodeUTF8 (s, (uint32) (sEnd - s));
+
+ if (aChar > 0x7FFFFFFF)
+ {
+ aChar = kREPLACEMENT_CHARACTER;
+ }
+
+ #if qDNGValidate
+
+ if (aChar == kREPLACEMENT_CHARACTER)
+ {
+ ReportWarning ("Expected UTF-8 value is not valid UTF-8 (or contains a kREPLACEMENT_CHARACTER)");
+ }
+
+ #endif
+
+ if (aChar < 0x00000080)
+ {
+ *(d++) = (uint8) aChar;
+ }
+
+ else if (aChar < 0x00000800)
+ {
+ *(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
+ *(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else if (aChar < 0x00010000)
+ {
+ *(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else if (aChar < 0x00200000)
+ {
+ *(d++) = (uint8) ( (aChar >> 18) | 0x000000F0);
+ *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else if (aChar < 0x04000000)
+ {
+ *(d++) = (uint8) ( (aChar >> 24) | 0x000000F8);
+ *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else
+ {
+ *(d++) = (uint8) ( (aChar >> 30) | 0x000000FC);
+ *(d++) = (uint8) (((aChar >> 24) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ }
+
+ *d = 0;
+
+ Set (buffer.Buffer_char ());
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_string::Get_SystemEncoding (dng_memory_data &buffer) const
+ {
+
+ if (IsASCII ())
+ {
+
+ uint32 len = Length ();
+
+ buffer.Allocate (len + 1);
+
+ memcpy (buffer.Buffer (), Get (), len + 1);
+
+ return len;
+
+ }
+
+ else
+ {
+
+ #if (qMacOS && qEnableCarbon) || qWinOS
+
+ return Extract_SystemEncoding (*this, buffer);
+
+ #else
+
+ // Fallback logic to force the string to ASCII.
+
+ dng_string temp (*this);
+
+ temp.ForceASCII ();
+
+ return temp.Get_SystemEncoding (buffer);
+
+ #endif
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set_SystemEncoding (const char *s)
+ {
+
+ if (::IsASCII (s))
+ {
+
+ Set (s);
+
+ }
+
+ else
+ {
+
+ #if (qMacOS && qEnableCarbon) || qWinOS
+
+ Assign_SystemEncoding (*this, s);
+
+ #else
+
+ // Fallback logic that just grabs the ASCII characters and
+ // ignores the non-ASCII characters.
+
+ uint32 len = (uint32) strlen (s);
+
+ dng_memory_data buffer (len + 1);
+
+ uint8 *d = buffer.Buffer_uint8 ();
+
+ while (*s)
+ {
+
+ uint8 c = (uint8) *(s++);
+
+ if ((c & 0x80) == 0)
+ {
+
+ *(d++) = c;
+
+ }
+
+ }
+
+ *d = 0;
+
+ Set (buffer.Buffer_char ());
+
+ #endif
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::ValidSystemEncoding () const
+ {
+
+ if (IsASCII ())
+ {
+
+ return true;
+
+ }
+
+ dng_memory_data buffer;
+
+ Get_SystemEncoding (buffer);
+
+ dng_string temp;
+
+ temp.Set_SystemEncoding (buffer.Buffer_char ());
+
+ return (*this == temp);
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set_JIS_X208_1990 (const char *s)
+ {
+
+ if (::IsASCII (s))
+ {
+
+ Set (s);
+
+ }
+
+ else
+ {
+
+ #if (qMacOS && qEnableCarbon) || qWinOS
+
+ Assign_JIS_X208_1990 (*this, s);
+
+ #else
+
+ // Fallback to the ASCII extraction logic.
+
+ Set_SystemEncoding (s);
+
+ #endif
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_string::DecodeUTF8 (const char *&s,
+ uint32 maxBytes,
+ bool *isValid)
+ {
+
+ static const uint8 gUTF8Bytes [256] =
+ {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6
+ };
+
+ if (isValid)
+ {
+ *isValid = true;
+ }
+
+ const uint8 *nBuf = (const uint8 *) s;
+
+ uint32 aChar = nBuf [0];
+
+ uint32 aSize = gUTF8Bytes [aChar];
+
+ if (aSize > maxBytes)
+ {
+
+ s += maxBytes;
+
+ if (isValid)
+ {
+ *isValid = false;
+ }
+
+ return kREPLACEMENT_CHARACTER;
+
+ }
+
+ s += aSize;
+
+ for (uint32 extra = 1; extra < aSize; extra++)
+ {
+
+ if ((nBuf [extra] & 0xC0) != 0x80)
+ {
+
+ if (isValid)
+ {
+ *isValid = false;
+ }
+
+ return kREPLACEMENT_CHARACTER;
+
+ }
+
+ }
+
+ switch (aSize)
+ {
+
+ case 0:
+ {
+
+ s++; // Don't get stuck in infinite loop
+
+ if (isValid)
+ {
+ *isValid = false;
+ }
+
+ return kREPLACEMENT_CHARACTER;
+
+ }
+
+ case 1:
+ {
+
+ return aChar;
+
+ }
+
+ case 2:
+ {
+
+ aChar = ((aChar << 6) + nBuf [1]) - (uint32) 0x00003080UL;
+
+ break;
+
+ }
+
+ case 3:
+ {
+
+ aChar = ((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2]) - (uint32) 0x000E2080UL;
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ aChar = ((((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2])
+ << 6) + nBuf [3]) - (uint32) 0x03C82080UL;
+
+ break;
+
+ }
+
+ case 5:
+ {
+
+ aChar = ((((((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2])
+ << 6) + nBuf [3])
+ << 6) + nBuf [4]) - (uint32) 0xFA082080UL;
+
+ break;
+
+ }
+
+ case 6:
+ {
+
+ aChar = ((((((((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2])
+ << 6) + nBuf [3])
+ << 6) + nBuf [4])
+ << 6) + nBuf [5]) - (uint32) 0x82082080UL;
+
+ break;
+
+ }
+
+ }
+
+ if (aChar < 0x7F || aChar > 0x0010FFFF)
+ {
+
+ if (isValid)
+ {
+ *isValid = false;
+ }
+
+ return kREPLACEMENT_CHARACTER;
+
+ }
+
+ return aChar;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::IsUTF8 (const char *s)
+ {
+
+ uint32 len = (uint32) strlen (s);
+
+ const char *sEnd = s + len;
+
+ while (s < sEnd)
+ {
+
+ bool isValid = true;
+
+ (void) DecodeUTF8 (s, (uint32) (sEnd - s), &isValid);
+
+ if (!isValid)
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set_UTF8_or_System (const char *s)
+ {
+
+ if (::IsASCII (s))
+ {
+
+ Set (s);
+
+ }
+
+ else if (IsUTF8 (s))
+ {
+
+ Set_UTF8 (s);
+
+ }
+
+ else
+ {
+
+ Set_SystemEncoding (s);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_string::Get_UTF16 (dng_memory_data &buffer) const
+ {
+
+ uint32 count = 0;
+
+ const char *sPtr = Get ();
+
+ while (*sPtr)
+ {
+
+ uint32 x = DecodeUTF8 (sPtr);
+
+ if (x <= 0x0000FFFF ||
+ x > 0x0010FFFF)
+ {
+
+ count += 1;
+
+ }
+
+ else
+ {
+
+ count += 2;
+
+ }
+
+ }
+
+ buffer.Allocate ((count + 1) * (uint32) sizeof (uint16));
+
+ uint16 *dPtr = buffer.Buffer_uint16 ();
+
+ sPtr = Get ();
+
+ while (*sPtr)
+ {
+
+ uint32 x = DecodeUTF8 (sPtr);
+
+ if (x <= 0x0000FFFF)
+ {
+
+ *(dPtr++) = (uint16) x;
+
+ }
+
+ else if (x > 0x0010FFFF)
+ {
+
+ *(dPtr++) = (uint16) kREPLACEMENT_CHARACTER;
+
+ }
+
+ else
+ {
+
+ x -= 0x00010000;
+
+ *(dPtr++) = (uint16) ((x >> 10 ) + 0x0000D800);
+ *(dPtr++) = (uint16) ((x & 0x000003FF) + 0x0000DC00);
+
+ }
+
+ }
+
+ *dPtr = 0;
+
+ return count;
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Set_UTF16 (const uint16 *s)
+ {
+
+ if (!s)
+ {
+ Clear ();
+ return;
+ }
+
+ bool swap = false;
+
+ if (s [0] == 0xFFFE) // Swapped byte order marker
+ {
+ swap = true;
+ s++;
+ }
+
+ else if (s [0] == 0xFEFF) // Non-swapped byte order marker
+ {
+ s++;
+ }
+
+ uint32 length16 = 0;
+
+ while (s [length16] != 0)
+ {
+ length16++;
+ }
+
+ const uint16 *sEnd = s + length16;
+
+ dng_memory_data buffer (length16 * 6 + 1);
+
+ uint8 *d = buffer.Buffer_uint8 ();
+
+ while (s < sEnd)
+ {
+
+ uint32 aChar = *s++;
+
+ if (swap)
+ {
+ aChar = ((aChar << 8) | (aChar >> 8)) & 0x0000FFFF;
+ }
+
+ if ((aChar >= 0x0000D800) && (aChar <= 0x0000DBFF) && (s < sEnd))
+ {
+
+ uint32 aLow = *s;
+
+ if (swap)
+ {
+ aLow = ((aLow << 8) | (aLow >> 8)) & 0x0000FFFF;
+ }
+
+ if ((aLow >= 0x0000DC00) && (aLow <= 0x0000DFFF))
+ {
+
+ aChar = ((aChar - 0x0000D800) << 10) +
+ (aLow - 0x0000DC00) +
+ 0x00010000;
+
+ s++;
+
+ }
+
+ }
+
+ if (aChar > 0x7FFFFFFF)
+ {
+ aChar = kREPLACEMENT_CHARACTER;
+ }
+
+ if (aChar < 0x00000080)
+ {
+ *(d++) = (uint8) aChar;
+ }
+
+ else if (aChar < 0x00000800)
+ {
+ *(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
+ *(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else if (aChar < 0x00010000)
+ {
+ *(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else if (aChar < 0x00200000)
+ {
+ *(d++) = (uint8) ( (aChar >> 18) | 0x000000F0);
+ *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else if (aChar < 0x04000000)
+ {
+ *(d++) = (uint8) ( (aChar >> 24) | 0x000000F8);
+ *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ else
+ {
+ *(d++) = (uint8) ( (aChar >> 30) | 0x000000FC);
+ *(d++) = (uint8) (((aChar >> 24) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 18) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 12) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
+ *(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
+ }
+
+ }
+
+ *d = 0;
+
+ Set (buffer.Buffer_char ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Clear ()
+ {
+
+ Set (NULL);
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Truncate (uint32 maxBytes)
+ {
+
+ uint32 len = Length ();
+
+ if (len > maxBytes)
+ {
+
+ uint8 *s = fData.Buffer_uint8 ();
+
+ // Don't truncate on an extension character. Extensions characters
+ // in UTF-8 have the 0x80 bit set and the 0x40 bit clear.
+
+ while (maxBytes > 0 && ((s [maxBytes]) & 0xC0) == 0x80)
+ {
+
+ maxBytes--;
+
+ }
+
+ s [maxBytes] = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::TrimTrailingBlanks ()
+ {
+
+ bool didTrim = false;
+
+ if (fData.Buffer ())
+ {
+
+ char *s = fData.Buffer_char ();
+
+ uint32 len = (uint32) strlen (s);
+
+ while (len > 0 && s [len - 1] == ' ')
+ {
+ len--;
+ didTrim = true;
+ }
+
+ s [len] = 0;
+
+ }
+
+ return didTrim;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::TrimLeadingBlanks ()
+ {
+
+ bool didTrim = false;
+
+ const char *s = Get ();
+
+ while (*s == ' ')
+ {
+ s++;
+ didTrim = true;
+ }
+
+ if (didTrim)
+ {
+ Set (s);
+ }
+
+ return didTrim;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::IsEmpty () const
+ {
+
+ const char *s = Get ();
+
+ return *s == 0;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_string::Length () const
+ {
+
+ const char *s = Get ();
+
+ return (uint32) strlen (s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::operator== (const dng_string &s) const
+ {
+
+ const char *s1 = Get ();
+ const char *s2 = s.Get ();
+
+ return strcmp (s1, s2) == 0;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::Matches (const char *t,
+ const char *s,
+ bool case_sensitive)
+ {
+
+ while (*s != 0)
+ {
+
+ char c1 = *(s++);
+ char c2 = *(t++);
+
+ if (!case_sensitive)
+ {
+ c1 = ForceUppercase (c1);
+ c2 = ForceUppercase (c2);
+ }
+
+ if (c1 != c2)
+ {
+ return false;
+ }
+
+ }
+
+ return (*t == 0);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::Matches (const char *s,
+ bool case_sensitive) const
+ {
+
+ return dng_string::Matches (Get (), s, case_sensitive);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::StartsWith (const char *s,
+ bool case_sensitive) const
+ {
+
+ const char *t = Get ();
+
+ while (*s != 0)
+ {
+
+ char c1 = *(s++);
+ char c2 = *(t++);
+
+ if (!case_sensitive)
+ {
+ c1 = ForceUppercase (c1);
+ c2 = ForceUppercase (c2);
+ }
+
+ if (c1 != c2)
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::EndsWith (const char *s,
+ bool case_sensitive) const
+ {
+
+ uint32 len1 = Length ();
+
+ uint32 len2 = (uint32) strlen (s);
+
+ if (len1 < len2)
+ {
+ return false;
+ }
+
+ const char *t = Get () + (len1 - len2);
+
+ while (*s != 0)
+ {
+
+ char c1 = *(s++);
+ char c2 = *(t++);
+
+ if (!case_sensitive)
+ {
+ c1 = ForceUppercase (c1);
+ c2 = ForceUppercase (c2);
+ }
+
+ if (c1 != c2)
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::Contains (const char *s,
+ bool case_sensitive,
+ int32 *match_offset) const
+ {
+
+ if (match_offset)
+ {
+ *match_offset = -1;
+ }
+
+ uint32 len1 = Length ();
+
+ uint32 len2 = (uint32) strlen (s);
+
+ if (len1 < len2)
+ {
+ return false;
+ }
+
+ uint32 offsets = len1 - len2;
+
+ for (uint32 offset = 0; offset <= offsets; offset++)
+ {
+
+ const char *ss = s;
+ const char *tt = Get () + offset;
+
+ while (*ss != 0)
+ {
+
+ char c1 = *(ss++);
+ char c2 = *(tt++);
+
+ if (!case_sensitive)
+ {
+ c1 = ForceUppercase (c1);
+ c2 = ForceUppercase (c2);
+ }
+
+ if (c1 != c2)
+ {
+ goto tryNextOffset;
+ }
+
+ }
+
+ if (match_offset)
+ {
+ *match_offset = offset;
+ }
+
+ return true;
+
+ tryNextOffset: ;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::Replace (const char *old_string,
+ const char *new_string,
+ bool case_sensitive)
+ {
+
+ int32 match_offset = -1;
+
+ if (Contains (old_string,
+ case_sensitive,
+ &match_offset))
+ {
+
+ uint32 len1 = Length ();
+
+ uint32 len2 = (uint32) strlen (old_string);
+ uint32 len3 = (uint32) strlen (new_string);
+
+ if (len2 == len3)
+ {
+
+ strncpy (fData.Buffer_char () + match_offset,
+ new_string,
+ len3);
+
+ }
+
+ else if (len2 > len3)
+ {
+
+ strncpy (fData.Buffer_char () + match_offset,
+ new_string,
+ len3);
+
+ const char *s = fData.Buffer_char () + match_offset + len2;
+ char *d = fData.Buffer_char () + match_offset + len3;
+
+ uint32 extra = len1 - match_offset - len2 + 1; // + 1 for NULL termination
+
+ for (uint32 j = 0; j < extra; j++)
+ {
+ *(d++) = *(s++);
+ }
+
+ }
+
+ else
+ {
+
+ dng_memory_data tempBuffer (len1 - len2 + len3 + 1);
+
+ if (match_offset)
+ {
+
+ strncpy (tempBuffer.Buffer_char (),
+ fData .Buffer_char (),
+ match_offset);
+
+ }
+
+ if (len3)
+ {
+
+ strncpy (tempBuffer.Buffer_char () + match_offset,
+ new_string,
+ len3);
+
+ }
+
+ uint32 extra = len1 - match_offset - len2 + 1; // + 1 for NULL termination
+
+ strncpy (tempBuffer.Buffer_char () + match_offset + len3,
+ fData .Buffer_char () + match_offset + len2,
+ extra);
+
+ Set (tempBuffer.Buffer_char ());
+
+ }
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string::TrimLeading (const char *s,
+ bool case_sensitive)
+ {
+
+ if (StartsWith (s, case_sensitive))
+ {
+
+ Set (Get () + (uint32) strlen (s));
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::Append (const char *s)
+ {
+
+ uint32 len2 = (uint32) strlen (s);
+
+ if (len2)
+ {
+
+ uint32 len1 = Length ();
+
+ dng_memory_data temp (len1 + len2 + 1);
+
+ char *buffer = temp.Buffer_char ();
+
+ if (len1)
+ {
+ memcpy (buffer, Get (), len1);
+ }
+
+ memcpy (buffer + len1, s, len2 + 1);
+
+ Set (buffer);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::SetUppercase ()
+ {
+
+ if (fData.Buffer ())
+ {
+
+ uint32 len = Length ();
+
+ char *dPtr = fData.Buffer_char ();
+
+ for (uint32 j = 0; j < len; j++)
+ {
+
+ char c = dPtr [j];
+
+ if (c >= 'a' && c <= 'z')
+ {
+
+ dPtr [j] = c - 'a' + 'A';
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::SetLowercase ()
+ {
+
+ if (fData.Buffer ())
+ {
+
+ uint32 len = Length ();
+
+ char *dPtr = fData.Buffer_char ();
+
+ for (uint32 j = 0; j < len; j++)
+ {
+
+ char c = dPtr [j];
+
+ if (c >= 'A' && c <= 'Z')
+ {
+
+ dPtr [j] = c - 'A' + 'a';
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::SetLineEndings (char ending)
+ {
+
+ if (fData.Buffer ())
+ {
+
+ const char *sPtr = fData.Buffer_char ();
+ char *dPtr = fData.Buffer_char ();
+
+ while (*sPtr)
+ {
+
+ char c = *(sPtr++);
+
+ char nc = sPtr [0];
+
+ if ((c == '\r' && nc == '\n') ||
+ (c == '\n' && nc == '\r'))
+ {
+
+ sPtr++;
+
+ if (ending)
+ {
+ *(dPtr++) = ending;
+ }
+
+ }
+
+ else if (c == '\n' ||
+ c == '\r')
+ {
+
+ if (ending)
+ {
+ *(dPtr++) = ending;
+ }
+
+ }
+
+ else
+ {
+
+ *(dPtr++) = c;
+
+ }
+
+ }
+
+ *dPtr = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::StripLowASCII ()
+ {
+
+ if (fData.Buffer ())
+ {
+
+ const char *sPtr = fData.Buffer_char ();
+ char *dPtr = fData.Buffer_char ();
+
+ while (*sPtr)
+ {
+
+ char c = *(sPtr++);
+
+ if (c == '\r' || c == '\n' || (uint8) c >= ' ')
+ {
+
+ *(dPtr++) = c;
+
+ }
+
+ }
+
+ *dPtr = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string::NormalizeAsCommaSeparatedNumbers ()
+ {
+
+ if (fData.Buffer ())
+ {
+
+ const char *sPtr = fData.Buffer_char ();
+ char *dPtr = fData.Buffer_char ();
+
+ bool commaInserted = false;
+
+ while (*sPtr)
+ {
+
+ uint32 c = DecodeUTF8 (sPtr);
+
+ // Support number formats such as "3", "+3.0", "-3.1416", "314.16e-2",
+ // "0.31416E1", but no hex/octal number representations.
+
+ if (isdigit ((int) c) || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E')
+ {
+
+ *(dPtr++) = (char) c;
+
+ if (commaInserted)
+ {
+
+ commaInserted = false;
+
+ }
+
+ }
+
+ else if (!commaInserted)
+ {
+
+ *(dPtr++) = ',';
+
+ commaInserted = true;
+
+ }
+
+ }
+
+ *dPtr = 0;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+// Unicode to low-ASCII strings table.
+
+struct UnicodeToLowASCIIEntry
+ {
+ uint32 unicode;
+ const char *ascii;
+ };
+
+static const UnicodeToLowASCIIEntry kUnicodeToLowASCII [] =
+ {
+ { 0x00A0, " " },
+ { 0x00A1, "!" },
+ { 0x00A9, "(C)" },
+ { 0x00AA, "a" },
+ { 0x00AB, "<<" },
+ { 0x00AC, "!" },
+ { 0x00AE, "(R)" },
+ { 0x00B0, "dg" },
+ { 0x00B1, "+-" },
+ { 0x00B7, "." },
+ { 0x00BA, "o" },
+ { 0x00BB, ">>" },
+ { 0x00BF, "?" },
+ { 0x00C0, "A" },
+ { 0x00C1, "A" },
+ { 0x00C2, "A" },
+ { 0x00C3, "A" },
+ { 0x00C4, "A" },
+ { 0x00C5, "A" },
+ { 0x00C6, "AE" },
+ { 0x00C7, "C" },
+ { 0x00C8, "E" },
+ { 0x00C9, "E" },
+ { 0x00CA, "E" },
+ { 0x00CB, "E" },
+ { 0x00CC, "I" },
+ { 0x00CD, "I" },
+ { 0x00CE, "I" },
+ { 0x00CF, "I" },
+ { 0x00D1, "N" },
+ { 0x00D2, "O" },
+ { 0x00D3, "O" },
+ { 0x00D4, "O" },
+ { 0x00D5, "O" },
+ { 0x00D6, "O" },
+ { 0x00D8, "O" },
+ { 0x00D9, "U" },
+ { 0x00DA, "U" },
+ { 0x00DB, "U" },
+ { 0x00DC, "U" },
+ { 0x00DD, "Y" },
+ { 0x00E0, "a" },
+ { 0x00E1, "a" },
+ { 0x00E2, "a" },
+ { 0x00E3, "a" },
+ { 0x00E4, "a" },
+ { 0x00E5, "a" },
+ { 0x00E6, "ae" },
+ { 0x00E7, "c" },
+ { 0x00E8, "e" },
+ { 0x00E9, "e" },
+ { 0x00EA, "e" },
+ { 0x00EB, "e" },
+ { 0x00EC, "i" },
+ { 0x00ED, "i" },
+ { 0x00EE, "i" },
+ { 0x00EF, "i" },
+ { 0x00F1, "n" },
+ { 0x00F2, "o" },
+ { 0x00F3, "o" },
+ { 0x00F4, "o" },
+ { 0x00F5, "o" },
+ { 0x00F6, "o" },
+ { 0x00F7, "/" },
+ { 0x00F8, "o" },
+ { 0x00F9, "u" },
+ { 0x00FA, "u" },
+ { 0x00FB, "u" },
+ { 0x00FC, "u" },
+ { 0x00FD, "y" },
+ { 0x00FF, "y" },
+ { 0x0131, "i" },
+ { 0x0152, "OE" },
+ { 0x0153, "oe" },
+ { 0x0178, "Y" },
+ { 0x2013, "-" },
+ { 0x2014, "-" },
+ { 0x2018, "'" },
+ { 0x2019, "'" },
+ { 0x201A, "," },
+ { 0x201C, "\"" },
+ { 0x201D, "\"" },
+ { 0x201E, ",," },
+ { 0x2022, "." },
+ { 0x2026, "..." },
+ { 0x2039, "<" },
+ { 0x203A, ">" },
+ { 0x2044, "/" },
+ { 0x2122, "TM" },
+ { 0x2206, "d" },
+ { 0x2211, "S" },
+ { 0x2260, "!=" },
+ { 0x2264, "<=" },
+ { 0x2265, ">=" },
+ { 0x2318, "#" },
+ { 0xFB01, "fi" },
+ { 0xFB02, "fl" }
+ };
+
+/******************************************************************************/
+
+void dng_string::ForceASCII ()
+ {
+
+ if (!IsASCII ())
+ {
+
+ dng_memory_data tempBuffer (Length () * 3 + 1);
+
+ char *dPtr = tempBuffer.Buffer_char ();
+
+ const char *sPtr = Get ();
+
+ while (*sPtr)
+ {
+
+ uint32 x = DecodeUTF8 (sPtr);
+
+ if (x <= 0x007F)
+ {
+
+ *(dPtr++) = (char) x;
+
+ }
+
+ else
+ {
+
+ const char *ascii = NULL;
+
+ const uint32 kTableEntrys = sizeof (kUnicodeToLowASCII ) /
+ sizeof (kUnicodeToLowASCII [0]);
+
+ for (uint32 entry = 0; entry < kTableEntrys; entry++)
+ {
+
+ if (kUnicodeToLowASCII [entry] . unicode == x)
+ {
+
+ ascii = kUnicodeToLowASCII [entry] . ascii;
+
+ break;
+
+ }
+
+ }
+
+ if (ascii)
+ {
+
+ while (*ascii)
+ {
+
+ *(dPtr++) = *(ascii++);
+
+ }
+
+ }
+
+ else
+ {
+
+ *(dPtr++) ='?';
+
+ }
+
+ }
+
+ }
+
+ *dPtr = 0;
+
+ Set (tempBuffer.Buffer_char ());
+
+ }
+
+ }
+
+/******************************************************************************/
+
+static dng_mutex gProtectUCCalls ("gProtectUCCalls");
+
+/******************************************************************************/
+
+int32 dng_string::Compare (const dng_string &s) const
+ {
+
+ #if qMacOS && qEnableCarbon
+
+ {
+
+ dng_memory_data aStrA;
+ dng_memory_data aStrB;
+
+ uint32 aLenA = this->Get_UTF16 (aStrA);
+ uint32 aLenB = s .Get_UTF16 (aStrB);
+
+ if (aLenA > 0)
+ {
+
+ if (aLenB > 0)
+ {
+
+ // For some Mac OS versions anyway, UCCompareTextDefault is not
+ // thread safe.
+
+ dng_lock_mutex lockMutex (&gProtectUCCalls);
+
+ UCCollateOptions aOptions = kUCCollateStandardOptions |
+ kUCCollatePunctuationSignificantMask;
+
+ SInt32 aOrder = -1;
+
+ Boolean aEqual = false;
+
+ OSStatus searchStatus = ::UCCompareTextDefault (aOptions,
+ aStrA.Buffer_uint16 (),
+ aLenA,
+ aStrB.Buffer_uint16 (),
+ aLenB,
+ &aEqual,
+ &aOrder);
+
+ if (searchStatus == noErr)
+ {
+
+ if (aEqual || (aOrder == 0))
+ {
+ return 0;
+ }
+
+ else
+ {
+ return (aOrder > 0) ? 1 : -1;
+ }
+
+ }
+
+ else
+ {
+
+ DNG_REPORT ("UCCompareTextDefault failed");
+
+ return -1;
+
+ }
+
+ }
+
+ else
+ {
+ return 1;
+ }
+
+ }
+
+ else
+ {
+
+ if (aLenB > 0)
+ {
+ return -1;
+ }
+
+ else
+ {
+ return 0;
+ }
+
+ }
+
+ }
+
+ #elif qWinOS
+
+ {
+
+ dng_memory_data aStrA;
+ dng_memory_data aStrB;
+
+ uint32 aLenA = this->Get_UTF16 (aStrA);
+ uint32 aLenB = s .Get_UTF16 (aStrB);
+
+ if (aLenA > 0)
+ {
+
+ if (aLenB > 0)
+ {
+
+ LCID locale = LOCALE_SYSTEM_DEFAULT;
+
+ DWORD aFlags = NORM_IGNOREWIDTH;
+
+ int aOrder = ::CompareStringW (locale,
+ aFlags,
+ (const WCHAR *) aStrA.Buffer_uint16 (),
+ aLenA,
+ (const WCHAR *) aStrB.Buffer_uint16 (),
+ aLenB);
+
+ if (aOrder == CSTR_EQUAL)
+ {
+ return 0;
+ }
+
+ else if (aOrder == CSTR_GREATER_THAN)
+ {
+ return 1;
+ }
+
+ else
+ {
+ return -1;
+ }
+
+ }
+
+ else
+ {
+ return 1;
+ }
+
+ }
+
+ else
+ {
+
+ if (aLenB > 0)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+
+ }
+
+ }
+
+ #else
+
+ // Fallback to a pure Unicode sort order.
+
+ {
+
+ for (uint32 pass = 0; pass < 2; pass++)
+ {
+
+ const char *aPtr = Get ();
+ const char *bPtr = s.Get ();
+
+ while (*aPtr || *bPtr)
+ {
+
+ if (!bPtr)
+ {
+ return 1;
+ }
+
+ else if (!aPtr)
+ {
+ return -1;
+ }
+
+ uint32 a = DecodeUTF8 (aPtr);
+ uint32 b = DecodeUTF8 (bPtr);
+
+ // Ignore case on first compare pass.
+
+ if (pass == 0)
+ {
+
+ if (a >= (uint32) 'a' && a <= (uint32) 'z')
+ {
+ a = a - (uint32) 'a' + (uint32) 'A';
+ }
+
+ if (b >= (uint32) 'a' && b <= (uint32) 'z')
+ {
+ b = b - (uint32) 'a' + (uint32) 'A';
+ }
+
+ }
+
+ if (b > a)
+ {
+ return 1;
+ }
+
+ else if (a < b)
+ {
+ return -1;
+ }
+
+ }
+
+ }
+
+ }
+
+ #endif
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_string.h b/gpr/source/lib/dng_sdk/dng_string.h
new file mode 100644
index 0000000..41608f1
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_string.h
@@ -0,0 +1,165 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_string.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Text string representation.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_string__
+#define __dng_string__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+#include "dng_memory.h"
+
+/*****************************************************************************/
+
+class dng_string
+ {
+
+ private:
+
+ // Always stored internally as a UTF-8 encoded string.
+
+ dng_memory_data fData;
+
+ public:
+
+ dng_string ();
+
+ dng_string (const dng_string &s);
+
+ dng_string & operator= (const dng_string &s);
+
+ ~dng_string ();
+
+ const char * Get () const;
+
+ bool IsASCII () const;
+
+ void Set (const char *s);
+
+ void Set_ASCII (const char *s);
+
+ void Set_UTF8 (const char *s);
+
+ uint32 Get_SystemEncoding (dng_memory_data &buffer) const;
+
+ void Set_SystemEncoding (const char *s);
+
+ bool ValidSystemEncoding () const;
+
+ void Set_JIS_X208_1990 (const char *s);
+
+ static uint32 DecodeUTF8 (const char *&s,
+ uint32 maxBytes = 6,
+ bool *isValid = NULL);
+
+ static bool IsUTF8 (const char *s);
+
+ void Set_UTF8_or_System (const char *s);
+
+ uint32 Get_UTF16 (dng_memory_data &buffer) const;
+
+ void Set_UTF16 (const uint16 *s);
+
+ void Clear ();
+
+ void Truncate (uint32 maxBytes);
+
+ bool TrimTrailingBlanks ();
+
+ bool TrimLeadingBlanks ();
+
+ bool IsEmpty () const;
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ uint32 Length () const;
+
+ bool operator== (const dng_string &s) const;
+
+ bool operator!= (const dng_string &s) const
+ {
+ return !(*this == s);
+ }
+
+ // A utility for doing case insensitive comparisons on strings...
+
+ static bool Matches (const char *t,
+ const char *s,
+ bool case_sensitive = false);
+
+ // ...wrapped up for use with dng_string.
+
+ bool Matches (const char *s,
+ bool case_sensitive = false) const;
+
+ bool StartsWith (const char *s,
+ bool case_sensitive = false) const;
+
+ bool EndsWith (const char *s,
+ bool case_sensitive = false) const;
+
+ bool Contains (const char *s,
+ bool case_sensitive = false,
+ int32 *match_offset = NULL) const;
+
+ bool Replace (const char *old_string,
+ const char *new_string,
+ bool case_sensitive = true);
+
+ bool TrimLeading (const char *s,
+ bool case_sensitive = false);
+
+ void Append (const char *s);
+
+ void SetUppercase ();
+
+ void SetLowercase ();
+
+ void SetLineEndings (char ending);
+
+ void SetLineEndingsToNewLines ()
+ {
+ SetLineEndings ('\n');
+ }
+
+ void SetLineEndingsToReturns ()
+ {
+ SetLineEndings ('\r');
+ }
+
+ void StripLowASCII ();
+
+ void ForceASCII ();
+
+ int32 Compare (const dng_string &s) const;
+
+ // A utility to convert fields of numbers into comma separated numbers.
+
+ void NormalizeAsCommaSeparatedNumbers ();
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_string_list.cpp b/gpr/source/lib/dng_sdk/dng_string_list.cpp
new file mode 100644
index 0000000..25595f4
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_string_list.cpp
@@ -0,0 +1,162 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_string_list.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_string_list.h"
+
+#include "dng_bottlenecks.h"
+#include "dng_exceptions.h"
+#include "dng_string.h"
+#include "dng_utils.h"
+
+#include "gpr_allocator.h"
+
+/*****************************************************************************/
+
+dng_string_list::dng_string_list ()
+
+ : fCount (0)
+ , fAllocated (0)
+ , fList (NULL)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_string_list::~dng_string_list ()
+ {
+
+ Clear ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_string_list::Allocate (uint32 minSize)
+ {
+
+ if (fAllocated < minSize)
+ {
+
+ uint32 newSize = Max_uint32 (minSize, fAllocated * 2);
+
+ dng_string **list = (dng_string **)gpr_global_malloc (newSize * sizeof (dng_string *));
+
+ if (!list)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ if (fCount)
+ {
+
+ DoCopyBytes (fList, list, fCount * (uint32) sizeof (dng_string *));
+
+ }
+
+ if (fList)
+ {
+ gpr_global_free( fList );
+ }
+
+ fList = list;
+
+ fAllocated = newSize;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_string_list::Insert (uint32 index,
+ const dng_string &s)
+ {
+
+ Allocate (fCount + 1);
+
+ dng_string *ss = new dng_string (s);
+
+ if (!ss)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ fCount++;
+
+ for (uint32 j = fCount - 1; j > index; j--)
+ {
+
+ fList [j] = fList [j - 1];
+
+ }
+
+ fList [index] = ss;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_string_list::Contains (const dng_string &s) const
+ {
+
+ for (uint32 j = 0; j < fCount; j++)
+ {
+
+ if ((*this) [j] == s)
+ {
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_string_list::Clear ()
+ {
+
+ if (fList)
+ {
+
+ for (uint32 index = 0; index < fCount; index++)
+ {
+
+ delete fList [index];
+
+ }
+
+ gpr_global_free( fList );
+
+ fList = NULL;
+
+ }
+
+ fCount = 0;
+ fAllocated = 0;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_string_list.h b/gpr/source/lib/dng_sdk/dng_string_list.h
new file mode 100644
index 0000000..c2e78d8
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_string_list.h
@@ -0,0 +1,86 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_string_list.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_string_list__
+#define __dng_string_list__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_string_list
+ {
+
+ private:
+
+ uint32 fCount;
+
+ uint32 fAllocated;
+
+ dng_string **fList;
+
+ public:
+
+ dng_string_list ();
+
+ ~dng_string_list ();
+
+ uint32 Count () const
+ {
+ return fCount;
+ }
+
+ dng_string & operator[] (uint32 index)
+ {
+ return *(fList [index]);
+ }
+
+ const dng_string & operator[] (uint32 index) const
+ {
+ return *(fList [index]);
+ }
+
+ void Allocate (uint32 minSize);
+
+ void Insert (uint32 index,
+ const dng_string &s);
+
+ void Append (const dng_string &s)
+ {
+ Insert (Count (), s);
+ }
+
+ bool Contains (const dng_string &s) const;
+
+ void Clear ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_string_list (const dng_string_list &list);
+
+ dng_string_list & operator= (const dng_string_list &list);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tag_codes.h b/gpr/source/lib/dng_sdk/dng_tag_codes.h
new file mode 100644
index 0000000..f1332fc
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tag_codes.h
@@ -0,0 +1,543 @@
+/*****************************************************************************/
+// Copyright 2006-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tag_codes.h#3 $ */
+/* $DateTime: 2012/05/31 13:27:06 $ */
+/* $Change: 832568 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_tag_codes__
+#define __dng_tag_codes__
+
+/*****************************************************************************/
+
+// TIFF tags 50706 through 50741 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2003-11-04 & 2003-12-02, purpose "Digital Negative".
+
+// TIFF tags 50778 through 50781 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2004-08-17, purpose "Digital Negative".
+
+// TIFF tags 50827 through 50834 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2004-12-06, purpose "Digital Negative".
+
+// TIFF tag number 50879 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2006-03-23, purpose "Digital Negative".
+
+// TIFF compression numbers 34892 through 34895 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2003-11-04, purpose "Digital Negative".
+
+// TIFF tags numbers 50931 through 50942 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2007-04-30, purpose "Digital Negative".
+
+// TIFF tags numbers 50964 through 50975 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2007-12-17, purpose "Digital Negative".
+
+// TIFF tags numbers 50981 through 50982 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2008-04-01, purpose "Digital Negative".
+
+// TIFF tags numbers 51008 through 51009 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2008-10-15, purpose "Digital Negative".
+
+// TIFF tag number 51022 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2008-12-15, purpose "Digital Negative".
+
+// TIFF tag number 51041 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2009-5-7, purpose "Digital Negative".
+
+// TIFF tags numbers 51089 through 51091 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2011-07-01, purpose "Digital Negative".
+
+// TIFF tags numbers 51107 through 51110 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2011-09-22, purpose "Digital Negative".
+
+// TIFF tag number 51111 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2011-10-07, purpose "Digital Negative".
+
+// TIFF tags numbers 51112 through 51114 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2011-10-25, purpose "Digital Negative".
+
+// TIFF tags number 51125 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2012-05-31, purpose "Digital Negative".
+
+/*****************************************************************************/
+
+// TIFF, DNG, TIFF/EP, and Exif tag codes all share the main TIFF tag code
+// number space. In cases where TIFF/EP and Exif have different values for
+// tags with the same name, "Exif" is appended to the name of the Exif version
+// of the tag.
+
+enum
+ {
+ tcNewSubFileType = 254,
+ tcSubFileType = 255,
+ tcImageWidth = 256,
+ tcImageLength = 257,
+ tcBitsPerSample = 258,
+ tcCompression = 259,
+ tcPhotometricInterpretation = 262,
+ tcThresholding = 263,
+ tcCellWidth = 264,
+ tcCellLength = 265,
+ tcFillOrder = 266,
+ tcImageDescription = 270,
+ tcMake = 271,
+ tcModel = 272,
+ tcStripOffsets = 273,
+ tcOrientation = 274,
+ tcSamplesPerPixel = 277,
+ tcRowsPerStrip = 278,
+ tcStripByteCounts = 279,
+ tcMinSampleValue = 280,
+ tcMaxSampleValue = 281,
+ tcXResolution = 282,
+ tcYResolution = 283,
+ tcPlanarConfiguration = 284,
+ tcFreeOffsets = 285,
+ tcFreeByteCounts = 286,
+ tcGrayResponseUnit = 290,
+ tcGrayResponseCurve = 291,
+ tcResolutionUnit = 296,
+ tcTransferFunction = 301,
+ tcSoftware = 305,
+ tcDateTime = 306,
+ tcArtist = 315,
+ tcHostComputer = 316,
+ tcPredictor = 317,
+ tcWhitePoint = 318,
+ tcPrimaryChromaticities = 319,
+ tcColorMap = 320,
+ tcTileWidth = 322,
+ tcTileLength = 323,
+ tcTileOffsets = 324,
+ tcTileByteCounts = 325,
+ tcSubIFDs = 330,
+ tcExtraSamples = 338,
+ tcSampleFormat = 339,
+ tcJPEGTables = 347,
+ tcJPEGProc = 512,
+ tcJPEGInterchangeFormat = 513,
+ tcJPEGInterchangeFormatLength = 514,
+ tcYCbCrCoefficients = 529,
+ tcYCbCrSubSampling = 530,
+ tcYCbCrPositioning = 531,
+ tcReferenceBlackWhite = 532,
+ tcXMP = 700,
+ tcKodakCameraSerialNumber = 33405,
+ tcCFARepeatPatternDim = 33421,
+ tcCFAPattern = 33422,
+ tcBatteryLevel = 33423,
+ tcKodakDCRPrivateIFD = 33424,
+ tcCopyright = 33432,
+ tcExposureTime = 33434,
+ tcFNumber = 33437,
+ tcIPTC_NAA = 33723,
+ tcLeafPKTS = 34310,
+ tcAdobeData = 34377,
+ tcExifIFD = 34665,
+ tcICCProfile = 34675,
+ tcExposureProgram = 34850,
+ tcSpectralSensitivity = 34852,
+ tcGPSInfo = 34853,
+ tcISOSpeedRatings = 34855, // EXIF 2.3: PhotographicSensitivity.
+ tcOECF = 34856,
+ tcInterlace = 34857,
+ tcTimeZoneOffset = 34858,
+ tcSelfTimerMode = 34859,
+ tcSensitivityType = 34864,
+ tcStandardOutputSensitivity = 34865,
+ tcRecommendedExposureIndex = 34866,
+ tcISOSpeed = 34867,
+ tcISOSpeedLatitudeyyy = 34868,
+ tcISOSpeedLatitudezzz = 34869,
+ tcExifVersion = 36864,
+ tcDateTimeOriginal = 36867,
+ tcDateTimeDigitized = 36868,
+ tcComponentsConfiguration = 37121,
+ tcCompressedBitsPerPixel = 37122,
+ tcShutterSpeedValue = 37377,
+ tcApertureValue = 37378,
+ tcBrightnessValue = 37379,
+ tcExposureBiasValue = 37380,
+ tcMaxApertureValue = 37381,
+ tcSubjectDistance = 37382,
+ tcMeteringMode = 37383,
+ tcLightSource = 37384,
+ tcFlash = 37385,
+ tcFocalLength = 37386,
+ tcFlashEnergy = 37387,
+ tcSpatialFrequencyResponse = 37388,
+ tcNoise = 37389,
+ tcFocalPlaneXResolution = 37390,
+ tcFocalPlaneYResolution = 37391,
+ tcFocalPlaneResolutionUnit = 37392,
+ tcImageNumber = 37393,
+ tcSecurityClassification = 37394,
+ tcImageHistory = 37395,
+ tcSubjectArea = 37396,
+ tcExposureIndex = 37397,
+ tcTIFF_EP_StandardID = 37398,
+ tcSensingMethod = 37399,
+ tcMakerNote = 37500,
+ tcUserComment = 37510,
+ tcSubsecTime = 37520,
+ tcSubsecTimeOriginal = 37521,
+ tcSubsecTimeDigitized = 37522,
+ tcAdobeLayerData = 37724,
+ tcFlashPixVersion = 40960,
+ tcColorSpace = 40961,
+ tcPixelXDimension = 40962,
+ tcPixelYDimension = 40963,
+ tcRelatedSoundFile = 40964,
+ tcInteroperabilityIFD = 40965,
+ tcFlashEnergyExif = 41483,
+ tcSpatialFrequencyResponseExif = 41484,
+ tcFocalPlaneXResolutionExif = 41486,
+ tcFocalPlaneYResolutionExif = 41487,
+ tcFocalPlaneResolutionUnitExif = 41488,
+ tcSubjectLocation = 41492,
+ tcExposureIndexExif = 41493,
+ tcSensingMethodExif = 41495,
+ tcFileSource = 41728,
+ tcSceneType = 41729,
+ tcCFAPatternExif = 41730,
+ tcCustomRendered = 41985,
+ tcExposureMode = 41986,
+ tcWhiteBalance = 41987,
+ tcDigitalZoomRatio = 41988,
+ tcFocalLengthIn35mmFilm = 41989,
+ tcSceneCaptureType = 41990,
+ tcGainControl = 41991,
+ tcContrast = 41992,
+ tcSaturation = 41993,
+ tcSharpness = 41994,
+ tcDeviceSettingDescription = 41995,
+ tcSubjectDistanceRange = 41996,
+ tcImageUniqueID = 42016,
+ tcCameraOwnerNameExif = 42032,
+ tcCameraSerialNumberExif = 42033,
+ tcLensSpecificationExif = 42034,
+ tcLensMakeExif = 42035,
+ tcLensModelExif = 42036,
+ tcLensSerialNumberExif = 42037,
+ tcGamma = 42240,
+ tcPrintImageMatchingInfo = 50341,
+ tcDNGVersion = 50706,
+ tcDNGBackwardVersion = 50707,
+ tcUniqueCameraModel = 50708,
+ tcLocalizedCameraModel = 50709,
+ tcCFAPlaneColor = 50710,
+ tcCFALayout = 50711,
+ tcLinearizationTable = 50712,
+ tcBlackLevelRepeatDim = 50713,
+ tcBlackLevel = 50714,
+ tcBlackLevelDeltaH = 50715,
+ tcBlackLevelDeltaV = 50716,
+ tcWhiteLevel = 50717,
+ tcDefaultScale = 50718,
+ tcDefaultCropOrigin = 50719,
+ tcDefaultCropSize = 50720,
+ tcColorMatrix1 = 50721,
+ tcColorMatrix2 = 50722,
+ tcCameraCalibration1 = 50723,
+ tcCameraCalibration2 = 50724,
+ tcReductionMatrix1 = 50725,
+ tcReductionMatrix2 = 50726,
+ tcAnalogBalance = 50727,
+ tcAsShotNeutral = 50728,
+ tcAsShotWhiteXY = 50729,
+ tcBaselineExposure = 50730,
+ tcBaselineNoise = 50731,
+ tcBaselineSharpness = 50732,
+ tcBayerGreenSplit = 50733,
+ tcLinearResponseLimit = 50734,
+ tcCameraSerialNumber = 50735,
+ tcLensInfo = 50736,
+ tcChromaBlurRadius = 50737,
+ tcAntiAliasStrength = 50738,
+ tcShadowScale = 50739,
+ tcDNGPrivateData = 50740,
+ tcMakerNoteSafety = 50741,
+ tcCalibrationIlluminant1 = 50778,
+ tcCalibrationIlluminant2 = 50779,
+ tcBestQualityScale = 50780,
+ tcRawDataUniqueID = 50781,
+ tcOriginalRawFileName = 50827,
+ tcOriginalRawFileData = 50828,
+ tcActiveArea = 50829,
+ tcMaskedAreas = 50830,
+ tcAsShotICCProfile = 50831,
+ tcAsShotPreProfileMatrix = 50832,
+ tcCurrentICCProfile = 50833,
+ tcCurrentPreProfileMatrix = 50834,
+ tcColorimetricReference = 50879,
+ tcCameraCalibrationSignature = 50931,
+ tcProfileCalibrationSignature = 50932,
+ tcExtraCameraProfiles = 50933,
+ tcAsShotProfileName = 50934,
+ tcNoiseReductionApplied = 50935,
+ tcProfileName = 50936,
+ tcProfileHueSatMapDims = 50937,
+ tcProfileHueSatMapData1 = 50938,
+ tcProfileHueSatMapData2 = 50939,
+ tcProfileToneCurve = 50940,
+ tcProfileEmbedPolicy = 50941,
+ tcProfileCopyright = 50942,
+ tcForwardMatrix1 = 50964,
+ tcForwardMatrix2 = 50965,
+ tcPreviewApplicationName = 50966,
+ tcPreviewApplicationVersion = 50967,
+ tcPreviewSettingsName = 50968,
+ tcPreviewSettingsDigest = 50969,
+ tcPreviewColorSpace = 50970,
+ tcPreviewDateTime = 50971,
+ tcRawImageDigest = 50972,
+ tcOriginalRawFileDigest = 50973,
+ tcSubTileBlockSize = 50974,
+ tcRowInterleaveFactor = 50975,
+ tcProfileLookTableDims = 50981,
+ tcProfileLookTableData = 50982,
+ tcOpcodeList1 = 51008,
+ tcOpcodeList2 = 51009,
+ tcOpcodeList3 = 51022,
+ tcNoiseProfile = 51041,
+ tcOriginalDefaultFinalSize = 51089,
+ tcOriginalBestQualityFinalSize = 51090,
+ tcOriginalDefaultCropSize = 51091,
+ tcProfileHueSatMapEncoding = 51107,
+ tcProfileLookTableEncoding = 51108,
+ tcBaselineExposureOffset = 51109,
+ tcDefaultBlackRender = 51110,
+ tcNewRawImageDigest = 51111,
+ tcRawToPreviewGain = 51112,
+ tcCacheBlob = 51113,
+ tcCacheVersion = 51114,
+ tcDefaultUserCrop = 51125,
+ tcKodakKDCPrivateIFD = 65024
+ };
+
+/*****************************************************************************/
+
+// Additional values that can be passed as IFD parent codes.
+
+enum
+ {
+
+ tcFirstSubIFD = 0x10000,
+ tcLastSubIFD = 0x1FFFF,
+
+ tcFirstChainedIFD = 0x20000,
+ tcLastChainedIFD = 0x2FFFF,
+
+ tcFirstMakerNoteIFD = 0x30000,
+ tcLastMakerNoteIFD = 0x3FFFF,
+
+ tcCanonMakerNote = tcFirstMakerNoteIFD,
+ tcCasioMakerNote,
+ tcEpsonMakerNote,
+ tcFujiMakerNote,
+ tcHasselbladMakerNote,
+ tcKodakMakerNote,
+ tcKodakMakerNote65280,
+ tcLeicaMakerNote,
+ tcMamiyaMakerNote,
+ tcMinoltaMakerNote,
+ tcNikonMakerNote,
+ tcOlympusMakerNote,
+ tcOlympusMakerNote8208,
+ tcOlympusMakerNote8224,
+ tcOlympusMakerNote8240,
+ tcOlympusMakerNote8256,
+ tcOlympusMakerNote8272,
+ tcOlympusMakerNote12288,
+ tcPanasonicMakerNote,
+ tcPentaxMakerNote,
+ tcPhaseOneMakerNote,
+ tcRicohMakerNote,
+ tcRicohMakerNoteCameraInfo,
+ tcSamsungMakerNote,
+ tcSonyMakerNote,
+ tcSonyMakerNoteSubInfo,
+ tcSonyPrivateIFD1,
+ tcSonyPrivateIFD2,
+ tcSonyPrivateIFD3A,
+ tcSonyPrivateIFD3B,
+ tcSonyPrivateIFD3C,
+
+ tcCanonCRW = 0x40000,
+ tcContaxRAW,
+ tcContaxHeader,
+ tcFujiRAF,
+ tcFujiHeader,
+ tcFujiRawInfo1,
+ tcFujiRawInfo2,
+ tcLeafMOS,
+ tcMinoltaMRW,
+ tcPanasonicRAW,
+ tcFoveonX3F,
+ tcJPEG,
+ tcAdobePSD
+
+ };
+
+/*****************************************************************************/
+
+// GPS tag codes are only valid in the GPS IFD.
+
+enum
+ {
+ tcGPSVersionID = 0,
+ tcGPSLatitudeRef = 1,
+ tcGPSLatitude = 2,
+ tcGPSLongitudeRef = 3,
+ tcGPSLongitude = 4,
+ tcGPSAltitudeRef = 5,
+ tcGPSAltitude = 6,
+ tcGPSTimeStamp = 7,
+ tcGPSSatellites = 8,
+ tcGPSStatus = 9,
+ tcGPSMeasureMode = 10,
+ tcGPSDOP = 11,
+ tcGPSSpeedRef = 12,
+ tcGPSSpeed = 13,
+ tcGPSTrackRef = 14,
+ tcGPSTrack = 15,
+ tcGPSImgDirectionRef = 16,
+ tcGPSImgDirection = 17,
+ tcGPSMapDatum = 18,
+ tcGPSDestLatitudeRef = 19,
+ tcGPSDestLatitude = 20,
+ tcGPSDestLongitudeRef = 21,
+ tcGPSDestLongitude = 22,
+ tcGPSDestBearingRef = 23,
+ tcGPSDestBearing = 24,
+ tcGPSDestDistanceRef = 25,
+ tcGPSDestDistance = 26,
+ tcGPSProcessingMethod = 27,
+ tcGPSAreaInformation = 28,
+ tcGPSDateStamp = 29,
+ tcGPSDifferential = 30,
+ tcGPSHPositioningError = 31
+ };
+
+/*****************************************************************************/
+
+// Tag codes used in the Interoperability IFD.
+
+enum
+ {
+ tcInteroperabilityIndex = 0x0001,
+ tcInteroperabilityVersion = 0x0002,
+ tcRelatedImageFileFormat = 0x1000,
+ tcRelatedImageWidth = 0x1001,
+ tcRelatedImageLength = 0x1002
+ };
+
+/*****************************************************************************/
+
+// JPEG marker codes.
+
+enum JpegMarker
+ {
+
+ M_TEM = 0x01,
+
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+ M_DHT = 0xc4,
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+ M_DAC = 0xcc,
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG1 = 0xf1,
+ M_JPG2 = 0xf2,
+ M_JPG3 = 0xf3,
+ M_JPG4 = 0xf4,
+ M_JPG5 = 0xf5,
+ M_JPG6 = 0xf6,
+ M_JPG7 = 0xf7,
+ M_JPG8 = 0xf8,
+ M_JPG9 = 0xf9,
+ M_JPG10 = 0xfa,
+ M_JPG11 = 0xfb,
+ M_JPG12 = 0xfc,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_ERROR = 0x100
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tag_types.cpp b/gpr/source/lib/dng_sdk/dng_tag_types.cpp
new file mode 100644
index 0000000..fcc34e0
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tag_types.cpp
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tag_types.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_tag_types.h"
+
+/*****************************************************************************/
+
+uint32 TagTypeSize (uint32 tagType)
+ {
+
+ switch (tagType)
+ {
+
+ case ttByte:
+ case ttAscii:
+ case ttSByte:
+ case ttUndefined:
+ {
+ return 1;
+ }
+
+ case ttShort:
+ case ttSShort:
+ case ttUnicode:
+ {
+ return 2;
+ }
+
+ case ttLong:
+ case ttSLong:
+ case ttFloat:
+ case ttIFD:
+ {
+ return 4;
+ }
+
+ case ttRational:
+ case ttDouble:
+ case ttSRational:
+ case ttComplex:
+ {
+ return 8;
+ }
+
+ default:
+ break;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tag_types.h b/gpr/source/lib/dng_sdk/dng_tag_types.h
new file mode 100644
index 0000000..46fd6c5
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tag_types.h
@@ -0,0 +1,52 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tag_types.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_tag_types__
+#define __dng_tag_types__
+
+/*****************************************************************************/
+
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+enum
+ {
+ ttByte = 1,
+ ttAscii,
+ ttShort,
+ ttLong,
+ ttRational,
+ ttSByte,
+ ttUndefined,
+ ttSShort,
+ ttSLong,
+ ttSRational,
+ ttFloat,
+ ttDouble,
+ ttIFD,
+ ttUnicode,
+ ttComplex
+ };
+
+/*****************************************************************************/
+
+uint32 TagTypeSize (uint32 tagType);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tag_values.h b/gpr/source/lib/dng_sdk/dng_tag_values.h
new file mode 100644
index 0000000..291b29e
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tag_values.h
@@ -0,0 +1,485 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tag_values.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_tag_values__
+#define __dng_tag_values__
+
+/*****************************************************************************/
+
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+// Values for NewSubFileType tag.
+
+enum
+ {
+
+ // The main image data.
+
+ sfMainImage = 0,
+
+ // Preview image for the primary settings.
+
+ sfPreviewImage = 1,
+
+ // Transparency mask
+
+ sfTransparencyMask = 4,
+
+ // Preview Transparency mask
+
+ sfPreviewMask = sfPreviewImage + sfTransparencyMask,
+
+ // Preview image for non-primary settings.
+
+ sfAltPreviewImage = 0x10001
+
+ };
+
+/******************************************************************************/
+
+// Values for PhotometricInterpretation tag.
+
+enum
+ {
+
+ piWhiteIsZero = 0,
+ piBlackIsZero = 1,
+ piRGB = 2,
+ piRGBPalette = 3,
+ piTransparencyMask = 4,
+ piCMYK = 5,
+ piYCbCr = 6,
+ piCIELab = 8,
+ piICCLab = 9,
+
+ piCFA = 32803, // TIFF-EP spec
+
+ piLinearRaw = 34892
+
+ };
+
+/******************************************************************************/
+
+// Values for PlanarConfiguration tag.
+
+enum
+ {
+
+ pcInterleaved = 1,
+ pcPlanar = 2,
+
+ pcRowInterleaved = 100000 // Internal use only
+
+ };
+
+/******************************************************************************/
+
+// Values for ExtraSamples tag.
+
+enum
+ {
+
+ esUnspecified = 0,
+ esAssociatedAlpha = 1,
+ esUnassociatedAlpha = 2
+
+ };
+
+/******************************************************************************/
+
+// Values for SampleFormat tag.
+
+enum
+ {
+
+ sfUnsignedInteger = 1,
+ sfSignedInteger = 2,
+ sfFloatingPoint = 3,
+ sfUndefined = 4
+
+ };
+
+/******************************************************************************/
+
+// Values for Compression tag.
+
+enum
+ {
+
+ ccUncompressed = 1,
+ ccLZW = 5,
+ ccOldJPEG = 6,
+ ccJPEG = 7,
+ ccDeflate = 8,
+
+#if GPR_WRITING || GPR_READING
+ ccVc5 = 9, // Vc5 compression type
+#endif
+
+ ccPackBits = 32773,
+ ccOldDeflate = 32946,
+
+ // Used in DNG files in places that allow lossless JPEG.
+
+ ccLossyJPEG = 34892
+
+ };
+
+/******************************************************************************/
+
+// Values for Predictor tag.
+
+enum
+ {
+
+ cpNullPredictor = 1,
+ cpHorizontalDifference = 2,
+ cpFloatingPoint = 3,
+
+ cpHorizontalDifferenceX2 = 34892,
+ cpHorizontalDifferenceX4 = 34893,
+ cpFloatingPointX2 = 34894,
+ cpFloatingPointX4 = 34895
+
+ };
+
+/******************************************************************************/
+
+// Values for ResolutionUnit tag.
+
+enum
+ {
+
+ ruNone = 1,
+ ruInch = 2,
+ ruCM = 3,
+ ruMM = 4,
+ ruMicroM = 5
+
+ };
+
+/******************************************************************************/
+
+// Values for LightSource tag.
+
+enum
+ {
+
+ lsUnknown = 0,
+
+ lsDaylight = 1,
+ lsFluorescent = 2,
+ lsTungsten = 3,
+ lsFlash = 4,
+ lsFineWeather = 9,
+ lsCloudyWeather = 10,
+ lsShade = 11,
+ lsDaylightFluorescent = 12, // D 5700 - 7100K
+ lsDayWhiteFluorescent = 13, // N 4600 - 5500K
+ lsCoolWhiteFluorescent = 14, // W 3800 - 4500K
+ lsWhiteFluorescent = 15, // WW 3250 - 3800K
+ lsWarmWhiteFluorescent = 16, // L 2600 - 3250K
+ lsStandardLightA = 17,
+ lsStandardLightB = 18,
+ lsStandardLightC = 19,
+ lsD55 = 20,
+ lsD65 = 21,
+ lsD75 = 22,
+ lsD50 = 23,
+ lsISOStudioTungsten = 24,
+
+ lsOther = 255
+
+ };
+
+/******************************************************************************/
+
+// Values for ExposureProgram tag.
+
+enum
+ {
+
+ epUnidentified = 0,
+ epManual = 1,
+ epProgramNormal = 2,
+ epAperturePriority = 3,
+ epShutterPriority = 4,
+ epProgramCreative = 5,
+ epProgramAction = 6,
+ epPortraitMode = 7,
+ epLandscapeMode = 8
+
+ };
+
+/******************************************************************************/
+
+// Values for MeteringMode tag.
+
+enum
+ {
+
+ mmUnidentified = 0,
+ mmAverage = 1,
+ mmCenterWeightedAverage = 2,
+ mmSpot = 3,
+ mmMultiSpot = 4,
+ mmPattern = 5,
+ mmPartial = 6,
+
+ mmOther = 255
+
+ };
+
+/******************************************************************************/
+
+// CFA color codes from the TIFF/EP specification.
+
+enum ColorKeyCode
+ {
+
+ colorKeyRed = 0,
+ colorKeyGreen = 1,
+ colorKeyBlue = 2,
+ colorKeyCyan = 3,
+ colorKeyMagenta = 4,
+ colorKeyYellow = 5,
+ colorKeyWhite = 6,
+
+ colorKeyMaxEnum = 0xFF
+
+ };
+
+/*****************************************************************************/
+
+// Values for the SensitivityType tag.
+
+enum
+ {
+
+ stUnknown = 0,
+
+ stStandardOutputSensitivity = 1,
+ stRecommendedExposureIndex = 2,
+ stISOSpeed = 3,
+ stSOSandREI = 4,
+ stSOSandISOSpeed = 5,
+ stREIandISOSpeed = 6,
+ stSOSandREIandISOSpeed = 7
+
+ };
+
+/*****************************************************************************/
+
+// Values for the ColorimetricReference tag. It specifies the colorimetric
+// reference used for images with PhotometricInterpretation values of CFA
+// or LinearRaw.
+
+enum
+ {
+
+ // Scene referred (default):
+
+ crSceneReferred = 0,
+
+ // Output referred using the parameters of the ICC profile PCS.
+
+ crICCProfilePCS = 1
+
+ };
+
+/*****************************************************************************/
+
+// Values for the ProfileEmbedPolicy tag.
+
+enum
+ {
+
+ // Freely embedable and copyable into installations that encounter this
+ // profile, so long as the profile is only used to process DNG files.
+
+ pepAllowCopying = 0,
+
+ // Can be embeded in a DNG for portable processing, but cannot be used
+ // to process other files that the profile is not embedded in.
+
+ pepEmbedIfUsed = 1,
+
+ // Can only be used if installed on the machine processing the file.
+ // Note that this only applies to stand-alone profiles. Profiles that
+ // are already embedded inside a DNG file allowed to remain embedded
+ // in that DNG, even if the DNG is resaved.
+
+ pepEmbedNever = 2,
+
+ // No restricts on profile use or embedding.
+
+ pepNoRestrictions = 3
+
+ };
+
+/*****************************************************************************/
+
+// Values for the ProfileHueSatMapEncoding and ProfileLookTableEncoding tags.
+
+enum
+ {
+
+ // 1. Convert linear ProPhoto RGB values to HSV.
+ // 2. Use the HSV coordinates to index into the color table.
+ // 3. Apply color table result to the original HSV values.
+ // 4. Convert modified HSV values back to linear ProPhoto RGB.
+
+ encoding_Linear = 0,
+
+ // 1. Convert linear ProPhoto RGB values to HSV.
+ // 2. Encode V coordinate using sRGB encoding curve.
+ // 3. Use the encoded HSV coordinates to index into the color table.
+ // 4. Apply color table result to the encoded values from step 2.
+ // 5. Decode V coordinate using sRGB decoding curve (inverse of step 2).
+ // 6. Convert HSV values back to linear ProPhoto RGB (inverse of step 1).
+
+ encoding_sRGB = 1
+
+ };
+
+/*****************************************************************************/
+
+// Values for the DefaultBlackRender tag.
+
+enum
+ {
+
+ // By default, the renderer applies (possibly auto-calculated) black subtraction
+ // prior to the look table.
+
+ defaultBlackRender_Auto = 0,
+
+ // By default, the renderer does not apply any black subtraction prior to the
+ // look table.
+
+ defaultBlackRender_None = 1
+
+ };
+
+/*****************************************************************************/
+
+// Values for the PreviewColorSpace tag.
+
+enum PreviewColorSpaceEnum
+ {
+
+ previewColorSpace_Unknown = 0,
+ previewColorSpace_GrayGamma22 = 1,
+ previewColorSpace_sRGB = 2,
+ previewColorSpace_AdobeRGB = 3,
+ previewColorSpace_ProPhotoRGB = 4,
+
+ previewColorSpace_LastValid = previewColorSpace_ProPhotoRGB,
+
+ previewColorSpace_MaxEnum = 0xFFFFFFFF
+
+ };
+
+/*****************************************************************************/
+
+// Values for CacheVersion tag.
+
+enum
+ {
+
+ // The low-16 bits are a rendering version number.
+
+ cacheVersionMask = 0x0FFFF,
+
+ // Default cache version.
+
+ cacheVersionDefault = 0x00100,
+
+ // Is this an integer preview of a floating point image?
+
+ cacheVersionDefloated = 0x10000,
+
+ // Is this an flattening preview of an image with tranparency?
+
+ cacheVersionFlattened = 0x20000,
+
+ // Was this preview build using a the default baseline multi-channel
+ // CFA merge (i.e. only using the first channel)?
+
+ cacheVersionFakeMerge = 0x40000
+
+ };
+
+/*****************************************************************************/
+
+// TIFF-style byte order markers.
+
+enum
+ {
+
+ byteOrderII = 0x4949, // 'II'
+ byteOrderMM = 0x4D4D // 'MM'
+
+ };
+
+/*****************************************************************************/
+
+// "Magic" numbers.
+
+enum
+ {
+
+ // DNG related.
+
+ magicTIFF = 42, // TIFF (and DNG)
+ magicExtendedProfile = 0x4352, // 'CR'
+ magicRawCache = 1022, // Raw cache (fast load data)
+
+ // Other raw formats - included here so the DNG SDK can parse them.
+
+ magicPanasonic = 85,
+ magicOlympusA = 0x4F52,
+ magicOlympusB = 0x5352
+
+ };
+
+/*****************************************************************************/
+
+// DNG Version numbers
+
+enum
+ {
+
+ dngVersion_None = 0,
+
+ dngVersion_1_0_0_0 = 0x01000000,
+ dngVersion_1_1_0_0 = 0x01010000,
+ dngVersion_1_2_0_0 = 0x01020000,
+ dngVersion_1_3_0_0 = 0x01030000,
+ dngVersion_1_4_0_0 = 0x01040000,
+
+ dngVersion_Current = dngVersion_1_4_0_0,
+
+ dngVersion_SaveDefault = dngVersion_Current
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_temperature.cpp b/gpr/source/lib/dng_sdk/dng_temperature.cpp
new file mode 100644
index 0000000..3635d91
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_temperature.cpp
@@ -0,0 +1,259 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_temperature.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+#include "dng_temperature.h"
+
+#include "dng_xy_coord.h"
+
+/*****************************************************************************/
+
+// Scale factor between distances in uv space to a more user friendly "tint"
+// parameter.
+
+static const real64 kTintScale = -3000.0;
+
+/*****************************************************************************/
+
+// Table from Wyszecki & Stiles, "Color Science", second edition, page 228.
+
+struct ruvt
+ {
+ real64 r;
+ real64 u;
+ real64 v;
+ real64 t;
+ };
+
+static const ruvt kTempTable [] =
+ {
+ { 0, 0.18006, 0.26352, -0.24341 },
+ { 10, 0.18066, 0.26589, -0.25479 },
+ { 20, 0.18133, 0.26846, -0.26876 },
+ { 30, 0.18208, 0.27119, -0.28539 },
+ { 40, 0.18293, 0.27407, -0.30470 },
+ { 50, 0.18388, 0.27709, -0.32675 },
+ { 60, 0.18494, 0.28021, -0.35156 },
+ { 70, 0.18611, 0.28342, -0.37915 },
+ { 80, 0.18740, 0.28668, -0.40955 },
+ { 90, 0.18880, 0.28997, -0.44278 },
+ { 100, 0.19032, 0.29326, -0.47888 },
+ { 125, 0.19462, 0.30141, -0.58204 },
+ { 150, 0.19962, 0.30921, -0.70471 },
+ { 175, 0.20525, 0.31647, -0.84901 },
+ { 200, 0.21142, 0.32312, -1.0182 },
+ { 225, 0.21807, 0.32909, -1.2168 },
+ { 250, 0.22511, 0.33439, -1.4512 },
+ { 275, 0.23247, 0.33904, -1.7298 },
+ { 300, 0.24010, 0.34308, -2.0637 },
+ { 325, 0.24702, 0.34655, -2.4681 },
+ { 350, 0.25591, 0.34951, -2.9641 },
+ { 375, 0.26400, 0.35200, -3.5814 },
+ { 400, 0.27218, 0.35407, -4.3633 },
+ { 425, 0.28039, 0.35577, -5.3762 },
+ { 450, 0.28863, 0.35714, -6.7262 },
+ { 475, 0.29685, 0.35823, -8.5955 },
+ { 500, 0.30505, 0.35907, -11.324 },
+ { 525, 0.31320, 0.35968, -15.628 },
+ { 550, 0.32129, 0.36011, -23.325 },
+ { 575, 0.32931, 0.36038, -40.770 },
+ { 600, 0.33724, 0.36051, -116.45 }
+ };
+
+/*****************************************************************************/
+
+void dng_temperature::Set_xy_coord (const dng_xy_coord &xy)
+ {
+
+ // Convert to uv space.
+
+ real64 u = 2.0 * xy.x / (1.5 - xy.x + 6.0 * xy.y);
+ real64 v = 3.0 * xy.y / (1.5 - xy.x + 6.0 * xy.y);
+
+ // Search for line pair coordinate is between.
+
+ real64 last_dt = 0.0;
+
+ real64 last_dv = 0.0;
+ real64 last_du = 0.0;
+
+ for (uint32 index = 1; index <= 30; index++)
+ {
+
+ // Convert slope to delta-u and delta-v, with length 1.
+
+ real64 du = 1.0;
+ real64 dv = kTempTable [index] . t;
+
+ real64 len = sqrt (1.0 + dv * dv);
+
+ du /= len;
+ dv /= len;
+
+ // Find delta from black body point to test coordinate.
+
+ real64 uu = u - kTempTable [index] . u;
+ real64 vv = v - kTempTable [index] . v;
+
+ // Find distance above or below line.
+
+ real64 dt = - uu * dv + vv * du;
+
+ // If below line, we have found line pair.
+
+ if (dt <= 0.0 || index == 30)
+ {
+
+ // Find fractional weight of two lines.
+
+ if (dt > 0.0)
+ dt = 0.0;
+
+ dt = -dt;
+
+ real64 f;
+
+ if (index == 1)
+ {
+ f = 0.0;
+ }
+ else
+ {
+ f = dt / (last_dt + dt);
+ }
+
+ // Interpolate the temperature.
+
+ fTemperature = 1.0E6 / (kTempTable [index - 1] . r * f +
+ kTempTable [index ] . r * (1.0 - f));
+
+ // Find delta from black body point to test coordinate.
+
+ uu = u - (kTempTable [index - 1] . u * f +
+ kTempTable [index ] . u * (1.0 - f));
+
+ vv = v - (kTempTable [index - 1] . v * f +
+ kTempTable [index ] . v * (1.0 - f));
+
+ // Interpolate vectors along slope.
+
+ du = du * (1.0 - f) + last_du * f;
+ dv = dv * (1.0 - f) + last_dv * f;
+
+ len = sqrt (du * du + dv * dv);
+
+ du /= len;
+ dv /= len;
+
+ // Find distance along slope.
+
+ fTint = (uu * du + vv * dv) * kTintScale;
+
+ break;
+
+ }
+
+ // Try next line pair.
+
+ last_dt = dt;
+
+ last_du = du;
+ last_dv = dv;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xy_coord dng_temperature::Get_xy_coord () const
+ {
+
+ dng_xy_coord result;
+
+ // Find inverse temperature to use as index.
+
+ real64 r = 1.0E6 / fTemperature;
+
+ // Convert tint to offset is uv space.
+
+ real64 offset = fTint * (1.0 / kTintScale);
+
+ // Search for line pair containing coordinate.
+
+ for (uint32 index = 0; index <= 29; index++)
+ {
+
+ if (r < kTempTable [index + 1] . r || index == 29)
+ {
+
+ // Find relative weight of first line.
+
+ real64 f = (kTempTable [index + 1] . r - r) /
+ (kTempTable [index + 1] . r - kTempTable [index] . r);
+
+ // Interpolate the black body coordinates.
+
+ real64 u = kTempTable [index ] . u * f +
+ kTempTable [index + 1] . u * (1.0 - f);
+
+ real64 v = kTempTable [index ] . v * f +
+ kTempTable [index + 1] . v * (1.0 - f);
+
+ // Find vectors along slope for each line.
+
+ real64 uu1 = 1.0;
+ real64 vv1 = kTempTable [index] . t;
+
+ real64 uu2 = 1.0;
+ real64 vv2 = kTempTable [index + 1] . t;
+
+ real64 len1 = sqrt (1.0 + vv1 * vv1);
+ real64 len2 = sqrt (1.0 + vv2 * vv2);
+
+ uu1 /= len1;
+ vv1 /= len1;
+
+ uu2 /= len2;
+ vv2 /= len2;
+
+ // Find vector from black body point.
+
+ real64 uu3 = uu1 * f + uu2 * (1.0 - f);
+ real64 vv3 = vv1 * f + vv2 * (1.0 - f);
+
+ real64 len3 = sqrt (uu3 * uu3 + vv3 * vv3);
+
+ uu3 /= len3;
+ vv3 /= len3;
+
+ // Adjust coordinate along this vector.
+
+ u += uu3 * offset;
+ v += vv3 * offset;
+
+ // Convert to xy coordinates.
+
+ result.x = 1.5 * u / (u - 4.0 * v + 2.0);
+ result.y = v / (u - 4.0 * v + 2.0);
+
+ break;
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_temperature.h b/gpr/source/lib/dng_sdk/dng_temperature.h
new file mode 100644
index 0000000..7d662bd
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_temperature.h
@@ -0,0 +1,97 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_temperature.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Representation of color temperature and offset (tint) using black body
+ * radiator definition.
+ */
+
+#ifndef __dng_temperature__
+#define __dng_temperature__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_temperature
+ {
+
+ private:
+
+ real64 fTemperature;
+
+ real64 fTint;
+
+ public:
+
+ dng_temperature ()
+
+ : fTemperature (0.0)
+ , fTint (0.0)
+
+ {
+ }
+
+ dng_temperature (real64 temperature,
+ real64 tint)
+
+ : fTemperature (temperature)
+ , fTint (tint )
+
+ {
+
+ }
+
+ dng_temperature (const dng_xy_coord &xy)
+
+ : fTemperature (0.0)
+ , fTint (0.0)
+
+ {
+ Set_xy_coord (xy);
+ }
+
+ void SetTemperature (real64 temperature)
+ {
+ fTemperature = temperature;
+ }
+
+ real64 Temperature () const
+ {
+ return fTemperature;
+ }
+
+ void SetTint (real64 tint)
+ {
+ fTint = tint;
+ }
+
+ real64 Tint () const
+ {
+ return fTint;
+ }
+
+ void Set_xy_coord (const dng_xy_coord &xy);
+
+ dng_xy_coord Get_xy_coord () const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tile_iterator.cpp b/gpr/source/lib/dng_sdk/dng_tile_iterator.cpp
new file mode 100644
index 0000000..b91a9dc
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tile_iterator.cpp
@@ -0,0 +1,199 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tile_iterator.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_tile_iterator.h"
+
+#include "dng_exceptions.h"
+#include "dng_image.h"
+#include "dng_pixel_buffer.h"
+#include "dng_tag_types.h"
+#include "dng_utils.h"
+
+/*****************************************************************************/
+
+dng_tile_iterator::dng_tile_iterator (const dng_image &image,
+ const dng_rect &area)
+
+ : fArea ()
+ , fTileWidth (0)
+ , fTileHeight (0)
+ , fTileTop (0)
+ , fTileLeft (0)
+ , fRowLeft (0)
+ , fLeftPage (0)
+ , fRightPage (0)
+ , fTopPage (0)
+ , fBottomPage (0)
+ , fHorizontalPage (0)
+ , fVerticalPage (0)
+
+ {
+
+ Initialize (image.RepeatingTile (),
+ area & image.Bounds ());
+
+ }
+
+/*****************************************************************************/
+
+dng_tile_iterator::dng_tile_iterator (const dng_point &tileSize,
+ const dng_rect &area)
+
+ : fArea ()
+ , fTileWidth (0)
+ , fTileHeight (0)
+ , fTileTop (0)
+ , fTileLeft (0)
+ , fRowLeft (0)
+ , fLeftPage (0)
+ , fRightPage (0)
+ , fTopPage (0)
+ , fBottomPage (0)
+ , fHorizontalPage (0)
+ , fVerticalPage (0)
+
+ {
+
+ dng_rect tile (area);
+
+ tile.b = Min_int32 (tile.b, tile.t + tileSize.v);
+ tile.r = Min_int32 (tile.r, tile.l + tileSize.h);
+
+ Initialize (tile,
+ area);
+
+ }
+
+/*****************************************************************************/
+
+dng_tile_iterator::dng_tile_iterator (const dng_rect &tile,
+ const dng_rect &area)
+
+ : fArea ()
+ , fTileWidth (0)
+ , fTileHeight (0)
+ , fTileTop (0)
+ , fTileLeft (0)
+ , fRowLeft (0)
+ , fLeftPage (0)
+ , fRightPage (0)
+ , fTopPage (0)
+ , fBottomPage (0)
+ , fHorizontalPage (0)
+ , fVerticalPage (0)
+
+ {
+
+ Initialize (tile,
+ area);
+
+ }
+
+/*****************************************************************************/
+
+void dng_tile_iterator::Initialize (const dng_rect &tile,
+ const dng_rect &area)
+ {
+
+ fArea = area;
+
+ if (area.IsEmpty ())
+ {
+
+ fVerticalPage = 0;
+ fBottomPage = -1;
+
+ return;
+
+ }
+
+ int32 vOffset = tile.t;
+ int32 hOffset = tile.l;
+
+ int32 tileHeight = tile.b - vOffset;
+ int32 tileWidth = tile.r - hOffset;
+
+ fTileHeight = tileHeight;
+ fTileWidth = tileWidth;
+
+ fLeftPage = (fArea.l - hOffset ) / tileWidth;
+ fRightPage = (fArea.r - hOffset - 1) / tileWidth;
+
+ fHorizontalPage = fLeftPage;
+
+ fTopPage = (fArea.t - vOffset ) / tileHeight;
+ fBottomPage = (fArea.b - vOffset - 1) / tileHeight;
+
+ fVerticalPage = fTopPage;
+
+ fTileLeft = fHorizontalPage * tileWidth + hOffset;
+ fTileTop = fVerticalPage * tileHeight + vOffset;
+
+ fRowLeft = fTileLeft;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_tile_iterator::GetOneTile (dng_rect &tile)
+ {
+
+ if (fVerticalPage > fBottomPage)
+ {
+ return false;
+ }
+
+ if (fVerticalPage > fTopPage)
+ tile.t = fTileTop;
+ else
+ tile.t = fArea.t;
+
+ if (fVerticalPage < fBottomPage)
+ tile.b = fTileTop + fTileHeight;
+ else
+ tile.b = fArea.b;
+
+ if (fHorizontalPage > fLeftPage)
+ tile.l = fTileLeft;
+ else
+ tile.l = fArea.l;
+
+ if (fHorizontalPage < fRightPage)
+ tile.r = fTileLeft + fTileWidth;
+ else
+ tile.r = fArea.r;
+
+ if (fHorizontalPage < fRightPage)
+ {
+ fHorizontalPage++;
+ fTileLeft += fTileWidth;
+ }
+
+ else
+ {
+
+ fVerticalPage++;
+ fTileTop += fTileHeight;
+
+ fHorizontalPage = fLeftPage;
+ fTileLeft = fRowLeft;
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tile_iterator.h b/gpr/source/lib/dng_sdk/dng_tile_iterator.h
new file mode 100644
index 0000000..98bdb1c
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tile_iterator.h
@@ -0,0 +1,76 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tile_iterator.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_tile_iterator__
+#define __dng_tile_iterator__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_point.h"
+#include "dng_rect.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_tile_iterator
+ {
+
+ private:
+
+ dng_rect fArea;
+
+ int32 fTileWidth;
+ int32 fTileHeight;
+
+ int32 fTileTop;
+ int32 fTileLeft;
+
+ int32 fRowLeft;
+
+ int32 fLeftPage;
+ int32 fRightPage;
+
+ int32 fTopPage;
+ int32 fBottomPage;
+
+ int32 fHorizontalPage;
+ int32 fVerticalPage;
+
+ public:
+
+ dng_tile_iterator (const dng_image &image,
+ const dng_rect &area);
+
+ dng_tile_iterator (const dng_point &tileSize,
+ const dng_rect &area);
+
+ dng_tile_iterator (const dng_rect &tile,
+ const dng_rect &area);
+
+ bool GetOneTile (dng_rect &tile);
+
+ private:
+
+ void Initialize (const dng_rect &tile,
+ const dng_rect &area);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tone_curve.cpp b/gpr/source/lib/dng_sdk/dng_tone_curve.cpp
new file mode 100644
index 0000000..466ca95
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tone_curve.cpp
@@ -0,0 +1,138 @@
+/*****************************************************************************/
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tone_curve.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_tone_curve.h"
+
+#include "dng_assertions.h"
+#include "dng_spline.h"
+#include "dng_utils.h"
+
+/******************************************************************************/
+
+dng_tone_curve::dng_tone_curve ()
+
+ : fCoord ()
+
+ {
+
+ SetNull ();
+
+ }
+
+/******************************************************************************/
+
+bool dng_tone_curve::operator== (const dng_tone_curve &curve) const
+ {
+
+ return fCoord == curve.fCoord;
+
+ }
+
+/******************************************************************************/
+
+void dng_tone_curve::SetNull ()
+ {
+
+ fCoord.resize (2);
+
+ fCoord [0].h = 0.0;
+ fCoord [0].v = 0.0;
+
+ fCoord [1].h = 1.0;
+ fCoord [1].v = 1.0;
+
+ }
+
+/******************************************************************************/
+
+bool dng_tone_curve::IsNull () const
+ {
+
+ dng_tone_curve temp;
+
+ return (*this == temp);
+
+ }
+
+/******************************************************************************/
+
+void dng_tone_curve::SetInvalid ()
+ {
+
+ fCoord.clear ();
+
+ }
+
+/******************************************************************************/
+
+bool dng_tone_curve::IsValid () const
+ {
+
+ if (fCoord.size () < 2)
+ {
+
+ return false;
+
+ }
+
+ for (uint32 j = 0; j < fCoord.size (); j++)
+ {
+
+ if (fCoord [j] . h < 0.0 || fCoord [j] . h > 1.0 ||
+ fCoord [j] . v < 0.0 || fCoord [j] . v > 1.0)
+ {
+
+ return false;
+
+ }
+
+ if (j > 0)
+ {
+
+ if (fCoord [j] . h <= fCoord [j - 1] . h)
+ {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/******************************************************************************/
+
+void dng_tone_curve::Solve (dng_spline_solver &solver) const
+ {
+
+ solver.Reset ();
+
+ for (uint32 index = 0; index < fCoord.size (); index++)
+ {
+
+ solver.Add (fCoord [index].h,
+ fCoord [index].v);
+
+ }
+
+ solver.Solve ();
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_tone_curve.h b/gpr/source/lib/dng_sdk/dng_tone_curve.h
new file mode 100644
index 0000000..e85052f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_tone_curve.h
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_tone_curve.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Representation of 1-dimensional tone curve.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_tone_curve__
+#define __dng_tone_curve__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_point.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+class dng_tone_curve
+ {
+
+ public:
+
+ std::vector<dng_point_real64> fCoord;
+
+ public:
+
+ dng_tone_curve ();
+
+ bool operator== (const dng_tone_curve &curve) const;
+
+ bool operator!= (const dng_tone_curve &curve) const
+ {
+ return !(*this == curve);
+ }
+
+ void SetNull ();
+
+ bool IsNull () const;
+
+ void SetInvalid ();
+
+ bool IsValid () const;
+
+ void Solve (dng_spline_solver &solver) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_types.h b/gpr/source/lib/dng_sdk/dng_types.h
new file mode 100644
index 0000000..2e944c6
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_types.h
@@ -0,0 +1,112 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_types.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_types__
+#define __dng_types__
+
+/*****************************************************************************/
+
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+// Standard integer types.
+
+#ifdef _MSC_VER
+#include <stddef.h>
+#endif
+
+#include <stdint.h>
+
+/*****************************************************************************/
+
+#if qDNGUseStdInt || 1
+
+typedef int8_t int8;
+typedef int16_t int16;
+typedef int32_t int32;
+typedef int64_t int64;
+
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+
+#else
+
+typedef signed char int8;
+typedef signed short int16;
+#if __LP64__
+typedef signed int int32;
+#else
+typedef signed long int32;
+#endif
+typedef signed long long int64;
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+/*Some Mac OS X 10.5 SDK headers already define uint32.*/
+#ifndef _UINT32
+#if __LP64__
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+#define _UINT32
+#endif
+typedef unsigned long long uint64;
+
+#endif
+
+typedef uintptr_t uintptr;
+
+/*****************************************************************************/
+
+typedef float real32;
+typedef double real64;
+
+/*****************************************************************************/
+
+/// \def Build a Macintosh style four-character constant in a compiler safe way.
+
+#define DNG_CHAR4(a,b,c,d) ((((uint32) a) << 24) |\
+ (((uint32) b) << 16) |\
+ (((uint32) c) << 8) |\
+ (((uint32) d) ))
+
+/*****************************************************************************/
+
+// #include "stdc_includes.h"
+#include <math.h>
+
+/*****************************************************************************/
+
+// Visual Studio now prefers _hypot to hypot
+
+#ifdef _MSC_VER
+
+#ifdef hypot
+#undef hypot
+#endif
+
+#define hypot _hypot
+
+#endif
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_uncopyable.h b/gpr/source/lib/dng_sdk/dng_uncopyable.h
new file mode 100644
index 0000000..f25745a
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_uncopyable.h
@@ -0,0 +1,48 @@
+/*****************************************************************************/
+// Copyright 2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_uncopyable.h#1 $ */
+/* $DateTime: 2012/09/05 12:31:51 $ */
+/* $Change: 847652 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_uncopyable__
+#define __dng_uncopyable__
+
+/*****************************************************************************/
+
+// Virtual base class to prevent object copies.
+
+class dng_uncopyable
+ {
+
+ protected:
+
+ dng_uncopyable ()
+ {
+ }
+
+ ~dng_uncopyable ()
+ {
+ }
+
+ private:
+
+ dng_uncopyable (const dng_uncopyable &);
+
+ dng_uncopyable & operator= (const dng_uncopyable &);
+
+ };
+
+/*****************************************************************************/
+
+#endif // __dng_uncopyable__
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_utils.cpp b/gpr/source/lib/dng_sdk/dng_utils.cpp
new file mode 100644
index 0000000..d9f7224
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_utils.cpp
@@ -0,0 +1,706 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_utils.cpp#3 $ */
+/* $DateTime: 2012/08/12 15:38:38 $ */
+/* $Change: 842799 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_utils.h"
+
+#include "dng_area_task.h"
+#include "dng_assertions.h"
+#include "dng_bottlenecks.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_flags.h"
+#include "dng_point.h"
+#include "dng_rect.h"
+#include "dng_tile_iterator.h"
+
+#if qMacOS && qEnableCarbon
+#include <CoreServices/CoreServices.h>
+#endif
+
+#if qiPhone || qMacOS
+// these provide timers
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif
+
+#if qWinOS
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <stdarg.h> // for va_start/va_end
+#endif
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+#if qDNGDebug
+
+/*****************************************************************************/
+
+#if qMacOS
+ #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
+#elif qWinOS
+ #if qDNG64Bit
+ // no inline assembly on Win 64-bit, so use DebugBreak
+ #define DNG_DEBUG_BREAK DebugBreak()
+ #else
+ #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
+ #endif
+#elif qiPhone
+ // simulator is running on Intel
+ #if qiPhoneSimulator
+ #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
+ #else
+ // The debugger doesn't restore program counter after this is called.
+ // Caller must move program counter past line to continue.
+ // As of iOS5/xCode 4.2, recovery may not be possible.
+ #define DNG_DEBUG_BREAK __asm__ volatile ("bkpt 1")
+ #endif
+#elif qAndroid
+ #define DNG_DEBUG_BREAK __asm__ volatile ("bkpt 1")
+#elif qLinux
+ #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
+#else
+ #define DNG_DEBUG_BREAK
+#endif
+
+/*****************************************************************************/
+
+bool gPrintAsserts = true;
+bool gBreakOnAsserts = true;
+
+/*****************************************************************************/
+
+void dng_show_message (const char *s)
+ {
+
+ #if qDNGPrintMessages
+
+ // display the message
+ if (gPrintAsserts)
+ fprintf (stderr, "%s\n", s);
+
+ #elif qiPhone || qAndroid || qLinux
+
+ if (gPrintAsserts)
+ fprintf (stderr, "%s\n", s);
+
+ // iOS doesn't print a message to the console like DebugStr and MessageBox do, so we have to do both
+ // You'll have to advance the program counter manually past this statement
+ if (gBreakOnAsserts)
+ DNG_DEBUG_BREAK;
+
+ #elif qMacOS
+
+ if (gBreakOnAsserts)
+ {
+ // truncate the to 255 chars
+ char ss [256];
+
+ uint32 len = strlen (s);
+ if (len > 255)
+ len = 255;
+ strncpy (&(ss [1]), s, len );
+ ss [0] = (unsigned char) len;
+
+ DebugStr ((unsigned char *) ss);
+ }
+ else if (gPrintAsserts)
+ {
+ fprintf (stderr, "%s\n", s);
+ }
+
+ #elif qWinOS
+
+ // display a dialog
+ // This is not thread safe. Multiple message boxes can be launched.
+ // Should also be launched in its own thread so main msg queue isn't thrown off.
+ if (gBreakOnAsserts)
+ MessageBoxA (NULL, (LPSTR) s, NULL, MB_OK);
+ else if (gPrintAsserts)
+ fprintf (stderr, "%s\n", s);
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+void dng_show_message_f (const char *fmt, ... )
+ {
+
+ char buffer [1024];
+
+ va_list ap;
+ va_start (ap, fmt);
+
+ vsnprintf (buffer, sizeof (buffer), fmt, ap);
+
+ va_end (ap);
+
+ dng_show_message (buffer);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+real64 TickTimeInSeconds ()
+ {
+
+ #if qWinOS
+
+ // One might think it prudent to cache the frequency here, however
+ // low-power CPU modes can, and do, change the value returned.
+ // Thus the frequencey needs to be retrieved each time.
+
+ // Note that the frequency changing can cause the return
+ // result to jump backwards, which is why the TickCountInSeconds
+ // (below) also exists.
+
+ // Just plug in laptop when doing timings to minimize this.
+ // QPC/QPH is a slow call compared to rtdsc.
+
+ #if qImagecore
+
+ // You should be plugged-in when measuring.
+
+ static real64 freqMultiplier = 0.0;
+
+ if (freqMultiplier == 0.0)
+ {
+
+ LARGE_INTEGER freq;
+
+ QueryPerformanceFrequency (&freq);
+
+ freqMultiplier = 1.0 / (real64) freq.QuadPart;
+
+ }
+
+ #else
+
+ LARGE_INTEGER freq;
+
+ QueryPerformanceFrequency (&freq);
+
+ real64 freqMultiplier = 1.0 / (real64) freq.QuadPart;
+
+ #endif // qImagecore
+
+ LARGE_INTEGER cycles;
+
+ QueryPerformanceCounter (&cycles);
+
+ return (real64) cycles.QuadPart * freqMultiplier;
+
+ #elif qiPhone || qMacOS
+
+ // this is switching Mac to high performance timer
+ // and this is also the timer for iPhone
+
+ // assume frequency is unchanging, requesting frequency every time call
+ // is too slow. multiple cores, different frequency ?
+
+ static real64 freqMultiplier = 0.0;
+ if (freqMultiplier == 0.0)
+ {
+ mach_timebase_info_data_t freq;
+ mach_timebase_info(&freq);
+
+ // converts from nanos to micros
+ // numer = 125, denom = 3 * 1000
+ freqMultiplier = ((real64)freq.numer / (real64)freq.denom) * 1.0e-9;
+ }
+
+ return mach_absolute_time() * freqMultiplier;
+
+ #elif qAndroid || qLinux
+
+ //this is a fast timer to nanos
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec + (real64)now.tv_nsec * 1.0e-9;
+
+ #else
+
+ // Perhaps a better call exists. (e.g. avoid adjtime effects)
+
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ return tv.tv_sec + (real64)tv.tv_usec * 1.0e-6;
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+real64 TickCountInSeconds ()
+ {
+
+ #if qWinOS
+
+ return GetTickCount () * (1.0 / 1000.0);
+
+ #elif qMacOS && qEnableCarbon
+
+ return TickCount () * (1.0 / 60.0);
+
+ #else
+
+ return TickTimeInSeconds ();
+
+ #endif
+
+ }
+
+/*****************************************************************************/
+
+bool gDNGShowTimers = true;
+
+dng_timer::dng_timer (const char *message)
+
+ : fMessage (message )
+ , fStartTime (TickTimeInSeconds ())
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_timer::~dng_timer ()
+ {
+
+ if (!gDNGShowTimers)
+ return;
+
+ real64 totalTime = TickTimeInSeconds () - fStartTime;
+
+ fprintf (stderr, "%s: %0.3f sec\n", fMessage, totalTime);
+
+ }
+
+/*****************************************************************************/
+
+real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
+ const dng_rect_real64 &rect)
+ {
+
+ real64 distSqr = DistanceSquared (point,
+ rect.TL ());
+
+ distSqr = Max_real64 (distSqr,
+ DistanceSquared (point,
+ rect.BL ()));
+
+ distSqr = Max_real64 (distSqr,
+ DistanceSquared (point,
+ rect.BR ()));
+
+ distSqr = Max_real64 (distSqr,
+ DistanceSquared (point,
+ rect.TR ()));
+
+ return distSqr;
+
+ }
+
+/*****************************************************************************/
+
+real64 MaxDistancePointToRect (const dng_point_real64 &point,
+ const dng_rect_real64 &rect)
+ {
+
+ return sqrt (MaxSquaredDistancePointToRect (point,
+ rect));
+
+ }
+
+/*****************************************************************************/
+
+dng_dither::dng_dither ()
+
+ : fNoiseBuffer ()
+
+ {
+
+ const uint32 kSeed = 1;
+
+ fNoiseBuffer.Allocate (kRNGSize2D * sizeof (uint16));
+
+ uint16 *buffer = fNoiseBuffer.Buffer_uint16 ();
+
+ uint32 seed = kSeed;
+
+ for (uint32 i = 0; i < kRNGSize2D; i++)
+ {
+
+ seed = DNG_Random (seed);
+
+ buffer [i] = (uint16) (seed);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+const dng_dither & dng_dither::Get ()
+ {
+
+ static dng_dither dither;
+
+ return dither;
+
+ }
+
+/*****************************************************************************/
+
+void HistogramArea (dng_host & /* host */,
+ const dng_image &image,
+ const dng_rect &area,
+ uint32 *hist,
+ uint32 maxValue,
+ uint32 plane)
+ {
+
+ DNG_ASSERT (image.PixelType () == ttShort, "Unsupported pixel type");
+
+ DoZeroBytes (hist, (maxValue + 1) * (uint32) sizeof (uint32));
+
+ dng_rect tile;
+
+ dng_tile_iterator iter (image, area);
+
+ while (iter.GetOneTile (tile))
+ {
+
+ dng_const_tile_buffer buffer (image, tile);
+
+ const void *sPtr = buffer.ConstPixel (tile.t,
+ tile.l,
+ plane);
+
+ uint32 count0 = 1;
+ uint32 count1 = tile.H ();
+ uint32 count2 = tile.W ();
+
+ int32 step0 = 0;
+ int32 step1 = buffer.fRowStep;
+ int32 step2 = buffer.fColStep;
+
+ OptimizeOrder (sPtr,
+ buffer.fPixelSize,
+ count0,
+ count1,
+ count2,
+ step0,
+ step1,
+ step2);
+
+ DNG_ASSERT (count0 == 1, "OptimizeOrder logic error");
+
+ const uint16 *s1 = (const uint16 *) sPtr;
+
+ for (uint32 row = 0; row < count1; row++)
+ {
+
+ if (maxValue == 0x0FFFF && step2 == 1)
+ {
+
+ for (uint32 col = 0; col < count2; col++)
+ {
+
+ uint32 x = s1 [col];
+
+ hist [x] ++;
+
+ }
+
+ }
+
+ else
+ {
+
+ const uint16 *s2 = s1;
+
+ for (uint32 col = 0; col < count2; col++)
+ {
+
+ uint32 x = s2 [0];
+
+ if (x <= maxValue)
+ {
+
+ hist [x] ++;
+
+ }
+
+ s2 += step2;
+
+ }
+
+ }
+
+ s1 += step1;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+class dng_limit_float_depth_task: public dng_area_task
+ {
+
+ private:
+
+ const dng_image &fSrcImage;
+
+ dng_image &fDstImage;
+
+ uint32 fBitDepth;
+
+ real32 fScale;
+
+ public:
+
+ dng_limit_float_depth_task (const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale);
+
+ virtual dng_rect RepeatingTile1 () const
+ {
+ return fSrcImage.RepeatingTile ();
+ }
+
+ virtual dng_rect RepeatingTile2 () const
+ {
+ return fDstImage.RepeatingTile ();
+ }
+
+ virtual void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer *sniffer);
+
+ };
+
+/*****************************************************************************/
+
+dng_limit_float_depth_task::dng_limit_float_depth_task (const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale)
+
+ : fSrcImage (srcImage)
+ , fDstImage (dstImage)
+ , fBitDepth (bitDepth)
+ , fScale (scale)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_limit_float_depth_task::Process (uint32 /* threadIndex */,
+ const dng_rect &tile,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ dng_const_tile_buffer srcBuffer (fSrcImage, tile);
+ dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
+
+ uint32 count0 = tile.H ();
+ uint32 count1 = tile.W ();
+ uint32 count2 = fDstImage.Planes ();
+
+ int32 sStep0 = srcBuffer.fRowStep;
+ int32 sStep1 = srcBuffer.fColStep;
+ int32 sStep2 = srcBuffer.fPlaneStep;
+
+ int32 dStep0 = dstBuffer.fRowStep;
+ int32 dStep1 = dstBuffer.fColStep;
+ int32 dStep2 = dstBuffer.fPlaneStep;
+
+ const void *sPtr = srcBuffer.ConstPixel (tile.t,
+ tile.l,
+ 0);
+
+ void *dPtr = dstBuffer.DirtyPixel (tile.t,
+ tile.l,
+ 0);
+
+ OptimizeOrder (sPtr,
+ dPtr,
+ srcBuffer.fPixelSize,
+ dstBuffer.fPixelSize,
+ count0,
+ count1,
+ count2,
+ sStep0,
+ sStep1,
+ sStep2,
+ dStep0,
+ dStep1,
+ dStep2);
+
+ const real32 *sPtr0 = (const real32 *) sPtr;
+ real32 *dPtr0 = ( real32 *) dPtr;
+
+ real32 scale = fScale;
+
+ bool limit16 = (fBitDepth == 16);
+ bool limit24 = (fBitDepth == 24);
+
+ for (uint32 index0 = 0; index0 < count0; index0++)
+ {
+
+ const real32 *sPtr1 = sPtr0;
+ real32 *dPtr1 = dPtr0;
+
+ for (uint32 index1 = 0; index1 < count1; index1++)
+ {
+
+ // If the scale is a NOP, and the data is packed solid, we can just do memory
+ // copy.
+
+ if (scale == 1.0f && sStep2 == 1 && dStep2 == 1)
+ {
+
+ if (dPtr1 != sPtr1) // srcImage != dstImage
+ {
+
+ memcpy (dPtr1, sPtr1, count2 * (uint32) sizeof (real32));
+
+ }
+
+ }
+
+ else
+ {
+
+ const real32 *sPtr2 = sPtr1;
+ real32 *dPtr2 = dPtr1;
+
+ for (uint32 index2 = 0; index2 < count2; index2++)
+ {
+
+ real32 x = sPtr2 [0];
+
+ x *= scale;
+
+ dPtr2 [0] = x;
+
+ sPtr2 += sStep2;
+ dPtr2 += dStep2;
+
+ }
+
+ }
+
+ // The data is now in the destination buffer.
+
+ if (limit16)
+ {
+
+ uint32 *dPtr2 = (uint32 *) dPtr1;
+
+ for (uint32 index2 = 0; index2 < count2; index2++)
+ {
+
+ uint32 x = dPtr2 [0];
+
+ uint16 y = DNG_FloatToHalf (x);
+
+ x = DNG_HalfToFloat (y);
+
+ dPtr2 [0] = x;
+
+ dPtr2 += dStep2;
+
+ }
+
+ }
+
+ else if (limit24)
+ {
+
+ uint32 *dPtr2 = (uint32 *) dPtr1;
+
+ for (uint32 index2 = 0; index2 < count2; index2++)
+ {
+
+ uint32 x = dPtr2 [0];
+
+ uint8 temp [3];
+
+ DNG_FloatToFP24 (x, temp);
+
+ x = DNG_FP24ToFloat (temp);
+
+ dPtr2 [0] = x;
+
+ dPtr2 += dStep2;
+
+ }
+
+ }
+
+ sPtr1 += sStep1;
+ dPtr1 += dStep1;
+
+ }
+
+ sPtr0 += sStep0;
+ dPtr0 += dStep0;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void LimitFloatBitDepth (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale)
+ {
+
+ DNG_ASSERT (srcImage.PixelType () == ttFloat, "Floating point image expected");
+ DNG_ASSERT (dstImage.PixelType () == ttFloat, "Floating point image expected");
+
+ dng_limit_float_depth_task task (srcImage,
+ dstImage,
+ bitDepth,
+ scale);
+
+ host.PerformAreaTask (task, dstImage.Bounds ());
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_utils.h b/gpr/source/lib/dng_sdk/dng_utils.h
new file mode 100644
index 0000000..560c37c
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_utils.h
@@ -0,0 +1,1237 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_utils.h#3 $ */
+/* $DateTime: 2012/06/14 20:24:41 $ */
+/* $Change: 835078 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_utils__
+#define __dng_utils__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_flags.h"
+#include "dng_memory.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+inline uint32 Abs_int32 (int32 x)
+ {
+
+ #if 0
+
+ // Reference version.
+
+ return (uint32) (x < 0 ? -x : x);
+
+ #else
+
+ // Branchless version.
+
+ uint32 mask = (uint32) (x >> 31);
+
+ return (uint32) (((uint32) x + mask) ^ mask);
+
+ #endif
+
+ }
+
+inline int32 Min_int32 (int32 x, int32 y)
+ {
+
+ return (x <= y ? x : y);
+
+ }
+
+inline int32 Max_int32 (int32 x, int32 y)
+ {
+
+ return (x >= y ? x : y);
+
+ }
+
+inline int32 Pin_int32 (int32 min, int32 x, int32 max)
+ {
+
+ return Max_int32 (min, Min_int32 (x, max));
+
+ }
+
+inline int32 Pin_int32_between (int32 a, int32 x, int32 b)
+ {
+
+ int32 min, max;
+ if (a < b) { min = a; max = b; }
+ else { min = b; max = a; }
+
+ return Pin_int32 (min, x, max);
+
+ }
+
+/*****************************************************************************/
+
+inline uint16 Min_uint16 (uint16 x, uint16 y)
+ {
+
+ return (x <= y ? x : y);
+
+ }
+
+inline uint16 Max_uint16 (uint16 x, uint16 y)
+ {
+
+ return (x >= y ? x : y);
+
+ }
+
+inline int16 Pin_int16 (int32 x)
+ {
+
+ x = Pin_int32 (-32768, x, 32767);
+
+ return (int16) x;
+
+ }
+
+/*****************************************************************************/
+
+inline uint32 Min_uint32 (uint32 x, uint32 y)
+ {
+
+ return (x <= y ? x : y);
+
+ }
+
+inline uint32 Min_uint32 (uint32 x, uint32 y, uint32 z)
+ {
+
+ return Min_uint32 (x, Min_uint32 (y, z));
+
+ }
+
+inline uint32 Max_uint32 (uint32 x, uint32 y)
+ {
+
+ return (x >= y ? x : y);
+
+ }
+
+inline uint32 Max_uint32 (uint32 x, uint32 y, uint32 z)
+ {
+
+ return Max_uint32 (x, Max_uint32 (y, z));
+
+ }
+
+inline uint32 Pin_uint32 (uint32 min, uint32 x, uint32 max)
+ {
+
+ return Max_uint32 (min, Min_uint32 (x, max));
+
+ }
+
+/*****************************************************************************/
+
+inline uint16 Pin_uint16 (int32 x)
+ {
+
+ #if 0
+
+ // Reference version.
+
+ x = Pin_int32 (0, x, 0x0FFFF);
+
+ #else
+
+ // Single branch version.
+
+ if (x & ~65535)
+ {
+
+ x = ~x >> 31;
+
+ }
+
+ #endif
+
+ return (uint16) x;
+
+ }
+
+/*****************************************************************************/
+
+inline uint32 RoundUp2 (uint32 x)
+ {
+
+ return (x + 1) & (uint32) ~1;
+
+ }
+
+inline uint32 RoundUp4 (uint32 x)
+ {
+
+ return (x + 3) & (uint32) ~3;
+
+ }
+
+inline uint32 RoundUp8 (uint32 x)
+ {
+
+ return (x + 7) & (uint32) ~7;
+
+ }
+
+inline uint32 RoundUp16 (uint32 x)
+ {
+
+ return (x + 15) & (uint32) ~15;
+
+ }
+
+inline uint32 RoundUp4096 (uint32 x)
+ {
+
+ return (x + 4095) & (uint32) ~4095;
+
+ }
+
+/******************************************************************************/
+
+inline uint32 RoundDown2 (uint32 x)
+ {
+
+ return x & (uint32) ~1;
+
+ }
+
+inline uint32 RoundDown4 (uint32 x)
+ {
+
+ return x & (uint32) ~3;
+
+ }
+
+inline uint32 RoundDown8 (uint32 x)
+ {
+
+ return x & (uint32) ~7;
+
+ }
+
+inline uint32 RoundDown16 (uint32 x)
+ {
+
+ return x & (uint32) ~15;
+
+ }
+
+/******************************************************************************/
+
+inline uint32 RoundUpForPixelSize (uint32 x, uint32 pixelSize)
+ {
+
+ switch (pixelSize)
+ {
+
+ case 1:
+ return RoundUp16 (x);
+
+ case 2:
+ return RoundUp8 (x);
+
+ case 4:
+ return RoundUp4 (x);
+
+ case 8:
+ return RoundUp2 (x);
+
+ default:
+ return RoundUp16 (x);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+inline uint64 Abs_int64 (int64 x)
+ {
+
+ return (uint64) (x < 0 ? -x : x);
+
+ }
+
+inline int64 Min_int64 (int64 x, int64 y)
+ {
+
+ return (x <= y ? x : y);
+
+ }
+
+inline int64 Max_int64 (int64 x, int64 y)
+ {
+
+ return (x >= y ? x : y);
+
+ }
+
+inline int64 Pin_int64 (int64 min, int64 x, int64 max)
+ {
+
+ return Max_int64 (min, Min_int64 (x, max));
+
+ }
+
+/******************************************************************************/
+
+inline uint64 Min_uint64 (uint64 x, uint64 y)
+ {
+
+ return (x <= y ? x : y);
+
+ }
+
+inline uint64 Max_uint64 (uint64 x, uint64 y)
+ {
+
+ return (x >= y ? x : y);
+
+ }
+
+inline uint64 Pin_uint64 (uint64 min, uint64 x, uint64 max)
+ {
+
+ return Max_uint64 (min, Min_uint64 (x, max));
+
+ }
+
+/*****************************************************************************/
+
+inline real32 Abs_real32 (real32 x)
+ {
+
+ return (x < 0.0f ? -x : x);
+
+ }
+
+inline real32 Min_real32 (real32 x, real32 y)
+ {
+
+ return (x < y ? x : y);
+
+ }
+
+inline real32 Max_real32 (real32 x, real32 y)
+ {
+
+ return (x > y ? x : y);
+
+ }
+
+inline real32 Pin_real32 (real32 min, real32 x, real32 max)
+ {
+
+ return Max_real32 (min, Min_real32 (x, max));
+
+ }
+
+inline real32 Pin_real32 (real32 x)
+ {
+
+ return Pin_real32 (0.0f, x, 1.0f);
+
+ }
+
+inline real32 Pin_real32_Overrange (real32 min,
+ real32 x,
+ real32 max)
+ {
+
+ // Normal numbers in (min,max). No change.
+
+ if (x > min && x < max)
+ {
+ return x;
+ }
+
+ // Map large numbers (including positive infinity) to max.
+
+ else if (x > min)
+ {
+ return max;
+ }
+
+ // Map everything else (including negative infinity and all NaNs) to min.
+
+ return min;
+
+ }
+
+inline real32 Pin_Overrange (real32 x)
+ {
+
+ // Normal in-range numbers, except for plus and minus zero.
+
+ if (x > 0.0f && x <= 1.0f)
+ {
+ return x;
+ }
+
+ // Large numbers, including positive infinity.
+
+ else if (x > 0.5f)
+ {
+ return 1.0f;
+ }
+
+ // Plus and minus zero, negative numbers, negative infinity, and all NaNs.
+
+ return 0.0f;
+
+ }
+
+inline real32 Lerp_real32 (real32 a, real32 b, real32 t)
+ {
+
+ return a + t * (b - a);
+
+ }
+
+/*****************************************************************************/
+
+inline real64 Abs_real64 (real64 x)
+ {
+
+ return (x < 0.0 ? -x : x);
+
+ }
+
+inline real64 Min_real64 (real64 x, real64 y)
+ {
+
+ return (x < y ? x : y);
+
+ }
+
+inline real64 Max_real64 (real64 x, real64 y)
+ {
+
+ return (x > y ? x : y);
+
+ }
+
+inline real64 Pin_real64 (real64 min, real64 x, real64 max)
+ {
+
+ return Max_real64 (min, Min_real64 (x, max));
+
+ }
+
+inline real64 Pin_real64 (real64 x)
+ {
+
+ return Pin_real64 (0.0, x, 1.0);
+
+ }
+
+inline real64 Pin_real64_Overrange (real64 min,
+ real64 x,
+ real64 max)
+ {
+
+ // Normal numbers in (min,max). No change.
+
+ if (x > min && x < max)
+ {
+ return x;
+ }
+
+ // Map large numbers (including positive infinity) to max.
+
+ else if (x > min)
+ {
+ return max;
+ }
+
+ // Map everything else (including negative infinity and all NaNs) to min.
+
+ return min;
+
+ }
+
+inline real64 Lerp_real64 (real64 a, real64 b, real64 t)
+ {
+
+ return a + t * (b - a);
+
+ }
+
+/*****************************************************************************/
+
+inline int32 Round_int32 (real32 x)
+ {
+
+ return (int32) (x > 0.0f ? x + 0.5f : x - 0.5f);
+
+ }
+
+inline int32 Round_int32 (real64 x)
+ {
+
+ return (int32) (x > 0.0 ? x + 0.5 : x - 0.5);
+
+ }
+
+inline uint32 Floor_uint32 (real32 x)
+ {
+
+ return (uint32) Max_real32 (0.0f, x);
+
+ }
+
+inline uint32 Floor_uint32 (real64 x)
+ {
+
+ return (uint32) Max_real64 (0.0, x);
+
+ }
+
+inline uint32 Round_uint32 (real32 x)
+ {
+
+ return Floor_uint32 (x + 0.5f);
+
+ }
+
+inline uint32 Round_uint32 (real64 x)
+ {
+
+ return Floor_uint32 (x + 0.5);
+
+ }
+
+/******************************************************************************/
+
+inline int64 Round_int64 (real64 x)
+ {
+
+ return (int64) (x >= 0.0 ? x + 0.5 : x - 0.5);
+
+ }
+
+/*****************************************************************************/
+
+const int64 kFixed64_One = (((int64) 1) << 32);
+const int64 kFixed64_Half = (((int64) 1) << 31);
+
+/******************************************************************************/
+
+inline int64 Real64ToFixed64 (real64 x)
+ {
+
+ return Round_int64 (x * (real64) kFixed64_One);
+
+ }
+
+/******************************************************************************/
+
+inline real64 Fixed64ToReal64 (int64 x)
+ {
+
+ return x * (1.0 / (real64) kFixed64_One);
+
+ }
+
+/*****************************************************************************/
+
+inline char ForceUppercase (char c)
+ {
+
+ if (c >= 'a' && c <= 'z')
+ {
+
+ c -= 'a' - 'A';
+
+ }
+
+ return c;
+
+ }
+
+/*****************************************************************************/
+
+inline uint16 SwapBytes16 (uint16 x)
+ {
+
+ return (uint16) ((x << 8) |
+ (x >> 8));
+
+ }
+
+inline uint32 SwapBytes32 (uint32 x)
+ {
+
+ return (x << 24) +
+ ((x << 8) & 0x00FF0000) +
+ ((x >> 8) & 0x0000FF00) +
+ (x >> 24);
+
+ }
+
+/*****************************************************************************/
+
+inline bool IsAligned16 (const void *p)
+ {
+
+ return (((uintptr) p) & 1) == 0;
+
+ }
+
+inline bool IsAligned32 (const void *p)
+ {
+
+ return (((uintptr) p) & 3) == 0;
+
+ }
+
+inline bool IsAligned64 (const void *p)
+ {
+
+ return (((uintptr) p) & 7) == 0;
+
+ }
+
+inline bool IsAligned128 (const void *p)
+ {
+
+ return (((uintptr) p) & 15) == 0;
+
+ }
+
+/******************************************************************************/
+
+// Converts from RGB values (range 0.0 to 1.0) to HSV values (range 0.0 to
+// 6.0 for hue, and 0.0 to 1.0 for saturation and value).
+
+inline void DNG_RGBtoHSV (real32 r,
+ real32 g,
+ real32 b,
+ real32 &h,
+ real32 &s,
+ real32 &v)
+ {
+
+ v = Max_real32 (r, Max_real32 (g, b));
+
+ real32 gap = v - Min_real32 (r, Min_real32 (g, b));
+
+ if (gap > 0.0f)
+ {
+
+ if (r == v)
+ {
+
+ h = (g - b) / gap;
+
+ if (h < 0.0f)
+ {
+ h += 6.0f;
+ }
+
+ }
+
+ else if (g == v)
+ {
+ h = 2.0f + (b - r) / gap;
+ }
+
+ else
+ {
+ h = 4.0f + (r - g) / gap;
+ }
+
+ s = gap / v;
+
+ }
+
+ else
+ {
+ h = 0.0f;
+ s = 0.0f;
+ }
+
+ }
+
+/*****************************************************************************/
+
+// Converts from HSV values (range 0.0 to 6.0 for hue, and 0.0 to 1.0 for
+// saturation and value) to RGB values (range 0.0 to 1.0).
+
+inline void DNG_HSVtoRGB (real32 h,
+ real32 s,
+ real32 v,
+ real32 &r,
+ real32 &g,
+ real32 &b)
+ {
+
+ if (s > 0.0f)
+ {
+
+ if (h < 0.0f)
+ h += 6.0f;
+
+ if (h >= 6.0f)
+ h -= 6.0f;
+
+ int32 i = (int32) h;
+ real32 f = h - (real32) i;
+
+ real32 p = v * (1.0f - s);
+
+ #define q (v * (1.0f - s * f))
+ #define t (v * (1.0f - s * (1.0f - f)))
+
+ switch (i)
+ {
+ case 0: r = v; g = t; b = p; break;
+ case 1: r = q; g = v; b = p; break;
+ case 2: r = p; g = v; b = t; break;
+ case 3: r = p; g = q; b = v; break;
+ case 4: r = t; g = p; b = v; break;
+ case 5: r = v; g = p; b = q; break;
+ }
+
+ #undef q
+ #undef t
+
+ }
+
+ else
+ {
+ r = v;
+ g = v;
+ b = v;
+ }
+
+ }
+
+/******************************************************************************/
+
+// High resolution timer, for code profiling.
+
+real64 TickTimeInSeconds ();
+
+// Lower resolution timer, but more stable.
+
+real64 TickCountInSeconds ();
+
+/******************************************************************************/
+
+class dng_timer
+ {
+
+ public:
+
+ dng_timer (const char *message);
+
+ ~dng_timer ();
+
+ private:
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_timer (const dng_timer &timer);
+
+ dng_timer & operator= (const dng_timer &timer);
+
+ private:
+
+ const char *fMessage;
+
+ real64 fStartTime;
+
+ };
+
+/*****************************************************************************/
+
+// Returns the maximum squared Euclidean distance from the specified point to the
+// specified rectangle rect.
+
+real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
+ const dng_rect_real64 &rect);
+
+/*****************************************************************************/
+
+// Returns the maximum Euclidean distance from the specified point to the specified
+// rectangle rect.
+
+real64 MaxDistancePointToRect (const dng_point_real64 &point,
+ const dng_rect_real64 &rect);
+
+/*****************************************************************************/
+
+inline uint32 DNG_HalfToFloat (uint16 halfValue)
+ {
+
+ int32 sign = (halfValue >> 15) & 0x00000001;
+ int32 exponent = (halfValue >> 10) & 0x0000001f;
+ int32 mantissa = halfValue & 0x000003ff;
+
+ if (exponent == 0)
+ {
+
+ if (mantissa == 0)
+ {
+
+ // Plus or minus zero
+
+ return (uint32) (sign << 31);
+
+ }
+
+ else
+ {
+
+ // Denormalized number -- renormalize it
+
+ while (!(mantissa & 0x00000400))
+ {
+ mantissa <<= 1;
+ exponent -= 1;
+ }
+
+ exponent += 1;
+ mantissa &= ~0x00000400;
+
+ }
+
+ }
+
+ else if (exponent == 31)
+ {
+
+ if (mantissa == 0)
+ {
+
+ // Positive or negative infinity, convert to maximum (16 bit) values.
+
+ return (uint32) ((sign << 31) | ((0x1eL + 127 - 15) << 23) | (0x3ffL << 13));
+
+ }
+
+ else
+ {
+
+ // Nan -- Just set to zero.
+
+ return 0;
+
+ }
+
+ }
+
+ // Normalized number
+
+ exponent += (127 - 15);
+ mantissa <<= 13;
+
+ // Assemble sign, exponent and mantissa.
+
+ return (uint32) ((sign << 31) | (exponent << 23) | mantissa);
+
+ }
+
+/*****************************************************************************/
+
+inline uint16 DNG_FloatToHalf (uint32 i)
+ {
+
+ int32 sign = (i >> 16) & 0x00008000;
+ int32 exponent = ((i >> 23) & 0x000000ff) - (127 - 15);
+ int32 mantissa = i & 0x007fffff;
+
+ if (exponent <= 0)
+ {
+
+ if (exponent < -10)
+ {
+
+ // Zero or underflow to zero.
+
+ return (uint16)sign;
+
+ }
+
+ // E is between -10 and 0. We convert f to a denormalized half.
+
+ mantissa = (mantissa | 0x00800000) >> (1 - exponent);
+
+ // Round to nearest, round "0.5" up.
+ //
+ // Rounding may cause the significand to overflow and make
+ // our number normalized. Because of the way a half's bits
+ // are laid out, we don't have to treat this case separately;
+ // the code below will handle it correctly.
+
+ if (mantissa & 0x00001000)
+ mantissa += 0x00002000;
+
+ // Assemble the half from sign, exponent (zero) and mantissa.
+
+ return (uint16)(sign | (mantissa >> 13));
+
+ }
+
+ else if (exponent == 0xff - (127 - 15))
+ {
+
+ if (mantissa == 0)
+ {
+
+ // F is an infinity; convert f to a half
+ // infinity with the same sign as f.
+
+ return (uint16)(sign | 0x7c00);
+
+ }
+
+ else
+ {
+
+ // F is a NAN; produce a half NAN that preserves
+ // the sign bit and the 10 leftmost bits of the
+ // significand of f.
+
+ return (uint16)(sign | 0x7c00 | (mantissa >> 13));
+
+ }
+
+ }
+
+ // E is greater than zero. F is a normalized float.
+ // We try to convert f to a normalized half.
+
+ // Round to nearest, round "0.5" up
+
+ if (mantissa & 0x00001000)
+ {
+
+ mantissa += 0x00002000;
+
+ if (mantissa & 0x00800000)
+ {
+ mantissa = 0; // overflow in significand,
+ exponent += 1; // adjust exponent
+ }
+
+ }
+
+ // Handle exponent overflow
+
+ if (exponent > 30)
+ {
+ return (uint16)(sign | 0x7c00); // infinity with the same sign as f.
+ }
+
+ // Assemble the half from sign, exponent and mantissa.
+
+ return (uint16)(sign | (exponent << 10) | (mantissa >> 13));
+
+ }
+
+/*****************************************************************************/
+
+inline uint32 DNG_FP24ToFloat (const uint8 *input)
+ {
+
+ int32 sign = (input [0] >> 7) & 0x01;
+ int32 exponent = (input [0] ) & 0x7F;
+ int32 mantissa = (((int32) input [1]) << 8) | input[2];
+
+ if (exponent == 0)
+ {
+
+ if (mantissa == 0)
+ {
+
+ // Plus or minus zero
+
+ return (uint32) (sign << 31);
+
+ }
+
+ else
+ {
+
+ // Denormalized number -- renormalize it
+
+ while (!(mantissa & 0x00010000))
+ {
+ mantissa <<= 1;
+ exponent -= 1;
+ }
+
+ exponent += 1;
+ mantissa &= ~0x00010000;
+
+ }
+
+ }
+
+ else if (exponent == 127)
+ {
+
+ if (mantissa == 0)
+ {
+
+ // Positive or negative infinity, convert to maximum (24 bit) values.
+
+ return (uint32) ((sign << 31) | ((0x7eL + 128 - 64) << 23) | (0xffffL << 7));
+
+ }
+
+ else
+ {
+
+ // Nan -- Just set to zero.
+
+ return 0;
+
+ }
+
+ }
+
+ // Normalized number
+
+ exponent += (128 - 64);
+ mantissa <<= 7;
+
+ // Assemble sign, exponent and mantissa.
+
+ return (uint32) ((sign << 31) | (exponent << 23) | mantissa);
+
+ }
+
+/*****************************************************************************/
+
+inline void DNG_FloatToFP24 (uint32 input, uint8 *output)
+ {
+
+ int32 exponent = (int32) ((input >> 23) & 0xFF) - 128;
+ int32 mantissa = input & 0x007FFFFF;
+
+ if (exponent == 127) // infinity or NaN
+ {
+
+ // Will the NaN alais to infinity?
+
+ if (mantissa != 0x007FFFFF && ((mantissa >> 7) == 0xFFFF))
+ {
+
+ mantissa &= 0x003FFFFF; // knock out msb to make it a NaN
+
+ }
+
+ }
+
+ else if (exponent > 63) // overflow, map to infinity
+ {
+
+ exponent = 63;
+ mantissa = 0x007FFFFF;
+
+ }
+
+ else if (exponent <= -64)
+ {
+
+ if (exponent >= -79) // encode as denorm
+ {
+ mantissa = (mantissa | 0x00800000) >> (-63 - exponent);
+ }
+
+ else // underflow to zero
+ {
+ mantissa = 0;
+ }
+
+ exponent = -64;
+
+ }
+
+ output [0] = (uint8)(((input >> 24) & 0x80) | (uint32) (exponent + 64));
+
+ output [1] = (mantissa >> 15) & 0x00FF;
+ output [2] = (mantissa >> 7) & 0x00FF;
+
+ }
+
+/******************************************************************************/
+
+// The following code was from PSDivide.h in Photoshop.
+
+// High order 32-bits of an unsigned 32 by 32 multiply.
+
+#ifndef MULUH
+
+#if defined(_X86_) && defined(_MSC_VER)
+
+inline uint32 Muluh86 (uint32 x, uint32 y)
+ {
+ uint32 result;
+ __asm
+ {
+ MOV EAX, x
+ MUL y
+ MOV result, EDX
+ }
+ return (result);
+ }
+
+#define MULUH Muluh86
+
+#else
+
+#define MULUH(x,y) ((uint32) (((x) * (uint64) (y)) >> 32))
+
+#endif
+
+#endif
+
+// High order 32-bits of an signed 32 by 32 multiply.
+
+#ifndef MULSH
+
+#if defined(_X86_) && defined(_MSC_VER)
+
+inline int32 Mulsh86 (int32 x, int32 y)
+ {
+ int32 result;
+ __asm
+ {
+ MOV EAX, x
+ IMUL y
+ MOV result, EDX
+ }
+ return (result);
+ }
+
+#define MULSH Mulsh86
+
+#else
+
+#define MULSH(x,y) ((int32) (((x) * (int64) (y)) >> 32))
+
+#endif
+
+#endif
+
+/******************************************************************************/
+
+// Random number generator (identical to Apple's) for portable use.
+
+// This implements the "minimal standard random number generator"
+// as proposed by Park and Miller in CACM October, 1988.
+// It has a period of 2147483647 (0x7fffffff)
+
+// This is the ACM standard 30 bit generator:
+// x' = (x * 16807) mod 2^31-1
+
+inline uint32 DNG_Random (uint32 seed)
+ {
+
+ // high = seed / 127773
+
+ uint32 temp = MULUH (0x069C16BD, seed);
+ uint32 high = (temp + ((seed - temp) >> 1)) >> 16;
+
+ // low = seed % 127773
+
+ uint32 low = seed - high * 127773;
+
+ // seed = (seed * 16807) % 2147483647
+
+ seed = 16807 * low - 2836 * high;
+
+ if (seed & 0x80000000)
+ seed += 2147483647;
+
+ return seed;
+
+ }
+
+/*****************************************************************************/
+
+class dng_dither
+ {
+
+ public:
+
+ static const uint32 kRNGBits = 7;
+
+ static const uint32 kRNGSize = 1 << kRNGBits;
+
+ static const uint32 kRNGMask = kRNGSize - 1;
+
+ static const uint32 kRNGSize2D = kRNGSize * kRNGSize;
+
+ private:
+
+ dng_memory_data fNoiseBuffer;
+
+ private:
+
+ dng_dither ();
+
+ // Hidden copy constructor and assignment operator.
+
+ dng_dither (const dng_dither &);
+
+ dng_dither & operator= (const dng_dither &);
+
+ public:
+
+ static const dng_dither & Get ();
+
+ public:
+
+ const uint16 *NoiseBuffer16 () const
+ {
+ return fNoiseBuffer.Buffer_uint16 ();
+ }
+
+ };
+
+/*****************************************************************************/
+
+void HistogramArea (dng_host &host,
+ const dng_image &image,
+ const dng_rect &area,
+ uint32 *hist,
+ uint32 histLimit,
+ uint32 plane = 0);
+
+/*****************************************************************************/
+
+void LimitFloatBitDepth (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale = 1.0f);
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_validate.cpp b/gpr/source/lib/dng_sdk/dng_validate.cpp
new file mode 100644
index 0000000..468968f
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_validate.cpp
@@ -0,0 +1,879 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_validate.cpp#2 $ */
+/* $DateTime: 2012/06/14 20:24:41 $ */
+/* $Change: 835078 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_color_space.h"
+#include "dng_date_time.h"
+#include "dng_exceptions.h"
+#include "dng_file_stream.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image_writer.h"
+#include "dng_info.h"
+#include "dng_linearization_info.h"
+#include "dng_mosaic_info.h"
+#include "dng_negative.h"
+#include "dng_preview.h"
+#include "dng_render.h"
+#include "dng_simple_image.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_xmp.h"
+#include "dng_xmp_sdk.h"
+
+/*****************************************************************************/
+
+#if qDNGValidateTarget
+
+/*****************************************************************************/
+
+#define kDNGValidateVersion "1.4"
+
+/*****************************************************************************/
+
+static bool gFourColorBayer = false;
+
+static int32 gMosaicPlane = -1;
+
+static uint32 gPreferredSize = 0;
+static uint32 gMinimumSize = 0;
+static uint32 gMaximumSize = 0;
+
+static uint32 gProxyDNGSize = 0;
+
+static const dng_color_space *gFinalSpace = &dng_space_sRGB::Get ();
+
+static uint32 gFinalPixelType = ttByte;
+
+static dng_string gDumpStage1;
+static dng_string gDumpStage2;
+static dng_string gDumpStage3;
+static dng_string gDumpTIF;
+static dng_string gDumpDNG;
+
+/*****************************************************************************/
+
+static dng_error_code dng_validate (const char *filename)
+ {
+
+ printf ("Validating \"%s\"...\n", filename);
+
+ try
+ {
+
+ dng_file_stream stream (filename);
+
+ dng_host host;
+
+ host.SetPreferredSize (gPreferredSize);
+ host.SetMinimumSize (gMinimumSize );
+ host.SetMaximumSize (gMaximumSize );
+
+ host.ValidateSizes ();
+
+ if (host.MinimumSize ())
+ {
+
+ host.SetForPreview (true);
+
+ gDumpDNG.Clear ();
+
+ }
+
+ if (gDumpDNG.NotEmpty ())
+ {
+
+ host.SetSaveDNGVersion (dngVersion_SaveDefault);
+
+ host.SetSaveLinearDNG (false);
+
+ host.SetKeepOriginalFile (false);
+
+ }
+
+ // Read into the negative.
+
+ AutoPtr<dng_negative> negative;
+
+ {
+
+ dng_info info;
+
+ info.Parse (host, stream);
+
+ info.PostParse (host);
+
+ if (!info.IsValidDNG ())
+ {
+ return dng_error_bad_format;
+ }
+
+ negative.Reset (host.Make_dng_negative ());
+
+ negative->Parse (host, stream, info);
+
+ negative->PostParse (host, stream, info);
+
+ {
+
+ dng_timer timer ("Raw image read time");
+
+ negative->ReadStage1Image (host, stream, info);
+
+ }
+
+ if (info.fMaskIndex != -1)
+ {
+
+ dng_timer timer ("Transparency mask read time");
+
+ negative->ReadTransparencyMask (host, stream, info);
+
+ }
+
+ negative->ValidateRawImageDigest (host);
+
+ }
+
+ // Option to write stage 1 image.
+
+ if (gDumpStage1.NotEmpty ())
+ {
+
+ dng_file_stream stream2 (gDumpStage1.Get (), true);
+
+ const dng_image &stage1 = *negative->Stage1Image ();
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ stage1,
+ stage1.Planes () >= 3 ? piRGB
+ : piBlackIsZero);
+
+ gDumpStage1.Clear ();
+
+ }
+
+ // Metadata.
+
+ negative->SynchronizeMetadata ();
+
+ // Four color Bayer option.
+
+ if (gFourColorBayer)
+ {
+ negative->SetFourColorBayer ();
+ }
+
+ // Build stage 2 image.
+
+ {
+
+ dng_timer timer ("Linearization time");
+
+ negative->BuildStage2Image (host);
+
+ }
+
+ if (gDumpStage2.NotEmpty ())
+ {
+
+ dng_file_stream stream2 (gDumpStage2.Get (), true);
+
+ const dng_image &stage2 = *negative->Stage2Image ();
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ stage2,
+ stage2.Planes () >= 3 ? piRGB
+ : piBlackIsZero);
+
+ gDumpStage2.Clear ();
+
+ }
+
+ // Build stage 3 image.
+
+ {
+
+ dng_timer timer ("Interpolate time");
+
+ negative->BuildStage3Image (host,
+ gMosaicPlane);
+
+ }
+
+ // Convert to proxy, if requested.
+
+ if (gProxyDNGSize)
+ {
+
+ dng_timer timer ("ConvertToProxy time");
+
+ dng_image_writer writer;
+
+ negative->ConvertToProxy (host,
+ writer,
+ gProxyDNGSize);
+
+ }
+
+ // Flatten transparency, if required.
+
+ if (negative->NeedFlattenTransparency (host))
+ {
+
+ dng_timer timer ("FlattenTransparency time");
+
+ negative->FlattenTransparency (host);
+
+ }
+
+ if (gDumpStage3.NotEmpty ())
+ {
+
+ dng_file_stream stream2 (gDumpStage3.Get (), true);
+
+ const dng_image &stage3 = *negative->Stage3Image ();
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ stage3,
+ stage3.Planes () >= 3 ? piRGB
+ : piBlackIsZero);
+
+ gDumpStage3.Clear ();
+
+ }
+
+ // Output DNG file if requested.
+
+ if (gDumpDNG.NotEmpty ())
+ {
+
+ // Build the preview list.
+
+ dng_preview_list previewList;
+
+ dng_date_time_info dateTimeInfo;
+
+ CurrentDateTimeAndZone (dateTimeInfo);
+
+ for (uint32 previewIndex = 0; previewIndex < 2; previewIndex++)
+ {
+
+ // Skip preview if writing a compresssed main image to save space
+ // in this example code.
+
+ if (negative->RawJPEGImage () != NULL && previewIndex > 0)
+ {
+ break;
+ }
+
+ // Report timing.
+
+ dng_timer timer (previewIndex == 0 ? "Build thumbnail time"
+ : "Build preview time");
+
+ // Render a preview sized image.
+
+ AutoPtr<dng_image> previewImage;
+
+ {
+
+ dng_render render (host, *negative);
+
+ render.SetFinalSpace (negative->IsMonochrome () ? dng_space_GrayGamma22::Get ()
+ : dng_space_sRGB ::Get ());
+
+ render.SetFinalPixelType (ttByte);
+
+ render.SetMaximumSize (previewIndex == 0 ? 256 : 1024);
+
+ previewImage.Reset (render.Render ());
+
+ }
+
+ // Don't write the preview if it is same size as thumbnail.
+
+ if (previewIndex > 0 &&
+ Max_uint32 (previewImage->Bounds ().W (),
+ previewImage->Bounds ().H ()) <= 256)
+ {
+ break;
+ }
+
+ // If we have compressed JPEG data, create a compressed thumbnail. Otherwise
+ // save a uncompressed thumbnail.
+
+ bool useCompressedPreview = (negative->RawJPEGImage () != NULL) ||
+ (previewIndex > 0);
+
+ AutoPtr<dng_preview> preview (useCompressedPreview ?
+ (dng_preview *) new dng_jpeg_preview :
+ (dng_preview *) new dng_image_preview);
+
+ // Setup up preview info.
+
+ preview->fInfo.fApplicationName .Set ("dng_validate");
+ preview->fInfo.fApplicationVersion.Set (kDNGValidateVersion);
+
+ preview->fInfo.fSettingsName.Set ("Default");
+
+ preview->fInfo.fColorSpace = previewImage->Planes () == 1 ?
+ previewColorSpace_GrayGamma22 :
+ previewColorSpace_sRGB;
+
+ preview->fInfo.fDateTime = dateTimeInfo.Encode_ISO_8601 ();
+
+ if (!useCompressedPreview)
+ {
+
+ dng_image_preview *imagePreview = dynamic_cast<dng_image_preview *> (preview.Get ());
+
+ imagePreview->fImage.Reset (previewImage.Release ());
+
+ }
+
+ else
+ {
+
+ dng_jpeg_preview *jpegPreview = dynamic_cast<dng_jpeg_preview *> (preview.Get ());
+
+ int32 quality = (previewIndex == 0 ? 8 : 5);
+
+ dng_image_writer writer;
+
+ writer.EncodeJPEGPreview (host,
+ *previewImage,
+ *jpegPreview,
+ quality);
+
+ }
+
+ previewList.Append (preview);
+
+ }
+
+ // Write DNG file.
+
+ dng_file_stream stream2 (gDumpDNG.Get (), true);
+
+ {
+
+ dng_timer timer ("Write DNG time");
+
+ dng_image_writer writer;
+
+ writer.WriteDNG (host,
+ stream2,
+ *negative.Get (),
+ &previewList,
+ dngVersion_Current,
+ false);
+
+ }
+
+ gDumpDNG.Clear ();
+
+ }
+
+ // Output TIF file if requested.
+
+ if (gDumpTIF.NotEmpty ())
+ {
+
+ // Render final image.
+
+ dng_render render (host, *negative);
+
+ render.SetFinalSpace (*gFinalSpace );
+ render.SetFinalPixelType (gFinalPixelType);
+
+ if (host.MinimumSize ())
+ {
+
+ dng_point stage3Size = negative->Stage3Image ()->Size ();
+
+ render.SetMaximumSize (Max_uint32 (stage3Size.v,
+ stage3Size.h));
+
+ }
+
+ AutoPtr<dng_image> finalImage;
+
+ {
+
+ dng_timer timer ("Render time");
+
+ finalImage.Reset (render.Render ());
+
+ }
+
+ finalImage->Rotate (negative->Orientation ());
+
+ // Now that Camera Raw supports non-raw formats, we should
+ // not keep any Camera Raw settings in the XMP around when
+ // writing rendered files.
+
+ if (negative->GetXMP ())
+ {
+
+ negative->GetXMP ()->RemoveProperties (XMP_NS_CRS);
+ negative->GetXMP ()->RemoveProperties (XMP_NS_CRSS);
+
+ }
+
+ // Write TIF file.
+
+ dng_file_stream stream2 (gDumpTIF.Get (), true);
+
+ {
+
+ dng_timer timer ("Write TIFF time");
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ *finalImage.Get (),
+ finalImage->Planes () >= 3 ? piRGB
+ : piBlackIsZero,
+ ccUncompressed,
+ negative.Get (),
+ &render.FinalSpace ());
+
+ }
+
+ gDumpTIF.Clear ();
+
+ }
+
+ }
+
+ catch (const dng_exception &except)
+ {
+
+ return except.ErrorCode ();
+
+ }
+
+ catch (...)
+ {
+
+ return dng_error_unknown;
+
+ }
+
+ printf ("Validation complete\n");
+
+ return dng_error_none;
+
+ }
+
+/*****************************************************************************/
+
+int main (int argc, char *argv [])
+ {
+
+ try
+ {
+
+ if (argc == 1)
+ {
+
+ fprintf (stderr,
+ "\n"
+ "dng_validate, version " kDNGValidateVersion " "
+ #if qDNG64Bit
+ "(64-bit)"
+ #else
+ "(32-bit)"
+ #endif
+ "\n"
+ "Copyright 2005-2012 Adobe Systems, Inc.\n"
+ "\n"
+ "Usage: %s [options] file1 file2 ...\n"
+ "\n"
+ "Valid options:\n"
+ "-v Verbose mode\n"
+ "-d <num> Dump line limit (implies -v)\n"
+ "-b4 Use four-color Bayer interpolation\n"
+ "-s <num> Use this sample of multi-sample CFAs\n"
+ "-size <num> Preferred preview image size\n"
+ "-min <num> Minimum preview image size\n"
+ "-max <num> Maximum preview image size\n"
+ "-proxy <num> Target size for proxy DNG\n"
+ "-cs1 Color space: \"sRGB\" (default)\n"
+ "-cs2 Color space: \"Adobe RGB\"\n"
+ "-cs3 Color space: \"ProPhoto RGB\"\n"
+ "-cs4 Color space: \"ColorMatch RGB\"\n"
+ "-cs5 Color space: \"Gray Gamma 1.8\"\n"
+ "-cs6 Color space: \"Gray Gamma 2.2\"\n"
+ "-16 16-bits/channel output\n"
+ "-1 <file> Write stage 1 image to \"<file>.tif\"\n"
+ "-2 <file> Write stage 2 image to \"<file>.tif\"\n"
+ "-3 <file> Write stage 3 image to \"<file>.tif\"\n"
+ "-tif <file> Write TIF image to \"<file>.tif\"\n"
+ "-dng <file> Write DNG image to \"<file>.dng\"\n"
+ "\n",
+ argv [0]);
+
+ return 1;
+
+ }
+
+ int index;
+
+ for (index = 1; index < argc && argv [index] [0] == '-'; index++)
+ {
+
+ dng_string option;
+
+ option.Set (&argv [index] [1]);
+
+ if (option.Matches ("v", true))
+ {
+ gVerbose = true;
+ }
+
+ else if (option.Matches ("d", true))
+ {
+
+ gVerbose = true;
+
+ gDumpLineLimit = 0;
+
+ if (index + 1 < argc)
+ {
+ gDumpLineLimit = atoi (argv [++index]);
+ }
+
+ if (!gDumpLineLimit)
+ {
+ fprintf (stderr, "*** Invalid number after -d\n");
+ return 1;
+ }
+
+ }
+
+ else if (option.Matches ("s", true))
+ {
+
+ if (index + 1 < argc)
+ {
+ gMosaicPlane = atoi (argv [++index]);
+ }
+
+ else
+ {
+ fprintf (stderr, "*** Missing number after -s\n");
+ return 1;
+ }
+
+ }
+
+ else if (option.Matches ("b4", true))
+ {
+ gFourColorBayer = true;
+ }
+
+ else if (option.Matches ("size", true))
+ {
+
+ if (index + 1 < argc)
+ {
+ gPreferredSize = (uint32) atoi (argv [++index]);
+ }
+
+ else
+ {
+ fprintf (stderr, "*** Missing number after -size\n");
+ return 1;
+ }
+
+ }
+
+ else if (option.Matches ("min", true))
+ {
+
+ if (index + 1 < argc)
+ {
+ gMinimumSize = (uint32) atoi (argv [++index]);
+ }
+
+ else
+ {
+ fprintf (stderr, "*** Missing number after -min\n");
+ return 1;
+ }
+
+ }
+
+ else if (option.Matches ("max", true))
+ {
+
+ if (index + 1 < argc)
+ {
+ gMaximumSize = (uint32) atoi (argv [++index]);
+ }
+
+ else
+ {
+ fprintf (stderr, "*** Missing number after -max\n");
+ return 1;
+ }
+
+ }
+
+ else if (option.Matches ("proxy", true))
+ {
+
+ if (index + 1 < argc)
+ {
+ gProxyDNGSize = (uint32) atoi (argv [++index]);
+ }
+
+ else
+ {
+ fprintf (stderr, "*** Missing number after -proxy\n");
+ return 1;
+ }
+
+ }
+
+ else if (option.Matches ("cs1", true))
+ {
+
+ gFinalSpace = &dng_space_sRGB::Get ();
+
+ }
+
+ else if (option.Matches ("cs2", true))
+ {
+
+ gFinalSpace = &dng_space_AdobeRGB::Get ();
+
+ }
+
+ else if (option.Matches ("cs3", true))
+ {
+
+ gFinalSpace = &dng_space_ProPhoto::Get ();
+
+ }
+
+ else if (option.Matches ("cs4", true))
+ {
+
+ gFinalSpace = &dng_space_ColorMatch::Get ();
+
+ }
+
+ else if (option.Matches ("cs5", true))
+ {
+
+ gFinalSpace = &dng_space_GrayGamma18::Get ();
+
+ }
+
+ else if (option.Matches ("cs6", true))
+ {
+
+ gFinalSpace = &dng_space_GrayGamma22::Get ();
+
+ }
+
+ else if (option.Matches ("16"))
+ {
+
+ gFinalPixelType = ttShort;
+
+ }
+
+ else if (option.Matches ("1"))
+ {
+
+ gDumpStage1.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpStage1.Set (argv [++index]);
+ }
+
+ if (gDumpStage1.IsEmpty () || gDumpStage1.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -1\n");
+ return 1;
+ }
+
+ if (!gDumpStage1.EndsWith (".tif"))
+ {
+ gDumpStage1.Append (".tif");
+ }
+
+ }
+
+ else if (option.Matches ("2"))
+ {
+
+ gDumpStage2.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpStage2.Set (argv [++index]);
+ }
+
+ if (gDumpStage2.IsEmpty () || gDumpStage2.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -2\n");
+ return 1;
+ }
+
+ if (!gDumpStage2.EndsWith (".tif"))
+ {
+ gDumpStage2.Append (".tif");
+ }
+
+ }
+
+ else if (option.Matches ("3"))
+ {
+
+ gDumpStage3.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpStage3.Set (argv [++index]);
+ }
+
+ if (gDumpStage3.IsEmpty () || gDumpStage3.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -3\n");
+ return 1;
+ }
+
+ if (!gDumpStage3.EndsWith (".tif"))
+ {
+ gDumpStage3.Append (".tif");
+ }
+
+ }
+
+ else if (option.Matches ("tif", true))
+ {
+
+ gDumpTIF.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpTIF.Set (argv [++index]);
+ }
+
+ if (gDumpTIF.IsEmpty () || gDumpTIF.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -tif\n");
+ return 1;
+ }
+
+ if (!gDumpTIF.EndsWith (".tif"))
+ {
+ gDumpTIF.Append (".tif");
+ }
+
+ }
+
+ else if (option.Matches ("dng", true))
+ {
+
+ gDumpDNG.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpDNG.Set (argv [++index]);
+ }
+
+ if (gDumpDNG.IsEmpty () || gDumpDNG.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -dng\n");
+ return 1;
+ }
+
+ if (!gDumpDNG.EndsWith (".dng"))
+ {
+ gDumpDNG.Append (".dng");
+ }
+
+ }
+
+ else
+ {
+ fprintf (stderr, "*** Unknown option \"-%s\"\n", option.Get ());
+ return 1;
+ }
+
+ }
+
+ if (index == argc)
+ {
+ fprintf (stderr, "*** No file specified\n");
+ return 1;
+ }
+
+ dng_xmp_sdk::InitializeSDK ();
+
+ int result = 0;
+
+ while (index < argc)
+ {
+
+ if (dng_validate (argv [index++]) != dng_error_none)
+ {
+
+ result = 1;
+
+ }
+
+ }
+
+ dng_xmp_sdk::TerminateSDK ();
+
+ return result;
+
+ }
+
+ catch (...)
+ {
+
+ }
+
+ fprintf (stderr, "*** Exception thrown in main routine\n");
+
+ return 1;
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_xmp.cpp b/gpr/source/lib/dng_sdk/dng_xmp.cpp
new file mode 100644
index 0000000..13ba6c3
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_xmp.cpp
@@ -0,0 +1,4417 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xmp.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_xmp.h"
+
+#include "dng_assertions.h"
+#include "dng_date_time.h"
+#include "dng_exceptions.h"
+#include "dng_exif.h"
+#include "dng_image_writer.h"
+#include "dng_iptc.h"
+#include "dng_negative.h"
+#include "dng_string.h"
+#include "dng_string_list.h"
+#include "dng_utils.h"
+#include "dng_xmp_sdk.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+dng_xmp::dng_xmp (dng_memory_allocator &allocator)
+
+ : fAllocator (allocator)
+
+ , fSDK (NULL)
+
+ {
+
+ fSDK = new dng_xmp_sdk ();
+
+ if (!fSDK)
+ {
+ ThrowMemoryFull ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp::dng_xmp (const dng_xmp &xmp)
+
+ : fAllocator (xmp.fAllocator)
+
+ , fSDK (NULL)
+
+ {
+
+ fSDK = new dng_xmp_sdk (*xmp.fSDK);
+
+ if (!fSDK)
+ {
+ ThrowMemoryFull ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp::~dng_xmp ()
+ {
+
+ if (fSDK)
+ {
+
+ delete fSDK;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp * dng_xmp::Clone () const
+ {
+
+ dng_xmp *result = new dng_xmp (*this);
+
+ if (!result)
+ {
+ ThrowMemoryFull ();
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::TrimDecimal (char *s)
+ {
+
+ uint32 len = (uint32) strlen (s);
+
+ while (len > 0)
+ {
+
+ if (s [len - 1] == '0')
+ s [--len] = 0;
+
+ else
+ break;
+
+ }
+
+ if (len > 0)
+ {
+
+ if (s [len - 1] == '.')
+ s [--len] = 0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_xmp::EncodeFingerprint (const dng_fingerprint &f,
+ bool allowInvalid)
+ {
+
+ dng_string result;
+
+ if (f.IsValid () || allowInvalid)
+ {
+
+ char s [dng_fingerprint::kDNGFingerprintSize * 2 + 1];
+
+ f.ToUtf8HexString (s);
+
+ result.Set (s);
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_fingerprint dng_xmp::DecodeFingerprint (const dng_string &s)
+ {
+
+ dng_fingerprint result;
+
+ if (s.Length () == 32)
+ result.FromUtf8HexString (s.Get ());
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_xmp::EncodeGPSVersion (uint32 version)
+ {
+
+ dng_string result;
+
+ if (version)
+ {
+
+ uint8 b0 = (uint8) (version >> 24);
+ uint8 b1 = (uint8) (version >> 16);
+ uint8 b2 = (uint8) (version >> 8);
+ uint8 b3 = (uint8) (version );
+
+ if (b0 <= 9 && b1 <= 9 && b2 <= 9 && b3 <= 9)
+ {
+
+ char s [32];
+
+ sprintf (s,
+ "%u.%u.%u.%u",
+ (unsigned) b0,
+ (unsigned) b1,
+ (unsigned) b2,
+ (unsigned) b3);
+
+ result.Set (s);
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_xmp::DecodeGPSVersion (const dng_string &s)
+ {
+
+ uint32 result = 0;
+
+ if (s.Length () == 7)
+ {
+
+ unsigned b0 = 0;
+ unsigned b1 = 0;
+ unsigned b2 = 0;
+ unsigned b3 = 0;
+
+ if (sscanf (s.Get (),
+ "%u.%u.%u.%u",
+ &b0,
+ &b1,
+ &b2,
+ &b3) == 4)
+ {
+
+ result = (b0 << 24) |
+ (b1 << 16) |
+ (b2 << 8) |
+ (b3 );
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_xmp::EncodeGPSCoordinate (const dng_string &ref,
+ const dng_urational *coord)
+ {
+
+ dng_string result;
+
+ if (ref.Length () == 1 && coord [0].IsValid () &&
+ coord [1].IsValid ())
+ {
+
+ char refChar = ForceUppercase (ref.Get () [0]);
+
+ if (refChar == 'N' ||
+ refChar == 'S' ||
+ refChar == 'E' ||
+ refChar == 'W')
+ {
+
+ char s [256];
+
+ // Use the seconds case if all three values are
+ // integers.
+
+ if (coord [0].d == 1 &&
+ coord [1].d == 1 &&
+ coord [2].d == 1)
+ {
+
+ sprintf (s,
+ "%u,%u,%u%c",
+ (unsigned) coord [0].n,
+ (unsigned) coord [1].n,
+ (unsigned) coord [2].n,
+ refChar);
+
+ }
+
+ // Else we need to use the fractional minutes case.
+
+ else
+ {
+
+ // Find value minutes.
+
+ real64 x = coord [0].As_real64 () * 60.0 +
+ coord [1].As_real64 () +
+ coord [2].As_real64 () * (1.0 / 60.0);
+
+ // Round to fractional four decimal places.
+
+ uint32 y = Round_uint32 (x * 10000.0);
+
+ // Split into degrees and minutes.
+
+ uint32 d = y / (60 * 10000);
+ uint32 m = y % (60 * 10000);
+
+ char min [32];
+
+ sprintf (min, "%.4f", m * (1.0 / 10000.0));
+
+ TrimDecimal (min);
+
+ sprintf (s,
+ "%u,%s%c",
+ (unsigned) d,
+ min,
+ refChar);
+
+ }
+
+ result.Set (s);
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DecodeGPSCoordinate (const dng_string &s,
+ dng_string &ref,
+ dng_urational *coord)
+ {
+
+ ref.Clear ();
+
+ coord [0].Clear ();
+ coord [1].Clear ();
+ coord [2].Clear ();
+
+ if (s.Length () > 1)
+ {
+
+ char refChar = ForceUppercase (s.Get () [s.Length () - 1]);
+
+ if (refChar == 'N' ||
+ refChar == 'S' ||
+ refChar == 'E' ||
+ refChar == 'W')
+ {
+
+ dng_string ss (s);
+
+ ss.Truncate (ss.Length () - 1);
+
+ ss.NormalizeAsCommaSeparatedNumbers();
+
+ int degrees = 0;
+
+ real64 minutes = 0.0;
+ real64 seconds = 0.0;
+
+ int count = sscanf (ss.Get (),
+ "%d,%lf,%lf",
+ &degrees,
+ &minutes,
+ &seconds);
+
+ if (count < 1)
+ {
+ return;
+ }
+
+ // The degree, minute, second values should always be positive.
+
+ if (degrees < 0 || minutes < 0 || seconds < 0)
+ {
+ return;
+ }
+
+ coord [0] = dng_urational ((uint32) degrees, 1);
+
+ if (count <= 2)
+ {
+ coord [1].Set_real64 (minutes, 10000);
+ coord [2] = dng_urational (0, 1);
+ }
+ else
+ {
+ coord [1].Set_real64 (minutes, 1);
+ coord [2].Set_real64 (seconds, 100);
+ }
+
+ char r [2];
+
+ r [0] = refChar;
+ r [1] = 0;
+
+ ref.Set (r);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_xmp::EncodeGPSDateTime (const dng_string &dateStamp,
+ const dng_urational *timeStamp)
+ {
+
+ dng_string result;
+
+ if (timeStamp [0].IsValid () &&
+ timeStamp [1].IsValid () &&
+ timeStamp [2].IsValid ())
+ {
+
+ char s [256];
+
+ char sec [32];
+
+ sprintf (sec,
+ "%09.6f",
+ timeStamp [2].As_real64 ());
+
+ TrimDecimal (sec);
+
+ int year = 0;
+ int month = 0;
+ int day = 0;
+
+ if (dateStamp.NotEmpty ())
+ {
+
+ sscanf (dateStamp.Get (),
+ "%d:%d:%d",
+ &year,
+ &month,
+ &day);
+
+ }
+
+ if (year >= 1 && year <= 9999 &&
+ month >= 1 && month <= 12 &&
+ day >= 1 && day <= 31)
+ {
+
+ sprintf (s,
+ "%04d-%02d-%02dT%02u:%02u:%sZ",
+ year,
+ month,
+ day,
+ (unsigned) Round_uint32 (timeStamp [0].As_real64 ()),
+ (unsigned) Round_uint32 (timeStamp [1].As_real64 ()),
+ sec);
+
+ }
+
+ else
+ {
+
+ sprintf (s,
+ "%02u:%02u:%sZ",
+ (unsigned) Round_uint32 (timeStamp [0].As_real64 ()),
+ (unsigned) Round_uint32 (timeStamp [1].As_real64 ()),
+ sec);
+
+ }
+
+ result.Set (s);
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DecodeGPSDateTime (const dng_string &s,
+ dng_string &dateStamp,
+ dng_urational *timeStamp)
+ {
+
+ dateStamp.Clear ();
+
+ timeStamp [0].Clear ();
+ timeStamp [1].Clear ();
+ timeStamp [2].Clear ();
+
+ if (s.NotEmpty ())
+ {
+
+ unsigned year = 0;
+ unsigned month = 0;
+ unsigned day = 0;
+ unsigned hour = 0;
+ unsigned minute = 0;
+
+ double second = 0.0;
+
+ if (sscanf (s.Get (),
+ "%u-%u-%uT%u:%u:%lf",
+ &year,
+ &month,
+ &day,
+ &hour,
+ &minute,
+ &second) == 6)
+ {
+
+ if (year >= 1 && year <= 9999 &&
+ month >= 1 && month <= 12 &&
+ day >= 1 && day <= 31 )
+ {
+
+ char ss [64];
+
+ sprintf (ss,
+ "%04u:%02u:%02u",
+ year,
+ month,
+ day);
+
+ dateStamp.Set (ss);
+
+ }
+
+ }
+
+ else if (sscanf (s.Get (),
+ "%u:%u:%lf",
+ &hour,
+ &minute,
+ &second) != 3)
+ {
+
+ return;
+
+ }
+
+ timeStamp [0] = dng_urational ((uint32) hour , 1);
+ timeStamp [1] = dng_urational ((uint32) minute, 1);
+
+ timeStamp [2].Set_real64 (second, 1000);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Parse (dng_host &host,
+ const void *buffer,
+ uint32 count)
+ {
+
+ fSDK->Parse (host,
+ (const char *) buffer,
+ count);
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_xmp::Serialize (bool asPacket,
+ uint32 targetBytes,
+ uint32 padBytes,
+ bool forJPEG,
+ bool compact) const
+ {
+
+ return fSDK->Serialize (fAllocator,
+ asPacket,
+ targetBytes,
+ padBytes,
+ forJPEG,
+ compact);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::PackageForJPEG (AutoPtr<dng_memory_block> &stdBlock,
+ AutoPtr<dng_memory_block> &extBlock,
+ dng_string &extDigest) const
+ {
+
+ fSDK->PackageForJPEG (fAllocator,
+ stdBlock,
+ extBlock,
+ extDigest);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::MergeFromJPEG (const dng_xmp &xmp)
+ {
+
+ fSDK->MergeFromJPEG (xmp.fSDK);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::HasMeta () const
+ {
+
+ return fSDK->HasMeta ();
+
+ }
+
+/*****************************************************************************/
+
+void * dng_xmp::GetPrivateMeta ()
+ {
+
+ return fSDK->GetPrivateMeta ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::Exists (const char *ns,
+ const char *path) const
+ {
+
+ return fSDK->Exists (ns, path);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::HasNameSpace (const char *ns) const
+ {
+
+ return fSDK->HasNameSpace (ns);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::IteratePaths (IteratePathsCallback *callback,
+ void *callbackData,
+ const char *ns,
+ const char *path)
+ {
+
+ return fSDK->IteratePaths (callback, callbackData, ns, path);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Remove (const char *ns,
+ const char *path)
+ {
+
+ fSDK->Remove (ns, path);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::RemoveProperties (const char *ns)
+ {
+
+ fSDK->RemoveProperties (ns);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::RemoveEmptyStringOrArray (const char *ns,
+ const char *path)
+ {
+
+ if (path == NULL || path [0] == 0)
+ {
+ return;
+ }
+
+ if (fSDK->IsEmptyString (ns, path) ||
+ fSDK->IsEmptyArray (ns, path))
+ {
+
+ Remove (ns, path);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+static bool RemoveEmptyStringsAndArraysCallback (const char *ns,
+ const char *path,
+ void *callbackData)
+ {
+
+ dng_xmp *xmp = (dng_xmp *) callbackData;
+
+ xmp->RemoveEmptyStringOrArray (ns, path);
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::RemoveEmptyStringsAndArrays (const char *ns)
+ {
+
+ IteratePaths (RemoveEmptyStringsAndArraysCallback,
+ (void *) this,
+ ns,
+ NULL);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Set (const char *ns,
+ const char *path,
+ const char *text)
+ {
+
+ fSDK->Set (ns, path, text);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::GetString (const char *ns,
+ const char *path,
+ dng_string &s) const
+ {
+
+ return fSDK->GetString (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SetString (const char *ns,
+ const char *path,
+ const dng_string &s)
+ {
+
+ fSDK->SetString (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::SyncString (const char *ns,
+ const char *path,
+ dng_string &s,
+ uint32 options)
+ {
+
+ bool isDefault = s.IsEmpty ();
+
+ // Sync 1: Force XMP to match non-XMP.
+
+ if (options & ignoreXMP)
+ {
+
+ if (isDefault || (options & removeXMP))
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ SetString (ns, path, s);
+
+ }
+
+ return false;
+
+ }
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
+ if ((options & preferNonXMP) && !isDefault)
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ SetString (ns, path, s);
+
+ }
+
+ return false;
+
+ }
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
+ if ((options & preferXMP) || isDefault)
+ {
+
+ if (GetString (ns, path, s))
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ return true;
+
+ }
+
+ }
+
+ // Sync 4: From non-XMP to XMP.
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else if (!isDefault)
+ {
+
+ SetString (ns, path, s);
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::GetStringList (const char *ns,
+ const char *path,
+ dng_string_list &list) const
+ {
+
+ return fSDK->GetStringList (ns, path, list);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SetStringList (const char *ns,
+ const char *path,
+ const dng_string_list &list,
+ bool isBag)
+ {
+
+ fSDK->SetStringList (ns, path, list, isBag);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncStringList (const char *ns,
+ const char *path,
+ dng_string_list &list,
+ bool isBag,
+ uint32 options)
+ {
+
+ bool isDefault = (list.Count () == 0);
+
+ // First make sure the XMP is not badly formatted, since
+ // this breaks some Photoshop logic.
+
+ ValidateStringList (ns, path);
+
+ // Sync 1: Force XMP to match non-XMP.
+
+ if (options & ignoreXMP)
+ {
+
+ if (isDefault)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ SetStringList (ns, path, list, isBag);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
+ if ((options & preferNonXMP) && !isDefault)
+ {
+
+ SetStringList (ns, path, list, isBag);
+
+ return;
+
+ }
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
+ if ((options & preferXMP) || isDefault)
+ {
+
+ if (GetStringList (ns, path, list))
+ {
+
+ return;
+
+ }
+
+ }
+
+ // Sync 4: From non-XMP to XMP.
+
+ if (!isDefault)
+ {
+
+ SetStringList (ns, path, list, isBag);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ const dng_string &s)
+ {
+
+ dng_string ss (s);
+
+ ss.SetLineEndings ('\n');
+
+ ss.StripLowASCII ();
+
+ fSDK->SetStructField (ns, path, fieldNS, fieldName, ss.Get ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ const char *s)
+ {
+
+ fSDK->SetStructField (ns, path, fieldNS, fieldName, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DeleteStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName)
+ {
+
+ fSDK->DeleteStructField (ns, path, fieldNS, fieldName);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::GetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const
+ {
+
+ return fSDK->GetStructField (ns, path, fieldNS, fieldName, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SetAltLangDefault (const char *ns,
+ const char *path,
+ const dng_string &s)
+ {
+
+ fSDK->SetAltLangDefault (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::GetAltLangDefault (const char *ns,
+ const char *path,
+ dng_string &s) const
+ {
+
+ return fSDK->GetAltLangDefault (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::SyncAltLangDefault (const char *ns,
+ const char *path,
+ dng_string &s,
+ uint32 options)
+ {
+
+ bool isDefault = s.IsEmpty ();
+
+ // Sync 1: Force XMP to match non-XMP.
+
+ if (options & ignoreXMP)
+ {
+
+ if (isDefault)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ SetAltLangDefault (ns, path, s);
+
+ }
+
+ return false;
+
+ }
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
+ if ((options & preferNonXMP) && !isDefault)
+ {
+
+ SetAltLangDefault (ns, path, s);
+
+ return false;
+
+ }
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
+ if ((options & preferXMP) || isDefault)
+ {
+
+ if (GetAltLangDefault (ns, path, s))
+ {
+
+ return true;
+
+ }
+
+ }
+
+ // Sync 4: From non-XMP to XMP.
+
+ if (!isDefault)
+ {
+
+ SetAltLangDefault (ns, path, s);
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::GetBoolean (const char *ns,
+ const char *path,
+ bool &x) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.Matches ("True"))
+ {
+
+ x = true;
+
+ return true;
+
+ }
+
+ if (s.Matches ("False"))
+ {
+
+ x = false;
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SetBoolean (const char *ns,
+ const char *path,
+ bool x)
+ {
+
+ Set (ns, path, x ? "True" : "False");
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::Get_int32 (const char *ns,
+ const char *path,
+ int32 &x) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ int y = 0;
+
+ if (sscanf (s.Get (), "%d", &y) == 1)
+ {
+
+ x = y;
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Set_int32 (const char *ns,
+ const char *path,
+ int32 x,
+ bool usePlus)
+ {
+
+ char s [64];
+
+ if (x > 0 && usePlus)
+ {
+ sprintf (s, "+%d", (int) x);
+ }
+ else
+ {
+ sprintf (s, "%d", (int) x);
+ }
+
+ Set (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::Get_uint32 (const char *ns,
+ const char *path,
+ uint32 &x) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ unsigned y = 0;
+
+ if (sscanf (s.Get (), "%u", &y) == 1)
+ {
+
+ x = y;
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Set_uint32 (const char *ns,
+ const char *path,
+ uint32 x)
+ {
+
+ char s [64];
+
+ sprintf (s,
+ "%u",
+ (unsigned) x);
+
+ Set (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Sync_uint32 (const char *ns,
+ const char *path,
+ uint32 &x,
+ bool isDefault,
+ uint32 options)
+ {
+
+ // Sync 1: Force XMP to match non-XMP.
+
+ if (options & ignoreXMP)
+ {
+
+ if (isDefault || (options & removeXMP))
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_uint32 (ns, path, x);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
+ if ((options & preferNonXMP) && !isDefault)
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_uint32 (ns, path, x);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
+ if ((options & preferXMP) || isDefault)
+ {
+
+ if (Get_uint32 (ns, path, x))
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ return;
+
+ }
+
+ }
+
+ // Sync 4: From non-XMP to XMP.
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else if (!isDefault)
+ {
+
+ Set_uint32 (ns, path, x);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Sync_uint32_array (const char *ns,
+ const char *path,
+ uint32 *data,
+ uint32 &count,
+ uint32 maxCount,
+ uint32 options)
+ {
+
+ dng_string_list list;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ char s [32];
+
+ sprintf (s, "%u", (unsigned) data [j]);
+
+ dng_string ss;
+
+ ss.Set (s);
+
+ list.Append (ss);
+
+ }
+
+ SyncStringList (ns,
+ path,
+ list,
+ false,
+ options);
+
+ count = 0;
+
+ for (uint32 k = 0; k < maxCount; k++)
+ {
+
+ data [k] = 0;
+
+ if (k < list.Count ())
+ {
+
+ unsigned x = 0;
+
+ if (sscanf (list [k].Get (), "%u", &x) == 1)
+ {
+
+ data [count++] = x;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::Get_real64 (const char *ns,
+ const char *path,
+ real64 &x) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ double y = 0;
+
+ if (sscanf (s.Get (), "%lf", &y) == 1)
+ {
+
+ x = y;
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Set_real64 (const char *ns,
+ const char *path,
+ real64 x,
+ uint32 places,
+ bool trim,
+ bool usePlus)
+ {
+
+ char s [64];
+
+ if (x > 0.0 && usePlus)
+ {
+ sprintf (s, "+%0.*f", (unsigned) places, (double) x);
+ }
+ else
+ {
+ sprintf (s, "%0.*f", (unsigned) places, (double) x);
+ }
+
+ if (trim)
+ {
+
+ while (s [strlen (s) - 1] == '0')
+ {
+ s [strlen (s) - 1] = 0;
+ }
+
+ if (s [strlen (s) - 1] == '.')
+ {
+ s [strlen (s) - 1] = 0;
+ }
+
+ }
+
+ Set (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::Get_urational (const char *ns,
+ const char *path,
+ dng_urational &r) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ unsigned n = 0;
+ unsigned d = 0;
+
+ if (sscanf (s.Get (), "%u/%u", &n, &d) == 2)
+ {
+
+ if (d != 0)
+ {
+
+ r = dng_urational (n, d);
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Set_urational (const char *ns,
+ const char *path,
+ const dng_urational &r)
+ {
+
+ char s [64];
+
+ sprintf (s,
+ "%u/%u",
+ (unsigned) r.n,
+ (unsigned) r.d);
+
+ Set (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Sync_urational (const char *ns,
+ const char *path,
+ dng_urational &r,
+ uint32 options)
+ {
+
+ bool isDefault = r.NotValid ();
+
+ // Sync 1: Force XMP to match non-XMP.
+
+ if (options & ignoreXMP)
+ {
+
+ if (isDefault || (options & removeXMP))
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_urational (ns, path, r);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
+ if ((options & preferNonXMP) && !isDefault)
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_urational (ns, path, r);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
+ if ((options & preferXMP) || isDefault)
+ {
+
+ if (Get_urational (ns, path, r))
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ return;
+
+ }
+
+ }
+
+ // Sync 4: From non-XMP to XMP.
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else if (!isDefault)
+ {
+
+ Set_urational (ns, path, r);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::Get_srational (const char *ns,
+ const char *path,
+ dng_srational &r) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ int n = 0;
+ int d = 0;
+
+ if (sscanf (s.Get (), "%d/%d", &n, &d) == 2)
+ {
+
+ if (d != 0)
+ {
+
+ r = dng_srational (n, d);
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Set_srational (const char *ns,
+ const char *path,
+ const dng_srational &r)
+ {
+
+ char s [64];
+
+ sprintf (s,
+ "%d/%d",
+ (int) r.n,
+ (int) r.d);
+
+ Set (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::Sync_srational (const char *ns,
+ const char *path,
+ dng_srational &r,
+ uint32 options)
+ {
+
+ bool isDefault = r.NotValid ();
+
+ // Sync 1: Force XMP to match non-XMP.
+
+ if (options & ignoreXMP)
+ {
+
+ if (isDefault || (options & removeXMP))
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_srational (ns, path, r);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
+ if ((options & preferNonXMP) && !isDefault)
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_srational (ns, path, r);
+
+ }
+
+ return;
+
+ }
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
+ if ((options & preferXMP) || isDefault)
+ {
+
+ if (Get_srational (ns, path, r))
+ {
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ return;
+
+ }
+
+ }
+
+ // Sync 4: From non-XMP to XMP.
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else if (!isDefault)
+ {
+
+ Set_srational (ns, path, r);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::GetFingerprint (const char *ns,
+ const char *path,
+ dng_fingerprint &print) const
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ dng_fingerprint temp = DecodeFingerprint (s);
+
+ if (temp.IsValid ())
+ {
+
+ print = temp;
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetFingerprint (const char *ns,
+ const char *tag,
+ const dng_fingerprint &print,
+ bool allowInvalid)
+ {
+
+ dng_string s = EncodeFingerprint (print, allowInvalid);
+
+ if (s.IsEmpty ())
+ {
+
+ Remove (ns, tag);
+
+ }
+
+ else
+ {
+
+ SetString (ns, tag, s);
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetVersion2to4 (const char *ns,
+ const char *path,
+ uint32 version)
+ {
+
+ char buf [32];
+
+ if (version & 0x000000ff)
+ {
+
+ // x.x.x.x
+
+ sprintf (buf,
+ "%u.%u.%u.%u",
+ (unsigned) ((version >> 24) & 0xff),
+ (unsigned) ((version >> 16) & 0xff),
+ (unsigned) ((version >> 8) & 0xff),
+ (unsigned) ((version ) & 0xff));
+
+ }
+
+ else if (version & 0x0000ff00)
+ {
+
+ // x.x.x
+
+ sprintf (buf,
+ "%u.%u.%u",
+ (unsigned) ((version >> 24) & 0xff),
+ (unsigned) ((version >> 16) & 0xff),
+ (unsigned) ((version >> 8) & 0xff));
+
+ }
+
+ else
+ {
+
+ // x.x
+
+ sprintf (buf,
+ "%u.%u",
+ (unsigned) ((version >> 24) & 0xff),
+ (unsigned) ((version >> 16) & 0xff));
+
+ }
+
+ Set (ns, path, buf);
+
+ }
+
+/******************************************************************************/
+
+dng_fingerprint dng_xmp::GetIPTCDigest () const
+ {
+
+ dng_fingerprint digest;
+
+ if (GetFingerprint (XMP_NS_PHOTOSHOP,
+ "LegacyIPTCDigest",
+ digest))
+ {
+
+ return digest;
+
+ }
+
+ return dng_fingerprint ();
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetIPTCDigest (dng_fingerprint &digest)
+ {
+
+ SetFingerprint (XMP_NS_PHOTOSHOP,
+ "LegacyIPTCDigest",
+ digest);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::ClearIPTCDigest ()
+ {
+
+ Remove (XMP_NS_PHOTOSHOP, "LegacyIPTCDigest");
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncIPTC (dng_iptc &iptc,
+ uint32 options)
+ {
+
+ SyncAltLangDefault (XMP_NS_DC,
+ "title",
+ iptc.fTitle,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "Category",
+ iptc.fCategory,
+ options);
+
+ {
+
+ uint32 x = 0xFFFFFFFF;
+
+ if (iptc.fUrgency >= 0)
+ {
+
+ x = (uint32) iptc.fUrgency;
+
+ }
+
+ Sync_uint32 (XMP_NS_PHOTOSHOP,
+ "Urgency",
+ x,
+ x == 0xFFFFFFFF,
+ options);
+
+ if (x <= 9)
+ {
+
+ iptc.fUrgency = (int32) x;
+
+ }
+
+ }
+
+ SyncStringList (XMP_NS_PHOTOSHOP,
+ "SupplementalCategories",
+ iptc.fSupplementalCategories,
+ true,
+ options);
+
+ SyncStringList (XMP_NS_PHOTOSHOP,
+ "Keywords",
+ iptc.fKeywords,
+ true,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "Instructions",
+ iptc.fInstructions,
+ options);
+
+ {
+
+ dng_string s = iptc.fDateTimeCreated.Encode_ISO_8601 ();
+
+ if (SyncString (XMP_NS_PHOTOSHOP,
+ "DateCreated",
+ s,
+ options))
+ {
+
+ iptc.fDateTimeCreated.Decode_ISO_8601 (s.Get ());
+
+ }
+
+ }
+
+ {
+
+ dng_string s = iptc.fDigitalCreationDateTime.Encode_ISO_8601 ();
+
+ if (SyncString (XMP_NS_EXIF,
+ "DateTimeDigitized",
+ s,
+ options))
+ {
+
+ iptc.fDigitalCreationDateTime.Decode_ISO_8601 (s.Get ());
+
+ }
+
+ }
+
+ SyncStringList (XMP_NS_DC,
+ "creator",
+ iptc.fAuthors,
+ false,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "AuthorsPosition",
+ iptc.fAuthorsPosition,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "City",
+ iptc.fCity,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "State",
+ iptc.fState,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "Country",
+ iptc.fCountry,
+ options);
+
+ SyncString (XMP_NS_IPTC,
+ "CountryCode",
+ iptc.fCountryCode,
+ options);
+
+ SyncString (XMP_NS_IPTC,
+ "Location",
+ iptc.fLocation,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "TransmissionReference",
+ iptc.fTransmissionReference,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "Headline",
+ iptc.fHeadline,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "Credit",
+ iptc.fCredit,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "Source",
+ iptc.fSource,
+ options);
+
+ SyncAltLangDefault (XMP_NS_DC,
+ "rights",
+ iptc.fCopyrightNotice,
+ options);
+
+ SyncAltLangDefault (XMP_NS_DC,
+ "description",
+ iptc.fDescription,
+ options);
+
+ SyncString (XMP_NS_PHOTOSHOP,
+ "CaptionWriter",
+ iptc.fDescriptionWriter,
+ options);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::IngestIPTC (dng_metadata &metadata,
+ bool xmpIsNewer)
+ {
+
+ if (metadata.IPTCLength ())
+ {
+
+ // Parse the IPTC block.
+
+ dng_iptc iptc;
+
+ iptc.Parse (metadata.IPTCData (),
+ metadata.IPTCLength (),
+ metadata.IPTCOffset ());
+
+ // Compute fingerprint of IPTC data both ways, including and
+ // excluding the padding data.
+
+ dng_fingerprint iptcDigest1 = metadata.IPTCDigest (true );
+ dng_fingerprint iptcDigest2 = metadata.IPTCDigest (false);
+
+ // See if there is an IPTC fingerprint stored in the XMP.
+
+ dng_fingerprint xmpDigest = GetIPTCDigest ();
+
+ if (xmpDigest.IsValid ())
+ {
+
+ // If they match, the XMP was already synced with this
+ // IPTC block, and we should not resync since it might
+ // overwrite changes in the XMP data.
+
+ if (iptcDigest1 == xmpDigest)
+ {
+
+ return;
+
+ }
+
+ // If it matches the incorrectly computed digest, skip
+ // the sync, but fix the digest in the XMP.
+
+ if (iptcDigest2 == xmpDigest)
+ {
+
+ SetIPTCDigest (iptcDigest1);
+
+ return;
+
+ }
+
+ // Else the IPTC has changed, so force an update.
+
+ xmpIsNewer = false;
+
+ }
+
+ else
+ {
+
+ // There is no IPTC digest. Previously we would
+ // prefer the IPTC in this case, but the MWG suggests
+ // that we prefer the XMP in this case.
+
+ xmpIsNewer = true;
+
+ }
+
+ // Remember the fingerprint of the IPTC we are syncing with.
+
+ SetIPTCDigest (iptcDigest1);
+
+ // Find the sync options.
+
+ uint32 options = xmpIsNewer ? preferXMP
+ : preferNonXMP;
+
+ // Synchronize the fields.
+
+ SyncIPTC (iptc, options);
+
+ }
+
+ // After the IPTC data is moved to XMP, we don't need it anymore.
+
+ metadata.ClearIPTC ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::RebuildIPTC (dng_metadata &metadata,
+ dng_memory_allocator &allocator,
+ bool padForTIFF)
+ {
+
+ // If there is no XMP, then there is no IPTC.
+
+ if (!fSDK->HasMeta ())
+ {
+ return;
+ }
+
+ // Extract the legacy IPTC fields from the XMP data.
+
+ dng_iptc iptc;
+
+ SyncIPTC (iptc, preferXMP);
+
+ // Build legacy IPTC record
+
+ if (iptc.NotEmpty ())
+ {
+
+ AutoPtr<dng_memory_block> block (iptc.Spool (allocator,
+ padForTIFF));
+
+ metadata.SetIPTC (block);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncFlash (uint32 &flashState,
+ uint32 &flashMask,
+ uint32 options)
+ {
+
+ bool isDefault = (flashState == 0xFFFFFFFF);
+
+ if ((options & ignoreXMP) || !isDefault)
+ {
+
+ Remove (XMP_NS_EXIF, "Flash");
+
+ }
+
+ if (!isDefault)
+ {
+
+ fSDK->SetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Fired",
+ (flashState & 0x1) ? "True" : "False");
+
+ if (((flashMask >> 1) & 3) == 3)
+ {
+
+ char s [8];
+
+ sprintf (s, "%u", (unsigned) ((flashState >> 1) & 3));
+
+ fSDK->SetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Return",
+ s);
+
+ }
+
+ if (((flashMask >> 3) & 3) == 3)
+ {
+
+ char s [8];
+
+ sprintf (s, "%u", (unsigned) ((flashState >> 3) & 3));
+
+ fSDK->SetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Mode",
+ s);
+
+ }
+
+ if ((flashMask & (1 << 5)) != 0)
+ {
+
+ fSDK->SetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Function",
+ (flashState & (1 << 5)) ? "True" : "False");
+
+ }
+
+ if ((flashMask & (1 << 6)) != 0)
+ {
+
+ fSDK->SetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "RedEyeMode",
+ (flashState & (1 << 6)) ? "True" : "False");
+
+ }
+
+ }
+
+ else if (fSDK->Exists (XMP_NS_EXIF, "Flash"))
+ {
+
+ dng_string s;
+
+ if (fSDK->GetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Fired",
+ s))
+ {
+
+ flashState = 0;
+ flashMask = 1;
+
+ if (s.Matches ("True"))
+ {
+ flashState |= 1;
+ }
+
+ if (fSDK->GetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Return",
+ s))
+ {
+
+ unsigned x = 0;
+
+ if (sscanf (s.Get (), "%u", &x) == 1 && x <= 3)
+ {
+
+ flashState |= x << 1;
+ flashMask |= 3 << 1;
+
+ }
+
+ }
+
+ if (fSDK->GetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Mode",
+ s))
+ {
+
+ unsigned x = 0;
+
+ if (sscanf (s.Get (), "%u", &x) == 1 && x <= 3)
+ {
+
+ flashState |= x << 3;
+ flashMask |= 3 << 3;
+
+ }
+
+ }
+
+ if (fSDK->GetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "Function",
+ s))
+ {
+
+ flashMask |= 1 << 5;
+
+ if (s.Matches ("True"))
+ {
+ flashState |= 1 << 5;
+ }
+
+ }
+
+ if (fSDK->GetStructField (XMP_NS_EXIF,
+ "Flash",
+ XMP_NS_EXIF,
+ "RedEyeMode",
+ s))
+ {
+
+ flashMask |= 1 << 6;
+
+ if (s.Matches ("True"))
+ {
+ flashState |= 1 << 6;
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncExif (dng_exif &exif,
+ const dng_exif *originalExif,
+ bool doingUpdateFromXMP,
+ bool removeFromXMP)
+ {
+
+ DNG_ASSERT (!doingUpdateFromXMP || originalExif,
+ "Must have original EXIF if doingUpdateFromXMP");
+
+ // Default synchronization options for the read-only fields.
+
+ uint32 readOnly = doingUpdateFromXMP ? ignoreXMP
+ : preferNonXMP;
+
+ // Option for removable fields.
+
+ uint32 removable = removeFromXMP ? removeXMP
+ : 0;
+
+ // Make:
+
+ SyncString (XMP_NS_TIFF,
+ "Make",
+ exif.fMake,
+ readOnly + removable);
+
+ // Model:
+
+ SyncString (XMP_NS_TIFF,
+ "Model",
+ exif.fModel,
+ readOnly + removable);
+
+ // Exif version number:
+
+ {
+
+ dng_string exifVersion;
+
+ if (exif.fExifVersion)
+ {
+
+ unsigned b0 = ((exif.fExifVersion >> 24) & 0x0FF) - '0';
+ unsigned b1 = ((exif.fExifVersion >> 16) & 0x0FF) - '0';
+ unsigned b2 = ((exif.fExifVersion >> 8) & 0x0FF) - '0';
+ unsigned b3 = ((exif.fExifVersion ) & 0x0FF) - '0';
+
+ if (b0 <= 9 && b1 <= 9 && b2 <= 9 && b3 <= 9)
+ {
+
+ char s [5];
+
+ sprintf (s,
+ "%1u%1u%1u%1u",
+ b0,
+ b1,
+ b2,
+ b3);
+
+ exifVersion.Set (s);
+
+ }
+
+ }
+
+ SyncString (XMP_NS_EXIF,
+ "ExifVersion",
+ exifVersion,
+ readOnly);
+
+ if (exifVersion.NotEmpty ())
+ {
+
+ unsigned b0;
+ unsigned b1;
+ unsigned b2;
+ unsigned b3;
+
+ if (sscanf (exifVersion.Get (),
+ "%1u%1u%1u%1u",
+ &b0,
+ &b1,
+ &b2,
+ &b3) == 4)
+ {
+
+ if (b0 <= 9 && b1 <= 9 && b2 <= 9 && b3 <= 9)
+ {
+
+ b0 += '0';
+ b1 += '0';
+ b2 += '0';
+ b3 += '0';
+
+ exif.fExifVersion = (b0 << 24) |
+ (b1 << 16) |
+ (b2 << 8) |
+ (b3 );
+
+ }
+
+ }
+
+ }
+
+ // Provide default value for ExifVersion.
+
+ if (!exif.fExifVersion)
+ {
+
+ exif.fExifVersion = DNG_CHAR4 ('0','2','2','1');
+
+ Set (XMP_NS_EXIF,
+ "ExifVersion",
+ "0221");
+
+ }
+
+ if (removeFromXMP)
+ {
+
+ Remove (XMP_NS_EXIF, "ExifVersion");
+
+ }
+
+ }
+
+ // ExposureTime / ShutterSpeedValue:
+
+ {
+
+ // Process twice in case XMP contains only one of the
+ // two fields.
+
+ for (uint32 pass = 0; pass < 2; pass++)
+ {
+
+ dng_urational et = exif.fExposureTime;
+
+ Sync_urational (XMP_NS_EXIF,
+ "ExposureTime",
+ et,
+ readOnly);
+
+ if (et.IsValid ())
+ {
+
+ exif.SetExposureTime (et.As_real64 (), false);
+
+ }
+
+ dng_srational ss = exif.fShutterSpeedValue;
+
+ Sync_srational (XMP_NS_EXIF,
+ "ShutterSpeedValue",
+ ss,
+ readOnly);
+
+ if (ss.IsValid ())
+ {
+
+ exif.SetShutterSpeedValue (ss.As_real64 ());
+
+ }
+
+ }
+
+ if (removeFromXMP)
+ {
+
+ Remove (XMP_NS_EXIF, "ExposureTime");
+
+ Remove (XMP_NS_EXIF, "ShutterSpeedValue");
+
+ }
+
+ }
+
+ // FNumber / ApertureValue:
+
+ {
+
+ for (uint32 pass = 0; pass < 2; pass++)
+ {
+
+ dng_urational fs = exif.fFNumber;
+
+ Sync_urational (XMP_NS_EXIF,
+ "FNumber",
+ fs,
+ readOnly);
+
+ if (fs.IsValid ())
+ {
+
+ exif.SetFNumber (fs.As_real64 ());
+
+ }
+
+ dng_urational av = exif.fApertureValue;
+
+ Sync_urational (XMP_NS_EXIF,
+ "ApertureValue",
+ av,
+ readOnly);
+
+ if (av.IsValid ())
+ {
+
+ exif.SetApertureValue (av.As_real64 ());
+
+ }
+
+ }
+
+ if (removeFromXMP)
+ {
+
+ Remove (XMP_NS_EXIF, "FNumber");
+
+ Remove (XMP_NS_EXIF, "ApertureValue");
+
+ }
+
+ }
+
+ // Exposure program:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "ExposureProgram",
+ exif.fExposureProgram,
+ exif.fExposureProgram == 0xFFFFFFFF,
+ readOnly + removable);
+
+ // ISO Speed Ratings:
+
+ {
+
+ uint32 isoSpeedRatingsCount = 0;
+
+ uint32 isoSpeedRatingsOptions = readOnly;
+
+ uint32 oldISOSpeedRatings [3];
+
+ memcpy (oldISOSpeedRatings,
+ exif.fISOSpeedRatings,
+ sizeof (oldISOSpeedRatings));
+
+ bool checkXMPForHigherISO = false;
+
+ for (uint32 j = 0; j < 3; j++)
+ {
+
+ // Special case: the EXIF 2.2x standard represents ISO speed ratings with
+ // 2 bytes, which cannot hold ISO speed ratings above 65535 (e.g.,
+ // 102400). If the EXIF ISO speed rating value is 65535, prefer the XMP
+ // ISOSpeedRatings tag value.
+
+ if (exif.fISOSpeedRatings [j] == 65535)
+ {
+
+ isoSpeedRatingsOptions = preferXMP;
+
+ checkXMPForHigherISO = true;
+
+ isoSpeedRatingsCount = 0;
+
+ break;
+
+ }
+
+ else if (exif.fISOSpeedRatings [j] == 0)
+ {
+ break;
+ }
+
+ isoSpeedRatingsCount++;
+
+ }
+
+ Sync_uint32_array (XMP_NS_EXIF,
+ "ISOSpeedRatings",
+ exif.fISOSpeedRatings,
+ isoSpeedRatingsCount,
+ 3,
+ isoSpeedRatingsOptions);
+
+ // If the EXIF ISO was 65535 and we failed to find anything meaningful in the
+ // XMP, then we fall back to the EXIF ISO.
+
+ if (checkXMPForHigherISO && (isoSpeedRatingsCount == 0))
+ {
+
+ memcpy (exif.fISOSpeedRatings,
+ oldISOSpeedRatings,
+ sizeof (oldISOSpeedRatings));
+
+ }
+
+ // Only remove the ISO tag if there are not ratings over 65535.
+
+ if (removeFromXMP)
+ {
+
+ bool hasHighISO = false;
+
+ for (uint32 j = 0; j < 3; j++)
+ {
+
+ if (exif.fISOSpeedRatings [j] == 0)
+ {
+ break;
+ }
+
+ hasHighISO = hasHighISO || (exif.fISOSpeedRatings [j] > 65535);
+
+ }
+
+ if (!hasHighISO)
+ {
+
+ Remove (XMP_NS_EXIF, "ISOSpeedRatings");
+
+ }
+
+ }
+
+ }
+
+ // SensitivityType:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "SensitivityType",
+ exif.fSensitivityType,
+ exif.fSensitivityType == stUnknown,
+ readOnly + removable);
+
+ // StandardOutputSensitivity:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "StandardOutputSensitivity",
+ exif.fStandardOutputSensitivity,
+ exif.fStandardOutputSensitivity == 0,
+ readOnly + removable);
+
+ // RecommendedExposureIndex:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "RecommendedExposureIndex",
+ exif.fRecommendedExposureIndex,
+ exif.fRecommendedExposureIndex == 0,
+ readOnly + removable);
+
+ // ISOSpeed:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "ISOSpeed",
+ exif.fISOSpeed,
+ exif.fISOSpeed == 0,
+ readOnly + removable);
+
+ // ISOSpeedLatitudeyyy:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "ISOSpeedLatitudeyyy",
+ exif.fISOSpeedLatitudeyyy,
+ exif.fISOSpeedLatitudeyyy == 0,
+ readOnly + removable);
+
+ // ISOSpeedLatitudezzz:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "ISOSpeedLatitudezzz",
+ exif.fISOSpeedLatitudezzz,
+ exif.fISOSpeedLatitudezzz == 0,
+ readOnly + removable);
+
+ // ExposureIndex:
+
+ Sync_urational (XMP_NS_EXIF,
+ "ExposureIndex",
+ exif.fExposureIndex,
+ readOnly + removable);
+
+ // Brightness Value:
+
+ Sync_srational (XMP_NS_EXIF,
+ "BrightnessValue",
+ exif.fBrightnessValue,
+ readOnly + removable);
+
+ // Exposure Bias:
+
+ Sync_srational (XMP_NS_EXIF,
+ "ExposureBiasValue",
+ exif.fExposureBiasValue,
+ readOnly + removable);
+
+ // Max Aperture:
+
+ Sync_urational (XMP_NS_EXIF,
+ "MaxApertureValue",
+ exif.fMaxApertureValue,
+ readOnly + removable);
+
+ // Subject Distance:
+
+ Sync_urational (XMP_NS_EXIF,
+ "SubjectDistance",
+ exif.fSubjectDistance,
+ readOnly + removable);
+
+ // Metering Mode:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "MeteringMode",
+ exif.fMeteringMode,
+ exif.fMeteringMode == 0xFFFFFFFF,
+ readOnly + removable);
+
+ // Light Source:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "LightSource",
+ exif.fLightSource,
+ exif.fLightSource > 0x0FFFF,
+ readOnly + removable);
+
+ // Flash State:
+
+ SyncFlash (exif.fFlash,
+ exif.fFlashMask,
+ readOnly);
+
+ if (removeFromXMP)
+ {
+ Remove (XMP_NS_EXIF, "Flash");
+ }
+
+ // Focal Length:
+
+ Sync_urational (XMP_NS_EXIF,
+ "FocalLength",
+ exif.fFocalLength,
+ readOnly + removable);
+
+ // Sensing Method.
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "SensingMethod",
+ exif.fSensingMethod,
+ exif.fSensingMethod > 0x0FFFF,
+ readOnly + removable);
+
+ // File Source.
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "FileSource",
+ exif.fFileSource,
+ exif.fFileSource > 0x0FF,
+ readOnly + removable);
+
+ // Scene Type.
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "SceneType",
+ exif.fSceneType,
+ exif.fSceneType > 0x0FF,
+ readOnly + removable);
+
+ // Focal Length in 35mm Film:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "FocalLengthIn35mmFilm",
+ exif.fFocalLengthIn35mmFilm,
+ exif.fFocalLengthIn35mmFilm == 0,
+ readOnly + removable);
+
+ // Custom Rendered:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "CustomRendered",
+ exif.fCustomRendered,
+ exif.fCustomRendered > 0x0FFFF,
+ readOnly + removable);
+
+ // Exposure Mode:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "ExposureMode",
+ exif.fExposureMode,
+ exif.fExposureMode > 0x0FFFF,
+ readOnly + removable);
+
+ // White Balance:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "WhiteBalance",
+ exif.fWhiteBalance,
+ exif.fWhiteBalance > 0x0FFFF,
+ readOnly + removable);
+
+ // Scene Capture Type:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "SceneCaptureType",
+ exif.fSceneCaptureType,
+ exif.fSceneCaptureType > 0x0FFFF,
+ readOnly + removable);
+
+ // Gain Control:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "GainControl",
+ exif.fGainControl,
+ exif.fGainControl > 0x0FFFF,
+ readOnly + removable);
+
+ // Contrast:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "Contrast",
+ exif.fContrast,
+ exif.fContrast > 0x0FFFF,
+ readOnly + removable);
+
+ // Saturation:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "Saturation",
+ exif.fSaturation,
+ exif.fSaturation > 0x0FFFF,
+ readOnly + removable);
+
+ // Sharpness:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "Sharpness",
+ exif.fSharpness,
+ exif.fSharpness > 0x0FFFF,
+ readOnly + removable);
+
+ // Subject Distance Range:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "SubjectDistanceRange",
+ exif.fSubjectDistanceRange,
+ exif.fSubjectDistanceRange > 0x0FFFF,
+ readOnly + removable);
+
+ // Subject Area:
+
+ Sync_uint32_array (XMP_NS_EXIF,
+ "SubjectArea",
+ exif.fSubjectArea,
+ exif.fSubjectAreaCount,
+ sizeof (exif.fSubjectArea ) /
+ sizeof (exif.fSubjectArea [0]),
+ readOnly);
+
+ if (removeFromXMP)
+ {
+ Remove (XMP_NS_EXIF, "SubjectArea");
+ }
+
+ // Digital Zoom Ratio:
+
+ Sync_urational (XMP_NS_EXIF,
+ "DigitalZoomRatio",
+ exif.fDigitalZoomRatio,
+ readOnly + removable);
+
+ // Focal Plane Resolution:
+
+ Sync_urational (XMP_NS_EXIF,
+ "FocalPlaneXResolution",
+ exif.fFocalPlaneXResolution,
+ readOnly + removable);
+
+ Sync_urational (XMP_NS_EXIF,
+ "FocalPlaneYResolution",
+ exif.fFocalPlaneYResolution,
+ readOnly + removable);
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "FocalPlaneResolutionUnit",
+ exif.fFocalPlaneResolutionUnit,
+ exif.fFocalPlaneResolutionUnit > 0x0FFFF,
+ readOnly + removable);
+
+ // ImageDescription: (XMP is is always preferred)
+
+ if (fSDK->GetAltLangDefault (XMP_NS_DC,
+ "description",
+ exif.fImageDescription))
+
+ {
+
+ }
+
+ else if (doingUpdateFromXMP)
+ {
+
+ exif.fImageDescription.Clear ();
+
+ if (originalExif->fImageDescription.NotEmpty ())
+ {
+
+ fSDK->SetAltLangDefault (XMP_NS_DC,
+ "description",
+ dng_string ());
+
+ }
+
+ }
+
+ else if (exif.fImageDescription.NotEmpty ())
+ {
+
+ fSDK->SetAltLangDefault (XMP_NS_DC,
+ "description",
+ exif.fImageDescription);
+
+ }
+
+ // Artist: (XMP is is always preferred)
+
+ {
+
+ dng_string_list xmpList;
+
+ if (fSDK->GetStringList (XMP_NS_DC,
+ "creator",
+ xmpList))
+ {
+
+ exif.fArtist.Clear ();
+
+ if (xmpList.Count () > 0)
+ {
+
+ uint32 j;
+
+ uint32 bufferSize = xmpList.Count () * 4 + 1;
+
+ for (j = 0; j < xmpList.Count (); j++)
+ {
+
+ bufferSize += xmpList [j].Length () * 2;
+
+ }
+
+ dng_memory_data temp (bufferSize);
+
+ char *t = temp.Buffer_char ();
+
+ for (j = 0; j < xmpList.Count (); j++)
+ {
+
+ const char *s = xmpList [j].Get ();
+
+ bool needQuotes = xmpList [j].Contains ("; ") ||
+ s [0] == '\"';
+
+ if (needQuotes)
+ {
+ *(t++) = '\"';
+ }
+
+ while (s [0] != 0)
+ {
+
+ if (s [0] == '\"' && needQuotes)
+ {
+ *(t++) = '\"';
+ }
+
+ *(t++) = *(s++);
+
+ }
+
+ if (needQuotes)
+ {
+ *(t++) = '\"';
+ }
+
+ if (j != xmpList.Count () - 1)
+ {
+ *(t++) = ';';
+ *(t++) = ' ';
+ }
+ else
+ {
+ *t = 0;
+ }
+
+ }
+
+ exif.fArtist.Set (temp.Buffer_char ());
+
+ }
+
+ }
+
+ else if (doingUpdateFromXMP)
+ {
+
+ exif.fArtist.Clear ();
+
+ if (originalExif->fArtist.NotEmpty ())
+ {
+
+ dng_string_list fakeList;
+
+ fakeList.Append (dng_string ());
+
+ SetStringList (XMP_NS_DC,
+ "creator",
+ fakeList,
+ false);
+
+ }
+
+ }
+
+ else if (exif.fArtist.NotEmpty ())
+ {
+
+ dng_string_list newList;
+
+ dng_memory_data temp (exif.fArtist.Length () + 1);
+
+ const char *s = exif.fArtist.Get ();
+
+ char *t = temp.Buffer_char ();
+
+ bool first = true;
+
+ bool quoted = false;
+
+ bool valid = true;
+
+ while (s [0] != 0 && valid)
+ {
+
+ if (first)
+ {
+
+ if (s [0] == '\"')
+ {
+
+ quoted = true;
+
+ s++;
+
+ }
+
+ }
+
+ first = false;
+
+ if (quoted)
+ {
+
+ if (s [0] == '\"' &&
+ s [1] == '\"')
+ {
+
+ s+= 2;
+
+ *(t++) = '\"';
+
+ }
+
+ else if (s [0] == '\"')
+ {
+
+ s++;
+
+ quoted = false;
+
+ valid = valid && ((s [0] == 0) || ((s [0] == ';' && s [1] == ' ')));
+
+ }
+
+ else
+ {
+
+ *(t++) = *(s++);
+
+ }
+
+ }
+
+ else if (s [0] == ';' &&
+ s [1] == ' ')
+ {
+
+ s += 2;
+
+ t [0] = 0;
+
+ dng_string ss;
+
+ ss.Set (temp.Buffer_char ());
+
+ newList.Append (ss);
+
+ t = temp.Buffer_char ();
+
+ first = true;
+
+ }
+
+ else
+ {
+
+ *(t++) = *(s++);
+
+ }
+
+ }
+
+ if (quoted)
+ {
+
+ valid = false;
+
+ }
+
+ if (valid)
+ {
+
+ if (t != temp.Buffer_char ())
+ {
+
+ t [0] = 0;
+
+ dng_string ss;
+
+ ss.Set (temp.Buffer_char ());
+
+ newList.Append (ss);
+
+ }
+
+ }
+
+ else
+ {
+
+ newList.Clear ();
+
+ newList.Append (exif.fArtist);
+
+ }
+
+ SetStringList (XMP_NS_DC,
+ "creator",
+ newList,
+ false);
+
+ }
+
+ }
+
+ // Software: (XMP is is always preferred)
+
+ if (fSDK->GetString (XMP_NS_XAP,
+ "CreatorTool",
+ exif.fSoftware))
+
+ {
+
+ }
+
+ else if (doingUpdateFromXMP)
+ {
+
+ exif.fSoftware.Clear ();
+
+ if (originalExif->fSoftware.NotEmpty ())
+ {
+
+ fSDK->SetString (XMP_NS_XAP,
+ "CreatorTool",
+ dng_string ());
+
+ }
+
+ }
+
+ else if (exif.fSoftware.NotEmpty ())
+ {
+
+ fSDK->SetString (XMP_NS_XAP,
+ "CreatorTool",
+ exif.fSoftware);
+
+ }
+
+ // Copyright: (XMP is is always preferred)
+
+ if (fSDK->GetAltLangDefault (XMP_NS_DC,
+ "rights",
+ exif.fCopyright))
+
+ {
+
+ }
+
+ else if (doingUpdateFromXMP)
+ {
+
+ exif.fCopyright.Clear ();
+
+ if (originalExif->fCopyright.NotEmpty ())
+ {
+
+ fSDK->SetAltLangDefault (XMP_NS_DC,
+ "rights",
+ dng_string ());
+
+ }
+
+ }
+
+ else if (exif.fCopyright.NotEmpty ())
+ {
+
+ fSDK->SetAltLangDefault (XMP_NS_DC,
+ "rights",
+ exif.fCopyright);
+
+ }
+
+ // Camera serial number private tag:
+
+ SyncString (XMP_NS_AUX,
+ "SerialNumber",
+ exif.fCameraSerialNumber,
+ readOnly);
+
+ // Lens Info:
+
+ {
+
+ dng_string s;
+
+ if (exif.fLensInfo [0].IsValid ())
+ {
+
+ char ss [256];
+
+ sprintf (ss,
+ "%u/%u %u/%u %u/%u %u/%u",
+ (unsigned) exif.fLensInfo [0].n,
+ (unsigned) exif.fLensInfo [0].d,
+ (unsigned) exif.fLensInfo [1].n,
+ (unsigned) exif.fLensInfo [1].d,
+ (unsigned) exif.fLensInfo [2].n,
+ (unsigned) exif.fLensInfo [2].d,
+ (unsigned) exif.fLensInfo [3].n,
+ (unsigned) exif.fLensInfo [3].d);
+
+ s.Set (ss);
+
+ }
+
+ SyncString (XMP_NS_AUX,
+ "LensInfo",
+ s,
+ readOnly);
+
+ if (s.NotEmpty ())
+ {
+
+ unsigned n [4];
+ unsigned d [4];
+
+ if (sscanf (s.Get (),
+ "%u/%u %u/%u %u/%u %u/%u",
+ &n [0],
+ &d [0],
+ &n [1],
+ &d [1],
+ &n [2],
+ &d [2],
+ &n [3],
+ &d [3]) == 8)
+ {
+
+ for (uint32 j = 0; j < 4; j++)
+ {
+
+ exif.fLensInfo [j] = dng_urational (n [j], d [j]);
+
+ }
+
+ }
+
+
+ }
+
+ }
+
+ // Lens name:
+
+ {
+
+ // EXIF lens names are sometimes missing or wrong (esp. when non-OEM lenses
+ // are used). So prefer the value from XMP.
+
+ SyncString (XMP_NS_AUX,
+ "Lens",
+ exif.fLensName,
+ preferXMP);
+
+ // Generate default lens name from lens info if required.
+ // Ignore names names that end in "f/0.0" due to third party bug.
+
+ if ((exif.fLensName.IsEmpty () ||
+ exif.fLensName.EndsWith ("f/0.0")) && exif.fLensInfo [0].IsValid ())
+ {
+
+ char s [256];
+
+ real64 minFL = exif.fLensInfo [0].As_real64 ();
+ real64 maxFL = exif.fLensInfo [1].As_real64 ();
+
+ // The f-stop numbers are optional.
+
+ if (exif.fLensInfo [2].IsValid ())
+ {
+
+ real64 minFS = exif.fLensInfo [2].As_real64 ();
+ real64 maxFS = exif.fLensInfo [3].As_real64 ();
+
+ if (minFL == maxFL)
+ sprintf (s, "%.1f mm f/%.1f", minFL, minFS);
+
+ else if (minFS == maxFS)
+ sprintf (s, "%.1f-%.1f mm f/%.1f", minFL, maxFL, minFS);
+
+ else
+ sprintf (s, "%.1f-%.1f mm f/%.1f-%.1f", minFL, maxFL, minFS, maxFS);
+
+ }
+
+ else
+ {
+
+ if (minFL == maxFL)
+ sprintf (s, "%.1f mm", minFL);
+
+ else
+ sprintf (s, "%.1f-%.1f mm", minFL, maxFL);
+
+ }
+
+ exif.fLensName.Set (s);
+
+ SetString (XMP_NS_AUX,
+ "Lens",
+ exif.fLensName);
+
+ }
+
+ }
+
+ // Lens ID:
+
+ SyncString (XMP_NS_AUX,
+ "LensID",
+ exif.fLensID,
+ readOnly);
+
+ // Lens Make:
+
+ SyncString (XMP_NS_EXIF,
+ "LensMake",
+ exif.fLensMake,
+ readOnly + removable);
+
+ // Lens Serial Number:
+
+ SyncString (XMP_NS_AUX,
+ "LensSerialNumber",
+ exif.fLensSerialNumber,
+ readOnly);
+
+ // Image Number:
+
+ Sync_uint32 (XMP_NS_AUX,
+ "ImageNumber",
+ exif.fImageNumber,
+ exif.fImageNumber == 0xFFFFFFFF,
+ readOnly);
+
+ // User Comment:
+
+ if (exif.fUserComment.NotEmpty ())
+ {
+
+ fSDK->SetAltLangDefault (XMP_NS_EXIF,
+ "UserComment",
+ exif.fUserComment);
+
+ }
+
+ else
+ {
+
+ (void) fSDK->GetAltLangDefault (XMP_NS_EXIF,
+ "UserComment",
+ exif.fUserComment);
+
+ }
+
+ if (removeFromXMP)
+ {
+ Remove (XMP_NS_EXIF, "UserComment");
+ }
+
+ // Approximate focus distance:
+
+ SyncApproximateFocusDistance (exif,
+ readOnly);
+
+ // Flash Compensation:
+
+ Sync_srational (XMP_NS_AUX,
+ "FlashCompensation",
+ exif.fFlashCompensation,
+ readOnly);
+
+ // Owner Name: (allow XMP updates)
+
+ SyncString (XMP_NS_AUX,
+ "OwnerName",
+ exif.fOwnerName,
+ preferXMP);
+
+ // Firmware:
+
+ SyncString (XMP_NS_AUX,
+ "Firmware",
+ exif.fFirmware,
+ readOnly);
+
+ // Image Unique ID:
+
+ {
+
+ dng_string s = EncodeFingerprint (exif.fImageUniqueID);
+
+ SyncString (XMP_NS_EXIF,
+ "ImageUniqueID",
+ s,
+ readOnly + removable);
+
+ exif.fImageUniqueID = DecodeFingerprint (s);
+
+ }
+
+ // Allow EXIF GPS to be updated via updates from XMP.
+
+ if (doingUpdateFromXMP)
+ {
+
+ // Require that at least one basic GPS field exist in the
+ // XMP before overrriding the EXIF GPS fields.
+
+ if (Exists (XMP_NS_EXIF, "GPSVersionID" ) ||
+ Exists (XMP_NS_EXIF, "GPSLatitude" ) ||
+ Exists (XMP_NS_EXIF, "GPSLongitude" ) ||
+ Exists (XMP_NS_EXIF, "GPSAltitude" ) ||
+ Exists (XMP_NS_EXIF, "GPSTimeStamp" ) ||
+ Exists (XMP_NS_EXIF, "GPSProcessingMethod"))
+ {
+
+ // Clear out the GPS info from the EXIF so it will
+ // replaced by the GPS info from the XMP.
+
+ dng_exif blankExif;
+
+ exif.CopyGPSFrom (blankExif);
+
+ }
+
+ }
+
+ // GPS Version ID:
+
+ {
+
+ dng_string s = EncodeGPSVersion (exif.fGPSVersionID);
+
+ if (SyncString (XMP_NS_EXIF,
+ "GPSVersionID",
+ s,
+ preferNonXMP + removable))
+ {
+
+ exif.fGPSVersionID = DecodeGPSVersion (s);
+
+ }
+
+ }
+
+ // GPS Latitude:
+
+ {
+
+ dng_string s = EncodeGPSCoordinate (exif.fGPSLatitudeRef,
+ exif.fGPSLatitude);
+
+ if (SyncString (XMP_NS_EXIF,
+ "GPSLatitude",
+ s,
+ preferNonXMP + removable))
+ {
+
+ DecodeGPSCoordinate (s,
+ exif.fGPSLatitudeRef,
+ exif.fGPSLatitude);
+
+ }
+
+ }
+
+ // GPS Longitude:
+
+ {
+
+ dng_string s = EncodeGPSCoordinate (exif.fGPSLongitudeRef,
+ exif.fGPSLongitude);
+
+ if (SyncString (XMP_NS_EXIF,
+ "GPSLongitude",
+ s,
+ preferNonXMP + removable))
+ {
+
+ DecodeGPSCoordinate (s,
+ exif.fGPSLongitudeRef,
+ exif.fGPSLongitude);
+
+ }
+
+ }
+
+ // Handle simple case of incorrectly written GPS altitude where someone didn't understand the GPSAltitudeRef and assumed the GPSAltitude RATIONAL is signed.
+ // Only handle this case as we do not want to misinterpret e.g. a fixed point representation of very high GPS altitudes.
+
+ uint32 &altitudeRef = exif.fGPSAltitudeRef;
+ dng_urational &altitude = exif.fGPSAltitude;
+
+ if (altitude.IsValid () &&
+ (altitudeRef == 0 || altitudeRef == 0xFFFFFFFF)) // If the file contains a "below sea level" altitudeRef, assume the writing software is working according to the spec.
+ {
+
+ if ((altitude.n & (1U << 31)) &&
+ altitude.d < 7) // As the denominator increases, large numerator values become possibly valid distances. Pick a limit on the conservative side (approx 33e6m) to prevent misinterpretation.
+ // Noting that the normal case for this mistake has a denominator of 1
+ {
+
+ altitude.n = ~altitude.n + 1;
+ altitudeRef = 1;
+
+ }
+
+ }
+
+ // GPS Altitude Reference:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "GPSAltitudeRef",
+ altitudeRef,
+ altitudeRef == 0xFFFFFFFF,
+ preferNonXMP + removable);
+
+ // GPS Altitude:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSAltitude",
+ altitude,
+ preferNonXMP + removable);
+
+ // GPS Date/Time:
+
+ {
+
+ dng_string s = EncodeGPSDateTime (exif.fGPSDateStamp,
+ exif.fGPSTimeStamp);
+
+ if (SyncString (XMP_NS_EXIF,
+ "GPSTimeStamp",
+ s,
+ preferNonXMP + removable))
+ {
+
+ DecodeGPSDateTime (s,
+ exif.fGPSDateStamp,
+ exif.fGPSTimeStamp);
+
+ }
+
+ }
+
+ // GPS Satellites:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSSatellites",
+ exif.fGPSSatellites,
+ preferNonXMP + removable);
+
+ // GPS Status:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSStatus",
+ exif.fGPSStatus,
+ preferNonXMP + removable);
+
+ // GPS Measure Mode:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSMeasureMode",
+ exif.fGPSMeasureMode,
+ preferNonXMP + removable);
+
+ // GPS DOP:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSDOP",
+ exif.fGPSDOP,
+ preferNonXMP + removable);
+
+ // GPS Speed Reference:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSSpeedRef",
+ exif.fGPSSpeedRef,
+ preferNonXMP + removable);
+
+ // GPS Speed:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSSpeed",
+ exif.fGPSSpeed,
+ preferNonXMP + removable);
+
+ // GPS Track Reference:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSTrackRef",
+ exif.fGPSTrackRef,
+ preferNonXMP + removable);
+
+ // GPS Track:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSTrack",
+ exif.fGPSTrack,
+ preferNonXMP + removable);
+
+ // GPS Image Direction Reference:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSImgDirectionRef",
+ exif.fGPSImgDirectionRef,
+ preferNonXMP + removable);
+
+ // GPS Image Direction:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSImgDirection",
+ exif.fGPSImgDirection,
+ preferNonXMP + removable);
+
+ // GPS Map Datum:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSMapDatum",
+ exif.fGPSMapDatum,
+ preferNonXMP + removable);
+
+ // GPS Destination Latitude:
+
+ {
+
+ dng_string s = EncodeGPSCoordinate (exif.fGPSDestLatitudeRef,
+ exif.fGPSDestLatitude);
+
+ if (SyncString (XMP_NS_EXIF,
+ "GPSDestLatitude",
+ s,
+ preferNonXMP + removable))
+ {
+
+ DecodeGPSCoordinate (s,
+ exif.fGPSDestLatitudeRef,
+ exif.fGPSDestLatitude);
+
+ }
+
+ }
+
+ // GPS Destination Longitude:
+
+ {
+
+ dng_string s = EncodeGPSCoordinate (exif.fGPSDestLongitudeRef,
+ exif.fGPSDestLongitude);
+
+ if (SyncString (XMP_NS_EXIF,
+ "GPSDestLongitude",
+ s,
+ preferNonXMP + removable))
+ {
+
+ DecodeGPSCoordinate (s,
+ exif.fGPSDestLongitudeRef,
+ exif.fGPSDestLongitude);
+
+ }
+
+ }
+
+ // GPS Destination Bearing Reference:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSDestBearingRef",
+ exif.fGPSDestBearingRef,
+ preferNonXMP + removable);
+
+ // GPS Destination Bearing:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSDestBearing",
+ exif.fGPSDestBearing,
+ preferNonXMP + removable);
+
+ // GPS Destination Distance Reference:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSDestDistanceRef",
+ exif.fGPSDestDistanceRef,
+ preferNonXMP + removable);
+
+ // GPS Destination Distance:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSDestDistance",
+ exif.fGPSDestDistance,
+ preferNonXMP + removable);
+
+ // GPS Processing Method:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSProcessingMethod",
+ exif.fGPSProcessingMethod,
+ preferNonXMP + removable);
+
+ // GPS Area Information:
+
+ SyncString (XMP_NS_EXIF,
+ "GPSAreaInformation",
+ exif.fGPSAreaInformation,
+ preferNonXMP + removable);
+
+ // GPS Differential:
+
+ Sync_uint32 (XMP_NS_EXIF,
+ "GPSDifferential",
+ exif.fGPSDifferential,
+ exif.fGPSDifferential == 0xFFFFFFFF,
+ preferNonXMP + removable);
+
+ // GPS Horizontal Positioning Error:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSHPositioningError",
+ exif.fGPSHPositioningError,
+ preferNonXMP + removable);
+
+ // Sync date/times.
+
+ UpdateExifDates (exif, removeFromXMP);
+
+ // We are syncing EXIF and XMP, but we are not updating the
+ // NativeDigest tags. It is better to just delete them than leave
+ // the stale values around.
+
+ Remove (XMP_NS_EXIF, "NativeDigest");
+ Remove (XMP_NS_TIFF, "NativeDigest");
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncApproximateFocusDistance (dng_exif &exif,
+ const uint32 readOnly)
+ {
+
+ Sync_urational (XMP_NS_AUX,
+ "ApproximateFocusDistance",
+ exif.fApproxFocusDistance,
+ readOnly);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::ValidateStringList (const char *ns,
+ const char *path)
+ {
+
+ fSDK->ValidateStringList (ns, path);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::ValidateMetadata ()
+ {
+
+ // The following values should be arrays, but are not always. So
+ // fix them up because Photoshop sometimes has problems parsing invalid
+ // tags.
+
+ ValidateStringList (XMP_NS_DC, "creator");
+
+ ValidateStringList (XMP_NS_PHOTOSHOP, "Keywords");
+ ValidateStringList (XMP_NS_PHOTOSHOP, "SupplementalCategories");
+
+ }
+
+/******************************************************************************/
+
+bool dng_xmp::DateTimeIsDateOnly (const char *ns,
+ const char *path)
+ {
+
+ dng_string s;
+
+ if (GetString (ns, path, s))
+ {
+
+ uint32 len = s.Length ();
+
+ if (len)
+ {
+
+ for (uint32 j = 0; j < len; j++)
+ {
+
+ if (s.Get () [j] == 'T')
+ {
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::UpdateExifDates (dng_exif &exif,
+ bool removeFromXMP)
+ {
+
+ // For the following three date/time fields, we always prefer XMP to
+ // the EXIF values. This is to allow the user to correct the date/times
+ // via changes in a sidecar XMP file, without modifying the original
+ // raw file.
+
+ // Kludge: The Nikon D4 is writing date only date/times into XMP, so
+ // prefer the EXIF values if the XMP only contains a date.
+
+ // Modification Date/Time:
+ // exif.fDateTime
+ // kXMP_NS_XMP:"ModifyDate" & kXMP_NS_TIFF:"DateTime" are aliased
+
+ {
+
+ dng_string s = exif.fDateTime.Encode_ISO_8601 ();
+
+ bool dateOnly = DateTimeIsDateOnly (XMP_NS_TIFF, "DateTime");
+
+ SyncString (XMP_NS_TIFF,
+ "DateTime",
+ s,
+ dateOnly ? preferNonXMP : preferXMP);
+
+ if (s.NotEmpty ())
+ {
+
+ exif.fDateTime.Decode_ISO_8601 (s.Get ());
+
+ // Round trip again in case we need to add a fake time zone.
+
+ s = exif.fDateTime.Encode_ISO_8601 ();
+
+ SetString (XMP_NS_TIFF,
+ "DateTime",
+ s);
+
+ }
+
+ }
+
+ // Original Date/Time:
+ // exif.fDateTimeOriginal
+ // IPTC: DateCreated
+ // XMP_NS_EXIF:"DateTimeOriginal" & XMP_NS_PHOTOSHOP:"DateCreated"
+ // Adobe has decided to keep the two XMP fields separate.
+
+ {
+
+ dng_string s = exif.fDateTimeOriginal.Encode_ISO_8601 ();
+
+ bool dateOnly = DateTimeIsDateOnly (XMP_NS_EXIF, "DateTimeOriginal");
+
+ SyncString (XMP_NS_EXIF,
+ "DateTimeOriginal",
+ s,
+ dateOnly ? preferNonXMP : preferXMP);
+
+ if (s.NotEmpty ())
+ {
+
+ exif.fDateTimeOriginal.Decode_ISO_8601 (s.Get ());
+
+ // Round trip again in case we need to add a fake time zone.
+
+ s = exif.fDateTimeOriginal.Encode_ISO_8601 ();
+
+ SetString (XMP_NS_EXIF,
+ "DateTimeOriginal",
+ s);
+
+ }
+
+ // Sync the IPTC value to the EXIF value if only the EXIF
+ // value exists.
+
+ if (s.NotEmpty () && !Exists (XMP_NS_PHOTOSHOP, "DateCreated"))
+ {
+
+ SetString (XMP_NS_PHOTOSHOP, "DateCreated", s);
+
+ }
+
+ if (removeFromXMP)
+ {
+
+ Remove (XMP_NS_EXIF, "DateTimeOriginal");
+
+ }
+
+ }
+
+ // Date Time Digitized:
+ // XMP_NS_EXIF:"DateTimeDigitized" & kXMP_NS_XMP:"CreateDate" are aliased
+
+ {
+
+ dng_string s = exif.fDateTimeDigitized.Encode_ISO_8601 ();
+
+ bool dateOnly = DateTimeIsDateOnly (XMP_NS_EXIF, "DateTimeDigitized");
+
+ SyncString (XMP_NS_EXIF,
+ "DateTimeDigitized",
+ s,
+ dateOnly ? preferNonXMP : preferXMP);
+
+ if (s.NotEmpty ())
+ {
+
+ exif.fDateTimeDigitized.Decode_ISO_8601 (s.Get ());
+
+ // Round trip again in case we need to add a fake time zone.
+
+ s = exif.fDateTimeDigitized.Encode_ISO_8601 ();
+
+ SetString (XMP_NS_EXIF,
+ "DateTimeDigitized",
+ s);
+
+ }
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::UpdateDateTime (const dng_date_time_info &dt)
+ {
+
+ dng_string s = dt.Encode_ISO_8601 ();
+
+ SetString (XMP_NS_TIFF,
+ "DateTime",
+ s);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::UpdateMetadataDate (const dng_date_time_info &dt)
+ {
+
+ dng_string s = dt.Encode_ISO_8601 ();
+
+ SetString (XMP_NS_XAP,
+ "MetadataDate",
+ s);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp::HasOrientation () const
+ {
+
+ uint32 x = 0;
+
+ if (Get_uint32 (XMP_NS_TIFF,
+ "Orientation",
+ x))
+ {
+
+ return (x >= 1) && (x <= 8);
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+dng_orientation dng_xmp::GetOrientation () const
+ {
+
+ dng_orientation result;
+
+ uint32 x = 0;
+
+ if (Get_uint32 (XMP_NS_TIFF,
+ "Orientation",
+ x))
+ {
+
+ if ((x >= 1) && (x <= 8))
+ {
+
+ result.SetTIFF (x);
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::ClearOrientation ()
+ {
+
+ fSDK->Remove (XMP_NS_TIFF, "Orientation");
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetOrientation (const dng_orientation &orientation)
+ {
+
+ Set_uint32 (XMP_NS_TIFF,
+ "Orientation",
+ orientation.GetTIFF ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncOrientation (dng_negative &negative,
+ bool xmpIsMaster)
+ {
+
+ SyncOrientation (negative.Metadata (), xmpIsMaster);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::SyncOrientation (dng_metadata &metadata,
+ bool xmpIsMaster)
+ {
+
+ // See if XMP contains the orientation.
+
+ bool xmpHasOrientation = HasOrientation ();
+
+ // See if XMP is the master value.
+
+ if (xmpHasOrientation && (xmpIsMaster || !metadata.HasBaseOrientation ()))
+ {
+
+ metadata.SetBaseOrientation (GetOrientation ());
+
+ }
+
+ else
+ {
+
+ SetOrientation (metadata.BaseOrientation ());
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::ClearImageInfo ()
+ {
+
+ Remove (XMP_NS_TIFF, "ImageWidth" );
+ Remove (XMP_NS_TIFF, "ImageLength");
+
+ Remove (XMP_NS_EXIF, "PixelXDimension");
+ Remove (XMP_NS_EXIF, "PixelYDimension");
+
+ Remove (XMP_NS_TIFF, "BitsPerSample");
+
+ Remove (XMP_NS_TIFF, "Compression");
+
+ Remove (XMP_NS_TIFF, "PhotometricInterpretation");
+
+ // "Orientation" is handled separately.
+
+ Remove (XMP_NS_TIFF, "SamplesPerPixel");
+
+ Remove (XMP_NS_TIFF, "PlanarConfiguration");
+
+ Remove (XMP_NS_TIFF, "XResolution");
+ Remove (XMP_NS_TIFF, "YResolution");
+
+ Remove (XMP_NS_TIFF, "ResolutionUnit");
+
+ Remove (XMP_NS_PHOTOSHOP, "ColorMode" );
+ Remove (XMP_NS_PHOTOSHOP, "ICCProfile");
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetImageSize (const dng_point &size)
+ {
+
+ Set_uint32 (XMP_NS_TIFF, "ImageWidth" , size.h);
+ Set_uint32 (XMP_NS_TIFF, "ImageLength", size.v);
+
+ // Mirror these values to the EXIF tags.
+
+ Set_uint32 (XMP_NS_EXIF, "PixelXDimension" , size.h);
+ Set_uint32 (XMP_NS_EXIF, "PixelYDimension" , size.v);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetSampleInfo (uint32 samplesPerPixel,
+ uint32 bitsPerSample)
+ {
+
+ Set_uint32 (XMP_NS_TIFF, "SamplesPerPixel", samplesPerPixel);
+
+ char s [32];
+
+ sprintf (s, "%u", (unsigned) bitsPerSample);
+
+ dng_string ss;
+
+ ss.Set (s);
+
+ dng_string_list list;
+
+ for (uint32 j = 0; j < samplesPerPixel; j++)
+ {
+ list.Append (ss);
+ }
+
+ SetStringList (XMP_NS_TIFF, "BitsPerSample", list, false);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetPhotometricInterpretation (uint32 pi)
+ {
+
+ Set_uint32 (XMP_NS_TIFF, "PhotometricInterpretation", pi);
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp::SetResolution (const dng_resolution &res)
+ {
+
+ Set_urational (XMP_NS_TIFF, "XResolution", res.fXResolution);
+ Set_urational (XMP_NS_TIFF, "YResolution", res.fYResolution);
+
+ Set_uint32 (XMP_NS_TIFF, "ResolutionUnit", res.fResolutionUnit);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::ComposeArrayItemPath (const char *ns,
+ const char *arrayName,
+ int32 itemNumber,
+ dng_string &s) const
+ {
+
+ fSDK->ComposeArrayItemPath (ns, arrayName, itemNumber, s);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::ComposeStructFieldPath (const char *ns,
+ const char *structName,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const
+ {
+
+ fSDK->ComposeStructFieldPath (ns, structName, fieldNS, fieldName, s);
+
+ }
+
+/*****************************************************************************/
+
+int32 dng_xmp::CountArrayItems (const char *ns,
+ const char *path) const
+ {
+
+ return fSDK->CountArrayItems (ns, path);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::AppendArrayItem (const char *ns,
+ const char *arrayName,
+ const char *itemValue,
+ bool isBag,
+ bool propIsStruct)
+ {
+
+ fSDK->AppendArrayItem (ns,
+ arrayName,
+ itemValue,
+ isBag,
+ propIsStruct);
+ }
+
+/*****************************************************************************/
+
+#if qDNGXMPDocOps
+
+/*****************************************************************************/
+
+void dng_xmp::DocOpsOpenXMP (const char *srcMIMI)
+ {
+
+ fSDK->DocOpsOpenXMP (srcMIMI);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DocOpsPrepareForSave (const char *srcMIMI,
+ const char *dstMIMI,
+ bool newPath)
+ {
+
+ fSDK->DocOpsPrepareForSave (srcMIMI,
+ dstMIMI,
+ newPath);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DocOpsUpdateMetadata (const char *srcMIMI)
+ {
+
+ fSDK->DocOpsUpdateMetadata (srcMIMI);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_xmp.h b/gpr/source/lib/dng_sdk/dng_xmp.h
new file mode 100644
index 0000000..8b8319e
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_xmp.h
@@ -0,0 +1,405 @@
+/*****************************************************************************/
+// Copyright 2006-2011 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xmp.h#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_xmp__
+#define __dng_xmp__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+#include "dng_xmp_sdk.h"
+
+/*****************************************************************************/
+
+class dng_xmp
+ {
+
+ protected:
+
+ // Sync option bits.
+
+ enum
+ {
+ ignoreXMP = 1, // Force XMP values to match non-XMP
+ preferXMP = 2, // Prefer XMP values if conflict
+ preferNonXMP = 4, // Prefer non-XMP values if conflict
+ removeXMP = 8 // Remove XMP value after syncing
+ };
+
+ dng_memory_allocator &fAllocator;
+
+ dng_xmp_sdk *fSDK;
+
+ public:
+
+ dng_xmp (dng_memory_allocator &allocator);
+
+ dng_xmp (const dng_xmp &xmp);
+
+ virtual ~dng_xmp ();
+
+ virtual dng_xmp * Clone () const;
+
+ void Parse (dng_host &host,
+ const void *buffer,
+ uint32 count);
+
+ dng_memory_block * Serialize (bool asPacket = false,
+ uint32 targetBytes = 0,
+ uint32 padBytes = 4096,
+ bool forJPEG = false,
+ bool compact = true) const;
+
+ // Kludge: Due to a bug in Premere Elements 9, we need to pass non-compact XMP
+ // to the host, until we drop support for this Premere version. This bug
+ // is fixed in Premere Elements 10 and later.
+
+ dng_memory_block * SerializeNonCompact () const
+ {
+ return Serialize (false,
+ 0,
+ 4096,
+ false,
+ false);
+ }
+
+ void PackageForJPEG (AutoPtr<dng_memory_block> &stdBlock,
+ AutoPtr<dng_memory_block> &extBlock,
+ dng_string &extDigest) const;
+
+ void MergeFromJPEG (const dng_xmp &xmp);
+
+ bool HasMeta () const;
+
+ void * GetPrivateMeta ();
+
+ bool Exists (const char *ns,
+ const char *path) const;
+
+ bool HasNameSpace (const char *ns) const;
+
+ bool IteratePaths (IteratePathsCallback *callback,
+ void *callbackData,
+ const char *ns = 0,
+ const char *path = 0);
+
+ void Remove (const char *ns,
+ const char *path);
+
+ void RemoveProperties (const char *ns);
+
+ void RemoveEmptyStringOrArray (const char *ns,
+ const char *path);
+
+ void RemoveEmptyStringsAndArrays (const char *ns = 0);
+
+ void Set (const char *ns,
+ const char *path,
+ const char *text);
+
+ bool GetString (const char *ns,
+ const char *path,
+ dng_string &s) const;
+
+ void SetString (const char *ns,
+ const char *path,
+ const dng_string &s);
+
+ bool GetStringList (const char *ns,
+ const char *path,
+ dng_string_list &list) const;
+
+ void SetStringList (const char *ns,
+ const char *path,
+ const dng_string_list &list,
+ bool isBag = false);
+
+ void SetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ const dng_string &s);
+
+ void SetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ const char *s);
+
+ void DeleteStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName);
+
+ bool GetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const;
+
+ void SetAltLangDefault (const char *ns,
+ const char *path,
+ const dng_string &s);
+
+ bool GetAltLangDefault (const char *ns,
+ const char *path,
+ dng_string &s) const;
+
+ bool GetBoolean (const char *ns,
+ const char *path,
+ bool &x) const;
+
+ void SetBoolean (const char *ns,
+ const char *path,
+ bool x);
+
+ bool Get_int32 (const char *ns,
+ const char *path,
+ int32 &x) const;
+
+ void Set_int32 (const char *ns,
+ const char *path,
+ int32 x,
+ bool usePlus = false);
+
+ bool Get_uint32 (const char *ns,
+ const char *path,
+ uint32 &x) const;
+
+ void Set_uint32 (const char *ns,
+ const char *path,
+ uint32 x);
+
+ bool Get_real64 (const char *ns,
+ const char *path,
+ real64 &x) const;
+
+ void Set_real64 (const char *ns,
+ const char *path,
+ real64 x,
+ uint32 places = 6,
+ bool trim = true,
+ bool usePlus = false);
+
+ bool Get_urational (const char *ns,
+ const char *path,
+ dng_urational &r) const;
+
+ void Set_urational (const char *ns,
+ const char *path,
+ const dng_urational &r);
+
+ bool Get_srational (const char *ns,
+ const char *path,
+ dng_srational &r) const;
+
+ void Set_srational (const char *ns,
+ const char *path,
+ const dng_srational &r);
+
+ bool GetFingerprint (const char *ns,
+ const char *path,
+ dng_fingerprint &print) const;
+
+ void SetFingerprint (const char *ns,
+ const char *path,
+ const dng_fingerprint &print,
+ bool allowInvalid = false);
+
+ void SetVersion2to4 (const char *ns,
+ const char *path,
+ uint32 version);
+
+ dng_fingerprint GetIPTCDigest () const;
+
+ void SetIPTCDigest (dng_fingerprint &digest);
+
+ void ClearIPTCDigest ();
+
+ void IngestIPTC (dng_metadata &metadata,
+ bool xmpIsNewer = false);
+
+ void RebuildIPTC (dng_metadata &metadata,
+ dng_memory_allocator &allocator,
+ bool padForTIFF);
+
+ virtual void SyncExif (dng_exif &exif,
+ const dng_exif *originalExif = NULL,
+ bool doingUpdateFromXMP = false,
+ bool removeFromXMP = false);
+
+ void ValidateStringList (const char *ns,
+ const char *path);
+
+ void ValidateMetadata ();
+
+ void UpdateDateTime (const dng_date_time_info &dt);
+
+ void UpdateMetadataDate (const dng_date_time_info &dt);
+
+ void UpdateExifDates (dng_exif &exif,
+ bool removeFromXMP = false);
+
+ bool HasOrientation () const;
+
+ dng_orientation GetOrientation () const;
+
+ void ClearOrientation ();
+
+ void SetOrientation (const dng_orientation &orientation);
+
+ void SyncOrientation (dng_negative &negative,
+ bool xmpIsMaster);
+ // FIX_ME_API: Backwards compatibility
+
+ void SyncOrientation (dng_metadata &metadata,
+ bool xmpIsMaster);
+
+ void ClearImageInfo ();
+
+ void SetImageSize (const dng_point &size);
+
+ void SetSampleInfo (uint32 samplesPerPixel,
+ uint32 bitsPerSample);
+
+ void SetPhotometricInterpretation (uint32 pi);
+
+ void SetResolution (const dng_resolution &res);
+
+ void ComposeArrayItemPath (const char *ns,
+ const char *arrayName,
+ int32 itemNumber,
+ dng_string &s) const;
+
+ void ComposeStructFieldPath (const char *ns,
+ const char *structName,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const;
+
+ int32 CountArrayItems (const char *ns,
+ const char *path) const;
+
+ void AppendArrayItem (const char *ns,
+ const char *arrayName,
+ const char *itemValue,
+ bool isBag = true,
+ bool propIsStruct = false);
+
+ static dng_string EncodeFingerprint (const dng_fingerprint &f,
+ bool allowInvalid = false);
+
+ static dng_fingerprint DecodeFingerprint (const dng_string &s);
+
+ #if qDNGXMPDocOps
+
+ void DocOpsOpenXMP (const char *srcMIMI);
+
+ void DocOpsPrepareForSave (const char *srcMIMI,
+ const char *dstMIMI,
+ bool newPath = true);
+
+ void DocOpsUpdateMetadata (const char *srcMIMI);
+
+ #endif
+
+ protected:
+
+ static void TrimDecimal (char *s);
+
+ static dng_string EncodeGPSVersion (uint32 version);
+
+ static uint32 DecodeGPSVersion (const dng_string &s);
+
+ static dng_string EncodeGPSCoordinate (const dng_string &ref,
+ const dng_urational *coord);
+
+ static void DecodeGPSCoordinate (const dng_string &s,
+ dng_string &ref,
+ dng_urational *coord);
+
+ static dng_string EncodeGPSDateTime (const dng_string &dateStamp,
+ const dng_urational *timeStamp);
+
+ static void DecodeGPSDateTime (const dng_string &s,
+ dng_string &dateStamp,
+ dng_urational *timeStamp);
+
+ bool SyncString (const char *ns,
+ const char *path,
+ dng_string &s,
+ uint32 options = 0);
+
+ void SyncStringList (const char *ns,
+ const char *path,
+ dng_string_list &list,
+ bool isBag = false,
+ uint32 options = 0);
+
+ bool SyncAltLangDefault (const char *ns,
+ const char *path,
+ dng_string &s,
+ uint32 options = 0);
+
+ void Sync_uint32 (const char *ns,
+ const char *path,
+ uint32 &x,
+ bool isDefault = false,
+ uint32 options = 0);
+
+ void Sync_uint32_array (const char *ns,
+ const char *path,
+ uint32 *data,
+ uint32 &count,
+ uint32 maxCount,
+ uint32 options = 0);
+
+ void Sync_urational (const char *ns,
+ const char *path,
+ dng_urational &r,
+ uint32 options = 0);
+
+ void Sync_srational (const char *ns,
+ const char *path,
+ dng_srational &r,
+ uint32 options = 0);
+
+ void SyncIPTC (dng_iptc &iptc,
+ uint32 options);
+
+ void SyncFlash (uint32 &flashState,
+ uint32 &flashMask,
+ uint32 options);
+
+ bool DateTimeIsDateOnly (const char *ns,
+ const char *path);
+
+ virtual void SyncApproximateFocusDistance (dng_exif &exif,
+ const uint32 readOnly);
+
+ private:
+
+ // Hidden assignment operator.
+
+ dng_xmp & operator= (const dng_xmp &xmp);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_xmp_sdk.cpp b/gpr/source/lib/dng_sdk/dng_xmp_sdk.cpp
new file mode 100644
index 0000000..fa8ea35
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_xmp_sdk.cpp
@@ -0,0 +1,1670 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xmp_sdk.cpp#4 $ */
+/* $DateTime: 2012/09/05 12:31:51 $ */
+/* $Change: 847652 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_xmp_sdk.h"
+
+#include "dng_auto_ptr.h"
+#include "dng_assertions.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_host.h"
+#include "dng_memory.h"
+#include "dng_string.h"
+#include "dng_string_list.h"
+#include "dng_utils.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+#include <new>
+#include <string>
+
+#define TXMP_STRING_TYPE std::string
+
+#define XMP_INCLUDE_XMPFILES qDNGXMPFiles
+
+#define XMP_StaticBuild 1
+#undef TXMP_EXPAND_INLINE
+
+#include "XMP.incl_cpp"
+
+/*****************************************************************************/
+
+const char *XMP_NS_TIFF = "http://ns.adobe.com/tiff/1.0/";
+const char *XMP_NS_EXIF = "http://ns.adobe.com/exif/1.0/";
+const char *XMP_NS_PHOTOSHOP = "http://ns.adobe.com/photoshop/1.0/";
+const char *XMP_NS_XAP = "http://ns.adobe.com/xap/1.0/";
+const char *XMP_NS_XAP_RIGHTS = "http://ns.adobe.com/xap/1.0/rights/";
+const char *XMP_NS_DC = "http://purl.org/dc/elements/1.1/";
+const char *XMP_NS_XMP_NOTE = "http://ns.adobe.com/xmp/note/";
+const char *XMP_NS_MM = "http://ns.adobe.com/xap/1.0/mm/";
+
+const char *XMP_NS_CRS = "http://ns.adobe.com/camera-raw-settings/1.0/";
+const char *XMP_NS_CRSS = "http://ns.adobe.com/camera-raw-saved-settings/1.0/";
+const char *XMP_NS_AUX = "http://ns.adobe.com/exif/1.0/aux/";
+
+const char *XMP_NS_LCP = "http://ns.adobe.com/photoshop/1.0/camera-profile";
+
+const char *XMP_NS_IPTC = "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/";
+const char *XMP_NS_IPTC_EXT = "http://iptc.org/std/Iptc4xmpExt/2008-02-29/";
+
+const char *XMP_NS_CRX = "http://ns.adobe.com/lightroom-settings-experimental/1.0/";
+
+const char *XMP_NS_DNG = "http://ns.adobe.com/dng/1.0/";
+
+/******************************************************************************/
+
+#define CATCH_XMP(routine, fatal)\
+ \
+ catch (std::bad_alloc &)\
+ {\
+ DNG_REPORT ("Info: XMP " routine " threw memory exception");\
+ ThrowMemoryFull ();\
+ }\
+ \
+ catch (XMP_Error &error)\
+ {\
+ const char *errMessage = error.GetErrMsg ();\
+ if (errMessage && strlen (errMessage) <= 128)\
+ {\
+ char errBuffer [256];\
+ sprintf (errBuffer, "Info: XMP " routine " threw '%s' exception", errMessage);\
+ DNG_REPORT ( errBuffer);\
+ }\
+ else\
+ {\
+ DNG_REPORT ("Info: XMP " routine " threw unnamed exception");\
+ }\
+ if (fatal) ThrowProgramError ();\
+ }\
+ \
+ catch (...)\
+ {\
+ DNG_REPORT ("Info: XMP " routine " threw unknown exception");\
+ if (fatal) ThrowProgramError ();\
+ }
+
+/*****************************************************************************/
+
+class dng_xmp_private
+ {
+
+ public:
+
+ SXMPMeta *fMeta;
+
+ dng_xmp_private ()
+ : fMeta (NULL)
+ {
+ }
+
+ dng_xmp_private (const dng_xmp_private &xmp);
+
+ ~dng_xmp_private ()
+ {
+ if (fMeta)
+ {
+ delete fMeta;
+ }
+ }
+
+ private:
+
+ // Hidden assignment operator.
+
+ dng_xmp_private & operator= (const dng_xmp_private &xmp);
+
+ };
+
+/*****************************************************************************/
+
+dng_xmp_private::dng_xmp_private (const dng_xmp_private &xmp)
+
+ : fMeta (NULL)
+
+ {
+
+ if (xmp.fMeta)
+ {
+
+ fMeta = new SXMPMeta (xmp.fMeta->Clone (0));
+
+ if (!fMeta)
+ {
+ ThrowMemoryFull ();
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp_sdk::dng_xmp_sdk ()
+
+ : fPrivate (NULL)
+
+ {
+
+ fPrivate = new dng_xmp_private;
+
+ if (!fPrivate)
+ {
+ ThrowMemoryFull ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp_sdk::dng_xmp_sdk (const dng_xmp_sdk &sdk)
+
+ : fPrivate (NULL)
+
+ {
+
+ fPrivate = new dng_xmp_private (*sdk.fPrivate);
+
+ if (!fPrivate)
+ {
+ ThrowMemoryFull ();
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_xmp_sdk::~dng_xmp_sdk ()
+ {
+
+ if (fPrivate)
+ {
+ delete fPrivate;
+ }
+
+ }
+
+/*****************************************************************************/
+
+static bool gInitializedXMP = false;
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::InitializeSDK (dng_xmp_namespace * extraNamespaces,
+ const char *software)
+ {
+
+ if (!gInitializedXMP)
+ {
+
+ try
+ {
+
+ if (!SXMPMeta::Initialize ())
+ {
+ ThrowProgramError ();
+ }
+
+ // Register Lightroom beta settings namespace.
+ // We no longer read this but I don't want to cut it out this close
+ // to a release. [bruzenak]
+
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (XMP_NS_CRX,
+ "crx",
+ &ss);
+
+ }
+
+ // Register CRSS snapshots namespace
+
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (XMP_NS_CRSS,
+ "crss",
+ &ss);
+
+ }
+
+ // Register LCP (lens correction profiles) namespace
+
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (XMP_NS_LCP,
+ "stCamera",
+ &ss);
+
+ }
+
+ // Register DNG format metadata namespace
+
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (XMP_NS_DNG,
+ "dng",
+ &ss);
+
+ }
+
+ // Register extra namespaces.
+
+ if (extraNamespaces != NULL)
+ {
+
+ for (; extraNamespaces->fullName != NULL; ++extraNamespaces)
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (extraNamespaces->fullName,
+ extraNamespaces->shortName,
+ &ss);
+
+ }
+
+ }
+
+ #if qDNGXMPFiles
+
+ #if qLinux
+ if (!SXMPFiles::Initialize (kXMPFiles_IgnoreLocalText))
+ #else
+ if (!SXMPFiles::Initialize ())
+ #endif
+ {
+ ThrowProgramError ();
+ }
+
+ #endif
+
+ #if qDNGXMPDocOps
+
+ if (software)
+ {
+
+ SXMPDocOps::SetAppName (software);
+
+ }
+
+ #else
+
+ (void) software;
+
+ #endif
+
+ }
+
+ CATCH_XMP ("Initialization", true)
+
+ gInitializedXMP = true;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp_sdk::TerminateSDK ()
+ {
+
+ if (gInitializedXMP)
+ {
+
+ try
+ {
+
+ #if qDNGXMPFiles
+
+ SXMPFiles::Terminate ();
+
+ #endif
+
+ SXMPMeta::Terminate ();
+
+ }
+
+ catch (...)
+ {
+
+ }
+
+ gInitializedXMP = false;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+bool dng_xmp_sdk::HasMeta () const
+ {
+
+ if (fPrivate->fMeta)
+ {
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp_sdk::ClearMeta ()
+ {
+
+ if (HasMeta ())
+ {
+
+ delete fPrivate->fMeta;
+
+ fPrivate->fMeta = NULL;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp_sdk::MakeMeta ()
+ {
+
+ ClearMeta ();
+
+ InitializeSDK ();
+
+ try
+ {
+
+ fPrivate->fMeta = new SXMPMeta;
+
+ if (!fPrivate->fMeta)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ }
+
+ CATCH_XMP ("MakeMeta", true)
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp_sdk::NeedMeta ()
+ {
+
+ if (!HasMeta ())
+ {
+
+ MakeMeta ();
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void * dng_xmp_sdk::GetPrivateMeta ()
+ {
+
+ NeedMeta ();
+
+ return (void *) fPrivate->fMeta;
+
+ }
+
+/******************************************************************************/
+
+void dng_xmp_sdk::Parse (dng_host &host,
+ const char *buffer,
+ uint32 count)
+ {
+
+ MakeMeta ();
+
+ try
+ {
+
+ try
+ {
+
+ fPrivate->fMeta->ParseFromBuffer (buffer, count);
+
+ }
+
+ CATCH_XMP ("ParseFromBuffer", true)
+
+ }
+
+ catch (dng_exception &except)
+ {
+
+ ClearMeta ();
+
+ if (host.IsTransientError (except.ErrorCode ()))
+ {
+
+ throw;
+
+ }
+
+ ThrowBadFormat ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::AppendArrayItem (const char *ns,
+ const char *arrayName,
+ const char *itemValue,
+ bool isBag,
+ bool propIsStruct)
+ {
+
+ NeedMeta();
+
+ try
+ {
+
+ fPrivate->fMeta->AppendArrayItem (ns,
+ arrayName,
+ isBag ? kXMP_PropValueIsArray
+ : kXMP_PropArrayIsOrdered,
+ itemValue,
+ propIsStruct ? kXMP_PropValueIsStruct
+ : 0);
+
+ }
+ CATCH_XMP ("AppendArrayItem", true )
+
+ }
+
+/*****************************************************************************/
+
+int32 dng_xmp_sdk::CountArrayItems (const char *ns,
+ const char *path) const
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ return fPrivate->fMeta->CountArrayItems (ns, path);
+
+ }
+
+ CATCH_XMP ("CountArrayItems", false)
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::Exists (const char *ns,
+ const char *path) const
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ return fPrivate->fMeta->DoesPropertyExist (ns, path);
+
+ }
+
+ catch (...)
+ {
+
+ // Does not exist...
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::HasNameSpace (const char *ns) const
+ {
+
+ bool result = false;
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ SXMPIterator iter (*fPrivate->fMeta, ns);
+
+ TXMP_STRING_TYPE nsTemp;
+ TXMP_STRING_TYPE prop;
+
+ if (iter.Next (&nsTemp,
+ &prop,
+ NULL,
+ NULL))
+ {
+
+ result = true;
+
+ }
+
+ }
+
+ CATCH_XMP ("HasNameSpace", true)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::Remove (const char *ns,
+ const char *path)
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ fPrivate->fMeta->DeleteProperty (ns, path);
+
+ }
+
+ CATCH_XMP ("DeleteProperty", false)
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::RemoveProperties (const char *ns)
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ SXMPUtils::RemoveProperties (fPrivate->fMeta,
+ ns,
+ NULL,
+ kXMPUtil_DoAllProperties);
+
+ }
+
+ catch (...)
+ {
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::IsEmptyString (const char *ns,
+ const char *path)
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ XMP_OptionBits options = 0;
+
+ if (fPrivate->fMeta->GetProperty (ns,
+ path,
+ &ss,
+ &options))
+ {
+
+ // Item must be simple.
+
+ if (XMP_PropIsSimple (options))
+ {
+
+ // Check for null strings.
+
+ return (ss.c_str () == 0 ||
+ ss.c_str () [0] == 0);
+
+ }
+
+ }
+
+ }
+
+ CATCH_XMP ("IsEmptyString", false)
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::IsEmptyArray (const char *ns,
+ const char *path)
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ XMP_OptionBits options = 0;
+
+ if (fPrivate->fMeta->GetProperty (ns,
+ path,
+ &ss,
+ &options))
+ {
+
+ if (XMP_PropIsArray (options))
+ {
+
+ if (fPrivate->fMeta->GetArrayItem (ns,
+ path,
+ 1,
+ &ss,
+ &options))
+ {
+
+ // If the first item is a null string...
+
+ if (XMP_PropIsSimple (options))
+ {
+
+ if ((ss.c_str () == 0 ||
+ ss.c_str () [0] == 0))
+ {
+
+ // And there is no second item.
+
+ if (!fPrivate->fMeta->GetArrayItem (ns,
+ path,
+ 2,
+ &ss,
+ &options))
+ {
+
+ // Then we have an empty array.
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ else
+ {
+
+ // Unable to get first item, so array is empty.
+
+ return true;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ CATCH_XMP ("IsEmptyArray", false)
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::ComposeArrayItemPath (const char *ns,
+ const char *arrayName,
+ int32 index,
+ dng_string &s) const
+ {
+
+ try
+ {
+
+ std::string ss;
+
+ SXMPUtils::ComposeArrayItemPath (ns, arrayName, index, &ss);
+
+ s.Set (ss.c_str ());
+
+ return;
+
+ }
+
+ CATCH_XMP ("ComposeArrayItemPath", true)
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::ComposeStructFieldPath (const char *ns,
+ const char *structName,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const
+ {
+
+ try
+ {
+
+ std::string ss;
+
+ SXMPUtils::ComposeStructFieldPath (ns,
+ structName,
+ fieldNS,
+ fieldName,
+ &ss);
+
+ s.Set (ss.c_str ());
+
+ return;
+
+ }
+
+ CATCH_XMP ("ComposeStructFieldPath", true)
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::GetNamespacePrefix (const char *uri,
+ dng_string &s) const
+ {
+
+ bool result = false;
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ std::string ss;
+
+ fPrivate->fMeta->GetNamespacePrefix (uri, &ss);
+
+ s.Set (ss.c_str ());
+
+ result = true;
+
+ }
+
+ CATCH_XMP ("GetNamespacePrefix", false)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::GetString (const char *ns,
+ const char *path,
+ dng_string &s) const
+ {
+
+ bool result = false;
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ if (fPrivate->fMeta->GetProperty (ns, path, &ss, NULL))
+ {
+
+ s.Set (ss.c_str ());
+
+ result = true;
+
+ }
+
+ }
+
+ CATCH_XMP ("GetProperty", false)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::ValidateStringList (const char *ns,
+ const char *path)
+ {
+
+ if (Exists (ns, path))
+ {
+
+ bool bogus = true;
+
+ try
+ {
+
+ XMP_Index index = 1;
+
+ TXMP_STRING_TYPE ss;
+
+ while (fPrivate->fMeta->GetArrayItem (ns,
+ path,
+ index++,
+ &ss,
+ NULL))
+ {
+
+ }
+
+ bogus = false;
+
+ }
+
+ CATCH_XMP ("GetArrayItem", false)
+
+ if (bogus)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::GetStringList (const char *ns,
+ const char *path,
+ dng_string_list &list) const
+ {
+
+ bool result = false;
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ XMP_Index index = 1;
+
+ TXMP_STRING_TYPE ss;
+
+ while (fPrivate->fMeta->GetArrayItem (ns,
+ path,
+ index++,
+ &ss,
+ NULL))
+ {
+
+ dng_string s;
+
+ s.Set (ss.c_str ());
+
+ list.Append (s);
+
+ result = true;
+
+ }
+
+ }
+
+ CATCH_XMP ("GetArrayItem", false)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::GetAltLangDefault (const char *ns,
+ const char *path,
+ dng_string &s) const
+ {
+
+ bool result = false;
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ if (fPrivate->fMeta->GetLocalizedText (ns,
+ path,
+ "x-default",
+ "x-default",
+ NULL,
+ &ss,
+ NULL))
+ {
+
+ s.Set (ss.c_str ());
+
+ result = true;
+
+ }
+ //
+ // Special Case: treat the following two representation equivalently.
+ // The first is an empty alt lang array; the second is an array with
+ // an empty item. It seems that xmp lib could be generating both under
+ // some circumstances!
+ //
+ // <dc:description>
+ // <rdf:Alt/>
+ // </dc:description>
+ //
+ // and
+ //
+ // <dc:description>
+ // <rdf:Alt>
+ // <rdf:li xml:lang="x-default"/>
+ // </rdf:Alt>
+ // </dc:description>
+ //
+ else if (fPrivate->fMeta->GetProperty (ns,
+ path,
+ &ss,
+ NULL))
+ {
+
+ if (ss.empty ())
+ {
+
+ s.Clear ();
+
+ result = true;
+
+ }
+
+ }
+
+ }
+
+ CATCH_XMP ("GetLocalizedText", false)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::GetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const
+ {
+
+ bool result = false;
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ if (fPrivate->fMeta->GetStructField (ns,
+ path,
+ fieldNS,
+ fieldName,
+ &ss,
+ NULL))
+ {
+
+ s.Set (ss.c_str ());
+
+ result = true;
+
+ }
+
+ }
+
+ CATCH_XMP ("GetStructField", false)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::Set (const char *ns,
+ const char *path,
+ const char *text)
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ fPrivate->fMeta->SetProperty (ns, path, text);
+
+ return;
+
+ }
+
+ catch (...)
+ {
+
+ // Failed for some reason.
+
+ }
+
+ // Remove existing value and try again.
+
+ Remove (ns, path);
+
+ try
+ {
+
+ fPrivate->fMeta->SetProperty (ns, path, text);
+
+ }
+
+ CATCH_XMP ("SetProperty", true)
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::SetString (const char *ns,
+ const char *path,
+ const dng_string &s)
+ {
+
+ dng_string ss (s);
+
+ ss.SetLineEndings ('\n');
+
+ ss.StripLowASCII ();
+
+ Set (ns, path, ss.Get ());
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::SetStringList (const char *ns,
+ const char *path,
+ const dng_string_list &list,
+ bool isBag)
+ {
+
+ // Remove any existing structure.
+
+ Remove (ns, path);
+
+ // If list is not empty, add the items.
+
+ if (list.Count ())
+ {
+
+ NeedMeta ();
+
+ for (uint32 index = 0; index < list.Count (); index++)
+ {
+
+ dng_string s (list [index]);
+
+ s.SetLineEndings ('\n');
+
+ s.StripLowASCII ();
+
+ try
+ {
+
+ fPrivate->fMeta->AppendArrayItem (ns,
+ path,
+ isBag ? kXMP_PropValueIsArray
+ : kXMP_PropArrayIsOrdered,
+ s.Get ());
+
+ }
+
+ CATCH_XMP ("AppendArrayItem", true)
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::SetAltLangDefault (const char *ns,
+ const char *path,
+ const dng_string &s)
+ {
+
+ NeedMeta ();
+
+ Remove (ns, path);
+
+ dng_string ss (s);
+
+ ss.SetLineEndings ('\n');
+
+ ss.StripLowASCII ();
+
+ try
+ {
+
+ fPrivate->fMeta->SetLocalizedText (ns,
+ path,
+ "x-default",
+ "x-default",
+ ss.Get ());
+
+ }
+
+ CATCH_XMP ("SetLocalizedText", true)
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::SetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ const char *text)
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ fPrivate->fMeta->SetStructField (ns,
+ path,
+ fieldNS,
+ fieldName,
+ text);
+
+ }
+
+ CATCH_XMP ("SetStructField", true)
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::DeleteStructField (const char *ns,
+ const char *structName,
+ const char *fieldNS,
+ const char *fieldName)
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ fPrivate->fMeta->DeleteStructField (ns, structName, fieldNS, fieldName);
+
+ }
+
+ catch (...)
+ {
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block * dng_xmp_sdk::Serialize (dng_memory_allocator &allocator,
+ bool asPacket,
+ uint32 targetBytes,
+ uint32 padBytes,
+ bool forJPEG,
+ bool compact) const
+ {
+
+ // The largest XMP packet you can embed in JPEG using normal methods:
+
+ const uint32 kJPEG_XMP_Limit = 65504;
+
+ if (HasMeta ())
+ {
+
+ TXMP_STRING_TYPE s;
+
+ bool havePacket = false;
+
+ // Note that the XMP lib is changing its default to compact format
+ // in the future, so the following line will need to change.
+
+ uint32 formatOption = compact ? kXMP_UseCompactFormat : 0;
+
+ if (asPacket && targetBytes)
+ {
+
+ try
+ {
+
+ fPrivate->fMeta->SerializeToBuffer (&s,
+ formatOption | kXMP_ExactPacketLength,
+ targetBytes,
+ "",
+ " ");
+
+ havePacket = true;
+
+ }
+
+ catch (...)
+ {
+
+ // Most likely the packet cannot fit in the target
+ // byte count. So try again without the limit.
+
+ }
+
+ }
+
+ if (!havePacket)
+ {
+
+ try
+ {
+
+ fPrivate->fMeta->SerializeToBuffer (&s,
+ formatOption |
+ (asPacket ? 0
+ : kXMP_OmitPacketWrapper),
+ (asPacket ? padBytes
+ : 0),
+ "",
+ " ");
+
+ }
+
+ CATCH_XMP ("SerializeToBuffer", true)
+
+ }
+
+ uint32 packetLen = (uint32) s.size ();
+
+ if (forJPEG && asPacket && padBytes > 0 && targetBytes <= kJPEG_XMP_Limit &&
+ packetLen > kJPEG_XMP_Limit)
+ {
+
+ uint32 overLimitCount = packetLen - kJPEG_XMP_Limit;
+
+ if (overLimitCount > padBytes)
+ {
+ padBytes = 0;
+ }
+ else
+ {
+ padBytes -= overLimitCount;
+ }
+
+ try
+ {
+
+ fPrivate->fMeta->SerializeToBuffer (&s,
+ formatOption,
+ padBytes,
+ "",
+ " ");
+
+ }
+
+ CATCH_XMP ("SerializeToBuffer", true)
+
+ packetLen = (uint32) s.size ();
+
+ }
+
+ if (packetLen)
+ {
+
+ AutoPtr<dng_memory_block> buffer (allocator.Allocate (packetLen));
+
+ memcpy (buffer->Buffer (), s.c_str (), packetLen);
+
+ return buffer.Release ();
+
+ }
+
+ }
+
+ return NULL;
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::PackageForJPEG (dng_memory_allocator &allocator,
+ AutoPtr<dng_memory_block> &stdBlock,
+ AutoPtr<dng_memory_block> &extBlock,
+ dng_string &extDigest) const
+ {
+
+ if (HasMeta ())
+ {
+
+ TXMP_STRING_TYPE stdStr;
+ TXMP_STRING_TYPE extStr;
+ TXMP_STRING_TYPE digestStr;
+
+ try
+ {
+
+ SXMPUtils::PackageForJPEG (*fPrivate->fMeta,
+ &stdStr,
+ &extStr,
+ &digestStr);
+
+ }
+
+ CATCH_XMP ("PackageForJPEG", true)
+
+ uint32 stdLen = (uint32) stdStr.size ();
+ uint32 extLen = (uint32) extStr.size ();
+
+ if (stdLen)
+ {
+
+ stdBlock.Reset (allocator.Allocate (stdLen));
+
+ memcpy (stdBlock->Buffer (), stdStr.c_str (), stdLen);
+
+ }
+
+ if (extLen)
+ {
+
+ extBlock.Reset (allocator.Allocate (extLen));
+
+ memcpy (extBlock->Buffer (), extStr.c_str (), extLen);
+
+ if (digestStr.size () != 32)
+ {
+ ThrowProgramError ();
+ }
+
+ extDigest.Set (digestStr.c_str ());
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::MergeFromJPEG (const dng_xmp_sdk *xmp)
+ {
+
+ if (xmp && xmp->HasMeta ())
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPUtils::MergeFromJPEG (fPrivate->fMeta,
+ *xmp->fPrivate->fMeta);
+
+ }
+
+ CATCH_XMP ("MergeFromJPEG", true)
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::ReplaceXMP (dng_xmp_sdk *xmp)
+ {
+
+ ClearMeta ();
+
+ if (xmp && xmp->HasMeta ())
+ {
+
+ fPrivate->fMeta = xmp->fPrivate->fMeta;
+
+ xmp->fPrivate->fMeta = NULL;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_xmp_sdk::IteratePaths (IteratePathsCallback *callback,
+ void *callbackData,
+ const char* startingNS,
+ const char* startingPath)
+ {
+
+ if (HasMeta ())
+ {
+
+ try
+ {
+
+ SXMPIterator iter (*fPrivate->fMeta, startingNS, startingPath);
+
+ TXMP_STRING_TYPE ns;
+ TXMP_STRING_TYPE prop;
+
+ while (iter.Next (&ns,
+ &prop,
+ NULL,
+ NULL))
+ {
+
+ if (!callback (ns .c_str (),
+ prop.c_str (),
+ callbackData))
+ {
+
+ return false;
+
+ }
+
+ }
+
+ }
+
+ CATCH_XMP ("IteratePaths", true)
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+#if qDNGXMPDocOps
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::DocOpsOpenXMP (const char *srcMIMI)
+ {
+
+ if (srcMIMI [0])
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPDocOps docOps;
+
+ docOps.OpenXMP (fPrivate->fMeta,
+ srcMIMI);
+
+ }
+
+ CATCH_XMP ("DocOpsOpenXMP", false)
+
+ Set (XMP_NS_DC,
+ "format",
+ srcMIMI);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::DocOpsPrepareForSave (const char *srcMIMI,
+ const char *dstMIMI,
+ bool newPath)
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPDocOps docOps;
+
+ docOps.OpenXMP (fPrivate->fMeta,
+ srcMIMI,
+ "old path");
+
+ docOps.NoteChange (kXMP_Part_All);
+
+ docOps.PrepareForSave (dstMIMI,
+ newPath ? "new path" : "old path");
+
+ }
+
+ CATCH_XMP ("DocOpsPrepareForSave", false)
+
+ Set (XMP_NS_DC,
+ "format",
+ dstMIMI);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp_sdk::DocOpsUpdateMetadata (const char *srcMIMI)
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPDocOps docOps;
+
+ docOps.OpenXMP (fPrivate->fMeta,
+ srcMIMI);
+
+ docOps.NoteChange (kXMP_Part_Metadata);
+
+ docOps.PrepareForSave (srcMIMI);
+
+ }
+
+ CATCH_XMP ("DocOpsUpdateMetadata", false)
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_xmp_sdk.h b/gpr/source/lib/dng_sdk/dng_xmp_sdk.h
new file mode 100644
index 0000000..7f4332b
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_xmp_sdk.h
@@ -0,0 +1,238 @@
+/*****************************************************************************/
+// Copyright 2006-2012 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xmp_sdk.h#2 $ */
+/* $DateTime: 2012/05/31 09:29:29 $ */
+/* $Change: 832505 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#ifndef __dng_xmp_sdk__
+#define __dng_xmp_sdk__
+
+/*****************************************************************************/
+
+#include "dng_auto_ptr.h"
+#include "dng_classes.h"
+#include "dng_flags.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+extern const char *XMP_NS_TIFF;
+extern const char *XMP_NS_EXIF;
+extern const char *XMP_NS_PHOTOSHOP;
+extern const char *XMP_NS_XAP;
+extern const char *XMP_NS_XAP_RIGHTS;
+extern const char *XMP_NS_DC;
+extern const char *XMP_NS_XMP_NOTE;
+extern const char *XMP_NS_MM;
+
+extern const char *XMP_NS_CRS;
+extern const char *XMP_NS_CRSS;
+
+extern const char *XMP_NS_LCP;
+
+extern const char *XMP_NS_AUX;
+
+extern const char *XMP_NS_IPTC;
+extern const char *XMP_NS_IPTC_EXT;
+
+extern const char *XMP_NS_CRX;
+
+extern const char *XMP_NS_DNG;
+
+/*****************************************************************************/
+
+class dng_xmp_private;
+
+/*****************************************************************************/
+
+typedef bool (IteratePathsCallback) (const char *ns,
+ const char *path,
+ void *callbackData);
+
+/*****************************************************************************/
+
+struct dng_xmp_namespace
+ {
+ const char * fullName;
+ const char * shortName;
+ };
+
+/*****************************************************************************/
+
+class dng_xmp_sdk
+ {
+
+ private:
+
+ dng_xmp_private *fPrivate;
+
+ public:
+
+ dng_xmp_sdk ();
+
+ dng_xmp_sdk (const dng_xmp_sdk &sdk);
+
+ virtual ~dng_xmp_sdk ();
+
+ static void InitializeSDK (dng_xmp_namespace * extraNamespaces = NULL,
+ const char *software = NULL);
+
+ static void TerminateSDK ();
+
+ bool HasMeta () const;
+
+ void * GetPrivateMeta ();
+
+ void Parse (dng_host &host,
+ const char *buffer,
+ uint32 count);
+
+ bool Exists (const char *ns,
+ const char *path) const;
+
+ void AppendArrayItem (const char *ns,
+ const char *arrayName,
+ const char *itemValue,
+ bool isBag = true,
+ bool propIsStruct = false);
+
+ int32 CountArrayItems (const char *ns,
+ const char *path) const;
+
+ bool HasNameSpace (const char *ns) const;
+
+ void Remove (const char *ns,
+ const char *path);
+
+ void RemoveProperties (const char *ns);
+
+ bool IsEmptyString (const char *ns,
+ const char *path);
+
+ bool IsEmptyArray (const char *ns,
+ const char *path);
+
+ void ComposeArrayItemPath (const char *ns,
+ const char *arrayName,
+ int32 itemNumber,
+ dng_string &s) const;
+
+ void ComposeStructFieldPath (const char *ns,
+ const char *structName,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const;
+
+ bool GetNamespacePrefix (const char *uri,
+ dng_string &s) const;
+
+ bool GetString (const char *ns,
+ const char *path,
+ dng_string &s) const;
+
+ void ValidateStringList (const char *ns,
+ const char *path);
+
+ bool GetStringList (const char *ns,
+ const char *path,
+ dng_string_list &list) const;
+
+ bool GetAltLangDefault (const char *ns,
+ const char *path,
+ dng_string &s) const;
+
+ bool GetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ dng_string &s) const;
+
+ void Set (const char *ns,
+ const char *path,
+ const char *text);
+
+ void SetString (const char *ns,
+ const char *path,
+ const dng_string &s);
+
+ void SetStringList (const char *ns,
+ const char *path,
+ const dng_string_list &list,
+ bool isBag);
+
+ void SetAltLangDefault (const char *ns,
+ const char *path,
+ const dng_string &s);
+
+ void SetStructField (const char *ns,
+ const char *path,
+ const char *fieldNS,
+ const char *fieldName,
+ const char *text);
+
+ void DeleteStructField (const char *ns,
+ const char *structName,
+ const char *fieldNS,
+ const char *fieldName);
+
+ dng_memory_block * Serialize (dng_memory_allocator &allocator,
+ bool asPacket,
+ uint32 targetBytes,
+ uint32 padBytes,
+ bool forJPEG,
+ bool compact) const;
+
+ void PackageForJPEG (dng_memory_allocator &allocator,
+ AutoPtr<dng_memory_block> &stdBlock,
+ AutoPtr<dng_memory_block> &extBlock,
+ dng_string &extDigest) const;
+
+ void MergeFromJPEG (const dng_xmp_sdk *xmp);
+
+ void ReplaceXMP (dng_xmp_sdk *xmp);
+
+ bool IteratePaths (IteratePathsCallback *callback,
+ void *callbackData = NULL,
+ const char *startNS = 0,
+ const char *startingPath = 0);
+
+ #if qDNGXMPDocOps
+
+ void DocOpsOpenXMP (const char *srcMIMI);
+
+ void DocOpsPrepareForSave (const char *srcMIMI,
+ const char *dstMIMI,
+ bool newPath = true);
+
+ void DocOpsUpdateMetadata (const char *srcMIMI);
+
+ #endif
+
+ private:
+
+ void ClearMeta ();
+
+ void MakeMeta ();
+
+ void NeedMeta ();
+
+ // Hidden assignment operator.
+
+ dng_xmp_sdk & operator= (const dng_xmp_sdk &sdk);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_xy_coord.cpp b/gpr/source/lib/dng_sdk/dng_xy_coord.cpp
new file mode 100644
index 0000000..c4fe8f0
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_xy_coord.cpp
@@ -0,0 +1,89 @@
+/*****************************************************************************/
+// Copyright 2006-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xy_coord.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_xy_coord.h"
+
+#include "dng_matrix.h"
+#include "dng_utils.h"
+
+/******************************************************************************/
+
+dng_xy_coord XYZtoXY (const dng_vector_3 &coord)
+ {
+
+ real64 X = coord [0];
+ real64 Y = coord [1];
+ real64 Z = coord [2];
+
+ real64 total = X + Y + Z;
+
+ if (total > 0.0)
+ {
+
+ return dng_xy_coord (X / total,
+ Y / total);
+
+ }
+
+ return D50_xy_coord ();
+
+ }
+
+/*****************************************************************************/
+
+dng_vector_3 XYtoXYZ (const dng_xy_coord &coord)
+ {
+
+ dng_xy_coord temp = coord;
+
+ // Restrict xy coord to someplace inside the range of real xy coordinates.
+ // This prevents math from doing strange things when users specify
+ // extreme temperature/tint coordinates.
+
+ temp.x = Pin_real64 (0.000001, temp.x, 0.999999);
+ temp.y = Pin_real64 (0.000001, temp.y, 0.999999);
+
+ if (temp.x + temp.y > 0.999999)
+ {
+ real64 scale = 0.999999 / (temp.x + temp.y);
+ temp.x *= scale;
+ temp.y *= scale;
+ }
+
+ return dng_vector_3 (temp.x / temp.y,
+ 1.0,
+ (1.0 - temp.x - temp.y) / temp.y);
+
+ }
+
+/*****************************************************************************/
+
+dng_xy_coord PCStoXY ()
+ {
+
+ return D50_xy_coord ();
+
+ }
+
+/*****************************************************************************/
+
+dng_vector_3 PCStoXYZ ()
+ {
+
+ return XYtoXYZ (PCStoXY ());
+
+ }
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/dng_sdk/dng_xy_coord.h b/gpr/source/lib/dng_sdk/dng_xy_coord.h
new file mode 100644
index 0000000..daf2125
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_xy_coord.h
@@ -0,0 +1,187 @@
+/*****************************************************************************/
+// Copyright 2006 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xy_coord.h#2 $ */
+/* $DateTime: 2012/07/31 22:04:34 $ */
+/* $Change: 840853 $ */
+/* $Author: tknoll $ */
+
+/** \file
+ * Representation of colors in xy and XYZ coordinates.
+ */
+
+/*****************************************************************************/
+
+#ifndef __dng_xy_coord__
+#define __dng_xy_coord__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_types.h"
+
+/*****************************************************************************/
+
+class dng_xy_coord
+ {
+
+ public:
+
+ real64 x;
+ real64 y;
+
+ public:
+
+ dng_xy_coord ()
+ : x (0.0)
+ , y (0.0)
+ {
+ }
+
+ dng_xy_coord (real64 xx, real64 yy)
+ : x (xx)
+ , y (yy)
+ {
+ }
+
+ void Clear ()
+ {
+ x = 0.0;
+ y = 0.0;
+ }
+
+ bool IsValid () const
+ {
+ return x > 0.0 &&
+ y > 0.0;
+ }
+
+ bool NotValid () const
+ {
+ return !IsValid ();
+ }
+
+ bool operator== (const dng_xy_coord &coord) const
+ {
+ return coord.x == x &&
+ coord.y == y;
+ }
+
+ bool operator!= (const dng_xy_coord &coord) const
+ {
+ return !(*this == coord);
+ }
+
+ };
+
+/*****************************************************************************/
+
+inline dng_xy_coord operator+ (const dng_xy_coord &A,
+ const dng_xy_coord &B)
+ {
+
+ dng_xy_coord C;
+
+ C.x = A.x + B.x;
+ C.y = A.y + B.y;
+
+ return C;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_xy_coord operator- (const dng_xy_coord &A,
+ const dng_xy_coord &B)
+ {
+
+ dng_xy_coord C;
+
+ C.x = A.x - B.x;
+ C.y = A.y - B.y;
+
+ return C;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_xy_coord operator* (real64 scale,
+ const dng_xy_coord &A)
+ {
+
+ dng_xy_coord B;
+
+ B.x = A.x * scale;
+ B.y = A.y * scale;
+
+ return B;
+
+ }
+
+/******************************************************************************/
+
+inline real64 operator* (const dng_xy_coord &A,
+ const dng_xy_coord &B)
+ {
+
+ return A.x * B.x +
+ A.y * B.y;
+
+ }
+
+/*****************************************************************************/
+
+// Standard xy coordinate constants.
+
+inline dng_xy_coord StdA_xy_coord ()
+ {
+ return dng_xy_coord (0.4476, 0.4074);
+ }
+
+inline dng_xy_coord D50_xy_coord ()
+ {
+ return dng_xy_coord (0.3457, 0.3585);
+ }
+
+inline dng_xy_coord D55_xy_coord ()
+ {
+ return dng_xy_coord (0.3324, 0.3474);
+ }
+
+inline dng_xy_coord D65_xy_coord ()
+ {
+ return dng_xy_coord (0.3127, 0.3290);
+ }
+
+inline dng_xy_coord D75_xy_coord ()
+ {
+ return dng_xy_coord (0.2990, 0.3149);
+ }
+
+/*****************************************************************************/
+
+// Convert between xy coordinates and XYZ coordinates.
+
+dng_xy_coord XYZtoXY (const dng_vector_3 &coord);
+
+dng_vector_3 XYtoXYZ (const dng_xy_coord &coord);
+
+/*****************************************************************************/
+
+// Returns the ICC XYZ profile connection space white point.
+
+dng_xy_coord PCStoXY ();
+
+dng_vector_3 PCStoXYZ ();
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/gpr/source/lib/expat_lib/CMakeLists.txt b/gpr/source/lib/expat_lib/CMakeLists.txt
new file mode 100644
index 0000000..a4c44f8
--- /dev/null
+++ b/gpr/source/lib/expat_lib/CMakeLists.txt
@@ -0,0 +1,21 @@
+# library
+set( LIB_NAME expat_lib )
+
+# get source files
+file( GLOB SRC_FILES "*.c" )
+
+# get include files
+file( GLOB INC_FILES "*.h" )
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+# define compile time definitions
+target_compile_definitions( ${LIB_NAME} PUBLIC XML_STATIC=1 )
+
+SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libstdc++")
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/expat_lib/amigaconfig.h b/gpr/source/lib/expat_lib/amigaconfig.h
new file mode 100644
index 0000000..740f565
--- /dev/null
+++ b/gpr/source/lib/expat_lib/amigaconfig.h
@@ -0,0 +1,29 @@
+#ifndef AMIGACONFIG_H
+#define AMIGACONFIG_H
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 4321
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the <check.h> header file. */
+#undef HAVE_CHECK_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* whether byteorder is bigendian */
+#define WORDS_BIGENDIAN
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+#define XML_DTD
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS
+
+#endif /* AMIGACONFIG_H */
diff --git a/gpr/source/lib/expat_lib/ascii.h b/gpr/source/lib/expat_lib/ascii.h
new file mode 100644
index 0000000..d10530b
--- /dev/null
+++ b/gpr/source/lib/expat_lib/ascii.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#define ASCII_A 0x41
+#define ASCII_B 0x42
+#define ASCII_C 0x43
+#define ASCII_D 0x44
+#define ASCII_E 0x45
+#define ASCII_F 0x46
+#define ASCII_G 0x47
+#define ASCII_H 0x48
+#define ASCII_I 0x49
+#define ASCII_J 0x4A
+#define ASCII_K 0x4B
+#define ASCII_L 0x4C
+#define ASCII_M 0x4D
+#define ASCII_N 0x4E
+#define ASCII_O 0x4F
+#define ASCII_P 0x50
+#define ASCII_Q 0x51
+#define ASCII_R 0x52
+#define ASCII_S 0x53
+#define ASCII_T 0x54
+#define ASCII_U 0x55
+#define ASCII_V 0x56
+#define ASCII_W 0x57
+#define ASCII_X 0x58
+#define ASCII_Y 0x59
+#define ASCII_Z 0x5A
+
+#define ASCII_a 0x61
+#define ASCII_b 0x62
+#define ASCII_c 0x63
+#define ASCII_d 0x64
+#define ASCII_e 0x65
+#define ASCII_f 0x66
+#define ASCII_g 0x67
+#define ASCII_h 0x68
+#define ASCII_i 0x69
+#define ASCII_j 0x6A
+#define ASCII_k 0x6B
+#define ASCII_l 0x6C
+#define ASCII_m 0x6D
+#define ASCII_n 0x6E
+#define ASCII_o 0x6F
+#define ASCII_p 0x70
+#define ASCII_q 0x71
+#define ASCII_r 0x72
+#define ASCII_s 0x73
+#define ASCII_t 0x74
+#define ASCII_u 0x75
+#define ASCII_v 0x76
+#define ASCII_w 0x77
+#define ASCII_x 0x78
+#define ASCII_y 0x79
+#define ASCII_z 0x7A
+
+#define ASCII_0 0x30
+#define ASCII_1 0x31
+#define ASCII_2 0x32
+#define ASCII_3 0x33
+#define ASCII_4 0x34
+#define ASCII_5 0x35
+#define ASCII_6 0x36
+#define ASCII_7 0x37
+#define ASCII_8 0x38
+#define ASCII_9 0x39
+
+#define ASCII_TAB 0x09
+#define ASCII_SPACE 0x20
+#define ASCII_EXCL 0x21
+#define ASCII_QUOT 0x22
+#define ASCII_AMP 0x26
+#define ASCII_APOS 0x27
+#define ASCII_MINUS 0x2D
+#define ASCII_PERIOD 0x2E
+#define ASCII_COLON 0x3A
+#define ASCII_SEMI 0x3B
+#define ASCII_LT 0x3C
+#define ASCII_EQUALS 0x3D
+#define ASCII_GT 0x3E
+#define ASCII_LSQB 0x5B
+#define ASCII_RSQB 0x5D
+#define ASCII_UNDERSCORE 0x5F
+#define ASCII_LPAREN 0x28
+#define ASCII_RPAREN 0x29
+#define ASCII_FF 0x0C
+#define ASCII_SLASH 0x2F
+#define ASCII_HASH 0x23
+#define ASCII_PIPE 0x7C
+#define ASCII_COMMA 0x2C
diff --git a/gpr/source/lib/expat_lib/asciitab.h b/gpr/source/lib/expat_lib/asciitab.h
new file mode 100644
index 0000000..79a15c2
--- /dev/null
+++ b/gpr/source/lib/expat_lib/asciitab.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/gpr/source/lib/expat_lib/expat.h b/gpr/source/lib/expat_lib/expat.h
new file mode 100644
index 0000000..9a21680
--- /dev/null
+++ b/gpr/source/lib/expat_lib/expat.h
@@ -0,0 +1,1047 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_INCLUDED
+#define Expat_INCLUDED 1
+
+#ifdef __VMS
+/* 0 1 2 3 0 1 2 3
+ 1234567890123456789012345678901 1234567890123456789012345678901 */
+#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler
+#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler
+#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler
+#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg
+#endif
+
+#include <stdlib.h>
+#include "expat_external.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct *XML_Parser;
+
+/* Should this be defined using stdbool.h when C99 is available? */
+typedef unsigned char XML_Bool;
+#define XML_TRUE ((XML_Bool) 1)
+#define XML_FALSE ((XML_Bool) 0)
+
+/* The XML_Status enum gives the possible return values for several
+ API functions. The preprocessor #defines are included so this
+ stanza can be added to code that still needs to support older
+ versions of Expat 1.95.x:
+
+ #ifndef XML_STATUS_OK
+ #define XML_STATUS_OK 1
+ #define XML_STATUS_ERROR 0
+ #endif
+
+ Otherwise, the #define hackery is quite ugly and would have been
+ dropped.
+*/
+enum XML_Status {
+ XML_STATUS_ERROR = 0,
+#define XML_STATUS_ERROR XML_STATUS_ERROR
+ XML_STATUS_OK = 1,
+#define XML_STATUS_OK XML_STATUS_OK
+ XML_STATUS_SUSPENDED = 2
+#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
+};
+
+enum XML_Error {
+ XML_ERROR_NONE,
+ XML_ERROR_NO_MEMORY,
+ XML_ERROR_SYNTAX,
+ XML_ERROR_NO_ELEMENTS,
+ XML_ERROR_INVALID_TOKEN,
+ XML_ERROR_UNCLOSED_TOKEN,
+ XML_ERROR_PARTIAL_CHAR,
+ XML_ERROR_TAG_MISMATCH,
+ XML_ERROR_DUPLICATE_ATTRIBUTE,
+ XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
+ XML_ERROR_PARAM_ENTITY_REF,
+ XML_ERROR_UNDEFINED_ENTITY,
+ XML_ERROR_RECURSIVE_ENTITY_REF,
+ XML_ERROR_ASYNC_ENTITY,
+ XML_ERROR_BAD_CHAR_REF,
+ XML_ERROR_BINARY_ENTITY_REF,
+ XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
+ XML_ERROR_MISPLACED_XML_PI,
+ XML_ERROR_UNKNOWN_ENCODING,
+ XML_ERROR_INCORRECT_ENCODING,
+ XML_ERROR_UNCLOSED_CDATA_SECTION,
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ XML_ERROR_NOT_STANDALONE,
+ XML_ERROR_UNEXPECTED_STATE,
+ XML_ERROR_ENTITY_DECLARED_IN_PE,
+ XML_ERROR_FEATURE_REQUIRES_XML_DTD,
+ XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,
+ /* Added in 1.95.7. */
+ XML_ERROR_UNBOUND_PREFIX,
+ /* Added in 1.95.8. */
+ XML_ERROR_UNDECLARING_PREFIX,
+ XML_ERROR_INCOMPLETE_PE,
+ XML_ERROR_XML_DECL,
+ XML_ERROR_TEXT_DECL,
+ XML_ERROR_PUBLICID,
+ XML_ERROR_SUSPENDED,
+ XML_ERROR_NOT_SUSPENDED,
+ XML_ERROR_ABORTED,
+ XML_ERROR_FINISHED,
+ XML_ERROR_SUSPEND_PE,
+ /* Added in 2.0. */
+ XML_ERROR_RESERVED_PREFIX_XML,
+ XML_ERROR_RESERVED_PREFIX_XMLNS,
+ XML_ERROR_RESERVED_NAMESPACE_URI
+};
+
+enum XML_Content_Type {
+ XML_CTYPE_EMPTY = 1,
+ XML_CTYPE_ANY,
+ XML_CTYPE_MIXED,
+ XML_CTYPE_NAME,
+ XML_CTYPE_CHOICE,
+ XML_CTYPE_SEQ
+};
+
+enum XML_Content_Quant {
+ XML_CQUANT_NONE,
+ XML_CQUANT_OPT,
+ XML_CQUANT_REP,
+ XML_CQUANT_PLUS
+};
+
+/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
+ XML_CQUANT_NONE, and the other fields will be zero or NULL.
+ If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
+ numchildren will contain number of elements that may be mixed in
+ and children point to an array of XML_Content cells that will be
+ all of XML_CTYPE_NAME type with no quantification.
+
+ If type == XML_CTYPE_NAME, then the name points to the name, and
+ the numchildren field will be zero and children will be NULL. The
+ quant fields indicates any quantifiers placed on the name.
+
+ CHOICE and SEQ will have name NULL, the number of children in
+ numchildren and children will point, recursively, to an array
+ of XML_Content cells.
+
+ The EMPTY, ANY, and MIXED types will only occur at top level.
+*/
+
+typedef struct XML_cp XML_Content;
+
+struct XML_cp {
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ XML_Char * name;
+ unsigned int numchildren;
+ XML_Content * children;
+};
+
+
+/* This is called for an element declaration. See above for
+ description of the model argument. It's the caller's responsibility
+ to free model when finished with it.
+*/
+typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
+ const XML_Char *name,
+ XML_Content *model);
+
+XMLPARSEAPI(void)
+XML_SetElementDeclHandler(XML_Parser parser,
+ XML_ElementDeclHandler eldecl);
+
+/* The Attlist declaration handler is called for *each* attribute. So
+ a single Attlist declaration with multiple attributes declared will
+ generate multiple calls to this handler. The "default" parameter
+ may be NULL in the case of the "#IMPLIED" or "#REQUIRED"
+ keyword. The "isrequired" parameter will be true and the default
+ value will be NULL in the case of "#REQUIRED". If "isrequired" is
+ true and default is non-NULL, then this is a "#FIXED" default.
+*/
+typedef void (XMLCALL *XML_AttlistDeclHandler) (
+ void *userData,
+ const XML_Char *elname,
+ const XML_Char *attname,
+ const XML_Char *att_type,
+ const XML_Char *dflt,
+ int isrequired);
+
+XMLPARSEAPI(void)
+XML_SetAttlistDeclHandler(XML_Parser parser,
+ XML_AttlistDeclHandler attdecl);
+
+/* The XML declaration handler is called for *both* XML declarations
+ and text declarations. The way to distinguish is that the version
+ parameter will be NULL for text declarations. The encoding
+ parameter may be NULL for XML declarations. The standalone
+ parameter will be -1, 0, or 1 indicating respectively that there
+ was no standalone parameter in the declaration, that it was given
+ as no, or that it was given as yes.
+*/
+typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData,
+ const XML_Char *version,
+ const XML_Char *encoding,
+ int standalone);
+
+XMLPARSEAPI(void)
+XML_SetXmlDeclHandler(XML_Parser parser,
+ XML_XmlDeclHandler xmldecl);
+
+
+typedef struct {
+ void *(*malloc_fcn)(size_t size);
+ void *(*realloc_fcn)(void *ptr, size_t size);
+ void (*free_fcn)(void *ptr);
+} XML_Memory_Handling_Suite;
+
+/* Constructs a new parser; encoding is the encoding specified by the
+ external protocol or NULL if there is none specified.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate(const XML_Char *encoding);
+
+/* Constructs a new parser and namespace processor. Element type
+ names and attribute names that belong to a namespace will be
+ expanded; unprefixed attribute names are never expanded; unprefixed
+ element type names are expanded only if there is a default
+ namespace. The expanded name is the concatenation of the namespace
+ URI, the namespace separator character, and the local part of the
+ name. If the namespace separator is '\0' then the namespace URI
+ and the local part will be concatenated without any separator.
+ It is a programming error to use the separator '\0' with namespace
+ triplets (see XML_SetReturnNSTriplet).
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
+
+
+/* Constructs a new parser using the memory management suite referred to
+ by memsuite. If memsuite is NULL, then use the standard library memory
+ suite. If namespaceSeparator is non-NULL it creates a parser with
+ namespace processing as described above. The character pointed at
+ will serve as the namespace separator.
+
+ All further memory operations used for the created parser will come from
+ the given suite.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate_MM(const XML_Char *encoding,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *namespaceSeparator);
+
+/* Prepare a parser object to be re-used. This is particularly
+ valuable when memory allocation overhead is disproportionatly high,
+ such as when a large number of small documnents need to be parsed.
+ All handlers are cleared from the parser, except for the
+ unknownEncodingHandler. The parser's external state is re-initialized
+ except for the values of ns and ns_triplets.
+
+ Added in Expat 1.95.3.
+*/
+XMLPARSEAPI(XML_Bool)
+XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
+
+/* atts is array of name/value pairs, terminated by 0;
+ names and values are 0 terminated.
+*/
+typedef void (XMLCALL *XML_StartElementHandler) (void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
+ const XML_Char *name);
+
+
+/* s is not 0 terminated. */
+typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData,
+ const XML_Char *s,
+ int len);
+
+/* target and data are 0 terminated */
+typedef void (XMLCALL *XML_ProcessingInstructionHandler) (
+ void *userData,
+ const XML_Char *target,
+ const XML_Char *data);
+
+/* data is 0 terminated */
+typedef void (XMLCALL *XML_CommentHandler) (void *userData,
+ const XML_Char *data);
+
+typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData);
+typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
+
+/* This is called for any characters in the XML document for which
+ there is no applicable handler. This includes both characters that
+ are part of markup which is of a kind that is not reported
+ (comments, markup declarations), or characters that are part of a
+ construct which could be reported but for which no handler has been
+ supplied. The characters are passed exactly as they were in the XML
+ document except that they will be encoded in UTF-8 or UTF-16.
+ Line boundaries are not normalized. Note that a byte order mark
+ character is not passed to the default handler. There are no
+ guarantees about how characters are divided between calls to the
+ default handler: for example, a comment might be split between
+ multiple calls.
+*/
+typedef void (XMLCALL *XML_DefaultHandler) (void *userData,
+ const XML_Char *s,
+ int len);
+
+/* This is called for the start of the DOCTYPE declaration, before
+ any DTD or internal subset is parsed.
+*/
+typedef void (XMLCALL *XML_StartDoctypeDeclHandler) (
+ void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid,
+ int has_internal_subset);
+
+/* This is called for the start of the DOCTYPE declaration when the
+ closing > is encountered, but after processing any external
+ subset.
+*/
+typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
+
+/* This is called for entity declarations. The is_parameter_entity
+ argument will be non-zero if the entity is a parameter entity, zero
+ otherwise.
+
+ For internal entities (<!ENTITY foo "bar">), value will
+ be non-NULL and systemId, publicID, and notationName will be NULL.
+ The value string is NOT nul-terminated; the length is provided in
+ the value_length argument. Since it is legal to have zero-length
+ values, do not use this argument to test for internal entities.
+
+ For external entities, value will be NULL and systemId will be
+ non-NULL. The publicId argument will be NULL unless a public
+ identifier was provided. The notationName argument will have a
+ non-NULL value only for unparsed entity declarations.
+
+ Note that is_parameter_entity can't be changed to XML_Bool, since
+ that would break binary compatibility.
+*/
+typedef void (XMLCALL *XML_EntityDeclHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity,
+ const XML_Char *value,
+ int value_length,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+XMLPARSEAPI(void)
+XML_SetEntityDeclHandler(XML_Parser parser,
+ XML_EntityDeclHandler handler);
+
+/* OBSOLETE -- OBSOLETE -- OBSOLETE
+ This handler has been superceded by the EntityDeclHandler above.
+ It is provided here for backward compatibility.
+
+ This is called for a declaration of an unparsed (NDATA) entity.
+ The base argument is whatever was set by XML_SetBase. The
+ entityName, systemId and notationName arguments will never be
+ NULL. The other arguments may be.
+*/
+typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+/* This is called for a declaration of notation. The base argument is
+ whatever was set by XML_SetBase. The notationName will never be
+ NULL. The other arguments can be.
+*/
+typedef void (XMLCALL *XML_NotationDeclHandler) (
+ void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* When namespace processing is enabled, these are called once for
+ each namespace declaration. The call to the start and end element
+ handlers occur between the calls to the start and end namespace
+ declaration handlers. For an xmlns attribute, prefix will be
+ NULL. For an xmlns="" attribute, uri will be NULL.
+*/
+typedef void (XMLCALL *XML_StartNamespaceDeclHandler) (
+ void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
+typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
+ void *userData,
+ const XML_Char *prefix);
+
+/* This is called if the document is not standalone, that is, it has an
+ external subset or a reference to a parameter entity, but does not
+ have standalone="yes". If this handler returns XML_STATUS_ERROR,
+ then processing will not continue, and the parser will return a
+ XML_ERROR_NOT_STANDALONE error.
+ If parameter entity parsing is enabled, then in addition to the
+ conditions above this handler will only be called if the referenced
+ entity was actually read.
+*/
+typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
+
+/* This is called for a reference to an external parsed general
+ entity. The referenced entity is not automatically parsed. The
+ application can parse it immediately or later using
+ XML_ExternalEntityParserCreate.
+
+ The parser argument is the parser parsing the entity containing the
+ reference; it can be passed as the parser argument to
+ XML_ExternalEntityParserCreate. The systemId argument is the
+ system identifier as specified in the entity declaration; it will
+ not be NULL.
+
+ The base argument is the system identifier that should be used as
+ the base for resolving systemId if systemId was relative; this is
+ set by XML_SetBase; it may be NULL.
+
+ The publicId argument is the public identifier as specified in the
+ entity declaration, or NULL if none was specified; the whitespace
+ in the public identifier will have been normalized as required by
+ the XML spec.
+
+ The context argument specifies the parsing context in the format
+ expected by the context argument to XML_ExternalEntityParserCreate;
+ context is valid only until the handler returns, so if the
+ referenced entity is to be parsed later, it must be copied.
+ context is NULL only when the entity is a parameter entity.
+
+ The handler should return XML_STATUS_ERROR if processing should not
+ continue because of a fatal error in the handling of the external
+ entity. In this case the calling parser will return an
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
+
+ Note that unlike other handlers the first argument is the parser,
+ not userData.
+*/
+typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
+ XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* This is called in two situations:
+ 1) An entity reference is encountered for which no declaration
+ has been read *and* this is not an error.
+ 2) An internal entity reference is read, but not expanded, because
+ XML_SetDefaultHandler has been called.
+ Note: skipped parameter entities in declarations and skipped general
+ entities in attribute values cannot be reported, because
+ the event would be out of sync with the reporting of the
+ declarations or attribute values
+*/
+typedef void (XMLCALL *XML_SkippedEntityHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
+
+/* This structure is filled in by the XML_UnknownEncodingHandler to
+ provide information to the parser about encodings that are unknown
+ to the parser.
+
+ The map[b] member gives information about byte sequences whose
+ first byte is b.
+
+ If map[b] is c where c is >= 0, then b by itself encodes the
+ Unicode scalar value c.
+
+ If map[b] is -1, then the byte sequence is malformed.
+
+ If map[b] is -n, where n >= 2, then b is the first byte of an
+ n-byte sequence that encodes a single Unicode scalar value.
+
+ The data member will be passed as the first argument to the convert
+ function.
+
+ The convert function is used to convert multibyte sequences; s will
+ point to a n-byte sequence where map[(unsigned char)*s] == -n. The
+ convert function must return the Unicode scalar value represented
+ by this byte sequence or -1 if the byte sequence is malformed.
+
+ The convert function may be NULL if the encoding is a single-byte
+ encoding, that is if map[b] >= -1 for all bytes b.
+
+ When the parser is finished with the encoding, then if release is
+ not NULL, it will call release passing it the data member; once
+ release has been called, the convert function will not be called
+ again.
+
+ Expat places certain restrictions on the encodings that are supported
+ using this mechanism.
+
+ 1. Every ASCII character that can appear in a well-formed XML document,
+ other than the characters
+
+ $@\^`{}~
+
+ must be represented by a single byte, and that byte must be the
+ same byte that represents that character in ASCII.
+
+ 2. No character may require more than 4 bytes to encode.
+
+ 3. All characters encoded must have Unicode scalar values <=
+ 0xFFFF, (i.e., characters that would be encoded by surrogates in
+ UTF-16 are not allowed). Note that this restriction doesn't
+ apply to the built-in support for UTF-8 and UTF-16.
+
+ 4. No Unicode character may be encoded by more than one distinct
+ sequence of bytes.
+*/
+typedef struct {
+ int map[256];
+ void *data;
+ int (XMLCALL *convert)(void *data, const char *s);
+ void (XMLCALL *release)(void *data);
+} XML_Encoding;
+
+/* This is called for an encoding that is unknown to the parser.
+
+ The encodingHandlerData argument is that which was passed as the
+ second argument to XML_SetUnknownEncodingHandler.
+
+ The name argument gives the name of the encoding as specified in
+ the encoding declaration.
+
+ If the callback can provide information about the encoding, it must
+ fill in the XML_Encoding structure, and return XML_STATUS_OK.
+ Otherwise it must return XML_STATUS_ERROR.
+
+ If info does not describe a suitable encoding, then the parser will
+ return an XML_UNKNOWN_ENCODING error.
+*/
+typedef int (XMLCALL *XML_UnknownEncodingHandler) (
+ void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
+
+XMLPARSEAPI(void)
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartElementHandler(XML_Parser parser,
+ XML_StartElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetEndElementHandler(XML_Parser parser,
+ XML_EndElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler);
+XMLPARSEAPI(void)
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+ XML_EndCdataSectionHandler end);
+
+/* This sets the default handler and also inhibits expansion of
+ internal entities. These entity references will be passed to the
+ default handler, or to the skipped entity handler, if one is set.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+/* This sets the default handler but does not inhibit expansion of
+ internal entities. The entity reference will not be passed to the
+ default handler.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+ XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+ XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler);
+
+/* If a non-NULL value for arg is specified here, then it will be
+ passed as the first argument to the external entity ref handler
+ instead of the parser object.
+*/
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
+ void *arg);
+
+XMLPARSEAPI(void)
+XML_SetSkippedEntityHandler(XML_Parser parser,
+ XML_SkippedEntityHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *encodingHandlerData);
+
+/* This can be called within a handler for a start element, end
+ element, processing instruction or character data. It causes the
+ corresponding markup to be passed to the default handler.
+*/
+XMLPARSEAPI(void)
+XML_DefaultCurrent(XML_Parser parser);
+
+/* If do_nst is non-zero, and namespace processing is in effect, and
+ a name has a prefix (i.e. an explicit namespace qualifier) then
+ that name is returned as a triplet in a single string separated by
+ the separator character specified when the parser was created: URI
+ + sep + local_name + sep + prefix.
+
+ If do_nst is zero, then namespace information is returned in the
+ default manner (URI + sep + local_name) whether or not the name
+ has a prefix.
+
+ Note: Calling XML_SetReturnNSTriplet after XML_Parse or
+ XML_ParseBuffer has no effect.
+*/
+
+XMLPARSEAPI(void)
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
+
+/* This value is passed as the userData argument to callbacks. */
+XMLPARSEAPI(void)
+XML_SetUserData(XML_Parser parser, void *userData);
+
+/* Returns the last value set by XML_SetUserData or NULL. */
+#define XML_GetUserData(parser) (*(void **)(parser))
+
+/* This is equivalent to supplying an encoding argument to
+ XML_ParserCreate. On success XML_SetEncoding returns non-zero,
+ zero otherwise.
+ Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer
+ has no effect and returns XML_STATUS_ERROR.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
+
+/* If this function is called, then the parser will be passed as the
+ first argument to callbacks instead of userData. The userData will
+ still be accessible using XML_GetUserData.
+*/
+XMLPARSEAPI(void)
+XML_UseParserAsHandlerArg(XML_Parser parser);
+
+/* If useDTD == XML_TRUE is passed to this function, then the parser
+ will assume that there is an external subset, even if none is
+ specified in the document. In such a case the parser will call the
+ externalEntityRefHandler with a value of NULL for the systemId
+ argument (the publicId and context arguments will be NULL as well).
+ Note: For the purpose of checking WFC: Entity Declared, passing
+ useDTD == XML_TRUE will make the parser behave as if the document
+ had a DTD with an external subset.
+ Note: If this function is called, then this must be done before
+ the first call to XML_Parse or XML_ParseBuffer, since it will
+ have no effect after that. Returns
+ XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING.
+ Note: If the document does not have a DOCTYPE declaration at all,
+ then startDoctypeDeclHandler and endDoctypeDeclHandler will not
+ be called, despite an external subset being parsed.
+ Note: If XML_DTD is not defined when Expat is compiled, returns
+ XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
+
+
+/* Sets the base to be used for resolving relative URIs in system
+ identifiers in declarations. Resolving relative identifiers is
+ left to the application: this value will be passed through as the
+ base argument to the XML_ExternalEntityRefHandler,
+ XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base
+ argument will be copied. Returns XML_STATUS_ERROR if out of memory,
+ XML_STATUS_OK otherwise.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetBase(XML_Parser parser, const XML_Char *base);
+
+XMLPARSEAPI(const XML_Char *)
+XML_GetBase(XML_Parser parser);
+
+/* Returns the number of the attribute/value pairs passed in last call
+ to the XML_StartElementHandler that were specified in the start-tag
+ rather than defaulted. Each attribute/value pair counts as 2; thus
+ this correspondds to an index into the atts array passed to the
+ XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetSpecifiedAttributeCount(XML_Parser parser);
+
+/* Returns the index of the ID attribute passed in the last call to
+ XML_StartElementHandler, or -1 if there is no ID attribute. Each
+ attribute/value pair counts as 2; thus this correspondds to an
+ index into the atts array passed to the XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetIdAttributeIndex(XML_Parser parser);
+
+#ifdef XML_ATTR_INFO
+/* Source file byte offsets for the start and end of attribute names and values.
+ The value indices are exclusive of surrounding quotes; thus in a UTF-8 source
+ file an attribute value of "blah" will yield:
+ info->valueEnd - info->valueStart = 4 bytes.
+*/
+typedef struct {
+ XML_Index nameStart; /* Offset to beginning of the attribute name. */
+ XML_Index nameEnd; /* Offset after the attribute name's last byte. */
+ XML_Index valueStart; /* Offset to beginning of the attribute value. */
+ XML_Index valueEnd; /* Offset after the attribute value's last byte. */
+} XML_AttrInfo;
+
+/* Returns an array of XML_AttrInfo structures for the attribute/value pairs
+ passed in last call to the XML_StartElementHandler that were specified
+ in the start-tag rather than defaulted. Each attribute/value pair counts
+ as 1; thus the number of entries in the array is
+ XML_GetSpecifiedAttributeCount(parser) / 2.
+*/
+XMLPARSEAPI(const XML_AttrInfo *)
+XML_GetAttributeInfo(XML_Parser parser);
+#endif
+
+/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
+ detected. The last call to XML_Parse must have isFinal true; len
+ may be zero for this call (or any other).
+
+ Though the return values for these functions has always been
+ described as a Boolean value, the implementation, at least for the
+ 1.95.x series, has always returned exactly one of the XML_Status
+ values.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
+
+XMLPARSEAPI(void *)
+XML_GetBuffer(XML_Parser parser, int len);
+
+XMLPARSEAPI(enum XML_Status)
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
+
+/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
+ Must be called from within a call-back handler, except when aborting
+ (resumable = 0) an already suspended parser. Some call-backs may
+ still follow because they would otherwise get lost. Examples:
+ - endElementHandler() for empty elements when stopped in
+ startElementHandler(),
+ - endNameSpaceDeclHandler() when stopped in endElementHandler(),
+ and possibly others.
+
+ Can be called from most handlers, including DTD related call-backs,
+ except when parsing an external parameter entity and resumable != 0.
+ Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
+ Possible error codes:
+ - XML_ERROR_SUSPENDED: when suspending an already suspended parser.
+ - XML_ERROR_FINISHED: when the parser has already finished.
+ - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
+
+ When resumable != 0 (true) then parsing is suspended, that is,
+ XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED.
+ Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
+ return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
+
+ *Note*:
+ This will be applied to the current parser instance only, that is, if
+ there is a parent parser then it will continue parsing when the
+ externalEntityRefHandler() returns. It is up to the implementation of
+ the externalEntityRefHandler() to call XML_StopParser() on the parent
+ parser (recursively), if one wants to stop parsing altogether.
+
+ When suspended, parsing can be resumed by calling XML_ResumeParser().
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_StopParser(XML_Parser parser, XML_Bool resumable);
+
+/* Resumes parsing after it has been suspended with XML_StopParser().
+ Must not be called from within a handler call-back. Returns same
+ status codes as XML_Parse() or XML_ParseBuffer().
+ Additional error code XML_ERROR_NOT_SUSPENDED possible.
+
+ *Note*:
+ This must be called on the most deeply nested child parser instance
+ first, and on its parent parser only after the child parser has finished,
+ to be applied recursively until the document entity's parser is restarted.
+ That is, the parent parser will not resume by itself and it is up to the
+ application to call XML_ResumeParser() on it at the appropriate moment.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_ResumeParser(XML_Parser parser);
+
+enum XML_Parsing {
+ XML_INITIALIZED,
+ XML_PARSING,
+ XML_FINISHED,
+ XML_SUSPENDED
+};
+
+typedef struct {
+ enum XML_Parsing parsing;
+ XML_Bool finalBuffer;
+} XML_ParsingStatus;
+
+/* Returns status of parser with respect to being initialized, parsing,
+ finished, or suspended and processing the final buffer.
+ XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus,
+ XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
+*/
+XMLPARSEAPI(void)
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
+
+/* Creates an XML_Parser object that can parse an external general
+ entity; context is a '\0'-terminated string specifying the parse
+ context; encoding is a '\0'-terminated string giving the name of
+ the externally specified encoding, or NULL if there is no
+ externally specified encoding. The context string consists of a
+ sequence of tokens separated by formfeeds (\f); a token consisting
+ of a name specifies that the general entity of the name is open; a
+ token of the form prefix=uri specifies the namespace for a
+ particular prefix; a token of the form =uri specifies the default
+ namespace. This can be called at any point after the first call to
+ an ExternalEntityRefHandler so longer as the parser has not yet
+ been freed. The new parser is completely independent and may
+ safely be used in a separate thread. The handlers and userData are
+ initialized from the parser argument. Returns NULL if out of memory.
+ Otherwise returns a new XML_Parser object.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ExternalEntityParserCreate(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *encoding);
+
+enum XML_ParamEntityParsing {
+ XML_PARAM_ENTITY_PARSING_NEVER,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
+ XML_PARAM_ENTITY_PARSING_ALWAYS
+};
+
+/* Controls parsing of parameter entities (including the external DTD
+ subset). If parsing of parameter entities is enabled, then
+ references to external parameter entities (including the external
+ DTD subset) will be passed to the handler set with
+ XML_SetExternalEntityRefHandler. The context passed will be 0.
+
+ Unlike external general entities, external parameter entities can
+ only be parsed synchronously. If the external parameter entity is
+ to be parsed, it must be parsed during the call to the external
+ entity ref handler: the complete sequence of
+ XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
+ XML_ParserFree calls must be made during this call. After
+ XML_ExternalEntityParserCreate has been called to create the parser
+ for the external parameter entity (context must be 0 for this
+ call), it is illegal to make any calls on the old parser until
+ XML_ParserFree has been called on the newly created parser.
+ If the library has been compiled without support for parameter
+ entity parsing (ie without XML_DTD being defined), then
+ XML_SetParamEntityParsing will return 0 if parsing of parameter
+ entities is requested; otherwise it will return non-zero.
+ Note: If XML_SetParamEntityParsing is called after XML_Parse or
+ XML_ParseBuffer, then it has no effect and will always return 0.
+*/
+XMLPARSEAPI(int)
+XML_SetParamEntityParsing(XML_Parser parser,
+ enum XML_ParamEntityParsing parsing);
+
+/* Sets the hash salt to use for internal hash calculations.
+ Helps in preventing DoS attacks based on predicting hash
+ function behavior. This must be called before parsing is started.
+ Returns 1 if successful, 0 when called after parsing has started.
+*/
+XMLPARSEAPI(int)
+XML_SetHashSalt(XML_Parser parser,
+ unsigned long hash_salt);
+
+/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
+ XML_GetErrorCode returns information about the error.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_GetErrorCode(XML_Parser parser);
+
+/* These functions return information about the current parse
+ location. They may be called from any callback called to report
+ some parse event; in this case the location is the location of the
+ first of the sequence of characters that generated the event. When
+ called from callbacks generated by declarations in the document
+ prologue, the location identified isn't as neatly defined, but will
+ be within the relevant markup. When called outside of the callback
+ functions, the position indicated will be just past the last parse
+ event (regardless of whether there was an associated callback).
+
+ They may also be called after returning from a call to XML_Parse
+ or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then
+ the location is the location of the character at which the error
+ was detected; otherwise the location is the location of the last
+ parse event, as described above.
+*/
+XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
+
+/* Return the number of bytes in the current event.
+ Returns 0 if the event is in an internal entity.
+*/
+XMLPARSEAPI(int)
+XML_GetCurrentByteCount(XML_Parser parser);
+
+/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+ the integer pointed to by offset to the offset within this buffer
+ of the current parse position, and sets the integer pointed to by size
+ to the size of this buffer (the number of input bytes). Otherwise
+ returns a NULL pointer. Also returns a NULL pointer if a parse isn't
+ active.
+
+ NOTE: The character pointer returned should not be used outside
+ the handler that makes the call.
+*/
+XMLPARSEAPI(const char *)
+XML_GetInputContext(XML_Parser parser,
+ int *offset,
+ int *size);
+
+/* For backwards compatibility with previous versions. */
+#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
+#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
+#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
+
+/* Frees the content model passed to the element declaration handler */
+XMLPARSEAPI(void)
+XML_FreeContentModel(XML_Parser parser, XML_Content *model);
+
+/* Exposing the memory handling functions used in Expat */
+XMLPARSEAPI(void *)
+XML_MemMalloc(XML_Parser parser, size_t size);
+
+XMLPARSEAPI(void *)
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
+
+XMLPARSEAPI(void)
+XML_MemFree(XML_Parser parser, void *ptr);
+
+/* Frees memory used by the parser. */
+XMLPARSEAPI(void)
+XML_ParserFree(XML_Parser parser);
+
+/* Returns a string describing the error. */
+XMLPARSEAPI(const XML_LChar *)
+XML_ErrorString(enum XML_Error code);
+
+/* Return a string containing the version number of this expat */
+XMLPARSEAPI(const XML_LChar *)
+XML_ExpatVersion(void);
+
+typedef struct {
+ int major;
+ int minor;
+ int micro;
+} XML_Expat_Version;
+
+/* Return an XML_Expat_Version structure containing numeric version
+ number information for this version of expat.
+*/
+XMLPARSEAPI(XML_Expat_Version)
+XML_ExpatVersionInfo(void);
+
+/* Added in Expat 1.95.5. */
+enum XML_FeatureEnum {
+ XML_FEATURE_END = 0,
+ XML_FEATURE_UNICODE,
+ XML_FEATURE_UNICODE_WCHAR_T,
+ XML_FEATURE_DTD,
+ XML_FEATURE_CONTEXT_BYTES,
+ XML_FEATURE_MIN_SIZE,
+ XML_FEATURE_SIZEOF_XML_CHAR,
+ XML_FEATURE_SIZEOF_XML_LCHAR,
+ XML_FEATURE_NS,
+ XML_FEATURE_LARGE_SIZE,
+ XML_FEATURE_ATTR_INFO
+ /* Additional features must be added to the end of this enum. */
+};
+
+typedef struct {
+ enum XML_FeatureEnum feature;
+ const XML_LChar *name;
+ long int value;
+} XML_Feature;
+
+XMLPARSEAPI(const XML_Feature *)
+XML_GetFeatureList(void);
+
+
+/* Expat follows the GNU/Linux convention of odd number minor version for
+ beta/development releases and even number minor version for stable
+ releases. Micro is bumped with each release, and set to 0 with each
+ change to major or minor version.
+*/
+#define XML_MAJOR_VERSION 2
+#define XML_MINOR_VERSION 1
+#define XML_MICRO_VERSION 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_INCLUDED */
diff --git a/gpr/source/lib/expat_lib/expat_external.h b/gpr/source/lib/expat_lib/expat_external.h
new file mode 100644
index 0000000..2c03284
--- /dev/null
+++ b/gpr/source/lib/expat_lib/expat_external.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_External_INCLUDED
+#define Expat_External_INCLUDED 1
+
+/* External API definitions */
+
+#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
+#define XML_USE_MSC_EXTENSIONS 1
+#endif
+
+/* Expat tries very hard to make the API boundary very specifically
+ defined. There are two macros defined to control this boundary;
+ each of these can be defined before including this header to
+ achieve some different behavior, but doing so it not recommended or
+ tested frequently.
+
+ XMLCALL - The calling convention to use for all calls across the
+ "library boundary." This will default to cdecl, and
+ try really hard to tell the compiler that's what we
+ want.
+
+ XMLIMPORT - Whatever magic is needed to note that a function is
+ to be imported from a dynamically loaded library
+ (.dll, .so, or .sl, depending on your platform).
+
+ The XMLCALL macro was added in Expat 1.95.7. The only one which is
+ expected to be directly useful in client code is XMLCALL.
+
+ Note that on at least some Unix versions, the Expat library must be
+ compiled with the cdecl calling convention as the default since
+ system headers may assume the cdecl convention.
+*/
+#ifndef XMLCALL
+#if defined(_MSC_VER)
+#define XMLCALL __cdecl
+#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
+#define XMLCALL __attribute__((cdecl))
+#else
+/* For any platform which uses this definition and supports more than
+ one calling convention, we need to extend this definition to
+ declare the convention used on that platform, if it's possible to
+ do so.
+
+ If this is the case for your platform, please file a bug report
+ with information on how to identify your platform via the C
+ pre-processor and how to specify the same calling convention as the
+ platform's malloc() implementation.
+*/
+#define XMLCALL
+#endif
+#endif /* not defined XMLCALL */
+
+
+#if !defined(XML_STATIC) && !defined(XMLIMPORT)
+#ifndef XML_BUILDING_EXPAT
+/* using Expat from an application */
+
+#ifdef XML_USE_MSC_EXTENSIONS
+#define XMLIMPORT __declspec(dllimport)
+#endif
+
+#endif
+#endif /* not defined XML_STATIC */
+
+
+/* If we didn't define it above, define it away: */
+#ifndef XMLIMPORT
+#define XMLIMPORT
+#endif
+
+
+#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_UNICODE
+#endif
+
+#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
+#ifdef XML_UNICODE_WCHAR_T
+typedef wchar_t XML_Char;
+typedef wchar_t XML_LChar;
+#else
+typedef unsigned short XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE_WCHAR_T */
+#else /* Information is UTF-8 encoded. */
+typedef char XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE */
+
+#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
+#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+typedef __int64 XML_Index;
+typedef unsigned __int64 XML_Size;
+#else
+typedef long long XML_Index;
+typedef unsigned long long XML_Size;
+#endif
+#else
+typedef long XML_Index;
+typedef unsigned long XML_Size;
+#endif /* XML_LARGE_SIZE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_External_INCLUDED */
diff --git a/gpr/source/lib/expat_lib/iasciitab.h b/gpr/source/lib/expat_lib/iasciitab.h
new file mode 100644
index 0000000..24a1d5c
--- /dev/null
+++ b/gpr/source/lib/expat_lib/iasciitab.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/gpr/source/lib/expat_lib/internal.h b/gpr/source/lib/expat_lib/internal.h
new file mode 100644
index 0000000..9ee06af
--- /dev/null
+++ b/gpr/source/lib/expat_lib/internal.h
@@ -0,0 +1,79 @@
+/* internal.h
+
+ Internal definitions used by Expat. This is not needed to compile
+ client code.
+
+ The following calling convention macros are defined for frequently
+ called functions:
+
+ FASTCALL - Used for those internal functions that have a simple
+ body and a low number of arguments and local variables.
+
+ PTRCALL - Used for functions called though function pointers.
+
+ PTRFASTCALL - Like PTRCALL, but for low number of arguments.
+
+ inline - Used for selected internal functions for which inlining
+ may improve performance on some platforms.
+
+ Note: Use of these macros is based on judgement, not hard rules,
+ and therefore subject to change.
+*/
+
+#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
+/* We'll use this version by default only where we know it helps.
+
+ regparm() generates warnings on Solaris boxes. See SF bug #692878.
+
+ Instability reported with egcs on a RedHat Linux 7.3.
+ Let's comment out:
+ #define FASTCALL __attribute__((stdcall, regparm(3)))
+ and let's try this:
+*/
+#define FASTCALL __attribute__((regparm(3)))
+#define PTRFASTCALL __attribute__((regparm(3)))
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 7 || defined(__clang__) && __clang_major__ >= 10
+#define FALL_THROUGH __attribute__ ((fallthrough))
+#else
+#define FALL_THROUGH ((void)0)
+#endif
+
+/* Using __fastcall seems to have an unexpected negative effect under
+ MS VC++, especially for function pointers, so we won't use it for
+ now on that platform. It may be reconsidered for a future release
+ if it can be made more effective.
+ Likely reason: __fastcall on Windows is like stdcall, therefore
+ the compiler cannot perform stack optimizations for call clusters.
+*/
+
+/* Make sure all of these are defined if they aren't already. */
+
+#ifndef FASTCALL
+#define FASTCALL
+#endif
+
+#ifndef PTRCALL
+#define PTRCALL
+#endif
+
+#ifndef PTRFASTCALL
+#define PTRFASTCALL
+#endif
+
+#ifndef XML_MIN_SIZE
+#if !defined(__cplusplus) && !defined(inline)
+#ifdef __GNUC__
+#define inline __inline
+#endif /* __GNUC__ */
+#endif
+#endif /* XML_MIN_SIZE */
+
+#ifdef __cplusplus
+#define inline inline
+#else
+#ifndef inline
+#define inline
+#endif
+#endif
diff --git a/gpr/source/lib/expat_lib/latin1tab.h b/gpr/source/lib/expat_lib/latin1tab.h
new file mode 100644
index 0000000..53c25d7
--- /dev/null
+++ b/gpr/source/lib/expat_lib/latin1tab.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
+/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/gpr/source/lib/expat_lib/macconfig.h b/gpr/source/lib/expat_lib/macconfig.h
new file mode 100644
index 0000000..3579cfc
--- /dev/null
+++ b/gpr/source/lib/expat_lib/macconfig.h
@@ -0,0 +1,50 @@
+/*================================================================
+** Copyright 2000, Clark Cooper
+** All rights reserved.
+**
+** This is free software. You are permitted to copy, distribute, or modify
+** it under the terms of the MIT/X license (contained in the COPYING file
+** with this distribution.)
+**
+*/
+
+#ifndef MACCONFIG_H
+#define MACCONFIG_H
+
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 4321
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* whether byteorder is bigendian */
+#define WORDS_BIGENDIAN
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#undef XML_CONTEXT_BYTES
+
+/* Define to make parameter entity parsing functionality available. */
+#define XML_DTD
+
+/* Define to make XML Namespaces functionality available. */
+#define XML_NS
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `long' if <sys/types.h> does not define. */
+#define off_t long
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+
+#endif /* ifndef MACCONFIG_H */
diff --git a/gpr/source/lib/expat_lib/nametab.h b/gpr/source/lib/expat_lib/nametab.h
new file mode 100644
index 0000000..b05e62c
--- /dev/null
+++ b/gpr/source/lib/expat_lib/nametab.h
@@ -0,0 +1,150 @@
+static const unsigned namingBitmap[] = {
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
+0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
+0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
+0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
+0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
+0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
+0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
+0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
+0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
+0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
+0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
+0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
+0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
+0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
+0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
+0x40000000, 0xF580C900, 0x00000007, 0x02010800,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
+0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
+0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
+0x00000000, 0x00004C40, 0x00000000, 0x00000000,
+0x00000007, 0x00000000, 0x00000000, 0x00000000,
+0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
+0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
+0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
+0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
+0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
+0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
+0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
+0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
+0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
+0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
+0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
+0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
+0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
+0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
+0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
+0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
+};
+static const unsigned char nmstrtPages[] = {
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
+0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+static const unsigned char namePages[] = {
+0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
+0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/gpr/source/lib/expat_lib/utf8tab.h b/gpr/source/lib/expat_lib/utf8tab.h
new file mode 100644
index 0000000..7bb3e77
--- /dev/null
+++ b/gpr/source/lib/expat_lib/utf8tab.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+
+/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
+/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/gpr/source/lib/expat_lib/winconfig.h b/gpr/source/lib/expat_lib/winconfig.h
new file mode 100644
index 0000000..c4e2646
--- /dev/null
+++ b/gpr/source/lib/expat_lib/winconfig.h
@@ -0,0 +1,27 @@
+/*================================================================
+** Copyright 2000, Clark Cooper
+** All rights reserved.
+**
+** This is free software. You are permitted to copy, distribute, or modify
+** it under the terms of the MIT/X license (contained in the COPYING file
+** with this distribution.)
+*/
+
+#ifndef WINCONFIG_H
+#define WINCONFIG_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <memory.h>
+#include <string.h>
+
+#define XML_NS 1
+#define XML_DTD 1
+#define XML_CONTEXT_BYTES 1024
+
+/* we will assume all Windows platforms are little endian */
+#define BYTEORDER 1234
+
+#endif /* ndef WINCONFIG_H */
diff --git a/gpr/source/lib/expat_lib/xmlparse.c b/gpr/source/lib/expat_lib/xmlparse.c
new file mode 120000
index 0000000..0c018b0
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmlparse.c
@@ -0,0 +1 @@
+../../../../.git/annex/objects/4Z/7Q/SHA256E-s197456--49037b9f6b0e160aa4b2a73bfa43f4b2ba3aec69617db904fe3b5e34b7aa644c.c/SHA256E-s197456--49037b9f6b0e160aa4b2a73bfa43f4b2ba3aec69617db904fe3b5e34b7aa644c.c \ No newline at end of file
diff --git a/gpr/source/lib/expat_lib/xmlrole.c b/gpr/source/lib/expat_lib/xmlrole.c
new file mode 100644
index 0000000..44772e2
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmlrole.c
@@ -0,0 +1,1336 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#else
+#ifdef HAVE_EXPAT_CONFIG_H
+#include <expat_config.h>
+#endif
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmlrole.h"
+#include "ascii.h"
+
+/* Doesn't check:
+
+ that ,| are not mixed in a model group
+ content of literals
+
+*/
+
+static const char KW_ANY[] = {
+ ASCII_A, ASCII_N, ASCII_Y, '\0' };
+static const char KW_ATTLIST[] = {
+ ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
+static const char KW_CDATA[] = {
+ ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_DOCTYPE[] = {
+ ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
+static const char KW_ELEMENT[] = {
+ ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
+static const char KW_EMPTY[] = {
+ ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
+static const char KW_ENTITIES[] = {
+ ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S,
+ '\0' };
+static const char KW_ENTITY[] = {
+ ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+static const char KW_FIXED[] = {
+ ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
+static const char KW_ID[] = {
+ ASCII_I, ASCII_D, '\0' };
+static const char KW_IDREF[] = {
+ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+static const char KW_IDREFS[] = {
+ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+#ifdef XML_DTD
+static const char KW_IGNORE[] = {
+ ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
+#endif
+static const char KW_IMPLIED[] = {
+ ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
+#ifdef XML_DTD
+static const char KW_INCLUDE[] = {
+ ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
+#endif
+static const char KW_NDATA[] = {
+ ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_NMTOKEN[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+static const char KW_NMTOKENS[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S,
+ '\0' };
+static const char KW_NOTATION[] =
+ { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N,
+ '\0' };
+static const char KW_PCDATA[] = {
+ ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_PUBLIC[] = {
+ ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
+static const char KW_REQUIRED[] = {
+ ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D,
+ '\0' };
+static const char KW_SYSTEM[] = {
+ ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
+
+#ifndef MIN_BYTES_PER_CHAR
+#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
+#endif
+
+#ifdef XML_DTD
+#define setTopLevel(state) \
+ ((state)->handler = ((state)->documentEntity \
+ ? internalSubset \
+ : externalSubset1))
+#else /* not XML_DTD */
+#define setTopLevel(state) ((state)->handler = internalSubset)
+#endif /* not XML_DTD */
+
+typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+
+static PROLOG_HANDLER
+ prolog0, prolog1, prolog2,
+ doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
+ internalSubset,
+ entity0, entity1, entity2, entity3, entity4, entity5, entity6,
+ entity7, entity8, entity9, entity10,
+ notation0, notation1, notation2, notation3, notation4,
+ attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
+ attlist7, attlist8, attlist9,
+ element0, element1, element2, element3, element4, element5, element6,
+ element7,
+#ifdef XML_DTD
+ externalSubset0, externalSubset1,
+ condSect0, condSect1, condSect2,
+#endif /* XML_DTD */
+ declClose,
+ error;
+
+static int FASTCALL common(PROLOG_STATE *state, int tok);
+
+static int PTRCALL
+prolog0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ state->handler = prolog1;
+ return XML_ROLE_NONE;
+ case XML_TOK_XML_DECL:
+ state->handler = prolog1;
+ return XML_ROLE_XML_DECL;
+ case XML_TOK_PI:
+ state->handler = prolog1;
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ state->handler = prolog1;
+ return XML_ROLE_COMMENT;
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_DOCTYPE))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+prolog1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_DOCTYPE))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+prolog2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = doctype1;
+ return XML_ROLE_DOCTYPE_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = doctype2;
+ return XML_ROLE_DOCTYPE_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype4;
+ return XML_ROLE_DOCTYPE_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+internalSubset(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ENTITY)) {
+ state->handler = entity0;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ATTLIST)) {
+ state->handler = attlist0;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ELEMENT)) {
+ state->handler = element0;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_NOTATION)) {
+ state->handler = notation0;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ break;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_PARAM_ENTITY_REF:
+ return XML_ROLE_PARAM_ENTITY_REF;
+ case XML_TOK_CLOSE_BRACKET:
+ state->handler = doctype5;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_NONE:
+ return XML_ROLE_NONE;
+ }
+ return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+externalSubset0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ state->handler = externalSubset1;
+ if (tok == XML_TOK_XML_DECL)
+ return XML_ROLE_TEXT_DECL;
+ return externalSubset1(state, tok, ptr, end, enc);
+}
+
+static int PTRCALL
+externalSubset1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_COND_SECT_OPEN:
+ state->handler = condSect0;
+ return XML_ROLE_NONE;
+ case XML_TOK_COND_SECT_CLOSE:
+ if (state->includeLevel == 0)
+ break;
+ state->includeLevel -= 1;
+ return XML_ROLE_NONE;
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_BRACKET:
+ break;
+ case XML_TOK_NONE:
+ if (state->includeLevel)
+ break;
+ return XML_ROLE_NONE;
+ default:
+ return internalSubset(state, tok, ptr, end, enc);
+ }
+ return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+entity0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_PERCENT:
+ state->handler = entity1;
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity2;
+ return XML_ROLE_GENERAL_ENTITY_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity7;
+ return XML_ROLE_PARAM_ENTITY_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = entity3;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity5;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ENTITY_COMPLETE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) {
+ state->handler = entity6;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_NOTATION_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = entity8;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity9(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity10;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity10(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ENTITY_COMPLETE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_NAME:
+ state->handler = notation1;
+ return XML_ROLE_NOTATION_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = notation3;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = notation2;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = notation4;
+ return XML_ROLE_NOTATION_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_NOTATION_NONE;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_NOTATION_NONE;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_NOTATION_NO_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist1;
+ return XML_ROLE_ATTLIST_ELEMENT_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist2;
+ return XML_ROLE_ATTRIBUTE_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ {
+ static const char * const types[] = {
+ KW_CDATA,
+ KW_ID,
+ KW_IDREF,
+ KW_IDREFS,
+ KW_ENTITY,
+ KW_ENTITIES,
+ KW_NMTOKEN,
+ KW_NMTOKENS,
+ };
+ int i;
+ for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
+ if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
+ state->handler = attlist8;
+ return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
+ state->handler = attlist5;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist3;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NMTOKEN:
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist4;
+ return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist3;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist6;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ state->handler = attlist7;
+ return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist6;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+/* default value */
+static int PTRCALL
+attlist8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_IMPLIED)) {
+ state->handler = attlist1;
+ return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_REQUIRED)) {
+ state->handler = attlist1;
+ return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_FIXED)) {
+ state->handler = attlist9;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist9(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element1;
+ return XML_ROLE_ELEMENT_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_CONTENT_EMPTY;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_CONTENT_ANY;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = element2;
+ state->level = 1;
+ return XML_ROLE_GROUP_OPEN;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_PCDATA)) {
+ state->handler = element3;
+ return XML_ROLE_CONTENT_PCDATA;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->level = 2;
+ state->handler = element6;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element5;
+ return XML_ROLE_CONTENT_ELEMENT;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->level += 1;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_CLOSE_PAREN_QUESTION:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_OPT;
+ case XML_TOK_CLOSE_PAREN_PLUS:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_PLUS;
+ case XML_TOK_COMMA:
+ state->handler = element6;
+ return XML_ROLE_GROUP_SEQUENCE;
+ case XML_TOK_OR:
+ state->handler = element6;
+ return XML_ROLE_GROUP_CHOICE;
+ }
+ return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+condSect0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) {
+ state->handler = condSect1;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) {
+ state->handler = condSect2;
+ return XML_ROLE_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+condSect1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = externalSubset1;
+ state->includeLevel += 1;
+ return XML_ROLE_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+condSect2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = externalSubset1;
+ return XML_ROLE_IGNORE_SECT;
+ }
+ return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+declClose(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return state->role_none;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return state->role_none;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+error(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ return XML_ROLE_NONE;
+}
+
+static int FASTCALL
+common(PROLOG_STATE *state, int tok)
+{
+#ifdef XML_DTD
+ if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
+ return XML_ROLE_INNER_PARAM_ENTITY_REF;
+#endif
+ state->handler = error;
+ return XML_ROLE_ERROR;
+}
+
+void
+XmlPrologStateInit(PROLOG_STATE *state)
+{
+ state->handler = prolog0;
+#ifdef XML_DTD
+ state->documentEntity = 1;
+ state->includeLevel = 0;
+ state->inEntityValue = 0;
+#endif /* XML_DTD */
+}
+
+#ifdef XML_DTD
+
+void
+XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
+{
+ state->handler = externalSubset0;
+ state->documentEntity = 0;
+ state->includeLevel = 0;
+}
+
+#endif /* XML_DTD */
diff --git a/gpr/source/lib/expat_lib/xmlrole.h b/gpr/source/lib/expat_lib/xmlrole.h
new file mode 100644
index 0000000..4dd9f06
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmlrole.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef XmlRole_INCLUDED
+#define XmlRole_INCLUDED 1
+
+#ifdef __VMS
+/* 0 1 2 3 0 1 2 3
+ 1234567890123456789012345678901 1234567890123456789012345678901 */
+#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
+#endif
+
+#include "xmltok.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ XML_ROLE_ERROR = -1,
+ XML_ROLE_NONE = 0,
+ XML_ROLE_XML_DECL,
+ XML_ROLE_INSTANCE_START,
+ XML_ROLE_DOCTYPE_NONE,
+ XML_ROLE_DOCTYPE_NAME,
+ XML_ROLE_DOCTYPE_SYSTEM_ID,
+ XML_ROLE_DOCTYPE_PUBLIC_ID,
+ XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
+ XML_ROLE_DOCTYPE_CLOSE,
+ XML_ROLE_GENERAL_ENTITY_NAME,
+ XML_ROLE_PARAM_ENTITY_NAME,
+ XML_ROLE_ENTITY_NONE,
+ XML_ROLE_ENTITY_VALUE,
+ XML_ROLE_ENTITY_SYSTEM_ID,
+ XML_ROLE_ENTITY_PUBLIC_ID,
+ XML_ROLE_ENTITY_COMPLETE,
+ XML_ROLE_ENTITY_NOTATION_NAME,
+ XML_ROLE_NOTATION_NONE,
+ XML_ROLE_NOTATION_NAME,
+ XML_ROLE_NOTATION_SYSTEM_ID,
+ XML_ROLE_NOTATION_NO_SYSTEM_ID,
+ XML_ROLE_NOTATION_PUBLIC_ID,
+ XML_ROLE_ATTRIBUTE_NAME,
+ XML_ROLE_ATTRIBUTE_TYPE_CDATA,
+ XML_ROLE_ATTRIBUTE_TYPE_ID,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREF,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
+ XML_ROLE_ATTRIBUTE_ENUM_VALUE,
+ XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
+ XML_ROLE_ATTLIST_NONE,
+ XML_ROLE_ATTLIST_ELEMENT_NAME,
+ XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
+ XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
+ XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
+ XML_ROLE_FIXED_ATTRIBUTE_VALUE,
+ XML_ROLE_ELEMENT_NONE,
+ XML_ROLE_ELEMENT_NAME,
+ XML_ROLE_CONTENT_ANY,
+ XML_ROLE_CONTENT_EMPTY,
+ XML_ROLE_CONTENT_PCDATA,
+ XML_ROLE_GROUP_OPEN,
+ XML_ROLE_GROUP_CLOSE,
+ XML_ROLE_GROUP_CLOSE_REP,
+ XML_ROLE_GROUP_CLOSE_OPT,
+ XML_ROLE_GROUP_CLOSE_PLUS,
+ XML_ROLE_GROUP_CHOICE,
+ XML_ROLE_GROUP_SEQUENCE,
+ XML_ROLE_CONTENT_ELEMENT,
+ XML_ROLE_CONTENT_ELEMENT_REP,
+ XML_ROLE_CONTENT_ELEMENT_OPT,
+ XML_ROLE_CONTENT_ELEMENT_PLUS,
+ XML_ROLE_PI,
+ XML_ROLE_COMMENT,
+#ifdef XML_DTD
+ XML_ROLE_TEXT_DECL,
+ XML_ROLE_IGNORE_SECT,
+ XML_ROLE_INNER_PARAM_ENTITY_REF,
+#endif /* XML_DTD */
+ XML_ROLE_PARAM_ENTITY_REF
+};
+
+typedef struct prolog_state {
+ int (PTRCALL *handler) (struct prolog_state *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+ unsigned level;
+ int role_none;
+#ifdef XML_DTD
+ unsigned includeLevel;
+ int documentEntity;
+ int inEntityValue;
+#endif /* XML_DTD */
+} PROLOG_STATE;
+
+void XmlPrologStateInit(PROLOG_STATE *);
+#ifdef XML_DTD
+void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
+#endif /* XML_DTD */
+
+#define XmlTokenRole(state, tok, ptr, end, enc) \
+ (((state)->handler)(state, tok, ptr, end, enc))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlRole_INCLUDED */
diff --git a/gpr/source/lib/expat_lib/xmltok.c b/gpr/source/lib/expat_lib/xmltok.c
new file mode 100644
index 0000000..c2e5e8c
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmltok.c
@@ -0,0 +1,1664 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#else
+#ifdef HAVE_EXPAT_CONFIG_H
+#include <expat_config.h>
+#endif
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmltok.h"
+#include "nametab.h"
+
+#ifdef XML_DTD
+#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
+#else
+#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
+#endif
+
+#define VTABLE1 \
+ { PREFIX(prologTok), PREFIX(contentTok), \
+ PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
+ { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
+ PREFIX(sameName), \
+ PREFIX(nameMatchesAscii), \
+ PREFIX(nameLength), \
+ PREFIX(skipS), \
+ PREFIX(getAtts), \
+ PREFIX(charRefNumber), \
+ PREFIX(predefinedEntityName), \
+ PREFIX(updatePosition), \
+ PREFIX(isPublicId)
+
+#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
+
+#define UCS2_GET_NAMING(pages, hi, lo) \
+ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
+
+/* A 2 byte UTF-8 representation splits the characters 11 bits between
+ the bottom 5 and 6 bits of the bytes. We need 8 bits to index into
+ pages, 3 bits to add to that index and 5 bits to generate the mask.
+*/
+#define UTF8_GET_NAMING2(pages, byte) \
+ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
+ + ((((byte)[0]) & 3) << 1) \
+ + ((((byte)[1]) >> 5) & 1)] \
+ & (1 << (((byte)[1]) & 0x1F)))
+
+/* A 3 byte UTF-8 representation splits the characters 16 bits between
+ the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index
+ into pages, 3 bits to add to that index and 5 bits to generate the
+ mask.
+*/
+#define UTF8_GET_NAMING3(pages, byte) \
+ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
+ + ((((byte)[1]) >> 2) & 0xF)] \
+ << 3) \
+ + ((((byte)[1]) & 3) << 1) \
+ + ((((byte)[2]) >> 5) & 1)] \
+ & (1 << (((byte)[2]) & 0x1F)))
+
+#define UTF8_GET_NAMING(pages, p, n) \
+ ((n) == 2 \
+ ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
+ : ((n) == 3 \
+ ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
+ : 0))
+
+/* Detection of invalid UTF-8 sequences is based on Table 3.1B
+ of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
+ with the additional restriction of not allowing the Unicode
+ code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE).
+ Implementation details:
+ (A & 0x80) == 0 means A < 0x80
+ and
+ (A & 0xC0) == 0xC0 means A > 0xBF
+*/
+
+#define UTF8_INVALID2(p) \
+ ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0)
+
+#define UTF8_INVALID3(p) \
+ (((p)[2] & 0x80) == 0 \
+ || \
+ ((*p) == 0xEF && (p)[1] == 0xBF \
+ ? \
+ (p)[2] > 0xBD \
+ : \
+ ((p)[2] & 0xC0) == 0xC0) \
+ || \
+ ((*p) == 0xE0 \
+ ? \
+ (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
+ : \
+ ((p)[1] & 0x80) == 0 \
+ || \
+ ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
+
+#define UTF8_INVALID4(p) \
+ (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \
+ || \
+ ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \
+ || \
+ ((*p) == 0xF0 \
+ ? \
+ (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
+ : \
+ ((p)[1] & 0x80) == 0 \
+ || \
+ ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
+
+static int PTRFASTCALL
+isNever(const ENCODING *enc, const char *p)
+{
+ return 0;
+}
+
+static int PTRFASTCALL
+utf8_isName2(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isName3(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
+}
+
+#define utf8_isName4 isNever
+
+static int PTRFASTCALL
+utf8_isNmstrt2(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isNmstrt3(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
+}
+
+#define utf8_isNmstrt4 isNever
+
+static int PTRFASTCALL
+utf8_isInvalid2(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID2((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid3(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID3((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid4(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID4((const unsigned char *)p);
+}
+
+struct normal_encoding {
+ ENCODING enc;
+ unsigned char type[256];
+#ifdef XML_MIN_SIZE
+ int (PTRFASTCALL *byteType)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
+ int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
+ int (PTRCALL *charMatches)(const ENCODING *, const char *, int);
+#endif /* XML_MIN_SIZE */
+ int (PTRFASTCALL *isName2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isName3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isName4)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
+};
+
+#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc))
+
+#ifdef XML_MIN_SIZE
+
+#define STANDARD_VTABLE(E) \
+ E ## byteType, \
+ E ## isNameMin, \
+ E ## isNmstrtMin, \
+ E ## byteToAscii, \
+ E ## charMatches,
+
+#else
+
+#define STANDARD_VTABLE(E) /* as nothing */
+
+#endif
+
+#define NORMAL_VTABLE(E) \
+ E ## isName2, \
+ E ## isName3, \
+ E ## isName4, \
+ E ## isNmstrt2, \
+ E ## isNmstrt3, \
+ E ## isNmstrt4, \
+ E ## isInvalid2, \
+ E ## isInvalid3, \
+ E ## isInvalid4
+
+#define EMPTY_VTABLE \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL
+
+static int FASTCALL checkCharRefNumber(int);
+
+#include "xmltok_impl.h"
+#include "ascii.h"
+
+#ifdef XML_MIN_SIZE
+#define sb_isNameMin isNever
+#define sb_isNmstrtMin isNever
+#endif
+
+#ifdef XML_MIN_SIZE
+#define MINBPC(enc) ((enc)->minBytesPerChar)
+#else
+/* minimum bytes per character */
+#define MINBPC(enc) 1
+#endif
+
+#define SB_BYTE_TYPE(enc, p) \
+ (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
+
+#ifdef XML_MIN_SIZE
+static int PTRFASTCALL
+sb_byteType(const ENCODING *enc, const char *p)
+{
+ return SB_BYTE_TYPE(enc, p);
+}
+#define BYTE_TYPE(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
+#else
+#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define BYTE_TO_ASCII(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
+static int PTRFASTCALL
+sb_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return *p;
+}
+#else
+#define BYTE_TO_ASCII(enc, p) (*(p))
+#endif
+
+#define IS_NAME_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p))
+#define IS_NMSTRT_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p))
+#define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p))
+
+#ifdef XML_MIN_SIZE
+#define IS_NAME_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
+#else
+#define IS_NAME_CHAR_MINBPC(enc, p) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define CHAR_MATCHES(enc, p, c) \
+ (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
+static int PTRCALL
+sb_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return *p == c;
+}
+#else
+/* c is an ASCII character */
+#define CHAR_MATCHES(enc, p, c) (*(p) == c)
+#endif
+
+#define PREFIX(ident) normal_ ## ident
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
+ UTF8_cval1 = 0x00,
+ UTF8_cval2 = 0xc0,
+ UTF8_cval3 = 0xe0,
+ UTF8_cval4 = 0xf0
+};
+
+static void PTRCALL
+utf8_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ char *to;
+ const char *from;
+ if (fromLim - *fromP > toLim - *toP) {
+ /* Avoid copying partial characters. */
+ for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
+ if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
+ break;
+ }
+ for (to = *toP, from = *fromP; from != fromLim; from++, to++)
+ *to = *from;
+ *fromP = from;
+ *toP = to;
+}
+
+static void PTRCALL
+utf8_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ unsigned short *to = *toP;
+ const char *from = *fromP;
+ while (from != fromLim && to != toLim) {
+ switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
+ case BT_LEAD2:
+ *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
+ from += 2;
+ break;
+ case BT_LEAD3:
+ *to++ = (unsigned short)(((from[0] & 0xf) << 12)
+ | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
+ from += 3;
+ break;
+ case BT_LEAD4:
+ {
+ unsigned long n;
+ if (to + 1 == toLim)
+ goto after;
+ n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
+ | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
+ n -= 0x10000;
+ to[0] = (unsigned short)((n >> 10) | 0xD800);
+ to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
+ to += 2;
+ from += 4;
+ }
+ break;
+ default:
+ *to++ = *from++;
+ break;
+ }
+ }
+after:
+ *fromP = from;
+ *toP = to;
+}
+
+#ifdef XML_NS
+static const struct normal_encoding utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+#endif
+
+static const struct normal_encoding utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "iasciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#endif
+
+static const struct normal_encoding internal_utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+static void PTRCALL
+latin1_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ for (;;) {
+ unsigned char c;
+ if (*fromP == fromLim)
+ break;
+ c = (unsigned char)**fromP;
+ if (c & 0x80) {
+ if (toLim - *toP < 2)
+ break;
+ *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
+ *(*toP)++ = (char)((c & 0x3f) | 0x80);
+ (*fromP)++;
+ }
+ else {
+ if (*toP == toLim)
+ break;
+ *(*toP)++ = *(*fromP)++;
+ }
+ }
+}
+
+static void PTRCALL
+latin1_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim)
+ *(*toP)++ = (unsigned char)*(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding latin1_encoding_ns = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_) EMPTY_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding latin1_encoding = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_) EMPTY_VTABLE
+};
+
+static void PTRCALL
+ascii_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim)
+ *(*toP)++ = *(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding ascii_encoding_ns = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_) EMPTY_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding ascii_encoding = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_) EMPTY_VTABLE
+};
+
+static int PTRFASTCALL
+unicode_byte_type(char hi, char lo)
+{
+ switch ((unsigned char)hi) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ return BT_LEAD4;
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return BT_TRAIL;
+ case 0xFF:
+ switch ((unsigned char)lo) {
+ case 0xFF:
+ case 0xFE:
+ return BT_NONXML;
+ }
+ break;
+ }
+ return BT_NONASCII;
+}
+
+#define DEFINE_UTF16_TO_UTF8(E) \
+static void PTRCALL \
+E ## toUtf8(const ENCODING *enc, \
+ const char **fromP, const char *fromLim, \
+ char **toP, const char *toLim) \
+{ \
+ const char *from; \
+ for (from = *fromP; from != fromLim; from += 2) { \
+ int plane; \
+ unsigned char lo2; \
+ unsigned char lo = GET_LO(from); \
+ unsigned char hi = GET_HI(from); \
+ switch (hi) { \
+ case 0: \
+ if (lo < 0x80) { \
+ if (*toP == toLim) { \
+ *fromP = from; \
+ return; \
+ } \
+ *(*toP)++ = lo; \
+ break; \
+ } \
+ __attribute((fallthrough)); \
+ /* fall through */ \
+ case 0x1: case 0x2: case 0x3: \
+ case 0x4: case 0x5: case 0x6: case 0x7: \
+ if (toLim - *toP < 2) { \
+ *fromP = from; \
+ return; \
+ } \
+ *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ default: \
+ if (toLim - *toP < 3) { \
+ *fromP = from; \
+ return; \
+ } \
+ /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
+ *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
+ *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
+ if (toLim - *toP < 4) { \
+ *fromP = from; \
+ return; \
+ } \
+ plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
+ *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
+ *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
+ from += 2; \
+ lo2 = GET_LO(from); \
+ *(*toP)++ = (((lo & 0x3) << 4) \
+ | ((GET_HI(from) & 0x3) << 2) \
+ | (lo2 >> 6) \
+ | 0x80); \
+ *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
+ break; \
+ } \
+ } \
+ *fromP = from; \
+}
+
+#define DEFINE_UTF16_TO_UTF16(E) \
+static void PTRCALL \
+E ## toUtf16(const ENCODING *enc, \
+ const char **fromP, const char *fromLim, \
+ unsigned short **toP, const unsigned short *toLim) \
+{ \
+ /* Avoid copying first half only of surrogate */ \
+ if (fromLim - *fromP > ((toLim - *toP) << 1) \
+ && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
+ fromLim -= 2; \
+ for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
+ *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+}
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[0])
+#define GET_HI(ptr) ((unsigned char)(ptr)[1])
+
+DEFINE_UTF16_TO_UTF8(little2_)
+DEFINE_UTF16_TO_UTF16(little2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[1])
+#define GET_HI(ptr) ((unsigned char)(ptr)[0])
+
+DEFINE_UTF16_TO_UTF8(big2_)
+DEFINE_UTF16_TO_UTF16(big2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define LITTLE2_BYTE_TYPE(enc, p) \
+ ((p)[1] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
+ : unicode_byte_type((p)[1], (p)[0]))
+#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
+#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
+#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+little2_byteType(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+little2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+little2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return LITTLE2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+little2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+little2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) little2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding little2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) EMPTY_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding little2_encoding = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) EMPTY_VTABLE
+};
+
+#if BYTEORDER != 4321
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_little2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) EMPTY_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding internal_little2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) EMPTY_VTABLE
+};
+
+#endif
+
+
+#define BIG2_BYTE_TYPE(enc, p) \
+ ((p)[0] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
+ : unicode_byte_type((p)[0], (p)[1]))
+#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
+#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
+#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+big2_byteType(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+big2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+big2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return BIG2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+big2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+big2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) big2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding big2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) EMPTY_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding big2_encoding = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) EMPTY_VTABLE
+};
+
+#if BYTEORDER != 1234
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_big2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) EMPTY_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding internal_big2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) EMPTY_VTABLE
+};
+
+#endif
+
+#undef PREFIX
+
+static int FASTCALL
+streqci(const char *s1, const char *s2)
+{
+ for (;;) {
+ char c1 = *s1++;
+ char c2 = *s2++;
+ if (ASCII_a <= c1 && c1 <= ASCII_z)
+ c1 += ASCII_A - ASCII_a;
+ if (ASCII_a <= c2 && c2 <= ASCII_z)
+ c2 += ASCII_A - ASCII_a;
+ if (c1 != c2)
+ return 0;
+ if (!c1)
+ break;
+ }
+ return 1;
+}
+
+static void PTRCALL
+initUpdatePosition(const ENCODING *enc, const char *ptr,
+ const char *end, POSITION *pos)
+{
+ normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
+}
+
+static int
+toAscii(const ENCODING *enc, const char *ptr, const char *end)
+{
+ char buf[1];
+ char *p = buf;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
+ if (p == buf)
+ return -1;
+ else
+ return buf[0];
+}
+
+static int FASTCALL
+isSpace(int c)
+{
+ switch (c) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ case 0x9:
+ return 1;
+ }
+ return 0;
+}
+
+/* Return 1 if there's just optional white space or there's an S
+ followed by name=val.
+*/
+static int
+parsePseudoAttribute(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **namePtr,
+ const char **nameEndPtr,
+ const char **valPtr,
+ const char **nextTokPtr)
+{
+ int c;
+ char open;
+ if (ptr == end) {
+ *namePtr = NULL;
+ return 1;
+ }
+ if (!isSpace(toAscii(enc, ptr, end))) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(toAscii(enc, ptr, end)));
+ if (ptr == end) {
+ *namePtr = NULL;
+ return 1;
+ }
+ *namePtr = ptr;
+ for (;;) {
+ c = toAscii(enc, ptr, end);
+ if (c == -1) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ if (c == ASCII_EQUALS) {
+ *nameEndPtr = ptr;
+ break;
+ }
+ if (isSpace(c)) {
+ *nameEndPtr = ptr;
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(c = toAscii(enc, ptr, end)));
+ if (c != ASCII_EQUALS) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ ptr += enc->minBytesPerChar;
+ }
+ if (ptr == *namePtr) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ while (isSpace(c)) {
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ }
+ if (c != ASCII_QUOT && c != ASCII_APOS) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ open = (char)c;
+ ptr += enc->minBytesPerChar;
+ *valPtr = ptr;
+ for (;; ptr += enc->minBytesPerChar) {
+ c = toAscii(enc, ptr, end);
+ if (c == open)
+ break;
+ if (!(ASCII_a <= c && c <= ASCII_z)
+ && !(ASCII_A <= c && c <= ASCII_Z)
+ && !(ASCII_0 <= c && c <= ASCII_9)
+ && c != ASCII_PERIOD
+ && c != ASCII_MINUS
+ && c != ASCII_UNDERSCORE) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ }
+ *nextTokPtr = ptr + enc->minBytesPerChar;
+ return 1;
+}
+
+static const char KW_version[] = {
+ ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
+};
+
+static const char KW_encoding[] = {
+ ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
+};
+
+static const char KW_standalone[] = {
+ ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o,
+ ASCII_n, ASCII_e, '\0'
+};
+
+static const char KW_yes[] = {
+ ASCII_y, ASCII_e, ASCII_s, '\0'
+};
+
+static const char KW_no[] = {
+ ASCII_n, ASCII_o, '\0'
+};
+
+static int
+doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
+ const char *,
+ const char *),
+ int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ const char *val = NULL;
+ const char *name = NULL;
+ const char *nameEnd = NULL;
+ ptr += 5 * enc->minBytesPerChar;
+ end -= 2 * enc->minBytesPerChar;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
+ || !name) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
+ if (!isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ }
+ else {
+ if (versionPtr)
+ *versionPtr = val;
+ if (versionEndPtr)
+ *versionEndPtr = ptr;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name) {
+ if (isGeneralTextEntity) {
+ /* a TextDecl must have an EncodingDecl */
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
+ int c = toAscii(enc, val, end);
+ if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
+ *badPtr = val;
+ return 0;
+ }
+ if (encodingName)
+ *encodingName = val;
+ if (encoding)
+ *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name)
+ return 1;
+ }
+ if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
+ || isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
+ if (standalone)
+ *standalone = 1;
+ }
+ else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
+ if (standalone)
+ *standalone = 0;
+ }
+ else {
+ *badPtr = val;
+ return 0;
+ }
+ while (isSpace(toAscii(enc, ptr, end)))
+ ptr += enc->minBytesPerChar;
+ if (ptr != end) {
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+}
+
+static int FASTCALL
+checkCharRefNumber(int result)
+{
+ switch (result >> 8) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return -1;
+ case 0:
+ if (latin1_encoding.type[result] == BT_NONXML)
+ return -1;
+ break;
+ case 0xFF:
+ if (result == 0xFFFE || result == 0xFFFF)
+ return -1;
+ break;
+ }
+ return result;
+}
+
+int FASTCALL
+XmlUtf8Encode(int c, char *buf)
+{
+ enum {
+ /* minN is minimum legal resulting value for N byte sequence */
+ min2 = 0x80,
+ min3 = 0x800,
+ min4 = 0x10000
+ };
+
+ if (c < 0)
+ return 0;
+ if (c < min2) {
+ buf[0] = (char)(c | UTF8_cval1);
+ return 1;
+ }
+ if (c < min3) {
+ buf[0] = (char)((c >> 6) | UTF8_cval2);
+ buf[1] = (char)((c & 0x3f) | 0x80);
+ return 2;
+ }
+ if (c < min4) {
+ buf[0] = (char)((c >> 12) | UTF8_cval3);
+ buf[1] = (char)(((c >> 6) & 0x3f) | 0x80);
+ buf[2] = (char)((c & 0x3f) | 0x80);
+ return 3;
+ }
+ if (c < 0x110000) {
+ buf[0] = (char)((c >> 18) | UTF8_cval4);
+ buf[1] = (char)(((c >> 12) & 0x3f) | 0x80);
+ buf[2] = (char)(((c >> 6) & 0x3f) | 0x80);
+ buf[3] = (char)((c & 0x3f) | 0x80);
+ return 4;
+ }
+ return 0;
+}
+
+int FASTCALL
+XmlUtf16Encode(int charNum, unsigned short *buf)
+{
+ if (charNum < 0)
+ return 0;
+ if (charNum < 0x10000) {
+ buf[0] = (unsigned short)charNum;
+ return 1;
+ }
+ if (charNum < 0x110000) {
+ charNum -= 0x10000;
+ buf[0] = (unsigned short)((charNum >> 10) + 0xD800);
+ buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00);
+ return 2;
+ }
+ return 0;
+}
+
+struct unknown_encoding {
+ struct normal_encoding normal;
+ CONVERTER convert;
+ void *userData;
+ unsigned short utf16[256];
+ char utf8[256][4];
+};
+
+#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc))
+
+int
+XmlSizeOfUnknownEncoding(void)
+{
+ return sizeof(struct unknown_encoding);
+}
+
+static int PTRFASTCALL
+unknown_isName(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isNmstrt(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isInvalid(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
+}
+
+static void PTRCALL
+unknown_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ char buf[XML_UTF8_ENCODE_MAX];
+ for (;;) {
+ const char *utf8;
+ int n;
+ if (*fromP == fromLim)
+ break;
+ utf8 = uenc->utf8[(unsigned char)**fromP];
+ n = *utf8++;
+ if (n == 0) {
+ int c = uenc->convert(uenc->userData, *fromP);
+ n = XmlUtf8Encode(c, buf);
+ if (n > toLim - *toP)
+ break;
+ utf8 = buf;
+ *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2));
+ }
+ else {
+ if (n > toLim - *toP)
+ break;
+ (*fromP)++;
+ }
+ do {
+ *(*toP)++ = *utf8++;
+ } while (--n != 0);
+ }
+}
+
+static void PTRCALL
+unknown_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ while (*fromP != fromLim && *toP != toLim) {
+ unsigned short c = uenc->utf16[(unsigned char)**fromP];
+ if (c == 0) {
+ c = (unsigned short)
+ uenc->convert(uenc->userData, *fromP);
+ *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2));
+ }
+ else
+ (*fromP)++;
+ *(*toP)++ = c;
+ }
+}
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData)
+{
+ int i;
+ struct unknown_encoding *e = (struct unknown_encoding *)mem;
+ for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
+ ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
+ for (i = 0; i < 128; i++)
+ if (latin1_encoding.type[i] != BT_OTHER
+ && latin1_encoding.type[i] != BT_NONXML
+ && table[i] != i)
+ return 0;
+ for (i = 0; i < 256; i++) {
+ int c = table[i];
+ if (c == -1) {
+ e->normal.type[i] = BT_MALFORM;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else if (c < 0) {
+ if (c < -4)
+ return 0;
+ e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2));
+ e->utf8[i][0] = 0;
+ e->utf16[i] = 0;
+ }
+ else if (c < 0x80) {
+ if (latin1_encoding.type[c] != BT_OTHER
+ && latin1_encoding.type[c] != BT_NONXML
+ && c != i)
+ return 0;
+ e->normal.type[i] = latin1_encoding.type[c];
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = (char)c;
+ e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c);
+ }
+ else if (checkCharRefNumber(c) < 0) {
+ e->normal.type[i] = BT_NONXML;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else {
+ if (c > 0xFFFF)
+ return 0;
+ if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NMSTRT;
+ else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NAME;
+ else
+ e->normal.type[i] = BT_OTHER;
+ e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
+ e->utf16[i] = (unsigned short)c;
+ }
+ }
+ e->userData = userData;
+ e->convert = convert;
+ if (convert) {
+ e->normal.isName2 = unknown_isName;
+ e->normal.isName3 = unknown_isName;
+ e->normal.isName4 = unknown_isName;
+ e->normal.isNmstrt2 = unknown_isNmstrt;
+ e->normal.isNmstrt3 = unknown_isNmstrt;
+ e->normal.isNmstrt4 = unknown_isNmstrt;
+ e->normal.isInvalid2 = unknown_isInvalid;
+ e->normal.isInvalid3 = unknown_isInvalid;
+ e->normal.isInvalid4 = unknown_isInvalid;
+ }
+ e->normal.enc.utf8Convert = unknown_toUtf8;
+ e->normal.enc.utf16Convert = unknown_toUtf16;
+ return &(e->normal.enc);
+}
+
+/* If this enumeration is changed, getEncodingIndex and encodings
+must also be changed. */
+enum {
+ UNKNOWN_ENC = -1,
+ ISO_8859_1_ENC = 0,
+ US_ASCII_ENC,
+ UTF_8_ENC,
+ UTF_16_ENC,
+ UTF_16BE_ENC,
+ UTF_16LE_ENC,
+ /* must match encodingNames up to here */
+ NO_ENC
+};
+
+static const char KW_ISO_8859_1[] = {
+ ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9,
+ ASCII_MINUS, ASCII_1, '\0'
+};
+static const char KW_US_ASCII[] = {
+ ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I,
+ '\0'
+};
+static const char KW_UTF_8[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
+};
+static const char KW_UTF_16[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
+};
+static const char KW_UTF_16BE[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E,
+ '\0'
+};
+static const char KW_UTF_16LE[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E,
+ '\0'
+};
+
+static int FASTCALL
+getEncodingIndex(const char *name)
+{
+ static const char * const encodingNames[] = {
+ KW_ISO_8859_1,
+ KW_US_ASCII,
+ KW_UTF_8,
+ KW_UTF_16,
+ KW_UTF_16BE,
+ KW_UTF_16LE,
+ };
+ int i;
+ if (name == NULL)
+ return NO_ENC;
+ for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
+ if (streqci(name, encodingNames[i]))
+ return i;
+ return UNKNOWN_ENC;
+}
+
+/* For binary compatibility, we store the index of the encoding
+ specified at initialization in the isUtf16 member.
+*/
+
+#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16)
+#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i)
+
+/* This is what detects the encoding. encodingTable maps from
+ encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of
+ the external (protocol) specified encoding; state is
+ XML_CONTENT_STATE if we're parsing an external text entity, and
+ XML_PROLOG_STATE otherwise.
+*/
+
+
+static int
+initScan(const ENCODING * const *encodingTable,
+ const INIT_ENCODING *enc,
+ int state,
+ const char *ptr,
+ const char *end,
+ const char **nextTokPtr)
+{
+ const ENCODING **encPtr;
+
+ if (ptr == end)
+ return XML_TOK_NONE;
+ encPtr = enc->encPtr;
+ if (ptr + 1 == end) {
+ /* only a single byte available for auto-detection */
+#ifndef XML_DTD /* FIXME */
+ /* a well-formed document entity must have more than one byte */
+ if (state != XML_CONTENT_STATE)
+ return XML_TOK_PARTIAL;
+#endif
+ /* so we're parsing an external text entity... */
+ /* if UTF-16 was externally specified, then we need at least 2 bytes */
+ switch (INIT_ENC_INDEX(enc)) {
+ case UTF_16_ENC:
+ case UTF_16LE_ENC:
+ case UTF_16BE_ENC:
+ return XML_TOK_PARTIAL;
+ }
+ switch ((unsigned char)*ptr) {
+ case 0xFE:
+ case 0xFF:
+ case 0xEF: /* possibly first byte of UTF-8 BOM */
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ __attribute((fallthrough));
+ /* fall through */
+ case 0x00:
+ case 0x3C:
+ return XML_TOK_PARTIAL;
+ }
+ }
+ else {
+ switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
+ case 0xFEFF:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XML_TOK_BOM;
+ /* 00 3C is handled in the default case */
+ case 0x3C00:
+ if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
+ || INIT_ENC_INDEX(enc) == UTF_16_ENC)
+ && state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ case 0xFFFE:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XML_TOK_BOM;
+ case 0xEFBB:
+ /* Maybe a UTF-8 BOM (EF BB BF) */
+ /* If there's an explicitly specified (external) encoding
+ of ISO-8859-1 or some flavour of UTF-16
+ and this is an external text entity,
+ don't look for the BOM,
+ because it might be a legal data.
+ */
+ if (state == XML_CONTENT_STATE) {
+ int e = INIT_ENC_INDEX(enc);
+ if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC
+ || e == UTF_16LE_ENC || e == UTF_16_ENC)
+ break;
+ }
+ if (ptr + 2 == end)
+ return XML_TOK_PARTIAL;
+ if ((unsigned char)ptr[2] == 0xBF) {
+ *nextTokPtr = ptr + 3;
+ *encPtr = encodingTable[UTF_8_ENC];
+ return XML_TOK_BOM;
+ }
+ break;
+ default:
+ if (ptr[0] == '\0') {
+ /* 0 isn't a legal data character. Furthermore a document
+ entity can only start with ASCII characters. So the only
+ way this can fail to be big-endian UTF-16 if it it's an
+ external parsed general entity that's labelled as
+ UTF-16LE.
+ */
+ if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
+ break;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ else if (ptr[1] == '\0') {
+ /* We could recover here in the case:
+ - parsing an external entity
+ - second byte is 0
+ - no externally specified encoding
+ - no encoding declaration
+ by assuming UTF-16LE. But we don't, because this would mean when
+ presented just with a single byte, we couldn't reliably determine
+ whether we needed further bytes.
+ */
+ if (state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ break;
+ }
+ }
+ *encPtr = encodingTable[INIT_ENC_INDEX(enc)];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+}
+
+
+#define NS(x) x
+#define ns(x) x
+#define XML_TOK_NS_C
+#include "xmltok_ns.c"
+#undef XML_TOK_NS_C
+#undef NS
+#undef ns
+
+#ifdef XML_NS
+
+#define NS(x) x ## NS
+#define ns(x) x ## _ns
+
+#define XML_TOK_NS_C
+#include "xmltok_ns.c"
+#undef XML_TOK_NS_C
+
+#undef NS
+#undef ns
+
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData)
+{
+ ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
+ if (enc)
+ ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
+ return enc;
+}
+
+#endif /* XML_NS */
diff --git a/gpr/source/lib/expat_lib/xmltok.h b/gpr/source/lib/expat_lib/xmltok.h
new file mode 100644
index 0000000..ca867aa
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmltok.h
@@ -0,0 +1,316 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef XmlTok_INCLUDED
+#define XmlTok_INCLUDED 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following token may be returned by XmlContentTok */
+#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
+ start of illegal ]]> sequence */
+/* The following tokens may be returned by both XmlPrologTok and
+ XmlContentTok.
+*/
+#define XML_TOK_NONE -4 /* The string to be scanned is empty */
+#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
+ might be part of CRLF sequence */
+#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
+#define XML_TOK_PARTIAL -1 /* only part of a token */
+#define XML_TOK_INVALID 0
+
+/* The following tokens are returned by XmlContentTok; some are also
+ returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
+*/
+#define XML_TOK_START_TAG_WITH_ATTS 1
+#define XML_TOK_START_TAG_NO_ATTS 2
+#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
+#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
+#define XML_TOK_END_TAG 5
+#define XML_TOK_DATA_CHARS 6
+#define XML_TOK_DATA_NEWLINE 7
+#define XML_TOK_CDATA_SECT_OPEN 8
+#define XML_TOK_ENTITY_REF 9
+#define XML_TOK_CHAR_REF 10 /* numeric character reference */
+
+/* The following tokens may be returned by both XmlPrologTok and
+ XmlContentTok.
+*/
+#define XML_TOK_PI 11 /* processing instruction */
+#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
+#define XML_TOK_COMMENT 13
+#define XML_TOK_BOM 14 /* Byte order mark */
+
+/* The following tokens are returned only by XmlPrologTok */
+#define XML_TOK_PROLOG_S 15
+#define XML_TOK_DECL_OPEN 16 /* <!foo */
+#define XML_TOK_DECL_CLOSE 17 /* > */
+#define XML_TOK_NAME 18
+#define XML_TOK_NMTOKEN 19
+#define XML_TOK_POUND_NAME 20 /* #name */
+#define XML_TOK_OR 21 /* | */
+#define XML_TOK_PERCENT 22
+#define XML_TOK_OPEN_PAREN 23
+#define XML_TOK_CLOSE_PAREN 24
+#define XML_TOK_OPEN_BRACKET 25
+#define XML_TOK_CLOSE_BRACKET 26
+#define XML_TOK_LITERAL 27
+#define XML_TOK_PARAM_ENTITY_REF 28
+#define XML_TOK_INSTANCE_START 29
+
+/* The following occur only in element type declarations */
+#define XML_TOK_NAME_QUESTION 30 /* name? */
+#define XML_TOK_NAME_ASTERISK 31 /* name* */
+#define XML_TOK_NAME_PLUS 32 /* name+ */
+#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
+#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
+#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
+#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
+#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
+#define XML_TOK_COMMA 38
+
+/* The following token is returned only by XmlAttributeValueTok */
+#define XML_TOK_ATTRIBUTE_VALUE_S 39
+
+/* The following token is returned only by XmlCdataSectionTok */
+#define XML_TOK_CDATA_SECT_CLOSE 40
+
+/* With namespace processing this is returned by XmlPrologTok for a
+ name with a colon.
+*/
+#define XML_TOK_PREFIXED_NAME 41
+
+#ifdef XML_DTD
+#define XML_TOK_IGNORE_SECT 42
+#endif /* XML_DTD */
+
+#ifdef XML_DTD
+#define XML_N_STATES 4
+#else /* not XML_DTD */
+#define XML_N_STATES 3
+#endif /* not XML_DTD */
+
+#define XML_PROLOG_STATE 0
+#define XML_CONTENT_STATE 1
+#define XML_CDATA_SECTION_STATE 2
+#ifdef XML_DTD
+#define XML_IGNORE_SECTION_STATE 3
+#endif /* XML_DTD */
+
+#define XML_N_LITERAL_TYPES 2
+#define XML_ATTRIBUTE_VALUE_LITERAL 0
+#define XML_ENTITY_VALUE_LITERAL 1
+
+/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
+#define XML_UTF8_ENCODE_MAX 4
+/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
+#define XML_UTF16_ENCODE_MAX 2
+
+typedef struct position {
+ /* first line and first column are 0 not 1 */
+ XML_Size lineNumber;
+ XML_Size columnNumber;
+} POSITION;
+
+typedef struct {
+ const char *name;
+ const char *valuePtr;
+ const char *valueEnd;
+ char normalized;
+} ATTRIBUTE;
+
+struct encoding;
+typedef struct encoding ENCODING;
+
+typedef int (PTRCALL *SCANNER)(const ENCODING *,
+ const char *,
+ const char *,
+ const char **);
+
+struct encoding {
+ SCANNER scanners[XML_N_STATES];
+ SCANNER literalScanners[XML_N_LITERAL_TYPES];
+ int (PTRCALL *sameName)(const ENCODING *,
+ const char *,
+ const char *);
+ int (PTRCALL *nameMatchesAscii)(const ENCODING *,
+ const char *,
+ const char *,
+ const char *);
+ int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
+ const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
+ int (PTRCALL *getAtts)(const ENCODING *enc,
+ const char *ptr,
+ int attsMax,
+ ATTRIBUTE *atts);
+ int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
+ int (PTRCALL *predefinedEntityName)(const ENCODING *,
+ const char *,
+ const char *);
+ void (PTRCALL *updatePosition)(const ENCODING *,
+ const char *ptr,
+ const char *end,
+ POSITION *);
+ int (PTRCALL *isPublicId)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr);
+ void (PTRCALL *utf8Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ char **toP,
+ const char *toLim);
+ void (PTRCALL *utf16Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ unsigned short **toP,
+ const unsigned short *toLim);
+ int minBytesPerChar;
+ char isUtf8;
+ char isUtf16;
+};
+
+/* Scan the string starting at ptr until the end of the next complete
+ token, but do not scan past eptr. Return an integer giving the
+ type of token.
+
+ Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
+
+ Return XML_TOK_PARTIAL when the string does not contain a complete
+ token; nextTokPtr will not be set.
+
+ Return XML_TOK_INVALID when the string does not start a valid
+ token; nextTokPtr will be set to point to the character which made
+ the token invalid.
+
+ Otherwise the string starts with a valid token; nextTokPtr will be
+ set to point to the character following the end of that token.
+
+ Each data character counts as a single token, but adjacent data
+ characters may be returned together. Similarly for characters in
+ the prolog outside literals, comments and processing instructions.
+*/
+
+
+#define XmlTok(enc, state, ptr, end, nextTokPtr) \
+ (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
+
+#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
+
+#define XmlContentTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
+
+#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
+
+#ifdef XML_DTD
+
+#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
+
+#endif /* XML_DTD */
+
+/* This is used for performing a 2nd-level tokenization on the content
+ of a literal that has already been returned by XmlTok.
+*/
+#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
+ (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
+
+#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
+
+#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
+ (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
+
+#define XmlNameLength(enc, ptr) \
+ (((enc)->nameLength)(enc, ptr))
+
+#define XmlSkipS(enc, ptr) \
+ (((enc)->skipS)(enc, ptr))
+
+#define XmlGetAttributes(enc, ptr, attsMax, atts) \
+ (((enc)->getAtts)(enc, ptr, attsMax, atts))
+
+#define XmlCharRefNumber(enc, ptr) \
+ (((enc)->charRefNumber)(enc, ptr))
+
+#define XmlPredefinedEntityName(enc, ptr, end) \
+ (((enc)->predefinedEntityName)(enc, ptr, end))
+
+#define XmlUpdatePosition(enc, ptr, end, pos) \
+ (((enc)->updatePosition)(enc, ptr, end, pos))
+
+#define XmlIsPublicId(enc, ptr, end, badPtr) \
+ (((enc)->isPublicId)(enc, ptr, end, badPtr))
+
+#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
+
+#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
+
+typedef struct {
+ ENCODING initEnc;
+ const ENCODING **encPtr;
+} INIT_ENCODING;
+
+int XmlParseXmlDecl(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncoding(void);
+const ENCODING *XmlGetUtf16InternalEncoding(void);
+int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
+int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
+int XmlSizeOfUnknownEncoding(void);
+
+
+typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData);
+
+int XmlParseXmlDeclNS(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncodingNS(void);
+const ENCODING *XmlGetUtf16InternalEncodingNS(void);
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlTok_INCLUDED */
diff --git a/gpr/source/lib/expat_lib/xmltok_impl.c b/gpr/source/lib/expat_lib/xmltok_impl.c
new file mode 100644
index 0000000..41679ea
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmltok_impl.c
@@ -0,0 +1,1797 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* This file is included! */
+#ifdef XML_TOK_IMPL_C
+
+#ifndef IS_INVALID_CHAR
+#define IS_INVALID_CHAR(enc, ptr, n) (0)
+#endif
+
+#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define INVALID_CASES(ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
+ case BT_NONXML: \
+ case BT_MALFORM: \
+ case BT_TRAIL: \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID;
+
+#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NAME_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ __attribute((fallthrough)); \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ case BT_DIGIT: \
+ case BT_NAME: \
+ case BT_MINUS: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
+
+#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ __attribute((fallthrough)); \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
+
+#ifndef PREFIX
+#define PREFIX(ident) ident
+#endif
+
+/* ptr points to character following "<!-" */
+
+static int PTRCALL
+PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr != end) {
+ if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_MINUS:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMENT;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<!" */
+
+static int PTRCALL
+PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COND_SECT_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_PERCNT:
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_PARTIAL;
+ /* don't allow <!ENTITY% foo "whatever"> */
+ switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
+ case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ FALL_THROUGH;
+ /* fall through */
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DECL_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
+ const char *end, int *tokPtr)
+{
+ int upper = 0;
+ *tokPtr = XML_TOK_PI;
+ if (end - ptr != MINBPC(enc)*3)
+ return 1;
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_x:
+ break;
+ case ASCII_X:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_m:
+ break;
+ case ASCII_M:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_l:
+ break;
+ case ASCII_L:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ if (upper)
+ return 0;
+ *tokPtr = XML_TOK_XML_DECL;
+ return 1;
+}
+
+/* ptr points to character following "<?" */
+
+static int PTRCALL
+PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ int tok;
+ const char *target = ptr;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUEST:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+ case BT_QUEST:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ FALL_THROUGH;
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
+ ASCII_T, ASCII_A, ASCII_LSQB };
+ int i;
+ /* CDATA[ */
+ if (end - ptr < 6 * MINBPC(enc))
+ return XML_TOK_PARTIAL;
+ for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
+ if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CDATA_SECT_OPEN;
+}
+
+static int PTRCALL
+PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ break;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CDATA_SECT_CLOSE;
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ case BT_RSQB:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "</" */
+
+static int PTRCALL
+PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ break;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+#ifdef XML_NS
+ case BT_COLON:
+ /* no need to check qname syntax here,
+ since end-tag must match exactly */
+ ptr += MINBPC(enc);
+ break;
+#endif
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#X" */
+
+static int PTRCALL
+PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#" */
+
+static int PTRCALL
+PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr != end) {
+ if (CHAR_MATCHES(enc, ptr, ASCII_x))
+ return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&" */
+
+static int PTRCALL
+PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_NUM:
+ return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following first character of attribute name */
+
+static int PTRCALL
+PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon = 0;
+#endif
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ for (;;) {
+ int t;
+
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ t = BYTE_TYPE(enc, ptr);
+ if (t == BT_EQUALS)
+ break;
+ switch (t) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ FALL_THROUGH;
+ /* fall through */
+ case BT_EQUALS:
+ {
+ int open;
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ open = BYTE_TYPE(enc, ptr);
+ if (open == BT_QUOT || open == BT_APOS)
+ break;
+ switch (open) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ ptr += MINBPC(enc);
+ /* in attribute value */
+ for (;;) {
+ int t;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ t = BYTE_TYPE(enc, ptr);
+ if (t == open)
+ break;
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_AMP:
+ {
+ int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
+ if (tok <= 0) {
+ if (tok == XML_TOK_INVALID)
+ *nextTokPtr = ptr;
+ return tok;
+ }
+ break;
+ }
+ case BT_LT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ break;
+ case BT_SOL:
+ goto sol;
+ case BT_GT:
+ goto gt;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* ptr points to closing quote */
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ continue;
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_WITH_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+ }
+ break;
+ }
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<" */
+
+static int PTRCALL
+PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon;
+#endif
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_EXCL:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc),
+ end, nextTokPtr);
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_SOL:
+ return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ /* we have a start-tag */
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ {
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT:
+ goto gt;
+ case BT_SOL:
+ goto sol;
+ case BT_S: case BT_CR: case BT_LF:
+ ptr += MINBPC(enc);
+ continue;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
+ }
+ return XML_TOK_PARTIAL;
+ }
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_NO_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LT:
+ return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_AMP:
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ break;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_RSQB:
+ if (ptr + MINBPC(enc) != end) {
+ if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ if (ptr + 2*MINBPC(enc) != end) {
+ if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_INVALID;
+ }
+ }
+ FALL_THROUGH;
+ /* fall through */
+ case BT_AMP:
+ case BT_LT:
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "%" */
+
+static int PTRCALL
+PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_PERCENT;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_PARAM_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_POUND_NAME;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return -XML_TOK_POUND_NAME;
+}
+
+static int PTRCALL
+PREFIX(scanLit)(int open, const ENCODING *enc,
+ const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ while (ptr != end) {
+ int t = BYTE_TYPE(enc, ptr);
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUOT:
+ case BT_APOS:
+ ptr += MINBPC(enc);
+ if (t != open)
+ break;
+ if (ptr == end)
+ return -XML_TOK_LITERAL;
+ *nextTokPtr = ptr;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ case BT_GT: case BT_PERCNT: case BT_LSQB:
+ return XML_TOK_LITERAL;
+ default:
+ return XML_TOK_INVALID;
+ }
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ int tok;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_QUOT:
+ return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_APOS:
+ return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LT:
+ {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_EXCL:
+ return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_NMSTRT:
+ case BT_HEX:
+ case BT_NONASCII:
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ *nextTokPtr = ptr - MINBPC(enc);
+ return XML_TOK_INSTANCE_START;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ case BT_CR:
+ if (ptr + MINBPC(enc) == end) {
+ *nextTokPtr = end;
+ /* indicate that this might be part of a CR/LF pair */
+ return -XML_TOK_PROLOG_S;
+ }
+ FALL_THROUGH;
+ /* fall through */
+ case BT_S: case BT_LF:
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ break;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_LF:
+ break;
+ case BT_CR:
+ /* don't split CR/LF pair */
+ if (ptr + MINBPC(enc) != end)
+ break;
+ FALL_THROUGH;
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ case BT_PERCNT:
+ return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_COMMA:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMA;
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_BRACKET;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return -XML_TOK_CLOSE_BRACKET;
+ if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_COND_SECT_CLOSE;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_BRACKET;
+ case BT_LPAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_PAREN;
+ case BT_RPAR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return -XML_TOK_CLOSE_PAREN;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_AST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_ASTERISK;
+ case BT_QUEST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_QUESTION;
+ case BT_PLUS:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_PLUS;
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_GT: case BT_COMMA: case BT_VERBAR:
+ case BT_RPAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_PAREN;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_VERBAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OR;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DECL_CLOSE;
+ case BT_NUM:
+ return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NAME; \
+ break; \
+ } \
+ if (IS_NAME_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NMTOKEN; \
+ break; \
+ } \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NMSTRT:
+ case BT_HEX:
+ tok = XML_TOK_NAME;
+ ptr += MINBPC(enc);
+ break;
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ tok = XML_TOK_NMTOKEN;
+ ptr += MINBPC(enc);
+ break;
+ case BT_NONASCII:
+ if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NAME;
+ break;
+ }
+ if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ FALL_THROUGH;
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT: case BT_RPAR: case BT_COMMA:
+ case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return tok;
+#ifdef XML_NS
+ case BT_COLON:
+ ptr += MINBPC(enc);
+ switch (tok) {
+ case XML_TOK_NAME:
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ tok = XML_TOK_PREFIXED_NAME;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+ case XML_TOK_PREFIXED_NAME:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+#endif
+ case BT_PLUS:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_PLUS;
+ case BT_AST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_ASTERISK;
+ case BT_QUEST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_QUESTION;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return -tok;
+}
+
+static int PTRCALL
+PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ start = ptr;
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LT:
+ /* this is for inside entity references */
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_S:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ATTRIBUTE_VALUE_S;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+static int PTRCALL
+PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ start = ptr;
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_PERCNT:
+ if (ptr == start) {
+ int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
+ end, nextTokPtr);
+ return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ int level = 0;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ end = ptr + n;
+ }
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_LT:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
+ ++level;
+ ptr += MINBPC(enc);
+ }
+ }
+ break;
+ case BT_RSQB:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr += MINBPC(enc);
+ if (level == 0) {
+ *nextTokPtr = ptr;
+ return XML_TOK_IGNORE_SECT;
+ }
+ --level;
+ }
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **badPtr)
+{
+ ptr += MINBPC(enc);
+ end -= MINBPC(enc);
+ for (; ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ case BT_MINUS:
+ case BT_APOS:
+ case BT_LPAR:
+ case BT_RPAR:
+ case BT_PLUS:
+ case BT_COMMA:
+ case BT_SOL:
+ case BT_EQUALS:
+ case BT_QUEST:
+ case BT_CR:
+ case BT_LF:
+ case BT_SEMI:
+ case BT_EXCL:
+ case BT_AST:
+ case BT_PERCNT:
+ case BT_NUM:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ break;
+ case BT_S:
+ if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ case BT_NAME:
+ case BT_NMSTRT:
+ if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
+ break;
+ FALL_THROUGH;
+ default:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 0x24: /* $ */
+ case 0x40: /* @ */
+ break;
+ default:
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+/* This must only be called for a well-formed start-tag or empty
+ element tag. Returns the number of attributes. Pointers to the
+ first attsMax attributes are stored in atts.
+*/
+
+static int PTRCALL
+PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
+ int attsMax, ATTRIBUTE *atts)
+{
+ enum { other, inName, inValue } state = inName;
+ int nAtts = 0;
+ int open = 0; /* defined when state == inValue;
+ initialization just to shut up compilers */
+
+ for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define START_NAME \
+ if (state == other) { \
+ if (nAtts < attsMax) { \
+ atts[nAtts].name = ptr; \
+ atts[nAtts].normalized = 1; \
+ } \
+ state = inName; \
+ }
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+ case BT_HEX:
+ START_NAME
+ break;
+#undef START_NAME
+ case BT_QUOT:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ open = BT_QUOT;
+ }
+ else if (open == BT_QUOT) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_APOS:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ open = BT_APOS;
+ }
+ else if (open == BT_APOS) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_AMP:
+ if (nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_S:
+ if (state == inName)
+ state = other;
+ else if (state == inValue
+ && nAtts < attsMax
+ && atts[nAtts].normalized
+ && (ptr == atts[nAtts].valuePtr
+ || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
+ || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
+ || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_CR: case BT_LF:
+ /* This case ensures that the first attribute name is counted
+ Apart from that we could just change state on the quote. */
+ if (state == inName)
+ state = other;
+ else if (state == inValue && nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_GT:
+ case BT_SOL:
+ if (state != inValue)
+ return nAtts;
+ break;
+ default:
+ break;
+ }
+ }
+ /* not reached */
+}
+
+static int PTRFASTCALL
+PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
+{
+ int result = 0;
+ /* skip &# */
+ ptr += 2*MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
+ for (ptr += MINBPC(enc);
+ !CHAR_MATCHES(enc, ptr, ASCII_SEMI);
+ ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ switch (c) {
+ case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
+ case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
+ result <<= 4;
+ result |= (c - ASCII_0);
+ break;
+ case ASCII_A: case ASCII_B: case ASCII_C:
+ case ASCII_D: case ASCII_E: case ASCII_F:
+ result <<= 4;
+ result += 10 + (c - ASCII_A);
+ break;
+ case ASCII_a: case ASCII_b: case ASCII_c:
+ case ASCII_d: case ASCII_e: case ASCII_f:
+ result <<= 4;
+ result += 10 + (c - ASCII_a);
+ break;
+ }
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ else {
+ for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ result *= 10;
+ result += (c - ASCII_0);
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ return checkCharRefNumber(result);
+}
+
+static int PTRCALL
+PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
+ const char *end)
+{
+ switch ((end - ptr)/MINBPC(enc)) {
+ case 2:
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_l:
+ return ASCII_LT;
+ case ASCII_g:
+ return ASCII_GT;
+ }
+ }
+ break;
+ case 3:
+ if (CHAR_MATCHES(enc, ptr, ASCII_a)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_m)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_p))
+ return ASCII_AMP;
+ }
+ }
+ break;
+ case 4:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_q:
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_u)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_t))
+ return ASCII_QUOT;
+ }
+ }
+ break;
+ case ASCII_a:
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_p)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_s))
+ return ASCII_APOS;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static int PTRCALL
+PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr1)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (*ptr1++ != *ptr2++) \
+ return 0;
+ LEAD_CASE(4)
+ FALL_THROUGH;
+ LEAD_CASE(3)
+ FALL_THROUGH;
+ LEAD_CASE(2)
+#undef LEAD_CASE
+ /* fall through */
+ if (*ptr1++ != *ptr2++)
+ return 0;
+ break;
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 1) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 2) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 3) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
+ return 1;
+ switch (BYTE_TYPE(enc, ptr2)) {
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ return 0;
+ default:
+ return 1;
+ }
+ }
+ }
+ /* not reached */
+}
+
+static int PTRCALL
+PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
+ const char *end1, const char *ptr2)
+{
+ for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
+ if (ptr1 == end1)
+ return 0;
+ if (!CHAR_MATCHES(enc, ptr1, *ptr2))
+ return 0;
+ }
+ return ptr1 == end1;
+}
+
+static int PTRFASTCALL
+PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
+{
+ const char *start = ptr;
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return (int)(ptr - start);
+ }
+ }
+}
+
+static const char * PTRFASTCALL
+PREFIX(skipS)(const ENCODING *enc, const char *ptr)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LF:
+ case BT_CR:
+ case BT_S:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return ptr;
+ }
+ }
+}
+
+static void PTRCALL
+PREFIX(updatePosition)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ POSITION *pos)
+{
+ while (ptr < end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_LF:
+ pos->columnNumber = (XML_Size)-1;
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ break;
+ case BT_CR:
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ pos->columnNumber = (XML_Size)-1;
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ pos->columnNumber++;
+ }
+}
+
+#undef DO_LEAD_CASE
+#undef MULTIBYTE_CASES
+#undef INVALID_CASES
+#undef CHECK_NAME_CASE
+#undef CHECK_NAME_CASES
+#undef CHECK_NMSTRT_CASE
+#undef CHECK_NMSTRT_CASES
+
+#endif /* XML_TOK_IMPL_C */
diff --git a/gpr/source/lib/expat_lib/xmltok_impl.h b/gpr/source/lib/expat_lib/xmltok_impl.h
new file mode 100644
index 0000000..da0ea60
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmltok_impl.h
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+See the file COPYING for copying permission.
+*/
+
+enum {
+ BT_NONXML,
+ BT_MALFORM,
+ BT_LT,
+ BT_AMP,
+ BT_RSQB,
+ BT_LEAD2,
+ BT_LEAD3,
+ BT_LEAD4,
+ BT_TRAIL,
+ BT_CR,
+ BT_LF,
+ BT_GT,
+ BT_QUOT,
+ BT_APOS,
+ BT_EQUALS,
+ BT_QUEST,
+ BT_EXCL,
+ BT_SOL,
+ BT_SEMI,
+ BT_NUM,
+ BT_LSQB,
+ BT_S,
+ BT_NMSTRT,
+ BT_COLON,
+ BT_HEX,
+ BT_DIGIT,
+ BT_NAME,
+ BT_MINUS,
+ BT_OTHER, /* known not to be a name or name start character */
+ BT_NONASCII, /* might be a name or name start character */
+ BT_PERCNT,
+ BT_LPAR,
+ BT_RPAR,
+ BT_AST,
+ BT_PLUS,
+ BT_COMMA,
+ BT_VERBAR
+};
+
+#include <stddef.h>
diff --git a/gpr/source/lib/expat_lib/xmltok_ns.c b/gpr/source/lib/expat_lib/xmltok_ns.c
new file mode 100644
index 0000000..c3b88fd
--- /dev/null
+++ b/gpr/source/lib/expat_lib/xmltok_ns.c
@@ -0,0 +1,115 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* This file is included! */
+#ifdef XML_TOK_NS_C
+
+const ENCODING *
+NS(XmlGetUtf8InternalEncoding)(void)
+{
+ return &ns(internal_utf8_encoding).enc;
+}
+
+const ENCODING *
+NS(XmlGetUtf16InternalEncoding)(void)
+{
+#if BYTEORDER == 1234
+ return &ns(internal_little2_encoding).enc;
+#elif BYTEORDER == 4321
+ return &ns(internal_big2_encoding).enc;
+#else
+ const short n = 1;
+ return (*(const char *)&n
+ ? &ns(internal_little2_encoding).enc
+ : &ns(internal_big2_encoding).enc);
+#endif
+}
+
+static const ENCODING * const NS(encodings)[] = {
+ &ns(latin1_encoding).enc,
+ &ns(ascii_encoding).enc,
+ &ns(utf8_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(little2_encoding).enc,
+ &ns(utf8_encoding).enc /* NO_ENC */
+};
+
+static int PTRCALL
+NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+ XML_PROLOG_STATE, ptr, end, nextTokPtr);
+}
+
+static int PTRCALL
+NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+ XML_CONTENT_STATE, ptr, end, nextTokPtr);
+}
+
+int
+NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
+ const char *name)
+{
+ int i = getEncodingIndex(name);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ SET_INIT_ENC_INDEX(p, i);
+ p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
+ p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
+ p->initEnc.updatePosition = initUpdatePosition;
+ p->encPtr = encPtr;
+ *encPtr = &(p->initEnc);
+ return 1;
+}
+
+static const ENCODING *
+NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
+{
+#define ENCODING_MAX 128
+ char buf[ENCODING_MAX];
+ char *p = buf;
+ int i;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
+ if (ptr != end)
+ return 0;
+ *p = 0;
+ if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
+ return enc;
+ i = getEncodingIndex(buf);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ return NS(encodings)[i];
+}
+
+int
+NS(XmlParseXmlDecl)(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ return doParseXmlDecl(NS(findEncoding),
+ isGeneralTextEntity,
+ enc,
+ ptr,
+ end,
+ badPtr,
+ versionPtr,
+ versionEndPtr,
+ encodingName,
+ encoding,
+ standalone);
+}
+
+#endif /* XML_TOK_NS_C */
diff --git a/gpr/source/lib/gpr_sdk/CMakeLists.txt b/gpr/source/lib/gpr_sdk/CMakeLists.txt
new file mode 100644
index 0000000..9ce99c4
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/CMakeLists.txt
@@ -0,0 +1,44 @@
+# library
+set( LIB_NAME gpr_sdk )
+
+# get source files
+file( GLOB SRC_FILES "private/*.cpp" "public/*.cpp" )
+
+# get include files
+file( GLOB INC_FILES "private/*.h" "public/*.h" )
+
+# add include files from other folders
+include_directories( "./public" )
+include_directories( "../common/private" )
+include_directories( "../common/public" )
+include_directories( "../dng_sdk" )
+include_directories( "../vc5_common" )
+
+if(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/vc5_decoder")
+ include_directories( "../vc5_decoder" )
+ add_definitions("-DGPR_READING=1")
+else(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/vc5_decoder")
+ add_definitions("-DGPR_READING=0")
+endif(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/vc5_decoder")
+
+if(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/vc5_encoder")
+ include_directories( "../vc5_encoder" )
+ add_definitions("-DGPR_WRITING=1")
+else(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/vc5_encoder")
+ add_definitions("-DGPR_WRITING=0")
+endif(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/vc5_encoder")
+
+if(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/tiny_jpeg")
+ include_directories( "../tiny_jpeg" )
+ add_definitions("-DGPR_JPEG_AVAILABLE=1")
+else(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/tiny_jpeg")
+ add_definitions("-DGPR_JPEG_AVAILABLE=0")
+endif(EXISTS "${CMAKE_SOURCE_DIR}/source/lib/tiny_jpeg")
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/gpr_sdk/private/gpr.cpp b/gpr/source/lib/gpr_sdk/private/gpr.cpp
new file mode 100755
index 0000000..516c0f5
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr.cpp
@@ -0,0 +1,1849 @@
+/*! @file gpr.c
+ *
+ * @brief Implementation of top level functions that implement GPR-SDK API
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gpr.h"
+
+#include "dng_camera_profile.h"
+#include "dng_color_space.h"
+#include "dng_date_time.h"
+#include "dng_exceptions.h"
+#include "dng_file_stream.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image_writer.h"
+#include "dng_info.h"
+#include "dng_linearization_info.h"
+#include "dng_mosaic_info.h"
+#include "dng_negative.h"
+#include "dng_preview.h"
+#include "dng_render.h"
+#include "dng_simple_image.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_xmp.h"
+#include "dng_xmp_sdk.h"
+#include "dng_memory_stream.h"
+#include "dng_bottlenecks.h"
+
+#include "dng_misc_opcodes.h"
+#include "dng_gain_map.h"
+#include "dng_lens_correction.h"
+
+#include "gpr_utils.h"
+
+#include "macros.h"
+#include "gpr_buffer.h"
+#include "gpr_buffer_auto.h"
+
+#if GPR_READING
+#include "vc5_decoder.h"
+#endif
+
+#if GPR_WRITING
+#include "gpr_image_writer.h"
+#endif
+
+#if GPR_READING
+#include "gpr_read_image.h"
+#endif
+
+#if GPR_JPEG_AVAILABLE
+#include "jpeg.h"
+#endif
+
+extern bool gDNGShowTimers;
+
+#define PRINT_MATRIX 0
+
+// Include logging file (for reporting timing)
+#include "log.h"
+
+void find_rational(float number, float error_tolerance, int* numerator, int* denominator_pow2)
+{
+ int _num;
+ int _den_pow2;
+
+ _den_pow2 = 1;
+
+ while(1)
+ {
+ _num = number * (1 << _den_pow2);
+
+ float error = number - (float)_num / (float)((1 << _den_pow2));
+
+ if( error < error_tolerance )
+ break;
+
+ _den_pow2++;
+ }
+
+ *numerator = _num;
+ *denominator_pow2 = _den_pow2;
+}
+
+static void unpack_pixel_format( const gpr_buffer_auto* input_buffer, const gpr_parameters* convert_params, gpr_buffer_auto* output_buffer )
+{
+ size_t buffer_size = convert_params->input_height * convert_params->input_width * 2;
+ output_buffer->allocate( buffer_size );
+
+ unsigned char* src = input_buffer->to_uchar();
+ uint16_t* dst = output_buffer->to_uint16_t();
+
+ int src_stride = convert_params->input_pitch;
+ int dst_stride = convert_params->input_width;
+
+ for (unsigned int row = 0; row < convert_params->input_height; row++ )
+ {
+ for (unsigned int col = 0; col < (convert_params->input_width / 2); col++ )
+ {
+ unsigned char byte_0 = *(src + col * 3 + 0);
+ unsigned char byte_1 = *(src + col * 3 + 1);
+ unsigned char byte_2 = *(src + col * 3 + 2);
+
+ uint16_t pix1 = (byte_2 << 4) + ((byte_1 & 0xf0) >> 4);
+ uint16_t pix2 = (byte_0) + ((byte_1 & 0x0f) << 8);
+
+ *(dst + col * 2 + 0) = pix2;
+ *(dst + col * 2 + 1) = pix1;
+ }
+
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+#if GPR_WRITING
+static void set_vc5_encoder_parameters( vc5_encoder_parameters& vc5_encoder_params, const gpr_parameters* convert_params )
+{
+ vc5_encoder_params.input_width = convert_params->input_width;
+ vc5_encoder_params.input_height = convert_params->input_height;
+ vc5_encoder_params.input_pitch = convert_params->input_pitch;
+
+ switch ( convert_params->tuning_info.pixel_format )
+ {
+ case PIXEL_FORMAT_RGGB_12:
+ vc5_encoder_params.pixel_format = VC5_ENCODER_PIXEL_FORMAT_RGGB_12;
+ break;
+
+ case PIXEL_FORMAT_RGGB_12P:
+ vc5_encoder_params.pixel_format = VC5_ENCODER_PIXEL_FORMAT_RGGB_12P;
+ break;
+
+ case PIXEL_FORMAT_RGGB_14:
+ vc5_encoder_params.pixel_format = VC5_ENCODER_PIXEL_FORMAT_RGGB_14;
+ break;
+
+ case PIXEL_FORMAT_GBRG_12:
+ vc5_encoder_params.pixel_format = VC5_ENCODER_PIXEL_FORMAT_GBRG_12;
+ break;
+
+ case PIXEL_FORMAT_GBRG_12P:
+ vc5_encoder_params.pixel_format = VC5_ENCODER_PIXEL_FORMAT_GBRG_12P;
+ break;
+
+ default:
+ break;
+ }
+
+ if( convert_params->fast_encoding )
+ vc5_encoder_params.quality_setting = VC5_ENCODER_QUALITY_SETTING_MEDIUM;
+ else
+ vc5_encoder_params.quality_setting = VC5_ENCODER_QUALITY_SETTING_FS1;
+}
+#endif
+
+void gpr_parameters_set_defaults(gpr_parameters* x)
+{
+ memset(x, 0, sizeof(gpr_parameters));
+
+ gpr_exif_info_set_defaults(&x->exif_info);
+ gpr_profile_info_set_defaults(&x->profile_info);
+ gpr_tuning_info_set_defaults(&x->tuning_info);
+
+ x->enable_preview = true;
+
+ x->compute_md5sum = false;
+
+ x->fast_encoding = false;
+}
+
+void gpr_parameters_construct_copy(const gpr_parameters* y, gpr_parameters* x, gpr_malloc mem_alloc)
+{
+ gpr_parameters_set_defaults(x);
+
+ *x = *y;
+
+ if( y->gpmf_payload.size > 0 && y->gpmf_payload.buffer != NULL )
+ {
+ x->gpmf_payload.buffer = mem_alloc( y->gpmf_payload.size );
+ memcpy( x->gpmf_payload.buffer, y->gpmf_payload.buffer, y->gpmf_payload.size );
+ }
+
+ if( y->tuning_info.gain_map.size > 0 )
+ {
+ for ( int i = 0; i < 4; i++)
+ {
+ if( y->tuning_info.gain_map.buffers[i] != 0 )
+ {
+ x->tuning_info.gain_map.buffers[i] = (char*)mem_alloc( y->tuning_info.gain_map.size );
+ memcpy( x->tuning_info.gain_map.buffers[i], y->tuning_info.gain_map.buffers[i], y->tuning_info.gain_map.size );
+ }
+ }
+ }
+}
+
+void gpr_parameters_destroy(gpr_parameters* x, gpr_free mem_free)
+{
+ if( x->gpmf_payload.buffer && x->gpmf_payload.size > 0 )
+ {
+ mem_free( x->gpmf_payload.buffer );
+ }
+
+ if( x->tuning_info.gain_map.size > 0 )
+ {
+ for ( int i = 0; i < 4; i++)
+ {
+ if( x->tuning_info.gain_map.buffers[i] )
+ mem_free( x->tuning_info.gain_map.buffers[i] );
+ }
+ }
+}
+
+
+static dng_srational convert_to_dng_srational(gpr_signed_rational x)
+{
+ return dng_srational(x.numerator, x.denominator);
+}
+
+static dng_urational convert_to_dng_urational(gpr_unsigned_rational x)
+{
+ return dng_urational(x.numerator, x.denominator);
+}
+
+static gpr_unsigned_rational convert_to_unsigned_rational(dng_urational x)
+{
+ gpr_unsigned_rational a;
+ a.numerator = x.n;
+ a.denominator = x.d;
+
+ return a;
+}
+
+static gpr_signed_rational convert_to_signed_rational(dng_srational x)
+{
+ gpr_signed_rational a;
+ a.numerator = x.n;
+ a.denominator = x.d;
+
+ return a;
+}
+
+static dng_date_time convert_to_dng_date_time( const gpr_date_and_time& x )
+{
+ return dng_date_time (x.year, x.month, x.day, x.hour, x.minute, x.second );
+}
+
+static gpr_date_and_time convert_to_dng_date_and_time( const dng_date_time& x )
+{
+ gpr_date_and_time a;
+
+ a.year = x.fYear;
+ a.month = x.fMonth;
+ a.day = x.fDay;
+ a.hour = x.fHour;
+ a.minute = x.fMinute;
+ a.second = x.fSecond;
+
+ return a;
+}
+
+static void convert_dng_exif_info_to_dng_exif( dng_exif* dst_exif, const gpr_exif_info* src_exif )
+{
+ dst_exif->fModel.Set_ASCII( src_exif->camera_model );
+ dst_exif->fMake.Set_ASCII( src_exif->camera_make );
+ dst_exif->fCameraSerialNumber.Set_ASCII( src_exif->camera_serial );
+ dst_exif->fImageDescription.Set_ASCII( src_exif->image_description );
+
+ dst_exif->fApertureValue = convert_to_dng_urational( src_exif->aperture );
+ dst_exif->fMaxApertureValue = convert_to_dng_urational( src_exif->aperture );
+ dst_exif->fFNumber = convert_to_dng_urational( src_exif->f_stop_number );
+ dst_exif->fExposureTime = convert_to_dng_urational( src_exif->exposure_time );
+ dst_exif->fFocalLength = convert_to_dng_urational( src_exif->focal_length );
+ dst_exif->fDigitalZoomRatio = convert_to_dng_urational( src_exif->digital_zoom );
+ dst_exif->fExposureBiasValue = convert_to_dng_srational( src_exif->exposure_bias );
+
+ const int32_t focal_plane = 72;
+ dst_exif->fFocalPlaneXResolution = dng_urational(focal_plane, 1);
+ dst_exif->fFocalPlaneYResolution = dng_urational(focal_plane, 1);
+
+ dst_exif->fMeteringMode = src_exif->metering_mode;
+ dst_exif->fFocalLengthIn35mmFilm = src_exif->focal_length_in_35mm_film;
+ dst_exif->fExposureProgram = src_exif->exposure_program;
+ dst_exif->fLightSource = src_exif->light_source;
+ dst_exif->fFlash = src_exif->flash;
+ dst_exif->fSensingMethod = src_exif->sensing_method;
+ dst_exif->fFileSource = src_exif->file_source;
+ dst_exif->fSceneType = src_exif->scene_type;
+ dst_exif->fWhiteBalance = src_exif->white_balance;
+ dst_exif->fExposureMode = src_exif->exposure_mode;
+ dst_exif->fSceneCaptureType = src_exif->scene_capture_type;
+ dst_exif->fGainControl = src_exif->gain_control;
+ dst_exif->fContrast = src_exif->contrast;
+ dst_exif->fSaturation = src_exif->saturation;
+ dst_exif->fSharpness = src_exif->sharpness;
+
+ dst_exif->fISOSpeedRatings[0] = src_exif->iso_speed_rating;
+
+ dst_exif->fComponentsConfiguration = 0x04050600; //?? - since we're raw?
+
+ dst_exif->fDateTimeOriginal.SetDateTime( convert_to_dng_date_time( src_exif->date_time_original ) );
+ dst_exif->fDateTimeDigitized.SetDateTime( convert_to_dng_date_time( src_exif->date_time_digitized ) );
+
+ dst_exif->fSoftware.Set(src_exif->software_version);
+
+ dst_exif->fUserComment.Set(src_exif->user_comment);
+
+ const gpr_gps_info& src_gps_info = src_exif->gps_info;
+
+ if( src_gps_info.gps_info_valid )
+ {
+ dst_exif->fGPSVersionID = src_gps_info.version_id;
+
+ dst_exif->fGPSLatitudeRef.Set( src_gps_info.latitude_ref );
+
+ dst_exif->fGPSLatitude[0] = convert_to_dng_urational( src_gps_info.latitude[0] );
+ dst_exif->fGPSLatitude[1] = convert_to_dng_urational( src_gps_info.latitude[1] );
+ dst_exif->fGPSLatitude[2] = convert_to_dng_urational( src_gps_info.latitude[2] );
+
+ dst_exif->fGPSLongitudeRef.Set( src_gps_info.longitude_ref );
+
+ dst_exif->fGPSLongitude[0] = convert_to_dng_urational( src_gps_info.longitude[0] );
+ dst_exif->fGPSLongitude[1] = convert_to_dng_urational( src_gps_info.longitude[1] );
+ dst_exif->fGPSLongitude[2] = convert_to_dng_urational( src_gps_info.longitude[2] );
+
+ dst_exif->fGPSAltitudeRef = src_gps_info.altitude_ref;
+
+ dst_exif->fGPSAltitude = convert_to_dng_urational( src_gps_info.altitude );
+
+ dst_exif->fGPSTimeStamp[0] = convert_to_dng_urational( src_gps_info.time_stamp[0] );
+ dst_exif->fGPSTimeStamp[1] = convert_to_dng_urational( src_gps_info.time_stamp[1] );
+ dst_exif->fGPSTimeStamp[2] = convert_to_dng_urational( src_gps_info.time_stamp[2] );
+
+ dst_exif->fGPSSatellites.Set( src_gps_info.satellites );
+
+ dst_exif->fGPSStatus.Set( src_gps_info.status );
+
+ dst_exif->fGPSMeasureMode.Set( src_gps_info.measure_mode );
+
+ dst_exif->fGPSDOP = convert_to_dng_urational( src_gps_info.dop );
+
+ dst_exif->fGPSSpeedRef.Set( src_gps_info.speed_ref );
+
+ dst_exif->fGPSSpeed = convert_to_dng_urational( src_gps_info.speed );
+
+ dst_exif->fGPSTrackRef.Set( src_gps_info.track_ref );
+
+ dst_exif->fGPSTrack = convert_to_dng_urational( src_gps_info.track );
+
+ dst_exif->fGPSImgDirectionRef.Set( src_gps_info.img_direction_ref );
+
+ dst_exif->fGPSImgDirection = convert_to_dng_urational( src_gps_info.img_direction );
+
+ dst_exif->fGPSMapDatum.Set( src_gps_info.map_datum );
+
+ dst_exif->fGPSDestLatitudeRef.Set( src_gps_info.dest_latitude_ref );
+
+ dst_exif->fGPSDestLatitude[0] = convert_to_dng_urational( src_gps_info.dest_latitude[0] );
+ dst_exif->fGPSDestLatitude[1] = convert_to_dng_urational( src_gps_info.dest_latitude[1] );
+ dst_exif->fGPSDestLatitude[2] = convert_to_dng_urational( src_gps_info.dest_latitude[2] );
+
+ dst_exif->fGPSDestLongitudeRef.Set( src_gps_info.dest_longitude_ref );
+
+ dst_exif->fGPSDestLongitude[0] = convert_to_dng_urational( src_gps_info.dest_longitude[0] );
+ dst_exif->fGPSDestLongitude[1] = convert_to_dng_urational( src_gps_info.dest_longitude[1] );
+ dst_exif->fGPSDestLongitude[2] = convert_to_dng_urational( src_gps_info.dest_longitude[2] );
+
+ dst_exif->fGPSDestBearingRef.Set( src_gps_info.dest_bearing_ref );
+
+ dst_exif->fGPSDestBearing = convert_to_dng_urational( src_gps_info.dest_bearing );
+
+ dst_exif->fGPSDestDistanceRef.Set( src_gps_info.dest_distance_ref );
+
+ dst_exif->fGPSDestDistance = convert_to_dng_urational( src_gps_info.dest_distance );
+
+ dst_exif->fGPSProcessingMethod.Set( src_gps_info.processing_method );
+
+ dst_exif->fGPSAreaInformation.Set( src_gps_info.area_information );
+
+ dst_exif->fGPSDateStamp.Set( src_gps_info.date_stamp );
+
+ dst_exif->fGPSDifferential = src_gps_info.differential;
+ }
+}
+
+static void convert_dng_exif_to_dng_exif_info( gpr_exif_info* dst_exif, const dng_exif* src_exif )
+{
+ assert(src_exif->fModel.Length() < sizeof(dst_exif->camera_model));
+ strcpy( dst_exif->camera_model, src_exif->fModel.Get() );
+
+ assert(src_exif->fMake.Length() < sizeof(dst_exif->camera_make));
+ strcpy( dst_exif->camera_make, src_exif->fMake.Get() );
+
+ assert(src_exif->fCameraSerialNumber.Length() < sizeof(dst_exif->camera_serial));
+ strcpy( dst_exif->camera_serial, src_exif->fCameraSerialNumber.Get() );
+
+ assert(src_exif->fImageDescription.Length() < sizeof(dst_exif->image_description));
+ strcpy( dst_exif->image_description, src_exif->fImageDescription.Get() );
+
+ dst_exif->aperture = convert_to_unsigned_rational( src_exif->fMaxApertureValue );
+ dst_exif->f_stop_number = convert_to_unsigned_rational( src_exif->fFNumber );
+ dst_exif->exposure_time = convert_to_unsigned_rational( src_exif->fExposureTime );
+ dst_exif->focal_length = convert_to_unsigned_rational( src_exif->fFocalLength );
+ dst_exif->digital_zoom = convert_to_unsigned_rational( src_exif->fDigitalZoomRatio );
+ dst_exif->exposure_bias = convert_to_signed_rational( src_exif->fExposureBiasValue );
+
+ dst_exif->metering_mode = (gpr_metering_mode)src_exif->fMeteringMode;
+ dst_exif->focal_length_in_35mm_film = src_exif->fFocalLengthIn35mmFilm;
+ dst_exif->exposure_program = (gpr_exposure_program)src_exif->fExposureProgram;
+ dst_exif->light_source = (gpr_light_source)src_exif->fLightSource;
+ dst_exif->flash = (gpr_flash)src_exif->fFlash;
+ dst_exif->sensing_method = (gpr_sensing_method)src_exif->fSensingMethod;
+ dst_exif->file_source = (gpr_file_source)src_exif->fFileSource;
+ dst_exif->scene_type = (gpr_scene_type)src_exif->fSceneType;
+ dst_exif->white_balance = (gpr_white_balance)src_exif->fWhiteBalance;
+ dst_exif->exposure_mode = (gpr_exposure_mode)src_exif->fExposureMode;
+ dst_exif->scene_capture_type = (gpr_scene_capture_type)src_exif->fSceneCaptureType;
+ dst_exif->gain_control = (gpr_gain_control)src_exif->fGainControl;
+ dst_exif->contrast = (gpr_contrast)src_exif->fContrast;
+ dst_exif->saturation = src_exif->fSaturation;
+ dst_exif->sharpness = (gpr_sharpness)src_exif->fSharpness;
+
+ dst_exif->iso_speed_rating = src_exif->fISOSpeedRatings[0];
+
+ dst_exif->date_time_original = convert_to_dng_date_and_time( src_exif->fDateTimeOriginal.DateTime() );
+ dst_exif->date_time_digitized = convert_to_dng_date_and_time( src_exif->fDateTimeOriginal.DateTime() );
+
+ assert(src_exif->fSoftware.Length() < sizeof(dst_exif->software_version));
+ memcpy( dst_exif->software_version, src_exif->fSoftware.Get(), src_exif->fSoftware.Length() );
+
+ assert(src_exif->fUserComment.Length() < sizeof(dst_exif->user_comment));
+ memcpy( dst_exif->user_comment, src_exif->fUserComment.Get(), src_exif->fUserComment.Length() );
+
+ // GPS Info
+ gpr_gps_info& dst_gps_info = dst_exif->gps_info;
+
+ dst_gps_info.version_id = src_exif->fGPSVersionID;
+
+ dst_gps_info.gps_info_valid = dst_gps_info.version_id > 0;
+
+ strcpy( dst_gps_info.latitude_ref, src_exif->fGPSLatitudeRef.Get() );
+
+ dst_gps_info.latitude[0] = convert_to_unsigned_rational( src_exif->fGPSLatitude[0] );
+ dst_gps_info.latitude[1] = convert_to_unsigned_rational( src_exif->fGPSLatitude[1] );
+ dst_gps_info.latitude[2] = convert_to_unsigned_rational( src_exif->fGPSLatitude[2] );
+
+ strcpy( dst_gps_info.longitude_ref, src_exif->fGPSLongitudeRef.Get() );
+
+ dst_gps_info.longitude[0] = convert_to_unsigned_rational( src_exif->fGPSLongitude[0] );
+ dst_gps_info.longitude[1] = convert_to_unsigned_rational( src_exif->fGPSLongitude[1] );
+ dst_gps_info.longitude[2] = convert_to_unsigned_rational( src_exif->fGPSLongitude[2] );
+
+ dst_gps_info.altitude_ref = src_exif->fGPSAltitudeRef;
+
+ dst_gps_info.altitude = convert_to_unsigned_rational( src_exif->fGPSAltitude );
+
+ dst_gps_info.time_stamp[0] = convert_to_unsigned_rational( src_exif->fGPSTimeStamp[0] );
+ dst_gps_info.time_stamp[1] = convert_to_unsigned_rational( src_exif->fGPSTimeStamp[1] );
+ dst_gps_info.time_stamp[2] = convert_to_unsigned_rational( src_exif->fGPSTimeStamp[2] );
+
+ strcpy( dst_gps_info.satellites, src_exif->fGPSSatellites.Get() );
+
+ strcpy( dst_gps_info.status, src_exif->fGPSStatus.Get() );
+
+ strcpy( dst_gps_info.measure_mode, src_exif->fGPSMeasureMode.Get() );
+
+ dst_gps_info.dop = convert_to_unsigned_rational( src_exif->fGPSDOP );
+
+ strcpy( dst_gps_info.speed_ref, src_exif->fGPSSpeedRef.Get() );
+
+ dst_gps_info.speed = convert_to_unsigned_rational( src_exif->fGPSSpeed );
+
+ strcpy( dst_gps_info.track_ref, src_exif->fGPSTrackRef.Get() );
+
+ dst_gps_info.track = convert_to_unsigned_rational( src_exif->fGPSTrack );
+
+ strcpy( dst_gps_info.img_direction_ref, src_exif->fGPSImgDirectionRef.Get() );
+
+ dst_gps_info.img_direction = convert_to_unsigned_rational( src_exif->fGPSImgDirection );
+
+ strcpy( dst_gps_info.map_datum, src_exif->fGPSMapDatum.Get() );
+
+ strcpy( dst_gps_info.dest_latitude_ref, src_exif->fGPSDestLatitudeRef.Get() );
+
+ dst_gps_info.dest_latitude[0] = convert_to_unsigned_rational( src_exif->fGPSDestLatitude[0] );
+ dst_gps_info.dest_latitude[1] = convert_to_unsigned_rational( src_exif->fGPSDestLatitude[1] );
+ dst_gps_info.dest_latitude[2] = convert_to_unsigned_rational( src_exif->fGPSDestLatitude[2] );
+
+ strcpy( dst_gps_info.dest_longitude_ref, src_exif->fGPSDestLongitudeRef.Get() );
+
+ dst_gps_info.dest_longitude[0] = convert_to_unsigned_rational( src_exif->fGPSDestLongitude[0] );
+ dst_gps_info.dest_longitude[1] = convert_to_unsigned_rational( src_exif->fGPSDestLongitude[1] );
+ dst_gps_info.dest_longitude[2] = convert_to_unsigned_rational( src_exif->fGPSDestLongitude[2] );
+
+ strcpy( dst_gps_info.dest_bearing_ref, src_exif->fGPSDestBearingRef.Get() );
+
+ dst_gps_info.dest_bearing = convert_to_unsigned_rational( src_exif->fGPSDestBearing );
+
+ strcpy( dst_gps_info.dest_distance_ref, src_exif->fGPSDestDistanceRef.Get() );
+
+ dst_gps_info.dest_distance = convert_to_unsigned_rational( src_exif->fGPSDestDistance );
+
+ strcpy( dst_gps_info.processing_method, src_exif->fGPSProcessingMethod.Get() );
+
+ strcpy( dst_gps_info.area_information, src_exif->fGPSAreaInformation.Get() );
+
+ strcpy( dst_gps_info.date_stamp, src_exif->fGPSDateStamp.Get() );
+
+ dst_gps_info.differential = src_exif->fGPSDifferential;
+}
+
+
+#define MAX_BUF_SIZE 16000
+
+static char _warp_rect_buffer [256];
+
+static bool read_dng(const gpr_allocator* allocator,
+ dng_stream* dng_read_stream,
+ gpr_buffer_auto* raw_image_buffer,
+ gpr_buffer_auto* vc5_image_buffer,
+ gpr_parameters* convert_params = NULL,
+ bool* is_vc5_format = NULL )
+{
+ dng_host host;
+
+ gpr_buffer_auto vc5_image_obj( allocator->Alloc, allocator->Free );
+
+ static uint32 gPreferredSize = 0;
+ static uint32 gMinimumSize = 0;
+ static uint32 gMaximumSize = 0;
+
+ static dng_string gDumpDNG;
+
+ host.SetPreferredSize (gPreferredSize);
+ host.SetMinimumSize (gMinimumSize );
+ host.SetMaximumSize (gMaximumSize );
+
+ host.ValidateSizes ();
+
+ host.SetSaveDNGVersion (dngVersion_SaveDefault);
+
+ host.SetSaveLinearDNG (false);
+
+ host.SetKeepOriginalFile (false);
+
+ AutoPtr<dng_negative> negative;
+
+ if( raw_image_buffer != NULL && vc5_image_buffer == NULL )
+ {
+ vc5_image_buffer = &vc5_image_obj;
+ }
+
+ {
+ dng_info info;
+
+ info.Parse (host, *dng_read_stream);
+
+ info.PostParse (host);
+
+ if (!info.IsValidDNG ())
+ {
+ return false;
+ }
+
+ dng_memory_block* gpmf_payload = host.GetGPMFPayload().Get();
+
+ if( gpmf_payload && gpmf_payload->LogicalSize() > 0 )
+ {
+ if( convert_params != NULL && convert_params->gpmf_payload.buffer == NULL && convert_params->gpmf_payload.size == 0 )
+ {
+ convert_params->gpmf_payload.size = gpmf_payload->LogicalSize();
+ convert_params->gpmf_payload.buffer = allocator->Alloc( convert_params->gpmf_payload.size );
+
+ memcpy( convert_params->gpmf_payload.buffer, gpmf_payload->Buffer(), convert_params->gpmf_payload.size );
+ }
+ }
+
+ negative.Reset (host.Make_dng_negative ());
+
+ negative->Parse (host, *dng_read_stream, info);
+
+ negative->PostParse (host, *dng_read_stream, info);
+
+#if GPR_READING
+ if( negative->IsVc5Image( info ) )
+ {
+ gpr_read_image reader( vc5_image_buffer );
+
+ if( vc5_image_buffer == NULL )
+ {
+ reader.SetReadVC5(false);
+ }
+
+ if( raw_image_buffer == NULL )
+ {
+ reader.SetDecodeVC5(false);
+ }
+
+ negative->ReadVc5Image(host, *dng_read_stream, info, reader);
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
+
+ if (rawIFD.fOpcodeList2Count)
+ {
+ negative->OpcodeList2().Parse (host, *dng_read_stream, rawIFD.fOpcodeList2Count, rawIFD.fOpcodeList2Offset);
+ }
+
+ if (rawIFD.fOpcodeList3Count)
+ {
+ negative->OpcodeList3().Parse (host, *dng_read_stream, rawIFD.fOpcodeList3Count, rawIFD.fOpcodeList3Offset);
+ }
+
+ if( is_vc5_format )
+ *is_vc5_format = true;
+ }
+ else
+#endif
+ {
+ negative->ReadStage1Image (host, *dng_read_stream, info);
+
+ if( is_vc5_format )
+ *is_vc5_format = false;
+ }
+
+ const dng_image& raw_image = negative->RawImage();
+
+ if( convert_params )
+ {
+ dng_rect bounds = raw_image.Bounds();
+ int i,j;
+
+ convert_params->input_width = bounds.W();
+ convert_params->input_height = bounds.H();
+ convert_params->input_pitch = convert_params->input_width * 2;
+
+ // Copy ColorMatrix1, ColorMatrix2
+ {
+ const dng_camera_profile &profile_info = negative->ProfileByIndex( 0 );
+ const dng_matrix &m1 = profile_info.ColorMatrix1();
+ const dng_matrix &m2 = profile_info.ColorMatrix2();
+
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < 3; j++)
+ {
+ convert_params->profile_info.color_matrix_1[i][j] = m1[i][j];
+ convert_params->profile_info.color_matrix_2[i][j] = m2[i][j];
+ }
+ }
+
+ convert_params->profile_info.compute_color_matrix = false;
+ convert_params->profile_info.matrix_weighting = 1.0;
+
+ memset( convert_params->profile_info.wb1, 0, sizeof(convert_params->profile_info.wb1) );
+ memset( convert_params->profile_info.wb2, 0, sizeof(convert_params->profile_info.wb2) );
+
+ memset( convert_params->profile_info.cam_to_srgb_1, 0, sizeof(convert_params->profile_info.cam_to_srgb_1) );
+ memset( convert_params->profile_info.cam_to_srgb_2, 0, sizeof(convert_params->profile_info.cam_to_srgb_2) );
+ }
+
+ // Set Exif Info
+ convert_dng_exif_to_dng_exif_info( &convert_params->exif_info, negative->GetExif() );
+
+ // Set Tuning Info
+ {
+ gpr_tuning_info& tuning_info = convert_params->tuning_info;
+
+ tuning_info.orientation = (GPR_ORIENTATION)negative->BaseOrientation().GetAdobe();
+
+ if( negative->HasCameraNeutral() )
+ {
+ const dng_vector& camNeutral = negative->CameraNeutral();
+
+ tuning_info.wb_gains.r_gain = 1 / camNeutral[0];
+ tuning_info.wb_gains.g_gain = 1 / camNeutral[1];
+ tuning_info.wb_gains.b_gain = 1 / camNeutral[2];
+ }
+
+ const dng_linearization_info& linearization_info = *negative->GetLinearizationInfo();
+
+ {
+ gpr_static_black_level& static_black_level = tuning_info.static_black_level;
+
+ static_black_level.r_black = linearization_info.fBlackLevel[0][0][0];
+ static_black_level.g_r_black = linearization_info.fBlackLevel[0][1][0];
+ static_black_level.g_b_black = linearization_info.fBlackLevel[1][0][0];
+ static_black_level.b_black = linearization_info.fBlackLevel[1][1][0];
+ }
+
+ {
+ gpr_saturation_level& dgain_saturation_level = tuning_info.dgain_saturation_level;
+
+ dgain_saturation_level.level_red = linearization_info.fWhiteLevel[0];
+ dgain_saturation_level.level_green_even = dgain_saturation_level.level_red;
+ dgain_saturation_level.level_green_odd = dgain_saturation_level.level_red;
+ dgain_saturation_level.level_blue = dgain_saturation_level.level_red;
+ }
+
+ {
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
+
+ gpr_saturation_level& dgain_saturation_level = tuning_info.dgain_saturation_level;
+
+ bool rggb_raw = (rawIFD.fCFAPattern[0][0] == 0) && (rawIFD.fCFAPattern[0][1] == 1) && (rawIFD.fCFAPattern[1][0] == 1) && (rawIFD.fCFAPattern[1][1] == 2);
+
+ if( rggb_raw )
+ {
+ if( dgain_saturation_level.level_red == 4095 &&
+ dgain_saturation_level.level_green_even == 4095 &&
+ dgain_saturation_level.level_green_odd == 4095 &&
+ dgain_saturation_level.level_blue == 4095 )
+ {
+ tuning_info.pixel_format = PIXEL_FORMAT_RGGB_12;
+ }
+ else if(dgain_saturation_level.level_red == 16383 &&
+ dgain_saturation_level.level_green_even == 16383 &&
+ dgain_saturation_level.level_green_odd == 16383 &&
+ dgain_saturation_level.level_blue == 16383 )
+ {
+ tuning_info.pixel_format = PIXEL_FORMAT_RGGB_14;
+ }
+ else
+ {
+ assert(0);
+ return false;
+ }
+ }
+ else
+ {
+ if( dgain_saturation_level.level_red == 4095 &&
+ dgain_saturation_level.level_green_even == 4095 &&
+ dgain_saturation_level.level_green_odd == 4095 &&
+ dgain_saturation_level.level_blue == 4095 )
+ {
+ tuning_info.pixel_format = PIXEL_FORMAT_GBRG_12;
+ }
+ else
+ {
+ assert(0);
+ return false;
+ }
+
+
+ }
+ }
+
+ // Noise profile
+ if ( negative->HasNoiseProfile() )
+ {
+ dng_noise_profile noise_profile = negative->NoiseProfile();
+
+ dng_noise_function noise_function = noise_profile.NoiseFunction (0);
+
+ tuning_info.noise_scale = noise_function.Scale();
+ tuning_info.noise_offset = noise_function.Offset();
+ //LogPrint( "Noise profile s = %f, o = %f ", tuning_info.noise_scale, tuning_info.noise_offset );
+ }
+
+ // GainMap
+ dng_opcode_list &opcodelist2 = negative->OpcodeList2 ();
+ uint32_t count = opcodelist2.Count ();
+ // Note: this code will have to get smarter if we ever have anything other than four GainMap tags in OpcodeList2
+ if ( count == 4 && tuning_info.gain_map.size == 0 )
+ {
+ char gainmap_buffer [4][MAX_BUF_SIZE];
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ // Get GainMap Opcode
+ dng_opcode &opcode = opcodelist2.Entry( i );
+
+ // generate stream data
+ dng_stream stream ( gainmap_buffer[i], MAX_BUF_SIZE );
+ stream.Put_uint32 ( 0x01040000 ); // version
+ stream.Put_uint32 ( 0x3 ); // flags
+ opcode.PutData( stream );
+
+ // Point to buffer
+ if( i == 0 )
+ tuning_info.gain_map.size = stream.Position();
+
+ assert( tuning_info.gain_map.buffers[i] == NULL );
+
+ tuning_info.gain_map.buffers[i] = (char*)allocator->Alloc( tuning_info.gain_map.size );
+ memcpy( tuning_info.gain_map.buffers[i], gainmap_buffer[i], tuning_info.gain_map.size );
+ }
+ }
+ else
+ {
+ tuning_info.gain_map.size = 0;
+ }
+
+ // WarpRectilinear
+ dng_opcode_list &opcodelist3 = negative->OpcodeList3 ();
+ count = opcodelist3.Count ();
+ // Note: this code will have to get smarter if we ever have anything other than one WarpRectilinear tag in OpcodeList3
+ if ( count == 1 )
+ {
+ // Get WarpRectilinear Opcode
+ dng_opcode &opcode = opcodelist3.Entry( 0 );
+
+ dng_stream stream ( _warp_rect_buffer, 256 );
+ opcode.PutData( stream );
+
+ // Ugly way to get the parameters, but I couldn't figure how else to get access to the data
+ double red_coefficient = * (double *) &_warp_rect_buffer[8];
+ double blue_coefficient = * (double *) &_warp_rect_buffer[8 + 2*6*8];
+ //LogPrint( "WarpRectilinear red = %f, blue = %f ", red_coefficient, blue_coefficient );
+
+ tuning_info.warp_red_coefficient = red_coefficient;
+ tuning_info.warp_blue_coefficient = blue_coefficient;
+ }
+ else
+ {
+ tuning_info.warp_red_coefficient = 0;
+ tuning_info.warp_blue_coefficient = 0;
+ }
+ }
+ }
+
+ if( raw_image_buffer )
+ {
+ CopyRawImageToBuffer( raw_image, *raw_image_buffer );
+ }
+ }
+
+ return true;
+}
+
+
+void reduction(double a[][6], int size, int pivot, int col)
+{
+ int i, j;
+ double factor;
+ factor = a[pivot][col];
+
+ for (i = 0; i < 2 * size; i++) {
+ a[pivot][i] /= factor;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (i != pivot) {
+ factor = a[i][col];
+ for (j = 0; j < 2 * size; j++) {
+ a[i][j] = a[i][j] - a[pivot][j] * factor;
+ }
+ }
+ }
+}
+
+void calc_color_matrix( double in_matrix[3][3], double wb[3], double weight, double out_matrix[3][3] )
+{
+ double temp1[3][3];
+ double temp2[3][3];
+
+ int i,j,k;
+
+#if PRINT_MATRIX
+ LogPrint("\nOriginal Matrix");
+ for (i = 0; i < 3; i++)
+ LogPrint("%8.5f %8.5f %8.5f", in_matrix[i][0], in_matrix[i][1], in_matrix[i][2] );
+#endif
+
+ // Interpolate with identity matrix by weight w
+ double w = weight;
+ double z = 1.0 - weight;
+
+ for (i = 0; i < 3; i++ )
+ {
+ for (j = 0; j < 3; j++ )
+ temp1[i][j] = in_matrix[i][j] * w;
+
+ temp1[i][i] += z;
+ }
+
+#if PRINT_MATRIX
+ LogPrint("\nInterpolated Matrix");
+ for (i = 0; i < 3; i++)
+ LogPrint("%8.5f %8.5f %8.5f", temp1[i][0], temp1[i][1], temp1[i][2] );
+#endif
+
+ // Multiply matrix by sRGB_to_XYZd50 (from http://www.brucelindbloom.com)
+ double sRGB_to_XYZd50[3][3] = {{0.4361, 0.3851, 0.1431}, {0.2225, 0.7169, 0.0606}, {0.0139, 0.0971, 0.7142}};
+
+ double sum;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ {
+ sum = 0;
+ for (k = 0; k < 3; k++)
+ sum = sum + sRGB_to_XYZd50[i][k] * temp1[k][j];
+
+ temp2[i][j] = sum;
+ }
+
+#if PRINT_MATRIX
+ LogPrint("\ntimes sRGB_to_XYZd50");
+ for (i = 0; i < 3; i++)
+ LogPrint("%8.5f %8.5f %8.5f", temp2[i][0], temp2[i][1], temp2[i][2] );
+#endif
+
+ // Set up diagonal matrix with white balance gains
+ double wb_diag[3][3];
+ for (i = 0; i < 3; i++)
+ {
+ for (j = 0; j < 3; j++)
+ wb_diag[i][j] = 0.0;
+
+ wb_diag[i][i] = wb[i];
+ }
+
+ // Multiply by white balance gains
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ {
+ sum = 0;
+ for (k = 0; k < 3; k++)
+ sum = sum + temp2[i][k] * wb_diag[k][j];
+
+ temp1[i][j] = sum;
+ }
+
+#if PRINT_MATRIX
+ LogPrint("\ntimes wb");
+ for (i = 0; i < 3; i++)
+ LogPrint("%8.5f %8.5f %8.5f", temp1[i][0], temp1[i][1], temp1[i][2] );
+#endif
+
+ // Invert the resulting matrix
+ double matrix[3][6];
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 6; j++)
+ if (j == i + 3)
+ matrix[i][j] = 1;
+ else
+ matrix[i][j] = 0;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ matrix[i][j] = temp1[i][j];
+
+ for (i = 0; i < 3; i++)
+ reduction(matrix, 3, i, i);
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out_matrix[i][j] = matrix[i][j+3];
+
+#if PRINT_MATRIX
+ LogPrint("\nInverse Matrix");
+ for (i = 0; i < 3; i++) {
+ LogPrint("%8.5f %8.5f %8.5f", out_matrix[i][0], out_matrix[i][1], out_matrix[i][2] );
+ }
+#endif
+
+}
+
+typedef struct
+{
+ unsigned char* orig_dst; /* Address to the memory location that this buffer points to */
+
+ unsigned char* next_dst;
+
+} jpg_write_context;
+
+void write_jpg_thumbnail(void* context, void* data, int size)
+{
+ jpg_write_context* _context = (jpg_write_context*)context;
+
+ memcpy( _context->next_dst, data, size );
+
+ _context->next_dst = (unsigned char*)_context->next_dst + size;
+}
+
+static void write_dng(const gpr_allocator* allocator,
+ dng_stream* dng_write_stream,
+ const gpr_buffer_auto* raw_image_buffer,
+ bool compress_raw_to_vc5,
+ gpr_buffer_auto* vc5_image_buffer,
+ const gpr_parameters* convert_params )
+{
+ gpr_profile_info* profile_info = (gpr_profile_info *) &convert_params->profile_info;
+ const gpr_exif_info* exif_info = &convert_params->exif_info;
+
+ const bool vc5_dng = compress_raw_to_vc5 || vc5_image_buffer;
+
+ int i,j;
+
+ int activeWidth = convert_params->input_width;
+ int activeHeight = convert_params->input_height;
+
+ int outputWidth = activeWidth;
+ int outputHeight = activeHeight;
+
+ gDNGShowTimers = false;
+
+ dng_memory_allocator memalloc(gDefaultDNGMemoryAllocator);
+
+ dng_rect rect(outputHeight, outputWidth);
+ dng_host host(&memalloc);
+
+ host.SetSaveDNGVersion(dngVersion_SaveDefault);
+ host.SetSaveLinearDNG(false);
+ host.SetKeepOriginalFile(true);
+
+ AutoPtr<dng_image> image(new dng_simple_image(rect, 1, ttShort, memalloc));
+
+ gpr_buffer_auto raw_allocated_buffer( allocator->Alloc, allocator->Free );
+
+ if( raw_image_buffer == NULL && vc5_image_buffer )
+ {
+#if GPR_READING
+ vc5_decoder_parameters vc5_decoder_params;
+
+ vc5_decoder_parameters_set_default(&vc5_decoder_params);
+
+ vc5_decoder_params.mem_alloc = allocator->Alloc;
+ vc5_decoder_params.mem_free = allocator->Free;
+
+ switch(convert_params->tuning_info.pixel_format)
+ {
+ case PIXEL_FORMAT_RGGB_12:
+ vc5_decoder_params.pixel_format = VC5_DECODER_PIXEL_FORMAT_RGGB_12;
+ break;
+
+ case PIXEL_FORMAT_RGGB_14:
+ vc5_decoder_params.pixel_format = VC5_DECODER_PIXEL_FORMAT_RGGB_14;
+ break;
+
+ case PIXEL_FORMAT_GBRG_12:
+ vc5_decoder_params.pixel_format = VC5_DECODER_PIXEL_FORMAT_GBRG_12;
+ break;
+
+ default:
+ assert(0);
+ return;
+ };
+
+ gpr_buffer vc5_image = { vc5_image_buffer->get_buffer(), vc5_image_buffer->get_size() };
+ gpr_buffer raw_image = { raw_allocated_buffer.get_buffer(), raw_allocated_buffer.get_size() };
+
+ if( vc5_decoder_process( &vc5_decoder_params, &vc5_image, &raw_image, NULL ) != CODEC_ERROR_OKAY )
+ {
+ assert(0);
+ }
+
+ raw_allocated_buffer.set( raw_image.buffer, raw_image.size, true );
+
+ raw_image_buffer = &raw_allocated_buffer;
+#else
+ return; // Since vc5 decoder is not enabled, we cannot decode this vc5 bitstream to create raw image
+#endif // GPR_READING
+ }
+
+ unsigned int input_pitch = convert_params->input_pitch;
+
+ if( ( convert_params->tuning_info.pixel_format == PIXEL_FORMAT_GBRG_12P ||
+ convert_params->tuning_info.pixel_format == PIXEL_FORMAT_RGGB_12P ) &&
+ vc5_dng == false )
+ {
+ unpack_pixel_format( raw_image_buffer, convert_params, &raw_allocated_buffer );
+
+ raw_image_buffer = &raw_allocated_buffer;
+
+ input_pitch = convert_params->input_width * 2;
+ }
+
+ if( vc5_dng == false )
+ {
+ CopyBufferToRawImage( *raw_image_buffer, input_pitch / sizeof(short), *(image.Get()) );
+ }
+
+ AutoPtr<dng_negative> negative(host.Make_dng_negative());
+
+ negative->SetOriginalBestQualityFinalSize( dng_point(outputHeight, outputWidth) );
+
+ negative->SetOriginalDefaultFinalSize( dng_point(outputHeight, outputWidth) );
+
+ { // Set Tuning Info
+ const gpr_tuning_info* tuning_info = &convert_params->tuning_info;
+
+ const gpr_static_black_level static_black_level = tuning_info->static_black_level;
+
+ switch( convert_params->tuning_info.pixel_format )
+ {
+ case PIXEL_FORMAT_RGGB_12:
+ case PIXEL_FORMAT_RGGB_12P:
+ case PIXEL_FORMAT_RGGB_14:
+ negative->SetQuadBlacks(static_black_level.r_black,
+ static_black_level.g_r_black,
+ static_black_level.g_b_black,
+ static_black_level.b_black,
+ -1 );
+ break;
+ case PIXEL_FORMAT_GBRG_12:
+ case PIXEL_FORMAT_GBRG_12P:
+ negative->SetQuadBlacks(static_black_level.g_b_black,
+ static_black_level.b_black,
+ static_black_level.r_black,
+ static_black_level.g_r_black,
+ -1 );
+ break;
+
+ default:
+ assert(0);
+ }
+
+ const gpr_saturation_level dgain_saturation_level = tuning_info->dgain_saturation_level;
+
+ if( dgain_saturation_level.level_red == dgain_saturation_level.level_green_even &&
+ dgain_saturation_level.level_red == dgain_saturation_level.level_green_odd &&
+ dgain_saturation_level.level_red == dgain_saturation_level.level_blue )
+ {
+ negative->SetWhiteLevel( dgain_saturation_level.level_red, -1 );
+ }
+ else
+ {
+ negative->SetWhiteLevel( dgain_saturation_level.level_red, 0 );
+ negative->SetWhiteLevel( dgain_saturation_level.level_green_even, 1 );
+ negative->SetWhiteLevel( dgain_saturation_level.level_green_odd, 2 );
+ negative->SetWhiteLevel( dgain_saturation_level.level_blue, 3 );
+ }
+
+ negative->SetBaseOrientation((dng_orientation::AdobeToDNG(tuning_info->orientation)));
+
+ dng_vector camNeutral(3);
+
+ camNeutral[0] = 1.0 / tuning_info->wb_gains.r_gain;
+ camNeutral[1] = 1.0 / tuning_info->wb_gains.g_gain;
+ camNeutral[2] = 1.0 / tuning_info->wb_gains.b_gain;
+
+ negative->SetCameraNeutral(camNeutral);
+
+
+ // Add noise profile
+ if ( tuning_info->noise_scale > 0 )
+ {
+ std::vector<dng_noise_function> noiseFunctions;
+ noiseFunctions.push_back( dng_noise_function ( tuning_info->noise_scale, tuning_info->noise_offset ) );
+ negative->SetNoiseProfile( dng_noise_profile ( noiseFunctions ) );
+ }
+
+ size_t gain_map_size = tuning_info->gain_map.size;
+
+ // GainMap - aka vignette or shading correction (one for each CFA channel)(applied before demosaicking (OpcodeList2))
+ if ( gain_map_size > 0 && tuning_info->gain_map.buffers[0] != 0 && tuning_info->gain_map.buffers[1] != 0 && tuning_info->gain_map.buffers[2] != 0 && tuning_info->gain_map.buffers[3] != 0 )
+ {
+ dng_opcode_list &opcodelist2 = negative->OpcodeList2 ();
+
+ dng_stream gain_map_stream0 (tuning_info->gain_map.buffers[0], gain_map_size);
+ AutoPtr<dng_opcode> gain_map_opcode0 ( new dng_opcode_GainMap ( host, gain_map_stream0 ));
+ opcodelist2.Append( gain_map_opcode0 );
+
+ dng_stream gain_map_stream1 (tuning_info->gain_map.buffers[1], gain_map_size);
+ AutoPtr<dng_opcode> gain_map_opcode1 ( new dng_opcode_GainMap ( host, gain_map_stream1 ));
+ opcodelist2.Append( gain_map_opcode1 );
+
+ dng_stream gain_map_stream2 (tuning_info->gain_map.buffers[2], gain_map_size);
+ AutoPtr<dng_opcode> gain_map_opcode2 ( new dng_opcode_GainMap ( host, gain_map_stream2 ));
+ opcodelist2.Append( gain_map_opcode2 );
+
+ dng_stream gain_map_stream3 (tuning_info->gain_map.buffers[3], gain_map_size);
+ AutoPtr<dng_opcode> gain_map_opcode3 ( new dng_opcode_GainMap ( host, gain_map_stream3 ));
+ opcodelist2.Append( gain_map_opcode3 );
+ }
+
+ // WarpRectilinear - aka chromatic aberration correction (applied after demosaicking (OpcodeList3))
+ if ( tuning_info->warp_red_coefficient > 0 && tuning_info->warp_blue_coefficient > 0 )
+ {
+ dng_opcode_list &opcodelist3 = negative->OpcodeList3 ();
+
+ dng_warp_params_rectilinear chromatic_aberration;
+
+ chromatic_aberration.fPlanes = 3;
+ chromatic_aberration.fCenter = dng_point_real64( 0.5, 0.5 );
+ chromatic_aberration.fRadParams[0][0] = tuning_info->warp_red_coefficient;
+ chromatic_aberration.fRadParams[1][0] = 1.0;
+ chromatic_aberration.fRadParams[2][0] = tuning_info->warp_blue_coefficient;
+
+ AutoPtr<dng_opcode> warp_opcode ( new dng_opcode_WarpRectilinear ( chromatic_aberration, 0x03 ));
+
+ opcodelist3.Append( warp_opcode );
+ }
+ }
+
+ //GP!! NEED outputWidth, activeWidth, outputHeight, activeHeight here
+ negative->SetDefaultScale(dng_urational(outputWidth, activeWidth), dng_urational(outputHeight, activeHeight));
+
+ uint32 crop_size_val = 0;
+ dng_point crop_origin( 0, 0 );
+ dng_point crop_size( activeHeight - 2 * crop_size_val, activeWidth - 2 * crop_size_val );
+
+ negative->SetDefaultCropOrigin( crop_origin.h, crop_origin.v );
+ negative->SetDefaultCropSize( crop_size.h, crop_size.v );
+
+ negative->SetOriginalDefaultCropSize( dng_urational(crop_size.h, 1), dng_urational(crop_size.v, 1) );
+
+ {
+ dng_rect activeArea = dng_rect(activeHeight, activeWidth);
+
+ negative->SetActiveArea(activeArea);
+ }
+
+ char camera_make_and_model[256];
+
+ gpr_exif_info_get_camera_make_and_model(exif_info, camera_make_and_model);
+
+ negative->SetModelName( camera_make_and_model );
+
+ negative->SetLocalName( camera_make_and_model );
+
+ //GP!! "Raw file?"
+ negative->SetOriginalRawFileName("RAW FILE");
+ //GP!! Either 1 or 3
+ negative->SetColorChannels(3);
+
+ //!! Need correct CFA sequence here!!
+ ColorKeyCode colorCodes[4] = { colorKeyRed, colorKeyGreen, colorKeyBlue, colorKeyGreen };
+ // ColorKeyCode colorCodes[4] = { colorKeyGreen, colorKeyRed, colorKeyGreen, colorKeyBlue };
+
+ negative->SetColorKeys(colorCodes[0], colorCodes[1], colorCodes[2], colorCodes[3]);
+
+ // Set Bayer Pattern
+ if( convert_params->tuning_info.pixel_format == PIXEL_FORMAT_RGGB_12 || convert_params->tuning_info.pixel_format == PIXEL_FORMAT_RGGB_12P || convert_params->tuning_info.pixel_format == PIXEL_FORMAT_RGGB_14 )
+ {
+ negative->SetBayerMosaic(1);
+ }
+ else if( convert_params->tuning_info.pixel_format == PIXEL_FORMAT_GBRG_12 || convert_params->tuning_info.pixel_format == PIXEL_FORMAT_GBRG_12P )
+ {
+ negative->SetBayerMosaic(3);
+ }
+ else
+ {
+ assert(0);
+ return;
+ }
+
+ negative->SetBaselineExposure(0);
+ negative->SetBaselineNoise(1.0);
+ negative->SetBaselineSharpness(1.0);
+
+ negative->SetAntiAliasStrength(dng_urational(100, 100));
+ negative->SetLinearResponseLimit(1.0);
+ negative->SetShadowScale( dng_urational(1, 1) );
+ negative->SetAnalogBalance(dng_vector_3(1.0, 1.0, 1.0));
+
+ AutoPtr<dng_camera_profile> prof(new dng_camera_profile);
+ prof->SetName( camera_make_and_model );
+
+ dng_matrix_3by3 mColor1;
+ dng_matrix_3by3 mColor2;
+
+ if ( profile_info->compute_color_matrix )
+ {
+ double matrix_weighting = profile_info->matrix_weighting;
+
+ double out_matrix[3][3];
+
+ if ( matrix_weighting < 0.0 || matrix_weighting > 1.0 )
+ matrix_weighting = 1.0;
+
+ calc_color_matrix( profile_info->cam_to_srgb_1, profile_info->wb1, matrix_weighting, out_matrix );
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ mColor1[i][j] = out_matrix[i][j];
+
+ calc_color_matrix( profile_info->cam_to_srgb_2, profile_info->wb2, matrix_weighting, out_matrix );
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ mColor2[i][j] = out_matrix[i][j];
+ }
+ else
+ {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ {
+ mColor1[i][j] = profile_info->color_matrix_1[i][j];
+ mColor2[i][j] = profile_info->color_matrix_2[i][j];
+ }
+ }
+
+#if PRINT_MATRIX
+ LogPrint("CM1:");
+ for (i = 0; i < 3; i++)
+ LogPrint(" %8.5f %8.5f %8.5f", mColor1[i][0], mColor1[i][1], mColor1[i][2] );
+ LogPrint("CM2:");
+ for (i = 0; i < 3; i++)
+ LogPrint(" %8.5f %8.5f %8.5f", mColor2[i][0], mColor2[i][1], mColor2[i][2] );
+#endif
+
+ prof->SetColorMatrix1((dng_matrix) mColor1);
+ prof->SetColorMatrix2((dng_matrix) mColor2);
+
+ prof->SetCalibrationIlluminant1(profile_info->illuminant1);
+ prof->SetCalibrationIlluminant2(profile_info->illuminant2);
+
+ negative->AddProfile(prof);
+
+ dng_exif* const exif = negative->GetExif();
+ exif->fModel.Set( exif_info->camera_model );
+ exif->fMake.Set( exif_info->camera_make );
+
+ convert_dng_exif_info_to_dng_exif(exif, exif_info );
+
+ {
+ dng_date_time_info date_time_original;
+ date_time_original.SetDateTime( convert_to_dng_date_time( exif_info->date_time_original ) );
+
+ negative->UpdateDateTime(date_time_original);
+ }
+
+ if( convert_params->gpmf_payload.buffer != NULL && convert_params->gpmf_payload.size > 0 )
+ { // Set GPMF Data
+ dng_string gopro_tag;
+ gopro_tag.Append("GoPro\n");
+
+ AutoPtr<dng_memory_block> gpmf_buffer;
+
+ gpmf_buffer.Reset (host.Allocate(gopro_tag.Length() + convert_params->gpmf_payload.size) );
+
+ unsigned char* gpmf_buffer_ptr = (unsigned char*)gpmf_buffer.Get()->Buffer();
+
+ memcpy( gpmf_buffer_ptr + 0, gopro_tag.Get(), gopro_tag.Length() );
+ memcpy( gpmf_buffer_ptr + gopro_tag.Length(), convert_params->gpmf_payload.buffer, convert_params->gpmf_payload.size );
+
+ negative->SetPrivateData(gpmf_buffer);
+ }
+
+ negative->SetStage1Image(image);
+
+ dng_preview_list* preview_list = NULL;
+
+ dng_image_writer* writer = NULL;
+
+#if GPR_WRITING
+ if( vc5_dng )
+ {
+ gpr_image_writer* gpr_writer = new gpr_image_writer(raw_image_buffer, convert_params->input_width, convert_params->input_height, convert_params->input_pitch, vc5_image_buffer );
+ set_vc5_encoder_parameters( gpr_writer->GetVc5EncoderParams(), convert_params );
+
+ gpr_writer->EncodeVc5Image();
+
+ if( convert_params->enable_preview )
+ {
+ const gpr_preview_image& preview_image = convert_params->preview_image;
+
+ if( preview_image.jpg_preview.size > 0 && preview_image.jpg_preview.buffer != NULL )
+ {
+ preview_list = new dng_preview_list;
+
+ AutoPtr<dng_jpeg_preview> jpeg_preview;
+ jpeg_preview.Reset(new dng_jpeg_preview);
+ jpeg_preview->fPhotometricInterpretation = piYCbCr;
+
+ jpeg_preview->fInfo.fIsPrimary = true;
+
+ jpeg_preview->fPreviewSize.v = preview_image.preview_height;
+ jpeg_preview->fPreviewSize.h = preview_image.preview_width;
+ jpeg_preview->fCompressedData.Reset(host.Allocate( preview_image.jpg_preview.size ));
+ memcpy( jpeg_preview->fCompressedData->Buffer_char(), preview_image.jpg_preview.buffer, preview_image.jpg_preview.size );
+
+ AutoPtr<dng_preview> pp( dynamic_cast<dng_preview*>(jpeg_preview.Release()) );
+
+ preview_list->Append(pp);
+ }
+#if GPR_JPEG_AVAILABLE
+ else
+ {
+ preview_list = new dng_preview_list;
+
+ AutoPtr<dng_jpeg_preview> jpeg_preview;
+ jpeg_preview.Reset(new dng_jpeg_preview);
+ jpeg_preview->fPhotometricInterpretation = piYCbCr;
+
+ jpeg_preview->fInfo.fIsPrimary = true;
+
+ const gpr_rgb_buffer& rgb_buffer = gpr_writer->get_rgb_thumbnail();
+
+ gpr_buffer_auto buffer( allocator->Alloc, allocator->Free );
+
+ buffer.allocate(1024*1024);
+
+ jpg_write_context context;
+ context.orig_dst = buffer.to_uchar();
+ context.next_dst = context.orig_dst;
+
+ tje_encode_with_func(write_jpg_thumbnail, (void*)&context, 2, rgb_buffer.width, rgb_buffer.height, 3, (const unsigned char*)rgb_buffer.buffer );
+
+ size_t size = context.next_dst - context.orig_dst;
+ jpeg_preview->fPreviewSize.v = rgb_buffer.height;
+ jpeg_preview->fPreviewSize.h = rgb_buffer.width;
+ jpeg_preview->fCompressedData.Reset(host.Allocate( size ));
+ memcpy( jpeg_preview->fCompressedData->Buffer_char(), buffer.get_buffer(), size );
+
+ AutoPtr<dng_preview> pp( dynamic_cast<dng_preview*>(jpeg_preview.Release()) );
+
+ preview_list->Append(pp);
+ }
+#endif
+ }
+
+ writer = gpr_writer;
+ }
+ else
+#endif
+ {
+ writer = new dng_image_writer;
+ }
+
+ writer->SetComputeMd5Sum( convert_params->compute_md5sum );
+
+ assert(writer);
+ writer->WriteDNG(host, *dng_write_stream, *negative.Get(), preview_list, dngVersion_Current, vc5_dng == false );
+
+ delete writer;
+
+ if( preview_list )
+ delete preview_list;
+}
+
+extern dng_memory_allocator gDefaultDNGMemoryAllocator;
+
+bool write_dngstream_to_buffer( dng_stream* stream, gpr_buffer* output_buffer, gpr_malloc mem_alloc, gpr_free mem_free )
+{
+ size_t buffer_size = stream->Length();
+ void* buffer = mem_alloc(buffer_size);
+
+ stream->SetReadPosition(0);
+ stream->Get(buffer, buffer_size);
+
+ output_buffer->buffer = buffer;
+ output_buffer->size = buffer_size;
+
+ return true;
+}
+
+bool gpr_parse_metadata(const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer,
+ gpr_parameters* parameters)
+{
+ dng_memory_stream inp_dng_stream( gDefaultDNGMemoryAllocator );
+ inp_dng_stream.Put( inp_dng_buffer->buffer, inp_dng_buffer->size );
+ inp_dng_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_dng_stream, NULL, NULL, parameters ) == false )
+ {
+ assert(0); return false;
+ }
+
+ return true;
+}
+
+bool gpr_convert_raw_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_raw_buffer,
+ gpr_buffer* out_dng_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+ raw_buffer.set( (char*)inp_raw_buffer->buffer, inp_raw_buffer->size );
+
+ dng_memory_stream out_dng_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_dng_stream, &raw_buffer, false, NULL, parameters );
+
+ write_dngstream_to_buffer( &out_dng_stream, out_dng_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_dng_to_raw(const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_raw_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_dng_stream( gDefaultDNGMemoryAllocator );
+ inp_dng_stream.Put( inp_dng_buffer->buffer, inp_dng_buffer->size );
+ inp_dng_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_dng_stream, &raw_buffer, NULL ) == false )
+ {
+ assert(0); return false;
+ }
+
+ out_raw_buffer->buffer = allocator->Alloc( raw_buffer.get_size() );
+ out_raw_buffer->size = raw_buffer.get_size();
+
+ memcpy(out_raw_buffer->buffer, raw_buffer.get_buffer(), raw_buffer.get_size() );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+//!< dng to raw conversion
+bool gpr_convert_dng_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_dng_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_dng_stream( gDefaultDNGMemoryAllocator );
+ inp_dng_stream.Put( inp_dng_buffer->buffer, inp_dng_buffer->size );
+ inp_dng_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_dng_stream, &raw_buffer, NULL ) == false )
+ {
+ assert(0); return false;
+ }
+
+ dng_memory_stream out_dng_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_dng_stream, &raw_buffer, false, NULL, parameters );
+
+ write_dngstream_to_buffer( &out_dng_stream, out_dng_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_vc5_to_gpr(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_vc5_buffer,
+ gpr_buffer* out_gpr_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto vc5_buffer(allocator->Alloc, allocator->Free);
+ vc5_buffer.set( (char*)inp_vc5_buffer->buffer, inp_vc5_buffer->size );
+
+ dng_memory_stream out_gpr_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_gpr_stream, NULL, false, &vc5_buffer, parameters );
+
+ write_dngstream_to_buffer( &out_gpr_stream, out_gpr_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_gpr_to_vc5(const gpr_allocator* allocator,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_buffer* out_vc5_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto vc5_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_gpr_stream( gDefaultDNGMemoryAllocator );
+ inp_gpr_stream.Put( inp_gpr_buffer->buffer, inp_gpr_buffer->size );
+ inp_gpr_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_gpr_stream, NULL, &vc5_buffer ) == false )
+ {
+ assert(0); return false;
+ }
+
+ if( vc5_buffer.is_valid() == false )
+ {
+ return false;
+ }
+
+ out_vc5_buffer->buffer = allocator->Alloc( vc5_buffer.get_size() );
+ out_vc5_buffer->size = vc5_buffer.get_size();
+ memcpy(out_vc5_buffer->buffer, vc5_buffer.get_buffer(), vc5_buffer.get_size() );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+#if GPR_WRITING
+
+bool gpr_convert_raw_to_gpr(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_raw_buffer,
+ gpr_buffer* out_gpr_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+
+ raw_buffer.set(inp_raw_buffer->buffer, inp_raw_buffer->size);
+
+ dng_memory_stream out_gpr_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_gpr_stream, &raw_buffer, true, NULL, parameters );
+
+ write_dngstream_to_buffer( &out_gpr_stream, out_gpr_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_dng_to_gpr(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_gpr_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_dng_stream( gDefaultDNGMemoryAllocator );
+ inp_dng_stream.Put( inp_dng_buffer->buffer, inp_dng_buffer->size );
+ inp_dng_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_dng_stream, &raw_buffer, NULL, NULL ) == false )
+ {
+ assert(0); return false;
+ }
+
+ dng_memory_stream out_gpr_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_gpr_stream, &raw_buffer, true, NULL, parameters );
+
+ write_dngstream_to_buffer( &out_gpr_stream, out_gpr_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_dng_to_vc5(const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_vc5_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+ gpr_buffer_auto vc5_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_dng_stream( gDefaultDNGMemoryAllocator );
+ inp_dng_stream.Put( inp_dng_buffer->buffer, inp_dng_buffer->size );
+ inp_dng_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_dng_stream, &raw_buffer, NULL ) == false )
+ {
+ assert(0); return false;
+ }
+
+ out_vc5_buffer->buffer = allocator->Alloc( vc5_buffer.get_size() );
+ out_vc5_buffer->size = vc5_buffer.get_size();
+
+ memcpy(out_vc5_buffer->buffer, vc5_buffer.get_buffer(), vc5_buffer.get_size() );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+#endif // GPR_WRITING
+
+#if GPR_READING
+
+bool gpr_convert_gpr_to_rgb(const gpr_allocator* allocator,
+ GPR_RGB_RESOLUTION rgb_resolution,
+ int rgb_bits,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_rgb_buffer* out_rgb_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_parameters params;
+
+ gpr_buffer_auto vc5_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_gpr_stream( gDefaultDNGMemoryAllocator );
+ inp_gpr_stream.Put( inp_gpr_buffer->buffer, inp_gpr_buffer->size );
+ inp_gpr_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_gpr_stream, NULL, &vc5_buffer, &params ) == false )
+ {
+ assert(0); return false;
+ }
+
+ if( vc5_buffer.is_valid() == false )
+ {
+ return false;
+ }
+
+ vc5_decoder_parameters vc5_decoder_params;
+
+ vc5_decoder_parameters_set_default(&vc5_decoder_params);
+
+ vc5_decoder_params.mem_alloc = allocator->Alloc;
+ vc5_decoder_params.mem_free = allocator->Free;
+ vc5_decoder_params.pixel_format = VC5_DECODER_PIXEL_FORMAT_DEFAULT;
+
+ vc5_decoder_params.rgb_bits = rgb_bits;
+
+ gpr_rgb_gain& rgb_gain = vc5_decoder_params.rgb_gain;
+
+ find_rational( params.tuning_info.wb_gains.r_gain, 0.125, &rgb_gain.r_gain_num, &rgb_gain.r_gain_pow2_den );
+ find_rational( params.tuning_info.wb_gains.g_gain, 0.125, &rgb_gain.g_gain_num, &rgb_gain.g_gain_pow2_den );
+ find_rational( params.tuning_info.wb_gains.b_gain, 0.125, &rgb_gain.b_gain_num, &rgb_gain.b_gain_pow2_den );
+
+ vc5_decoder_params.rgb_resolution = rgb_resolution;
+
+ if( vc5_decoder_process( &vc5_decoder_params, &vc5_buffer.get_gpr_buffer(), NULL, out_rgb_buffer ) != CODEC_ERROR_OKAY )
+ {
+ assert(0);
+ }
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_gpr_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_buffer* out_dng_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+ gpr_buffer_auto vc5_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_gpr_stream( gDefaultDNGMemoryAllocator );
+ inp_gpr_stream.Put( inp_gpr_buffer->buffer, inp_gpr_buffer->size );
+ inp_gpr_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_gpr_stream, &raw_buffer, &vc5_buffer, NULL ) == false )
+ {
+ assert(0); return false;
+ }
+
+ dng_memory_stream out_dng_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_dng_stream, &raw_buffer, false, NULL, parameters );
+
+ write_dngstream_to_buffer( &out_dng_stream, out_dng_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_vc5_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_vc5_buffer,
+ gpr_buffer* out_dng_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto vc5_buffer( allocator->Alloc, allocator->Free );
+
+ vc5_buffer.set(inp_vc5_buffer->buffer, inp_vc5_buffer->size);
+
+ dng_memory_stream out_dng_stream( gDefaultDNGMemoryAllocator );
+
+ write_dng( allocator, &out_dng_stream, NULL, false, &vc5_buffer, parameters );
+
+ write_dngstream_to_buffer( &out_dng_stream, out_dng_buffer, allocator->Alloc, allocator->Free );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+bool gpr_convert_gpr_to_raw(const gpr_allocator* allocator,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_buffer* out_raw_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+
+ dng_memory_stream inp_gpr_stream( gDefaultDNGMemoryAllocator );
+ inp_gpr_stream.Put( inp_gpr_buffer->buffer, inp_gpr_buffer->size );
+ inp_gpr_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_gpr_stream, &raw_buffer, NULL ) == false )
+ {
+ assert(0); return false;
+ }
+
+ out_raw_buffer->buffer = allocator->Alloc( raw_buffer.get_size() );
+ out_raw_buffer->size = raw_buffer.get_size();
+
+ memcpy(out_raw_buffer->buffer, raw_buffer.get_buffer(), raw_buffer.get_size() );
+
+ TIMESTAMP("[END]", 1)
+
+ return true;
+}
+
+#endif // GPR_READING
+
+bool gpr_check_vc5( const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer)
+{
+ TIMESTAMP("[BEG]", 1)
+
+ gpr_buffer_auto raw_buffer(allocator->Alloc, allocator->Free);
+ gpr_buffer_auto vc5_buffer(allocator->Alloc, allocator->Free);
+ bool is_vc5_format = false;
+
+ {
+ dng_memory_stream inp_dng_stream( gDefaultDNGMemoryAllocator );
+ inp_dng_stream.Put( inp_dng_buffer->buffer, inp_dng_buffer->size );
+ inp_dng_stream.SetReadPosition(0);
+
+ if( read_dng( allocator, &inp_dng_stream, &raw_buffer, &vc5_buffer, NULL, &is_vc5_format ) == false )
+ {
+ assert(0); return -1;
+ }
+ }
+
+ TIMESTAMP("[END]", 1)
+
+ return is_vc5_format;
+}
+
+
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_exif_info.cpp b/gpr/source/lib/gpr_sdk/private/gpr_exif_info.cpp
new file mode 100755
index 0000000..4b1e9bc
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_exif_info.cpp
@@ -0,0 +1,105 @@
+
+#include "gpr_platform.h"
+#include "gpr_exif_info.h"
+#include "stdc_includes.h"
+
+static gpr_signed_rational signed_rational_construct(int32_t numerator, int32_t denominator)
+{
+ gpr_signed_rational a;
+ a.numerator = numerator;
+ a.denominator = denominator;
+ return a;
+}
+
+static gpr_unsigned_rational unsigned_rational_construct(int32_t numerator, int32_t denominator)
+{
+ gpr_unsigned_rational a;
+ a.numerator = numerator;
+ a.denominator = denominator;
+ return a;
+}
+
+gpr_date_and_time construct_dng_date_and_time (uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute, uint32_t second)
+{
+ gpr_date_and_time x;
+ x.year = year;
+ x.month = month;
+ x.day = day;
+ x.hour = hour;
+ x.minute = minute;
+ x.second = second;
+
+ return x;
+}
+
+void gpr_exif_info_set_defaults( gpr_exif_info* x )
+{
+ x->exposure_time = unsigned_rational_construct(1, 60);
+
+ x->exposure_bias = signed_rational_construct( 0, 1 );
+
+ double d_aperture = 2.8;
+
+ x->f_stop_number = unsigned_rational_construct( (unsigned int)(d_aperture * 1000), 1000 );
+
+ // Convert aperture to APEX
+ double aperture_apex = log(d_aperture) / log(sqrt(2.0));
+
+ x->aperture = unsigned_rational_construct( (unsigned int)(aperture_apex * 1000), 1000 );
+
+ x->focal_length = unsigned_rational_construct(3, 1);
+
+ x->digital_zoom = unsigned_rational_construct(1, 1);
+
+ x->metering_mode = gpr_metering_mode_center_weighted_average;
+
+ x->focal_length_in_35mm_film = 15;
+
+ x->exposure_program = gpr_exposure_program_normal;
+
+ x->light_source = gpr_light_source_auto;
+
+ x->flash = gpr_flash_not_supported;
+
+ x->sensing_method = gpr_sensing_method_chip_color_area;
+
+ x->file_source = gpr_file_source_digital_still;
+
+ x->scene_type = gpr_scene_type_directly_photographed;
+
+ x->white_balance = gpr_white_balance_auto;
+
+ x->exposure_mode = gpr_exposure_mode_auto;
+
+ x->scene_capture_type = gpr_scene_capture_type_standard;
+
+ x->gain_control = gpr_gain_control_normal;
+
+ x->contrast = gpr_contrast_normal;
+
+ x->saturation = gpr_saturation_normal;
+
+ x->sharpness = gpr_sharpness_hard;
+
+ x->iso_speed_rating = 232;
+
+ x->date_time_original = construct_dng_date_and_time (2016, 03, 25, 15, 55, 23 );
+
+ x->date_time_digitized = x->date_time_original;
+
+ strcpy( x->camera_make, "GoPro" );
+
+ strcpy( x->camera_model, "HERO6 Black" );
+
+ sprintf( x->software_version, "%d.%d.%d", GPR_VERSION_MAJOR, GPR_VERSION_MINOR, GPR_VERSION_REVISION );
+
+ strcpy( x->user_comment, "" );
+}
+
+void gpr_exif_info_get_camera_make_and_model( const gpr_exif_info* x, char camera_make_and_model[256] )
+{
+ strcpy(camera_make_and_model, x->camera_make );
+ strcpy(camera_make_and_model + strlen(camera_make_and_model), " " );
+ strcpy(camera_make_and_model + strlen(camera_make_and_model), x->camera_model );
+}
+
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_image_writer.cpp b/gpr/source/lib/gpr_sdk/private/gpr_image_writer.cpp
new file mode 100755
index 0000000..891f66d
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_image_writer.cpp
@@ -0,0 +1,129 @@
+
+#include "gpr_image_writer.h"
+
+#include "dng_camera_profile.h"
+#include "dng_color_space.h"
+#include "dng_date_time.h"
+#include "dng_exceptions.h"
+#include "dng_file_stream.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image_writer.h"
+#include "dng_info.h"
+#include "dng_linearization_info.h"
+#include "dng_mosaic_info.h"
+#include "dng_negative.h"
+#include "dng_preview.h"
+#include "dng_render.h"
+#include "dng_simple_image.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_xmp.h"
+#include "dng_xmp_sdk.h"
+#include "dng_memory_stream.h"
+#include "dng_bottlenecks.h"
+
+#if GPR_WRITING
+#include "vc5_encoder.h"
+#endif
+
+#include "gpr_utils.h"
+
+#if GPR_WRITING
+
+gpr_image_writer::gpr_image_writer(const gpr_buffer_auto* raw_buffer,
+ unsigned int raw_buffer_width,
+ unsigned int raw_buffer_height,
+ size_t raw_buffer_pitch,
+ gpr_buffer_auto* vc5_buffer
+ ) : _vc5_buffer_obj( raw_buffer->get_malloc(), raw_buffer->get_free() ),
+ _vc5_buffer(vc5_buffer),
+ _raw_buffer(raw_buffer)
+{
+ if( _vc5_buffer == NULL )
+ {
+ _vc5_buffer = &_vc5_buffer_obj;
+ }
+
+ _rgb_thumbnail.buffer = NULL;
+ _rgb_thumbnail.size = 0;
+
+ vc5_encoder_parameters_set_default(&vc5_encoder_params);
+}
+
+gpr_image_writer::~gpr_image_writer()
+{
+ if( _rgb_thumbnail.buffer )
+ {
+ assert( _rgb_thumbnail.size > 0 );
+
+ _raw_buffer->get_free()(_rgb_thumbnail.buffer);
+ _rgb_thumbnail.buffer = NULL;
+ _rgb_thumbnail.size = 0;
+ }
+}
+
+
+void gpr_image_writer::EncodeVc5Image()
+{
+ if( _vc5_buffer->is_valid() == false )
+ {
+
+ gpr_buffer raw_image = { _raw_buffer->get_buffer(), _raw_buffer->get_size() };
+ gpr_buffer vc5_image = { _vc5_buffer->get_buffer(), _vc5_buffer->get_size() };
+
+ if( vc5_encoder_process( &vc5_encoder_params, &raw_image, &vc5_image, &_rgb_thumbnail ) != CODEC_ERROR_OKAY )
+ {
+ assert(0);
+ }
+
+ _vc5_buffer->set( vc5_image.buffer, vc5_image.size, true );
+ }
+}
+
+void gpr_image_writer::WriteImage (dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels)
+{
+ dng_image_writer::WriteImage ( host, ifd, basic, stream, image, fakeChannels);
+}
+
+uint32 gpr_image_writer::CompressedBufferSize (const dng_ifd &ifd, uint32 uncompressedSize)
+{
+ if( ifd.fCompression == ccVc5 )
+ {
+ return _vc5_buffer->get_size();
+ }
+ else
+ {
+ return dng_image_writer::CompressedBufferSize( ifd, uncompressedSize );
+ }
+}
+
+void gpr_image_writer::WriteTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ const dng_image &image,
+ const dng_rect &tileArea,
+ uint32 fakeChannels,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer)
+{
+ if( ifd.fCompression == ccVc5 )
+ {
+ stream.Put( _vc5_buffer->get_buffer(), _vc5_buffer->get_size() );
+ }
+ else
+ {
+ return dng_image_writer::WriteTile( host, ifd, stream, image, tileArea, fakeChannels, compressedBuffer, uncompressedBuffer, subTileBlockBuffer, tempBuffer );
+ }
+}
+
+#endif // GPR_WRITING
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_image_writer.h b/gpr/source/lib/gpr_sdk/private/gpr_image_writer.h
new file mode 100755
index 0000000..bb07c60
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_image_writer.h
@@ -0,0 +1,87 @@
+/*! @file gpr_image_writer.h
+ *
+ * @brief Declaration of gpr_image_writer class
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_IMAGE_WRITER
+#define GPR_IMAGE_WRITER
+
+#include "dng_image_writer.h"
+#include "gpr_buffer_auto.h"
+
+#if GPR_WRITING
+
+#include "vc5_encoder.h"
+
+class gpr_image_writer : public dng_image_writer
+{
+private:
+
+ gpr_buffer_auto _vc5_buffer_obj;
+
+ gpr_rgb_buffer _rgb_thumbnail;
+
+ gpr_buffer_auto* _vc5_buffer;
+ const gpr_buffer_auto* _raw_buffer;
+
+ vc5_encoder_parameters vc5_encoder_params;
+
+public:
+
+ void EncodeVc5Image();
+
+ const gpr_rgb_buffer& get_rgb_thumbnail() { return _rgb_thumbnail; }
+
+ vc5_encoder_parameters& GetVc5EncoderParams() { return vc5_encoder_params; }
+
+ gpr_image_writer(const gpr_buffer_auto* raw_buffer,
+ unsigned int raw_buffer_width,
+ unsigned int raw_buffer_height,
+ size_t raw_buffer_pitch,
+ gpr_buffer_auto* vc5_buffer = NULL );
+
+ ~gpr_image_writer();
+
+ void WriteImage (dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels);
+
+ uint32 CompressedBufferSize (const dng_ifd &ifd, uint32 uncompressedSize);
+
+ uint32 GetDefaultCompression() { return ccVc5; }
+
+ void WriteTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ const dng_image &image,
+ const dng_rect &tileArea,
+ uint32 fakeChannels,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer);
+
+};
+
+#endif // GPR_WRITING
+
+#endif // GPR_IMAGE_WRITER
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_profile_info.cpp b/gpr/source/lib/gpr_sdk/private/gpr_profile_info.cpp
new file mode 100755
index 0000000..93ad542
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_profile_info.cpp
@@ -0,0 +1,57 @@
+
+#include "gpr_profile_info.h"
+#include "stdc_includes.h"
+
+void gpr_profile_info_set_defaults(gpr_profile_info* x)
+{
+ x->compute_color_matrix = true;
+
+ x->matrix_weighting = 1.0;
+
+ x->illuminant1 = 3; // tungsten
+ x->illuminant2 = 23; // d50
+
+ x->wb1[0] = 1.339600;
+ x->wb1[1] = 1.00000;
+ x->wb1[2] = 2.780029;
+
+ x->wb2[0] = 1.9036;
+ x->wb2[1] = 1.00000;
+ x->wb2[2] = 1.7483;
+
+ {
+ const double cam_to_srgb[] = { 1.2963, -0.2025, -0.0939, -0.4789, 1.5728, -0.0939, -0.1007, -0.7605, 1.8612 };
+
+ x->cam_to_srgb_1[0][0] = cam_to_srgb[0];
+ x->cam_to_srgb_1[0][1] = cam_to_srgb[1];
+ x->cam_to_srgb_1[0][2] = cam_to_srgb[2];
+
+ x->cam_to_srgb_1[1][0] = cam_to_srgb[3];
+ x->cam_to_srgb_1[1][1] = cam_to_srgb[4];
+ x->cam_to_srgb_1[1][2] = cam_to_srgb[5];
+
+ x->cam_to_srgb_1[2][0] = cam_to_srgb[6];
+ x->cam_to_srgb_1[2][1] = cam_to_srgb[7];
+ x->cam_to_srgb_1[2][2] = cam_to_srgb[8];
+ }
+
+ {
+ const double cam_to_srgb[] = { 1.5580, -0.3019, -0.2561, -0.3023, 1.6328, -0.3305, -0.0365, -0.5127, 1.5492 };
+
+ x->cam_to_srgb_2[0][0] = cam_to_srgb[0];
+ x->cam_to_srgb_2[0][1] = cam_to_srgb[1];
+ x->cam_to_srgb_2[0][2] = cam_to_srgb[2];
+
+ x->cam_to_srgb_2[1][0] = cam_to_srgb[3];
+ x->cam_to_srgb_2[1][1] = cam_to_srgb[4];
+ x->cam_to_srgb_2[1][2] = cam_to_srgb[5];
+
+ x->cam_to_srgb_2[2][0] = cam_to_srgb[6];
+ x->cam_to_srgb_2[2][1] = cam_to_srgb[7];
+ x->cam_to_srgb_2[2][2] = cam_to_srgb[8];
+ }
+
+ memset( x->color_matrix_1, 0, sizeof(x->color_matrix_1) );
+ memset( x->color_matrix_2, 0, sizeof(x->color_matrix_2) );
+}
+
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_read_image.cpp b/gpr/source/lib/gpr_sdk/private/gpr_read_image.cpp
new file mode 100755
index 0000000..84c2fe9
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_read_image.cpp
@@ -0,0 +1,129 @@
+
+#include "gpr_read_image.h"
+
+#include "dng_camera_profile.h"
+#include "dng_color_space.h"
+#include "dng_date_time.h"
+#include "dng_exceptions.h"
+#include "dng_file_stream.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image_writer.h"
+#include "dng_info.h"
+#include "dng_linearization_info.h"
+#include "dng_mosaic_info.h"
+#include "dng_negative.h"
+#include "dng_preview.h"
+#include "dng_render.h"
+#include "dng_simple_image.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_xmp.h"
+#include "dng_xmp_sdk.h"
+#include "dng_memory_stream.h"
+#include "dng_bottlenecks.h"
+
+#include "gpr_utils.h"
+
+#if GPR_READING
+
+#include "vc5_decoder.h"
+
+static bool DecodeVC5(dng_image &image, gpr_buffer_auto& vc5_buffer, VC5_DECODER_PIXEL_FORMAT pixel_format )
+{
+ gpr_buffer_auto raw_buffer( malloc, free );
+
+ vc5_decoder_parameters vc5_decoder_params;
+
+ vc5_decoder_parameters_set_default(&vc5_decoder_params);
+
+ vc5_decoder_params.mem_alloc = raw_buffer.get_malloc();
+ vc5_decoder_params.mem_free = raw_buffer.get_free();
+ vc5_decoder_params.pixel_format = pixel_format;
+
+ gpr_buffer vc5_image = { vc5_buffer.get_buffer(), vc5_buffer.get_size() };
+ gpr_buffer raw_image = { raw_buffer.get_buffer(), raw_buffer.get_size() };
+
+ if( vc5_decoder_process( &vc5_decoder_params, &vc5_image, &raw_image, NULL ) != CODEC_ERROR_OKAY )
+ {
+ assert(0);
+ return false;
+ }
+
+ raw_buffer.set( raw_image.buffer, raw_image.size, true );
+
+ dng_point size = image.Bounds().Size();
+
+ CopyBufferToRawImage( raw_buffer, size.h, image );
+
+ return true;
+}
+
+gpr_read_image::gpr_read_image( gpr_buffer_auto* vc5_buffer ) : _vc5_buffer(vc5_buffer)
+{
+ fReadVC5 = true;
+ fDecodeVC5 = true;
+}
+
+void gpr_read_image::ReadTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
+{
+
+ if( ifd.fCompression == ccVc5 )
+ {
+ if( GetReadVC5() && _vc5_buffer != NULL )
+ {
+ _vc5_buffer->allocate( tileByteCount );
+
+ stream.Get(_vc5_buffer->get_buffer(), _vc5_buffer->get_size() );
+
+ if( GetDecodeVC5() == true )
+ {
+ bool rggb_raw = (ifd.fCFAPattern[0][0] == 0) && (ifd.fCFAPattern[0][1] == 1) && (ifd.fCFAPattern[1][0] == 1) && (ifd.fCFAPattern[1][1] == 2);
+
+ VC5_DECODER_PIXEL_FORMAT pixel_format;
+
+ if( rggb_raw )
+ {
+ pixel_format = VC5_DECODER_PIXEL_FORMAT_RGGB_14;
+ }
+ else
+ {
+ pixel_format = VC5_DECODER_PIXEL_FORMAT_GBRG_12;
+ }
+
+ if( DecodeVC5( image, *_vc5_buffer, pixel_format ) )
+ {
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ dng_read_image::ReadTile (host,
+ ifd,
+ stream,
+ image,
+ tileArea,
+ plane,
+ planes,
+ tileByteCount,
+ compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer);
+ }
+}
+
+#endif
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_read_image.h b/gpr/source/lib/gpr_sdk/private/gpr_read_image.h
new file mode 100755
index 0000000..c8aa534
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_read_image.h
@@ -0,0 +1,64 @@
+/*! @file gpr_read_image.h
+ *
+ * @brief Declaration of gpr_read_image class
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_READ_IMAGE
+#define GPR_READ_IMAGE
+
+#include "dng_read_image.h"
+#include "gpr_buffer_auto.h"
+
+#if GPR_READING
+
+class gpr_read_image : public dng_read_image
+{
+private:
+ gpr_buffer_auto* _vc5_buffer;
+
+ bool fReadVC5;
+
+ bool fDecodeVC5;
+
+public:
+
+ gpr_read_image( gpr_buffer_auto* vc5_buffer = NULL );
+
+ void SetReadVC5(bool read_vc5) { fReadVC5 = read_vc5; }
+ bool GetReadVC5() { return fReadVC5; }
+
+ void SetDecodeVC5(bool decode_vc5) { fDecodeVC5 = decode_vc5; }
+ bool GetDecodeVC5() { return fDecodeVC5; }
+
+ void ReadTile (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_image &image,
+ const dng_rect &tileArea,
+ uint32 plane,
+ uint32 planes,
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer);
+};
+
+#endif // GPR_READING
+
+#endif // GPR_READ_IMAGE
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_tuning_info.cpp b/gpr/source/lib/gpr_sdk/private/gpr_tuning_info.cpp
new file mode 100755
index 0000000..45ff9f7
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_tuning_info.cpp
@@ -0,0 +1,84 @@
+
+#include "gpr_buffer_auto.h"
+
+#include "gpr_tuning_info.h"
+
+static void _static_black_level_set_defaults(gpr_static_black_level* x)
+{
+ const int black = 0;
+
+ x->r_black = black;
+ x->g_r_black = black;
+ x->g_b_black = black;
+ x->b_black = black;
+}
+
+static void _ae_info_set_defaults(gpr_auto_exposure_info* x)
+{
+ x->iso_value = 228;
+ x->shutter_time = 34952;
+}
+
+static void _dgain_saturation_level_set_defaults(gpr_saturation_level* x)
+{
+ const int32_t saturation_level = 16383;
+
+ x->level_red = saturation_level;
+ x->level_green_even = saturation_level;
+ x->level_green_odd = saturation_level;
+ x->level_blue = saturation_level;
+}
+
+static void _wb_gains_set_defaults(gpr_white_balance_gains* x)
+{
+ x->r_gain = (float_t)6273.0 / 4096.0;
+ x->g_gain = (float_t)4096.0 / 4096.0;
+ x->b_gain = (float_t)8371.0 / 4096.0;
+}
+
+static void _gain_map_set_defaults( gpr_tuning_info* tuning_info )
+{
+ tuning_info->gain_map.size = 0;
+
+ tuning_info->gain_map.buffers[0] = NULL;
+ tuning_info->gain_map.buffers[1] = NULL;
+ tuning_info->gain_map.buffers[2] = NULL;
+ tuning_info->gain_map.buffers[3] = NULL;
+}
+
+int32_t gpr_tuning_info_get_dgain_saturation_level(const gpr_tuning_info* x, GPR_RAW_CHANNEL channel)
+{
+ switch(channel)
+ {
+ case RAW_CHANNEL_RED:
+ return x->dgain_saturation_level.level_red;
+ case RAW_CHANNEL_GREEN_EVEN:
+ return x->dgain_saturation_level.level_green_even;
+ case RAW_CHANNEL_GREEN_ODD:
+ return x->dgain_saturation_level.level_green_odd;
+ case RAW_CHANNEL_BLUE:
+ return x->dgain_saturation_level.level_blue;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+void gpr_tuning_info_set_defaults( gpr_tuning_info* x )
+{
+ x->orientation = ORIENTATION_DEFAULT;
+
+ _static_black_level_set_defaults(&x->static_black_level);
+
+ _dgain_saturation_level_set_defaults(&x->dgain_saturation_level);
+
+ _wb_gains_set_defaults(&x->wb_gains);
+
+ _ae_info_set_defaults(&x->ae_info);
+
+ _gain_map_set_defaults( x );
+
+ x->pixel_format = PIXEL_FORMAT_RGGB_14;
+}
+
+
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_utils.cpp b/gpr/source/lib/gpr_sdk/private/gpr_utils.cpp
new file mode 100755
index 0000000..7672fde
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_utils.cpp
@@ -0,0 +1,73 @@
+
+#include "gpr_utils.h"
+
+#include "dng_camera_profile.h"
+#include "dng_color_space.h"
+#include "dng_date_time.h"
+#include "dng_exceptions.h"
+#include "dng_file_stream.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_ifd.h"
+#include "dng_image_writer.h"
+#include "dng_info.h"
+#include "dng_linearization_info.h"
+#include "dng_mosaic_info.h"
+#include "dng_negative.h"
+#include "dng_preview.h"
+#include "dng_render.h"
+#include "dng_simple_image.h"
+#include "dng_tag_codes.h"
+#include "dng_tag_types.h"
+#include "dng_tag_values.h"
+#include "dng_xmp.h"
+#include "dng_xmp_sdk.h"
+#include "dng_memory_stream.h"
+#include "dng_bottlenecks.h"
+
+#include "gpr_platform.h"
+#include "gpr_buffer_auto.h"
+
+void CopyRawImageToBuffer( const dng_image& raw_image, gpr_buffer_auto& buffer )
+{
+ dng_point size = raw_image.Bounds().Size();
+
+ const int raw_image_size = size.h * size.v * 2;
+
+ buffer.allocate( raw_image_size );
+
+ dng_pixel_buffer pixel_buffer;
+
+ pixel_buffer.fArea = dng_rect(size.v, size.h);
+ pixel_buffer.fPlane = 0;
+ pixel_buffer.fPlanes = 1;
+ pixel_buffer.fRowStep = size.h;
+ pixel_buffer.fColStep = pixel_buffer.fPlanes;
+ pixel_buffer.fPlaneStep = 1;
+ pixel_buffer.fPixelType = ttShort;
+ pixel_buffer.fPixelSize = TagTypeSize(ttShort);
+
+ pixel_buffer.fData = buffer.get_buffer();
+
+ raw_image.Get(pixel_buffer);
+}
+
+void CopyBufferToRawImage( const gpr_buffer_auto& buffer, size_t stride, dng_image& raw_image )
+{
+ dng_pixel_buffer pixel_buffer;
+
+ dng_point size = raw_image.Bounds().Size();
+
+ pixel_buffer.fArea = dng_rect(size.v, size.h);
+ pixel_buffer.fPlane = 0;
+ pixel_buffer.fPlanes = 1;
+ pixel_buffer.fRowStep = stride;
+ pixel_buffer.fColStep = pixel_buffer.fPlanes;
+ pixel_buffer.fPlaneStep = 1;
+ pixel_buffer.fPixelType = ttShort;
+ pixel_buffer.fPixelSize = TagTypeSize(ttShort);
+
+ pixel_buffer.fData = buffer.get_buffer();
+
+ raw_image.Put(pixel_buffer);
+}
diff --git a/gpr/source/lib/gpr_sdk/private/gpr_utils.h b/gpr/source/lib/gpr_sdk/private/gpr_utils.h
new file mode 100755
index 0000000..45e30f3
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/private/gpr_utils.h
@@ -0,0 +1,40 @@
+/*! @file gpr_utils.h
+ *
+ * @brief Declaration of general gpr functions that belong in gpr library
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_UTILS_H
+#define GPR_UTILS_H
+
+#include "gpr_buffer_auto.h"
+#include "dng_image.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void CopyRawImageToBuffer( const dng_image& raw_image, gpr_buffer_auto& buffer );
+
+ void CopyBufferToRawImage( const gpr_buffer_auto& buffer, size_t buffer_stride, dng_image& raw_image );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPR_UTILS_H
diff --git a/gpr/source/lib/gpr_sdk/public/gpr.h b/gpr/source/lib/gpr_sdk/public/gpr.h
new file mode 100755
index 0000000..666e727
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/public/gpr.h
@@ -0,0 +1,169 @@
+/*! @file gpr.h
+ *
+ * @brief Declaration of the GPR-SDK objects and functions
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_H
+#define GPR_H
+
+#include "gpr_platform.h"
+#include "gpr_exif_info.h"
+#include "gpr_profile_info.h"
+#include "gpr_tuning_info.h"
+#include "gpr_allocator.h"
+#include "gpr_buffer.h"
+#include "gpr_rgb_buffer.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef struct
+ {
+ gpr_buffer jpg_preview; /* Address to the memory location that this buffer points to */
+
+ unsigned int preview_width; /* Width of input source in pixels (only applies to raw input) */
+
+ unsigned int preview_height; /* Height of input source in pixels (only applies to raw input) */
+
+ } gpr_preview_image;
+
+ typedef struct
+ {
+ unsigned int input_width; /* Width of input source in pixels (only applies to raw input) */
+
+ unsigned int input_height; /* Height of input source in pixels (only applies to raw input) */
+
+ unsigned int input_pitch; /* Pitch of input source in pixels (only applies to raw input) */
+
+ bool fast_encoding;
+
+ bool compute_md5sum;
+
+ gpr_buffer gpmf_payload; /* GPMF payload of image file */
+
+ gpr_preview_image preview_image; /* Preview JPG image */
+
+ bool enable_preview;
+
+ gpr_exif_info exif_info; /* Exif info object */
+
+ gpr_profile_info profile_info; /* Camera color profile info object */
+
+ gpr_tuning_info tuning_info; /* Camera tuning info object */
+
+ } gpr_parameters;
+
+ void gpr_parameters_set_defaults(gpr_parameters* x);
+
+ void gpr_parameters_construct_copy(const gpr_parameters* y, gpr_parameters* x);
+
+ void gpr_parameters_destroy(gpr_parameters* x, gpr_free mem_free);
+
+ //!< Parse Metadata of DNG File and return in gpr_parameters struct
+ bool gpr_parse_metadata(const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer,
+ gpr_parameters* parameters);
+
+ //!< CHECK IF DNG IS VC5 COMPRESSED
+ bool gpr_check_vc5( gpr_buffer* inp_dng_buffer, gpr_malloc mem_alloc, gpr_free mem_free );
+
+ //!< CONVERSION FUNCTIONS
+
+ //!< raw to dng conversion
+ bool gpr_convert_raw_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_raw_buffer,
+ gpr_buffer* out_dng_buffer);
+
+ //!< dng to raw conversion
+ bool gpr_convert_dng_to_raw(const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_raw_buffer);
+
+ //!< dng to raw conversion
+ bool gpr_convert_dng_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_dng_buffer);
+
+ //!< vc5 to gpr conversion
+ bool gpr_convert_vc5_to_gpr(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_vc5_buffer,
+ gpr_buffer* out_gpr_buffer);
+
+ //!< gpr to vc5 conversion
+ bool gpr_convert_gpr_to_vc5(const gpr_allocator* allocator,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_buffer* out_vc5_buffer);
+
+#if GPR_WRITING
+
+ //!< raw to gpr conversion
+ bool gpr_convert_raw_to_gpr(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_raw_buffer,
+ gpr_buffer* out_gpr_buffer);
+
+ //!< dng to gpr conversion
+ bool gpr_convert_dng_to_gpr(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_gpr_buffer);
+
+ //!< dng to vc5 conversion
+ bool gpr_convert_dng_to_vc5(const gpr_allocator* allocator,
+ gpr_buffer* inp_dng_buffer,
+ gpr_buffer* out_vc5_buffer);
+#endif // GPR_WRITING
+
+
+#if GPR_READING
+
+ //!< gpr to rgb conversion
+ bool gpr_convert_gpr_to_rgb(const gpr_allocator* allocator,
+ GPR_RGB_RESOLUTION rgb_resolution,
+ int rgb_bits,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_rgb_buffer* out_rgb_buffer);
+
+ //!< gpr to dng conversion
+ bool gpr_convert_gpr_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_buffer* out_dng_buffer);
+
+ //!< vc5 to dng conversion
+ bool gpr_convert_vc5_to_dng(const gpr_allocator* allocator,
+ const gpr_parameters* parameters,
+ gpr_buffer* inp_vc5_buffer,
+ gpr_buffer* out_dng_buffer);
+
+ //!< gpr to raw conversion
+ bool gpr_convert_gpr_to_raw(const gpr_allocator* allocator,
+ gpr_buffer* inp_gpr_buffer,
+ gpr_buffer* out_raw_buffer);
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // GPR_H
diff --git a/gpr/source/lib/gpr_sdk/public/gpr_exif_info.h b/gpr/source/lib/gpr_sdk/public/gpr_exif_info.h
new file mode 100755
index 0000000..2917b25
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/public/gpr_exif_info.h
@@ -0,0 +1,352 @@
+/*! @file gpr_exif_info.h
+ *
+ * @brief Declaration of gpr_exif_info object and associated functions
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_EXIF_INFO
+#define GPR_EXIF_INFO
+
+#define CAMERA_MAKE_SIZE 32
+#define CAMERA_MODEL_SIZE 32
+#define CAMERA_SERIAL_SIZE 32
+#define SOFTWARE_VERSION_SIZE 32
+#define USER_COMMENT_SIZE 64
+#define SATELLITES_USED_SIZE 32
+#define SURVEY_DATA_SIZE 32
+#define PROCESSING_METHOD_SIZE 32
+#define AREA_INFORMATION_SIZE 32
+#define IMAGE_DESCRIPTION_SIZE 32
+
+#include "gpr_platform.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef enum
+ {
+ gpr_sensing_method_chip_color_area = 2,
+
+ } gpr_sensing_method;
+
+ typedef enum
+ {
+ gpr_file_source_digital_still = 3,
+
+ } gpr_file_source;
+
+ typedef enum
+ {
+ gpr_scene_type_directly_photographed = 1,
+
+ } gpr_scene_type;
+
+ typedef enum
+ {
+ gpr_white_balance_auto = 0,
+
+ gpr_white_balance_manual = 1,
+
+ } gpr_white_balance;
+
+ typedef enum
+ {
+ gpr_exposure_mode_auto = 0,
+
+ gpr_exposure_mode_manual = 1,
+
+ gpr_exposure_mode_auto_bracket = 2,
+
+ } gpr_exposure_mode;
+
+ typedef enum
+ {
+ gpr_scene_capture_type_standard = 0,
+
+ gpr_scene_capture_type_landscape = 1,
+
+ gpr_scene_capture_type_portrait = 2,
+
+ gpr_scene_capture_type_night = 3,
+
+ } gpr_scene_capture_type;
+
+ typedef enum
+ {
+ gpr_contrast_normal = 0,
+
+ } gpr_contrast;
+
+ typedef enum
+ {
+ gpr_gain_control_normal = 0,
+
+ } gpr_gain_control;
+
+ typedef enum
+ {
+ gpr_saturation_normal = 0,
+
+ } gpr_saturation;
+
+ typedef enum
+ {
+ gpr_sharpness_normal = 0,
+
+ gpr_sharpness_soft = 1,
+
+ gpr_sharpness_hard = 2,
+
+ } gpr_sharpness;
+
+ typedef enum
+ {
+ gpr_flash_not_used = 0,
+
+ gpr_flash_used = 1,
+
+ gpr_flash_not_supported = 32,
+
+ } gpr_flash;
+
+ typedef enum
+ {
+ gpr_exposure_program_manual_control = 1,
+
+ gpr_exposure_program_normal = 2,
+
+ gpr_exposure_program_aperture_priority = 3,
+
+ gpr_exposure_program_shutter_priority = 4,
+
+ gpr_exposure_program_creative = 5,
+
+ gpr_exposure_program_action = 6,
+
+ gpr_exposure_program_portrait_mode = 7,
+
+ gpr_exposure_program_landscape_mode = 8,
+
+ } gpr_exposure_program;
+
+ typedef enum
+ {
+ gpr_metering_mode_average = 1,
+
+ gpr_metering_mode_center_weighted_average = 2,
+
+ gpr_metering_mode_spot = 3,
+
+ gpr_metering_mode_multi_spot = 4,
+
+ gpr_metering_mode_multi_segment = 5,
+
+ } gpr_metering_mode;
+
+ typedef enum
+ {
+ gpr_light_source_auto = 0,
+
+ gpr_light_source_daylight = 1,
+
+ gpr_light_source_fuorescent = 2,
+
+ gpr_light_source_tungsten = 3,
+
+ } gpr_light_source; // See this link for more info: http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/lightsource.html
+
+ /*****************************************************************************/
+
+ typedef struct
+ {
+ int32_t numerator; // Numerator
+
+ int32_t denominator; // Denominator
+
+ } gpr_signed_rational;
+
+ typedef struct
+ {
+ uint32_t numerator; // Numerator
+
+ uint32_t denominator; // Denominator
+
+ } gpr_unsigned_rational;
+
+ typedef struct
+ {
+ uint32_t year;
+
+ uint32_t month;
+
+ uint32_t day;
+
+ uint32_t hour;
+
+ uint32_t minute;
+
+ uint32_t second;
+
+ } gpr_date_and_time;
+
+ typedef struct
+ {
+ bool gps_info_valid;
+
+ uint32_t version_id;
+
+ char latitude_ref[2];
+
+ gpr_unsigned_rational latitude[3];
+
+ char longitude_ref[2];
+
+ gpr_unsigned_rational longitude[3];
+
+ uint8_t altitude_ref;
+
+ gpr_unsigned_rational altitude;
+
+ gpr_unsigned_rational time_stamp[3];
+
+ char satellites[SATELLITES_USED_SIZE];
+
+ char status[2];
+
+ char measure_mode[2];
+
+ gpr_unsigned_rational dop;
+
+ char speed_ref[2];
+
+ gpr_unsigned_rational speed;
+
+ char track_ref[2];
+
+ gpr_unsigned_rational track;
+
+ char img_direction_ref[2];
+
+ gpr_unsigned_rational img_direction;
+
+ char map_datum[SURVEY_DATA_SIZE];
+
+ char dest_latitude_ref[2];
+
+ gpr_unsigned_rational dest_latitude[3];
+
+ char dest_longitude_ref[2];
+
+ gpr_unsigned_rational dest_longitude[3];
+
+ char dest_bearing_ref[2];
+
+ gpr_unsigned_rational dest_bearing;
+
+ char dest_distance_ref[2];
+
+ gpr_unsigned_rational dest_distance;
+
+ char processing_method[PROCESSING_METHOD_SIZE];
+
+ char area_information[AREA_INFORMATION_SIZE];
+
+ char date_stamp[11];
+
+ unsigned short differential;
+
+ } gpr_gps_info;
+
+ typedef struct
+ {
+ char camera_make[CAMERA_MAKE_SIZE];
+
+ char camera_model[CAMERA_MODEL_SIZE];
+
+ char camera_serial[CAMERA_SERIAL_SIZE];
+
+ char software_version[SOFTWARE_VERSION_SIZE];
+
+ char user_comment[USER_COMMENT_SIZE];
+
+ char image_description[IMAGE_DESCRIPTION_SIZE];
+
+ gpr_unsigned_rational exposure_time; /* exposure time (as fraction) */
+
+ gpr_unsigned_rational f_stop_number; /* f-stop number (as fraction) */
+
+ gpr_unsigned_rational aperture; /* aperture */
+
+ gpr_exposure_program exposure_program;
+
+ uint16_t iso_speed_rating;
+
+ gpr_date_and_time date_time_original;
+
+ gpr_date_and_time date_time_digitized;
+
+ gpr_signed_rational exposure_bias;
+
+ gpr_metering_mode metering_mode;
+
+ gpr_light_source light_source;
+
+ gpr_flash flash;
+
+ gpr_unsigned_rational focal_length;
+
+ gpr_sharpness sharpness;
+
+ uint16_t saturation;
+
+ gpr_gain_control gain_control;
+
+ gpr_contrast contrast;
+
+ gpr_scene_capture_type scene_capture_type;
+
+ gpr_exposure_mode exposure_mode;
+
+ uint16_t focal_length_in_35mm_film;
+
+ gpr_unsigned_rational digital_zoom;
+
+ gpr_white_balance white_balance;
+
+ gpr_scene_type scene_type;
+
+ gpr_file_source file_source;
+
+ gpr_sensing_method sensing_method;
+
+ gpr_gps_info gps_info;
+
+ } gpr_exif_info;
+
+ void gpr_exif_info_set_defaults( gpr_exif_info* x );
+
+ void gpr_exif_info_get_camera_make_and_model( const gpr_exif_info* x, char camera_make_and_model[256] );
+
+ gpr_date_and_time construct_gpr_date_and_time (uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute, uint32_t second);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // GPR_EXIF_INFO
diff --git a/gpr/source/lib/gpr_sdk/public/gpr_profile_info.h b/gpr/source/lib/gpr_sdk/public/gpr_profile_info.h
new file mode 100755
index 0000000..5fc37b3
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/public/gpr_profile_info.h
@@ -0,0 +1,60 @@
+/*! @file gpr_profile_info.h
+ *
+ * @brief Declaration of gpr_profile_info object and associated functions
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_PROFILE_INFO_H
+#define GPR_PROFILE_INFO_H
+
+#include "gpr_platform.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef double Matrix[3][3];
+
+ typedef struct
+ {
+
+ bool compute_color_matrix;
+
+ double matrix_weighting;
+
+ double wb1[3];
+ double wb2[3];
+
+ Matrix cam_to_srgb_1;
+ Matrix cam_to_srgb_2;
+
+ Matrix color_matrix_1;
+ Matrix color_matrix_2;
+
+ uint16_t illuminant1;
+ uint16_t illuminant2;
+
+ } gpr_profile_info;
+
+ void gpr_profile_info_set_defaults(gpr_profile_info* x);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // GPR_PROFILE_INFO_H
diff --git a/gpr/source/lib/gpr_sdk/public/gpr_tuning_info.h b/gpr/source/lib/gpr_sdk/public/gpr_tuning_info.h
new file mode 100755
index 0000000..677d68d
--- /dev/null
+++ b/gpr/source/lib/gpr_sdk/public/gpr_tuning_info.h
@@ -0,0 +1,149 @@
+/*! @file gpr_tuning_info.h
+ *
+ * @brief Declaration of gpr_tuning_info object and associated functions
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GPR_TUNING_INFO_H
+#define GPR_TUNING_INFO_H
+
+#include "gpr_platform.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef enum
+ {
+ RAW_CHANNEL_RED = 0,
+
+ RAW_CHANNEL_GREEN_EVEN = 1,
+
+ RAW_CHANNEL_GREEN_ODD = 2,
+
+ RAW_CHANNEL_BLUE = 3,
+
+ } GPR_RAW_CHANNEL;
+
+ typedef enum
+ {
+ PIXEL_FORMAT_RGGB_12 = 0, // RGGB 12bit pixels packed into 16bits
+
+ PIXEL_FORMAT_RGGB_12P = 1, // RGGB 12bit pixels packed into 12bits
+
+ PIXEL_FORMAT_RGGB_14 = 2, // RGGB 14bit pixels packed into 16bits
+
+ PIXEL_FORMAT_GBRG_12 = 3, // GBRG 12bit pixels packed into 16bits
+
+ PIXEL_FORMAT_GBRG_12P = 4, // GBRG 12bit pixels packed into 12bits
+
+ } GPR_PIXEL_FORMAT;
+
+ typedef enum
+ {
+ ORIENTATION_NORMAL = 0,
+
+ ORIENTATION_MIRROR = 4,
+
+ ORIENTATION_DEFAULT = ORIENTATION_MIRROR,
+
+ } GPR_ORIENTATION;
+
+ typedef struct
+ {
+ int32_t r_black;
+
+ int32_t g_r_black;
+
+ int32_t g_b_black;
+
+ int32_t b_black;
+
+ } gpr_static_black_level;
+
+ typedef struct
+ {
+ uint16_t iso_value;
+
+ uint32_t shutter_time;
+
+ } gpr_auto_exposure_info;
+
+ typedef struct
+ {
+ int32_t level_red;
+
+ int32_t level_green_even;
+
+ int32_t level_green_odd;
+
+ int32_t level_blue;
+
+ } gpr_saturation_level;
+
+ typedef struct
+ {
+ float_t r_gain;
+
+ float_t g_gain;
+
+ float_t b_gain;
+
+ } gpr_white_balance_gains;
+
+ typedef struct
+ {
+ char *buffers[4];
+
+ uint32_t size;
+
+ } gpr_gain_map;
+
+ typedef struct
+ {
+ GPR_ORIENTATION orientation;
+
+ gpr_static_black_level static_black_level;
+
+ gpr_saturation_level dgain_saturation_level;
+
+ gpr_white_balance_gains wb_gains;
+
+ gpr_auto_exposure_info ae_info;
+
+ double noise_scale;
+ double noise_offset;
+
+ double warp_red_coefficient;
+ double warp_blue_coefficient;
+
+ gpr_gain_map gain_map;
+
+ GPR_PIXEL_FORMAT pixel_format;
+
+ } gpr_tuning_info;
+
+ int32_t gpr_tuning_info_get_dgain_saturation_level(const gpr_tuning_info* x, GPR_RAW_CHANNEL channel);
+
+ void gpr_tuning_info_set_defaults( gpr_tuning_info* x );
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // GPR_TUNING_INFO_H
diff --git a/gpr/source/lib/md5_lib/CMakeLists.txt b/gpr/source/lib/md5_lib/CMakeLists.txt
new file mode 100644
index 0000000..5782609
--- /dev/null
+++ b/gpr/source/lib/md5_lib/CMakeLists.txt
@@ -0,0 +1,23 @@
+# library
+set( LIB_NAME md5_lib )
+
+# get source files
+file( GLOB BASE_SRC_FILES "*.c" )
+
+# get include files
+file( GLOB BASE_INC_FILES "*.h" )
+
+# get all source files
+set( SRC_FILES ${BASE_SRC_FILES} )
+
+# get all include files
+set( INC_FILES ${BASE_INC_FILES} )
+
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/md5_lib/md5.c b/gpr/source/lib/md5_lib/md5.c
new file mode 100755
index 0000000..0aada26
--- /dev/null
+++ b/gpr/source/lib/md5_lib/md5.c
@@ -0,0 +1,257 @@
+/*
+ * This code implements the MD5 message-digest algorithm. The algorithm was
+ * written by Ron Rivest. This code was written by Colin Plumb in 1993, our
+ * understanding is that no copyright is claimed and that this code is in the
+ * public domain.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is functionally equivalent,
+ *
+ * To compute the message digest of a chunk of bytes, declare an MD5Context
+ * structure, pass it to MD5Init, call MD5Update as needed on buffers full of
+ * bytes, and then call MD5Final, which will fill a supplied 16-byte array with
+ * the digest.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "md5.h"
+
+//! \ingroup libMD5
+//! \{
+
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+
+#ifndef __BIG_ENDIAN__
+# define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(uint32_t *buf, unsigned len);
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(uint32_t *buf, unsigned len)
+{
+ uint32_t t;
+ do {
+ char* bytes = (char *) buf;
+ t = ((unsigned) bytes[3] << 8 | bytes[2]) << 16 |
+ ((unsigned) bytes[1] << 8 | bytes[0]);
+ *buf = t;
+ buf++;
+ } while (--len);
+}
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+
+void MD5Init(context_md5_t *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(context_md5_t *ctx, unsigned char *buf, unsigned len)
+{
+ uint32_t t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = ctx->in.b8 + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in.b32, 16);
+ MD5Transform(ctx->buf, ctx->in.b32);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in.b8, buf, 64);
+ byteReverse(ctx->in.b32, 16);
+ MD5Transform(ctx->buf, ctx->in.b32);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in.b8, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], context_md5_t *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in.b8 + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in.b32, 16);
+ MD5Transform(ctx->buf, ctx->in.b32);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in.b8, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in.b32, 14);
+
+ /* Append length in bits and transform */
+ ctx->in.b32[14] = ctx->bits[0];
+ ctx->in.b32[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, ctx->in.b32);
+ byteReverse((uint32_t *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+
+ memset(ctx, 0, sizeof(* ctx)); /* In case it's sensitive */
+ /* The original version of this code omitted the asterisk. In
+ effect, only the first part of ctx was wiped with zeros, not
+ the whole thing. Bug found by Derek Jones. Original line: */
+ // memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+ register uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
diff --git a/gpr/source/lib/md5_lib/md5.h b/gpr/source/lib/md5_lib/md5.h
new file mode 100755
index 0000000..5adc20e
--- /dev/null
+++ b/gpr/source/lib/md5_lib/md5.h
@@ -0,0 +1,60 @@
+/* The copyright in this software is being made available under the BSD
+ * License, included below. This software may be subject to other third party
+ * and contributor rights, including patent rights, and no such rights are
+ * granted under this license.
+ *
+ * Copyright (c) 2010-2015, ITU/ISO/IEC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+#include <stdint.h>
+
+//! \ingroup libMD5
+//! \{
+
+#define MD5_DIGEST_SIZE 16
+
+typedef struct _context_md5_t {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ union {
+ unsigned char b8[64];
+ uint32_t b32[16];
+ } in;
+} context_md5_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void MD5Init(context_md5_t *ctx);
+void MD5Update(context_md5_t *ctx, unsigned char *buf, unsigned len);
+void MD5Final(unsigned char digest[16], context_md5_t *ctx);
+#ifdef __cplusplus
+}
+#endif
+
+//! \}
diff --git a/gpr/source/lib/tiny_jpeg/CMakeLists.txt b/gpr/source/lib/tiny_jpeg/CMakeLists.txt
new file mode 100644
index 0000000..9d14921
--- /dev/null
+++ b/gpr/source/lib/tiny_jpeg/CMakeLists.txt
@@ -0,0 +1,23 @@
+# library
+set( LIB_NAME tiny_jpeg )
+
+# get source files
+file( GLOB BASE_SRC_FILES "*.c" )
+
+# get include files
+file( GLOB BASE_INC_FILES "*.h" )
+
+# get all source files
+set( SRC_FILES ${BASE_SRC_FILES} )
+
+# get all include files
+set( INC_FILES ${BASE_INC_FILES} )
+
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/tiny_jpeg/jpeg.c b/gpr/source/lib/tiny_jpeg/jpeg.c
new file mode 100644
index 0000000..f94ded4
--- /dev/null
+++ b/gpr/source/lib/tiny_jpeg/jpeg.c
@@ -0,0 +1,3 @@
+
+#define TJE_IMPLEMENTATION
+#include "tiny_jpeg.h"
diff --git a/gpr/source/lib/tiny_jpeg/jpeg.h b/gpr/source/lib/tiny_jpeg/jpeg.h
new file mode 100644
index 0000000..7995304
--- /dev/null
+++ b/gpr/source/lib/tiny_jpeg/jpeg.h
@@ -0,0 +1,27 @@
+/*! @file gpr.h
+ *
+ * @brief Declaration of the jpg encoding API
+ *
+ * GPR API can be invoked by simply including this header file.
+ * This file includes all other header files that are needed.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JPEG_H
+#define JPEG_H
+
+#include "tiny_jpeg.h"
+
+#endif // JPEG_H
diff --git a/gpr/source/lib/tiny_jpeg/tiny_jpeg.h b/gpr/source/lib/tiny_jpeg/tiny_jpeg.h
new file mode 100644
index 0000000..e9ab0f7
--- /dev/null
+++ b/gpr/source/lib/tiny_jpeg/tiny_jpeg.h
@@ -0,0 +1,1308 @@
+/**
+ * tiny_jpeg.h
+ *
+ * Tiny JPEG Encoder
+ * - Sergio Gonzalez
+ *
+ * This is a readable and simple single-header JPEG encoder.
+ *
+ * Features
+ * - Implements Baseline DCT JPEG compression.
+ * - No dynamic allocations.
+ *
+ * This library is coded in the spirit of the stb libraries and mostly follows
+ * the stb guidelines.
+ *
+ * It is written in C99. And depends on the C standard library.
+ * Works with C++11
+ *
+ *
+ * ==== Thanks ====
+ *
+ * AssociationSirius (Bug reports)
+ * Bernard van Gastel (Thread-safe defaults, BSD compilation)
+ *
+ *
+ * ==== License ====
+ *
+ * This software is in the public domain. Where that dedication is not
+ * recognized, you are granted a perpetual, irrevocable license to copy and
+ * modify this file as you see fit.
+ *
+ */
+
+// ============================================================
+// Usage
+// ============================================================
+// Include "tiny_jpeg.h" to and use the public interface defined below.
+//
+// You *must* do:
+//
+// #define TJE_IMPLEMENTATION
+// #include "tiny_jpeg.h"
+//
+// in exactly one of your C files to actually compile the implementation.
+
+
+// Here is an example program that loads a bmp with stb_image and writes it
+// with Tiny JPEG
+
+/*
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+
+#define TJE_IMPLEMENTATION
+#include "tiny_jpeg.h"
+
+
+int main()
+{
+ int width, height, num_components;
+ unsigned char* data = stbi_load("in.bmp", &width, &height, &num_components, 0);
+ if ( !data ) {
+ puts("Could not find file");
+ return EXIT_FAILURE;
+ }
+
+ if ( !tje_encode_to_file("out.jpg", width, height, num_components, data) ) {
+ fprintf(stderr, "Could not write JPEG\n");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+*/
+
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers" // We use {0}, which will zero-out the struct.
+#pragma GCC diagnostic ignored "-Wmissing-braces"
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 7 || defined(__clang__) && __clang_major__ >= 10
+#define FALL_THROUGH __attribute__ ((fallthrough))
+#else
+#define FALL_THROUGH ((void)0)
+#endif
+
+// ============================================================
+// Public interface:
+// ============================================================
+
+#ifndef TJE_HEADER_GUARD
+#define TJE_HEADER_GUARD
+
+// - tje_encode_to_file -
+//
+// Usage:
+// Takes bitmap data and writes a JPEG-encoded image to disk.
+//
+// PARAMETERS
+// dest_path: filename to which we will write. e.g. "out.jpg"
+// width, height: image size in pixels
+// num_components: 3 is RGB. 4 is RGBA. Those are the only supported values
+// src_data: pointer to the pixel data.
+//
+// RETURN:
+// 0 on error. 1 on success.
+
+int tje_encode_to_file(const char* dest_path,
+ const int width,
+ const int height,
+ const int num_components,
+ const unsigned char* src_data);
+
+// - tje_encode_to_file_at_quality -
+//
+// Usage:
+// Takes bitmap data and writes a JPEG-encoded image to disk.
+//
+// PARAMETERS
+// dest_path: filename to which we will write. e.g. "out.jpg"
+// quality: 3: Highest. Compression varies wildly (between 1/3 and 1/20).
+// 2: Very good quality. About 1/2 the size of 3.
+// 1: Noticeable. About 1/6 the size of 3, or 1/3 the size of 2.
+// width, height: image size in pixels
+// num_components: 3 is RGB. 4 is RGBA. Those are the only supported values
+// src_data: pointer to the pixel data.
+//
+// RETURN:
+// 0 on error. 1 on success.
+
+int tje_encode_to_file_at_quality(const char* dest_path,
+ const int quality,
+ const int width,
+ const int height,
+ const int num_components,
+ const unsigned char* src_data);
+
+// - tje_encode_with_func -
+//
+// Usage
+// Same as tje_encode_to_file_at_quality, but it takes a callback that knows
+// how to handle (or ignore) `context`. The callback receives an array `data`
+// of `size` bytes, which can be written directly to a file. There is no need
+// to free the data.
+
+typedef void tje_write_func(void* context, void* data, int size);
+
+int tje_encode_with_func(tje_write_func* func,
+ void* context,
+ const int quality,
+ const int width,
+ const int height,
+ const int num_components,
+ const unsigned char* src_data);
+
+#endif // TJE_HEADER_GUARD
+
+
+
+// Implementation: In exactly one of the source files of your application,
+// define TJE_IMPLEMENTATION and include tiny_jpeg.h
+
+// ============================================================
+// Internal
+// ============================================================
+#ifdef TJE_IMPLEMENTATION
+
+#define tjei_min(a, b) ((a) < b) ? (a) : (b);
+#define tjei_max(a, b) ((a) < b) ? (b) : (a);
+
+
+#if defined(_MSC_VER)
+#define TJEI_FORCE_INLINE __forceinline
+// #define TJEI_FORCE_INLINE __declspec(noinline) // For profiling
+#else
+#define TJEI_FORCE_INLINE static // TODO: equivalent for gcc & clang
+#endif
+
+// Only use zero for debugging and/or inspection.
+#define TJE_USE_FAST_DCT 1
+
+// C std lib
+#include <assert.h>
+#include <inttypes.h>
+#include <math.h> // floorf, ceilf
+#include <stdio.h> // FILE, puts
+#include <string.h> // memcpy
+
+
+#define TJEI_BUFFER_SIZE 1024
+
+#ifdef _WIN32
+
+#include <windows.h>
+#ifndef snprintf
+#define snprintf sprintf_s
+#endif
+// Not quite the same but it works for us. If I am not mistaken, it differs
+// only in the return value.
+
+#endif
+
+#ifndef NDEBUG
+
+#ifdef _WIN32
+#define tje_log(msg) OutputDebugStringA(msg)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#define tje_log(msg) puts(msg)
+#else
+#warning "need a tje_log definition for your platform for debugging purposes (not needed if compiling with NDEBUG)"
+#endif
+
+#else // NDEBUG
+#define tje_log(msg)
+#endif // NDEBUG
+
+
+typedef struct
+{
+ void* context;
+ tje_write_func* func;
+} TJEWriteContext;
+
+typedef struct
+{
+ // Huffman data.
+ uint8_t ehuffsize[4][257];
+ uint16_t ehuffcode[4][256];
+ uint8_t const * ht_bits[4];
+ uint8_t const * ht_vals[4];
+
+ // Cuantization tables.
+ uint8_t qt_luma[64];
+ uint8_t qt_chroma[64];
+
+ // fwrite by default. User-defined when using tje_encode_with_func.
+ TJEWriteContext write_context;
+
+ // Buffered output. Big performance win when using the usual stdlib implementations.
+ size_t output_buffer_count;
+ uint8_t output_buffer[TJEI_BUFFER_SIZE];
+} TJEState;
+
+// ============================================================
+// Table definitions.
+//
+// The spec defines tjei_default reasonably good quantization matrices and huffman
+// specification tables.
+//
+//
+// Instead of hard-coding the final huffman table, we only hard-code the table
+// spec suggested by the specification, and then derive the full table from
+// there. This is only for didactic purposes but it might be useful if there
+// ever is the case that we need to swap huffman tables from various sources.
+// ============================================================
+
+
+// K.1 - suggested luminance QT
+static const uint8_t tjei_default_qt_luma_from_spec[] =
+{
+ 16,11,10,16, 24, 40, 51, 61,
+ 12,12,14,19, 26, 58, 60, 55,
+ 14,13,16,24, 40, 57, 69, 56,
+ 14,17,22,29, 51, 87, 80, 62,
+ 18,22,37,56, 68,109,103, 77,
+ 24,35,55,64, 81,104,113, 92,
+ 49,64,78,87,103,121,120,101,
+ 72,92,95,98,112,100,103, 99,
+};
+
+// Unused
+#if 0
+static const uint8_t tjei_default_qt_chroma_from_spec[] =
+{
+ // K.1 - suggested chrominance QT
+ 17,18,24,47,99,99,99,99,
+ 18,21,26,66,99,99,99,99,
+ 24,26,56,99,99,99,99,99,
+ 47,66,99,99,99,99,99,99,
+ 99,99,99,99,99,99,99,99,
+ 99,99,99,99,99,99,99,99,
+ 99,99,99,99,99,99,99,99,
+ 99,99,99,99,99,99,99,99,
+};
+#endif
+
+static const uint8_t tjei_default_qt_chroma_from_paper[] =
+{
+ // Example QT from JPEG paper
+ 16, 12, 14, 14, 18, 24, 49, 72,
+ 11, 10, 16, 24, 40, 51, 61, 12,
+ 13, 17, 22, 35, 64, 92, 14, 16,
+ 22, 37, 55, 78, 95, 19, 24, 29,
+ 56, 64, 87, 98, 26, 40, 51, 68,
+ 81, 103, 112, 58, 57, 87, 109, 104,
+ 121,100, 60, 69, 80, 103, 113, 120,
+ 103, 55, 56, 62, 77, 92, 101, 99,
+};
+
+// == Procedure to 'deflate' the huffman tree: JPEG spec, C.2
+
+// Number of 16 bit values for every code length. (K.3.3.1)
+static const uint8_t tjei_default_ht_luma_dc_len[16] =
+{
+ 0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0
+};
+// values
+static const uint8_t tjei_default_ht_luma_dc[12] =
+{
+ 0,1,2,3,4,5,6,7,8,9,10,11
+};
+
+// Number of 16 bit values for every code length. (K.3.3.1)
+static const uint8_t tjei_default_ht_chroma_dc_len[16] =
+{
+ 0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0
+};
+// values
+static const uint8_t tjei_default_ht_chroma_dc[12] =
+{
+ 0,1,2,3,4,5,6,7,8,9,10,11
+};
+
+// Same as above, but AC coefficients.
+static const uint8_t tjei_default_ht_luma_ac_len[16] =
+{
+ 0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d
+};
+static const uint8_t tjei_default_ht_luma_ac[] =
+{
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
+ 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
+ 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF9, 0xFA
+};
+
+static const uint8_t tjei_default_ht_chroma_ac_len[16] =
+{
+ 0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77
+};
+static const uint8_t tjei_default_ht_chroma_ac[] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
+ 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
+ 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
+ 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
+ 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
+ 0xF9, 0xFA
+};
+
+
+// ============================================================
+// Code
+// ============================================================
+
+// Zig-zag order:
+static const uint8_t tjei_zig_zag[64] =
+{
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63,
+};
+
+// Memory order as big endian. 0xhilo -> 0xlohi which looks as 0xhilo in memory.
+static uint16_t tjei_be_word(const uint16_t le_word)
+{
+ uint16_t lo = (le_word & 0x00ff);
+ uint16_t hi = ((le_word & 0xff00) >> 8);
+ return (uint16_t)((lo << 8) | hi);
+}
+
+// ============================================================
+// The following structs exist only for code clarity, debugability, and
+// readability. They are used when writing to disk, but it is useful to have
+// 1-packed-structs to document how the format works, and to inspect memory
+// while developing.
+// ============================================================
+
+static const uint8_t tjeik_jfif_id[] = "JFIF";
+static const uint8_t tjeik_com_str[] = "Created by Tiny JPEG Encoder";
+
+// TODO: Get rid of packed structs!
+#pragma pack(push)
+#pragma pack(1)
+typedef struct
+{
+ uint16_t SOI;
+ // JFIF header.
+ uint16_t APP0;
+ uint16_t jfif_len;
+ uint8_t jfif_id[5];
+ uint16_t version;
+ uint8_t units;
+ uint16_t x_density;
+ uint16_t y_density;
+ uint8_t x_thumb;
+ uint8_t y_thumb;
+} TJEJPEGHeader;
+
+typedef struct
+{
+ uint16_t com;
+ uint16_t com_len;
+ char com_str[sizeof(tjeik_com_str) - 1];
+} TJEJPEGComment;
+
+// Helper struct for TJEFrameHeader (below).
+typedef struct
+{
+ uint8_t component_id;
+ uint8_t sampling_factors; // most significant 4 bits: horizontal. 4 LSB: vertical (A.1.1)
+ uint8_t qt; // Quantization table selector.
+} TJEComponentSpec;
+
+typedef struct
+{
+ uint16_t SOF;
+ uint16_t len; // 8 + 3 * frame.num_components
+ uint8_t precision; // Sample precision (bits per sample).
+ uint16_t height;
+ uint16_t width;
+ uint8_t num_components; // For this implementation, will be equal to 3.
+ TJEComponentSpec component_spec[3];
+} TJEFrameHeader;
+
+typedef struct
+{
+ uint8_t component_id; // Just as with TJEComponentSpec
+ uint8_t dc_ac; // (dc|ac)
+} TJEFrameComponentSpec;
+
+typedef struct
+{
+ uint16_t SOS;
+ uint16_t len;
+ uint8_t num_components; // 3.
+ TJEFrameComponentSpec component_spec[3];
+ uint8_t first; // 0
+ uint8_t last; // 63
+ uint8_t ah_al; // o
+} TJEScanHeader;
+#pragma pack(pop)
+
+
+static void tjei_write(TJEState* state, const void* data, size_t num_bytes, size_t num_elements)
+{
+ size_t to_write = num_bytes * num_elements;
+
+ // Cap to the buffer available size and copy memory.
+ size_t capped_count = tjei_min(to_write, TJEI_BUFFER_SIZE - 1 - state->output_buffer_count);
+
+ memcpy(state->output_buffer + state->output_buffer_count, data, capped_count);
+ state->output_buffer_count += capped_count;
+
+ assert (state->output_buffer_count <= TJEI_BUFFER_SIZE - 1);
+
+ // Flush the buffer.
+ if ( state->output_buffer_count == TJEI_BUFFER_SIZE - 1 ) {
+ state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);
+ state->output_buffer_count = 0;
+ }
+
+ // Recursively calling ourselves with the rest of the buffer.
+ if (capped_count < to_write) {
+ tjei_write(state, (uint8_t*)data+capped_count, to_write - capped_count, 1);
+ }
+}
+
+static void tjei_write_DQT(TJEState* state, const uint8_t* matrix, uint8_t id)
+{
+ uint16_t DQT = tjei_be_word(0xffdb);
+ tjei_write(state, &DQT, sizeof(uint16_t), 1);
+ uint16_t len = tjei_be_word(0x0043); // 2(len) + 1(id) + 64(matrix) = 67 = 0x43
+ tjei_write(state, &len, sizeof(uint16_t), 1);
+ assert(id < 4);
+ uint8_t precision_and_id = id; // 0x0000 8 bits | 0x00id
+ tjei_write(state, &precision_and_id, sizeof(uint8_t), 1);
+ // Write matrix
+ tjei_write(state, matrix, 64*sizeof(uint8_t), 1);
+}
+
+typedef enum
+{
+ TJEI_DC = 0,
+ TJEI_AC = 1
+} TJEHuffmanTableClass;
+
+static void tjei_write_DHT(TJEState* state,
+ uint8_t const * matrix_len,
+ uint8_t const * matrix_val,
+ TJEHuffmanTableClass ht_class,
+ uint8_t id)
+{
+ int num_values = 0;
+ int i;
+
+ for ( i = 0; i < 16; ++i ) {
+ num_values += matrix_len[i];
+ }
+ assert(num_values <= 0xffff);
+
+ uint16_t DHT = tjei_be_word(0xffc4);
+ // 2(len) + 1(Tc|th) + 16 (num lengths) + ?? (num values)
+ uint16_t len = tjei_be_word(2 + 1 + 16 + (uint16_t)num_values);
+ assert(id < 4);
+ uint8_t tc_th = (uint8_t)((((uint8_t)ht_class) << 4) | id);
+
+ tjei_write(state, &DHT, sizeof(uint16_t), 1);
+ tjei_write(state, &len, sizeof(uint16_t), 1);
+ tjei_write(state, &tc_th, sizeof(uint8_t), 1);
+ tjei_write(state, matrix_len, sizeof(uint8_t), 16);
+ tjei_write(state, matrix_val, sizeof(uint8_t), (size_t)num_values);
+}
+// ============================================================
+// Huffman deflation code.
+// ============================================================
+
+// Returns all code sizes from the BITS specification (JPEG C.3)
+static uint8_t* tjei_huff_get_code_lengths(uint8_t huffsize[/*256*/], uint8_t const * bits)
+{
+ int k = 0;
+ int i, j;
+
+ for ( i = 0; i < 16; ++i ) {
+ for ( j = 0; j < bits[i]; ++j ) {
+ huffsize[k++] = (uint8_t)(i + 1);
+ }
+ huffsize[k] = 0;
+ }
+ return huffsize;
+}
+
+// Fills out the prefixes for each code.
+static uint16_t* tjei_huff_get_codes(uint16_t codes[], uint8_t* huffsize, int64_t count)
+{
+ uint16_t code = 0;
+ int k = 0;
+ uint8_t sz = huffsize[0];
+ for(;;) {
+ do {
+ assert(k < count);
+ codes[k++] = code++;
+ } while (huffsize[k] == sz);
+ if (huffsize[k] == 0) {
+ return codes;
+ }
+ do {
+ code = (uint16_t)(code << 1);
+ ++sz;
+ } while( huffsize[k] != sz );
+ }
+}
+
+static void tjei_huff_get_extended(uint8_t* out_ehuffsize,
+ uint16_t* out_ehuffcode,
+ uint8_t const * huffval,
+ uint8_t* huffsize,
+ uint16_t* huffcode, int64_t count)
+{
+ int k = 0;
+ do {
+ uint8_t val = huffval[k];
+ out_ehuffcode[val] = huffcode[k];
+ out_ehuffsize[val] = huffsize[k];
+ k++;
+ } while ( k < count );
+}
+// ============================================================
+
+// Returns:
+// out[1] : number of bits
+// out[0] : bits
+TJEI_FORCE_INLINE void tjei_calculate_variable_length_int(int value, uint16_t out[2])
+{
+ int abs_val = value;
+ if ( value < 0 ) {
+ abs_val = -abs_val;
+ --value;
+ }
+ out[1] = 1;
+ while( abs_val >>= 1 ) {
+ ++out[1];
+ }
+ out[0] = (uint16_t)(value & ((1 << out[1]) - 1));
+}
+
+// Write bits to file.
+TJEI_FORCE_INLINE void tjei_write_bits(TJEState* state,
+ uint32_t* bitbuffer, uint32_t* location,
+ uint16_t num_bits, uint16_t bits)
+{
+ // v-- location
+ // [ ] <-- bit buffer
+ // 32 0
+ //
+ // This call pushes to the bitbuffer and saves the location. Data is pushed
+ // from most significant to less significant.
+ // When we can write a full byte, we write a byte and shift.
+
+ // Push the stack.
+ uint32_t nloc = *location + num_bits;
+ *bitbuffer |= (uint32_t)(bits << (32 - nloc));
+ *location = nloc;
+ while ( *location >= 8 ) {
+ // Grab the most significant byte.
+ uint8_t c = (uint8_t)((*bitbuffer) >> 24);
+ // Write it to file.
+ tjei_write(state, &c, 1, 1);
+ if ( c == 0xff ) {
+ // Special case: tell JPEG this is not a marker.
+ char z = 0;
+ tjei_write(state, &z, 1, 1);
+ }
+ // Pop the stack.
+ *bitbuffer <<= 8;
+ *location -= 8;
+ }
+}
+
+// DCT implementation by Thomas G. Lane.
+// Obtained through NVIDIA
+// http://developer.download.nvidia.com/SDK/9.5/Samples/vidimaging_samples.html#gpgpu_dct
+//
+// QUOTE:
+// This implementation is based on Arai, Agui, and Nakajima's algorithm for
+// scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+// Japanese, but the algorithm is described in the Pennebaker & Mitchell
+// JPEG textbook (see REFERENCES section in file README). The following code
+// is based directly on figure 4-8 in P&M.
+//
+static void tjei_fdct (float * data)
+{
+ float tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ float tmp10, tmp11, tmp12, tmp13;
+ float z1, z2, z3, z4, z5, z11, z13;
+ float *dataptr;
+ int ctr;
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for ( ctr = 7; ctr >= 0; ctr-- ) {
+ tmp0 = dataptr[0] + dataptr[7];
+ tmp7 = dataptr[0] - dataptr[7];
+ tmp1 = dataptr[1] + dataptr[6];
+ tmp6 = dataptr[1] - dataptr[6];
+ tmp2 = dataptr[2] + dataptr[5];
+ tmp5 = dataptr[2] - dataptr[5];
+ tmp3 = dataptr[3] + dataptr[4];
+ tmp4 = dataptr[3] - dataptr[4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */
+ z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((float) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += 8; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for ( ctr = 8-1; ctr >= 0; ctr-- ) {
+ tmp0 = dataptr[8*0] + dataptr[8*7];
+ tmp7 = dataptr[8*0] - dataptr[8*7];
+ tmp1 = dataptr[8*1] + dataptr[8*6];
+ tmp6 = dataptr[8*1] - dataptr[8*6];
+ tmp2 = dataptr[8*2] + dataptr[8*5];
+ tmp5 = dataptr[8*2] - dataptr[8*5];
+ tmp3 = dataptr[8*3] + dataptr[8*4];
+ tmp4 = dataptr[8*3] - dataptr[8*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[8*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[8*4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((float) 0.707106781); /* c4 */
+ dataptr[8*2] = tmp13 + z1; /* phase 5 */
+ dataptr[8*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((float) 0.382683433); /* c6 */
+ z2 = ((float) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((float) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((float) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[8*5] = z13 + z2; /* phase 6 */
+ dataptr[8*3] = z13 - z2;
+ dataptr[8*1] = z11 + z4;
+ dataptr[8*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+#if !TJE_USE_FAST_DCT
+static float slow_fdct(int u, int v, float* data)
+{
+#define kPI 3.14159265f
+ int x, y;
+ float res = 0.0f;
+ float cu = (u == 0) ? 0.70710678118654f : 1;
+ float cv = (v == 0) ? 0.70710678118654f : 1;
+ for ( y = 0; y < 8; ++y ) {
+ for ( x = 0; x < 8; ++x ) {
+ res += (data[y * 8 + x]) *
+ cosf(((2.0f * x + 1.0f) * u * kPI) / 16.0f) *
+ cosf(((2.0f * y + 1.0f) * v * kPI) / 16.0f);
+ }
+ }
+ res *= 0.25f * cu * cv;
+ return res;
+#undef kPI
+}
+#endif
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static void tjei_encode_and_write_MCU(TJEState* state,
+ float* mcu,
+#if TJE_USE_FAST_DCT
+ float* qt, // Pre-processed quantization matrix.
+#else
+ uint8_t* qt,
+#endif
+ uint8_t* huff_dc_len, uint16_t* huff_dc_code, // Huffman tables
+ uint8_t* huff_ac_len, uint16_t* huff_ac_code,
+ int* pred, // Previous DC coefficient
+ uint32_t* bitbuffer, // Bitstack.
+ uint32_t* location)
+{
+ int du[64]; // Data unit in zig-zag order
+
+ float dct_mcu[64];
+ memcpy(dct_mcu, mcu, 64 * sizeof(float));
+
+#if TJE_USE_FAST_DCT
+ tjei_fdct(dct_mcu);
+ int i;
+
+ for ( i = 0; i < 64; ++i ) {
+ float fval = dct_mcu[i];
+ fval *= qt[i];
+#if 0
+ fval = (fval > 0) ? floorf(fval + 0.5f) : ceilf(fval - 0.5f);
+#else
+ fval = floorf(fval + 1024 + 0.5f);
+ fval -= 1024;
+#endif
+ int val = (int)fval;
+ du[tjei_zig_zag[i]] = val;
+ }
+#else
+ int u, v;
+
+ for ( v = 0; v < 8; ++v ) {
+ for ( u = 0; u < 8; ++u ) {
+ dct_mcu[v * 8 + u] = slow_fdct(u, v, mcu);
+ }
+ }
+
+ for ( i = 0; i < 64; ++i ) {
+ float fval = dct_mcu[i] / (qt[i]);
+ int val = (int)((fval > 0) ? floorf(fval + 0.5f) : ceilf(fval - 0.5f));
+ du[tjei_zig_zag[i]] = val;
+ }
+#endif
+
+ uint16_t vli[2];
+
+ // Encode DC coefficient.
+ int diff = du[0] - *pred;
+ *pred = du[0];
+ if ( diff != 0 ) {
+ tjei_calculate_variable_length_int(diff, vli);
+ // Write number of bits with Huffman coding
+ tjei_write_bits(state, bitbuffer, location, huff_dc_len[vli[1]], huff_dc_code[vli[1]]);
+ // Write the bits.
+ tjei_write_bits(state, bitbuffer, location, vli[1], vli[0]);
+ } else {
+ tjei_write_bits(state, bitbuffer, location, huff_dc_len[0], huff_dc_code[0]);
+ }
+
+ // ==== Encode AC coefficients ====
+
+ int last_non_zero_i = 0;
+
+ // Find the last non-zero element.
+ for ( i = 63; i > 0; --i ) {
+ if (du[i] != 0) {
+ last_non_zero_i = i;
+ break;
+ }
+ }
+
+ for ( i = 1; i <= last_non_zero_i; ++i ) {
+ // If zero, increase count. If >=15, encode (FF,00)
+ int zero_count = 0;
+ while ( du[i] == 0 ) {
+ ++zero_count;
+ ++i;
+ if (zero_count == 16) {
+ // encode (ff,00) == 0xf0
+ tjei_write_bits(state, bitbuffer, location, huff_ac_len[0xf0], huff_ac_code[0xf0]);
+ zero_count = 0;
+ }
+ }
+ tjei_calculate_variable_length_int(du[i], vli);
+
+ assert(zero_count < 0x10);
+ assert(vli[1] <= 10);
+
+ uint16_t sym1 = (uint16_t)((uint16_t)zero_count << 4) | vli[1];
+
+ assert(huff_ac_len[sym1] != 0);
+
+ // Write symbol 1 --- (RUNLENGTH, SIZE)
+ tjei_write_bits(state, bitbuffer, location, huff_ac_len[sym1], huff_ac_code[sym1]);
+ // Write symbol 2 --- (AMPLITUDE)
+ tjei_write_bits(state, bitbuffer, location, vli[1], vli[0]);
+ }
+
+ if (last_non_zero_i != 63) {
+ // write EOB HUFF(00,00)
+ tjei_write_bits(state, bitbuffer, location, huff_ac_len[0], huff_ac_code[0]);
+ }
+ return;
+}
+
+enum {
+ TJEI_LUMA_DC,
+ TJEI_LUMA_AC,
+ TJEI_CHROMA_DC,
+ TJEI_CHROMA_AC,
+};
+
+#if TJE_USE_FAST_DCT
+struct TJEProcessedQT
+{
+ float chroma[64];
+ float luma[64];
+};
+#endif
+
+// Set up huffman tables in state.
+static void tjei_huff_expand(TJEState* state)
+{
+ assert(state);
+
+ state->ht_bits[TJEI_LUMA_DC] = tjei_default_ht_luma_dc_len;
+ state->ht_bits[TJEI_LUMA_AC] = tjei_default_ht_luma_ac_len;
+ state->ht_bits[TJEI_CHROMA_DC] = tjei_default_ht_chroma_dc_len;
+ state->ht_bits[TJEI_CHROMA_AC] = tjei_default_ht_chroma_ac_len;
+
+ state->ht_vals[TJEI_LUMA_DC] = tjei_default_ht_luma_dc;
+ state->ht_vals[TJEI_LUMA_AC] = tjei_default_ht_luma_ac;
+ state->ht_vals[TJEI_CHROMA_DC] = tjei_default_ht_chroma_dc;
+ state->ht_vals[TJEI_CHROMA_AC] = tjei_default_ht_chroma_ac;
+
+ // How many codes in total for each of LUMA_(DC|AC) and CHROMA_(DC|AC)
+ int32_t spec_tables_len[4] = { 0 };
+
+ int i, k;
+
+ for ( i = 0; i < 4; ++i ) {
+ for ( k = 0; k < 16; ++k ) {
+ spec_tables_len[i] += state->ht_bits[i][k];
+ }
+ }
+
+ // Fill out the extended tables..
+ uint8_t huffsize[4][257];
+ uint16_t huffcode[4][256];
+ for ( i = 0; i < 4; ++i ) {
+ assert (256 >= spec_tables_len[i]);
+ tjei_huff_get_code_lengths(huffsize[i], state->ht_bits[i]);
+ tjei_huff_get_codes(huffcode[i], huffsize[i], spec_tables_len[i]);
+ }
+ for ( i = 0; i < 4; ++i ) {
+ int64_t count = spec_tables_len[i];
+ tjei_huff_get_extended(state->ehuffsize[i],
+ state->ehuffcode[i],
+ state->ht_vals[i],
+ &huffsize[i][0],
+ &huffcode[i][0], count);
+ }
+}
+
+static int tjei_encode_main(TJEState* state,
+ const unsigned char* src_data,
+ const int width,
+ const int height,
+ const int src_num_components)
+{
+ if (src_num_components != 3 && src_num_components != 4) {
+ return 0;
+ }
+
+ if (width > 0xffff || height > 0xffff) {
+ return 0;
+ }
+
+#if TJE_USE_FAST_DCT
+ struct TJEProcessedQT pqt;
+ // Again, taken from classic japanese implementation.
+ //
+ /* For float AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ * What's actually stored is 1/divisor so that the inner loop can
+ * use a multiplication rather than a division.
+ */
+ static const float aan_scales[] = {
+ 1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f
+ };
+
+ int x, y;
+
+ // build (de)quantization tables
+ for(y=0; y<8; y++) {
+ for(x=0; x<8; x++) {
+ int i = y*8 + x;
+ pqt.luma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_luma[tjei_zig_zag[i]]);
+ pqt.chroma[y*8+x] = 1.0f / (8 * aan_scales[x] * aan_scales[y] * state->qt_chroma[tjei_zig_zag[i]]);
+ }
+ }
+#endif
+
+ { // Write header
+ TJEJPEGHeader header;
+ // JFIF header.
+ header.SOI = tjei_be_word(0xffd8); // Sequential DCT
+ header.APP0 = tjei_be_word(0xffe0);
+
+ uint16_t jfif_len = sizeof(TJEJPEGHeader) - 4 /*SOI & APP0 markers*/;
+ header.jfif_len = tjei_be_word(jfif_len);
+ memcpy(header.jfif_id, (void*)tjeik_jfif_id, 5);
+ header.version = tjei_be_word(0x0102);
+ header.units = 0x01; // Dots-per-inch
+ header.x_density = tjei_be_word(0x0060); // 96 DPI
+ header.y_density = tjei_be_word(0x0060); // 96 DPI
+ header.x_thumb = 0;
+ header.y_thumb = 0;
+ tjei_write(state, &header, sizeof(TJEJPEGHeader), 1);
+ }
+ { // Write comment
+ TJEJPEGComment com;
+ uint16_t com_len = 2 + sizeof(tjeik_com_str) - 1;
+ // Comment
+ com.com = tjei_be_word(0xfffe);
+ com.com_len = tjei_be_word(com_len);
+ memcpy(com.com_str, (void*)tjeik_com_str, sizeof(tjeik_com_str)-1);
+ tjei_write(state, &com, sizeof(TJEJPEGComment), 1);
+ }
+
+ // Write quantization tables.
+ tjei_write_DQT(state, state->qt_luma, 0x00);
+ tjei_write_DQT(state, state->qt_chroma, 0x01);
+
+ { // Write the frame marker.
+ TJEFrameHeader header;
+ header.SOF = tjei_be_word(0xffc0);
+ header.len = tjei_be_word(8 + 3 * 3);
+ header.precision = 8;
+ assert(width <= 0xffff);
+ assert(height <= 0xffff);
+ header.width = tjei_be_word((uint16_t)width);
+ header.height = tjei_be_word((uint16_t)height);
+ header.num_components = 3;
+ uint8_t tables[3] = {
+ 0, // Luma component gets luma table (see tjei_write_DQT call above.)
+ 1, // Chroma component gets chroma table
+ 1, // Chroma component gets chroma table
+ };
+
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ TJEComponentSpec spec;
+ spec.component_id = (uint8_t)(i + 1); // No particular reason. Just 1, 2, 3.
+ spec.sampling_factors = (uint8_t)0x11;
+ spec.qt = tables[i];
+
+ header.component_spec[i] = spec;
+ }
+ // Write to file.
+ tjei_write(state, &header, sizeof(TJEFrameHeader), 1);
+ }
+
+ tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_DC], state->ht_vals[TJEI_LUMA_DC], TJEI_DC, 0);
+ tjei_write_DHT(state, state->ht_bits[TJEI_LUMA_AC], state->ht_vals[TJEI_LUMA_AC], TJEI_AC, 0);
+ tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_DC], state->ht_vals[TJEI_CHROMA_DC], TJEI_DC, 1);
+ tjei_write_DHT(state, state->ht_bits[TJEI_CHROMA_AC], state->ht_vals[TJEI_CHROMA_AC], TJEI_AC, 1);
+
+ // Write start of scan
+ {
+ TJEScanHeader header;
+ header.SOS = tjei_be_word(0xffda);
+ header.len = tjei_be_word((uint16_t)(6 + (sizeof(TJEFrameComponentSpec) * 3)));
+ header.num_components = 3;
+
+ uint8_t tables[3] = {
+ 0x00,
+ 0x11,
+ 0x11,
+ };
+
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ TJEFrameComponentSpec cs;
+ // Must be equal to component_id from frame header above.
+ cs.component_id = (uint8_t)(i + 1);
+ cs.dc_ac = (uint8_t)tables[i];
+
+ header.component_spec[i] = cs;
+ }
+ header.first = 0;
+ header.last = 63;
+ header.ah_al = 0;
+ tjei_write(state, &header, sizeof(TJEScanHeader), 1);
+
+ }
+ // Write compressed data.
+
+ float du_y[64];
+ float du_b[64];
+ float du_r[64];
+
+ // Set diff to 0.
+ int pred_y = 0;
+ int pred_b = 0;
+ int pred_r = 0;
+
+ // Bit stack
+ uint32_t bitbuffer = 0;
+ uint32_t location = 0;
+
+ int off_x, off_y;
+
+ for ( y = 0; y < height; y += 8 ) {
+ for ( x = 0; x < width; x += 8 ) {
+ // Block loop: ====
+ for ( off_y = 0; off_y < 8; ++off_y ) {
+ for ( off_x = 0; off_x < 8; ++off_x ) {
+ int block_index = (off_y * 8 + off_x);
+
+ int src_index = (((y + off_y) * width) + (x + off_x)) * src_num_components;
+
+ int col = x + off_x;
+ int row = y + off_y;
+
+ if(row >= height) {
+ src_index -= (width * (row - height + 1)) * src_num_components;
+ }
+ if(col >= width) {
+ src_index -= (col - width + 1) * src_num_components;
+ }
+ assert(src_index < width * height * src_num_components);
+
+ uint8_t r = src_data[src_index + 0];
+ uint8_t g = src_data[src_index + 1];
+ uint8_t b = src_data[src_index + 2];
+
+ float luma = 0.299f * r + 0.587f * g + 0.114f * b - 128;
+ float cb = -0.1687f * r - 0.3313f * g + 0.5f * b;
+ float cr = 0.5f * r - 0.4187f * g - 0.0813f * b;
+
+ du_y[block_index] = luma;
+ du_b[block_index] = cb;
+ du_r[block_index] = cr;
+ }
+ }
+
+ tjei_encode_and_write_MCU(state, du_y,
+#if TJE_USE_FAST_DCT
+ pqt.luma,
+#else
+ state->qt_luma,
+#endif
+ state->ehuffsize[TJEI_LUMA_DC], state->ehuffcode[TJEI_LUMA_DC],
+ state->ehuffsize[TJEI_LUMA_AC], state->ehuffcode[TJEI_LUMA_AC],
+ &pred_y, &bitbuffer, &location);
+ tjei_encode_and_write_MCU(state, du_b,
+#if TJE_USE_FAST_DCT
+ pqt.chroma,
+#else
+ state->qt_chroma,
+#endif
+ state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],
+ state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],
+ &pred_b, &bitbuffer, &location);
+ tjei_encode_and_write_MCU(state, du_r,
+#if TJE_USE_FAST_DCT
+ pqt.chroma,
+#else
+ state->qt_chroma,
+#endif
+ state->ehuffsize[TJEI_CHROMA_DC], state->ehuffcode[TJEI_CHROMA_DC],
+ state->ehuffsize[TJEI_CHROMA_AC], state->ehuffcode[TJEI_CHROMA_AC],
+ &pred_r, &bitbuffer, &location);
+
+
+ }
+ }
+
+ // Finish the image.
+ { // Flush
+ if (location > 0 && location < 8) {
+ tjei_write_bits(state, &bitbuffer, &location, (uint16_t)(8 - location), 0);
+ }
+ }
+ uint16_t EOI = tjei_be_word(0xffd9);
+ tjei_write(state, &EOI, sizeof(uint16_t), 1);
+
+ if (state->output_buffer_count) {
+ state->write_context.func(state->write_context.context, state->output_buffer, (int)state->output_buffer_count);
+ state->output_buffer_count = 0;
+ }
+
+ return 1;
+}
+
+int tje_encode_to_file(const char* dest_path,
+ const int width,
+ const int height,
+ const int num_components,
+ const unsigned char* src_data)
+{
+ int res = tje_encode_to_file_at_quality(dest_path, 2, width, height, num_components, src_data);
+ return res;
+}
+
+static void tjei_stdlib_func(void* context, void* data, int size)
+{
+ FILE* fd = (FILE*)context;
+ fwrite(data, size, 1, fd);
+}
+
+// Define public interface.
+int tje_encode_to_file_at_quality(const char* dest_path,
+ const int quality,
+ const int width,
+ const int height,
+ const int num_components,
+ const unsigned char* src_data)
+{
+ FILE* fd = fopen(dest_path, "wb");
+ if (!fd) {
+ tje_log("Could not open file for writing.");
+ return 0;
+ }
+
+ int result = tje_encode_with_func(tjei_stdlib_func, fd,
+ quality, width, height, num_components, src_data);
+
+ result |= 0 == fclose(fd);
+
+ return result;
+}
+
+int tje_encode_with_func(tje_write_func* func,
+ void* context,
+ const int quality,
+ const int width,
+ const int height,
+ const int num_components,
+ const unsigned char* src_data)
+{
+ if (quality < 1 || quality > 3) {
+ tje_log("[ERROR] -- Valid 'quality' values are 1 (lowest), 2, or 3 (highest)\n");
+ return 0;
+ }
+
+ TJEState state = { 0 };
+ int i;
+
+ uint8_t qt_factor = 1;
+ switch(quality) {
+ case 3:
+ for ( i = 0; i < 64; ++i ) {
+ state.qt_luma[i] = 1;
+ state.qt_chroma[i] = 1;
+ }
+ break;
+ case 2:
+ qt_factor = 10;
+ FALL_THROUGH;
+ // don't break. fall through.
+ case 1:
+ for ( i = 0; i < 64; ++i ) {
+ state.qt_luma[i] = tjei_default_qt_luma_from_spec[i] / qt_factor;
+ if (state.qt_luma[i] == 0) {
+ state.qt_luma[i] = 1;
+ }
+ state.qt_chroma[i] = tjei_default_qt_chroma_from_paper[i] / qt_factor;
+ if (state.qt_chroma[i] == 0) {
+ state.qt_chroma[i] = 1;
+ }
+ }
+ break;
+ default:
+ assert(!"invalid code path");
+ break;
+ }
+
+ TJEWriteContext wc = { 0 };
+
+ wc.context = context;
+ wc.func = func;
+
+ state.write_context = wc;
+
+
+ tjei_huff_expand(&state);
+
+ int result = tjei_encode_main(&state, src_data, width, height, num_components);
+
+ return result;
+}
+// ============================================================
+#endif // TJE_IMPLEMENTATION
+// ============================================================
+//
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+
+#ifdef __cplusplus
+} // extern C
+#endif
+
diff --git a/gpr/source/lib/vc5_common/CMakeLists.txt b/gpr/source/lib/vc5_common/CMakeLists.txt
new file mode 100644
index 0000000..090b212
--- /dev/null
+++ b/gpr/source/lib/vc5_common/CMakeLists.txt
@@ -0,0 +1,20 @@
+# library
+set( LIB_NAME vc5_common )
+
+# get source files
+file( GLOB SRC_FILES "*.c" )
+
+# get include files
+file( GLOB INC_FILES "*.h" )
+
+# add include files from other folders
+include_directories( "../common/private" )
+include_directories( "../common/public" )
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/vc5_common/bitstream.c b/gpr/source/lib/vc5_common/bitstream.c
new file mode 100755
index 0000000..cef4312
--- /dev/null
+++ b/gpr/source/lib/vc5_common/bitstream.c
@@ -0,0 +1,445 @@
+/*! @file bitstream.c
+ *
+ * @brief Implementation of a bitstream for reading bits from a byte stream.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+/*!
+ @brief Return a mask with the specified number of bits set to one
+ */
+BITWORD BitMask(int n)
+{
+ if (n < bit_word_count)
+ {
+ BITWORD mask = 0;
+ if (n > 0) {
+ mask = ((1 << n) - 1);
+ }
+ return mask;
+ }
+ return BIT_WORD_MAX;
+}
+
+/*!
+ @brief Initialize a bitstream data structure
+
+ This routine is the constructor for the bitstream data type.
+
+ The sample offset stack is used to mark the offset to a position
+ in the bitstream for computing the size field of sample chunks.
+ */
+CODEC_ERROR InitBitstream(BITSTREAM *bitstream)
+{
+ if (bitstream != NULL)
+ {
+ bitstream->error = BITSTREAM_ERROR_OKAY;
+ bitstream->stream = NULL;
+ bitstream->buffer = 0;
+ bitstream->count = 0;
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ // Initialize the stack of sample offsets
+ memset(bitstream->sample_offset_stack, 0, sizeof(bitstream->sample_offset_stack));
+ bitstream->sample_offset_count = 0;
+#endif
+
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_NULLPTR;
+}
+
+/*!
+ @brief Attach a bitstream to a byte stream.
+
+ It is permitted for the byte stream to be NULL, in which case the
+ bitstream will not be able to replenish its internal buffer, but
+ the consequences are undefined.
+ */
+CODEC_ERROR AttachBitstream(struct _bitstream *bitstream, struct _stream *stream)
+{
+ assert(bitstream != NULL);
+ bitstream->stream = stream;
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Detach a bitstream from a byte stream.
+
+ Any resources allocated by the bitstream are released without deallocating
+ the bitstream data structure itself. The byte stream associated with the
+ bitstream is not closed by this routine. The byte stream must be closed,
+ if and when appropriate, by the caller.
+ */
+CODEC_ERROR ReleaseBitstream(BITSTREAM *bitstream)
+{
+ //TODO: What cleanup needs to be performed?
+ (void) bitstream;
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return the specified number of bits from the bitstream
+ */
+BITWORD GetBits(BITSTREAM *stream, BITCOUNT count)
+{
+ // Return zero if the request cannot be satisfied
+ BITWORD bits = 0;
+
+ // Check that the number of requested bits is valid
+ //assert(0 <= count && count <= bit_word_count);
+ assert(count <= bit_word_count);
+
+ // Check that the unused portion of the bit buffer is empty
+ assert((stream->buffer & BitMask(bit_word_count - stream->count)) == 0);
+
+ if (count == 0) goto finish;
+
+ // Are there enough bits in the buffer to satisfy the request?
+ if (count <= stream->count)
+ {
+ // Right align the requested number of bits in the bit buffer
+ bits = (stream->buffer >> (bit_word_count - count));
+
+ // Reduce the number of bits in the bit buffer
+ stream->buffer <<= count;
+ stream->count = (stream->count - count);
+ }
+ else
+ {
+ BITCOUNT low_bit_count;
+
+ // Use the remaining bits in the bit buffer
+ assert(stream->count > 0 || stream->buffer == 0);
+ bits = (stream->buffer >> (bit_word_count - count));
+
+ // Compute the number of bits to be used from the next word
+ low_bit_count = count - stream->count;
+ stream->count = 0;
+ assert(low_bit_count > 0);
+
+ // Fill the bit buffer
+ assert(stream->count == 0);
+ GetBuffer(stream);
+ assert(stream->count >= low_bit_count);
+
+ // Use the new bits in the bit buffer
+ bits |= (stream->buffer >> (bit_word_count - low_bit_count));
+
+ // Reduce the number of bits in the bit buffer
+ if (low_bit_count < bit_word_count) {
+ stream->buffer <<= low_bit_count;
+ }
+ else {
+ stream->buffer = 0;
+ }
+ assert(low_bit_count <= stream->count);
+ stream->count = (stream->count - low_bit_count);
+ }
+
+finish:
+ // The bit count should never be negative or larger than the size of the bit buffer
+ //assert(0 <= stream->count && stream->count <= bit_word_count);
+ assert(stream->count <= bit_word_count);
+
+ // The unused bits in the bit buffer should all be zero
+ assert((stream->buffer & BitMask(bit_word_count - stream->count)) == 0);
+
+ // The unused bits in the result should all be zero
+ assert((bits & ~BitMask(count)) == 0);
+
+ return bits;
+}
+
+/*!
+ @brief Read more bits and append to an existing word of bits
+
+ Read the specified number of bits from the bitstream and append
+ the new bits to the right end of the word supplied as an argument.
+ This is a convenience routine that is used to accumulate bits that
+ may match a codeword.
+ */
+BITWORD AddBits(BITSTREAM *bitstream, BITWORD bits, BITCOUNT count)
+{
+ BITWORD new_bits = GetBits(bitstream, count);
+ assert((new_bits & ~BitMask(count)) == 0);
+
+ bits = (bits << count) | new_bits;
+
+ return bits;
+}
+
+/*!
+ @brief Write a longword (32 bits) to the stream
+ */
+CODEC_ERROR PutLong(BITSTREAM *stream, BITWORD longword)
+{
+ return PutBits(stream, longword, bit_word_count);
+}
+
+/*!
+ @brief Write the specified number of bits to the bitstream
+ */
+CODEC_ERROR PutBits(BITSTREAM *stream, BITWORD bits, BITCOUNT count)
+{
+ BITCOUNT unused_bit_count;
+
+ if (count == 0) {
+ return CODEC_ERROR_OKAY;
+ }
+
+ // Check that the unused portion of the input bits is empty
+ assert((bits & (BitMask(bit_word_count - count) << count)) == 0);
+
+ // Check that the number of input bits is valid
+ //assert(0 <= count && count <= bit_word_count);
+ assert(count <= bit_word_count);
+
+ // Check that the unused portion of the bit buffer is empty
+ unused_bit_count = bit_word_count - stream->count;
+ assert((stream->buffer & BitMask(unused_bit_count)) == 0);
+
+ // Is there room in the bit buffer for the new bits?
+ if (count <= unused_bit_count)
+ {
+ // Fill the remaining space in the bit buffer
+ stream->buffer |= (bits << (unused_bit_count - count));
+
+ // Reduce the number of unused bits in the bit buffer
+ stream->count += count;
+ }
+ else
+ {
+ // Any room in the bit buffer?
+ if (unused_bit_count > 0)
+ {
+ // Use the number of input bits that will fit in the bit buffer
+ stream->buffer |= (bits >> (count - unused_bit_count));
+
+ // Reduce the number of input bits by the amount used
+ count -= unused_bit_count;
+ //assert(count >= 0);
+ }
+
+ // Write the bit buffer to the byte stream
+ PutWord(stream->stream, stream->buffer );
+
+ // Insert the remaining input bits into the bit buffer
+ stream->buffer = (bits << (bit_word_count - count));
+
+ // Increment the number of bits in the bit buffer
+ stream->count = count;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Fill the internal bitstream buffer by reading a byte stream
+
+ @todo Need to modify this routine to return an error code if it cannot
+ read from the byte stream associated with the bitstream.
+ */
+CODEC_ERROR GetBuffer(BITSTREAM *bitstream)
+{
+ // Need to signal an underflow error?
+ if (! (bitstream != NULL && bitstream->stream != NULL)) {
+ assert(0);
+
+ if( bitstream->error == BITSTREAM_ERROR_UNDERFLOW )
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ // The bit buffer should be empty
+ assert(bitstream->count == 0);
+
+ // Fill the bit buffer with a word from the byte stream
+ bitstream->buffer = Swap32(GetWord(bitstream->stream));
+ bitstream->count = bit_word_count;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the internal bitstream buffer to a byte stream
+
+ @todo Need to modify this routine to return an error code if it cannot
+ write to the byte stream associated with the bitstream.
+ */
+CODEC_ERROR PutBuffer(BITSTREAM *bitstream)
+{
+ //TODO: Need to signal an overflow error
+ assert(bitstream != NULL && bitstream->stream != NULL);
+
+ // The bit buffer should be full
+ assert(bitstream->count == bit_word_count);
+
+ // Write the bit buffer to the byte stream
+ PutWord(bitstream->stream, bitstream->buffer );
+
+ // Empty the bit buffer
+ bitstream->buffer = 0;
+ bitstream->count = 0;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Convert a bitstream error code to a codec error codec
+
+ The bitstream and byte stream modules use a separate enumeration
+ for error codes since these modules are used in other applications.
+ The bistream error code is embedded in a range of codec error codes
+ that are reserved for bitstream errors.
+ */
+CODEC_ERROR CodecErrorBitstream(BITSTREAM_ERROR error)
+{
+ uint32_t codec_error = CODEC_ERROR_BITSTREAM;
+ codec_error |= (uint32_t)error;
+ return (CODEC_ERROR)codec_error;
+}
+
+/*!
+ @brief Convert a bitstream error code into a codec error code
+
+ The bitstream and byte stream modules might be used in other
+ applications and have their own errors codes. This routine
+ embeds a bitstream error code into a codec error code. The
+ bitstream error code is carried in the low bits of the codec
+ error code.
+
+ @todo Eliminate separate error codes for bitstreams?
+ */
+CODEC_ERROR BitstreamCodecError(BITSTREAM *bitstream)
+{
+ assert(bitstream != NULL);
+ if (! (bitstream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ return CodecErrorBitstream(bitstream->error);
+}
+
+/*!
+ @brief Read a block of bytes from the bitstream
+ */
+CODEC_ERROR GetByteArray(BITSTREAM *bitstream, uint8_t *array, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ {
+ array[i] = GetBits(bitstream, 8);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write a block of bytes into the bitstream
+ */
+CODEC_ERROR PutByteArray(BITSTREAM *bitstream, const uint8_t *array, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ {
+ PutBits(bitstream, array[i], 8);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write any bits in the buffer to the byte stream
+ */
+CODEC_ERROR FlushBitstream(BITSTREAM *bitstream)
+{
+ // Any bits remaining in the bit buffer?
+ if (bitstream->count > 0)
+ {
+ // Write the bit buffer to the output stream
+ PutBuffer(bitstream);
+ }
+
+ // Indicate that the bitstream buffer is empty
+ bitstream->count = 0;
+ bitstream->buffer = 0;
+
+ // Flush the output stream
+ FlushStream(bitstream->stream);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Get the current position in the byte stream
+
+ The current position in the byte stream associated with the
+ bitstream is returned. The intent is to allow the bitstream
+ (and the associated byte stream) to be restored to the saved
+ position.
+
+ @todo Need to record the state of the bitstream buffer and
+ bit count so that the entire bitstream state can be restored.
+ */
+size_t GetBitstreamPosition(BITSTREAM *bitstream)
+{
+ if (bitstream->count == bit_word_count) {
+ PutBuffer(bitstream);
+ }
+
+ // The bit buffer must be empty
+ assert(bitstream->count == 0);
+
+ // The bit buffer must be empty
+ return (bitstream->stream->byte_count);
+}
+
+/*!
+ @brief Rewind the bitstream
+
+ This routine rewinds the bitstream to the beginning of the byte stream
+ that has been attached to the bitstream. The byte stream is also reset.
+
+ If the byte stream could not be reset, then the internal bitstream state
+ is not reset.
+ */
+CODEC_ERROR RewindBitstream(BITSTREAM *bitstream)
+{
+ assert(bitstream != NULL);
+ if (! (bitstream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ if (bitstream->stream != NULL) {
+ CODEC_ERROR error = RewindStream(bitstream->stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+ }
+
+ // Reset the bitstream internal state
+ bitstream->buffer = 0;
+ bitstream->count = 0;
+ bitstream->error = BITSTREAM_ERROR_OKAY;
+
+ return CODEC_ERROR_OKAY;
+}
+
diff --git a/gpr/source/lib/vc5_common/bitstream.h b/gpr/source/lib/vc5_common/bitstream.h
new file mode 100755
index 0000000..85c2a25
--- /dev/null
+++ b/gpr/source/lib/vc5_common/bitstream.h
@@ -0,0 +1,135 @@
+/*! @file bitstream.h
+ *
+ * @brief Declaration of the bitstream data structure.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BITSTREAM_H
+#define BITSTREAM_H
+
+/*!
+ @brief Bitstream error codes
+
+ The bitstream contains its own enumeration of error codes since this
+ module may be used in other applications.
+ */
+typedef enum _bitstream_error
+{
+ BITSTREAM_ERROR_OKAY = 0, //!< No error
+ BITSTREAM_ERROR_UNDERFLOW, //!< No unread bits remaining in the bitstream
+ BITSTREAM_ERROR_OVERFLOW, //!< No more bits can be written to the bitstream
+ BITSTREAM_ERROR_BADTAG, //!< Unexpected tag found in the bitstream
+
+ //TODO: Add more bitstream errors
+
+} BITSTREAM_ERROR;
+
+typedef uint32_t BITWORD; //!< Data type of the internal bitstream buffer
+
+typedef uint_fast8_t BITCOUNT; //!< Number of bits in the bitsteam buffer
+
+//! Maximum number of bits in a bit word
+static const BITCOUNT bit_word_count = 32;
+
+//! Maximum value of a bit word
+#define BIT_WORD_MAX 0xFFFFFFFF
+
+//! Sample offset stack depth
+#define MAX_SAMPLE_OFFSET_COUNT 8
+
+/*!
+ @brief Declaration of the bitstream data structure
+
+ The bitstream uses a byte stream to read bytes from a file or a buffer
+ in memory. This isolates that bitstream module from the type of byte
+ stream.
+ */
+typedef struct _bitstream
+{
+ BITSTREAM_ERROR error; //!< Error while processing the bitstream
+ struct _stream *stream; //!< Stream for reading bytes into the buffer
+ BITWORD buffer; //!< Internal buffer holds remaining bits
+ BITCOUNT count; //!< Number of bits remaining in the buffer
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ /*!
+ The sample offset stack is used to record offsets to the start of nested
+ syntax structures. For example, a sample size segment is written into the
+ bitstream with a size of zero, since the size of the syntax element is not
+ known in advance. The offset to the sample size segment is pushed onto the
+ sample offset stack so that the location of the sample size segment can be
+ updated with the actual size of a syntax element after the complete element
+ is written into the bitstream.
+
+ This data structure is called the ChunkSizeOffset in the current codec
+ implementation.
+ */
+ uint32_t sample_offset_stack[MAX_SAMPLE_OFFSET_COUNT];
+
+ //! Number of entries in the sample offset stack
+ uint_fast8_t sample_offset_count;
+#endif
+
+} BITSTREAM;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ BITWORD BitMask(int n);
+
+ CODEC_ERROR CodecErrorBitstream(BITSTREAM_ERROR error);
+
+ // Initialize a bitstream data structure
+ CODEC_ERROR InitBitstream(BITSTREAM *bitstream);
+
+ // Bind the bitstream to a byte stream
+ CODEC_ERROR AttachBitstream(struct _bitstream *bitstream, struct _stream *stream);
+
+ CODEC_ERROR ReleaseBitstream(BITSTREAM *stream);
+
+ BITWORD GetBits(BITSTREAM *stream, BITCOUNT count);
+
+ CODEC_ERROR PutBits(BITSTREAM *stream, BITWORD bits, BITCOUNT count);
+
+ BITWORD AddBits(BITSTREAM *stream, BITWORD bits, BITCOUNT count);
+
+ CODEC_ERROR GetBuffer(BITSTREAM *stream);
+
+ CODEC_ERROR PutBuffer(BITSTREAM *stream);
+
+ CODEC_ERROR PutLong(BITSTREAM *stream, BITWORD longword);
+
+ // Rewind the bitstream and the associated byte stream
+ CODEC_ERROR RewindBitstream(BITSTREAM *bitstream);
+
+ CODEC_ERROR BitstreamCodecError(BITSTREAM *bitstream);
+
+ // Return the current position of the bitstream pointer in the sample
+ size_t GetBitstreamPosition(BITSTREAM *stream);
+
+ CODEC_ERROR FlushBitstream(BITSTREAM *bitstream);
+
+ CODEC_ERROR GetByteArray(BITSTREAM *bitstream, uint8_t *array, size_t size);
+
+ CODEC_ERROR PutByteArray(BITSTREAM *bitstream, const uint8_t *block, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BITSTREAM_H
diff --git a/gpr/source/lib/vc5_common/codec.c b/gpr/source/lib/vc5_common/codec.c
new file mode 100755
index 0000000..2308f75
--- /dev/null
+++ b/gpr/source/lib/vc5_common/codec.c
@@ -0,0 +1,201 @@
+/*! @file codec.c
+ *
+ * @brief Implementation of functions that are common to the
+ * reference decoder and encoder
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+/*!
+ @brief Initialize the codec state to before encoding or decoding the bitstream
+
+ Most of the codec state can be deduced from the decoding parameters.
+ For example, the dimensions of the first wavelet band in the bitstream
+ can be deduced from the encoded frame dimensions and the structure of
+ the wavelet tree.
+
+ The encoder will not insert parameters into the bitstream if the values
+ of the parameters are the same as in the codec state. This routine
+ should initialize the codec state with correct values if those values
+ can be inferred by the decoder, otherwise the use incorrect or default
+ values.
+
+ Note that the default encoded format is YUV 4:2:2, but this format is not
+ supported by the baseline profile encoder so the encoded format must be
+ explicitly written into the bitstream.
+
+ @todo Add more default values required to properly initialize the codec state.
+*/
+CODEC_ERROR PrepareCodecState(CODEC_STATE *codec)
+{
+ // Initialize the channel to channel number zero
+ codec->channel_number = 0;
+
+ // Initialize the subband number to subband zero (the lowpass band)
+ codec->subband_number = 0;
+
+ // The number of subbands per channel is a constant
+ codec->subband_count = 10;
+
+ // The default precision of pixels in the input frame is ten bits
+ codec->bits_per_component = 12;
+
+ // Force the encoder to insert the encoded dimensions into the bitstream
+ //codec->encoded.width = 0;
+ //codec->encoded.height = 0;
+
+ /*
+ TODO: Do not have to encode the display dimensions into the bitstream if the decoder
+ can infer the display dimensions from the encoded dimensions and format, but must
+ encode the display dimensions if the encoded dimensions include padding.
+
+ TODO: Check that this matches the current decoder implementation.
+ */
+
+ // Set the default precision for encoding lowpass band coefficients
+ codec->lowpass_precision = 16;
+
+ //TODO: Set more default values in the codec state
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Reformat a segment value into the encoder version
+
+ The version of the encoder that created the clip may be encoded into every sample.
+
+ @todo Document the encoder version number format
+*/
+uint32_t EncoderVersion(uint32_t value)
+{
+ return (((value >> 12) & 0x0F) << 16) |
+ (((value >> 8) & 0x0F) << 8) |
+ ((value) & 0xFF);
+}
+
+/*!
+ @brief Unpack the version tag value into its components
+*/
+void SetCodecVersion(uint8_t version[3], uint16_t value)
+{
+ version[0] = (uint8_t)((value >> 12) & 0x0F); // Major version
+ version[1] = (uint8_t)((value >> 8) & 0x0F); // Minor version
+ version[2] = (uint8_t)(value & 0xFF); // Revision
+}
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Return true if the image format is valid
+*/
+bool ValidImageFormat(IMAGE_FORMAT image_format)
+{
+ if (0 < image_format && image_format < IMAGE_FORMAT_COUNT) {
+ return true;
+ }
+ return false;
+}
+#endif
+
+/*!
+ @brief Unpack the tag value into the prescale table
+
+ The prescale table contains the prescale value for each wavelet in the
+ transform. The prescale value is a right shift that is applied to the
+ input data before the wavelet is computed.
+
+ The prescale table is used for all transforms and does not depend on the
+ channel number.
+*/
+CODEC_ERROR UpdatePrescaleTable(CODEC_STATE *codec, TAGWORD value)
+{
+ int wavelet_index;
+
+ for (wavelet_index = 0; wavelet_index < MAX_WAVELET_COUNT; wavelet_index++)
+ {
+ // Unpack the prescale value
+ int prescale_value = (value >> (14 - wavelet_index * 2)) & 0x03;
+ assert(0 <= prescale_value && prescale_value < UINT8_MAX);
+
+ // Store the prescale value in the codec state
+ codec->prescale_table[wavelet_index] = (uint_fast8_t)prescale_value;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Update the flags that describe the frame structure
+
+ The frame structure includes characteristics such as interlaced versus
+ progressive and top or bottom field first.
+*/
+CODEC_ERROR UpdateFrameStructureFlags(CODEC_STATE *codec, TAGWORD value)
+{
+ codec->progressive = !(value & IMAGE_STRUCTURE_INTERLACED);
+ codec->top_field_first = !(value & IMAGE_STRUCTURE_BOTTOM_FIELD_FIRST);
+ codec->frame_inverted = (value & IMAGE_STRUCTURE_BOTTOM_ROW_FIRST);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize the codec state using the default constructor
+
+ This routine is like a default constructor in C++ as it guarantees that
+ the codec state is initialized to a know starting state with all pointers
+ set to NULL and all counters set to zero.
+
+ The routine @ref PrepareCodecState is used to set default values for the
+ codec state prior to decoding a sample.
+*/
+CODEC_ERROR InitCodecState(CODEC_STATE *state)
+{
+ // Clear the codec state
+ memset(state, 0, sizeof(CODEC_STATE));
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Set the flags that determine the band coding
+
+ There can be up to 15 different codebooks as specified by the lower
+ four bigs in the band coding flags. Use the default codebook if the
+ active codebook is zero.
+
+ The baseline profile does not allow difference coding or alternative
+ codebooks.
+*/
+CODEC_ERROR SetBandCoding(CODEC_STATE *codec, TAGWORD value)
+{
+ (void) codec;
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return true if the specified part is enabled at runtime
+
+ This predicate is used to test whether a specific part in the VC-5 standard is
+ enabled at runtime by this codec implementation.
+
+*/
+bool IsPartEnabled(ENABLED_PARTS enabled_parts, int part_number)
+{
+ return ((enabled_parts & VC5_PART_MASK(part_number)) != 0);
+}
+
diff --git a/gpr/source/lib/vc5_common/codec.h b/gpr/source/lib/vc5_common/codec.h
new file mode 100755
index 0000000..6763091
--- /dev/null
+++ b/gpr/source/lib/vc5_common/codec.h
@@ -0,0 +1,315 @@
+/*! @file codec.h
+ *
+ * @brief State of the decoder while decoding a sample. The codec state
+ * contains information about the current state of the decoding process.
+ * The codec state is updated as the bitstream is decoded.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC_H
+#define CODEC_H
+
+#include "syntax.h"
+
+static const SEGMENT StartMarkerSegment = ((0x56 << 24) | (0x43 << 16) | (0x2D << 8) | 0x35);
+
+/*!
+ @brief Tags that define elements in the bitstream
+
+ All syntax elements in the encoded bitstream begin with a 16-bit tag that
+ specifies the type of element. The 16-bit tag is followed by a 16-bit value,
+ forming a tag-value pair.
+
+ If the tag is a negative number, then the actual tag is the negation of the
+ tag value and the negative sign indicates that the tag and its value are an
+ optional tag value pair. If the tag is a positive value, then the segment
+ is required. A decoder must be able to decode all required tag-value pairs,
+ but can skip tag-value pairs that are optional.
+
+ In a VC-5 Part 1 bitstream, the image width and height are an upper bound on the
+ dimensions of each channel represented in the bitstream. In a VC-5 Part 3 bitstream,
+ the image width and height are the actual dimensions of the image represented in the
+ bitstream. The width and height of the image and each pattern element is sufficient
+ to determine the width and height of each component array.
+
+ A range of tags is reserved for chunks and the value is the size of the chunk.
+*/
+typedef enum _codec_tag
+{
+ CODEC_TAG_ImageWidth = 20, //!< Upper bound on the width of the image
+ CODEC_TAG_ImageHeight = 21, //!< Upper bound on the height of the image
+ CODEC_TAG_BitsPerComponent = 101, //!< Number of bits in the source image
+ CODEC_TAG_ChannelCount = 12, //!< Number of channels in the transform
+ CODEC_TAG_SubbandCount = 14, //!< Number of encoded subbands
+ CODEC_TAG_ChannelNumber = 62, //!< Channel number
+ CODEC_TAG_SubbandNumber = 48, //!< Subband number of this wavelet band
+ CODEC_TAG_LowpassPrecision = 35, //!< Number of bits per lowpass coefficient
+ CODEC_TAG_Quantization = 53, //!< Quantization applied to band
+ CODEC_TAG_PrescaleShift = 109, //!< Packed prescale shift for each wavelet level
+ CODEC_TAG_ChannelWidth = 104, //!< Width of the next channel in the bitstream
+ CODEC_TAG_ChannelHeight = 105, //!< Height of the next channel in the bitstream
+
+ CODEC_TAG_LargeCodeblock = 0x6000, //!< Large chunk that contains a codeblock
+
+ CODEC_TAG_SMALL_CHUNK = 0x4000, //!< Small chunk with a 16-bit payload size (in segments)
+ CODEC_TAG_LARGE_CHUNK = 0x2000, //!< Large chunk with a 24-bit payload size (in segments)
+
+ //! Mask for detecting the tag for a small or large chunk (including codeblocks)
+ CODEC_TAG_CHUNK_MASK = (CODEC_TAG_SMALL_CHUNK | CODEC_TAG_LARGE_CHUNK),
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ // Codec tags used by VC-5 Part 3 bitstreams
+ CODEC_TAG_PatternWidth = 106, //!< Number of samples per row in each pattern element
+ CODEC_TAG_PatternHeight = 107, //!< Number of rows of samples in each pattern element
+ CODEC_TAG_ComponentsPerSample = 108, //!< Number of components in each sample in the pattern element
+ CODEC_TAG_ImageFormat = 84, //!< Format of the image represented by the bitstream
+ CODEC_TAG_MaxBitsPerComponent = 102, //!< Upper bound on the number of bits per component
+
+ // Small chunk elements defined by VC-5 Part 3
+ CODEC_TAG_VendorSpecificData = 0x4000, //!< Small chunk containing vendor-specific data
+ CODEC_TAG_InversePermutation = 0x4001, //!< Small chunk containing the inverse component permutation
+ CODEC_TAG_InverseTransform = 0x4002, //!< Small chunk containing the inverse component transform (8 bit representation)
+ CODEC_TAG_InverseTransform16 = 0x4003, //!< Small chunk containing the inverse component transform (16 bit representation)
+ CODEC_TAG_UniqueImageIdentifier = 0x4004, //!< Small chunk containing the identifier and sequence number for the image
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ CODEC_TAG_LayerCount = 120, //!< Number of layers in the bitstream
+ CODEC_TAG_LayerNumber = 121, //!< Number of the next layer in the bitstream
+ CODEC_TAG_LayerPattern = 122, //!< Mask indicating the use cases in the bitstream
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ CODEC_TAG_ImageCount = 130, //!< Number of image bitstream sections in the bitstream
+ CODEC_TAG_ImageNumber = 131, //!< Unique number assigned to an image bitstream section
+
+ // Predefined codec tags for structures in the VC-5 bitstream
+ CODEC_TAG_ImageSectionTag = 0x2700, //!< Section that contains a single image
+ CODEC_TAG_HeaderSectionTag = 0x2500, //!< Section that contains the bitstream header
+ CODEC_TAG_LayerSectionTag = 0x2600, //!< Section that contains a single layer
+ CODEC_TAG_ChannelSectionTag = 0x2400, //!< Section that contains a single channel
+ CODEC_TAG_WaveletSectionTag = 0x2100, //!< Section that contains all subbands for one wavelet
+ CODEC_TAG_SubbandSectionTag = 0x2000, //!< Section that contains a single subband
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_METADATA)
+ // Small and large chunks of metadata
+ CODEC_TAG_SmallMetadata = 0x4010, //!< Small chunk containing metadata tuples (VC-5 Part 7)
+ CODEC_TAG_LargeMetadata = 0x6100, //!< Large chunk containing metadata tuples (VC-5 Part 7)
+#endif
+
+} CODEC_TAG;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Format of the encoded sample
+
+ The VC-5 Part 3 can support four bitstream representations of the encoded image.
+
+ The image format must be specified for any VC-5 Part 3 bitstream.
+*/
+typedef enum _image_format
+{
+ IMAGE_FORMAT_UNKNOWN = 0, //!< The image format has not been specified
+ IMAGE_FORMAT_RAW = 4, //!< RAW image format (special case of CFA)
+
+ /***** Add new encoded formats above this line *****/
+
+ IMAGE_FORMAT_COUNT, //!< Number of image formats that have been defined
+
+} IMAGE_FORMAT;
+
+#endif
+
+
+/*!
+ @brief Band encoding method
+
+ Several different schemes have been tried for entropy coding the highpass bands.
+ The baseline profile only supports the run lengths encoding method.
+
+ The run lengths encoding method using a Huffman code to encode runs of zeros and
+ highpass coefficient magnitudes (unsigned). Runs of zeros can extend across row
+ boundaries, so large sections of a highpass band that are mostly zeros can be
+ encoded very efficiently.
+
+ @todo Need to cull this list as many band encoding methods are no longer supported.
+*/
+enum band_encoding {
+ BAND_ENCODING_ZEROTREE = 1,
+ BAND_ENCODING_CODEBOOK,
+ BAND_ENCODING_RUNLENGTHS,
+ BAND_ENCODING_16BIT,
+ BAND_ENCODING_LOSSLESS
+};
+
+/*!
+ The codec state contains information about the decoding process obtained
+ as a sample is decoded. The information is transient and is only used
+ while decoding a sample. The decoder data structure contains information
+ that should persist from onen sample to the next.
+
+ The codec state is initialized using information in the decoder data structure
+ at the start of decoding a sample.
+
+ The intent is that the encoder can operate the same state machine during encoding
+ and any information available in the state machine does not have to be encoded into
+ the sample as it is assumed that the decoder can and will derive the same information.
+ For example, the dimensions of the first subband can be computed from the encoded
+ dimensions and the number of wavelet levels, so it is not necessary to encode this
+ information. Likewise, after the last band in a wavelet is decoded the dimensions
+ of the bands in the wavelet at the next level can be deduced and it is not necessary
+ to encode this information into the sample.
+*/
+typedef struct _codec_state
+{
+ uint16_t channel_number; //!< Index of current channel being decoded
+ DIMENSION channel_width; //!< Width of the next channel in the bitstream
+ DIMENSION channel_height; //!< Height of the next channel in the bitstream
+ PRECISION bits_per_component; //!< Precision of the component array (in bits)
+
+ uint16_t subband_number; //!< Index of current subband being decoded
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ IMAGE_FORMAT image_format; //!< Format of the image represented by the bitstream
+ DIMENSION pattern_width; //!< Width of the pattern elements (in samples)
+ DIMENSION pattern_height; //!< Height of the pattern elements (in rows)
+ DIMENSION components_per_sample; //!< Number of components in each sample in the pattern element
+ PRECISION max_bits_per_component; //!< Maximum number of bits for each value in the component arrays
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ uint_least8_t layer_count;
+#endif
+
+ uint_least8_t channel_count; //!< Number of channels in the current layer
+ uint_least8_t wavelet_count; //!< Number of wavelets in the current layer
+ uint_least8_t subband_count; //!< Number of suibbands in the current layer
+
+ //! The channel position is used for skipping subbands and jumping to particular channels
+ size_t channel_position;
+
+ uint32_t encoded_format; //!< Internal encoded representation
+ uint32_t encoded_quality; //!< Quality setting of the encoded video
+
+ uint32_t decoded_subband_mask; //!< Indicates which subbands have been decoded
+
+ bool progressive; //!< True if the encoded frame is progressive
+
+ bool top_field_first; //!< True if the top field is encoded first
+
+ bool frame_inverted; //!< True if the frame is encoded upside down
+
+ uint_least8_t group_length; //!< Number of frames in a group of pictures (GOP)
+
+ //! Indicates that enough of the sample has been read to allow decoding the sample
+ bool end_of_sample;
+
+ //! Indicates that the layer has been decoded
+ bool end_of_layer;
+
+ //! Most recent tag-value pair was a header parameter
+ bool header;
+
+ //! Most recent syntax element was a codeblock (large chunk element)
+ bool codeblock;
+
+ //! Parameters of the most recently decoded subband
+ struct
+ {
+ //DIMENSION width; //!< Width of the decoded band
+ //DIMENSION height; //!< Height of the decoded band
+ uint_least8_t subband; //!< Subband index
+ //uint_least8_t encoding; //!< Band encoding method
+ uint16_t quantization; //!< Quantization parameter
+
+ } band; //!< Information about the current highpass band
+
+ DIMENSION image_width; //!< Upper bound on the channel width
+ DIMENSION image_height; //!< Upper bound on the channel height
+
+ PRECISION lowpass_precision; //!< Number of bits per lowpass coefficient
+
+ /*!
+ @brief Table of prescale shifts applied before computing each wavelet transform
+
+ The prescale shift was applied by the encoder to each input to the forward
+ wavelet transform. The table of prescale values is indexed by the same
+ index used for the wavelets in the transform.
+ */
+ //uint_fast8_t prescale_table[MAX_WAVELET_COUNT];
+ PRESCALE prescale_table[MAX_WAVELET_COUNT];
+
+ //! Picture aspect ratio read from the encoded sample
+ struct _picture_aspect_ratio
+ {
+ uint_least16_t x; //!< Relative width of the picture
+ uint_least16_t y; //!< Relative height of the picture
+
+ } picture_aspect_ratio; //!< Picture aspect ratio read from the sample
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ uint32_t interlaced_flags;
+ uint32_t protection_flags;
+
+ //!< Parameters of the current layer
+ struct
+ {
+ int width; //!< Width of the current layer
+ int height; //!< Height of the current layer
+
+ } layer; //!< Information about the encoded layer from the sample
+
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ int section_number; //!< Number of the most recent section encountered in the bitstream
+ int section_length; //!< Length of the most recent section element payload (in segments)
+#endif
+
+} CODEC_STATE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Initialize the codec state
+ CODEC_ERROR PrepareCodecState(CODEC_STATE *codec);
+
+ uint32_t EncoderVersion(uint32_t value);
+
+ uint32_t RepackedEncoderVersion(uint32_t value);
+
+ void SetCodecVersion(uint8_t version[3], uint16_t value);
+
+ CODEC_ERROR UpdatePrescaleTable(CODEC_STATE *codec, TAGWORD value);
+
+ CODEC_ERROR UpdateSampleFlags(CODEC_STATE *codec, TAGWORD value);
+
+ CODEC_ERROR UpdateCodecFlags(CODEC_STATE *codec, TAGWORD value);
+
+ CODEC_ERROR UpdateFrameStructureFlags(CODEC_STATE *codec, TAGWORD value);
+
+ CODEC_ERROR SetBandCoding(CODEC_STATE *codec, TAGWORD value);
+
+ bool IsPartEnabled(ENABLED_PARTS enabled_parts, int part_number);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CODEC_H
diff --git a/gpr/source/lib/vc5_common/codeset.h b/gpr/source/lib/vc5_common/codeset.h
new file mode 100755
index 0000000..e220239
--- /dev/null
+++ b/gpr/source/lib/vc5_common/codeset.h
@@ -0,0 +1,44 @@
+/*! @file codeset.h
+ *
+ * @brief The codeset data structure includes the codebook and flags that
+ * indicate how to use the codebook. The codeset may also include tables
+ * that are derived from the codebook to facilite encoding and decoding.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODESET_H
+#define CODESET_H
+
+/*!
+ @brief Codeset flags that determine how the codebook is used for encoding
+
+ The codeset flags determine how the codebook in the codeset is used to
+ compute the tables for encoding coefficient magnitudes and runs of zeros.
+
+ The companding curve is applied to the quantized coefficients before the
+ values are entropy coded to fit the coefficient magnitudes into the range
+ of magnitudes provided by the codebook. The companding curve is applied
+ when the encoding table for coefficient magnitudes is computed.
+*/
+typedef enum _codeset_flags
+{
+ CODESET_FLAGS_COMPANDING_NONE = 0x0002, //!< Do not apply a companding curve
+ CODESET_FLAGS_COMPANDING_CUBIC = 0x0004, //!< Apply a cubic companding curve
+
+} CODESET_FLAGS;
+
+#endif // CODESET_H
diff --git a/gpr/source/lib/vc5_common/common.h b/gpr/source/lib/vc5_common/common.h
new file mode 100755
index 0000000..c0ff501
--- /dev/null
+++ b/gpr/source/lib/vc5_common/common.h
@@ -0,0 +1,53 @@
+/*! @file common.h
+ *
+ * @brief This file includes all of the header files that are used by
+ * the encoder and decoder. Including a single header file in all
+ * reference encoder and decoder source files ensures that all
+ * modules see the same header files in the same order.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "gpr_platform.h"
+#include "gpr_allocator.h"
+#include "gpr_buffer.h"
+#include "gpr_rgb_buffer.h"
+
+#include "stdc_includes.h"
+
+#include "log.h"
+#include "types.h"
+#include "timer.h"
+#include "config.h"
+#include "macros.h"
+#include "error.h"
+#include "pixel.h"
+#include "image.h"
+#include "logcurve.h"
+#include "wavelet.h"
+#include "bitstream.h"
+#include "stream.h"
+#include "companding.h"
+#include "syntax.h"
+#include "codec.h"
+#include "codeset.h"
+#include "utilities.h"
+#include "unique.h"
+
+#endif // COMMON_H
diff --git a/gpr/source/lib/vc5_common/companding.c b/gpr/source/lib/vc5_common/companding.c
new file mode 100755
index 0000000..00b0fb5
--- /dev/null
+++ b/gpr/source/lib/vc5_common/companding.c
@@ -0,0 +1,259 @@
+/*! @file companding.c
+ *
+ * @brief Implementation of the routines for computing the companding curves
+ * that is applied to the quantized coefficient magnitudes.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+//TODO: Change the companding parameter into a global constant
+
+#ifndef COMPANDING
+#define COMPANDING 1
+#define COMPANDING_MORE (54) // Zero means no companding (54 is a good value)
+#endif
+
+
+/*!
+ @brief Maximum coefficient magnitude in the codebook
+
+ @todo Need to calculate the maximum value from the codebook
+*/
+const int maximum_codebook_value = 255;
+
+
+/*!
+ @brief Apply the default companding curve to the specified value
+
+ Note that this companding curve has been superceeded by the cubic curve.
+*/
+int32_t CompandedValue(int32_t value)
+{
+ const int midpoint_rounding = 2;
+
+ int32_t magnitude = absolute(value);
+
+#if COMPANDING
+ if (magnitude >= 40)
+ {
+ magnitude -= 40;
+ magnitude += midpoint_rounding;
+ magnitude >>= 2;
+ magnitude += 40;
+
+ #if COMPANDING_MORE
+ if (magnitude >= COMPANDING_MORE)
+ {
+ magnitude -= COMPANDING_MORE;
+ magnitude += midpoint_rounding;
+ magnitude >>= 2;
+ magnitude += COMPANDING_MORE;
+ }
+#endif
+ }
+#endif
+
+ // Restore the sign to the companded value
+ return ((value >= 0) ? magnitude : neg(magnitude));
+}
+
+/*!
+ @brief Return the parameter that controls the companding curve
+
+ This parameter does not apply if the cubic companding curve is used.
+*/
+uint32_t CompandingParameter()
+{
+ return COMPANDING_MORE;
+}
+
+/*!
+ @brief Compute a table of values for the cubic companding curve
+
+ The companding curve is f(x) = x + (x ^ 3 / (255 ^ 3)) * 768
+ so the range of coefficient magnitudes from 0 to 255 becomess 0 to 1023.
+*/
+CODEC_ERROR ComputeCubicTable(int16_t cubic_table[], int cubic_table_length, int16_t maximum_value)
+{
+ size_t cubic_table_size = cubic_table_length * sizeof(cubic_table[0]);
+ int last_cubic_table_index = cubic_table_length - 2;
+ int16_t last_magnitude;
+ int16_t index;
+
+ // Clear the cubic table
+ memset(cubic_table, 0, cubic_table_size);
+
+ for (index = 1; index <= maximum_value; index++)
+ {
+ double cubic = index;
+
+ int magnitude = index;
+
+ cubic *= index;
+ cubic *= index;
+ cubic *= 768;
+ //cubic /= 256*256*256;
+ cubic /= 255*255*255;
+
+ magnitude += (int)cubic;
+
+ //if (mag > 1023) mag = 1023;
+ if (magnitude > last_cubic_table_index) {
+ magnitude = last_cubic_table_index;
+ }
+
+ cubic_table[magnitude] = index;
+ }
+
+ // Fill unused entries in the cubic table
+ last_magnitude = 0;
+ for (index = 0; index < cubic_table_length; index++)
+ {
+ if (cubic_table[index])
+ {
+ last_magnitude = cubic_table[index];
+ }
+ else
+ {
+ cubic_table[index] = last_magnitude;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Invert the companding curve applied during encoding
+*/
+int32_t UncompandedValue(int32_t value)
+{
+#if 1 //CUBIC_COMPANDING
+ double cubic;
+ int32_t magnitude = absolute(value);
+
+ cubic = magnitude;
+ cubic *= magnitude;
+ cubic *= magnitude;
+ cubic *= 768;
+ //cubic /= 256*256*256;
+ cubic /= 255*255*255;
+
+ magnitude += (int32_t)cubic;
+
+ // Restore the sign
+ value = ((value < 0) ? neg(magnitude) : magnitude);
+#else
+ if (40 <= value && value < 264)
+ {
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+ }
+ else if (value <= -40)
+ {
+ // Apply the inverse companding formula to the absolute value
+ value = -value;
+
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+
+ // Restore the sign
+ value = -value;
+ }
+#endif
+
+ return value;
+}
+
+/*!
+ @brief Invert the companding curve applied to a pixel
+*/
+PIXEL UncompandedPixel(PIXEL value)
+{
+#if 1 //CUBIC_COMPANDING
+ double cubic;
+ int32_t magnitude = absolute(value);
+
+ cubic = magnitude;
+ cubic *= magnitude;
+ cubic *= magnitude;
+ cubic *= 768;
+ //cubic /= 256*256*256;
+ cubic /= 255*255*255;
+
+ magnitude += (int32_t)cubic;
+
+ // Restore the sign
+ value = ClampPixel((value < 0) ? neg(magnitude) : magnitude);
+#else
+ if (40 <= value && value < 264)
+ {
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+ }
+ else if (value <= -40)
+ {
+ // Apply the inverse companding formula to the absolute value
+ value = neg(value);
+
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+
+ // Restore the sign
+ value = neg(value);
+ }
+#endif
+
+ return value;
+}
+
diff --git a/gpr/source/lib/vc5_common/companding.h b/gpr/source/lib/vc5_common/companding.h
new file mode 100755
index 0000000..5931e73
--- /dev/null
+++ b/gpr/source/lib/vc5_common/companding.h
@@ -0,0 +1,46 @@
+/*! @file companding.h
+ *
+ * @brief Declaration of the routines for computing the companding curves
+ * that is applied to the quantized coefficient magnitudes.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPANDING_H
+#define COMPANDING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int32_t CompandedValue(int32_t value);
+
+ uint32_t CompandingParameter(void);
+
+ CODEC_ERROR ComputeCubicTable(int16_t cubic_table[], int cubic_table_length, int16_t maximum_value);
+
+ // Invert the companding curve applied to a quantized coefficient magnitude (for debugging)
+ int32_t UncompandedValue(int32_t value);
+
+ PIXEL UncompandedPixel(PIXEL value);
+
+ CODEC_ERROR InvertCompanding(PIXEL *image, DIMENSION width, DIMENSION height, DIMENSION pitch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COMPANDING_H
diff --git a/gpr/source/lib/vc5_common/config.h b/gpr/source/lib/vc5_common/config.h
new file mode 100755
index 0000000..5169510
--- /dev/null
+++ b/gpr/source/lib/vc5_common/config.h
@@ -0,0 +1,87 @@
+/*! @file config.h
+ *
+ * @brief Parameters that control the configuration of the codec.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+// Maximum number of layers
+#define MAX_LAYER_COUNT 10
+
+// Maximum number of color channels
+#define MAX_CHANNEL_COUNT 4
+//const int MAX_CHANNEL_COUNT = 4;
+
+// Maximum number of wavelets per channel
+#define MAX_WAVELET_COUNT 3
+//const int MAX_WAVELET_COUNT = 3;
+
+// Maximum number of bands per wavelet
+#define MAX_BAND_COUNT 4
+//const int MAX_BAND_COUNT = 4;
+
+// Maximum number of subbands in all wavelets (including the lowpass band in the first wavelet)
+#define MAX_SUBBAND_COUNT 10
+
+// The number of prescale values that are encoded into the bitstream
+#define MAX_PRESCALE_COUNT 8
+
+//TODO: The maximum number of channels and wavelets depends on the profile
+
+//! Internal precision of the intermediate results after unpacking
+static const int default_internal_precision = 12;
+
+//TODO: Change the global variable from internal_precision to encoded_precision?
+
+// Definitions of VC-5 parts
+#define VC5_PART_ELEMENTARY 1
+#define VC5_PART_CONFORMANCE 2 // Conformance does not affect what capabilities are included
+#define VC5_PART_IMAGE_FORMATS 3
+#define VC5_PART_COLOR_SAMPLING 4
+#define VC5_PART_LAYERS 5
+#define VC5_PART_SECTIONS 6
+#define VC5_PART_METADATA 7
+
+// Convert a part number into a part mask
+#define VC5_PART_MASK(n) (1 << ((n)-1))
+
+// Define the parts supported by this codec implementation
+#define VC5_ENABLED_PARTS (VC5_PART_MASK(VC5_PART_ELEMENTARY) | \
+ VC5_PART_MASK(VC5_PART_IMAGE_FORMATS) | \
+ VC5_PART_MASK(VC5_PART_COLOR_SAMPLING) | \
+ VC5_PART_MASK(VC5_PART_SECTIONS))
+
+// Compile code if any of the parts in the specified mask are supported
+#define VC5_ENABLED_MASK(m) ((VC5_ENABLED_PARTS & (m)) != 0)
+
+// Macro for testing support for a specific part of the VC-5 standard
+#define VC5_ENABLED_PART(n) (VC5_ENABLED_MASK(VC5_PART_MASK(n)))
+
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+
+// Maximum number of layers supported by the reference codec
+#define MAX_LAYER_COUNT 10
+
+#endif
+
+//! Number of rows of intermediate horizontal transform results
+#define ROW_BUFFER_COUNT 6
+
+#endif // CONFIG_H
diff --git a/gpr/source/lib/vc5_common/error.h b/gpr/source/lib/vc5_common/error.h
new file mode 100755
index 0000000..fbb1573
--- /dev/null
+++ b/gpr/source/lib/vc5_common/error.h
@@ -0,0 +1,88 @@
+/*! @file config.h
+ *
+ * @brief Definitions of the error codes reported by this codec implementation
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ERROR_H
+#define ERROR_H
+
+/*!
+ @brief Codec error codes
+*/
+typedef enum _codec_error
+{
+ CODEC_ERROR_OKAY = 0, //!< No error
+ CODEC_ERROR_UNEXPECTED, //!< Encountered an unexpected condition
+ CODEC_ERROR_OUTOFMEMORY, //!< Memory allocation failed
+ CODEC_ERROR_UNIMPLEMENTED, //!< Function has not been implemented
+ CODEC_ERROR_NULLPTR, //!< Data structure or argument pointer was null
+ CODEC_ERROR_BITSTREAM_SYNTAX, //!< Error in the sequence of tag value pairs
+ CODEC_ERROR_IMAGE_DIMENSIONS, //!< Wrong or unknown image dimensions
+ CODEC_ERROR_INVALID_TAG, //!< Found a tag that should not be present
+ CODEC_ERROR_INVALID_BAND, //!< Wavelet band index is out of range
+ CODEC_ERROR_DECODING_SUBBAND, //!< Error decoding a wavetet subband
+ CODEC_ERROR_NOTFOUND, //!< Did not find a value codeword
+ CODEC_ERROR_BAND_END_MARKER, //!< Could not find special codeword after end of band
+ CODEC_ERROR_BAND_END_TRAILER, //!< Could not find start of highpass band trailer
+ CODEC_ERROR_PIXEL_FORMAT, //!< Unsupported pixel format
+ CODEC_ERROR_INVALID_MARKER, //!< Bitstream marker was not found in the codebook
+ CODEC_ERROR_FILE_GET_POSITION, //!< Could not get position of the file stream
+ CODEC_ERROR_FILE_SEEK, //!< Could not seek to a position in a file stream
+ CODEC_ERROR_FILE_READ, //!< Read from a file stream failed
+ CODEC_ERROR_FILE_WRITE, //!< Write to a file stream failed
+ CODEC_ERROR_CHANNEL_SIZE_TABLE, //!< Could not write the channel size table
+ CODEC_ERROR_UNSUPPORTED_FORMAT, //!< Pixel or encoded format is not supported
+ CODEC_ERROR_MISSING_START_MARKER, //!< Bitstream does not begin with the start marker
+ CODEC_ERROR_DUPLICATE_HEADER_PARAMETER, //!< Header parameter occurs more than once
+ CODEC_ERROR_REQUIRED_PARAMETER, //!< Optional tag-value pair for a required parameter
+ CODEC_ERROR_LOWPASS_PRECISION, //!< Number of bits per lowpass coefficient out of range
+ CODEC_ERROR_LOWPASS_VALUE, //!< Lowpass coefficient value is out of range
+ CODEC_ERROR_IMAGE_TYPE, //!< Could not determine the characteristics of the input image
+ CODEC_ERROR_BAD_IMAGE_FORMAT, //!< Bad image format (VC-5 Part 3 only)
+ CODEC_ERROR_PATTERN_DIMENSIONS, //!< Bad pattern dimensions (VC-5 Part 3 only)
+ CODEC_ERROR_ENABLED_PARTS, //!< Incorrect enabled parts of the VC-5 standard
+ CODEC_ERROR_SYNTAX_ERROR, //!< Unspecified error in the bitstream syntax
+ CODEC_ERROR_UMID_LABEL, //!< Incorrect UMID label
+ CODEC_ERROR_BAD_SECTION_TAG, //!< The specified tag does not correspond to a section header
+
+
+ /***** Reserve a block of error codes for the bitstream *****/
+
+ CODEC_ERROR_BITSTREAM = (1 << 10), //!< Block of bitstream error codes
+
+
+ /***** Reserve a block of error codes for the calling application *****/
+
+ CODEC_ERROR_APPLICATION = (16 << 10), //!< Block of error codes for the application
+ CODEC_ERROR_MISSING_ARGUMENT, //!< Program did not have enough arguments
+ CODEC_ERROR_BAD_ARGUMENT, //!< Invalid value for one of the arguments
+ CODEC_ERROR_OPEN_FILE_FAILED, //!< Could not open the file for reading
+ CODEC_ERROR_CREATE_FILE_FAILED, //!< Could not open the file for writing
+ CODEC_ERROR_UNSUPPORTED_FILE_TYPE, //!< The output file type is not supported
+ CODEC_ERROR_FILE_SIZE_FAILED, //!< Could not determine the size of the file
+ CODEC_ERROR_READ_FILE_FAILED, //!< Could not read a file
+ CODEC_ERROR_FILE_WRITE_FAILED, //!< Could not write to the file
+ CODEC_ERROR_FILE_FLUSH_FAILED, //!< Could not flush the file buffer
+ CODEC_ERROR_PARSE_ARGUMENTS, //!< Error while parsing the command-line arguments
+ CODEC_ERROR_USAGE_INFO, //!< User asked for help with program usage
+ CODEC_ERROR_BANDFILE_FAILED, //!< Could not write the bandfile
+ CODEC_ERROR_BAD_PARAMETER, //!< Missing or inconsistent parameters
+
+} CODEC_ERROR;
+
+#endif // ERROR_H
diff --git a/gpr/source/lib/vc5_common/image.c b/gpr/source/lib/vc5_common/image.c
new file mode 100755
index 0000000..0af14fe
--- /dev/null
+++ b/gpr/source/lib/vc5_common/image.c
@@ -0,0 +1,321 @@
+/*! @file image.c
+ *
+ * @brief Implementation of the data structure for the image that is
+ * input to the image unpacking process.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+/*!
+ @brief Initialize the fields in an image data structure
+ This routine is the constructor for the image data type that
+ initializes an image instance to default values.
+ */
+CODEC_ERROR InitImage(IMAGE *image)
+{
+ if (image != NULL)
+ {
+ image->width = 0;
+ image->height = 0;
+ image->pitch = 0;
+ image->offset = 0;
+ image->format = PIXEL_FORMAT_UNKNOWN;
+ image->buffer = NULL;
+ image->size = 0;
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_NULLPTR;
+}
+
+CODEC_ERROR InitRGBImage(RGB_IMAGE *image)
+{
+ if (image != NULL)
+ {
+ image->width = 0;
+ image->height = 0;
+ image->pitch = 0;
+ image->buffer = NULL;
+ image->size = 0;
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_NULLPTR;
+}
+/*!
+ @brief Allocate the buffer for a image with the sepcified dimensions and format.
+ This routine calculates the image pitch from the width and format, rounding up
+ the pitch to satisfy memory alignment requirements in the codec.
+ This routine will cause a memory leak if it is called with a image that has
+ already been allocated.
+ */
+CODEC_ERROR AllocImage(gpr_allocator *allocator, IMAGE *image, DIMENSION width, DIMENSION height, PIXEL_FORMAT format)
+{
+ size_t size = 0;
+ DIMENSION pitch = 0;
+
+ assert(image != NULL);
+
+ // Compute the pitch from the width and format
+ pitch = ImagePitch(width, format);
+ assert(pitch > 0);
+
+#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING)
+ size = height * pitch;
+#else
+ size = height * pitch;
+#endif
+ assert(size > 0);
+
+ // Allocate the image buffer
+ image->buffer = allocator->Alloc(size);
+ if (image->buffer != NULL)
+ {
+ image->width = width;
+ image->height = height;
+ image->pitch = pitch;
+ image->format = format;
+ image->offset = 0;
+ image->size = size;
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_OUTOFMEMORY;
+}
+
+/*!
+ @brief Deallocate the buffer in a image data structure
+ This routine does not deallocate the image data structure itself.
+ In the typical use case, the image data structure is allocated on
+ the stack and teh decoder allocates the buffer for the output image
+ after determining the size of the image. The image data structure
+ is deallocated automatically by a calling routine.
+ */
+CODEC_ERROR ReleaseImage(gpr_allocator *allocator, IMAGE *image)
+{
+ allocator->Free(image->buffer);
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Compute the image pitch for the specified width and pixel format
+ The pitch of the image (in bytes) is computed for a image with the width
+ and pixel format that is specified. The pitch is rounted up to satisfy
+ memory alignment constraints required by the codec.
+ The return value is zero if the pitch could not be computed for the
+ specified width and format.
+ */
+DIMENSION ImagePitch(DIMENSION width, PIXEL_FORMAT format)
+{
+ DIMENSION pitch = 0;
+
+ switch (format)
+ {
+ case PIXEL_FORMAT_RAW_RGGB_14:
+ case PIXEL_FORMAT_RAW_GBRG_12:
+ case PIXEL_FORMAT_RAW_GBRG_12P:
+ case PIXEL_FORMAT_RAW_RGGB_16:
+ // Half the width of the image times 2 samples times 2 bytes per sample
+ pitch = width * sizeof(uint16_t);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return pitch;
+}
+
+/*!
+ @brief Set the dimensions and pixel format of a image
+ This routine is used to set the dimensions and format of a image
+ that was allocated with unknown parameters.
+ */
+CODEC_ERROR SetImageFormat(IMAGE *image,
+ DIMENSION width,
+ DIMENSION height,
+ DIMENSION pitch,
+ PIXEL_FORMAT format,
+ size_t offset)
+{
+ assert(image != NULL);
+
+ image->width = width;
+ image->height = height;
+ image->pitch = pitch;
+ image->format = format;
+ image->offset = offset;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return the address of the image in the buffer
+ This routine should be used to obtain the starting address of
+ a image in a image buffer since the image may be offset from the
+ beginning of the buffer.
+ */
+void *ImageData(IMAGE *image)
+{
+ uint8_t *buffer = image->buffer;
+ buffer += image->offset;
+ return buffer;
+}
+
+/*!
+ @brief Return the address of the specified row in the image
+ The routine returns NULL if the image argument is null or the
+ specified row is out of bounds.
+ */
+void *RowAddress(IMAGE *image, DIMENSION row)
+{
+ size_t pitch = image->pitch;
+
+ if (image != NULL && image->pitch != 0)
+ {
+ //if (0 <= row && row < image->height)
+ if (row < image->height)
+ {
+ void *address = (void *)((uintptr_t)ImageData(image) + row * pitch);
+ return address;
+ }
+ }
+
+ // Could not compute the address of a valid row
+ return NULL;
+}
+
+CODEC_ERROR ReleaseComponentArrays(gpr_allocator *allocator,
+ UNPACKED_IMAGE *image,
+ int channel_count )
+{
+ int channel;
+
+ for (channel = 0; channel < channel_count; channel++)
+ {
+ allocator->Free( image->component_array_list[channel].data );
+ }
+
+ allocator->Free( image->component_array_list );
+
+ return CODEC_ERROR_OKAY;
+}
+
+CODEC_ERROR AllocateComponentArrays(gpr_allocator *allocator,
+ UNPACKED_IMAGE *image,
+ int channel_count,
+ DIMENSION max_channel_width,
+ DIMENSION max_channel_height,
+ PIXEL_FORMAT format,
+ int bits_per_component)
+{
+ int channel;
+
+ // Allocate the vector of component arrays
+ size_t size = channel_count * sizeof(COMPONENT_ARRAY);
+ image->component_array_list = allocator->Alloc(size);
+ if (image->component_array_list == NULL) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ // Clear the component array information so that the state is consistent
+ image->component_count = 0;
+ memset(image->component_array_list, 0, size);
+
+ // Initialize each component array
+ for (channel = 0; channel < channel_count; channel++)
+ {
+ DIMENSION channel_width = max_channel_width;
+ DIMENSION channel_height = max_channel_height;
+
+ // Allocate space for the data in the component array
+ CODEC_ERROR error = AllocateComponentArray( allocator, &image->component_array_list[channel], channel_width, channel_height, (uint_least8_t)bits_per_component );
+
+ if( error != CODEC_ERROR_OKAY ) {
+ return error;
+ }
+ }
+
+ // Set the number of component arrays
+ image->component_count = channel_count;
+
+ return CODEC_ERROR_OKAY;
+}
+
+CODEC_ERROR AllocateComponentArray(gpr_allocator *allocator,
+ COMPONENT_ARRAY *component_array,
+ DIMENSION width,
+ DIMENSION height,
+ PRECISION bits_per_component)
+{
+ //COMPONENT_ARRAY *component_array = Alloc(allocator, sizeof(COMPONENT_ARRAY));
+
+ // Allocate space for the data in the component array
+ size_t pitch = width * sizeof(COMPONENT_VALUE);
+ size_t size = height * pitch;
+ void *buffer = allocator->Alloc(size);
+ assert(buffer != NULL);
+ if (! (buffer != NULL)) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ component_array->width = width;
+ component_array->height = height;
+ component_array->pitch = pitch;
+ component_array->data = buffer;
+ component_array->bits_per_component = bits_per_component;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize the data structure for the unpacked image
+ Note that the component arrays will be allocated after the bitstream
+ has been decoded and the dimensions of the component arrys are known.
+ */
+CODEC_ERROR InitUnpackedImage(UNPACKED_IMAGE *unpacked_image)
+{
+ if (unpacked_image == NULL) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ // Clear the fields in the unpacked iamge
+ memset(unpacked_image, 0, sizeof(UNPACKED_IMAGE));
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return the maximum number of bits per component across all channels in the unpacked image
+ */
+PRECISION MaxBitsPerComponent(const UNPACKED_IMAGE *image)
+{
+ PRECISION max_bits_per_component = 0;
+ int channel;
+
+ for (channel = 0; channel < image->component_count; channel++)
+ {
+ COMPONENT_ARRAY *component_array = &image->component_array_list[channel];
+
+ if (max_bits_per_component < component_array->bits_per_component) {
+ max_bits_per_component = component_array->bits_per_component;
+ }
+ }
+
+ return max_bits_per_component;
+}
diff --git a/gpr/source/lib/vc5_common/image.h b/gpr/source/lib/vc5_common/image.h
new file mode 100755
index 0000000..4739727
--- /dev/null
+++ b/gpr/source/lib/vc5_common/image.h
@@ -0,0 +1,165 @@
+/*! @file image.h
+ *
+ * @brief Declaration of structures and functions for images
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMAGE_H
+#define IMAGE_H
+
+//! Data type for the values in a component array
+typedef uint16_t COMPONENT_VALUE;
+
+/*!
+ @brief Data structure for an image input to the unpacking process
+
+ This data structure is used to represent the image that is the input to the
+ image unpacking process that unpacks an image into component arrays for encoding.
+ Unlike the wavelet data structures, an image contains multiple color components,
+ usually in a packed pixel format.
+*/
+typedef struct _packed_image
+{
+ DIMENSION width; //!< Width of the frame (in pixels)
+ DIMENSION height; //!< Height of the frame
+ size_t pitch; //!< Distance between rows (in bytes)
+ PIXEL_FORMAT format; //!< Format of the pixels
+ void *buffer; //!< Address of the buffer for the frame
+ size_t size; //!< Allocated size of the buffer (in bytes)
+ size_t offset; //!< Offset to the start of the frame
+} PACKED_IMAGE;
+
+/*!
+ @brief Data structure for an image input to the unpacking process
+
+ This data structure is used to represent the image that is the input to the
+ image unpacking process that unpacks an image into component arrays for encoding.
+ Unlike the wavelet data structures, an image contains multiple color components,
+ usually in a packed pixel format.
+ */
+typedef struct _rgb_image
+{
+ DIMENSION width; //!< Width of the frame (in pixels)
+ DIMENSION height; //!< Height of the frame
+ size_t pitch; //!< Distance between rows (in bytes)
+ void *buffer; //!< Address of the buffer for the frame
+ size_t size; //!< Allocated size of the buffer (in bytes)
+} RGB_IMAGE;
+
+//! Short name for the packed image data type
+typedef PACKED_IMAGE IMAGE;
+
+/*!
+ @brief Data structure for an array that contains a single type of component
+
+ This data structure is used to represent the component array output by the image
+ unpacking process. The image unpacking process unpacks an image into component
+ arrays for encoding.
+*/
+typedef struct _component_array
+{
+ DIMENSION width; //!< Width of the frame (in pixels)
+ DIMENSION height; //!< Height of the frame
+ size_t pitch; //!< Distance between rows (in bytes)
+ COMPONENT_VALUE *data; //!< Buffer for the array of component values
+
+ //! Number of bits per in each component value
+ PRECISION bits_per_component;
+
+} COMPONENT_ARRAY;
+
+/*!
+ @brief Image represented as an ordered set of component arrays
+
+ The decoder outputs a set of component arrays that represent an image.
+
+ The image repacking process can pack the component arrays output by the
+ decoder into a packed image.
+*/
+typedef struct _unpacked_image
+{
+ //! Number of component arrays in the unpacked image
+ int component_count;
+
+ //! Vector of component arrays
+ COMPONENT_ARRAY *component_array_list;
+
+} UNPACKED_IMAGE;
+
+/*!
+ @brief Flags that describe the image structure
+*/
+typedef enum
+{
+ IMAGE_STRUCTURE_INTERLACED = 0x0001, //!< Set the first bit if the image is interlaced
+ IMAGE_STRUCTURE_BOTTOM_FIELD_FIRST = 0x0002, //!< The bottom field is encoded before the top field
+ IMAGE_STRUCTURE_BOTTOM_ROW_FIRST = 0x0010, //!< The encoded image is upside down
+} IMAGE_STRUCTURE;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InitImage(IMAGE *image);
+
+ CODEC_ERROR InitRGBImage(RGB_IMAGE *image);
+
+ CODEC_ERROR AllocImage(gpr_allocator *allocator, IMAGE *image, DIMENSION width, DIMENSION height, PIXEL_FORMAT format);
+
+ CODEC_ERROR ReleaseImage(gpr_allocator *allocator, IMAGE *image);
+
+ DIMENSION ImagePitch(DIMENSION width, PIXEL_FORMAT format);
+
+ CODEC_ERROR SetImageFormat(IMAGE *image,
+ DIMENSION width,
+ DIMENSION height,
+ DIMENSION pitch,
+ PIXEL_FORMAT format,
+ size_t offset);
+
+ void *ImageData(IMAGE *image);
+
+ void *RowAddress(IMAGE *image, DIMENSION row);
+
+ CODEC_ERROR ReleaseComponentArrays(gpr_allocator *allocator,
+ UNPACKED_IMAGE *image,
+ int channel_count );
+
+ CODEC_ERROR AllocateComponentArrays(gpr_allocator *allocator,
+ UNPACKED_IMAGE *image,
+ int channel_count,
+ DIMENSION max_channel_width,
+ DIMENSION max_channel_height,
+ PIXEL_FORMAT format,
+ int bits_per_component);
+
+ CODEC_ERROR AllocateComponentArray(gpr_allocator *allocator,
+ COMPONENT_ARRAY *component_array,
+ DIMENSION width,
+ DIMENSION height,
+ PRECISION bits_per_component);
+
+ CODEC_ERROR InitUnpackedImage(UNPACKED_IMAGE *image);
+
+ PRECISION MaxBitsPerComponent(const UNPACKED_IMAGE *image);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // IMAGE_H
diff --git a/gpr/source/lib/vc5_common/logcurve.c b/gpr/source/lib/vc5_common/logcurve.c
new file mode 100755
index 0000000..45aecbf
--- /dev/null
+++ b/gpr/source/lib/vc5_common/logcurve.c
@@ -0,0 +1,58 @@
+/*! @file logcurve.c
+ *
+ * @brief Implementation of functions used to do log conversion.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+uint16_t EncoderLogCurve[LOG_CURVE_TABLE_LENGTH];
+
+uint16_t DecoderLogCurve[LOG_CURVE_TABLE_LENGTH];
+
+void SetupDecoderLogCurve(void)
+{
+ int i;
+ const int log_table_size = sizeof(DecoderLogCurve) / sizeof(DecoderLogCurve[0]);
+
+ const int max_16_bit = (1 << 16) - 1;
+
+ for( i = 0; i < log_table_size; i++ )
+ {
+ //input 12-bit, output 16-bit
+ float input = i;
+ float output = max_16_bit * (pow(113.0, input/4095.0) - 1.0)/112.0;
+
+ DecoderLogCurve[i] = minimum( (int)output, max_16_bit );
+ }
+}
+
+void SetupEncoderLogCurve(void)
+{
+ int i;
+ const int max_input_val = LOG_CURVE_TABLE_LENGTH - 1;
+
+ for( i = 0; i < LOG_CURVE_TABLE_LENGTH; i++ )
+ {
+ //input 16-bit, output 12-bit
+ float input = maximum( 0, i );
+ float output = 4095.0 * (log10(input/max_input_val * 112.0 + 1.0)/log10(113));
+
+ EncoderLogCurve[i] = ( (uint16_t)output );
+ }
+}
+
diff --git a/gpr/source/lib/vc5_common/logcurve.h b/gpr/source/lib/vc5_common/logcurve.h
new file mode 100755
index 0000000..3e6a269
--- /dev/null
+++ b/gpr/source/lib/vc5_common/logcurve.h
@@ -0,0 +1,42 @@
+/*! @file logcurve.h
+ *
+ * @brief Declaration of the data structures and constants used to do log conversion.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGCURVE_H
+#define LOGCURVE_H
+
+#define LOG_CURVE_TABLE_LENGTH (1 << 12)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern uint16_t EncoderLogCurve[];
+
+ extern uint16_t DecoderLogCurve[];
+
+ void SetupDecoderLogCurve(void);
+
+ void SetupEncoderLogCurve(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LOGCURVE_H
diff --git a/gpr/source/lib/vc5_common/pixel.h b/gpr/source/lib/vc5_common/pixel.h
new file mode 100755
index 0000000..7c3b9e0
--- /dev/null
+++ b/gpr/source/lib/vc5_common/pixel.h
@@ -0,0 +1,100 @@
+/*! @file pixel.h
+ *
+ * @brief The pixel format enumerations define the pixel packing formats that are
+ * supported by the codec for input to the image unpacking process and for
+ * output from the image repacking process.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PIXEL_H
+#define PIXEL_H
+
+//! Data type for pixels
+typedef int16_t PIXEL;
+
+//! Minimum and maximum pixel values
+enum {
+ PIXEL_MIN = INT16_MIN,
+ PIXEL_MAX = INT16_MAX,
+};
+
+//! Alternative definition for wavelet coefficients
+typedef int16_t COEFFICIENT;
+
+//! Minimum and maximum coefficient values
+enum
+{
+ COEFFICIENT_MIN = INT16_MIN,
+ COEFFICIENT_MAX = INT16_MAX,
+};
+
+/*!
+ @brief Pixels formats supported by the codec
+
+ The pixel format is only the packing arrangement for color components and
+ does not specify whether the image is interlaced or the bottom row is first.
+
+ @todo Need to add support for more pixel formats to the reference decoder
+*/
+typedef enum
+{
+ PIXEL_FORMAT_UNKNOWN = 0,
+
+ PIXEL_FORMAT_RAW_RGGB_16 = 104,
+
+ PIXEL_FORMAT_RAW_RGGB_12 = 106,
+ PIXEL_FORMAT_RAW_RGGB_12P = 107,
+ PIXEL_FORMAT_RAW_RGGB_14 = 108,
+
+ PIXEL_FORMAT_RAW_GBRG_12 = 109,
+ PIXEL_FORMAT_RAW_GBRG_12P = 110,
+ PIXEL_FORMAT_RAW_GBRG_14 = 111,
+
+ PIXEL_FORMAT_RAW_DEFAULT = PIXEL_FORMAT_RAW_RGGB_14,
+
+ //! Input pixel formats above this value must be encoded into the sample
+ PIXEL_FORMAT_TAG_REQUIRED = 100,
+
+} PIXEL_FORMAT;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+@brief Force a pixel value to be in range
+*/
+STATIC_INLINE PIXEL ClampPixel(int32_t value)
+{
+ // Check for values that are outside the range (for debugging)
+ assert(PIXEL_MIN <= value && value <= PIXEL_MAX);
+
+ if (value < PIXEL_MIN)
+ value = PIXEL_MIN;
+ else
+ if (value > PIXEL_MAX)
+ value = PIXEL_MAX;
+
+ return (PIXEL)value;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PIXEL_H
diff --git a/gpr/source/lib/vc5_common/stream.c b/gpr/source/lib/vc5_common/stream.c
new file mode 100755
index 0000000..59ecc7d
--- /dev/null
+++ b/gpr/source/lib/vc5_common/stream.c
@@ -0,0 +1,524 @@
+/*! @file stream.h
+ *
+ * @brief This module implements a byte stream abstraction that hides the details
+ * of how a stream of bytes is read or written on demand by the bitstream.
+ * The byte stream can be bound to a binary file opened for reading (writing),
+ * to a buffer in memory, or to a module that reads (writes) a video track
+ * in a media container.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+// Local functions
+CODEC_ERROR GetBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset);
+CODEC_ERROR PutBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset);
+CODEC_ERROR GetBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset);
+CODEC_ERROR PutBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset);
+
+/*!
+ @brief Open a stream for reading bytes from the specified file
+
+*/
+CODEC_ERROR OpenStream(STREAM *stream, const char *pathname)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ // Clear all members of the stream data structure
+ memset(stream, 0, sizeof(STREAM));
+
+ // Open the file and bind it to the stream
+ stream->location.file.iobuf = fopen(pathname, "rb");
+ assert(stream->location.file.iobuf != NULL);
+ if (! (stream->location.file.iobuf != NULL)) {
+ return CODEC_ERROR_OPEN_FILE_FAILED;
+ }
+
+ // Set the stream type and access
+ stream->type = STREAM_TYPE_FILE;
+ stream->access = STREAM_ACCESS_READ;
+
+ // Clear the number of bytes read from the stream
+ stream->byte_count = 0;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Create a stream for writing bytes to a specified file
+
+*/
+CODEC_ERROR CreateStream(STREAM *stream, const char *pathname)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ // Clear all members of the stream data structure
+ memset(stream, 0, sizeof(STREAM));
+
+ // Open the file and bind it to the stream
+ stream->location.file.iobuf = fopen(pathname, "wb+");
+ assert(stream->location.file.iobuf != NULL);
+ if (! (stream->location.file.iobuf != NULL)) {
+ return CODEC_ERROR_CREATE_FILE_FAILED;
+ }
+
+ // Set the stream type and access
+ stream->type = STREAM_TYPE_FILE;
+ stream->access = STREAM_ACCESS_WRITE;
+
+ // Clear the number of bytes written to the stream
+ stream->byte_count = 0;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Read a word from a byte stream
+
+ This routine is used by the bitstream to read a word from a byte stream.
+ A word is the number of bytes that can be stored in the internal buffer
+ used by the bitstream.
+
+ @todo Need to modify the routine to return an indication of end of file
+ or an error reading from the byte stream.
+*/
+BITWORD GetWord(STREAM *stream)
+{
+ BITWORD buffer = 0;
+ size_t bytes_read = sizeof(buffer);
+
+ assert(stream != NULL);
+
+ switch (stream->type)
+ {
+ case STREAM_TYPE_FILE:
+ bytes_read = fread(&buffer, 1, sizeof(buffer), stream->location.file.iobuf);
+ assert(bytes_read == sizeof(buffer));
+ break;
+
+ case STREAM_TYPE_MEMORY:
+ memcpy(&buffer, (uint8_t *)stream->location.memory.buffer + stream->byte_count, sizeof(buffer));
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ if (bytes_read > 0)
+ stream->byte_count += sizeof(buffer);
+
+ return buffer;
+}
+
+/*!
+ @brief Read a byte from a byte stream
+*/
+uint8_t GetByte(STREAM *stream)
+{
+ assert(stream != NULL);
+ int byte = 0;
+
+ switch (stream->type)
+ {
+ case STREAM_TYPE_FILE:
+ byte = fgetc(stream->location.file.iobuf);
+ break;
+
+ case STREAM_TYPE_MEMORY:
+ byte = ((uint8_t *)stream->location.memory.buffer)[stream->byte_count];
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ stream->byte_count++;
+ assert(byte >= 0 && (byte & ~0xFF) == 0);
+
+ return (uint8_t)byte;
+}
+
+/*!
+ @brief Write a word to a byte stream
+
+ This routine is used by the bitstream to write a word to a byte stream.
+ A word is the number of bytes that can be stored in the internal buffer
+ used by the bitstream.
+
+ @todo Need to modify the routine to return an indication of an error
+ writing to the byte stream.
+*/
+CODEC_ERROR PutWord(STREAM *stream, BITWORD word)
+{
+ size_t written;
+
+ word = Swap32(word);
+
+ assert(stream != NULL);
+
+ switch (stream->type)
+ {
+ case STREAM_TYPE_FILE:
+ written = fwrite(&word, sizeof(word), 1, stream->location.file.iobuf);
+ if (written == 0)
+ return CODEC_ERROR_FILE_WRITE_FAILED;
+ break;
+
+ case STREAM_TYPE_MEMORY:
+ {
+ uint8_t* buffer = (uint8_t *)stream->location.memory.buffer + stream->byte_count;
+
+ memcpy(buffer, &word, sizeof(word));
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ stream->byte_count += sizeof(word);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write a byte to a byte stream
+*/
+CODEC_ERROR PutByte(STREAM *stream, uint8_t byte)
+{
+ assert(stream != NULL);
+
+ //assert(byte >= 0 && (byte & ~0xFF) == 0);
+
+ switch (stream->type)
+ {
+ case STREAM_TYPE_FILE:
+ if (fputc(byte, stream->location.file.iobuf) == EOF)
+ return CODEC_ERROR_FILE_WRITE_FAILED;
+ break;
+
+ case STREAM_TYPE_MEMORY:
+ ((uint8_t *)stream->location.memory.buffer)[stream->byte_count] = byte;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ stream->byte_count++;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Rewind the stream to the beginning of the buffer or file
+*/
+CODEC_ERROR RewindStream(STREAM *stream)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ if( stream->type == STREAM_TYPE_FILE )
+ {
+ if (stream->location.file.iobuf != NULL) {
+ assert(fseek(stream->location.file.iobuf, 0, SEEK_SET) == 0);
+ return CODEC_ERROR_BITSTREAM;
+ }
+ }
+
+ stream->byte_count = 0;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Skip the specified number of bytes in the stream
+*/
+CODEC_ERROR SkipBytes(STREAM *stream, size_t size)
+{
+ for (; size > 0; size--)
+ {
+ (void)GetByte(stream);
+ }
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Pad the specified number of bytes in the stream
+*/
+CODEC_ERROR PadBytes(STREAM *stream, size_t size)
+{
+ const uint8_t byte = 0;
+ for (; size > 0; size--)
+ {
+ PutByte(stream, byte);
+ }
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the stream buffer to the file
+*/
+CODEC_ERROR FlushStream(STREAM *stream)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ if (stream->type == STREAM_TYPE_FILE)
+ {
+ int result = fflush(stream->location.file.iobuf);
+ if (result != 0) {
+ return CODEC_ERROR_FILE_FLUSH_FAILED;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Create a byte stream for reading from a memory location
+ */
+CODEC_ERROR OpenStreamBuffer(STREAM *stream, void *buffer, size_t size)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ // Clear all members of the stream data structure
+ memset(stream, 0, sizeof(STREAM));
+
+ // Bind the stream to the buffer
+ stream->location.memory.buffer = buffer;
+ stream->location.memory.size = size;
+
+ // Set the stream type and access
+ stream->type = STREAM_TYPE_MEMORY;
+ stream->access = STREAM_ACCESS_READ;
+
+ // Clear the number of bytes written to the stream
+ stream->byte_count = 0;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Create a byte stream for writing to a memory location
+*/
+CODEC_ERROR CreateStreamBuffer(STREAM *stream, void *buffer, size_t size)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ // Clear all members of the stream data structure
+ memset(stream, 0, sizeof(STREAM));
+
+ // Bind the stream to the buffer
+ stream->location.memory.buffer = buffer;
+ stream->location.memory.size = size;
+
+ // Set the stream type and access
+ stream->type = STREAM_TYPE_MEMORY;
+ stream->access = STREAM_ACCESS_WRITE;
+
+ // Clear the number of bytes written to the stream
+ stream->byte_count = 0;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return the starting address and number of bytes in a buffer
+
+ This routine is used to get the address and count of the bytes written
+ to a memory stream (buffer).
+*/
+CODEC_ERROR GetStreamBuffer(STREAM *stream, void **buffer_out, size_t *size_out)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ assert(stream->type == STREAM_TYPE_MEMORY);
+
+ if (buffer_out != NULL) {
+ *buffer_out = stream->location.memory.buffer;
+ }
+
+ if (size_out != NULL) {
+ *size_out = stream->byte_count;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Read a block of data at the specified offset in the byte stream
+*/
+CODEC_ERROR GetBlock(STREAM *stream, void *buffer, size_t size, size_t offset)
+{
+ switch (stream->type)
+ {
+ case STREAM_TYPE_FILE:
+ return GetBlockFile(stream, buffer, size, offset);
+ break;
+
+ case STREAM_TYPE_MEMORY:
+ return GetBlockMemory(stream, buffer, size, offset);
+ break;
+
+ case STREAM_TYPE_UNKNOWN:
+ assert(0);
+ break;
+ }
+
+ return CODEC_ERROR_UNEXPECTED;
+}
+
+/*!
+ @brief Read a block of data from a file stream
+*/
+CODEC_ERROR GetBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset)
+{
+ FILE *file = stream->location.file.iobuf;
+ fpos_t position;
+
+ (void)file;
+ (void)position;
+
+ // Save the current position in the file
+ if (fgetpos(file, &position) != 0) {
+ return CODEC_ERROR_FILE_GET_POSITION;
+ }
+
+ // Seek to the specified offset
+ assert(offset <= LONG_MAX);
+ if (fseek(file, (long)offset, SEEK_SET) != 0) {
+ return CODEC_ERROR_FILE_SEEK;
+ }
+
+ // Read data from the file
+ if (fread(buffer, size, 1, file) != 1) {
+ return CODEC_ERROR_FILE_READ;
+ }
+
+ // Return to the previous position in the file
+ // if (fseek(file, (long)position, SEEK_SET) != 0) {
+ if (fsetpos(file, &position) != 0) {
+ return CODEC_ERROR_FILE_SEEK;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Read a block of data from a memory stream (buffer)
+*/
+CODEC_ERROR GetBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset)
+{
+ uint8_t *block = (uint8_t *)stream->location.memory.buffer + offset;
+ memcpy(buffer, block, size);
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write a block of data at the specified offset in the byte stream
+*/
+CODEC_ERROR PutBlock(STREAM *stream, void *buffer, size_t size, size_t offset)
+{
+ switch (stream->type)
+ {
+ case STREAM_TYPE_FILE:
+ return PutBlockFile(stream, buffer, size, offset);
+ break;
+
+ case STREAM_TYPE_MEMORY:
+ return PutBlockMemory(stream, buffer, size, offset);
+ break;
+
+ case STREAM_TYPE_UNKNOWN:
+ assert(0);
+ break;
+ }
+
+ return CODEC_ERROR_UNEXPECTED;
+}
+
+/*!
+ @brief Write a block of data at the specified offset in a file stream
+*/
+CODEC_ERROR PutBlockFile(STREAM *stream, void *buffer, size_t size, size_t offset)
+{
+ FILE *file = stream->location.file.iobuf;
+ fpos_t position;
+
+ (void)file;
+ (void)position;
+
+ // Save the current position in the file
+ if (fgetpos(file, &position) != 0) {
+ return CODEC_ERROR_FILE_GET_POSITION;
+ }
+
+ // Seek to the specified offset and write to the file
+ assert(offset <= LONG_MAX);
+ if (fseek(file, (long)offset, SEEK_SET) != 0) {
+ return CODEC_ERROR_FILE_SEEK;
+ }
+
+ // Write data to the file
+ if (fwrite(buffer, size, 1, file) != 1) {
+ return CODEC_ERROR_FILE_WRITE;
+ }
+
+ // Return to the previous position in the file
+ // if (fseek(file, (long)position, SEEK_SET) != 0) {
+ if (fsetpos(file, &position) != 0) {
+ return CODEC_ERROR_FILE_SEEK;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write a block of data at the specified offset in a memory stream
+*/
+CODEC_ERROR PutBlockMemory(STREAM *stream, void *buffer, size_t size, size_t offset)
+{
+ uint8_t *block = (uint8_t *)stream->location.memory.buffer + offset;
+ memcpy(block, buffer, size);
+ return CODEC_ERROR_OKAY;
+}
+
+
diff --git a/gpr/source/lib/vc5_common/stream.h b/gpr/source/lib/vc5_common/stream.h
new file mode 100755
index 0000000..df70a4f
--- /dev/null
+++ b/gpr/source/lib/vc5_common/stream.h
@@ -0,0 +1,133 @@
+/*! @file stream.h
+ *
+ * @brief The stream abstracts the methods used by bitstreams to output bytes
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STREAM_H
+#define STREAM_H
+
+//! Type of stream (binary file or memory buffer)
+typedef enum _stream_type
+{
+ STREAM_TYPE_UNKNOWN = 0, //!< Unknown type of stream
+ STREAM_TYPE_FILE, //!< Simple binary file
+ STREAM_TYPE_MEMORY, //!< Buffer in memory
+
+} STREAM_TYPE;
+
+/*!
+ @brief Stream access (read or write)
+
+ The stream provided with the reference decoder only supports
+ read access.
+*/
+typedef enum _stream_access
+{
+ STREAM_ACCESS_UNKNOWN = 0,
+ STREAM_ACCESS_READ,
+ STREAM_ACCESS_WRITE,
+
+} STREAM_ACCESS;
+
+
+/*!
+ @brief Declaration of the data structure for a byte stream
+
+ The byte stream encapsulates the location of encoded images and the
+ means for reading (writing) encoded images samples. The byte stream
+ could be a binary file that has been opened for reading (writing) or
+ a buffer in memory. The reference codec uses a binary file as the byte
+ stream so the functionality for streams attached to memory buffers has
+ not been tested.
+
+ It is intended that the byte stream can be enhanced to read (write)
+ encoded images from (into) a track in a media container.
+*/
+#define STREAM_CACHE_SIZE 16
+typedef struct _stream
+{
+ STREAM_TYPE type; //!< Type of stream (file or memory buffer)
+ STREAM_ACCESS access; //!< Type of access (read or write)
+
+ //! Union of parameters for different types of streams
+ union _location
+ {
+ //! Parameters for a binary file stream
+ struct _file
+ {
+ FILE *iobuf; //!< Binary file that contains the stream
+ BITWORD cache[STREAM_CACHE_SIZE];
+ int cache_index;
+
+ } file; //!< Parameters for a stream in a binary file
+
+ //! Parameters for a stream bound to a memory buffer
+ struct _memory
+ {
+ void *buffer; //!< Memory buffer that contains the stream
+ size_t size; //!< Length of the stream (in bytes)
+
+ } memory; //!< Parameters for a stream in a memory buffer
+
+ //TODO: Add other stream types for media containers
+
+ } location; //!< Location of the byte stream (file or memory buffer)
+
+ size_t byte_count; //!< Number of bytes read or written to the stream
+
+} STREAM;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR OpenStream(STREAM *stream, const char *pathname);
+
+ CODEC_ERROR CreateStream(STREAM *stream, const char *pathname);
+
+ CODEC_ERROR RewindStream(STREAM *stream);
+
+ BITWORD GetWord(STREAM *stream);
+
+ uint8_t GetByte(STREAM *stream);
+
+ CODEC_ERROR SkipBytes(STREAM *stream, size_t size);
+
+ CODEC_ERROR PutWord(STREAM *stream, BITWORD word);
+
+ CODEC_ERROR PutByte(STREAM *stream, uint8_t byte);
+
+ CODEC_ERROR PadBytes(STREAM *stream, size_t size);
+
+ CODEC_ERROR FlushStream(STREAM *stream);
+
+ CODEC_ERROR OpenStreamBuffer(STREAM *stream, void *buffer, size_t size);
+
+ CODEC_ERROR CreateStreamBuffer(STREAM *stream, void *buffer, size_t size);
+
+ CODEC_ERROR GetStreamBuffer(STREAM *stream, void **buffer_out, size_t *size_out);
+
+ CODEC_ERROR GetBlock(STREAM *stream, void *buffer, size_t size, size_t offset);
+
+ CODEC_ERROR PutBlock(STREAM *stream, void *buffer, size_t size, size_t offset);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gpr/source/lib/vc5_common/syntax.c b/gpr/source/lib/vc5_common/syntax.c
new file mode 100755
index 0000000..bf64afe
--- /dev/null
+++ b/gpr/source/lib/vc5_common/syntax.c
@@ -0,0 +1,150 @@
+/*! @file syntax.c
+ *
+ * @brief Implementation of functions for parsing the bitstream syntax of encoded samples.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+//TODO: Simplify the definition of the marker bits
+#define CODEC_LOWPASS_START_CODE 0x1A4A
+#define CODEC_LOWPASS_START_SIZE 16
+#define CODEC_LOWPASS_END_CODE 0x1B4B
+#define CODEC_LOWPASS_END_SIZE 16
+
+#define CODEC_HIGHPASS_START_CODE 0x0D0D
+#define CODEC_HIGHPASS_START_SIZE 16
+#define CODEC_HIGHPASS_END_CODE 0x0C0C
+#define CODEC_HIGHPASS_END_SIZE 16
+
+#define CODEC_BAND_START_CODE 0x0E0E
+#define CODEC_BAND_START_SIZE 16
+//#define CODEC_BAND_END_CODE 0x038F0B3E //Codeset dependent cs9
+//#define CODEC_BAND_END_SIZE 26 //Codeset dependent cs9
+#define CODEC_BAND_END_CODE 0x0000E33F //Codeset dependent cs15
+#define CODEC_BAND_END_SIZE 16 //Codeset dependent cs15
+
+#define CODEC_SAMPLE_STOP_CODE 0x1E1E
+#define CODEC_SAMPLE_STOP_SIZE 16
+
+#define CODEC_COEFFICIENT_START_CODE 0x0F0F
+#define CODEC_COEFFICIENT_START_SIZE 16
+
+//! Size of a tag or value (in bits)
+#define BITSTREAM_TAG_SIZE 16
+
+
+// Bits in the interlace structure flags
+
+#define CODEC_FLAGS_INTERLACED 0x01 //!< Interlaced flags
+#define CODEC_FLAGS_FIELD1_FIRST 0x02 //!< NTSC has this bit cleared
+#define CODEC_FLAGS_FIELD1_ONLY 0x04 //!< Indicates missing fields
+#define CODEC_FLAGS_FIELD2_ONLY 0x08
+#define CODEC_FLAGS_DOMINANCE 0x10
+
+#define CODEC_FLAGS_INTERLACED_MASK 0x1F //!< Unused bits must be zero
+
+// Useful macros for testing the interlaced flags
+
+#define INTERLACED(flags) (((flags) & CODEC_FLAGS_INTERLACED) != 0)
+#define PROGRESSIVE(flags) (((flags) & CODEC_FLAGS_INTERLACED) == 0)
+#define FIELD_ORDER_NTSC(flags) (((flags) & CODEC_FLAGS_FIELD1_FIRST) == 0)
+#define FIELD_ORDER_PAL(flags) (((flags) & CODEC_FLAGS_FIELD1_FIRST) != 0)
+#define FIELD_ONE_ONLY(flags) (((flags) & CODEC_FLAGS_FIELD1_ONLY) != 0)
+#define FIELD_TWO_ONLY(flags) (((flags) & CODEC_FLAGS_FIELD2_ONLY) != 0)
+#define FIELD_ONE_PRESENT(flags) (((flags) & CODEC_FLAGS_FIELD2_ONLY) == 0)
+#define FIELD_TWO_PRESENT(flags) (((flags) & CODEC_FLAGS_FIELD1_ONLY) == 0)
+#define FIELD_BOTH_PRESENT(flags) (((flags) & (CODEC_FLAGS_FIELD1_ONLY | CODEC_FLAGS_FIELD1_ONLY)) == 0)
+
+// Bits in the copy protection flags
+
+#define CODEC_FLAGS_PROTECTED 0x01 //!< Copy protection flags
+#define CODEC_FLAGS_PROTECTION_MASK 0x01 //!< Unused bits must be zero
+
+/*!
+ @brief Check that the bitstream is aligned to a segment boundary
+
+ This function definition duplicates the same function in common/src/syntax.c,
+ but that file includes definitions intended only for the encoder.
+
+ @todo Remove duplicate function definitions.
+ */
+bool IsAlignedSegment(BITSTREAM *stream)
+{
+ return (stream->count == 0 || stream->count == bit_word_count);
+}
+
+/*!
+ @brief Convert the tag to an optional tag
+
+ An optional tag has a negative value.
+*/
+TAGWORD OptionalTag(TAGWORD tag)
+{
+ return ((tag < 0) ? tag : neg(tag));
+}
+
+/*!
+ @brief Convert the tag to a required tag
+
+ An optional tag has a negative value.
+*/
+TAGWORD RequiredTag(TAGWORD tag)
+{
+ return ((tag >= 0) ? tag : neg(tag));
+}
+
+
+/*!
+ @brief Check that the bitstream is aligned to a tag word boundary
+
+ @todo Check the places in the code where this function is used to
+ determine whether the bitstream should actually be aligned to a
+ segment boundary.
+*/
+bool IsAlignedTag(BITSTREAM *stream)
+{
+ return ((stream->count % BITSTREAM_TAG_SIZE) == 0);
+}
+
+/*!
+ @brief Pack the vector of prescale values into a single word
+
+ The wavelet transform uses a vector of prescale values indexed by the
+ wavelet level with the input image at level zero to specify the amount
+ of prescaling that should be performed on the input the wavelet transform.
+
+ This routine packs the prescale values into a segment value that can be
+ written into the bitstream.
+*/
+TAGWORD PackTransformPrescale(TRANSFORM *transform)
+{
+ TAGWORD packed_prescale = 0;
+ int i;
+
+ // Encode the prescale values that are actually used
+ for (i = 0; i < MAX_WAVELET_COUNT; i++)
+ {
+ assert((transform->prescale[i] & ~0x03) == 0);
+ packed_prescale += transform->prescale[i] << (14 - i * 2);
+ }
+
+ // The remaining prescale values with filled with zeros
+
+ return packed_prescale;
+}
+
diff --git a/gpr/source/lib/vc5_common/syntax.h b/gpr/source/lib/vc5_common/syntax.h
new file mode 100755
index 0000000..699c72e
--- /dev/null
+++ b/gpr/source/lib/vc5_common/syntax.h
@@ -0,0 +1,129 @@
+/*! @file syntax.h
+ *
+ * @brief Declaration of bitstream elements and functions that define the syntax
+ * of an encoded sample.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYNTAX_H
+#define SYNTAX_H
+
+#define CODEC_TAG_SIZE 16 //!< Size of a codec tag (in bits)
+#define CODEC_TAG_MASK 0xFFFF //!< Mask for usable part of tag or value
+
+typedef uint32_t SEGMENT; //!< The bitstream is a sequence of segments
+
+typedef int16_t TAGWORD; //!< Bitstream tag or value
+
+//! Number of bits in a tag or value
+static const BITCOUNT tagword_count = 16;
+
+//! Number of bits in a segment (tag value pair)
+static const BITCOUNT segment_count = 32;
+
+typedef union tagvalue //!< Bitstream tag and value pair
+{
+ struct { // Fields are in the order for byte swapping
+ TAGWORD value;
+ TAGWORD tag;
+ } tuple; //!< Tag value pair as separate members
+
+ uint32_t longword; //!< Tag value pair as a int32_t word
+
+} TAGVALUE;
+
+/*!
+ @brief Values corresponding to the special codewords
+
+ Special codewords are inserted into an entropy coded band to
+ mark certain locations in the bitstream. For example, the end
+ of an encoded band is marked by the band end codeword. Special
+ codewords are recorded in the codebook as entries that have a
+ run length of zero. The value indicates the syntax element that
+ is represented by the codeword.
+*/
+typedef enum _special_marker
+{
+ SPECIAL_MARKER_BAND_END = 1,
+
+} SPECIAL_MARKER;
+
+
+// The encoded quality is inserted into the bitstream using two tag value pairs
+#define ENCODED_QUALITY_LOW_SHIFT 0 //!< Shift for the low part of the quality
+#define ENCODED_QUALITY_LOW_MASK 0xFFFF //!< Mask for the low part of the quality
+#define ENCODED_QUALITY_HIGH_SHIFT 16 //!< Shift for the high part of the quality
+#define ENCODED_QUALITY_HIGH_MASK 0xFFFF //!< Mask for the high part of the quality
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+TAGWORD RequiredTag(TAGWORD tag);
+
+//TAGVALUE GetSegment(BITSTREAM *stream);
+
+//TAGWORD GetValue(BITSTREAM *stream, int tag);
+
+// Output a tagged value with double word alignment
+CODEC_ERROR PutTagPair(BITSTREAM *stream, int tag, int value);
+
+// Output an optional tagged value
+CODEC_ERROR PutTagPairOptional(BITSTREAM *stream, int tag, int value);
+
+// Output a tag that marks a place in the bitstream for debugging
+CODEC_ERROR PutTagMarker(BITSTREAM *stream, uint32_t marker, int size);
+
+TAGWORD OptionalTag(TAGWORD tag);
+
+//bool IsTagOptional(TAGWORD tag);
+
+//bool IsTagRequired(TAGWORD tag);
+
+//bool IsValidSegment(BITSTREAM *stream, TAGVALUE segment, TAGWORD tag);
+
+//CODEC_ERROR AlignBitsTag(BITSTREAM *stream);
+
+bool IsLowPassHeaderMarker(int marker);
+bool IsLowPassBandMarker(int marker);
+bool IsHighPassBandMarker(int marker);
+
+bool IsAlignedTag(BITSTREAM *stream);
+
+bool IsAlignedSegment(BITSTREAM *stream);
+
+// Write an index block for the sample bands
+CODEC_ERROR PutGroupIndex(BITSTREAM *stream,
+ void *index_table[],
+ int index_table_length,
+ size_t *channel_size_table_offset);
+
+TAGWORD PackTransformPrescale(TRANSFORM *transform);
+
+//TODO: Move other declarations for routines that write syntax elements here
+struct _encoder ;
+
+CODEC_ERROR PutFrameStructureFlags(struct _encoder *encoder, BITSTREAM *stream);
+
+// Output a tag and marker before the lowpass coefficients for debugging
+CODEC_ERROR PutVideoLowpassMarker(BITSTREAM *stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYNTAX_H
diff --git a/gpr/source/lib/vc5_common/table17.inc b/gpr/source/lib/vc5_common/table17.inc
new file mode 100755
index 0000000..973f297
--- /dev/null
+++ b/gpr/source/lib/vc5_common/table17.inc
@@ -0,0 +1,290 @@
+/*! @file bitstream.h
+ *
+ * @brief Declaration of the bitstream data structure.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+RLVTABLE(264) table17 =
+{
+ 264,
+ {
+ {1, 0x00000000, 1, 0}, // m0
+ {2, 0x00000002, 1, 1}, // m1
+ {3, 0x00000007, 1, 2}, // m2
+ {5, 0x00000019, 1, 3}, // m3
+ {6, 0x00000030, 1, 4}, // m4
+ {6, 0x00000036, 1, 5}, // m5
+ {7, 0x0000006F, 1, 8}, // m8
+ {7, 0x00000063, 1, 6}, // m6
+ {7, 0x00000069, 12, 0}, // z12
+ {7, 0x0000006B, 1, 7}, // m7
+ {8, 0x000000D1, 20, 0}, // z20
+ {8, 0x000000D4, 1, 9}, // m9
+ {8, 0x000000DC, 1, 10}, // m10
+ {9, 0x00000189, 1, 11}, // m11
+ {9, 0x0000018A, 32, 0}, // z32
+ {9, 0x000001A0, 1, 12}, // m12
+ {9, 0x000001AB, 1, 13}, // m13
+ {10, 0x00000377, 1, 18}, // m18
+ {10, 0x00000310, 1, 14}, // m14
+ {10, 0x00000316, 1, 15}, // m15
+ {10, 0x00000343, 60, 0}, // z60
+ {10, 0x00000354, 1, 16}, // m16
+ {10, 0x00000375, 1, 17}, // m17
+ {11, 0x00000623, 1, 19}, // m19
+ {11, 0x00000684, 1, 20}, // m20
+ {11, 0x00000685, 100, 0}, // z100
+ {11, 0x000006AB, 1, 21}, // m21
+ {11, 0x000006EC, 1, 22}, // m22
+ {12, 0x00000DDB, 1, 29}, // m29
+ {12, 0x00000C5C, 1, 24}, // m24
+ {12, 0x00000C5E, 1, 25}, // m25
+ {12, 0x00000C44, 1, 23}, // m23
+ {12, 0x00000D55, 1, 26}, // m26
+ {12, 0x00000DD1, 1, 27}, // m27
+ {12, 0x00000DD3, 1, 28}, // m28
+ {13, 0x00001BB5, 1, 35}, // m35
+ {13, 0x0000188B, 1, 30}, // m30
+ {13, 0x000018BB, 1, 31}, // m31
+ {13, 0x000018BF, 180, 0}, // z180
+ {13, 0x00001AA8, 1, 32}, // m32
+ {13, 0x00001BA0, 1, 33}, // m33
+ {13, 0x00001BA5, 320, 0}, // z320
+ {13, 0x00001BA4, 1, 34}, // m34
+ {14, 0x00003115, 1, 36}, // m36
+ {14, 0x00003175, 1, 37}, // m37
+ {14, 0x0000317D, 1, 38}, // m38
+ {14, 0x00003553, 1, 39}, // m39
+ {14, 0x00003768, 1, 40}, // m40
+ {15, 0x00006E87, 1, 46}, // m46
+ {15, 0x00006ED3, 1, 47}, // m47
+ {15, 0x000062E8, 1, 42}, // m42
+ {15, 0x000062F8, 1, 43}, // m43
+ {15, 0x00006228, 1, 41}, // m41
+ {15, 0x00006AA4, 1, 44}, // m44
+ {15, 0x00006E85, 1, 45}, // m45
+ {16, 0x0000C453, 1, 48}, // m48
+ {16, 0x0000C5D3, 1, 49}, // m49
+ {16, 0x0000C5F3, 1, 50}, // m50
+ {16, 0x0000DDA4, 1, 53}, // m53
+ {16, 0x0000DD08, 1, 51}, // m51
+ {16, 0x0000DD0C, 1, 52}, // m52
+ {17, 0x0001BB4B, 1, 61}, // m61
+ {17, 0x0001BB4A, 1, 60}, // m60
+ {17, 0x00018BA5, 1, 55}, // m55
+ {17, 0x00018BE5, 1, 56}, // m56
+ {17, 0x0001AA95, 1, 57}, // m57
+ {17, 0x0001AA97, 1, 58}, // m58
+ {17, 0x000188A4, 1, 54}, // m54
+ {17, 0x0001BA13, 1, 59}, // m59
+ {18, 0x00031748, 1, 62}, // m62
+ {18, 0x000317C8, 1, 63}, // m63
+ {18, 0x00035528, 1, 64}, // m64
+ {18, 0x0003552C, 1, 65}, // m65
+ {18, 0x00037424, 1, 66}, // m66
+ {18, 0x00037434, 1, 67}, // m67
+ {18, 0x00037436, 1, 68}, // m68
+ {19, 0x00062294, 1, 69}, // m69
+ {19, 0x00062E92, 1, 70}, // m70
+ {19, 0x00062F92, 1, 71}, // m71
+ {19, 0x0006AA52, 1, 72}, // m72
+ {19, 0x0006AA5A, 1, 73}, // m73
+ {19, 0x0006E86A, 1, 75}, // m75
+ {19, 0x0006E86E, 1, 76}, // m76
+ {19, 0x0006E84A, 1, 74}, // m74
+ {20, 0x000C452A, 1, 77}, // m77
+ {20, 0x000C5D27, 1, 78}, // m78
+ {20, 0x000C5F26, 1, 79}, // m79
+ {20, 0x000D54A6, 1, 80}, // m80
+ {20, 0x000D54B6, 1, 81}, // m81
+ {20, 0x000DD096, 1, 82}, // m82
+ {20, 0x000DD0D6, 1, 83}, // m83
+ {20, 0x000DD0DE, 1, 84}, // m84
+ {21, 0x00188A56, 1, 85}, // m85
+ {21, 0x0018BA4D, 1, 86}, // m86
+ {21, 0x0018BE4E, 1, 87}, // m87
+ {21, 0x0018BE4F, 1, 88}, // m88
+ {21, 0x001AA96E, 1, 89}, // m89
+ {21, 0x001BA12E, 1, 90}, // m90
+ {21, 0x001BA12F, 1, 91}, // m91
+ {21, 0x001BA1AF, 1, 92}, // m92
+ {21, 0x001BA1BF, 1, 93}, // m93
+ {22, 0x0037435D, 1, 99}, // m99
+ {22, 0x0037437D, 1, 100}, // m100
+ {22, 0x00317498, 1, 94}, // m94
+ {22, 0x0035529C, 1, 95}, // m95
+ {22, 0x0035529D, 1, 96}, // m96
+ {22, 0x003552DE, 1, 97}, // m97
+ {22, 0x003552DF, 1, 98}, // m98
+ {23, 0x0062E933, 1, 102}, // m102
+ {23, 0x0062295D, 1, 101}, // m101
+ {23, 0x006AA53D, 1, 103}, // m103
+ {23, 0x006AA53F, 1, 105}, // m105
+ {23, 0x006AA53E, 1, 104}, // m104
+ {23, 0x006E86B9, 1, 106}, // m106
+ {23, 0x006E86F8, 1, 107}, // m107
+ {24, 0x00D54A79, 1, 111}, // m111
+ {24, 0x00C5D265, 1, 109}, // m109
+ {24, 0x00C452B8, 1, 108}, // m108
+ {24, 0x00DD0D71, 1, 113}, // m113
+ {24, 0x00D54A78, 1, 110}, // m110
+ {24, 0x00DD0D70, 1, 112}, // m112
+ {24, 0x00DD0DF2, 1, 114}, // m114
+ {24, 0x00DD0DF3, 1, 115}, // m115
+ {25, 0x0188A5F6, 1, 225}, // m225
+ {25, 0x0188A5F5, 1, 189}, // m189
+ {25, 0x0188A5F4, 1, 188}, // m188
+ {25, 0x0188A5F3, 1, 203}, // m203
+ {25, 0x0188A5F2, 1, 202}, // m202
+ {25, 0x0188A5F1, 1, 197}, // m197
+ {25, 0x0188A5F0, 1, 207}, // m207
+ {25, 0x0188A5EF, 1, 169}, // m169
+ {25, 0x0188A5EE, 1, 223}, // m223
+ {25, 0x0188A5ED, 1, 159}, // m159
+ {25, 0x0188A5AA, 1, 235}, // m235
+ {25, 0x0188A5E3, 1, 152}, // m152
+ {25, 0x0188A5DF, 1, 192}, // m192
+ {25, 0x0188A589, 1, 179}, // m179
+ {25, 0x0188A5DD, 1, 201}, // m201
+ {25, 0x0188A578, 1, 172}, // m172
+ {25, 0x0188A5E0, 1, 149}, // m149
+ {25, 0x0188A588, 1, 178}, // m178
+ {25, 0x0188A5D6, 1, 120}, // m120
+ {25, 0x0188A5DB, 1, 219}, // m219
+ {25, 0x0188A5E1, 1, 150}, // m150
+ {25, 0x0188A587, 1, 127}, // m127
+ {25, 0x0188A59A, 1, 211}, // m211
+ {25, 0x0188A5C4, 1, 125}, // m125
+ {25, 0x0188A5EC, 1, 158}, // m158
+ {25, 0x0188A586, 1, 247}, // m247
+ {25, 0x0188A573, 1, 238}, // m238
+ {25, 0x0188A59C, 1, 163}, // m163
+ {25, 0x0188A5C8, 1, 228}, // m228
+ {25, 0x0188A5FB, 1, 183}, // m183
+ {25, 0x0188A5A1, 1, 217}, // m217
+ {25, 0x0188A5EB, 1, 168}, // m168
+ {25, 0x0188A5A8, 1, 122}, // m122
+ {25, 0x0188A584, 1, 128}, // m128
+ {25, 0x0188A5D2, 1, 249}, // m249
+ {25, 0x0188A599, 1, 187}, // m187
+ {25, 0x0188A598, 1, 186}, // m186
+ {25, 0x0188A583, 1, 136}, // m136
+ {25, 0x018BA4C9, 1, 181}, // m181
+ {25, 0x0188A5D0, 1, 255}, // m255
+ {25, 0x0188A594, 1, 230}, // m230
+ {25, 0x0188A582, 1, 135}, // m135
+ {25, 0x0188A5CB, 1, 233}, // m233
+ {25, 0x0188A5D8, 1, 222}, // m222
+ {25, 0x0188A5E7, 1, 145}, // m145
+ {25, 0x0188A581, 1, 134}, // m134
+ {25, 0x0188A5EA, 1, 167}, // m167
+ {25, 0x0188A5A9, 1, 248}, // m248
+ {25, 0x0188A5A6, 1, 209}, // m209
+ {25, 0x0188A580, 1, 243}, // m243
+ {25, 0x0188A5A0, 1, 216}, // m216
+ {25, 0x0188A59D, 1, 164}, // m164
+ {25, 0x0188A5C3, 1, 140}, // m140
+ {25, 0x0188A57F, 1, 157}, // m157
+ {25, 0x0188A5C0, 1, 239}, // m239
+ {25, 0x0188A5DE, 1, 191}, // m191
+ {25, 0x0188A5D4, 1, 251}, // m251
+ {25, 0x0188A57E, 1, 156}, // m156
+ {25, 0x0188A5C2, 1, 139}, // m139
+ {25, 0x0188A592, 1, 242}, // m242
+ {25, 0x0188A5CD, 1, 133}, // m133
+ {25, 0x0188A57D, 1, 162}, // m162
+ {25, 0x0188A5A3, 1, 213}, // m213
+ {25, 0x0188A5E8, 1, 165}, // m165
+ {25, 0x0188A5A2, 1, 212}, // m212
+ {25, 0x0188A57C, 1, 227}, // m227
+ {25, 0x0188A58E, 1, 198}, // m198
+ {25, 0x0188A5B3, 1, 236}, // m236
+ {25, 0x0188A5B2, 1, 234}, // m234
+ {25, 0x0188A5B1, 1, 117}, // m117
+ {25, 0x0188A5B0, 1, 215}, // m215
+ {25, 0x0188A5AF, 1, 124}, // m124
+ {25, 0x0188A5AE, 1, 123}, // m123
+ {25, 0x0188A5AD, 1, 254}, // m254
+ {25, 0x0188A5AC, 1, 253}, // m253
+ {25, 0x0188A5AB, 1, 148}, // m148
+ {25, 0x0188A5DA, 1, 218}, // m218
+ {25, 0x0188A5E4, 1, 146}, // m146
+ {25, 0x0188A5E5, 1, 147}, // m147
+ {25, 0x0188A5D9, 1, 224}, // m224
+ {25, 0x0188A5B5, 1, 143}, // m143
+ {25, 0x0188A5BC, 1, 184}, // m184
+ {25, 0x0188A5BD, 1, 185}, // m185
+ {25, 0x0188A5E9, 1, 166}, // m166
+ {25, 0x0188A5CC, 1, 132}, // m132
+ {25, 0x0188A585, 1, 129}, // m129
+ {25, 0x0188A5D3, 1, 250}, // m250
+ {25, 0x0188A5E2, 1, 151}, // m151
+ {25, 0x0188A595, 1, 119}, // m119
+ {25, 0x0188A596, 1, 193}, // m193
+ {25, 0x0188A5B8, 1, 176}, // m176
+ {25, 0x0188A590, 1, 245}, // m245
+ {25, 0x0188A5C9, 1, 229}, // m229
+ {25, 0x0188A5A4, 1, 206}, // m206
+ {25, 0x0188A5E6, 1, 144}, // m144
+ {25, 0x0188A5A5, 1, 208}, // m208
+ {25, 0x0188A5CE, 1, 137}, // m137
+ {25, 0x0188A5BF, 1, 241}, // m241
+ {25, 0x0188A572, 1, 237}, // m237
+ {25, 0x0188A59B, 1, 190}, // m190
+ {25, 0x0188A5BE, 1, 240}, // m240
+ {25, 0x0188A5C7, 1, 131}, // m131
+ {25, 0x0188A5CA, 1, 232}, // m232
+ {25, 0x0188A5D5, 1, 252}, // m252
+ {25, 0x0188A57B, 1, 171}, // m171
+ {25, 0x0188A58D, 1, 205}, // m205
+ {25, 0x0188A58C, 1, 204}, // m204
+ {25, 0x0188A58B, 1, 118}, // m118
+ {25, 0x0188A58A, 1, 214}, // m214
+ {25, 0x018BA4C8, 1, 180}, // m180
+ {25, 0x0188A5C5, 1, 126}, // m126
+ {25, 0x0188A5FA, 1, 182}, // m182
+ {25, 0x0188A5BB, 1, 175}, // m175
+ {25, 0x0188A5C1, 1, 141}, // m141
+ {25, 0x0188A5CF, 1, 138}, // m138
+ {25, 0x0188A5B9, 1, 177}, // m177
+ {25, 0x0188A5B6, 1, 153}, // m153
+ {25, 0x0188A597, 1, 194}, // m194
+ {25, 0x0188A5FE, 1, 160}, // m160
+ {25, 0x0188A5D7, 1, 121}, // m121
+ {25, 0x0188A5BA, 1, 174}, // m174
+ {25, 0x0188A591, 1, 246}, // m246
+ {25, 0x0188A5C6, 1, 130}, // m130
+ {25, 0x0188A5DC, 1, 200}, // m200
+ {25, 0x0188A57A, 1, 170}, // m170
+ {25, 0x0188A59F, 1, 221}, // m221
+ {25, 0x0188A5F9, 1, 196}, // m196
+ {25, 0x0188A5B4, 1, 142}, // m142
+ {25, 0x0188A5A7, 1, 210}, // m210
+ {25, 0x0188A58F, 1, 199}, // m199
+ {25, 0x0188A5FD, 1, 155}, // m155
+ {25, 0x0188A5B7, 1, 154}, // m154
+ {25, 0x0188A593, 1, 244}, // m244
+ {25, 0x0188A59E, 1, 220}, // m220
+ {25, 0x0188A5F8, 1, 195}, // m195
+ {25, 0x0188A5FF, 1, 161}, // m161
+ {25, 0x0188A5FC, 1, 231}, // m231
+ {25, 0x0188A579, 1, 173}, // m173
+ {25, 0x0188A5F7, 1, 226}, // m226
+ {26, 0x03114BA2, 1, 116}, // m116
+ {26, 0x03114BA3, 0, 1}, // c256
+ }
+};
diff --git a/gpr/source/lib/vc5_common/types.h b/gpr/source/lib/vc5_common/types.h
new file mode 100755
index 0000000..2e5f5b9
--- /dev/null
+++ b/gpr/source/lib/vc5_common/types.h
@@ -0,0 +1,94 @@
+/*! @file types.h
+ *
+ * @brief Definition of some common data types used by the codec.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPES_H
+#define TYPES_H
+
+//! Data type for Boolean variables
+typedef uint_fast8_t BOOLEAN;
+
+//! Data type for image and frame dimensions
+typedef uint_least16_t DIMENSION;
+
+//! Data type for an unsigned number (count) that can be the value in a tag-value pair
+typedef uint_least16_t COUNT;
+
+/*!
+ @brief Define a data type large enough to hold a quantization value
+
+ Define a data type that is large enough to hold any quantization value.
+ Older code assumed that the quantization data type was an int, but newer
+ could should use the QUANT data type. After all quantization values are
+ stored in a QUANT data type, the data type can be redefined as a byte.
+*/
+typedef int QUANT;
+
+/*!
+ @brief Integer value for the amount of prescale shift
+
+ @todo Redefine this data type to be uint_fast8_t?
+*/
+typedef uint16_t PRESCALE;
+
+
+/*!
+ @brief Number of bits in a component value
+*/
+typedef uint_least8_t PRECISION;
+
+enum
+{
+ PRECISION_MIN = 8,
+ PRECISION_MAX = 32,
+};
+
+/*!
+ @brief Data type for the channel number
+*/
+typedef uint_least8_t CHANNEL;
+
+/*!
+ @brief Data type for the bit mask that represents enabled parts
+
+ The bit mask indicates which parts of the VC-5 standard are enabled
+ at runtime.
+*/
+typedef uint32_t ENABLED_PARTS;
+
+/*!
+ @brief Codec version number (major, minor, revision, build)
+
+ The major and minor product numbers identify versions that are released.
+ Revision numbers are used to identify interim releases for bug fixes.
+ The build number is incremented for every build, independent of product
+ numbering, to uniquely identify every build that is a release candidate.
+*/
+typedef struct _version
+{
+ uint8_t major; //!< Major product number
+ uint8_t minor; //!< Minor product number
+ uint8_t revision; //!< Product revision
+ uint8_t padding; //!< Padding to a multiple of 4 bytes
+ uint32_t build; //!< Unique number for each codec build
+} VERSION;
+
+#define VERSION_INITIALIZER(major, minor, revision, build) {major, minor, revision, 0, build}
+
+#endif // TYPES_H
diff --git a/gpr/source/lib/vc5_common/unique.h b/gpr/source/lib/vc5_common/unique.h
new file mode 100755
index 0000000..b90942e
--- /dev/null
+++ b/gpr/source/lib/vc5_common/unique.h
@@ -0,0 +1,42 @@
+/*! @file unique.h
+ *
+ * @brief Declaration of data structures for the unique image identifier.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UNIQUE_H
+#define UNIQUE_H
+
+// Basic UMID label using the UUID method
+
+static const uint8_t UMID_label[] = {
+ 0x06, 0x0A, 0x2B, 0x34, 0x01, 0x01, 0x01, 0x05, 0x01, 0x01, 0x01, 0x20,
+};
+
+// Length of the UMID (in bytes)
+#define UMID_size 32
+
+// Length of the unique identifier chunk payload (in segments)
+#define UMID_length (UMID_size/sizeof(SEGMENT))
+
+// Length of the image sequence number (in bytes)
+#define sequence_number_size sizeof(uint32_t)
+
+// Length of the image sequence number (in segments)
+#define sequence_number_length (sequence_number_size/sizeof(SEGMENT))
+
+#endif // UNIQUE_H
diff --git a/gpr/source/lib/vc5_common/utilities.c b/gpr/source/lib/vc5_common/utilities.c
new file mode 100755
index 0000000..adc8678
--- /dev/null
+++ b/gpr/source/lib/vc5_common/utilities.c
@@ -0,0 +1,82 @@
+/*! @file utilities.c
+ *
+ * @brief The utilities in this file are included to allow the codec to be tested.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+/*!
+ @brief Check that the enabled parts are correct
+*/
+CODEC_ERROR CheckEnabledParts(ENABLED_PARTS *enabled_parts_ref)
+{
+ ENABLED_PARTS enabled_parts = (*enabled_parts_ref);
+
+ // The elementary bitstream is always enabled
+ if ((enabled_parts & VC5_PART_MASK(VC5_PART_ELEMENTARY)) == 0) {
+ enabled_parts |= VC5_PART_MASK(VC5_PART_ELEMENTARY);
+ }
+
+ // The conformance specification is never enabled
+ enabled_parts &= ~((uint32_t)VC5_PART_MASK(VC5_PART_CONFORMANCE));
+
+ // Image formats must be enabled if subsampled color differences are enabled
+ if ((enabled_parts & VC5_PART_MASK(VC5_PART_COLOR_SAMPLING)) != 0) {
+ enabled_parts |= VC5_PART_MASK(VC5_PART_IMAGE_FORMATS);
+ }
+
+ // Check that the enabled parts were built at compile-time
+ //assert((enabled_parts & VC5_ENABLED_PARTS) == enabled_parts);
+ if (! ((enabled_parts & VC5_ENABLED_PARTS) == enabled_parts)) {
+ return CODEC_ERROR_ENABLED_PARTS;
+ }
+
+ // Return the correct enabled parts mask
+ *enabled_parts_ref = enabled_parts;
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Verify that the enabled parts are correct
+*/
+CODEC_ERROR VerifyEnabledParts(ENABLED_PARTS enabled_parts)
+{
+ // The elementary bitstream must always be enabled
+ if ((enabled_parts & VC5_PART_MASK(VC5_PART_ELEMENTARY)) == 0) {
+ return CODEC_ERROR_ENABLED_PARTS;
+ }
+
+ // The conformance specification must not be enabled
+ if ((enabled_parts & VC5_PART_MASK(VC5_PART_CONFORMANCE)) != 0) {
+ return CODEC_ERROR_ENABLED_PARTS;
+ }
+
+ // Image formats must be enabled if subsampled color differences are enabled
+ if ((enabled_parts & VC5_PART_MASK(VC5_PART_COLOR_SAMPLING)) != 0 &&
+ (enabled_parts & VC5_PART_MASK(VC5_PART_IMAGE_FORMATS)) == 0) {
+ return CODEC_ERROR_ENABLED_PARTS;
+ }
+
+ // All enabled parts must be compiled into this codec implementation
+ if ((enabled_parts & VC5_ENABLED_PARTS) != enabled_parts) {
+ return CODEC_ERROR_ENABLED_PARTS;
+ }
+
+ // This codec implementation supports the enabled parts of the VC-5 standard
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_common/utilities.h b/gpr/source/lib/vc5_common/utilities.h
new file mode 100755
index 0000000..851515b
--- /dev/null
+++ b/gpr/source/lib/vc5_common/utilities.h
@@ -0,0 +1,36 @@
+/*! @file utilities.c
+ *
+ * @brief Utility routines used by the code for testing the codec.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTILITIES_H
+#define UTILITIES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR CheckEnabledParts(ENABLED_PARTS *enabled_parts_ref);
+
+ CODEC_ERROR VerifyEnabledParts(ENABLED_PARTS enabled_parts);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // UTILITIES_H
diff --git a/gpr/source/lib/vc5_common/vc5_common.h b/gpr/source/lib/vc5_common/vc5_common.h
new file mode 100644
index 0000000..a83dc41
--- /dev/null
+++ b/gpr/source/lib/vc5_common/vc5_common.h
@@ -0,0 +1,34 @@
+/*! @file vc5_common.h
+ *
+ * @brief Declaration of items that are used by encoder and decoder API
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VC5_COMMON_H
+#define VC5_COMMON_H
+
+#include "config.h"
+
+// =================================================================================================
+// VC5 version numbering
+// =================================================================================================
+
+#define VC5_VERSION_MAJOR 1
+#define VC5_VERSION_MINOR 0
+#define VC5_VERSION_REVISION 0
+
+#endif // VC5_COMMON_H
diff --git a/gpr/source/lib/vc5_common/wavelet.c b/gpr/source/lib/vc5_common/wavelet.c
new file mode 100755
index 0000000..ec7e31a
--- /dev/null
+++ b/gpr/source/lib/vc5_common/wavelet.c
@@ -0,0 +1,519 @@
+/*! @file wavelet.c
+ *
+ * @brief Implementation of the module for wavelet data structures and transforms
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+/*!
+ @brief Table of prescale values for the spatial wavelet transform
+
+ Each prescale value is indexed by the wavelet level. Index level zero
+ corresponds to the input frame, the other prescale values correspond to
+ wavelets in the transform: frame, spatial, spatial, ...
+
+ Note that the prescale values depend on the encoded precision. The default
+ precale values are for 10-bit precision and the actual will depend on the
+ encoded precision.
+*/
+const int spatial_prescale[] = {0, 2, 0, 0, 0, 0, 0, 0};
+
+/*!
+ @brief Initialize a wavelet data structure with the specified dimensions
+*/
+CODEC_ERROR InitWavelet(WAVELET *wavelet, DIMENSION width, DIMENSION height)
+{
+ assert(wavelet != NULL);
+ if (! (wavelet != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ memset(wavelet, 0, sizeof(WAVELET));
+
+ wavelet->width = width;
+ wavelet->height = height;
+ wavelet->band_count = 4;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Allocate a wavelet data structure with the specified dimensions
+*/
+CODEC_ERROR AllocWavelet(gpr_allocator *allocator, WAVELET *wavelet, DIMENSION width, DIMENSION height)
+{
+ // Initialize the fields in the wavelet data structure
+ InitWavelet(wavelet, width, height);
+
+ if (width > 0 && height > 0)
+ {
+ int band;
+
+ //TODO: Align the pitch?
+ DIMENSION pitch = width * sizeof(PIXEL);
+
+ size_t band_data_size = height * pitch;
+
+ PIXEL* data_all_bands = (PIXEL *)allocator->Alloc(band_data_size * MAX_BAND_COUNT);
+
+ if ( data_all_bands == NULL )
+ {
+ ReleaseWavelet(allocator, wavelet);
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ // Allocate the wavelet bands
+ for (band = 0; band < MAX_BAND_COUNT; band++)
+ {
+ wavelet->data[band] = data_all_bands + band * height * width;
+ }
+
+ wavelet->pitch = pitch;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Release all resources allocated to the wavelet
+
+ The wavelet data structure itself is not reallocated.
+*/
+CODEC_ERROR ReleaseWavelet(gpr_allocator *allocator, WAVELET *wavelet)
+{
+ int band;
+
+ PIXEL* data_all_bands = wavelet->data[0];
+
+ allocator->Free(data_all_bands);
+
+ for (band = 0; band < MAX_BAND_COUNT; band++) {
+ wavelet->data[band] = NULL;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Create and allocate a wavelet data structure
+*/
+WAVELET *CreateWavelet(gpr_allocator *allocator, DIMENSION width, DIMENSION height)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ if (width > 0 && height > 0)
+ {
+ // Allocate the image data structure for the wavelet
+ WAVELET *wavelet = (WAVELET *)allocator->Alloc(sizeof(WAVELET));
+ assert(wavelet != NULL);
+ if (! (wavelet != NULL)) {
+ return NULL;
+ }
+
+ // Allocate space for the wavelet bands
+ error = AllocWavelet(allocator, wavelet, width, height);
+ if (error == CODEC_ERROR_OKAY) {
+ return wavelet;
+ }
+
+ // Avoid a memory leak
+ DeleteWavelet(allocator, wavelet);
+ }
+
+ return NULL;
+}
+
+/*!
+ @brief Release all resources the free the wavelet data structure
+*/
+CODEC_ERROR DeleteWavelet(gpr_allocator *allocator, WAVELET *wavelet)
+{
+ ReleaseWavelet(allocator, wavelet);
+ allocator->Free(wavelet);
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Compute the amount of scaling for each band in the wavelet tree
+
+ The forward wavelet transforms increase the number of bits required to
+ represent the coefficients. This routine computes the amount by which
+ the input pixels are scaled as each band is computed. The horizontal or
+ vertical transform scales the lowpass values by one bit, but the hgihpass
+ values are not scaled. The lowpass wavelet band will be scaled by two
+ bits, the first and second highpass bands will be scaled by one bit, and
+ the third highpass band will not be scaled.
+*/
+CODEC_ERROR SetTransformScale(TRANSFORM *transform)
+{
+ //int num_wavelets = 3;
+ int num_spatial = 2;
+
+ int num_lowpass_spatial; // Number of spatial transforms for lowpass temporal band
+ //int num_highpass_spatial; // Number of spatial transforms for highpass temporal band
+ int num_frame_wavelets; // Number of frame wavelets at the base of the pyramid
+
+ // Area of the temporal lowpass filter
+ int temporal_lowpass_area = 2;
+
+ // Area of the each wavelet filter
+ int horizontal_lowpass_area = 2;
+ int vertical_lowpass_area = 2;
+
+ // Combination of the horizontal and vertical wavelet transforms
+ int spatial_lowpass_area = (horizontal_lowpass_area * vertical_lowpass_area);
+
+ int temporal_lowpass_scale;
+ int temporal_highpass_scale;
+
+ WAVELET *wavelet = NULL;
+ //WAVELET *temporal;
+
+ int k;
+ int i;
+
+ // Coefficients in each band are scaled by the forward wavelet filters
+ int scale[4] = {1, 1, 1, 1};
+
+ // Compute the number of frame and spatial wavelets
+ num_frame_wavelets = 1;
+ num_lowpass_spatial = num_spatial;
+
+ // Compute the change in scale due to the filters used in the frame transform
+ temporal_lowpass_scale = temporal_lowpass_area * scale[0];
+ temporal_highpass_scale = scale[0];
+
+ // Compute the scale factors for the first wavelet
+ scale[0] = horizontal_lowpass_area * temporal_lowpass_scale;
+ scale[1] = temporal_lowpass_scale;
+ scale[2] = horizontal_lowpass_area * temporal_highpass_scale;
+ scale[3] = temporal_highpass_scale;
+
+ for (k = 0; k < num_frame_wavelets; k++)
+ {
+ wavelet = transform->wavelet[k];
+ assert(wavelet != NULL);
+ if (! (wavelet != NULL)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ wavelet->scale[0] = scale[0];
+ wavelet->scale[1] = scale[1];
+ wavelet->scale[2] = scale[2];
+ wavelet->scale[3] = scale[3];
+ }
+
+ // Compute the scale factors for the spatial wavelets
+ for (i = 0; i < num_lowpass_spatial; i++)
+ {
+ WAVELET *spatial = transform->wavelet[k++];
+ //int k;
+
+ assert(spatial != NULL);
+ if (! (spatial != NULL)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ assert(wavelet != NULL);
+ if (! (wavelet != NULL)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ // The lowpass band is the input to the spatial transform
+ temporal_lowpass_scale = wavelet->scale[0];
+
+ spatial->scale[0] = (spatial_lowpass_area * temporal_lowpass_scale);// >> _LOWPASS_PRESCALE;
+ spatial->scale[1] = (vertical_lowpass_area * temporal_lowpass_scale);// >> _LOWPASS_PRESCALE;
+ spatial->scale[2] = (horizontal_lowpass_area * temporal_lowpass_scale);// >> _LOWPASS_PRESCALE;
+ spatial->scale[3] = (temporal_lowpass_scale);// >> _LOWPASS_PRESCALE;
+
+ // The spatial wavelet is the input for the next level
+ wavelet = spatial;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Calculate the amount of prescaling required to prevent overflow
+
+ This routine calculates the arithmetic right shift that is applied to each
+ lowpass band prior to computation of the wavelet transform. Prescaling is
+ required to prevent overflow in the wavelet transforms.
+*/
+CODEC_ERROR SetTransformPrescale(TRANSFORM *transform, int precision)
+{
+ if (precision == 8)
+ {
+ memset(transform->prescale, 0, sizeof(transform->prescale));
+ return CODEC_ERROR_OKAY;
+ }
+ else if (precision == 10)
+ {
+ PRESCALE spatial_prescale[] = {0, 2, 2, 0, 0, 0, 0, 0};
+ memcpy(transform->prescale, spatial_prescale, sizeof(transform->prescale));
+ }
+ else if (precision == 12)
+ {
+ // frame, spatial, spatial, ...
+ PRESCALE spatial_prescale[] = {0, 2, 2, 0, 0, 0, 0, 0};
+ memcpy(transform->prescale, spatial_prescale, sizeof(transform->prescale));
+ }
+ else
+ {
+ //TODO: Need to handle other precisions
+ assert(0);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return a mask for the specified wavelet band
+
+ The wavelet data structure contains a mask that indicates which
+ bands have been decoded.
+*/
+bool BandValidMask(int band)
+{
+ return (1 << band);
+}
+
+/*!
+ @brief Check that all bands are valid
+
+ The wavelet valid band mask is checked to determine whether
+ all of the bands in the wavelet have been decoded.
+*/
+bool BandsAllValid(WAVELET *wavelet)
+{
+ uint32_t all_bands_valid_mask = ((1 << wavelet->band_count) - 1);
+ return (wavelet->valid_band_mask == all_bands_valid_mask);
+}
+
+/*!
+ @brief Set the bit for the specified band in the valid band mask
+*/
+CODEC_ERROR UpdateWaveletValidBandMask(WAVELET *wavelet, int band)
+{
+ if (0 <= band && band < MAX_BAND_COUNT)
+ {
+ // Update the valid wavelet band flags
+ wavelet->valid_band_mask |= (1 << band);
+ return CODEC_ERROR_OKAY;
+ }
+ return CODEC_ERROR_INVALID_BAND;
+}
+
+/*!
+ @brief Compute the wavelet index from the subband index
+
+ All subbands that are encoded into the bitstream, including the
+ lowpass band at the highest wavelet level, are numbered in decode
+ order starting with zero for the lowpass band.
+
+ This routine maps the subband index to the index of the wavelet
+ that contains the specified subband.
+
+ Note the sifference between a wavelet band and a subband: The bands in
+ each wavelet are numbered starting at zero, while the subband index
+ applies to all wavelet bands in the encoded sample and does not include
+ the lowpass bands that are reconstructed during decoding from the bands
+ that were encoded into the bitstream.
+*/
+int SubbandWaveletIndex(int subband)
+{
+ //TODO: Adjust for other transform types and decoded resolutions
+ static int subband_wavelet_index[] = {2, 2, 2, 2, 1, 1, 1, 0, 0, 0};
+
+ assert(0 <= subband && subband < MAX_SUBBAND_COUNT);
+
+ // Return the index of the wavelet corresponding to this subband
+ return subband_wavelet_index[subband];
+}
+
+/*!
+ @brief Compute the index for the band in a wavelet from the subband index
+
+ See the explanation of wavelet bands and subbands in the documentation for
+ @ref SubbandWaveletIndex.
+*/
+int SubbandBandIndex(int subband)
+{
+ //TODO: Adjust for other transform types and decoded resolutions
+ static int subband_band_index[] = {0, 1, 2, 3, 1, 2, 3, 1, 2, 3};
+
+ assert(0 <= subband && subband < MAX_SUBBAND_COUNT);
+
+ // Return the index to the band within the wavelet
+ return subband_band_index[subband];
+}
+
+/*!
+ @brief Free the wavelets allocated for this transform
+*/
+CODEC_ERROR ReleaseTransform(gpr_allocator *allocator, TRANSFORM *transform)
+{
+ int wavelet_index;
+
+ for (wavelet_index = 0; wavelet_index < MAX_WAVELET_COUNT; wavelet_index++)
+ {
+ WAVELET *wavelet = transform->wavelet[wavelet_index];
+ if (wavelet != NULL) {
+ DeleteWavelet(allocator, wavelet);
+ transform->wavelet[wavelet_index] = NULL;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return true if the prescale table is the same as the default table
+
+ This routine compares the prescale values used by the transform with the default
+ table of prescale values. If the actual prescale values are the same as the
+ default values, then the table of prescale values do not have to be encoded
+ into the bitstream.
+*/
+bool IsTransformPrescaleDefault(TRANSFORM *transform, int precision)
+{
+ int prescale_count = sizeof(transform->prescale) / sizeof(transform->prescale[0]);
+ int total = 0;
+ int i;
+
+ if (precision == 8)
+ {
+ for (i = 0; i < prescale_count; i++) {
+ total += transform->prescale[i];
+ }
+ return (total == 0);
+ }
+
+ for (i = 0; i < prescale_count; i++) {
+ total += absolute(transform->prescale[i] - spatial_prescale[i]);
+ }
+ for(; i < MAX_PRESCALE_COUNT; i++) {
+ total += spatial_prescale[i];
+ }
+ return (total == 0);
+}
+
+PIXEL *WaveletRowAddress(WAVELET *wavelet, int band, int row)
+{
+ assert(wavelet != NULL);
+ if (! (wavelet != NULL)) {
+ return NULL;
+ }
+
+ assert(0 <= row && row < wavelet->height);
+ if (! (0 <= row && row < wavelet->height))
+ {
+ return NULL;
+ }
+ else
+ {
+ uint8_t *address = (uint8_t *)wavelet->data[band];
+ address += row * wavelet->pitch;
+ return (PIXEL *)address;
+ }
+}
+
+void WaveletToRGB( gpr_allocator allocator, PIXEL* GS_src, PIXEL* RG_src, PIXEL* BG_src, DIMENSION src_width, DIMENSION src_height, DIMENSION src_pitch, RGB_IMAGE *dst_image,
+ int input_precision_bits, int output_precision_bits, gpr_rgb_gain* rgb_gain )
+{
+ TIMESTAMP("[BEG]", 2)
+
+ assert( dst_image );
+ assert( dst_image->buffer == NULL );
+
+ size_t size;
+ if( output_precision_bits == 8 )
+ {
+ size = src_width * src_height * 3;
+ }
+ else
+ {
+ size = src_width * src_height * 6;
+ }
+
+ dst_image->width = src_width;
+ dst_image->height = src_height;
+ dst_image->pitch = src_width * 3;
+ dst_image->size = size;
+ dst_image->buffer = allocator.Alloc( size );
+
+ const int32_t midpoint = (1 << (input_precision_bits - 1));
+ const int32_t shift = input_precision_bits - 12;
+
+ unsigned char* RGB_dst_8bits = dst_image->buffer;
+ unsigned short* RGB_dst_16bits = dst_image->buffer;
+
+ DIMENSION x, y;
+
+ for ( y = 0; y < src_height; y++)
+ {
+ for ( x = 0; x < src_width; x++)
+ {
+ int32_t G = GS_src[ (src_width - x - 1) + y * src_pitch];
+ int32_t R = 2 * ( RG_src[(src_width - x - 1) + y * src_pitch] - midpoint) + G;
+ int32_t B = 2 * ( BG_src[(src_width - x - 1) + y * src_pitch] - midpoint) + G;
+
+ // R,G,B are in 16-bit range since DecoderLogCurve outputs in 16 bits (although it's input is 12 bits)
+ R = DecoderLogCurve[ clamp_uint( (R >> shift), 12) ];
+ G = DecoderLogCurve[ clamp_uint( (G >> shift), 12) ];
+ B = DecoderLogCurve[ clamp_uint( (B >> shift), 12) ];
+
+ if( output_precision_bits == 8 )
+ {
+ R *= rgb_gain->r_gain_num;
+ R >>= rgb_gain->r_gain_pow2_den;
+
+ G *= rgb_gain->g_gain_num;
+ G >>= rgb_gain->g_gain_pow2_den;
+
+ B *= rgb_gain->b_gain_num;
+ B >>= rgb_gain->b_gain_pow2_den;
+
+ R = sqrtf((float)R);
+ G = sqrtf((float)G);
+ B = sqrtf((float)B);
+
+ R = clamp_uint8( R );
+ G = clamp_uint8( G );
+ B = clamp_uint8( B );
+
+ RGB_dst_8bits[3 * (x) + 0 + y * dst_image->pitch] = R;
+ RGB_dst_8bits[3 * (x) + 1 + y * dst_image->pitch] = G;
+ RGB_dst_8bits[3 * (x) + 2 + y * dst_image->pitch] = B;
+ }
+ else
+ {
+ R = clamp_uint16( R );
+ G = clamp_uint16( G );
+ B = clamp_uint16( B );
+
+ RGB_dst_16bits[3 * (x) + 0 + y * dst_image->pitch] = ( (R & 0x00FF) << 8 ) | ( (R & 0xFF00) >> 8 );
+ RGB_dst_16bits[3 * (x) + 1 + y * dst_image->pitch] = ( (G & 0x00FF) << 8 ) | ( (G & 0xFF00) >> 8 );
+ RGB_dst_16bits[3 * (x) + 2 + y * dst_image->pitch] = ( (B & 0x00FF) << 8 ) | ( (B & 0xFF00) >> 8 );
+ }
+ }
+ }
+
+ TIMESTAMP("[BEG]", 2)
+}
diff --git a/gpr/source/lib/vc5_common/wavelet.h b/gpr/source/lib/vc5_common/wavelet.h
new file mode 100755
index 0000000..cc5e2b6
--- /dev/null
+++ b/gpr/source/lib/vc5_common/wavelet.h
@@ -0,0 +1,126 @@
+/*! @file vlc.h
+ *
+ * @brief This file defines the data structures for the wavelet tree
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WAVELET_H
+#define WAVELET_H
+
+#include "common.h"
+
+/*!
+ @brief Data structure used for wavelets
+
+ This data structure is used for wavelets and can be used for images since
+ an image with multiple planar channels and a wavelet with multiple bands
+ are similar data structures.
+
+ The pitch is the distance between rows in bytes and must always be
+ an integer multiple of the pixel size in bytes.
+
+ The wavelet data structure contains an array of the scale factor for
+ each band that is the cummulative result of the application of the
+ wavelet transforms that created the wavelet.
+*/
+typedef struct _wavelet
+{
+ DIMENSION width; //!< Width of the image in pixels
+ DIMENSION height; //!< Height of the image in lines
+ DIMENSION pitch; //!< Distance between rows (in bytes)
+ uint16_t band_count; //!< Number of bands in a wavelet
+ uint32_t valid_band_mask; //!< Mask indicating which bands have been decoded
+ uint16_t scale[MAX_BAND_COUNT]; //!< Cumulative scaling by the wavelet transforms
+ QUANT quant[MAX_BAND_COUNT]; //!< Quantization value for each band
+ PIXEL *data[MAX_BAND_COUNT]; //!< Data buffer for each band
+
+} WAVELET;
+
+//! Indices for the wavelet bands in the image data structure
+typedef enum
+{
+ LL_BAND = 0, //!< Lowpass transform of lowpass intermediate result
+ LH_BAND, //!< Lowpass transform of highpass intermediate result
+ HL_BAND, //!< Highpass transform of lowpass intermediate result
+ HH_BAND //!< Highpass transform of highpass intermediate result
+} WAVELET_BAND;
+
+//! Types of wavelet tranforms
+enum
+{
+ WAVELET_TYPE_HORIZONTAL = 1,
+ WAVELET_TYPE_VERTICAL = 2,
+ WAVELET_TYPE_TEMPORAL = 4,
+
+ //! The baseline profile only supports spatial wavelets
+ WAVELET_TYPE_SPATIAL = (WAVELET_TYPE_HORIZONTAL | WAVELET_TYPE_VERTICAL),
+
+};
+
+//! Data structure for the wavelet tree (one channel)
+typedef struct _transform
+{
+ //! Prescale the input by the specified shift before the transform
+ PRESCALE prescale[MAX_WAVELET_COUNT];
+
+ //! List of the wavelets in the transform for one channel
+ WAVELET *wavelet[MAX_WAVELET_COUNT];
+
+} TRANSFORM;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR AllocWavelet(gpr_allocator *allocator, WAVELET *wavelet, DIMENSION width, DIMENSION height);
+ CODEC_ERROR ReleaseWavelet(gpr_allocator *allocator, WAVELET *wavelet);
+
+ WAVELET *CreateWavelet(gpr_allocator *allocator, DIMENSION width, DIMENSION height);
+ CODEC_ERROR DeleteWavelet(gpr_allocator *allocator, WAVELET *wavelet);
+
+ CODEC_ERROR SetTransformScale(TRANSFORM *transform);
+
+ CODEC_ERROR SetTransformPrescale(TRANSFORM *transform, int precision);
+
+ bool BandValidMask(int band);
+
+ bool BandsAllValid(WAVELET *wavelet);
+ #define AllBandsValid BandsAllValid
+
+ CODEC_ERROR UpdateWaveletValidBandMask(WAVELET *wavelet, int band);
+
+ int SubbandWaveletIndex(int subband);
+
+ int SubbandBandIndex(int subband);
+
+ CODEC_ERROR ResetTransformFlags(TRANSFORM transform[], int transform_count);
+
+ CODEC_ERROR ReleaseTransform(gpr_allocator *allocator, TRANSFORM *transform);
+
+ bool IsTransformPrescaleDefault(TRANSFORM *transform, int precision);
+
+ PIXEL *WaveletRowAddress(WAVELET *wavelet, int band, int row);
+
+ void WaveletToRGB( gpr_allocator allocator, PIXEL* GS_src, PIXEL* RG_src, PIXEL* BG_src, DIMENSION src_width, DIMENSION src_height, DIMENSION src_pitch, RGB_IMAGE *dst_image,
+ int input_precision_bits, int output_precision_bits, gpr_rgb_gain* rgb_gain );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // WAVELET_H
diff --git a/gpr/source/lib/vc5_decoder/CMakeLists.txt b/gpr/source/lib/vc5_decoder/CMakeLists.txt
new file mode 100644
index 0000000..d78522d
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/CMakeLists.txt
@@ -0,0 +1,22 @@
+# library
+set( LIB_NAME vc5_decoder )
+
+# get source files
+file( GLOB SRC_FILES "*.c" )
+
+# get include files
+file( GLOB INC_FILES "*.h" )
+
+# add include files from other folders
+include_directories( "../vc5_common" )
+include_directories( "../common/private" )
+include_directories( "../common/public" )
+
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/vc5_decoder/codebooks.c b/gpr/source/lib/vc5_decoder/codebooks.c
new file mode 100755
index 0000000..cfd40d4
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/codebooks.c
@@ -0,0 +1,36 @@
+/*! @file codebooks.c
+ *
+ * @brief Implementation of routines for the inverse component transform and permutation.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+#include "table17.inc"
+
+/*!
+ @brief Define the codeset used by the reference codec
+
+ The baseline codec only supports codebook #17.
+
+ Codebook #17 is intended to be used with cubic companding
+ (see @ref FillMagnitudeEncodingTable and @ref ComputeCubicTable).
+ */
+DECODER_CODESET decoder_codeset_17 = {
+ "Codebook set 17 from data by David Newman with tables automatically generated for the FSM decoder",
+ (const CODEBOOK *)&table17,
+ CODESET_FLAGS_COMPANDING_CUBIC,
+};
diff --git a/gpr/source/lib/vc5_decoder/codebooks.h b/gpr/source/lib/vc5_decoder/codebooks.h
new file mode 100755
index 0000000..94670ee
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/codebooks.h
@@ -0,0 +1,50 @@
+/*! @file codebooks.h
+ *
+ * @brief Declaration of routines for the inverse component transform and permutation.
+ * The collection of codebooks that are used by the decoder are called a codeset.
+ * The codebook in seach codeset is derived from the master codebook that is
+ * included in the codec by including the table for the codebook. The encoder
+ * uses specialized codebooks for coefficient magnitudes and runs of zeros that
+ * are derived from the master codebook.
+
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEBOOKS_H
+#define CODEBOOKS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct decoder_codeset {
+
+ const char *title; //!< Identifying string for the codeset
+
+ const CODEBOOK *codebook; //!< Codebook for runs and magnitudes
+
+ uint32_t flags; //!< Encoding flags (see the codeset flags)
+
+ } DECODER_CODESET;
+
+ //TODO: Need to support other codesets in the reference decoder?
+ extern DECODER_CODESET decoder_codeset_17;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CODEBOOKS_H
diff --git a/gpr/source/lib/vc5_decoder/component.c b/gpr/source/lib/vc5_decoder/component.c
new file mode 100755
index 0000000..c224dc5
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/component.c
@@ -0,0 +1,111 @@
+/*! @file component.c
+ *
+ * @brief Code for parsing the inverse component transform and inverse component permutation.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+CODEC_ERROR ParseInverseComponentTransform(DECODER *decoder, BITSTREAM *stream, size_t chunk_size)
+{
+ //CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &decoder->codec;
+ int component_count = codec->channel_count;
+ int padding;
+ int i;
+
+#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING)
+ if (IsPartEnabled(decoder->enabled_parts, VC5_PART_COLOR_SAMPLING))
+ {
+ // Recompute the number of components to account for color difference component subsampling
+ component_count = codec->pattern_width * codec->pattern_height + 2;
+ }
+#endif
+
+ // Compute the padding (in bytes) from the end of the component transform to the end of the chunk payload
+ padding = (int)((chunk_size * sizeof(SEGMENT)) - ((component_count + 2) * component_count) * sizeof(uint8_t));
+
+ for (i = 0; i < component_count; i++)
+ {
+ int offset;
+ int scale;
+ int j;
+
+ for (j = 0; j < component_count; j++)
+ {
+ int matrix_index = i * component_count + j;
+ int matrix_value = GetBits(stream, 8);
+
+ //TODO: Need to save the value in the codec state
+ (void)matrix_index;
+ (void)matrix_value;
+ }
+
+ offset = GetBits(stream, 8);
+ scale = GetBits(stream, 8);
+
+ //TODO: Need to save the offset and scale in the codec state
+ (void)offset;
+ (void)scale;
+ }
+
+ // Skip the padding at the end of the chunk payload
+ GetBits(stream, 8 * padding);
+
+ // Should be at the end of the last segment in the chunk
+ assert(IsAlignedSegment(stream));
+
+ return CODEC_ERROR_OKAY;
+}
+
+CODEC_ERROR ParseInverseComponentPermutation(DECODER *decoder, BITSTREAM *stream, size_t chunk_size)
+{
+ //CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &decoder->codec;
+ int component_count = codec->channel_count;
+ int padding;
+ int i;
+
+#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING)
+ if (IsPartEnabled(decoder->enabled_parts, VC5_PART_COLOR_SAMPLING))
+ {
+ // Recompute the number of components to account for color difference component subsampling
+ component_count = codec->pattern_width * codec->pattern_height + 2;
+ }
+#endif
+
+ // Compute the padding (in bytes) from the end of the component transform to the end of the chunk payload
+ padding = (int)((chunk_size * sizeof(SEGMENT)) - component_count * sizeof(uint8_t));
+
+ for (i = 0; i < component_count; i++)
+ {
+ int value;
+
+ value = GetBits(stream, 8);
+
+ //TODO: Need to save the permutation index in yhe codec state
+ (void)value;
+ }
+
+ // Skip the padding at the end of the chunk payload
+ GetBits(stream, 8 * padding);
+
+ // Should be at the end of the last segment in the chunk
+ assert(IsAlignedSegment(stream));
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_decoder/component.h b/gpr/source/lib/vc5_decoder/component.h
new file mode 100755
index 0000000..db208b0
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/component.h
@@ -0,0 +1,36 @@
+/*! @file component.h
+ *
+ * @brief Declaration of routines for the inverse component transform and permutation.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR ParseInverseComponentTransform(DECODER *decoder, BITSTREAM *stream, size_t chunk_size);
+
+ CODEC_ERROR ParseInverseComponentPermutation(DECODER *decoder, BITSTREAM *stream, size_t chunk_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COMPONENT_H
diff --git a/gpr/source/lib/vc5_decoder/decoder.c b/gpr/source/lib/vc5_decoder/decoder.c
new file mode 100755
index 0000000..73aa3b8
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/decoder.c
@@ -0,0 +1,2310 @@
+/*! @file decoder.h
+ *
+ * @brief Implementation of core decoder functions and data structure
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+/*!
+ @brief Align the bitstream to a byte boundary
+
+ Enough bits are removed from the bitstream buffer to
+ align the bitstream to the next byte.
+ */
+static CODEC_ERROR AlignBitsByte(BITSTREAM *bitstream)
+{
+ // Compute the number of bits to skip
+ BITCOUNT count = bitstream->count % 8;
+ GetBits(bitstream, count);
+ assert((bitstream->count % 8) == 0);
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Align the bitstream to the next word boundary
+
+ All of the bits in the bitstream buffer are flushed unless
+ the bitstream buffer is completely empty or completely full.
+ */
+static CODEC_ERROR AlignBitsWord(BITSTREAM *bitstream)
+{
+ BITCOUNT count = bitstream->count;
+
+ if (0 < count && count < bit_word_count) {
+ GetBits(bitstream, count);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Align the bitstream to the next tag value pair
+ */
+static CODEC_ERROR AlignBitsSegment(BITSTREAM *bitstream)
+{
+ STREAM *stream = bitstream->stream;
+ size_t byte_count;
+
+ // Byte align the bitstream
+ AlignBitsByte(bitstream);
+ assert((bitstream->count % 8) == 0);
+
+ // Compute the number of bytes in the bit buffer
+ byte_count = bitstream->count / 8;
+
+ // Add the number of bytes read from the stream
+ byte_count += stream->byte_count;
+
+ while ((byte_count % sizeof(TAGVALUE)) != 0)
+ {
+ GetBits(bitstream, 8);
+ byte_count++;
+ }
+
+ // The bitstream should be aligned to the next segment
+ assert((bitstream->count == 0) || (bitstream->count == bit_word_count));
+ assert((byte_count % sizeof(TAGVALUE)) == 0);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize the decoder data structure
+ This routine performs the same function as a C++ constructor.
+ The decoder is initialized with default values that are replaced
+ by the parameters used to prepare the decoder (see @ref PrepareDecoder).
+ This routine does not perform all of the initializations required
+ to prepare the decoder data structure for decoding a sample.
+ */
+CODEC_ERROR InitDecoder(DECODER *decoder, const gpr_allocator *allocator)
+{
+ assert(decoder != NULL);
+ if (! (decoder != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ memset(decoder, 0, sizeof(DECODER));
+
+ // Assign a memory allocator to the decoder
+ decoder->allocator = (gpr_allocator *)allocator;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Release resources allocated by the decoder
+ Note that this routine does not close the logfile.
+ */
+CODEC_ERROR ReleaseDecoder(DECODER *decoder)
+{
+ // Free the wavelet transforms and decoding buffers
+ ReleaseDecoderTransforms(decoder);
+ ReleaseDecoderBuffers(decoder);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Decode the bitstream encoded into the byte stream into separate component arrays
+ This is a convenience routine for applications that use the byte stream data structure
+ for bitstreams stored in a file or memory buffer.
+ The main entry point for decoding a bitstream is @ref DecodingProcess.
+ The parameters data structure is intended to simulate information that may be available
+ to the decoder from the media container or an external application.
+ This routine assumes that the unpacked image has already been initialized.
+ */
+CODEC_ERROR DecodeStream(STREAM *stream, UNPACKED_IMAGE *unpacked_image, const DECODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ BITSTREAM bitstream;
+ DECODER decoder;
+
+ // Initialize the bitstream data structure
+ InitBitstream(&bitstream);
+
+ // Bind the bitstream to the byte stream
+ error = AttachBitstream(&bitstream, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Decode the bitstream sample into a image buffer
+ error = DecodingProcess(&decoder, &bitstream, unpacked_image, parameters);
+
+ // Release any resources allocated by the decoder
+ ReleaseDecoder(&decoder);
+
+ // Release any resources allocated by the bitstream
+ ReleaseBitstream(&bitstream);
+
+ return error;
+}
+
+/*!
+ @brief Decode the bitstream encoded into the byte stream
+ This is a convenience routine for applications that use the byte
+ stream data structure for samples stored in a file or memory buffer.
+ The main entry point for decoding a bitstream is @ref DecodingProcess.
+ The parameters data structure is intended to simulate information that
+ may be available to the decoder from the media container or an external
+ application.
+ */
+CODEC_ERROR DecodeImage(STREAM *stream, IMAGE *packed_image, RGB_IMAGE *rgb_image, DECODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ BITSTREAM bitstream;
+ DECODER decoder;
+ DIMENSION packed_width;
+ DIMENSION packed_height;
+ PIXEL_FORMAT packed_format;
+
+ SetupDecoderLogCurve();
+
+ // The unpacked image will hold the component arrays decoded from the bitstream
+ UNPACKED_IMAGE unpacked_image;
+
+ // Initialize the bitstream data structure
+ InitBitstream(&bitstream);
+
+ // Bind the bitstream to the byte stream
+ error = AttachBitstream(&bitstream, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // The component arrays will be allocated after the bitstream is decoded
+ InitUnpackedImage(&unpacked_image);
+
+ // Decode the bitstream sample into a image buffer
+ error = DecodingProcess(&decoder, &bitstream, &unpacked_image, parameters);
+
+ if( error != CODEC_ERROR_OKAY )
+ {
+ return error;
+ }
+
+ switch (parameters->rgb_resolution) {
+
+ case GPR_RGB_RESOLUTION_NONE:
+ // The dimensions and format for the output of the image packing process
+ SetOutputImageFormat(&decoder, parameters, &packed_width, &packed_height, &packed_format);
+
+ // Allocate the image buffer for output of the image packing process
+ AllocImage(decoder.allocator, packed_image, packed_width, packed_height, packed_format);
+
+ // Pack the component arrays into the output image
+ ImageRepackingProcess(&unpacked_image, packed_image, parameters);
+ break;
+
+ case GPR_RGB_RESOLUTION_HALF:
+ WaveletToRGB(parameters->allocator, (PIXEL*)unpacked_image.component_array_list[0].data, (PIXEL*)unpacked_image.component_array_list[1].data, (PIXEL*)unpacked_image.component_array_list[2].data,
+ unpacked_image.component_array_list[2].width, unpacked_image.component_array_list[2].height, unpacked_image.component_array_list[2].pitch / 2,
+ rgb_image, 12, parameters->rgb_bits, &parameters->rgb_gain );
+ break;
+
+ case GPR_RGB_RESOLUTION_QUARTER:
+
+ WaveletToRGB(parameters->allocator, decoder.transform[0].wavelet[0]->data[0], decoder.transform[1].wavelet[0]->data[0], decoder.transform[2].wavelet[0]->data[0],
+ decoder.transform[2].wavelet[0]->width, decoder.transform[2].wavelet[0]->height, decoder.transform[2].wavelet[0]->width,
+ rgb_image, 14, parameters->rgb_bits, &parameters->rgb_gain );
+ break;
+
+ case GPR_RGB_RESOLUTION_EIGHTH:
+
+ WaveletToRGB(parameters->allocator, decoder.transform[0].wavelet[1]->data[0], decoder.transform[1].wavelet[1]->data[0], decoder.transform[2].wavelet[1]->data[0],
+ decoder.transform[2].wavelet[1]->width, decoder.transform[2].wavelet[1]->height, decoder.transform[2].wavelet[1]->width,
+ rgb_image, 14, parameters->rgb_bits, &parameters->rgb_gain );
+
+ break;
+
+ case GPR_RGB_RESOLUTION_SIXTEENTH:
+
+ WaveletToRGB(parameters->allocator, decoder.transform[0].wavelet[2]->data[0], decoder.transform[1].wavelet[2]->data[0], decoder.transform[2].wavelet[2]->data[0],
+ decoder.transform[2].wavelet[2]->width, decoder.transform[2].wavelet[2]->height, decoder.transform[2].wavelet[2]->width,
+ rgb_image, 14, parameters->rgb_bits, &parameters->rgb_gain );
+ break;
+
+ default:
+ return CODEC_ERROR_UNSUPPORTED_FORMAT;
+ break;
+ }
+
+ ReleaseComponentArrays( &parameters->allocator, &unpacked_image, unpacked_image.component_count );
+
+ // Release any resources allocated by the decoder
+ ReleaseDecoder(&decoder);
+
+ // Release any resources allocated by the bitstream
+ ReleaseBitstream(&bitstream);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize the decoder using the specified parameters
+ @todo Add more error checking to this top-level routine
+ */
+CODEC_ERROR PrepareDecoder(DECODER *decoder, const DECODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Initialize the decoder data structure
+ error = InitDecoder(decoder, &parameters->allocator);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Set the mask that specifies which parts of the VC-5 standard are supported
+ decoder->enabled_parts = parameters->enabled_parts;
+
+ // Verify that the enabled parts are correct
+ error = VerifyEnabledParts(decoder->enabled_parts);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Initialize the codec state (allocation routines use the codec state)
+ error = PrepareDecoderState(decoder, parameters);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ if (parameters != NULL)
+ {
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ decoder->layer_count = (uint_fast8_t)parameters->layer_count;
+ decoder->progressive = parameters->progressive;
+ decoder->top_field_first = parameters->top_field_first;
+#endif
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsPartEnabled(decoder->enabled_parts, VC5_PART_SECTIONS))
+ {
+ decoder->section_flag = parameters->section_flag;
+ }
+#endif
+
+ decoder->subbands_to_decode = MAX_SUBBAND_COUNT;
+
+ return error;
+}
+
+/*!
+ @brief Decode a VC-5 bitstream to an ordered set of component arrays
+ This is the main entry point for decoding a sample. The decoder must
+ have been initialized by a call to @ref PrepareDecoder.
+ The bitstream must be initialized and bound to a byte stream before
+ calling this routine. The unpacked output image will be initialized by this
+ routine to hold the decoded component arrays represented in the bitstream.
+ @todo When the VC-5 part for layers is defined, should be able to pass a mask
+ indicating which layers must be decoded
+ */
+CODEC_ERROR DecodingProcess(DECODER *decoder, BITSTREAM *stream, UNPACKED_IMAGE *image, const DECODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ TAGVALUE segment;
+
+ // Initialize the decoder with a default allocator
+ PrepareDecoder(decoder, parameters);
+
+ // Get the bitstream start marker
+ segment = GetSegment(stream);
+ if (segment.longword != StartMarkerSegment)
+ {
+ return CODEC_ERROR_MISSING_START_MARKER;
+ }
+
+ // Set up number of subbands to decode
+ if( parameters->rgb_resolution == GPR_RGB_RESOLUTION_SIXTEENTH )
+ {
+ decoder->subbands_to_decode = 1;
+ }
+ else if( parameters->rgb_resolution == GPR_RGB_RESOLUTION_EIGHTH )
+ {
+ decoder->subbands_to_decode = 4;
+ }
+ else if( parameters->rgb_resolution == GPR_RGB_RESOLUTION_QUARTER )
+ {
+ decoder->subbands_to_decode = 7;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ // Decode each layer in the sample
+ if (decoder->layer_count > 1)
+ {
+ IMAGE decoded_image[MAX_LAYER_COUNT];
+ PIXEL_FORMAT decoded_format = decoder->output.format;
+ int layer_index;
+
+ for (layer_index = 0; layer_index < decoder->layer_count; layer_index++)
+ {
+ DIMENSION layer_width = LayerWidth(decoder, decoder->output.width);
+ DIMENSION layer_height = LayerHeight(decoder, decoder->output.height);
+
+ // Allocate a image for this layer
+ AllocImage(decoder->allocator, &decoded_image[layer_index], layer_width, layer_height, decoded_format);
+
+ // Decode the layer into its own image
+ error = DecodeSampleLayer(decoder, stream, &decoded_image[layer_index]);
+ if (error != CODEC_ERROR_OKAY) {
+ break;
+ }
+ }
+
+ if (error == CODEC_ERROR_OKAY)
+ {
+ // The decoded image in each layer is composited into the output image
+ error = ReconstructSampleFrame(decoder, decoded_image, decoder->layer_count, image);
+ }
+
+ // Free the images used for decoding each layer
+ for (layer_index = 0; layer_index < decoder->layer_count; layer_index++)
+ {
+ ReleaseImage(decoder->allocator, &decoded_image[layer_index]);
+ }
+ }
+ else
+#endif
+ {
+ // A VC-5 Part 1 bitstream can only contain a single layer (encoded image)
+ error = DecodeSingleImage(decoder, stream, image, parameters);
+ }
+
+ // Done decoding all layers in the sample and computing the output image
+ return error;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Decode the portion of a sample that corresponds to a single layer
+ Samples can be contain multiple subsamples. Each subsample may correspond to
+ a different view. For example, an encoded video sample may contain both the
+ left and right subsamples in a stereo pair.
+ Subsamples have been called tracks or channels, but this terminology can be
+ confused with separate video tracks in a multimedia container or the color
+ planes that are called channels elsewhere in this codec.
+ The subsamples are decoded seperately and composited to form a single image
+ that is the output of the complete process of decoding a single video sample.
+ For this reason, the subsamples are called layers.
+ @todo Okay to call a subsample a layer?
+ */
+CODEC_ERROR DecodeSampleLayer(DECODER *decoder, BITSTREAM *input, UNPACKED_IMAGE *image)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Initialize the codec state (including the dimensions of the first wavelet band)
+ PrepareDecoderState(decoder, NULL);
+
+ // Reset the flags in the wavelet transforms
+ PrepareDecoderTransforms(decoder);
+
+ // Process tag value pairs until the layer has been decoded
+ for (;;)
+ {
+ TAGVALUE segment;
+
+ // Read the next tag value pair from the bitstream
+ segment = GetSegment(input);
+ assert(input->error == BITSTREAM_ERROR_OKAY);
+ if (input->error != BITSTREAM_ERROR_OKAY) {
+ decoder->error = CodecErrorBitstream(input->error);
+ return decoder->error;
+ break;
+ }
+
+ error = UpdateCodecState(decoder, input, segment);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Processed all wavelet bands in all channels?
+ if (IsLayerComplete(decoder)) break;
+
+ }
+
+ // Parsed the bitstream without errors?
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Reconstruct the output image using the last decoded wavelet in each channel
+ return ReconstructLayerImage(decoder, image);
+}
+#endif
+
+/*!
+ @brief Decode the bitstream into a list of component arrays
+ */
+CODEC_ERROR DecodeSingleImage(DECODER *decoder, BITSTREAM *input, UNPACKED_IMAGE *image, const DECODER_PARAMETERS *parameters)
+{
+ TIMESTAMP("[BEG]", 2)
+
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ CODEC_STATE *codec = &decoder->codec;
+
+ // Process tag value pairs until the layer has been decoded
+ for (;;)
+ {
+ TAGVALUE segment;
+
+ // Read the next tag value pair from the bitstream
+ segment = GetSegment(input);
+ assert(input->error == BITSTREAM_ERROR_OKAY);
+ if (input->error != BITSTREAM_ERROR_OKAY) {
+ decoder->error = CodecErrorBitstream(input->error);
+ return decoder->error;
+ break;
+ }
+
+ error = UpdateCodecState(decoder, input, segment);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Processed all wavelet bands in all channels?
+ if ( IsDecodingComplete(decoder) && codec->header == false ) {
+ break;
+ }
+ }
+
+ // Parsed the bitstream without errors?
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ TIMESTAMP("[END]", 2)
+
+ if( parameters->rgb_resolution == GPR_RGB_RESOLUTION_NONE ||
+ parameters->rgb_resolution == GPR_RGB_RESOLUTION_HALF ||
+ parameters->rgb_resolution == GPR_RGB_RESOLUTION_FULL )
+ {
+ // Reconstruct the output image using the last decoded wavelet in each channel
+ error = ReconstructUnpackedImage(decoder, image);
+ }
+
+ return error;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Set the channel dimensions from the image dimensions and format
+ This routine is used set the channel dimensions and other channel-specific
+ parameters after the bitstream header has been parsed. The dimensions of
+ each channel can only be set using the parameters present in the bitstream
+ header if the bitstream conforms to VC-5 Part 3.
+ */
+CODEC_ERROR SetImageChannelParameters(DECODER *decoder, int channel_number)
+{
+ CODEC_STATE *codec = &decoder->codec;
+ IMAGE_FORMAT image_format = codec->image_format;
+ DIMENSION image_width = codec->image_width;
+ DIMENSION image_height = codec->image_height;
+ DIMENSION pattern_width = codec->pattern_width;
+ DIMENSION pattern_height = codec->pattern_height;
+
+ // Are the image dimensions valid?
+ if (image_width == 0 || image_height == 0)
+ {
+ // Cannot set the channel dimensions without valid image dimensions
+ return CODEC_ERROR_IMAGE_DIMENSIONS;
+ }
+
+ // Are the pattern dimensions valid?
+ if (pattern_width == 0 || pattern_height == 0)
+ {
+ // The channel dimensions may depend on the pattern dimensions
+ return CODEC_ERROR_PATTERN_DIMENSIONS;
+ }
+
+ switch (image_format)
+ {
+ case IMAGE_FORMAT_RAW:
+ // The pattern width and height must be two
+ assert(pattern_width == 2 && pattern_height == 2);
+
+ // The image dimensions must be divisible by the pattern dimensions
+ //assert((image_width % 2) == 0 && (image_height % 2) == 0);
+
+ decoder->channel[channel_number].width = image_width / 2;
+ decoder->channel[channel_number].height = image_height / 2;
+ break;
+
+ default:
+ // Cannot set the channel dimensions without a valid image format
+ return CODEC_ERROR_BAD_IMAGE_FORMAT;
+ break;
+ }
+
+ //TODO: Is the default bits per component the correct value to use?
+ decoder->channel[channel_number].bits_per_component = codec->bits_per_component;
+ decoder->channel[channel_number].initialized = true;
+
+ return CODEC_ERROR_OKAY;
+}
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Allocate all of the wavelets used during decoding
+ This routine allocates all of the wavelets in the wavelet tree that
+ may be used during decoding.
+ This routine is used to preallocate the wavelets before decoding begins.
+ If the wavelet bands are allocated on demand if not preallocated.
+ By default, the wavelet bands are encoded into the bitstream with the bands
+ from the wavelet at the highest level (smallest wavelet) first so that the
+ bands can be processed by the decoder in the order as the sample is decoded.
+ */
+CODEC_ERROR AllocDecoderTransforms(DECODER *decoder)
+{
+ CODEC_ERROR result;
+ // Use the default allocator for the decoder
+
+ gpr_allocator *allocator = decoder->allocator;
+ int channel_number;
+ int wavelet_index;
+
+ int channel_count;
+ int wavelet_count;
+
+ assert(decoder != NULL);
+ if (! (decoder != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ channel_count = decoder->codec.channel_count;
+ wavelet_count = decoder->wavelet_count;
+
+ for (channel_number = 0; channel_number < channel_count; channel_number++)
+ {
+ DIMENSION wavelet_width;
+ DIMENSION wavelet_height;
+
+ // Set the channel dimensions using the information obtained from the bitstream header
+ result = SetImageChannelParameters(decoder, channel_number);
+ if( result != CODEC_ERROR_OKAY )
+ {
+ assert(0);
+ return result;
+ }
+
+ // Check that the channel dimensions and other parameters have been set
+ assert(decoder->channel[channel_number].initialized);
+
+ // The dimensions of the wavelet at level zero are equal to the channel dimensions
+ wavelet_width = decoder->channel[channel_number].width;
+ wavelet_height = decoder->channel[channel_number].height;
+
+ for (wavelet_index = 0; wavelet_index < wavelet_count; wavelet_index++)
+ {
+ WAVELET *wavelet;
+
+ // Pad the wavelet width if necessary
+ if ((wavelet_width % 2) != 0) {
+ wavelet_width++;
+ }
+
+ // Pad the wavelet height if necessary
+ if ((wavelet_height % 2) != 0) {
+ wavelet_height++;
+ }
+
+ // Dimensions of the current wavelet must be divisible by two
+ assert((wavelet_width % 2) == 0 && (wavelet_height % 2) == 0);
+
+ // Reduce the dimensions of the next wavelet by half
+ wavelet_width /= 2;
+ wavelet_height /= 2;
+
+ wavelet = CreateWavelet(allocator, wavelet_width, wavelet_height);
+ decoder->transform[channel_number].wavelet[wavelet_index] = wavelet;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+#endif
+
+/*!
+ @brief Free the wavelet transforms allocated by the decoder
+ */
+CODEC_ERROR ReleaseDecoderTransforms(DECODER *decoder)
+{
+ int channel_count = decoder->codec.channel_count;
+ int channel_index;
+
+ for (channel_index = 0; channel_index < channel_count; channel_index++)
+ {
+ int wavelet_index;
+
+ for (wavelet_index = 0; wavelet_index < decoder->wavelet_count; wavelet_index++)
+ {
+ WAVELET *wavelet = decoder->transform[channel_index].wavelet[wavelet_index];
+ DeleteWavelet(decoder->allocator, wavelet);
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Allocate all of the buffers required for decoding
+ This routine allocates buffers required for decoding, not including
+ the wavelet images in the wavelet tree which are allocated by
+ @ref AllocDecoderTransforms
+ This routine is used to preallocate buffers before decoding begins.
+ Decoding buffers are allocated on demand if not preallocated.
+ Currently, the reference decoder allocates scratch buffers as required
+ by each routine that needs scratch space and the scratch buffers are
+ deallocated at the end each routine that allocates scratch space.
+ @todo Should it be an error if the buffers are not preallocated?
+ */
+CODEC_ERROR AllocDecoderBuffers(DECODER *decoder)
+{
+ (void)decoder;
+ return CODEC_ERROR_UNIMPLEMENTED;
+}
+#endif
+
+/*!
+ @brief Free any buffers allocated by the decoder
+ */
+CODEC_ERROR ReleaseDecoderBuffers(DECODER *decoder)
+{
+ (void)decoder;
+ return CODEC_ERROR_UNIMPLEMENTED;
+}
+
+/*!
+ @brief Allocate the wavelets for the specified channel
+ */
+CODEC_ERROR AllocateChannelWavelets(DECODER *decoder, int channel_number)
+{
+ // Use the default allocator for the decoder
+ gpr_allocator *allocator = decoder->allocator;
+ int wavelet_index;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ // Use the channel dimensions computed from the image dimension and image format
+ DIMENSION channel_width = decoder->channel[channel_number].width;
+ DIMENSION channel_height = decoder->channel[channel_number].height;
+#else
+ // Use the channel dimensions from the current codec state
+ DIMENSION channel_width = decoder->codec.channel_width;
+ DIMENSION channel_height = decoder->codec.channel_height;
+#endif
+
+ // Round up the wavelet dimensions to an even number
+ DIMENSION wavelet_width = ((channel_width % 2) == 0) ? channel_width / 2 : (channel_width + 1) / 2;
+ DIMENSION wavelet_height = ((channel_height % 2) == 0) ? channel_height / 2 : (channel_height + 1) / 2;
+
+ //TODO: Check for errors before the code that initializes the local variables
+ assert(decoder != NULL);
+ if (! (decoder != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ for (wavelet_index = 0; wavelet_index < decoder->wavelet_count; wavelet_index++)
+ {
+ WAVELET *wavelet = decoder->transform[channel_number].wavelet[wavelet_index];
+
+ // Has a wavelet already been created?
+ if (wavelet != NULL)
+ {
+ // Is the wavelet the correct size?
+ if (wavelet_width != wavelet->width ||
+ wavelet_height != wavelet->height)
+ {
+ // Deallocate the wavelet
+ DeleteWavelet(allocator, wavelet);
+
+ wavelet = NULL;
+ }
+ }
+
+ if (wavelet == NULL)
+ {
+ wavelet = CreateWavelet(allocator, wavelet_width, wavelet_height);
+ assert(wavelet != NULL);
+
+ decoder->transform[channel_number].wavelet[wavelet_index] = wavelet;
+ }
+
+ // Pad the wavelet width if necessary
+ if ((wavelet_width % 2) != 0) {
+ wavelet_width++;
+ }
+
+ // Pad the wavelet height if necessary
+ if ((wavelet_height % 2) != 0) {
+ wavelet_height++;
+ }
+
+ // Dimensions of the current wavelet must be divisible by two
+ assert((wavelet_width % 2) == 0 && (wavelet_height % 2) == 0);
+
+ // Reduce the dimensions of the next wavelet by half
+ wavelet_width /= 2;
+ wavelet_height /= 2;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize the codec state before starting to decode a bitstream
+ */
+CODEC_ERROR PrepareDecoderState(DECODER *decoder, const DECODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &decoder->codec;
+
+ // Set the parameters that control the decoding process
+ decoder->wavelet_count = 3;
+
+ // The wavelets and decoding buffers have not been allocated
+ decoder->memory_allocated = false;
+
+ // Clear the table of information about each decoded channel
+ memset(decoder->channel, 0, sizeof(decoder->channel));
+
+ // Set the codebook
+ decoder->codebook = (CODEBOOK *)decoder_codeset_17.codebook;
+
+ // Initialize the codec state with the default parameter values
+ error = PrepareCodecState(codec);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Initialize the codec state with the external parameter values
+ codec->image_width = parameters->input.width;
+ codec->image_height = parameters->input.height;
+
+ //TODO: Initialize other parameters with external values?
+
+ // The default channel dimensions are the image dimensions
+ codec->channel_width = codec->image_width;
+ codec->channel_height = codec->image_height;
+
+ return error;
+}
+
+/*!
+ @brief Prepare the decoder transforms for the next layer
+ Each wavelet in the decoder transforms contain flags that indicate
+ whether the wavelet bands must be decoded. These flags must be reset
+ before decoding the next layer.
+ */
+CODEC_ERROR PrepareDecoderTransforms(DECODER *decoder)
+{
+ int channel_count = decoder->codec.channel_count;
+ int channel_index;
+
+ for (channel_index = 0; channel_index < channel_count; channel_index++)
+ {
+ int wavelet_count = decoder->wavelet_count;
+ int wavelet_index;
+
+ for (wavelet_index = 0; wavelet_index < wavelet_count; wavelet_index++)
+ {
+ WAVELET *wavelet = decoder->transform[channel_index].wavelet[wavelet_index];
+ wavelet->valid_band_mask = 0;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Pack the component arrays into the output image
+
+ The decoding process outputs a set of component arrays that does not correspond
+ to any common image format. The image repacking process converts the ordered
+ set of component arrays output by the decoding processing into a packed image.
+ The image repacking process is not normative in VC-5 Part 1.
+ */
+CODEC_ERROR ImageRepackingProcess(const UNPACKED_IMAGE *unpacked_image,
+ PACKED_IMAGE *packed_image,
+ const DECODER_PARAMETERS *parameters)
+{
+ DIMENSION output_width = packed_image->width;
+ DIMENSION output_height = packed_image->height;
+ size_t output_pitch = packed_image->pitch;
+ PIXEL_FORMAT output_format = packed_image->format;
+ PIXEL *output_buffer = packed_image->buffer;
+ ENABLED_PARTS enabled_parts = parameters->enabled_parts;
+
+ (void)parameters;
+
+ // The dimensions must be in units of Bayer pattern elements
+ output_width /= 2;
+ output_height /= 2;
+ output_pitch *= 2;
+
+ switch (output_format)
+ {
+ case PIXEL_FORMAT_RAW_RGGB_12:
+ case PIXEL_FORMAT_RAW_GBRG_12:
+ return PackComponentsToRAW(unpacked_image, output_buffer, output_pitch,
+ output_width, output_height, enabled_parts, 12, output_format );
+
+ case PIXEL_FORMAT_RAW_RGGB_14:
+ case PIXEL_FORMAT_RAW_GBRG_14:
+ return PackComponentsToRAW(unpacked_image, output_buffer, output_pitch,
+ output_width, output_height, enabled_parts, 14, output_format );
+ break;
+
+ case PIXEL_FORMAT_RAW_RGGB_16:
+ return PackComponentsToRAW(unpacked_image, output_buffer, output_pitch,
+ output_width, output_height, enabled_parts, 16, output_format );
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ // Unsupported output image format
+ return CODEC_ERROR_UNSUPPORTED_FORMAT;
+}
+
+/*!
+ @brief Compute default parameters for the repacked image
+ */
+CODEC_ERROR SetOutputImageFormat(DECODER *decoder,
+ const DECODER_PARAMETERS *parameters,
+ DIMENSION *width_out,
+ DIMENSION *height_out,
+ PIXEL_FORMAT *format_out)
+{
+ // The image dimensions are in units of samples
+ DIMENSION output_width = decoder->codec.image_width;
+ DIMENSION output_height = decoder->codec.image_height;
+
+ PIXEL_FORMAT output_format = PIXEL_FORMAT_UNKNOWN;
+
+ // Override the pixel format with the format passed as a parameter
+ if (parameters->output.format != PIXEL_FORMAT_UNKNOWN) {
+ output_format = parameters->output.format;
+ }
+ assert(output_format != PIXEL_FORMAT_UNKNOWN);
+
+ if (width_out != NULL) {
+ *width_out = output_width;
+ }
+
+ if (height_out != NULL) {
+ *height_out = output_height;
+ }
+
+ if (format_out != NULL) {
+ *format_out = output_format;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return true if the lowpass bands in all channels are valid
+ */
+bool ChannelLowpassBandsAllValid(const DECODER *decoder, int index)
+{
+ int channel_count = decoder->codec.channel_count;
+ int channel;
+ for (channel = 0; channel < channel_count; channel++)
+ {
+ WAVELET *wavelet = decoder->transform[channel].wavelet[index];
+ if ((wavelet->valid_band_mask & BandValidMask(0)) == 0) {
+ return false;
+ }
+ }
+
+ // All channels have valid lowpass bands at the specified level
+ return true;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+
+/*
+ @brief Return true if the tag identifies a section header
+ */
+bool IsSectionHeader(TAGWORD tag)
+{
+ switch (tag)
+ {
+ case CODEC_TAG_ImageSectionTag:
+ case CODEC_TAG_HeaderSectionTag:
+ case CODEC_TAG_LayerSectionTag:
+ case CODEC_TAG_ChannelSectionTag:
+ case CODEC_TAG_WaveletSectionTag:
+ case CODEC_TAG_SubbandSectionTag:
+ return true;
+
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+/*
+ @brief Map the tag for a section header to the section number
+ */
+CODEC_ERROR GetSectionNumber(TAGWORD tag, int *section_number_out)
+{
+ int section_number = 0;
+
+ switch (tag)
+ {
+ case CODEC_TAG_ImageSectionTag:
+ section_number = 1;
+ break;
+
+ case CODEC_TAG_HeaderSectionTag:
+ section_number = 2;
+ break;
+
+ case CODEC_TAG_LayerSectionTag:
+ section_number = 3;
+ break;
+
+ case CODEC_TAG_ChannelSectionTag:
+ section_number = 4;
+ break;
+
+ case CODEC_TAG_WaveletSectionTag:
+ section_number = 5;
+ break;
+
+ case CODEC_TAG_SubbandSectionTag:
+ section_number = 6;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ if (section_number_out != NULL) {
+ *section_number_out = section_number;
+ }
+
+ if (section_number > 0) {
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_BAD_SECTION_TAG;
+}
+
+/*!
+ @brief Write section information to the section log file
+ */
+CODEC_ERROR WriteSectionInformation(FILE *logfile, int section_number, int section_length)
+{
+ fprintf(logfile, "Section: %d, length: %d\n", section_number, section_length);
+ return CODEC_ERROR_OKAY;
+}
+
+#endif
+
+/*!
+ @brief Skip the payload in a chunk
+
+ A chunk is a tag value pair where the value specifies the length
+ of a payload. If the tag is a negative number, then the payload
+ can be skipped without affecting the decoding process.
+ */
+static CODEC_ERROR SkipPayload(BITSTREAM *bitstream, int chunk_size)
+{
+ // The chunk size is in units of 32-bit words
+ size_t size = 4 * chunk_size;
+
+ // This routine assumes that the bit buffer is empty
+ assert(bitstream->count == 0);
+
+ // Skip the specified number of bytes in the stream
+ return SkipBytes(bitstream->stream, size);
+}
+
+/*!
+ @brief Parse the unique image identifier in a small chunk payload
+
+ @todo Should the UMID instance number be a parameter to this routine?
+ */
+static CODEC_ERROR ParseUniqueImageIdentifier(DECODER *decoder, BITSTREAM *stream, size_t identifier_length)
+{
+ const int UMID_length_byte = 0x13;
+ const int UMID_instance_number = 0;
+
+ // Total length of the unique image identifier chunk payload (in segments)
+ const int identifier_chunk_payload_length = UMID_length + sequence_number_length;
+
+ uint8_t byte_array[12];
+ BITWORD length_byte;
+ BITWORD instance_number;
+
+ // Check that the chunk payload has the correct length (in segments)
+ if (identifier_length != identifier_chunk_payload_length) {
+ return CODEC_ERROR_SYNTAX_ERROR;
+ }
+
+ // The unique image identifier chunk should begin with a UMID label
+ GetByteArray(stream, byte_array, sizeof(byte_array));
+ if (memcmp(byte_array, UMID_label, sizeof(UMID_label)) != 0) {
+ return CODEC_ERROR_UMID_LABEL;
+ }
+
+ // Check the UMID length byte
+ length_byte = GetBits(stream, 8);
+ if (length_byte != UMID_length_byte) {
+ return CODEC_ERROR_SYNTAX_ERROR;
+ }
+
+ // Check the UMID instance number
+ instance_number = GetBits(stream, 24);
+ if (instance_number != UMID_instance_number) {
+ return CODEC_ERROR_SYNTAX_ERROR;
+ }
+
+ // Read the image sequence identifier
+ GetByteArray(stream, decoder->image_sequence_identifier, sizeof(decoder->image_sequence_identifier));
+
+ // Read the image sequence number
+ decoder->image_sequence_number = GetBits(stream, 32);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Update the codec state with the specified tag value pair
+ When a segment (tag value pair) is encountered in the bitstream of an
+ encoded sample, it may imply some change in the codec state. For example,
+ when a tag for the encoded format is read from the bitstream, the encoded
+ format entry in the codec state may change.
+ Some tags require that additional information must be read from the
+ bitstream and more segments may be encountered, leading to additional
+ changes in the codec state.
+ A tag may identify a single parameter and the parameter value must be updated
+ in the codec state with the new value specified in the segment, but a tag may
+ also imply that other pparameter values must be updated. For example, the tag
+ that marks the first encounter with a wavelet at a lower level in the wavelet
+ tree implies that the width and height of wavelet bands that may be encoded in
+ the remainder of the sample must be doubled.
+
+ It is not necessary for the encoder to insert segments into the bitstream if the
+ codec state change represented by an encoded tag and value can be deduced from
+ earlier segments in the bitstream and the codec state can be changed at a time
+ during decoding that is functionally the same as when the state change would have
+ been performed by an explicitly encoded tag and value.
+ @todo Need to check that parameters found in the sample are consistent with
+ the decoding parameters used to initialize the codec state.
+ */
+CODEC_ERROR UpdateCodecState(DECODER *decoder, BITSTREAM *stream, TAGVALUE segment)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &decoder->codec;
+ ENABLED_PARTS enabled_parts = decoder->enabled_parts;
+ bool optional = false;
+ int chunk_size = 0;
+ TAGWORD tag = segment.tuple.tag;
+ TAGWORD value = segment.tuple.value;
+
+ // The enabled parts variable may not be used depending on the compile-time options
+ (void)enabled_parts;
+
+ // Assume that the next syntax element is not a tag-value pair for a header parameter
+ codec->header = false;
+
+ // Assume that the next syntax element is not a codeblock (large chunk element)
+ codec->codeblock = false;
+
+ // Is this an optional tag?
+ if (tag < 0) {
+ tag = RequiredTag(tag);
+ optional = true;
+ }
+
+ switch (tag)
+ {
+ case CODEC_TAG_ChannelCount: // Number of channels in the transform
+ assert(0 < value && value <= MAX_CHANNEL_COUNT);
+ codec->channel_count = (uint_least8_t)value;
+ codec->header = true;
+ break;
+
+ case CODEC_TAG_ImageWidth: // Width of the image
+ codec->image_width = value;
+ codec->header = true;
+
+ // The image width is the default width of the next channel in the bitstream
+ codec->channel_width = value;
+ break;
+
+ case CODEC_TAG_ImageHeight: // Height of the image
+ codec->image_height = value;
+ codec->header = true;
+
+ // The image height is the default height of the next channel in the bitstream
+ codec->channel_height = value;
+ break;
+
+ case CODEC_TAG_SubbandNumber: // Subband number of this wavelet band
+ codec->subband_number = value;
+ break;
+
+ case CODEC_TAG_Quantization: // Quantization applied to band
+ codec->band.quantization = value;
+ break;
+
+ case CODEC_TAG_LowpassPrecision: // Number of bits per lowpass coefficient
+ if (! (PRECISION_MIN <= value && value <= PRECISION_MAX)) {
+ return CODEC_ERROR_LOWPASS_PRECISION;
+ }
+ codec->lowpass_precision = (PRECISION)value;
+ break;
+
+ case CODEC_TAG_ChannelNumber: // Channel number
+ codec->channel_number = value;
+ break;
+
+ case CODEC_TAG_BitsPerComponent: // Number of bits in the video source
+ codec->bits_per_component = (PRECISION)value;
+ //error = SetDecoderBitsPerComponent(decoder, codec->channel_number, codec->bits_per_component);
+ break;
+
+ case CODEC_TAG_PrescaleShift:
+ UpdatePrescaleTable(codec, value);
+ break;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_ImageFormat:
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ codec->image_format = (IMAGE_FORMAT)value;
+ codec->header = true;
+ }
+ else
+ {
+ // The image format shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ break;
+
+ case CODEC_TAG_PatternWidth:
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ codec->pattern_width = (DIMENSION)value;
+ codec->header = true;
+ }
+ else
+ {
+ // The pattern width shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ break;
+
+ case CODEC_TAG_PatternHeight:
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ codec->pattern_height = (DIMENSION)value;
+ codec->header = true;
+ }
+ else
+ {
+ // The pattern height shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ break;
+
+ case CODEC_TAG_ComponentsPerSample:
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ codec->components_per_sample = (DIMENSION)value;
+ codec->header = true;
+ }
+ else
+ {
+ // The components per sample shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ break;
+
+ case CODEC_TAG_MaxBitsPerComponent:
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ codec->max_bits_per_component = (PRECISION)value;
+ codec->header = true;
+ }
+ else
+ {
+ // The components per sample shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ break;
+#endif
+
+ case CODEC_TAG_ChannelWidth:
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ // The channel width shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ else
+#endif
+ {
+ // The channel width may be present in the bitstream
+ codec->channel_width = (DIMENSION)value;
+ }
+ break;
+
+ case CODEC_TAG_ChannelHeight:
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ // The channel height shall not be present in the bitstream
+ assert(0);
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ else
+#endif
+ {
+ // The channel height may be present in the bitstream
+ codec->channel_height = (DIMENSION)value;
+ }
+ break;
+
+ default: // Unknown tag or the tag identifies a chunk
+
+ //TODO: Check for chunk tags that are not defined in VC-5 Part 1
+
+ // Does this tag indicate a chunk of data?
+ if (tag & CODEC_TAG_CHUNK_MASK)
+ {
+ // Does this chunk have a 24-bit size?
+ if(tag & CODEC_TAG_LARGE_CHUNK)
+ {
+ // The chunk size includes the low byte in the tag
+ chunk_size = (value & 0xFFFF);
+ chunk_size += ((tag & 0xFF) << 16);
+ }
+ else
+ {
+ // The chunk size is specified by the value
+ chunk_size = (value & 0xFFFF);
+ }
+ }
+
+ // Is this a codeblock?
+ if ((tag & CODEC_TAG_LargeCodeblock) == CODEC_TAG_LargeCodeblock)
+ {
+ codec->codeblock = true;
+ }
+
+ // Is this chunk a unique image identifier?
+ else if (tag == CODEC_TAG_UniqueImageIdentifier)
+ {
+ // The unique image identifier should be optional
+ assert(optional);
+ if (! optional) {
+ return CODEC_ERROR_SYNTAX_ERROR;
+ }
+
+ // Parse the unique image identifier
+ error = ParseUniqueImageIdentifier(decoder, stream, chunk_size);
+ }
+
+ // Is this chunk an inverse component transform?
+ else if (tag == CODEC_TAG_InverseTransform)
+ {
+ // The inverse component transform should not be optional
+ assert(!optional);
+ if (optional) {
+ return CODEC_ERROR_SYNTAX_ERROR;
+ }
+
+ // Parse the inverse component transform
+ error = ParseInverseComponentTransform(decoder, stream, chunk_size);
+ }
+
+ // Is this chunk an inverse component permutation?
+ else if (tag == CODEC_TAG_InversePermutation)
+ {
+ // The inverse component permutation should not be optional
+ assert(!optional);
+ if (optional) {
+ return CODEC_ERROR_SYNTAX_ERROR;
+ }
+
+ // Parse the inverse component permutation
+ error = ParseInverseComponentPermutation(decoder, stream, chunk_size);
+ }
+
+ // Is this chunk a 16-bit inverse component transform?
+ else if (tag == CODEC_TAG_InverseTransform16)
+ {
+ // The 16-bit inverse component transform is not supported
+ assert(0);
+ return CODEC_ERROR_UNIMPLEMENTED;
+ }
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ // Is this a section header?
+ else if (IsPartEnabled(enabled_parts, VC5_PART_SECTIONS) && decoder->section_flag && IsSectionHeader(tag))
+ {
+ int section_number;
+
+ // Section headers are optional tag-value pairs
+ optional = true;
+
+ // Is this a bitstream header section?
+ if (tag == CODEC_TAG_HeaderSectionTag)
+ {
+ // Handle this tag-value pair as if it was a bitstream header parameter
+ codec->header = true;
+ }
+
+ // Convert the tag to a section number
+ GetSectionNumber(tag, &section_number);
+
+ // Record the section number and length (in segments)
+ codec->section_number = section_number;
+ codec->section_length = chunk_size;
+
+ if( decoder->section_logfile )
+ {
+ // Write the section information to the log file
+ WriteSectionInformation(decoder->section_logfile, section_number, chunk_size);
+ }
+ }
+#endif
+ else
+ {
+ // Does this chunk have a 24-bit chunk payload size?
+ if (tag & CODEC_TAG_LARGE_CHUNK)
+ {
+ optional = true;
+ chunk_size = 0;
+ }
+
+ assert(optional);
+ if (!optional)
+ {
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ else if (chunk_size > 0)
+ {
+ // Skip processing the payload of this optional chunk element
+ SkipPayload(stream, chunk_size);
+ }
+ }
+ break;
+ }
+
+ // Encountered an error while processing the tag?
+ if (error != CODEC_ERROR_OKAY)
+ {
+ return error;
+ }
+
+ //TODO: Check that bitstreams with missplaced header parameters fail to decode
+
+ //if (IsHeaderParameter(tag))
+ if (codec->header)
+ {
+ if (optional)
+ {
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (tag == CODEC_TAG_HeaderSectionTag)
+ {
+ // Okay for the bitstream header to contain an optional section header tag-value pair
+ }
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ else if (!IsPartEnabled(enabled_parts, VC5_PART_LAYERS))
+ {
+ // A header parameter cannot be optional
+ error = CODEC_ERROR_REQUIRED_PARAMETER;
+ }
+#endif
+#endif
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ if (!IsPartEnabled(enabled_parts, VC5_PART_LAYERS))
+ {
+ // A header parameter cannot be optional
+ error = CODEC_ERROR_REQUIRED_PARAMETER;
+ }
+#endif
+ }
+ else if (decoder->header_finished)
+ {
+ // Should not encounter a header parameter after the header has been parsed
+ error = CODEC_ERROR_BITSTREAM_SYNTAX;
+ }
+ else
+ {
+ // Record that this header parameter has been decoded
+ error = UpdateHeaderParameter(decoder, tag);
+ }
+ }
+ else if (!decoder->header_finished)
+ {
+ // There should be no more header parameters in the bitstream
+ decoder->header_finished = true;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ // The wavelets and buffers can be allocated after the bitstream header has been parsed
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS) &&
+ decoder->header_finished &&
+ !decoder->memory_allocated)
+ {
+ // Allocate space for the wavelet transforms
+ AllocDecoderTransforms(decoder);
+
+ // Allocate all buffers required for decoding
+ AllocDecoderBuffers(decoder);
+
+ // Reset the flags in the wavelet transforms
+ PrepareDecoderTransforms(decoder);
+
+ // The wavelet transforms and decoding buffers have been allocated
+ decoder->memory_allocated = true;
+ }
+#endif
+
+ // Found a codeblock element?
+ if (codec->codeblock)
+ {
+ const int channel_number = codec->channel_number;
+
+ // Have the channel dimensions been initialized?
+ if (!decoder->channel[channel_number].initialized)
+ {
+ // Record the channel dimensions and component precision
+ decoder->channel[channel_number].width = codec->channel_width;
+ decoder->channel[channel_number].height = codec->channel_height;
+
+ // Initialize the dimensions of this channel
+ decoder->channel[channel_number].initialized = true;
+
+ //TODO: Allocate space for the wavelet transforms and decoding buffers
+ }
+
+ // Is this the first codeblock encountered in the bitstream for this channel?
+ if (!decoder->channel[channel_number].found_first_codeblock)
+ {
+ // Remember the number of bits per component in this and higher numbered channel
+ decoder->channel[codec->channel_number].bits_per_component = codec->bits_per_component;
+
+ // Found the first codeblock in the channel
+ decoder->channel[channel_number].found_first_codeblock = true;
+ }
+
+ {
+ CODEC_STATE *codec = &decoder->codec;
+
+ const int subband_number = codec->subband_number;
+
+ if( subband_number < decoder->subbands_to_decode )
+ {
+ // Decode the subband into its wavelet band
+ error = DecodeChannelSubband(decoder, stream, chunk_size);
+ }
+ else
+ {
+ // Skip decoding of subband
+ error = SkipPayload(stream, chunk_size);
+
+ WAVELET* wavelet = decoder->transform[channel_number].wavelet[SubbandWaveletIndex(subband_number)];
+ wavelet->valid_band_mask = 0xF;
+ }
+
+ // Set the subband number for the next band expected in the bitstream
+ codec->subband_number++;
+
+ // Was the subband successfully decoded?
+ if (error == CODEC_ERROR_OKAY)
+ {
+ // Record that this subband has been decoded successfully
+ SetDecodedBandMask(codec, subband_number);
+ }
+
+ // Done decoding all subbands in this channel?
+ if (codec->subband_number == codec->subband_count)
+ {
+ // Advance to the next channel
+ codec->channel_number++;
+
+ // Reset the subband number
+ codec->subband_number = 0;
+ }
+ }
+
+ }
+
+ return error;
+}
+
+/*!
+ @brief Return true if the tag corresponds to a bitstream header parameter
+ */
+bool IsHeaderParameter(TAGWORD tag)
+{
+ switch (tag)
+ {
+ case CODEC_TAG_ImageWidth:
+ case CODEC_TAG_ImageHeight:
+ case CODEC_TAG_ChannelCount:
+ case CODEC_TAG_SubbandCount:
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_ImageFormat:
+ case CODEC_TAG_PatternWidth:
+ case CODEC_TAG_PatternHeight:
+ case CODEC_TAG_ComponentsPerSample:
+ case CODEC_TAG_MaxBitsPerComponent:
+#endif
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/*!
+ @brief Return the header mask that corresponds to the header tag
+ */
+uint16_t GetHeaderMask(TAGWORD tag)
+{
+ uint16_t header_mask = 0;
+
+ switch (tag)
+ {
+ case CODEC_TAG_ImageWidth:
+ header_mask = BITSTREAM_HEADER_FLAGS_IMAGE_WIDTH;
+ break;
+
+ case CODEC_TAG_ImageHeight:
+ header_mask = BITSTREAM_HEADER_FLAGS_IMAGE_HEIGHT;
+ break;
+
+ case CODEC_TAG_ChannelCount:
+ header_mask = BITSTREAM_HEADER_FLAGS_CHANNEL_COUNT;
+ break;
+
+ case CODEC_TAG_SubbandCount:
+ header_mask = BITSTREAM_HEADER_FLAGS_SUBBAND_COUNT;
+ break;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_ImageFormat:
+ header_mask = BITSTREAM_HEADER_FLAGS_IMAGE_FORMAT;
+ break;
+#endif
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_PatternWidth:
+ header_mask = BITSTREAM_HEADER_FLAGS_PATTERN_WIDTH;
+ break;
+#endif
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_PatternHeight:
+ header_mask = BITSTREAM_HEADER_FLAGS_PATTERN_HEIGHT;
+ break;
+#endif
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_ComponentsPerSample:
+ header_mask = BITSTREAM_HEADER_FLAGS_COMPONENTS_PER_SAMPLE;
+ break;
+#endif
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ case CODEC_TAG_MaxBitsPerComponent:
+ header_mask = BITSTREAM_HEADER_FLAGS_MAX_BITS_PER_COMPONENT;
+ break;
+#endif
+
+ default:
+ assert(0);
+ break;
+ }
+
+ return header_mask;
+}
+
+/*!
+ @brief Record that a header parameter was found in the bitstream.
+ The tag-value pair that corresponds to a header parameters must occur
+ in the bitstream header and must occur at most once in the bitstream.
+ */
+CODEC_ERROR UpdateHeaderParameter(DECODER *decoder, TAGWORD tag)
+{
+ uint16_t header_mask = 0;
+
+ if (!IsHeaderParameter(tag)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ header_mask = GetHeaderMask(tag);
+
+ if (header_mask == 0) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ if (decoder->header_mask & header_mask) {
+ // The header parameter should occur at most once
+ return CODEC_ERROR_DUPLICATE_HEADER_PARAMETER;
+ }
+
+ // Record this encounter with the header parameter
+ decoder->header_mask |= header_mask;
+
+ return CODEC_ERROR_OKAY;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING)
+/*!
+ @brief Adjust the width of the layer (if necessary)
+ Note that all layers have the same dimensions so the layer index is not
+ passed as an argument to this routine.
+ All layers have the same width as the encoded width.
+ */
+DIMENSION LayerWidth(DECODER *decoder, DIMENSION width)
+{
+ //CODEC_STATE *codec = &decoder->codec;
+ (void)decoder;
+ return width;
+}
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING)
+/*!
+ @brief Adjust the height of the layer to account for interlaced frames
+ Note that all layers have the same dimensions so the layer index is not
+ passed as an argument to this routine.
+ */
+DIMENSION LayerHeight(DECODER *decoder, DIMENSION height)
+{
+ CODEC_STATE *codec = &decoder->codec;
+
+ if (codec->progressive == 0)
+ {
+ height /= 2;
+ }
+
+ return height;
+}
+#endif
+
+/*!
+ @brief Decode the specified wavelet subband
+ After decoded the specified subband, the routine checks whether all bands
+ in the current wavelet have been decoded and if so the inverse transform is
+ applied to the wavelet to reconstruct the lowpass band in the wavelet at the
+ next lower level.
+ */
+CODEC_ERROR DecodeChannelSubband(DECODER *decoder, BITSTREAM *input, size_t chunk_size)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &decoder->codec;
+
+ const int channel_number = codec->channel_number;
+ const int subband_number = codec->subband_number;
+
+ // Get the index to the wavelet corresponding to this subband
+ const int index = SubbandWaveletIndex(subband_number);
+
+ // Get the index of the wavelet band corresponding to this subband
+ const int band = SubbandBandIndex(subband_number);
+
+ // Wavelet containing the band to decode
+ WAVELET *wavelet = NULL;
+
+ //TODO: Need to check that the codeblock matches the chunk size
+ (void)chunk_size;
+
+ // Allocate the wavelets for this channel if not already allocated
+ AllocateChannelWavelets(decoder, channel_number);
+
+ // Is this a highpass band?
+ if (subband_number > 0)
+ {
+ // Decode a highpass band
+
+ // Get the wavelet that contains the highpass band
+ wavelet = decoder->transform[channel_number].wavelet[index];
+
+ // The wavelets are preallocated
+ assert(wavelet != NULL);
+
+ error = DecodeHighpassBand(decoder, input, wavelet, band);
+ if (error == CODEC_ERROR_OKAY)
+ {
+ // Update the wavelet band valid flags
+ UpdateWaveletValidBandMask(wavelet, band);
+ }
+
+ // Save the quantization factor
+ wavelet->quant[band] = codec->band.quantization;
+ }
+ else
+ {
+ // Decode a lowpass band
+
+ // Get the wavelet that contains the lowpass band
+ wavelet = decoder->transform[channel_number].wavelet[index];
+
+ // The lowpass band must be subband zero
+ assert(subband_number == 0);
+
+ // The lowpass data is always stored in wavelet band zero
+ assert(band == 0);
+
+ // The wavelets are preallocated
+ assert(wavelet != NULL);
+
+ error = DecodeLowpassBand(decoder, input, wavelet);
+ if (error == CODEC_ERROR_OKAY)
+ {
+ // Update the wavelet band valid flags
+ UpdateWaveletValidBandMask(wavelet, band);
+ }
+ }
+
+ // Ready to invert this wavelet to get the lowpass band in the lower wavelet?
+ if (BandsAllValid(wavelet))
+ {
+ // Apply the inverse wavelet transform to reconstruct the lower level wavelet
+ error = ReconstructWaveletBand(decoder, channel_number, wavelet, index);
+ }
+
+ return error;
+}
+
+/*!
+ @brief Invert the wavelet to reconstruct a lowpass band
+ The bands in the wavelet at one level are used to compute the lowpass
+ band in the wavelet at the next lower level in the transform. Wavelet
+ levels are numbered starting at zero for the original image. The
+ reference codec for the baseline profile uses the classic wavelet
+ tree where each wavelet at a high level depends only on the wavelet
+ at the next lower level and each wavelet is a spatial wavelet with
+ four bands.
+ This routine is called during decoding after all bands in a wavelet
+ have been decoded and the lowpass band in the wavelet at the next
+ lower level can be computed by applying the inverse wavelet transform.
+ This routine is not called for the wavelet at level one to reconstruct the
+ decoded component arrays. Special routines are used to compute each component
+ array using the wavelet at level one in each channel.
+
+ See @ref ReconstructUnpackedImage.
+ */
+CODEC_ERROR ReconstructWaveletBand(DECODER *decoder, int channel, WAVELET *wavelet, int index)
+{
+ PRESCALE prescale = decoder->codec.prescale_table[index];
+
+ // Is the current wavelet at a higher level than wavelet level one?
+ if (index > 0)
+ {
+ // Reconstruct the lowpass band in the lower wavelet
+ const int lowpass_index = index - 1;
+ WAVELET *lowpass;
+ int lowpass_width;
+ int lowpass_height;
+
+ lowpass = decoder->transform[channel].wavelet[lowpass_index];
+ assert(lowpass != NULL);
+ if (! (lowpass != NULL)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ lowpass_width = lowpass->width;
+ lowpass_height = lowpass->height;
+
+ // Check that the reconstructed wavelet is valid
+ if( lowpass_width <= 0 || lowpass_height <= 0 )
+ {
+ assert(false);
+ return CODEC_ERROR_IMAGE_DIMENSIONS;
+ }
+
+ // Check that the lowpass band has not already been reconstructed
+ assert((lowpass->valid_band_mask & BandValidMask(0)) == 0);
+
+ // Check that all of the wavelet bands have been decoded
+ assert(BandsAllValid(wavelet));
+
+ // Decode the lowpass band in the wavelet one lower level than the input wavelet
+ TransformInverseSpatialQuantLowpass(decoder->allocator, wavelet, lowpass, prescale);
+
+ // Update the band valid flags
+ UpdateWaveletValidBandMask(lowpass, 0);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Set the bit for the specified subband in the decoded band mask
+ The decoded subband mask is used to track which subbands have been
+ decoded in the current channel. It is reset at the start of each
+ channel.
+ */
+CODEC_ERROR SetDecodedBandMask(CODEC_STATE *codec, int subband)
+{
+ if (0 <= subband && subband < MAX_SUBBAND_COUNT) {
+ codec->decoded_subband_mask |= (1 << subband);
+ }
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Decoded the lowpass band from the bitstream
+ The wavelet at the highest level is passes as an argument.
+ This routine decodes lowpass band in the bitstream into the
+ lowpass band of the wavelet.
+ */
+CODEC_ERROR DecodeLowpassBand(DECODER *decoder, BITSTREAM *stream, WAVELET *wavelet)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &decoder->codec;
+
+ int lowpass_band_width; // Lowpass band dimensions
+ int lowpass_band_height;
+ int lowpass_band_pitch;
+ PIXEL *lowpass_band_ptr; // Pointer into the lowpass band
+
+ PRECISION lowpass_precision; // Number of bits per lowpass coefficient
+
+ int row, column;
+
+ lowpass_band_width = wavelet->width;
+ lowpass_band_height = wavelet->height;
+ lowpass_band_pitch = wavelet->pitch/sizeof(PIXEL);
+ lowpass_band_ptr = wavelet->data[0];
+
+ lowpass_precision = codec->lowpass_precision;
+
+ // Decode each row in the lowpass image
+ for (row = 0; row < lowpass_band_height; row++)
+ {
+ for (column = 0; column < lowpass_band_width; column++)
+ {
+ COEFFICIENT lowpass_value = (COEFFICIENT)GetBits(stream, lowpass_precision);
+ //assert(0 <= lowpass_value && lowpass_value <= COEFFICIENT_MAX);
+
+ //if (lowpass_value > COEFFICIENT_MAX) {
+ // lowpass_value = COEFFICIENT_MAX;
+ //}
+
+ lowpass_band_ptr[column] = lowpass_value;
+ }
+
+ // Advance to the next row in the lowpass image
+ lowpass_band_ptr += lowpass_band_pitch;
+ }
+ // Align the bitstream to the next tag value pair
+ AlignBitsSegment(stream);
+
+ // Return indication of lowpass decoding success
+ return error;
+}
+
+/*!
+ @brief Decode the highpass band from the bitstream
+ The specified wavelet band is decoded from the bitstream
+ using the codebook and encoding method specified in the
+ bitstream.
+ */
+CODEC_ERROR DecodeHighpassBand(DECODER *decoder, BITSTREAM *stream, WAVELET *wavelet, int band)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Get the highpass band dimensions
+ DIMENSION width = wavelet->width; //codec->band.width;
+ DIMENSION height = wavelet->height; //codec->band.height;
+
+ // Check that the band index is in range
+ assert(0 <= band && band < wavelet->band_count);
+
+ // Encoded coefficients start on a tag boundary
+ AlignBitsSegment(stream);
+
+ // Decode this subband
+ error = DecodeBandRuns(stream, decoder->codebook, wavelet->data[band], width, height, wavelet->pitch);
+ assert(error == CODEC_ERROR_OKAY);
+
+ // Return failure if a problem was encountered while reading the band coefficients
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // The encoded band coefficients end on a bitstream word boundary
+ // to avoid interference with the marker for the coefficient band trailer
+ AlignBitsWord(stream);
+
+ // Decode the band trailer
+ error = DecodeBandTrailer(stream);
+ decoder->error = error;
+ assert(error == CODEC_ERROR_OKAY);
+ return error;
+}
+
+/*!
+ @brief Decode the highpass band from the bitstream
+ The highpass band in the bitstream is decoded using the specified
+ codebook. This routine assumes that the highpass band was encoded
+ using the run lengths encoding method which is the default for all
+ current codec implementations.
+ The encoded highpass band consists of signed values and runs of zeros.
+ Each codebook entry specifies either an unsigned magnitude with a run
+ length of one or a run of zeros. The unsigned magnitude is immediately
+ followed by the sign bit.
+ Unsigned magnitudes always have a run length of one.
+ Note that runs of zeros can straddle end of line boundaries.
+ The end of the highpass band is marked by a special codeword.
+ Special codewords in the codebook have a run length of zero.
+ The value indicates the type or purpose of the special codeword.
+ */
+CODEC_ERROR DecodeBandRuns(BITSTREAM *stream, CODEBOOK *codebook, PIXEL *data,
+ DIMENSION width, DIMENSION height, DIMENSION pitch)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ size_t data_count;
+ size_t row_padding;
+ int row = 0;
+ int column = 0;
+ int index = 0;
+ //BITWORD special;
+ RUN run = RUN_INITIALIZER;
+
+ // Convert the pitch to units of pixels
+ pitch /= sizeof(PIXEL);
+
+ // Check that the band dimensions are reasonable
+ assert(width <= pitch);
+
+ // Compute the number of pixels encoded into the band
+ data_count = height * width;
+ row_padding = pitch - width;
+
+ while (data_count > 0)
+ {
+ // Get the next run length and value
+ error = GetRun(stream, codebook, &run);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Check that the run does not extend past the end of the band
+ assert(run.count <= data_count);
+
+ // Copy the value into the specified number of pixels in the band
+ while (run.count > 0)
+ {
+ // Reached the end of the column?
+ if (column == width)
+ {
+ // Need to pad the end of the row?
+ if (row_padding > 0)
+ {
+ int count;
+ for (count = 0; (size_t)count < row_padding; count++) {
+ data[index++] = 0;
+ }
+ }
+
+ // Advance to the next row
+ row++;
+ column = 0;
+ }
+
+ data[index++] = (PIXEL)run.value;
+ column++;
+ run.count--;
+ data_count--;
+ }
+ }
+
+ // The last run should have ended at the end of the band
+ assert(data_count == 0 && run.count == 0);
+
+ // Check for the special codeword that marks the end of the highpass band
+ error = GetRlv(stream, codebook, &run);
+ if (error == CODEC_ERROR_OKAY) {
+ if (! (run.count == 0 || run.value == SPECIAL_MARKER_BAND_END)) {
+ error = CODEC_ERROR_BAND_END_MARKER;
+ }
+ }
+
+ return error;
+}
+
+/*!
+ @brief Decode the band trailer that follows a highpass band
+ This routine aligns the bitstream to a tag value boundary.
+ Currently the band trailer does not perform any function beyond
+ preparing the bitstream for reading the next tag value pair.
+ */
+CODEC_ERROR DecodeBandTrailer(BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Advance the bitstream to a tag boundary
+ AlignBitsSegment(stream);
+
+ return error;
+}
+
+/*!
+ @brief Return true if the bitstream has been completely decoded
+ The end of sample flag is set to true when enough of the sample has been read
+ from the bitstream to allow the output frame to be fully reconstructed. Any
+ remaining bits in the sample can be ignored and it may be the case that further
+ reads from the bitstream will result in an error.
+ The end of sample flag is set when the tag for the frame trailer is found, but
+ may be set when sufficient subbands have been decoded to allow the frame to be
+ reconstructed at the desired resolution. For example, it is not an error if
+ bands at level one in the wavelet tree are not present in the bitstream when
+ decoding to half resolution. The decoder should set the end of sample flag as
+ soon as it is no longer necessary to read further information from the sample.
+
+ @todo Rename this routine to end of image or end of bitstream?
+ */
+bool EndOfSample(DECODER *decoder)
+{
+ return decoder->codec.end_of_sample;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Return true of the layer has been completely read from the bitstream
+ */
+bool EndOfLayer(DECODER *decoder)
+{
+ return (decoder->codec.end_of_layer || decoder->codec.end_of_sample);
+}
+#endif
+
+/*!
+ @brief Return true if the entire bitstream header has been decoded
+ The bitstream header has been completely decoded when at least one
+ non-header parameter has been encountered in the bitstream and all
+ of the required header parameters have been decoded.
+
+ @todo Create a bitstream that can be used to test this predicate.
+ */
+bool IsHeaderComplete(DECODER *decoder)
+{
+ return (decoder->header_finished &&
+ ((decoder->header_mask & BITSTREAM_HEADER_FLAGS_REQUIRED) == BITSTREAM_HEADER_FLAGS_REQUIRED));
+}
+
+/*!
+ @brief Return true if all channels in the bitstream have been processed
+ It is only necessary to test the bands in the largest wavelet in each
+ channel since its lowpass band would not be finished if the wavelets
+ at the higher levels were incomplete.
+ */
+bool IsDecodingComplete(DECODER *decoder)
+{
+ int channel_count = decoder->codec.channel_count;
+ int channel_index;
+
+ for (channel_index = 0; channel_index < channel_count; channel_index++)
+ {
+ WAVELET *wavelet = decoder->transform[channel_index].wavelet[0];
+
+ // Processing is not complete if the wavelet has not been allocated
+ if (wavelet == NULL) return false;
+
+ // Processing is not complete unless all bands have been processed
+ if (!AllBandsValid(wavelet)) return false;
+ }
+
+ // All bands in all wavelets in all channels are done
+ return true;
+}
+
+/*!
+ @brief Perform the final wavelet transform in each channel to compute the component arrays
+ Each channel is decoded and the lowpass and highpass bands are used to reconstruct the
+ lowpass band in the wavelet at the next lower level by applying the inverse wavelet filter.
+ Highpass band decoding and computation of the inverse wavelet transform in each channel
+ stops when the wavelet at the level immediately above the output frame is computed.
+ This routine performs the final wavelet transform in each channel and combines the channels
+ into a single output frame. Note that this routine is called for each layer in a sample,
+ producing an output frame for each layer. The output frames for each layer must be combine
+ by an image compositing operation into a single output frame for the fully decoded sample.
+ */
+CODEC_ERROR ReconstructUnpackedImage(DECODER *decoder, UNPACKED_IMAGE *image)
+{
+ TIMESTAMP("[BEG]", 2)
+
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ gpr_allocator *allocator = decoder->allocator;
+
+ int channel_count = decoder->codec.channel_count;
+ int channel_number;
+
+ // Check for enough space in the local array allocations
+ //assert(channel_count <= MAX_CHANNEL_COUNT);
+
+ // Allocate the vector of component arrays
+ size_t size = channel_count * sizeof(COMPONENT_ARRAY);
+ image->component_array_list = allocator->Alloc(size);
+ if (image->component_array_list == NULL) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ // Clear the component array information so that the state is consistent
+ image->component_count = 0;
+ memset(image->component_array_list, 0, size);
+
+ for (channel_number = 0; channel_number < channel_count; channel_number++)
+ {
+ // Get the dimensions of this channel
+ DIMENSION channel_width = decoder->channel[channel_number].width;
+ DIMENSION channel_height = decoder->channel[channel_number].height;
+ PRECISION bits_per_component = decoder->channel[channel_number].bits_per_component;
+
+ // Amount of prescaling applied to the component array values before encoding
+ PRESCALE prescale = decoder->codec.prescale_table[0];
+
+ // Allocate the component array for this channel
+ error = AllocateComponentArray(allocator,
+ &image->component_array_list[channel_number],
+ channel_width,
+ channel_height,
+ bits_per_component);
+
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ error = TransformInverseSpatialQuantArray(allocator,
+ decoder->transform[channel_number].wavelet[0],
+ image->component_array_list[channel_number].data,
+ channel_width,
+ channel_height,
+ image->component_array_list[channel_number].pitch,
+ prescale);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+ }
+
+ // One component array is output by the decoding process per channel in the bitstream
+ image->component_count = channel_count;
+
+ TIMESTAMP("[END]", 2)
+
+ return error;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Perform the final wavelet transform in each channel to compute the output frame
+ Each channel is decoded and the lowpass and highpass bands are used to reconstruct the
+ lowpass band in the wavelet at the next lower level by applying the inverse wavelet filter.
+ Highpass band decoding and computation of the inverse wavelet transform in each channel
+ stops when the wavelet at the level immediately above the output frame is computed.
+ This routine performs the final wavelet transform in each channel and combines the channels
+ into a single output frame. Note that this routine is called for each layer in a sample,
+ producing an output frame for each layer. The output frames for each layer must be combine
+ by an image compositing operation into a single output frame for the fully decoded sample.
+ Refer to @ref ReconstructSampleFrame for the details of how the frames from each layer
+ are combined to produce the output frame for the decoded sample.
+ */
+CODEC_ERROR ReconstructLayerImage(DECODER *decoder, IMAGE *image)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ DIMENSION decoded_width = decoder->decoded.width;
+ DIMENSION decoded_height = decoder->decoded.height;
+ int channel_count = decoder->codec.channel_count;
+
+ //DIMENSION layer_width = LayerWidth(decoder, decoded_width);
+ //DIMENSION layer_height = LayerHeight(decoder, decoded_height);
+ DIMENSION layer_width = decoded_width;
+ DIMENSION layer_height = decoded_height;
+
+ //TODO: Adjust the layer width to account for chroma sampling
+
+ // Allocate a buffer for the intermediate output from each wavelet transform
+ size_t decoded_frame_pitch = layer_width * channel_count * sizeof(PIXEL);
+ size_t decoded_frame_size = layer_height * decoded_frame_pitch;
+ PIXEL *decoded_frame_buffer = (PIXEL *)Alloc(decoder->allocator, decoded_frame_size);
+ if (decoded_frame_buffer == NULL) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ error = TransformInverseSpatialQuantBuffer(decoder, decoded_frame_buffer, (DIMENSION)decoded_frame_pitch);
+ if (error == CODEC_ERROR_OKAY)
+ {
+ // Pack the decoded frame into the output format
+ error = PackOutputImage(decoded_frame_buffer, decoded_frame_pitch, decoder->encoded.format, image);
+ }
+
+ // Free the buffer for the decoded frame
+ Free(decoder->allocator, decoded_frame_buffer);
+
+ return error;
+}
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Combine multiple decoded frames from each layer into a single output frame
+ An encoded sample may contain multiple sub-samples called layers. For example,
+ there may be two sub-samples (layers) for the left and right frames in a stereo pair.
+ Note that the baseline profile supports only one layer per sample.
+ Each layer is decoded independently to produce an output frame for that layer. The
+ CineForm codec does not support dependent sub-samples in any of the existing profiles.
+
+ This routine forms a composite frame for the output of the completely decoded sample
+ from the individual frames obtained by decoding each layer. It is contemplated that
+ any image compositing algorithm could be used to combine decoded layers, although the
+ most sophisticated algorithms might be reserved for the most advanced profiles.
+ The dimensions of the output frame could be much larger than the dimensions of any
+ of the frames decoded from individual layers. Compositing could overlay the frames
+ from the individual layers with an arbitrary spatial offset applied to the frame from
+ each layer, creating a collage from frames decoded from the individual layers. Typical
+ applications may use only the most elementary compositing operations.
+ */
+CODEC_ERROR ReconstructSampleFrame(DECODER *decoder, IMAGE image_array[], int frame_count, IMAGE *output_image)
+{
+ DIMENSION frame_width = image_array[0].width;
+ DIMENSION field_height = image_array[0].height;
+ DIMENSION frame_height = 2 * field_height;
+ PIXEL_FORMAT frame_format = image_array[0].format;
+
+ AllocImage(decoder->allocator, output_image, frame_width, frame_height, frame_format);
+
+ return ComposeFields(image_array, frame_count, output_image);
+}
+#endif
+
+
diff --git a/gpr/source/lib/vc5_decoder/decoder.h b/gpr/source/lib/vc5_decoder/decoder.h
new file mode 100755
index 0000000..013aa31
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/decoder.h
@@ -0,0 +1,336 @@
+/*! @file decoder.h
+ *
+ * @brief Core decoder functions and data structure
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DECODER_H
+#define DECODER_H
+
+/*!
+ Data structure for the buffers and information used by
+ the decoder.
+
+ The decoder data structure contains information that will be
+ used by the decoder for decoding every sample in the sequence.
+ Information that varies during decoding, such as the current
+ subband index or the dimensions of the bands in the wavelet that
+ is being decoded, is stored in the codec state.
+
+ @todo Consider changing the transform data structure to use a
+ vector of wavelets rather than a vector of wavelet pointers.
+
+ @todo Remove unused substructures
+
+ @todo Dynamically allocate the vector of wavelet trees based on the
+ actual number of channels rather than the maximum channel count.
+
+ @todo Need to handle the cases where header parameters are provided
+ by the application instead of being in the bitstream.
+ */
+typedef struct _decoder
+{
+ CODEC_ERROR error; //!< Error code from the most recent codec operation
+ gpr_allocator *allocator; //!< Memory allocator used to allocate all dyynamic data
+ CODEC_STATE codec; //!< Information gathered while decoding the current sample
+
+ //! Parts of the VC-5 standard that are supported at runtime by the codec implementation
+ ENABLED_PARTS enabled_parts;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ uint64_t frame_number; //!< Every sample in a clip has a unique frame number
+#endif
+
+ uint16_t header_mask; //!< Track which header parameters have been decoded
+ bool header_finished; //!< Finished decoding the bitstream header?
+ bool memory_allocated; //!< True if memory for decoding has been allocated
+
+ //! Dimensions of each channel found in the bitstream
+ struct _channel
+ {
+ DIMENSION width; //!< Width of this channel
+ DIMENSION height; //!< Height of this channnel
+
+ //! Bits per component for the component array corresponding to this channel
+ uint_least8_t bits_per_component;
+
+ bool initialized; //!< Has the channel information been initialized?
+
+ bool found_first_codeblock; //!< Has the first codeblock in the channel been found?
+
+ } channel[MAX_CHANNEL_COUNT]; //!< Information about each channel in the bitstream
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ //! Dimensions and format of the encoded image
+ struct _encoded
+ {
+ DIMENSION width; //!< Encoded width
+ DIMENSION height; //!< Encoded height
+ IMAGE_FORMAT format; //!< Encoded format
+
+ } encoded; //!< Information about the image as represented in the bitstream
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ //! Dimensions and format of the decoded image
+ struct _decoded
+ {
+ DIMENSION width; //!< Decoded width
+ DIMENSION height; //!< Decoded height
+ //RESOLUTION resolution;
+
+ } decoded; //!< Information about the decoded component arrays
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ //! Dimensions and format of the frame after post-processing (see @ref ImageRepackingProcess)
+ struct _output
+ {
+ DIMENSION width; //!< Output frame width
+ DIMENSION height; //!< Output frame height
+ PIXEL_FORMAT format; //!< Output frame pixel format
+
+ } output; //!< Information about the packed image output by the image repacking process
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ //! Dimensions and format of the image output by the display process
+ struct _display
+ {
+ DIMENSION width; //!< Output frame width
+ DIMENSION height; //!< Output frame height
+ PIXEL_FORMAT format; //!< Output frame pixel format
+
+ } display; //!< Information about the displayable image output by the display process
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ int layer_count; //!< Number of subsamples in each sample
+#endif
+
+ int wavelet_count; //!< Number of wavelets in each channel
+
+ int subbands_to_decode;
+
+ //! Wavelet tree for each channel
+ TRANSFORM transform[MAX_CHANNEL_COUNT];
+
+ //! Pointer to the active codebook for variable-length codes
+ CODEBOOK *codebook;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ uint8_t image_sequence_identifier[16]; //!< UUID for the unique image sequence identifier
+ uint32_t image_sequence_number; //!< Number of the image in the image sequence
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ bool progressive; //!< True if the encoded frame is progressive
+ bool top_field_first; //!< True if the top field is encoded first
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ bool section_flag; //!< Control whether section processing is enabled
+ FILE *section_logfile; //!< Log file for writing section information
+#endif
+
+} DECODER;
+
+/*!
+ @brief Information that can be obtained from an bitstream header
+
+ The bitstream header consists of tag-value pairs that must occur in the bitstream
+ before the first codeblock if the parameters are present in the bitstream.
+
+ Consider organizing the values obtained from the bitstream into input parameters
+ and encoded parameters, as is done elsewhere in the decoder, even though the
+ bitstream does not have such a rigid syntax.
+ */
+typedef struct _bitstream_header
+{
+ uint16_t channel_count; //!< Number of channels in the bitstream
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ uint64_t frame_number; //!< Every sample in a clip has a unique frame number
+ PIXEL_FORMAT input_format; //!< Pixel format of the frame input to the encoder
+
+ // Encoded dimensions and format of the encoded frame (including padding)
+ DIMENSION encoded_width; //!< Width of the encoded frame
+ DIMENSION encoded_height; //!< Height of the encoded frame
+
+ IMAGE_FORMAT encoded_format; //!< Encoded format
+
+ // The display aperture within the encoded frame
+ DIMENSION row_offset;
+ DIMENSION column_offset;
+ DIMENSION display_width; //!< Width of the displayable frame (if specified in the sample)
+ DIMENSION display_height; //!< Height of the displayable frame (if specified in the sample)
+#endif
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ DIMENSION video_channel_count; // Number of layers?
+ DIMENSION current_video_channel; //TODO: Find better way to handle this
+ int layer_count; //!< Number of layers in the sample
+ bool progressive; //!< Progressive versus interlaced frames
+ bool top_field_first; //!< Interlaced frame with top field first
+#endif
+
+} BITSTREAM_HEADER;
+
+//! Flags that indicate which header parameters have been assigned values
+typedef enum _bitstream_header_flags
+{
+ BITSTREAM_HEADER_FLAGS_IMAGE_WIDTH = (1 << 0),
+ BITSTREAM_HEADER_FLAGS_IMAGE_HEIGHT = (1 << 1),
+ BITSTREAM_HEADER_FLAGS_CHANNEL_COUNT = (1 << 2),
+ BITSTREAM_HEADER_FLAGS_SUBBAND_COUNT = (1 << 3),
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ BITSTREAM_HEADER_FLAGS_IMAGE_FORMAT = (1 << 4),
+ BITSTREAM_HEADER_FLAGS_PATTERN_WIDTH = (1 << 5),
+ BITSTREAM_HEADER_FLAGS_PATTERN_HEIGHT = (1 << 6),
+ BITSTREAM_HEADER_FLAGS_COMPONENTS_PER_SAMPLE = (1 << 7),
+ BITSTREAM_HEADER_FLAGS_MAX_BITS_PER_COMPONENT = (1 << 8),
+
+ //! Required header parameters
+ BITSTREAM_HEADER_FLAGS_REQUIRED = (BITSTREAM_HEADER_FLAGS_IMAGE_WIDTH |
+ BITSTREAM_HEADER_FLAGS_IMAGE_HEIGHT |
+ BITSTREAM_HEADER_FLAGS_IMAGE_FORMAT |
+ BITSTREAM_HEADER_FLAGS_PATTERN_WIDTH |
+ BITSTREAM_HEADER_FLAGS_PATTERN_HEIGHT |
+ BITSTREAM_HEADER_FLAGS_COMPONENTS_PER_SAMPLE),
+#else
+
+ //! Required header parameters
+ BITSTREAM_HEADER_FLAGS_REQUIRED = (BITSTREAM_HEADER_FLAGS_IMAGE_WIDTH |
+ BITSTREAM_HEADER_FLAGS_IMAGE_HEIGHT),
+#endif
+
+} BITSTREAM_HEADER_FLAGS;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InitDecoder(DECODER *decoder, const gpr_allocator *allocator);
+
+ CODEC_ERROR SetDecoderLogfile(DECODER *decoder, FILE *logfile);
+
+ CODEC_ERROR ReleaseDecoder(DECODER *decoder);
+
+ CODEC_ERROR PrepareDecoderState(DECODER *decoder, const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR PrepareDecoderTransforms(DECODER *decoder);
+
+ CODEC_ERROR SetOutputImageFormat(DECODER *decoder,
+ const DECODER_PARAMETERS *parameters,
+ DIMENSION *width_out,
+ DIMENSION *height_out,
+ PIXEL_FORMAT *format_out);
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ CODEC_ERROR SetDisplayImageFormat(DECODER *decoder,
+ const DECODER_PARAMETERS *parameters,
+ DIMENSION *width_out,
+ DIMENSION *height_out,
+ PIXEL_FORMAT *format_out);
+#endif
+
+ bool ChannelLowpassBandsAllValid(const DECODER *decoder, int wavelet_index);
+
+ PIXEL_FORMAT EncodedPixelFormat(const DECODER *decoder, const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR PackOutputImage(void *buffer, size_t pitch, int encoded_format, IMAGE *image);
+
+ CODEC_ERROR ImageRepackingProcess(const UNPACKED_IMAGE *unpacked_image,
+ PACKED_IMAGE *packed_image,
+ const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR UpdateCodecState(DECODER *decoder, BITSTREAM *stream, TAGVALUE segment);
+
+ bool IsHeaderParameter(TAGWORD tag);
+
+ CODEC_ERROR UpdateHeaderParameter(DECODER *decoder, TAGWORD tag);
+
+ CODEC_ERROR PrepareDecoder(DECODER *decoder, const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR AllocDecoderTransforms(DECODER *decoder);
+
+ CODEC_ERROR ReleaseDecoderTransforms(DECODER *decoder);
+
+ CODEC_ERROR AllocDecoderBuffers(DECODER *decoder);
+
+ CODEC_ERROR ReleaseDecoderBuffers(DECODER *decoder);
+
+ CODEC_ERROR AllocateChannelWavelets(DECODER *decoder, int channel);
+
+ CODEC_ERROR DecodeStream(STREAM *stream, UNPACKED_IMAGE *image, const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR DecodeImage(STREAM *stream, IMAGE *image, RGB_IMAGE *rgb_image, DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR DecodingProcess(DECODER *decoder, BITSTREAM *stream, UNPACKED_IMAGE *image, const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR DecodeSingleImage(DECODER *decoder, BITSTREAM *input, UNPACKED_IMAGE *image, const DECODER_PARAMETERS *parameters);
+
+ CODEC_ERROR DecodeSampleLayer(DECODER *decoder, BITSTREAM *input, IMAGE *image);
+
+ CODEC_ERROR DecodeChannelSubband(DECODER *decoder, BITSTREAM *input, size_t chunk_size);
+
+ CODEC_ERROR ReconstructWaveletBand(DECODER *decoder, int channel, WAVELET *wavelet, int index);
+
+ CODEC_ERROR ParseChannelIndex(BITSTREAM *stream, uint32_t *channel_size, int channel_count);
+
+ DIMENSION LayerWidth(DECODER *decoder, DIMENSION width);
+ DIMENSION LayerHeight(DECODER *decoder, DIMENSION height);
+
+ CODEC_ERROR ProcessSampleMarker(DECODER *decoder, BITSTREAM *stream, TAGWORD marker);
+
+ CODEC_ERROR SetDecodedBandMask(CODEC_STATE *codec, int subband);
+
+ CODEC_ERROR DecodeLowpassBand(DECODER *decoder, BITSTREAM *stream, WAVELET *wavelet);
+
+ CODEC_ERROR DecodeHighpassBand(DECODER *decoder, BITSTREAM *stream, WAVELET *wavelet, int band);
+
+ CODEC_ERROR DecodeBandRuns(BITSTREAM *stream, CODEBOOK *codebook, PIXEL *data,
+ DIMENSION width, DIMENSION height, DIMENSION pitch);
+
+ CODEC_ERROR DecodeBandTrailer(BITSTREAM *stream);
+
+ CODEC_ERROR DecodeSampleChannelHeader(DECODER *decoder, BITSTREAM *stream);
+
+ bool IsHeaderComplete(DECODER *decoder);
+
+ bool EndOfSample(DECODER *decoder);
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ bool EndOfLayer(DECODER *decoder);
+ bool IsLayerComplete(DECODER *decoder);
+#endif
+
+ bool IsDecodingComplete(DECODER *decoder);
+
+ CODEC_ERROR ReconstructUnpackedImage(DECODER *decoder, UNPACKED_IMAGE *image);
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ CODEC_ERROR ReconstructLayerImage(DECODER *decoder, IMAGE *image);
+#endif
+
+ CODEC_ERROR TransformInverseSpatialQuantBuffer(DECODER *decoder, void *output_buffer, DIMENSION output_width, DIMENSION output_pitch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DECODER_H
diff --git a/gpr/source/lib/vc5_decoder/dequantize.c b/gpr/source/lib/vc5_decoder/dequantize.c
new file mode 100755
index 0000000..48cfb64
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/dequantize.c
@@ -0,0 +1,88 @@
+/*! @file dequantize.c
+ *
+ * @brief Implementation of inverse quantization functions
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+// Not using midpoint correction in dequantization
+static const int midpoint = 0;
+
+/*!
+ @brief Dequantize a band with the specified dimensions
+
+ The companding curve is inverted and the value is multiplied by the
+ quantization value that was used by the encoder to compress the band.
+*/
+CODEC_ERROR DequantizeBandRow16s(PIXEL *input, int width, int quantization, PIXEL *output)
+{
+ int column;
+
+ // Undo quantization in the entire row
+ for (column = 0; column < width; column++)
+ {
+ int32_t value = input[column];
+
+ // Invert the companding curve (if any)
+ value = UncompandedValue(value);
+
+ // Dequantize the absolute value
+ if (value > 0)
+ {
+ value = (quantization * value) + midpoint;
+ }
+ else if (value < 0)
+ {
+ value = neg(value);
+ value = (quantization * value) + midpoint;
+ value = neg(value);
+ }
+
+ // Store the dequantized coefficient
+ output[column] = ClampPixel(value);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief This function dequantizes the pixel value
+
+ The inverse companding curve is applied to convert the pixel value
+ to its quantized value and then the pixel value is multiplied by
+ the quantization parameter.
+*/
+PIXEL DequantizedValue(int32_t value, int quantization)
+{
+ // Invert the companding curve (if any)
+ value = UncompandedValue(value);
+
+ // Dequantize the absolute value
+ if (value > 0)
+ {
+ value = (quantization * value) + midpoint;
+ }
+ else if (value < 0)
+ {
+ value = neg(value);
+ value = (quantization * value) + midpoint;
+ value = neg(value);
+ }
+
+ return ClampPixel(value);
+}
diff --git a/gpr/source/lib/vc5_decoder/dequantize.h b/gpr/source/lib/vc5_decoder/dequantize.h
new file mode 100755
index 0000000..748bc36
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/dequantize.h
@@ -0,0 +1,36 @@
+/*! @file dequantize.h
+ *
+ * @brief Declaration of inverse quantization functions
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef QUANTIZE_H
+#define QUANTIZE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR DequantizeBandRow16s(PIXEL *input, int width, int quantization, PIXEL *output);
+
+ PIXEL DequantizedValue(int32_t value, int quantization);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // QUANTIZE_H
diff --git a/gpr/source/lib/vc5_decoder/headers.h b/gpr/source/lib/vc5_decoder/headers.h
new file mode 100755
index 0000000..54e17e4
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/headers.h
@@ -0,0 +1,49 @@
+/*! @file headers.h
+ *
+ * @brief This file includes all of the header files that are used by the decoder.
+ *
+ * Note that some header files are only used by the main program that
+ * calls the codec or are only used for debugging are not included by this file.
+ * Only headers that are part of the reference decoder are included by this file.
+
+ * Including a single header file in all reference decoder source files
+ * ensures that all modules see the same header files in the same order.
+
+ * This file can be used for creating a pre-compiled header if the
+ * compiler supports that capabilities.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HEADERS_H
+#define HEADERS_H
+
+#include "common.h"
+
+#include "vlc.h"
+#include "raw.h"
+#include "bitstream.h"
+#include "dequantize.h"
+#include "parameters.h"
+#include "inverse.h"
+#include "codebooks.h"
+#include "wavelet.h"
+#include "syntax.h"
+#include "decoder.h"
+#include "component.h"
+#include "vc5_decoder.h"
+
+#endif // HEADERS_H
diff --git a/gpr/source/lib/vc5_decoder/inverse.c b/gpr/source/lib/vc5_decoder/inverse.c
new file mode 100755
index 0000000..cacc7be
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/inverse.c
@@ -0,0 +1,1188 @@
+/*! @file inverse.c
+ *
+ * @brief Implementation of the inverse wavelet transforms.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+//! Rounding adjustment used by the inverse wavelet transforms
+static const int32_t rounding = 4;
+
+/*!
+ @brief Apply the inverse horizontal wavelet transform
+ This routine applies the inverse wavelet transform to a row of
+ lowpass and highpass coefficients, producing an output row that
+ is write as wide.
+ */
+STATIC CODEC_ERROR InvertHorizontal16s(PIXEL *lowpass, //!< Horizontal lowpass coefficients
+ PIXEL *highpass, //!< Horizontal highpass coefficients
+ PIXEL *output, //!< Row of reconstructed results
+ DIMENSION input_width, //!< Number of values in the input row
+ DIMENSION output_width //!< Number of values in the output row
+)
+{
+ const int last_column = input_width - 1;
+
+ int32_t even;
+ int32_t odd;
+
+ // Start processing at the beginning of the row
+ int column = 0;
+
+ // Process the first two output points with special filters for the left border
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 11 * lowpass[column + 0];
+ even -= 4 * lowpass[column + 1];
+ even += 1 * lowpass[column + 2];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highpass[column];
+ even >>= 1;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 5 * lowpass[column + 0];
+ odd += 4 * lowpass[column + 1];
+ odd -= 1 * lowpass[column + 2];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highpass[column];
+ odd >>= 1;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Store the last two output points produced by the loop
+ output[2 * column + 0] = clamp_uint14(even);
+ output[2 * column + 1] = clamp_uint14(odd);
+
+ // Advance to the next input column (second pair of output values)
+ column++;
+
+ // Process the rest of the columns up to the last column in the row
+ for (; column < last_column; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+ // Apply the even reconstruction filter to the lowpass band
+
+ even += lowpass[column - 1];
+ even -= lowpass[column + 1];
+ even += 4;
+ even >>= 3;
+ even += lowpass[column + 0];
+
+ // Add the highpass correction
+ even += highpass[column];
+ even >>= 1;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even column
+ //output[2 * column + 0] = clamp_uint12(even);
+ output[2 * column + 0] = clamp_uint14(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd -= lowpass[column - 1];
+ odd += lowpass[column + 1];
+ odd += 4;
+ odd >>= 3;
+ odd += lowpass[column + 0];
+
+ // Subtract the highpass correction
+ odd -= highpass[column];
+ odd >>= 1;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd column
+ //output[2 * column + 1] = clamp_uint14(odd);
+ output[2 * column + 1] = clamp_uint14(odd);
+ }
+
+ // Should have exited the loop at the column for right border processing
+ assert(column == last_column);
+
+ // Process the last two output points with special filters for the right border
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 5 * lowpass[column + 0];
+ even += 4 * lowpass[column - 1];
+ even -= 1 * lowpass[column - 2];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highpass[column];
+ even >>= 1;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even column
+ output[2 * column + 0] = clamp_uint14(even);
+
+ if (2 * column + 1 < output_width)
+ {
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 11 * lowpass[column + 0];
+ odd -= 4 * lowpass[column - 1];
+ odd += 1 * lowpass[column - 2];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highpass[column];
+ odd >>= 1;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd column
+ output[2 * column + 1] = clamp_uint14(odd);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Apply the inverse horizontal wavelet transform
+ This routine is similar to @ref InvertHorizontal16s, but a scale factor
+ that was applied during encoding is removed from the output values.
+ */
+STATIC CODEC_ERROR InvertHorizontalDescale16s(PIXEL *lowpass, PIXEL *highpass, PIXEL *output,
+ DIMENSION input_width, DIMENSION output_width,
+ int descale)
+{
+ const int last_column = input_width - 1;
+
+ // Start processing at the beginning of the row
+ int column = 0;
+
+ int descale_shift = 0;
+
+ int32_t even;
+ int32_t odd;
+
+ /*
+ The implementation of the inverse filter includes descaling by a factor of two
+ because the last division by two in the computation of the even and odd results
+ that is performed using a right arithmetic shift has been omitted from the code.
+ */
+ if (descale == 2) {
+ descale_shift = 1;
+ }
+
+ // Check that the descaling value is reasonable
+ assert(descale_shift >= 0);
+
+ // Process the first two output points with special filters for the left border
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 11 * lowpass[column + 0];
+ even -= 4 * lowpass[column + 1];
+ even += 1 * lowpass[column + 2];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highpass[column];
+
+ // Remove any scaling used during encoding
+ even <<= descale_shift;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 5 * lowpass[column + 0];
+ odd += 4 * lowpass[column + 1];
+ odd -= 1 * lowpass[column + 2];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highpass[column];
+
+ // Remove any scaling used during encoding
+ odd <<= descale_shift;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ output[2 * column + 0] = ClampPixel(even);
+ output[2 * column + 1] = ClampPixel(odd);
+
+ // Advance to the next input column (second pair of output values)
+ column++;
+
+ // Process the rest of the columns up to the last column in the row
+ for (; column < last_column; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += lowpass[column - 1];
+ even -= lowpass[column + 1];
+ even += 4;
+ even >>= 3;
+ even += lowpass[column + 0];
+
+ // Add the highpass correction
+ even += highpass[column];
+
+ // Remove any scaling used during encoding
+ even <<= descale_shift;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even column
+ output[2 * column + 0] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd -= lowpass[column - 1];
+ odd += lowpass[column + 1];
+ odd += 4;
+ odd >>= 3;
+ odd += lowpass[column + 0];
+
+ // Subtract the highpass correction
+ odd -= highpass[column];
+
+ // Remove any scaling used during encoding
+ odd <<= descale_shift;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd column
+ output[2 * column + 1] = ClampPixel(odd);
+ }
+
+ // Should have exited the loop at the column for right border processing
+ assert(column == last_column);
+
+ // Process the last two output points with special filters for the right border
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 5 * lowpass[column + 0];
+ even += 4 * lowpass[column - 1];
+ even -= 1 * lowpass[column - 2];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highpass[column];
+
+ // Remove any scaling used during encoding
+ even <<= descale_shift;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even column
+ output[2 * column + 0] = ClampPixel(even);
+
+ if (2 * column + 1 < output_width)
+ {
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 11 * lowpass[column + 0];
+ odd -= 4 * lowpass[column - 1];
+ odd += 1 * lowpass[column - 2];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highpass[column];
+
+ // Remove any scaling used during encoding
+ odd <<= descale_shift;
+
+ // The lowpass result should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd column
+ output[2 * column + 1] = ClampPixel(odd);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Apply the inverse spatial wavelet filter
+ Dequantize the coefficients in the highpass bands and apply the
+ inverse spatial wavelet filter to compute a lowpass band that
+ has twice the width and height of the input bands.
+ The inverse vertical filter is applied to the upper and lower bands
+ on the left and the upper and lower bands on the right. The inverse
+ horizontal filter is applied to the left and right (lowpass and highpass)
+ results from the vertical inverse. Each application of the inverse
+ vertical filter produces two output rows and each application of the
+ inverse horizontal filter produces an output row that is twice as wide.
+ The inverse wavelet filter is a three tap filter.
+
+ For the even output values, add and subtract the off-center values,
+ add the rounding correction, and divide by eight, then add the center
+ value, add the highpass coefficient, and divide by two.
+
+ For the odd output values, the add and subtract operations for the
+ off-center values are reversed the the highpass coefficient is subtracted.
+ Divisions are implemented by right arithmetic shifts.
+ Special formulas for the inverse vertical filter are applied to the top
+ and bottom rows.
+ */
+CODEC_ERROR InvertSpatialQuant16s(gpr_allocator *allocator,
+ PIXEL *lowlow_band, int lowlow_pitch,
+ PIXEL *lowhigh_band, int lowhigh_pitch,
+ PIXEL *highlow_band, int highlow_pitch,
+ PIXEL *highhigh_band, int highhigh_pitch,
+ PIXEL *output_image, int output_pitch,
+ DIMENSION input_width, DIMENSION input_height,
+ DIMENSION output_width, DIMENSION output_height,
+ QUANT quantization[])
+{
+ PIXEL *lowlow = (PIXEL *)lowlow_band;
+ PIXEL *lowhigh = lowhigh_band;
+ PIXEL *highlow = highlow_band;
+ PIXEL *highhigh = highhigh_band;
+ PIXEL *output = output_image;
+ PIXEL *even_lowpass;
+ PIXEL *even_highpass;
+ PIXEL *odd_lowpass;
+ PIXEL *odd_highpass;
+ PIXEL *even_output;
+ PIXEL *odd_output;
+ size_t buffer_row_size;
+ int last_row = input_height - 1;
+ int row, column;
+
+ PIXEL *lowhigh_row[3];
+
+ PIXEL *lowhigh_line[3];
+ PIXEL *highlow_line;
+ PIXEL *highhigh_line;
+
+ QUANT highlow_quantization = quantization[HL_BAND];
+ QUANT lowhigh_quantization = quantization[LH_BAND];
+ QUANT highhigh_quantization = quantization[HH_BAND];
+
+ // Compute positions within the temporary buffer for each row of horizontal lowpass
+ // and highpass intermediate coefficients computed by the vertical inverse transform
+ buffer_row_size = input_width * sizeof(PIXEL);
+
+ // Compute the positions of the even and odd rows of coefficients
+ even_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+ even_highpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+ odd_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+ odd_highpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+
+ // Compute the positions of the dequantized highpass rows
+ lowhigh_line[0] = (PIXEL *)allocator->Alloc(buffer_row_size);
+ lowhigh_line[1] = (PIXEL *)allocator->Alloc(buffer_row_size);
+ lowhigh_line[2] = (PIXEL *)allocator->Alloc(buffer_row_size);
+ highlow_line = (PIXEL *)allocator->Alloc(buffer_row_size);
+ highhigh_line = (PIXEL *)allocator->Alloc(buffer_row_size);
+
+ // Convert pitch from bytes to pixels
+ lowlow_pitch /= sizeof(PIXEL);
+ lowhigh_pitch /= sizeof(PIXEL);
+ highlow_pitch /= sizeof(PIXEL);
+ highhigh_pitch /= sizeof(PIXEL);
+ output_pitch /= sizeof(PIXEL);
+
+ // Initialize the pointers to the even and odd output rows
+ even_output = output;
+ odd_output = output + output_pitch;
+
+ // Apply the vertical border filter to the first row
+ row = 0;
+
+ // Set pointers to the first three rows in the first highpass band
+ lowhigh_row[0] = lowhigh + 0 * lowhigh_pitch;
+ lowhigh_row[1] = lowhigh + 1 * lowhigh_pitch;
+ lowhigh_row[2] = lowhigh + 2 * lowhigh_pitch;
+
+ // Dequantize three rows of highpass coefficients in the first highpass band
+ DequantizeBandRow16s(lowhigh_row[0], input_width, lowhigh_quantization, lowhigh_line[0]);
+ DequantizeBandRow16s(lowhigh_row[1], input_width, lowhigh_quantization, lowhigh_line[1]);
+ DequantizeBandRow16s(lowhigh_row[2], input_width, lowhigh_quantization, lowhigh_line[2]);
+
+ // Dequantize one row of coefficients each in the second and third highpass bands
+ DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line);
+ DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line);
+
+ for (column = 0; column < input_width; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+
+ /***** Compute the vertical inverse for the left two bands *****/
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 11 * lowlow[column + 0 * lowlow_pitch];
+ even -= 4 * lowlow[column + 1 * lowlow_pitch];
+ even += 1 * lowlow[column + 2 * lowlow_pitch];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highlow_line[column];
+ even >>= 1;
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even row
+ even_lowpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 5 * lowlow[column + 0 * lowlow_pitch];
+ odd += 4 * lowlow[column + 1 * lowlow_pitch];
+ odd -= 1 * lowlow[column + 2 * lowlow_pitch];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highlow_line[column];
+ odd >>= 1;
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd row
+ odd_lowpass[column] = ClampPixel(odd);
+
+
+ /***** Compute the vertical inverse for the right two bands *****/
+
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 11 * lowhigh_line[0][column];
+ even -= 4 * lowhigh_line[1][column];
+ even += 1 * lowhigh_line[2][column];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highhigh_line[column];
+ even >>= 1;
+
+ // Place the even result in the even row
+ even_highpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 5 * lowhigh_line[0][column];
+ odd += 4 * lowhigh_line[1][column];
+ odd -= 1 * lowhigh_line[2][column];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highhigh_line[column];
+ odd >>= 1;
+
+ // Place the odd result in the odd row
+ odd_highpass[column] = ClampPixel(odd);
+ }
+
+ // Apply the inverse horizontal transform to the even and odd rows
+ InvertHorizontal16s(even_lowpass, even_highpass, even_output, input_width, output_width);
+ InvertHorizontal16s(odd_lowpass, odd_highpass, odd_output, input_width, output_width);
+
+ // Advance to the next pair of even and odd output rows
+ even_output += 2 * output_pitch;
+ odd_output += 2 * output_pitch;
+
+ // Always advance the highpass row pointers
+ highlow += highlow_pitch;
+ highhigh += highhigh_pitch;
+
+ // Advance the row index
+ row++;
+
+ // Process the middle rows using the interior reconstruction filters
+ for (; row < last_row; row++)
+ {
+ // Dequantize one row from each of the two highpass bands
+ DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line);
+ DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line);
+
+ // Process the entire row
+ for (column = 0; column < input_width; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+
+ /***** Compute the vertical inverse for the left two bands *****/
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += lowlow[column + 0 * lowlow_pitch];
+ even -= lowlow[column + 2 * lowlow_pitch];
+ even += 4;
+ even >>= 3;
+ even += lowlow[column + 1 * lowlow_pitch];
+
+ // Add the highpass correction
+ even += highlow_line[column];
+ even >>= 1;
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even row
+ even_lowpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd -= lowlow[column + 0 * lowlow_pitch];
+ odd += lowlow[column + 2 * lowlow_pitch];
+ odd += 4;
+ odd >>= 3;
+ odd += lowlow[column + 1 * lowlow_pitch];
+
+ // Subtract the highpass correction
+ odd -= highlow_line[column];
+ odd >>= 1;
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd row
+ odd_lowpass[column] = ClampPixel(odd);
+
+
+ /***** Compute the vertical inverse for the right two bands *****/
+
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += lowhigh_line[0][column];
+ even -= lowhigh_line[2][column];
+ even += 4;
+ even >>= 3;
+ even += lowhigh_line[1][column];
+
+ // Add the highpass correction
+ even += highhigh_line[column];
+ even >>= 1;
+
+ // Place the even result in the even row
+ even_highpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd -= lowhigh_line[0][column];
+ odd += lowhigh_line[2][column];
+ odd += 4;
+ odd >>= 3;
+ odd += lowhigh_line[1][column];
+
+ // Subtract the highpass correction
+ odd -= highhigh_line[column];
+ odd >>= 1;
+
+ // Place the odd result in the odd row
+ odd_highpass[column] = ClampPixel(odd);
+ }
+
+ // Apply the inverse horizontal transform to the even and odd rows and descale the results
+ InvertHorizontal16s(even_lowpass, even_highpass, even_output, input_width, output_width);
+ InvertHorizontal16s(odd_lowpass, odd_highpass, odd_output, input_width, output_width);
+
+ // Advance to the next input row in each band
+ lowlow += lowlow_pitch;
+ lowhigh += lowhigh_pitch;
+ highlow += highlow_pitch;
+ highhigh += highhigh_pitch;
+
+ // Advance to the next pair of even and odd output rows
+ even_output += 2 * output_pitch;
+ odd_output += 2 * output_pitch;
+
+ if (row < last_row - 1)
+ {
+ // Compute the address of the next row in the lowhigh band
+ PIXEL *lowhigh_row_ptr = (lowhigh + 2 * lowhigh_pitch);
+ //PIXEL *lowhigh_row_ptr = (lowhigh + lowhigh_pitch);
+
+ // Shift the rows in the buffer of dequantized lowhigh bands
+ PIXEL *temp = lowhigh_line[0];
+ lowhigh_line[0] = lowhigh_line[1];
+ lowhigh_line[1] = lowhigh_line[2];
+ lowhigh_line[2] = temp;
+
+ // Undo quantization for the next row in the lowhigh band
+ DequantizeBandRow16s(lowhigh_row_ptr, input_width, lowhigh_quantization, lowhigh_line[2]);
+ }
+ }
+
+ // Should have exited the loop at the last row
+ assert(row == last_row);
+
+ // Advance the lowlow pointer to the last row in the band
+ lowlow += lowlow_pitch;
+
+ // Check that the band pointers are on the last row in each wavelet band
+ assert(lowlow == (lowlow_band + last_row * lowlow_pitch));
+
+ assert(highlow == (highlow_band + last_row * highlow_pitch));
+ assert(highhigh == (highhigh_band + last_row * highhigh_pitch));
+
+ // Undo quantization for the highlow and highhigh bands
+ DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line);
+ DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line);
+
+ // Apply the vertical border filter to the last row
+ for (column = 0; column < input_width; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+
+ /***** Compute the vertical inverse for the left two bands *****/
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 5 * lowlow[column + 0 * lowlow_pitch];
+ even += 4 * lowlow[column - 1 * lowlow_pitch];
+ even -= 1 * lowlow[column - 2 * lowlow_pitch];
+ even += 4;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highlow_line[column];
+ even >>= 1;
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even row
+ even_lowpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 11 * lowlow[column + 0 * lowlow_pitch];
+ odd -= 4 * lowlow[column - 1 * lowlow_pitch];
+ odd += 1 * lowlow[column - 2 * lowlow_pitch];
+ odd += 4;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highlow_line[column];
+ odd >>= 1;
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd row
+ odd_lowpass[column] = ClampPixel(odd);
+
+
+ // Compute the vertical inverse for the right two bands //
+
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 5 * lowhigh_line[2][column];
+ even += 4 * lowhigh_line[1][column];
+ even -= 1 * lowhigh_line[0][column];
+ even += 4;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highhigh_line[column];
+ even >>= 1;
+
+ // Place the even result in the even row
+ even_highpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 11 * lowhigh_line[2][column];
+ odd -= 4 * lowhigh_line[1][column];
+ odd += 1 * lowhigh_line[0][column];
+ odd += 4;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highhigh_line[column];
+ odd >>= 1;
+
+ // Place the odd result in the odd row
+ odd_highpass[column] = ClampPixel(odd);
+ }
+
+ // Apply the inverse horizontal transform to the even and odd rows and descale the results
+ InvertHorizontal16s(even_lowpass, even_highpass, even_output, input_width, output_width);
+
+ // Is the output wavelet shorter than twice the height of the input wavelet?
+ if (2 * row + 1 < output_height) {
+ InvertHorizontal16s(odd_lowpass, odd_highpass, odd_output, input_width, output_width);
+ }
+
+ // Free the scratch buffers
+ allocator->Free(even_lowpass);
+ allocator->Free(even_highpass);
+ allocator->Free(odd_lowpass);
+ allocator->Free(odd_highpass);
+
+ allocator->Free(lowhigh_line[0]);
+ allocator->Free(lowhigh_line[1]);
+ allocator->Free(lowhigh_line[2]);
+ allocator->Free(highlow_line);
+ allocator->Free(highhigh_line);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Apply the inverse spatial transform with descaling
+ This routine is similar to @ref InvertSpatialQuant16s, but a scale factor
+ that was applied during encoding is removed from the output values.
+ */
+CODEC_ERROR InvertSpatialQuantDescale16s(gpr_allocator *allocator,
+ PIXEL *lowlow_band, int lowlow_pitch,
+ PIXEL *lowhigh_band, int lowhigh_pitch,
+ PIXEL *highlow_band, int highlow_pitch,
+ PIXEL *highhigh_band, int highhigh_pitch,
+ PIXEL *output_image, int output_pitch,
+ DIMENSION input_width, DIMENSION input_height,
+ DIMENSION output_width, DIMENSION output_height,
+ int descale, QUANT quantization[])
+{
+ PIXEL *lowlow = lowlow_band;
+ PIXEL *lowhigh = lowhigh_band;
+ PIXEL *highlow = highlow_band;
+ PIXEL *highhigh = highhigh_band;
+ PIXEL *output = output_image;
+ PIXEL *even_lowpass;
+ PIXEL *even_highpass;
+ PIXEL *odd_lowpass;
+ PIXEL *odd_highpass;
+ PIXEL *even_output;
+ PIXEL *odd_output;
+ size_t buffer_row_size;
+ int last_row = input_height - 1;
+ int row, column;
+
+ PIXEL *lowhigh_row[3];
+
+ PIXEL *lowhigh_line[3];
+ PIXEL *highlow_line;
+ PIXEL *highhigh_line;
+
+ QUANT highlow_quantization = quantization[HL_BAND];
+ QUANT lowhigh_quantization = quantization[LH_BAND];
+ QUANT highhigh_quantization = quantization[HH_BAND];
+
+ // Compute positions within the temporary buffer for each row of horizontal lowpass
+ // and highpass intermediate coefficients computed by the vertical inverse transform
+ buffer_row_size = input_width * sizeof(PIXEL);
+
+ // Allocate space for the even and odd rows of results from the inverse vertical filter
+ even_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+ even_highpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+ odd_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+ odd_highpass = (PIXEL *)allocator->Alloc(buffer_row_size);
+
+ // Allocate scratch space for the dequantized highpass coefficients
+ lowhigh_line[0] = (PIXEL *)allocator->Alloc(buffer_row_size);
+ lowhigh_line[1] = (PIXEL *)allocator->Alloc(buffer_row_size);
+ lowhigh_line[2] = (PIXEL *)allocator->Alloc(buffer_row_size);
+ highlow_line = (PIXEL *)allocator->Alloc(buffer_row_size);
+ highhigh_line = (PIXEL *)allocator->Alloc(buffer_row_size);
+
+ // Convert pitch from bytes to pixels
+ lowlow_pitch /= sizeof(PIXEL);
+ lowhigh_pitch /= sizeof(PIXEL);
+ highlow_pitch /= sizeof(PIXEL);
+ highhigh_pitch /= sizeof(PIXEL);
+ output_pitch /= sizeof(PIXEL);
+
+ // Initialize the pointers to the even and odd output rows
+ even_output = output;
+ odd_output = output + output_pitch;
+
+ // Apply the vertical border filter to the first row
+ row = 0;
+
+ // Set pointers to the first three rows in the first highpass band
+ lowhigh_row[0] = lowhigh + 0 * lowhigh_pitch;
+ lowhigh_row[1] = lowhigh + 1 * lowhigh_pitch;
+ lowhigh_row[2] = lowhigh + 2 * lowhigh_pitch;
+
+ // Dequantize three rows of highpass coefficients in the first highpass band
+ DequantizeBandRow16s(lowhigh_row[0], input_width, lowhigh_quantization, lowhigh_line[0]);
+ DequantizeBandRow16s(lowhigh_row[1], input_width, lowhigh_quantization, lowhigh_line[1]);
+ DequantizeBandRow16s(lowhigh_row[2], input_width, lowhigh_quantization, lowhigh_line[2]);
+
+ // Dequantize one row of coefficients each in the second and third highpass bands
+ DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line);
+ DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line);
+
+ for (column = 0; column < input_width; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+
+ /***** Compute the vertical inverse for the left two bands *****/
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 11 * lowlow[column + 0 * lowlow_pitch];
+ even -= 4 * lowlow[column + 1 * lowlow_pitch];
+ even += 1 * lowlow[column + 2 * lowlow_pitch];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highlow_line[column];
+ even = DivideByShift(even, 1);
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even row
+ even_lowpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 5 * lowlow[column + 0 * lowlow_pitch];
+ odd += 4 * lowlow[column + 1 * lowlow_pitch];
+ odd -= 1 * lowlow[column + 2 * lowlow_pitch];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highlow_line[column];
+ odd = DivideByShift(odd, 1);
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd row
+ odd_lowpass[column] = ClampPixel(odd);
+
+
+ /***** Compute the vertical inverse for the right two bands *****/
+
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 11 * lowhigh_line[0][column];
+ even -= 4 * lowhigh_line[1][column];
+ even += 1 * lowhigh_line[2][column];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highhigh_line[column];
+ even = DivideByShift(even, 1);
+
+ // Place the even result in the even row
+ even_highpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 5 * lowhigh_line[0][column];
+ odd += 4 * lowhigh_line[1][column];
+ odd -= 1 * lowhigh_line[2][column];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highhigh_line[column];
+ odd = DivideByShift(odd, 1);
+
+ // Place the odd result in the odd row
+ odd_highpass[column] = ClampPixel(odd);
+ }
+
+ // Apply the inverse horizontal transform to the even and odd rows and descale the results
+ InvertHorizontalDescale16s(even_lowpass, even_highpass, even_output,
+ input_width, output_width, descale);
+
+ InvertHorizontalDescale16s(odd_lowpass, odd_highpass, odd_output,
+ input_width, output_width, descale);
+
+ // Advance to the next pair of even and odd output rows
+ even_output += 2 * output_pitch;
+ odd_output += 2 * output_pitch;
+
+ // Always advance the highpass row pointers
+ highlow += highlow_pitch;
+ highhigh += highhigh_pitch;
+
+ // Advance the row index
+ row++;
+
+ // Process the middle rows using the interior reconstruction filters
+ for (; row < last_row; row++)
+ {
+ // Dequantize one row from each of the two highpass bands
+ DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line);
+ DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line);
+
+ // Process the entire row
+ for (column = 0; column < input_width; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+
+ /***** Compute the vertical inverse for the left two bands *****/
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += lowlow[column + 0 * lowlow_pitch];
+ even -= lowlow[column + 2 * lowlow_pitch];
+ even += 4;
+ even >>= 3;
+ even += lowlow[column + 1 * lowlow_pitch];
+
+ // Add the highpass correction
+ even += highlow_line[column];
+ even = DivideByShift(even, 1);
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even row
+ even_lowpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd -= lowlow[column + 0 * lowlow_pitch];
+ odd += lowlow[column + 2 * lowlow_pitch];
+ odd += 4;
+ odd >>= 3;
+ odd += lowlow[column + 1 * lowlow_pitch];
+
+ // Subtract the highpass correction
+ odd -= highlow_line[column];
+ odd = DivideByShift(odd, 1);
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd row
+ odd_lowpass[column] = ClampPixel(odd);
+
+
+ /***** Compute the vertical inverse for the right two bands *****/
+
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += lowhigh_line[0][column];
+ even -= lowhigh_line[2][column];
+ even += 4;
+ even >>= 3;
+ even += lowhigh_line[1][column];
+
+ // Add the highpass correction
+ even += highhigh_line[column];
+ even = DivideByShift(even, 1);
+
+ // Place the even result in the even row
+ even_highpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd -= lowhigh_line[0][column];
+ odd += lowhigh_line[2][column];
+ odd += 4;
+ odd >>= 3;
+ odd += lowhigh_line[1][column];
+
+ // Subtract the highpass correction
+ odd -= highhigh_line[column];
+ odd = DivideByShift(odd, 1);
+
+ // Place the odd result in the odd row
+ odd_highpass[column] = ClampPixel(odd);
+ }
+
+ // Apply the inverse horizontal transform to the even and odd rows and descale the results
+ InvertHorizontalDescale16s(even_lowpass, even_highpass, even_output,
+ input_width, output_width, descale);
+
+ InvertHorizontalDescale16s(odd_lowpass, odd_highpass, odd_output,
+ input_width, output_width, descale);
+
+ // Advance to the next input row in each band
+ lowlow += lowlow_pitch;
+ lowhigh += lowhigh_pitch;
+ highlow += highlow_pitch;
+ highhigh += highhigh_pitch;
+
+ // Advance to the next pair of even and odd output rows
+ even_output += 2 * output_pitch;
+ odd_output += 2 * output_pitch;
+
+ if (row < last_row - 1)
+ {
+ // Compute the address of the next row in the lowhigh band
+ PIXEL *lowhigh_row_ptr = (lowhigh + 2 * lowhigh_pitch);
+
+ // Shift the rows in the buffer of dequantized lowhigh bands
+ PIXEL *temp = lowhigh_line[0];
+ lowhigh_line[0] = lowhigh_line[1];
+ lowhigh_line[1] = lowhigh_line[2];
+ lowhigh_line[2] = temp;
+
+ // Undo quantization for the next row in the lowhigh band
+ DequantizeBandRow16s(lowhigh_row_ptr, input_width, lowhigh_quantization, lowhigh_line[2]);
+ }
+ }
+
+ // Should have exited the loop at the last row
+ assert(row == last_row);
+
+ // Advance the lowlow pointer to the last row in the band
+ lowlow += lowlow_pitch;
+
+ // Check that the band pointers are on the last row in each wavelet band
+ assert(lowlow == (lowlow_band + last_row * lowlow_pitch));
+
+ assert(highlow == (highlow_band + last_row * highlow_pitch));
+ assert(highhigh == (highhigh_band + last_row * highhigh_pitch));
+
+ // Undo quantization for the highlow and highhigh bands
+ DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line);
+ DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line);
+
+ // Apply the vertical border filter to the last row
+ for (column = 0; column < input_width; column++)
+ {
+ int32_t even = 0; // Result of convolution with even filter
+ int32_t odd = 0; // Result of convolution with odd filter
+
+
+ /***** Compute the vertical inverse for the left two bands *****/
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 5 * lowlow[column + 0 * lowlow_pitch];
+ even += 4 * lowlow[column - 1 * lowlow_pitch];
+ even -= 1 * lowlow[column - 2 * lowlow_pitch];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highlow_line[column];
+ even = DivideByShift(even, 1);
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= even && even <= INT16_MAX);
+
+ // Place the even result in the even row
+ even_lowpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 11 * lowlow[column + 0 * lowlow_pitch];
+ odd -= 4 * lowlow[column - 1 * lowlow_pitch];
+ odd += 1 * lowlow[column - 2 * lowlow_pitch];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highlow_line[column];
+ odd = DivideByShift(odd, 1);
+
+ // The inverse of the left two bands should be a positive number
+ //assert(0 <= odd && odd <= INT16_MAX);
+
+ // Place the odd result in the odd row
+ odd_lowpass[column] = ClampPixel(odd);
+
+
+ /***** Compute the vertical inverse for the right two bands *****/
+
+ even = 0;
+ odd = 0;
+
+ // Apply the even reconstruction filter to the lowpass band
+ even += 5 * lowhigh_line[2][column];
+ even += 4 * lowhigh_line[1][column];
+ even -= 1 * lowhigh_line[0][column];
+ even += rounding;
+ even = DivideByShift(even, 3);
+
+ // Add the highpass correction
+ even += highhigh_line[column];
+ even = DivideByShift(even, 1);
+
+ // Place the even result in the even row
+ even_highpass[column] = ClampPixel(even);
+
+ // Apply the odd reconstruction filter to the lowpass band
+ odd += 11 * lowhigh_line[2][column];
+ odd -= 4 * lowhigh_line[1][column];
+ odd += 1 * lowhigh_line[0][column];
+ odd += rounding;
+ odd = DivideByShift(odd, 3);
+
+ // Subtract the highpass correction
+ odd -= highhigh_line[column];
+ odd = DivideByShift(odd, 1);
+
+ // Place the odd result in the odd row
+ odd_highpass[column] = ClampPixel(odd);
+ }
+
+ // Apply the inverse horizontal transform to the even and odd rows and descale the results
+ InvertHorizontalDescale16s(even_lowpass, even_highpass, even_output,
+ input_width, output_width, descale);
+
+ // Is the output wavelet shorter than twice the height of the input wavelet?
+ if (2 * row + 1 < output_height) {
+ InvertHorizontalDescale16s(odd_lowpass, odd_highpass, odd_output,
+ input_width, output_width, descale);
+ }
+
+ // Free the scratch buffers
+ allocator->Free(even_lowpass);
+ allocator->Free(even_highpass);
+ allocator->Free(odd_lowpass);
+ allocator->Free(odd_highpass);
+
+ allocator->Free(lowhigh_line[0]);
+ allocator->Free(lowhigh_line[1]);
+ allocator->Free(lowhigh_line[2]);
+ allocator->Free(highlow_line);
+ allocator->Free(highhigh_line);
+
+ return CODEC_ERROR_OKAY;
+}
+
diff --git a/gpr/source/lib/vc5_decoder/inverse.h b/gpr/source/lib/vc5_decoder/inverse.h
new file mode 100755
index 0000000..0d8d77c
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/inverse.h
@@ -0,0 +1,51 @@
+/*! @file inverse.h
+ *
+ * @brief Declaration of the inverse wavelet transform functions.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INVERSE_H
+#define INVERSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InvertSpatialQuant16s(gpr_allocator *allocator,
+ PIXEL *lowlow_band, int lowlow_pitch,
+ PIXEL *lowhigh_band, int lowhigh_pitch,
+ PIXEL *highlow_band, int highlow_pitch,
+ PIXEL *highhigh_band, int highhigh_pitch,
+ PIXEL *output_image, int output_pitch,
+ DIMENSION input_width, DIMENSION input_height,
+ DIMENSION output_width, DIMENSION output_height,
+ QUANT quantization[]);
+
+ CODEC_ERROR InvertSpatialQuantDescale16s(gpr_allocator *allocator,
+ PIXEL *lowlow_band, int lowlow_pitch,
+ PIXEL *lowhigh_band, int lowhigh_pitch,
+ PIXEL *highlow_band, int highlow_pitch,
+ PIXEL *highhigh_band, int highhigh_pitch,
+ PIXEL *output_image, int output_pitch,
+ DIMENSION input_width, DIMENSION input_height,
+ DIMENSION output_width, DIMENSION output_height,
+ //ROI roi, PIXEL *buffer, size_t buffer_size,
+ int descale, QUANT quantization[]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // INVERSE_H
diff --git a/gpr/source/lib/vc5_decoder/parameters.c b/gpr/source/lib/vc5_decoder/parameters.c
new file mode 100755
index 0000000..f8ef2cd
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/parameters.c
@@ -0,0 +1,47 @@
+/*! @file parameters.c
+ *
+ * @brief Implementation of the data structure used to pass decoding
+ * parameters to the decoder.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+//! Current version number of the parameters data structure
+#define PARAMETERS_VERSION 0
+
+/*!
+ @brief Initialize the parameters data structure
+
+ The version number of the parameters data structure must be
+ incremented whenever a change is made to the definition of
+ the parameters data structure.
+*/
+CODEC_ERROR InitDecoderParameters(DECODER_PARAMETERS *parameters)
+{
+ memset(parameters, 0, sizeof(DECODER_PARAMETERS));
+ parameters->version = 1;
+ parameters->verbose_flag = false;
+
+ parameters->enabled_parts = VC5_ENABLED_PARTS;
+
+ parameters->output.format = PIXEL_FORMAT_RAW_DEFAULT;
+
+ parameters->rgb_resolution = GPR_RGB_RESOLUTION_NONE;
+
+ gpr_rgb_gain_set_defaults(&parameters->rgb_gain);
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_decoder/parameters.h b/gpr/source/lib/vc5_decoder/parameters.h
new file mode 100755
index 0000000..d0bbb74
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/parameters.h
@@ -0,0 +1,119 @@
+/*! @file parameters.h
+ *
+ * @brief Declare a data structure for holding a table of parameters used
+ * during decoding to override the default decoding behavior.
+
+ * The decoder can be initialized using the dimensions of the encoded frame
+ * obtained from an external source such as a media container and the pixel
+ * format of the decoded frame. The encoded sample will be decoded to the
+ * dimensions of the encoded frame without at the full encoded resolution
+ * without scaling. The decoded frames will have the specified pixel format,
+ * but this assumes that the encoded dimensions used during initialization
+ * are the same as the actual encoded dimensions and that the pixel format of
+ * the decoded frames is a valid pixel format.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PARAMETERS_H
+#define PARAMETERS_H
+
+#include "vc5_decoder.h"
+
+/*!
+ @brief Declaration of a data structure for passing decoding parameters to the decoder
+*/
+typedef struct _decoder_parameters
+{
+ uint32_t version; //!< Version number for this definition of the parameters
+
+ uint32_t enabled_parts; //!< Parts of the VC-5 standard that are enabled
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ int layer_count; //!< Number of layers in the sample
+ bool progressive; //!< True if the frame is progressive
+ bool top_field_first; //!< True if interlaced with top field first
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ bool section_flag; //!< True if decoding sections element in the bitstream
+#endif
+
+ //! Dimensions and format of the output of the image unpacking process
+ struct _input_parameters
+ {
+ DIMENSION width;
+ DIMENSION height;
+ // PIXEL_FORMAT format;
+ } input; //! Dimensions and format of the unpacked image
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ //! Dimensions and format of the output of the decoding process
+ struct _decoded_parameters
+ {
+ DIMENSION width;
+ DIMENSION height;
+ PIXEL_FORMAT format;
+ } decoded; //! Decoded image dimensions and pixel format
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_ELEMENTARY)
+ //! Dimensions and format of the output of the image repacking process
+ struct _output_parameters
+ {
+ DIMENSION width;
+ DIMENSION height;
+ PIXEL_FORMAT format;
+ } output;
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ //! Dimensions and format of the displayable image
+ struct _display_parameters
+ {
+ DIMENSION width;
+ DIMENSION height;
+ PIXEL_FORMAT format;
+ } display;
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_METADATA)
+ //! Metadata that controls decoding
+ METADATA metadata;
+#endif
+
+ //! Flag that controls verbose output
+ bool verbose_flag;
+
+ GPR_RGB_RESOLUTION rgb_resolution;
+
+ int rgb_bits;
+
+ gpr_rgb_gain rgb_gain;
+
+ gpr_allocator allocator;
+
+} DECODER_PARAMETERS;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InitDecoderParameters(DECODER_PARAMETERS *parameters);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PARAMETERS_H
diff --git a/gpr/source/lib/vc5_decoder/raw.c b/gpr/source/lib/vc5_decoder/raw.c
new file mode 100755
index 0000000..7cbac6f
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/raw.c
@@ -0,0 +1,135 @@
+/*! @file raw.c
+ *
+ * @brief Definition of routines for packing a row of pixels into a RAW image.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+/*!
+ @brief Pack the component arrays into an output image
+
+ The inverse component transform for Bayer images (VC-5 Part 3)
+ is applied to the component arrays before combining the values
+ into a packed image.
+ */
+CODEC_ERROR PackComponentsToRAW(const UNPACKED_IMAGE *image,
+ PIXEL *output_buffer, size_t output_pitch,
+ DIMENSION width, DIMENSION height,
+ ENABLED_PARTS enabled_parts, uint16_t output_bit_depth, PIXEL_FORMAT output_format )
+{
+ // Define pointers to the rows for each input component
+ COMPONENT_VALUE *GS_input_buffer;
+ COMPONENT_VALUE *RG_input_buffer;
+ COMPONENT_VALUE *BG_input_buffer;
+ COMPONENT_VALUE *GD_input_buffer;
+
+ // Define pointers to the rows for each output component
+ uint16_t *output_row1_ptr;
+ uint16_t *output_row2_ptr;
+
+ //size_t input_quarter_pitch;
+ size_t output_half_pitch;
+
+ int row;
+
+ GS_input_buffer = image->component_array_list[0].data;
+ RG_input_buffer = image->component_array_list[1].data;
+ BG_input_buffer = image->component_array_list[2].data;
+ GD_input_buffer = image->component_array_list[3].data;
+
+ // Compute the distance between the half rows in the Bayer grid
+ output_half_pitch = output_pitch / 2;
+
+ for (row = 0; row < height; row++)
+ {
+ COMPONENT_VALUE *GS_input_row_ptr = (COMPONENT_VALUE *)((uintptr_t)GS_input_buffer + row * image->component_array_list[0].pitch);
+ COMPONENT_VALUE *RG_input_row_ptr = (COMPONENT_VALUE *)((uintptr_t)RG_input_buffer + row * image->component_array_list[1].pitch);
+ COMPONENT_VALUE *BG_input_row_ptr = (COMPONENT_VALUE *)((uintptr_t)BG_input_buffer + row * image->component_array_list[2].pitch);
+ COMPONENT_VALUE *GD_input_row_ptr = (COMPONENT_VALUE *)((uintptr_t)GD_input_buffer + row * image->component_array_list[3].pitch);
+
+ uint8_t *output_row_ptr = (uint8_t *)output_buffer + row * output_pitch;
+
+ const int32_t midpoint = 2048;
+
+ int column;
+
+ output_row1_ptr = (uint16_t *)output_row_ptr;
+ output_row2_ptr = (uint16_t *)(output_row_ptr + output_half_pitch);
+
+ // Pack the rows of Bayer components into the BYR4 pattern
+ for (column = 0; column < width; column++)
+ {
+ int32_t GS, RG, BG, GD;
+ int32_t R, G1, G2, B;
+
+ GS = GS_input_row_ptr[column];
+ RG = RG_input_row_ptr[column];
+ BG = BG_input_row_ptr[column];
+ GD = GD_input_row_ptr[column];
+
+ // Convert unsigned values to signed values
+ GD -= midpoint;
+ RG -= midpoint;
+ BG -= midpoint;
+
+ R = (RG << 1) + GS;
+ B = (BG << 1) + GS;
+ G1 = GS + GD;
+ G2 = GS - GD;
+
+ R = clamp_uint(R, 12);
+ G1 = clamp_uint(G1, 12);
+ G2 = clamp_uint(G2, 12);
+ B = clamp_uint(B, 12);
+
+ // Apply inverse protune log curve
+ R = DecoderLogCurve[R];
+ B = DecoderLogCurve[B];
+ G1 = DecoderLogCurve[G1];
+ G2 = DecoderLogCurve[G2];
+
+ R >>= (16 - output_bit_depth);
+ B >>= (16 - output_bit_depth);
+ G1 >>= (16 - output_bit_depth);
+ G2 >>= (16 - output_bit_depth);
+
+ switch (output_format)
+ {
+ case PIXEL_FORMAT_RAW_RGGB_12:
+ case PIXEL_FORMAT_RAW_RGGB_14:
+ output_row1_ptr[2 * column + 0] = (uint16_t)R;
+ output_row1_ptr[2 * column + 1] = (uint16_t)G1;
+ output_row2_ptr[2 * column + 0] = (uint16_t)G2;
+ output_row2_ptr[2 * column + 1] = (uint16_t)B;
+ break;
+
+ case PIXEL_FORMAT_RAW_GBRG_12:
+ case PIXEL_FORMAT_RAW_GBRG_14:
+ output_row1_ptr[2 * column + 0] = (uint16_t)G1;
+ output_row1_ptr[2 * column + 1] = (uint16_t)B;
+ output_row2_ptr[2 * column + 0] = (uint16_t)R;
+ output_row2_ptr[2 * column + 1] = (uint16_t)G2;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_decoder/raw.h b/gpr/source/lib/vc5_decoder/raw.h
new file mode 100755
index 0000000..7bca498
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/raw.h
@@ -0,0 +1,35 @@
+/*! @file raw.h
+ *
+ * @brief Declaration of routines for packing a row of pixels into a RAW image.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RAW_H
+#define RAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR PackComponentsToRAW(const UNPACKED_IMAGE *image,
+ PIXEL *output_buffer, size_t output_pitch,
+ DIMENSION width, DIMENSION height,
+ ENABLED_PARTS enabled_parts, uint16_t output_bit_depth, PIXEL_FORMAT output_format );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // RAW_H
diff --git a/gpr/source/lib/vc5_decoder/syntax.c b/gpr/source/lib/vc5_decoder/syntax.c
new file mode 100755
index 0000000..f0c4b58
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/syntax.c
@@ -0,0 +1,116 @@
+/*! @file syntax.c
+ *
+ * @brief Implementation of functions for parsing the bitstream syntax of encoded samples.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+//! Size of a tag or value (in bits)
+#define BITSTREAM_TAG_SIZE 16
+
+/*!
+ @brief Read the next tag-valie pair from the bitstream.
+
+ The next tag is read from the bitstream and the next value that
+ immediately follows the tag in the bitstreeam are read from the
+ bitstream.
+
+ The value may be the length of the payload in bytes or the value
+ may be a single scalar. This routine only reads the next tag and
+ value and does not intepret the tag or value and does not read any
+ data that may follow the segment in the bitstream.
+
+ The tag and value are interpreted by @ref UpdateCodecState and that
+ routine may read additional information from the bitstream.
+
+ If the value is the length of the payload then it encodes the number
+ of bytes in the segment payload, not counting the segment header.
+*/
+TAGVALUE GetSegment(BITSTREAM *stream)
+{
+ TAGVALUE segment;
+ segment.tuple.tag = (TAGWORD)GetBits(stream, 16);
+ segment.tuple.value = (TAGWORD)GetBits(stream, 16);
+ return segment;
+}
+
+/*!
+ @brief Read the specified tag from the bitstream and return the value
+*/
+TAGWORD GetValue(BITSTREAM *stream, int tag)
+{
+ TAGVALUE segment = GetTagValue(stream);
+
+ assert(stream->error == BITSTREAM_ERROR_OKAY);
+ if (stream->error == BITSTREAM_ERROR_OKAY) {
+ assert(segment.tuple.tag == tag);
+ if (segment.tuple.tag == tag) {
+ return segment.tuple.value;
+ }
+ else {
+ stream->error = BITSTREAM_ERROR_BADTAG;
+ }
+ }
+
+ // An error has occurred so return zero (error code was set above)
+ return 0;
+}
+
+/*!
+ @brief Read the next tag value pair from the bitstream
+*/
+TAGVALUE GetTagValue(BITSTREAM *stream)
+{
+ TAGVALUE segment = GetSegment(stream);
+ while (segment.tuple.tag < 0) {
+ segment = GetSegment(stream);
+ }
+
+ return segment;
+}
+
+/*!
+ @brief Return true if the tag is optional
+*/
+bool IsTagOptional(TAGWORD tag)
+{
+ return (tag < 0);
+}
+
+/*!
+ @brief Return true if the tag is required
+*/
+bool IsTagRequired(TAGWORD tag)
+{
+ return (tag >= 0);
+}
+
+/*!
+ @brief Return true if a valid tag read from the bitstream
+*/
+bool IsValidSegment(BITSTREAM *stream, TAGVALUE segment, TAGWORD tag)
+{
+ return (stream->error == BITSTREAM_ERROR_OKAY &&
+ segment.tuple.tag == tag);
+}
+
+/*!
+ @brief Return true if the tag value pair has the specified tag and value
+*/
+bool IsTagValue(TAGVALUE segment, int tag, TAGWORD value)
+{
+ return (segment.tuple.tag == tag && segment.tuple.value == value);
+}
diff --git a/gpr/source/lib/vc5_decoder/syntax.h b/gpr/source/lib/vc5_decoder/syntax.h
new file mode 100755
index 0000000..d5c4099
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/syntax.h
@@ -0,0 +1,44 @@
+/*! @file syntax.h
+ *
+ * @brief Declare functions for parsing the bitstream syntax of encoded samples.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DECODER_SYNTAX_H
+#define DECODER_SYNTAX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ TAGVALUE GetSegment(BITSTREAM *stream);
+
+ TAGWORD GetValue(BITSTREAM *stream, int tag);
+
+ TAGVALUE GetTagValue(BITSTREAM *stream);
+
+ bool IsTagOptional(TAGWORD tag);
+
+ bool IsTagRequired(TAGWORD tag);
+
+ bool IsValidSegment(BITSTREAM *stream, TAGVALUE segment, TAGWORD tag);
+
+ bool IsTagValue(TAGVALUE segment, int tag, TAGWORD value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DECODER_SYNTAX_H
diff --git a/gpr/source/lib/vc5_decoder/vc5_decoder.c b/gpr/source/lib/vc5_decoder/vc5_decoder.c
new file mode 100755
index 0000000..f36ad4c
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/vc5_decoder.c
@@ -0,0 +1,132 @@
+/*! @file vc5_decoder.c
+ *
+ * @brief Implementation of the top level vc5 decoder API.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+void vc5_decoder_parameters_set_default(vc5_decoder_parameters* decoding_parameters)
+{
+ decoding_parameters->enabled_parts = VC5_ENABLED_PARTS;
+
+ decoding_parameters->pixel_format = VC5_DECODER_PIXEL_FORMAT_DEFAULT;
+
+ decoding_parameters->rgb_resolution = VC5_DECODER_RGB_RESOLUTION_DEFAULT;
+ decoding_parameters->rgb_bits = 8;
+
+ gpr_rgb_gain_set_defaults(&decoding_parameters->rgb_gain);
+}
+
+CODEC_ERROR vc5_decoder_process(const vc5_decoder_parameters* decoding_parameters, /* vc5 decoding parameters */
+ const gpr_buffer* vc5_buffer, /* vc5 input buffer. */
+ gpr_buffer* raw_buffer, /* raw output buffer. */
+ gpr_rgb_buffer* rgb_buffer) /* rgb output buffer */
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ IMAGE output_image;
+ // Clear the members of the image data structure
+ InitImage(&output_image);
+
+ STREAM input;
+ DECODER_PARAMETERS parameters;
+
+ // Initialize the parameters passed to the decoder
+ InitDecoderParameters(&parameters);
+
+ parameters.enabled_parts = decoding_parameters->enabled_parts;
+
+ parameters.rgb_resolution = decoding_parameters->rgb_resolution;
+ parameters.rgb_bits = decoding_parameters->rgb_bits;
+ parameters.rgb_gain = decoding_parameters->rgb_gain;
+
+ if( rgb_buffer == NULL )
+ {
+ parameters.rgb_resolution = GPR_RGB_RESOLUTION_NONE;
+ }
+
+ parameters.allocator.Alloc = decoding_parameters->mem_alloc;
+ parameters.allocator.Free = decoding_parameters->mem_free;
+
+ switch( decoding_parameters->pixel_format )
+ {
+ case VC5_DECODER_PIXEL_FORMAT_RGGB_12:
+ parameters.output.format = PIXEL_FORMAT_RAW_RGGB_12;
+ break;
+
+ case VC5_DECODER_PIXEL_FORMAT_RGGB_14:
+ parameters.output.format = PIXEL_FORMAT_RAW_RGGB_14;
+ break;
+
+ case VC5_DECODER_PIXEL_FORMAT_GBRG_12:
+ parameters.output.format = PIXEL_FORMAT_RAW_GBRG_12;
+ break;
+
+ case VC5_DECODER_PIXEL_FORMAT_GBRG_14:
+ parameters.output.format = PIXEL_FORMAT_RAW_GBRG_14;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ // Check that the enabled parts are correct
+ error = CheckEnabledParts(&parameters.enabled_parts);
+ if (error != CODEC_ERROR_OKAY) {
+ return CODEC_ERROR_ENABLED_PARTS;
+ }
+
+ error = OpenStreamBuffer(&input, vc5_buffer->buffer, vc5_buffer->size );
+ if (error != CODEC_ERROR_OKAY) {
+ fprintf(stderr, "Could not open input vc5 stream\n" );
+ return error;
+ }
+
+ RGB_IMAGE rgb_image;
+ InitRGBImage(&rgb_image);
+
+ error = DecodeImage(&input, &output_image, &rgb_image, &parameters);
+ if (error != CODEC_ERROR_OKAY) {
+ fprintf(stderr, "Could not decode input vc5 bitstream. Error number %d\n", error );
+ return error;
+ }
+
+ if( parameters.rgb_resolution != GPR_RGB_RESOLUTION_NONE )
+ {
+ assert( rgb_buffer);
+
+ rgb_buffer->buffer = rgb_image.buffer;
+ rgb_buffer->size = rgb_image.size;
+ rgb_buffer->width = rgb_image.width;
+ rgb_buffer->height = rgb_image.height;
+ }
+
+ if( raw_buffer )
+ {
+ assert( output_image.buffer );
+ assert( output_image.size == output_image.width * output_image.height * sizeof(unsigned short) );
+
+ raw_buffer->buffer = output_image.buffer;
+ raw_buffer->size = output_image.size;
+ }
+ else
+ {
+ // Nothing should be returned in output_image since we do not want output raw image
+ assert( output_image.buffer == NULL );
+ }
+
+ return error;
+}
diff --git a/gpr/source/lib/vc5_decoder/vc5_decoder.h b/gpr/source/lib/vc5_decoder/vc5_decoder.h
new file mode 100755
index 0000000..c87111a
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/vc5_decoder.h
@@ -0,0 +1,84 @@
+/*! @file vc5_decoder.h
+ *
+ * @brief Declaration of the top level vc5 decoder API.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VC5_DECODER_H
+#define VC5_DECODER_H
+
+#include "error.h"
+#include "types.h"
+#include "gpr_buffer.h"
+#include "gpr_rgb_buffer.h"
+#include "vc5_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ /*!
+ @brief Bayer pattern ordering for vc5 encoder processing
+ */
+ typedef enum
+ {
+ VC5_DECODER_PIXEL_FORMAT_RGGB_12 = 0, // RGGB 14bit pixels packed into 16bits
+
+ VC5_DECODER_PIXEL_FORMAT_RGGB_14 = 1, // RGGB 14bit pixels packed into 16bits
+
+ VC5_DECODER_PIXEL_FORMAT_GBRG_12 = 2, // GBRG 12bit pixels packed into 16bits
+
+ VC5_DECODER_PIXEL_FORMAT_GBRG_14 = 3, // GBRG 12bit pixels packed into 16bits
+
+ VC5_DECODER_PIXEL_FORMAT_DEFAULT = VC5_DECODER_PIXEL_FORMAT_RGGB_14,
+
+ } VC5_DECODER_PIXEL_FORMAT;
+
+ #define VC5_DECODER_RGB_RESOLUTION_DEFAULT GPR_RGB_RESOLUTION_QUARTER
+
+ /*!
+ @brief vc5 decoder parameters
+ */
+ typedef struct
+ {
+ ENABLED_PARTS enabled_parts;
+
+ VC5_DECODER_PIXEL_FORMAT pixel_format; // Bayer Ordering Pattern (Default: VC5_ENCODER_BAYER_ORDERING_RGGB)
+
+ GPR_RGB_RESOLUTION rgb_resolution;
+
+ int rgb_bits;
+
+ gpr_rgb_gain rgb_gain;
+
+ gpr_malloc mem_alloc; // Callback function to allocate memory
+
+ gpr_free mem_free; // Callback function to free memory
+
+ } vc5_decoder_parameters;
+
+ void vc5_decoder_parameters_set_default(vc5_decoder_parameters* decoding_parameters);
+
+ CODEC_ERROR vc5_decoder_process(const vc5_decoder_parameters* decoding_parameters, /* vc5 decoding parameters */
+ const gpr_buffer* vc5_buffer, /* vc5 input buffer. */
+ gpr_buffer* raw_buffer, /* raw output buffer. */
+ gpr_rgb_buffer* rgb_buffer); /* rgb output buffer */
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // VC5_DECODER_H
diff --git a/gpr/source/lib/vc5_decoder/vlc.c b/gpr/source/lib/vc5_decoder/vlc.c
new file mode 100755
index 0000000..646fc59
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/vlc.c
@@ -0,0 +1,109 @@
+/*! @file vlc.c
+ *
+ * @brief Implementation of routines to parse a variable-length encoded bitstream.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+/*!
+ @brief Parse a run length coded magnitude in the bitstream
+*/
+CODEC_ERROR GetRlv(BITSTREAM *stream, CODEBOOK *codebook, RUN *run)
+{
+ BITWORD bitstream_bits = 0; // Buffer of bits read from the stream
+ BITCOUNT bitstream_count = 0; // Number of bits read from the stream
+
+ // Get the length of the codebook and initialize a pointer to its entries
+ int codebook_length = codebook->length;
+ RLV *codebook_entry = (RLV *)((uint8_t *)codebook + sizeof(CODEBOOK));
+
+ // Index into the codebook
+ int codeword_index = 0;
+
+ // Search the codebook for the run length and value
+ while (codeword_index < codebook_length)
+ {
+ // Get the size of the current word in the codebook
+ BITCOUNT codeword_count = codebook_entry[codeword_index].size;
+
+ // Need to read more bits from the stream?
+ if (bitstream_count < codeword_count)
+ {
+ // Calculate the number of additional bits to read from the stream
+ BITCOUNT read_count = codeword_count - bitstream_count;
+ bitstream_bits = AddBits(stream, bitstream_bits, read_count);
+ bitstream_count = codeword_count;
+ }
+
+ // Examine the run length table entries that have the same bit field length
+ for (; (codeword_index < codebook_length) && (bitstream_count == codebook_entry[codeword_index].size);
+ codeword_index++) {
+ if (bitstream_bits == codebook_entry[codeword_index].bits) {
+ run->count = codebook_entry[codeword_index].count;
+ run->value = codebook_entry[codeword_index].value;
+ goto found;
+ }
+ }
+ }
+
+ // Did not find a matching code in the codebook
+ return CODEC_ERROR_NOTFOUND;
+
+found:
+
+ // Found a valid codeword in the bitstream
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ Parse a run length coded signed value in the bitstream
+*/
+CODEC_ERROR GetRun(BITSTREAM *stream, CODEBOOK *codebook, RUN *run)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ int32_t value;
+
+ // Get the magnitude of the number from the bitstream
+ error = GetRlv(stream, codebook, run);
+
+ // Error while parsing the bitstream?
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Restore the sign to the magnitude of the run value
+ value = run->value;
+
+ // Signed quantity?
+ if (value != 0)
+ {
+ BITWORD sign;
+
+ // Something is wrong if the value is already negative
+ assert(value > 0);
+
+ // Get the codeword for the sign of the value
+ sign = GetBits(stream, VLC_SIGNCODE_SIZE);
+
+ // Change the sign if the codeword signalled a negative value
+ value = ((sign == VLC_NEGATIVE_CODE) ? neg(value) : value);
+ }
+
+ // Return the signed value of the coefficient
+ run->value = value;
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_decoder/vlc.h b/gpr/source/lib/vc5_decoder/vlc.h
new file mode 100755
index 0000000..6ec41f6
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/vlc.h
@@ -0,0 +1,103 @@
+/*! @file vlc.h
+ *
+ * @brief Declaration of the data structures for variable-length decoding
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VLC_H
+#define VLC_H
+
+// Codewords for the sign bits that follow a non-zero value
+#define VLC_POSITIVE_CODE 0x0 //!< Code that indicates a positive value
+#define VLC_NEGATIVE_CODE 0x1 //!< Code that indicates a negative value
+#define VLC_SIGNCODE_SIZE 1 //!< Size of the code for sign suffix
+
+/*!
+ @brief Codebook entries for arbitrary runs and values
+
+ The codebook data structure allows runs of an arbitrary value,
+ but all codec implementations only use runs of zeros. The
+ codeword for a non-zero value is followed by the sign bit.
+
+ @todo Could add the sign bit to the magnitude entries in this
+ table if it improves performance or makes the code more clear.
+*/
+typedef struct _rlv {
+ uint_fast8_t size; //!< Size of code word in bits
+ uint32_t bits; //!< Code word bits right justified
+ uint32_t count; //!< Run length
+ int32_t value; //!< Run value (unsigned)
+} RLV;
+
+/*!
+ @brief Declaration of a codebook
+
+ This data structure is often called the master codebook to distinguish
+ it from the encoding tables that are derived from the codebook. The
+ codebook has a header that is immediately followed by the codebook entries.
+ Each entry is an @ref RLV data structure that contains the codeword and
+ the size of the codeword in bits. Each codeword represent a run length
+ and value. The current codec implementation only supports runs of zeros,
+ so the run length is one for non-zero values. A non-zero value is an
+ unsigned coefficient magnitude. Special codewords that mark significant
+ locations in the bitstream are indicated by a run length of zero and the
+ value indicates the type of marker.
+
+ The codebook is generated by a separate program that takes as input a table
+ of the frequencies of coefficient magnitudes and runs of zeros.
+*/
+typedef struct _codebook
+{
+ uint32_t length; //!< Number of entries in the code book
+ // The length is followed by the RLV entries
+} CODEBOOK;
+
+//! Macro used to define the codebook generated by the Huffman program
+#define RLVTABLE(n) \
+ static struct \
+ { \
+ uint32_t length; \
+ RLV entries[n]; \
+ }
+
+/*!
+ @brief Structure returned by the run length decoding routines
+
+ The value returned may be signed if the routine that was called
+ to parse the bitstream found a run of a non-zero value and then
+ parsed the sign bit that follows the magnitude.
+*/
+typedef struct _run {
+ uint32_t count; //!< Run length count
+ int32_t value; //!< Run length value
+} RUN;
+
+//! Initializer for the run length data structure
+#define RUN_INITIALIZER {0, 0}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR GetRlv(BITSTREAM *stream, CODEBOOK *codebook, RUN *run);
+ CODEC_ERROR GetRun(BITSTREAM *stream, CODEBOOK *codebook, RUN *run);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VLC_H
diff --git a/gpr/source/lib/vc5_decoder/wavelet.c b/gpr/source/lib/vc5_decoder/wavelet.c
new file mode 100755
index 0000000..a60eb0a
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/wavelet.c
@@ -0,0 +1,173 @@
+/*! @file wavelet.c
+ *
+ * @brief Implementation of the module for wavelet data structures and transforms
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+/*!
+ @brief Apply the inverse wavelet transform to reconstruct a lowpass band
+
+ This routine reconstructs the lowpass band in the output wavelet from the
+ decoded bands in the input wavelet. The prescale argument is used to undo
+ scaling that may have been performed during encoding to prevent overflow.
+
+ @todo Replace the two different routines for different prescale shifts with
+ a single routine that can handle any prescale shift.
+*/
+CODEC_ERROR TransformInverseSpatialQuantLowpass(gpr_allocator *allocator, WAVELET *input, WAVELET *output, uint16_t prescale)
+{
+ // Dimensions of each wavelet band
+ DIMENSION input_width = input->width;
+ DIMENSION input_height = input->height;
+
+ // The output width may be less than twice the input width if the output width is odd
+ DIMENSION output_width = output->width;
+
+ // The output height may be less than twice the input height if the output height is odd
+ DIMENSION output_height = output->height;
+
+ // Check that a valid input image has been provided
+ assert(input != NULL);
+ assert(input->data[0] != NULL);
+ assert(input->data[1] != NULL);
+ assert(input->data[2] != NULL);
+ assert(input->data[3] != NULL);
+
+ // Check that the output image is a gray image or a lowpass wavelet band
+ assert(output->data[0] != NULL);
+
+ // Check for valid quantization values
+ if (input->quant[0] == 0) {
+ input->quant[0] = 1;
+ }
+
+ assert(input->quant[0] > 0);
+ assert(input->quant[1] > 0);
+ assert(input->quant[2] > 0);
+ assert(input->quant[3] > 0);
+
+ if (prescale > 1)
+ {
+ // This is a spatial transform for the lowpass temporal band
+ assert(prescale == 2);
+
+ // Apply the inverse spatial transform for a lowpass band that is not prescaled
+ InvertSpatialQuantDescale16s(allocator,
+ (PIXEL *)input->data[0], input->pitch,
+ (PIXEL *)input->data[1], input->pitch,
+ (PIXEL *)input->data[2], input->pitch,
+ (PIXEL *)input->data[3], input->pitch,
+ output->data[0], output->pitch,
+ input_width, input_height,
+ output_width, output_height,
+ prescale, input->quant);
+ }
+ else
+ {
+ // This case does not handle any prescaling applied during encoding
+ assert(prescale == 0);
+
+ // Apply the inverse spatial transform for a lowpass band that is not prescaled
+ InvertSpatialQuant16s(allocator,
+ (PIXEL *)input->data[0], input->pitch,
+ (PIXEL *)input->data[1], input->pitch,
+ (PIXEL *)input->data[2], input->pitch,
+ (PIXEL *)input->data[3], input->pitch,
+ output->data[0], output->pitch,
+ input_width, input_height,
+ output_width, output_height,
+ input->quant);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Apply the inverse wavelet transform to reconstruct a component array
+
+ This routine reconstructs the lowpass band in the output wavelet from the
+ decoded bands in the input wavelet. The prescale argument is used to undo
+ scaling that may have been performed during encoding to prevent overflow.
+*/
+CODEC_ERROR TransformInverseSpatialQuantArray(gpr_allocator *allocator,
+ WAVELET *input,
+ COMPONENT_VALUE *output_buffer,
+ DIMENSION output_width,
+ DIMENSION output_height,
+ size_t output_pitch,
+ PRESCALE prescale)
+{
+ // Dimensions of each wavelet band
+ DIMENSION input_width = input->width;
+ DIMENSION input_height = input->height;
+
+ // Check that a valid input image has been provided
+ assert(input != NULL);
+ assert(input->data[0] != NULL);
+ assert(input->data[1] != NULL);
+ assert(input->data[2] != NULL);
+ assert(input->data[3] != NULL);
+
+ // Check for valid quantization values
+ if (input->quant[0] == 0) {
+ input->quant[0] = 1;
+ }
+
+ assert(input->quant[0] > 0);
+ assert(input->quant[1] > 0);
+ assert(input->quant[2] > 0);
+ assert(input->quant[3] > 0);
+
+ assert(output_width > 0 && output_height > 0 && output_pitch > 0 && output_buffer != NULL);
+
+ if (prescale > 1)
+ {
+ // This is a spatial transform for the lowpass temporal band
+ assert(prescale == 2);
+
+ // Apply the inverse spatial transform for a lowpass band that is not prescaled
+ InvertSpatialQuantDescale16s(allocator,
+ (PIXEL *)input->data[0], input->pitch,
+ (PIXEL *)input->data[1], input->pitch,
+ (PIXEL *)input->data[2], input->pitch,
+ (PIXEL *)input->data[3], input->pitch,
+ (PIXEL *)output_buffer, (int)output_pitch,
+ input_width, input_height,
+ output_width, output_height,
+ prescale, input->quant);
+ }
+ else
+ {
+ // This case does not handle any prescaling applied during encoding
+ assert(prescale == 0);
+
+ // Apply the inverse spatial transform for a lowpass band that is not prescaled
+ InvertSpatialQuant16s(allocator,
+ (PIXEL *)input->data[0], input->pitch,
+ (PIXEL *)input->data[1], input->pitch,
+ (PIXEL *)input->data[2], input->pitch,
+ (PIXEL *)input->data[3], input->pitch,
+ (PIXEL *)output_buffer, (int)output_pitch,
+ input_width, input_height,
+ output_width, output_height,
+ input->quant);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_decoder/wavelet.h b/gpr/source/lib/vc5_decoder/wavelet.h
new file mode 100755
index 0000000..4f2d2fb
--- /dev/null
+++ b/gpr/source/lib/vc5_decoder/wavelet.h
@@ -0,0 +1,42 @@
+/*! @file wavelet.h
+ *
+ * @brief Declare of wavelet decoding functions
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DECODER_WAVELET_H
+#define _DECODER_WAVELET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CODEC_ERROR TransformInverseSpatialQuantLowpass(gpr_allocator *allocator, WAVELET *input, WAVELET *output, uint16_t prescale);
+
+CODEC_ERROR TransformInverseSpatialQuantArray( gpr_allocator *allocator,
+ WAVELET *input,
+ COMPONENT_VALUE *output_buffer,
+ DIMENSION output_width,
+ DIMENSION output_height,
+ size_t output_pitch,
+ PRESCALE prescale);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gpr/source/lib/vc5_encoder/CMakeLists.txt b/gpr/source/lib/vc5_encoder/CMakeLists.txt
new file mode 100644
index 0000000..9dc143b
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/CMakeLists.txt
@@ -0,0 +1,21 @@
+# library
+set( LIB_NAME vc5_encoder )
+
+# get source files
+file( GLOB SRC_FILES "*.c" )
+
+# get include files
+file( GLOB INC_FILES "*.h" )
+
+# add include files from other folders
+include_directories( "../vc5_common" )
+include_directories( "../common/private" )
+include_directories( "../common/public" )
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/vc5_encoder/codebooks.c b/gpr/source/lib/vc5_encoder/codebooks.c
new file mode 100755
index 0000000..c013f4d
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/codebooks.c
@@ -0,0 +1,425 @@
+/*! @file codebooks.c
+ *
+ * @brief Implementation of the routines for computing the encoding tables from a codebook.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+#include "table17.inc"
+
+//! Length of the codebook for runs of zeros
+#define RUNS_TABLE_LENGTH 3072
+
+
+/*!
+ @brief Define the codeset used by the reference codec
+
+ The baseline codec only supports codebook #17.
+
+ Codebook #17 is intended to be used with cubic companding
+ (see @ref FillMagnitudeEncodingTable and @ref ComputeCubicTable).
+ */
+ENCODER_CODESET encoder_codeset_17 = {
+ "Codebook set 17 from data by David Newman with tables automatically generated for the FSM decoder",
+ (const CODEBOOK *)&table17,
+ CODESET_FLAGS_COMPANDING_CUBIC,
+ NULL,
+ NULL,
+};
+
+/*!
+ @brief Initialize the codeset by creating more efficient tables for encoding
+
+ This routine takes the original codebook in the codeset and creates a table
+ of codewords for runs of zeros, indexed by the run length, and a table for
+ coefficient magnitudes, indexed by the coefficient magnitude. This allows
+ runs of zeros and non-zero coefficients to be entropy coded using a simple
+ table lookup.
+*/
+CODEC_ERROR PrepareCodebooks(const gpr_allocator *allocator, ENCODER_CODESET *cs)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Create a new table for runs of zeros with the default length
+ const int runs_table_length = RUNS_TABLE_LENGTH;
+
+ // Initialize the indexable table of run length codes
+ RLV *old_codes = (RLV *)(((uint8_t *)cs->codebook) + sizeof(CODEBOOK));
+ int old_length = cs->codebook->length;
+
+ size_t runs_table_size = runs_table_length * sizeof(RLC) + sizeof(RUNS_TABLE);
+
+ RUNS_TABLE *runs_table = allocator->Alloc(runs_table_size);
+ RLC *new_codes = (RLC *)(((uint8_t *)runs_table) + sizeof(RUNS_TABLE));
+ int new_length = runs_table_length;
+
+ // Set the length of the table for encoding coefficient magnitudes
+ int mags_table_shift = 8;
+ int mags_table_length;
+ size_t mags_table_size;
+ MAGS_TABLE *mags_table;
+ VLE *mags_table_entries;
+
+ // Use a larger table if companding
+ if (CompandingParameter() > 0) {
+ //mags_table_shift = 11;
+ mags_table_shift = 10;
+ }
+
+ // Allocate the table for encoding coefficient magnitudes
+ mags_table_length = (1 << mags_table_shift);
+ mags_table_size = mags_table_length * sizeof(VLE) + sizeof(MAGS_TABLE);
+ mags_table = allocator->Alloc(mags_table_size);
+ if (mags_table == NULL) {
+ allocator->Free( (void *)runs_table);
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ mags_table_entries = (VLE *)(((uint8_t *)mags_table) + sizeof(MAGS_TABLE));
+
+ // Create a more efficient codebook for encoding runs of zeros
+ error = ComputeRunLengthCodeTable(allocator,
+ old_codes, old_length, new_codes, new_length);
+ if (error != CODEC_ERROR_OKAY) {
+ allocator->Free( (void *)runs_table);
+ return error;
+ }
+
+ // Store the new table for runs of zeros in the codeset
+ runs_table->length = runs_table_length;
+ cs->runs_table = runs_table;
+
+ error = FillMagnitudeEncodingTable(cs->codebook, mags_table_entries, mags_table_length, cs->flags);
+ if (error != CODEC_ERROR_OKAY) {
+ allocator->Free( (void *)runs_table);
+ return error;
+ }
+
+ mags_table->length = mags_table_length;
+ cs->mags_table = mags_table;
+
+ // The codebooks have been initialized successfully
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Free all data structures allocated for the codebooks
+*/
+CODEC_ERROR ReleaseCodebooks(gpr_allocator *allocator, ENCODER_CODESET *cs)
+{
+ allocator->Free( (void *)cs->runs_table );
+ allocator->Free( (void *)cs->mags_table);
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Compute a table of codewords for runs of zeros
+
+ The table is indexed by the length of the run of zeros.
+*/
+CODEC_ERROR ComputeRunLengthCodeTable(const gpr_allocator *allocator,
+ RLV *input_codes, int input_length,
+ RLC *output_codes, int output_length)
+{
+ // Need enough space for the codebook and the code for a single value
+ int runs_codebook_length = input_length + 1;
+ size_t runs_codebook_size = runs_codebook_length * sizeof(RLC);
+ RLC *runs_codebook = (RLC *)allocator->Alloc(runs_codebook_size);
+ bool single_zero_run_flag = false;
+ int input_index;
+ int runs_codebook_count = 0;
+ CODEC_ERROR return_code = CODEC_ERROR_OKAY;
+
+ // Copy the codes for runs of zeros into the temporary codebook for sorting
+ for (input_index = 0; input_index < input_length; input_index++)
+ {
+ uint32_t count = input_codes[input_index].count;
+ int32_t value = input_codes[input_index].value;
+
+ // Is this code for a run of zeros?
+ if (value != 0 || count == 0) {
+ // Skip codebook entries for coefficient magnitudes and special codes
+ continue;
+ }
+
+ // Is this code for a single zero
+ if (count == 1 && value == 0) {
+ single_zero_run_flag = true;
+ }
+
+ // Check that the temporary runs codebook is not full
+ assert(runs_codebook_count < runs_codebook_length);
+
+ // Copy the code into the temporary runs codebook
+ runs_codebook[runs_codebook_count].size = input_codes[input_index].size;
+ runs_codebook[runs_codebook_count].bits = input_codes[input_index].bits;
+ runs_codebook[runs_codebook_count].count = count;
+
+ // Check the codebook entry
+ assert(runs_codebook[runs_codebook_count].size > 0);
+ assert(runs_codebook[runs_codebook_count].count > 0);
+
+ // Increment the count of codes in the temporary runs codebook
+ runs_codebook_count++;
+ }
+
+ // Check that the runs codebook includes a run of a single zero
+ if( single_zero_run_flag == false )
+ {
+ assert(false);
+ return_code = CODEC_ERROR_UNEXPECTED;
+ }
+
+ // Sort the codewords into decreasing run length
+ SortDecreasingRunLength(runs_codebook, runs_codebook_count);
+
+ // The last code must be for a single run
+ assert(runs_codebook[runs_codebook_count - 1].count == 1);
+
+ // Fill the lookup table with codes for runs indexed by the run length
+ FillRunLengthEncodingTable(runs_codebook, runs_codebook_count, output_codes, output_length);
+
+ // Free the space used for the sorted codewords
+ allocator->Free(runs_codebook);
+
+ return return_code;
+}
+
+/*!
+ @brief Sort the codebook into decreasing length of the run
+*/
+CODEC_ERROR SortDecreasingRunLength(RLC *codebook, int length)
+{
+ int i;
+ int j;
+
+ // Perform a simple bubble sort since the codebook may already be sorted
+ for (i = 0; i < length; i++)
+ {
+ for (j = i+1; j < length; j++)
+ {
+ // Should not have more than one codebook entry with the same run length
+ assert(codebook[i].count != codebook[j].count);
+
+ // Exchange codebook entries if the current entry is smaller
+ if (codebook[i].count < codebook[j].count)
+ {
+ int size = codebook[i].size;
+ uint32_t bits = codebook[i].bits;
+ int count = codebook[i].count;
+
+ codebook[i].size = codebook[j].size;
+ codebook[i].bits = codebook[j].bits;
+ codebook[i].count = codebook[j].count;
+
+ codebook[j].size = size;
+ codebook[j].bits = bits;
+ codebook[j].count = count;
+ }
+ }
+
+ // After two iterations that last two items should be in the proper order
+ assert(i == 0 || codebook[i-1].count > codebook[i].count);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Use a sparse run length code table to create an indexable table for faster encoding
+*/
+CODEC_ERROR FillRunLengthEncodingTable(RLC *codebook, int codebook_length, RLC *table, int table_length)
+{
+ int i; // Index into the lookup table
+ int j; // Index into the codebook
+
+ // Use all of the bits except the sign bit for the codewords
+ int max_code_size = bit_word_count - 1;
+
+ // Check that the input codes are sorted into decreasing run length
+ for (j = 1; j < codebook_length; j++)
+ {
+ RLC *previous = &codebook[j-1];
+ RLC *current = &codebook[j];
+
+ assert(previous->count > current->count);
+ if (! (previous->count > current->count)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+ }
+
+ // The last input code should be the code for a single zero
+ assert(codebook[codebook_length - 1].count == 1);
+
+ // Create the shortest codeword for each table entry
+ for (i = 0; i < table_length; i++)
+ {
+ int length = i; // Length of the run for this table entry
+ uint32_t codeword = 0; // Composite codeword for this run length
+ int codesize = 0; // Number of bits in the composite codeword
+ int remaining; // Remaining run length not covered by the codeword
+
+ remaining = length;
+
+ for (j = 0; j < codebook_length; j++)
+ {
+ int repetition; // Number of times the codeword is used
+ int k;
+
+ // Nothing to do if the remaining run length is zero
+ if (remaining == 0) break;
+
+ // The number of times that the codeword is used is the number
+ // of times that it divides evenly into the remaining run length
+ repetition = remaining / codebook[j].count;
+
+ // Append the codes to the end of the composite codeword
+ for (k = 0; k < repetition; k++)
+ {
+ // Terminate the loop if the codeword will not fit
+ if (codebook[j].size > (max_code_size - codesize))
+ {
+ if (codesize)
+ {
+ remaining -= (k * codebook[j].count);
+ goto next;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Shift the codeword to make room for the appended codes
+ codeword <<= codebook[j].size;
+
+ // Insert the codeword from the codebook at the end of the composite codeword
+ codeword |= codebook[j].bits;
+
+ // Increment the number of bits in the composite codeword
+ codesize += codebook[j].size;
+ }
+
+ // Reduce the run length by the amount that was consumed by the repeated codeword
+ remaining -= (k * codebook[j].count);
+ }
+
+next:
+ // Should have covered the entire run if the last codeword would fit
+ //assert(remaining == 0 || (max_code_size - codesize) < codebook[codebook_length - 1].size);
+
+ // Store the composite run length in the lookup table
+ table[i].bits = codeword;
+ table[i].size = codesize;
+ table[i].count = length - remaining;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Fill lookup table for encoding coefficient magnitudes
+
+ The table for encoding coefficient magnitudes is indexed by the magnitude.
+ Each entry is a codeword and the size in bits.
+
+ @todo Implement cubic companding
+*/
+CODEC_ERROR FillMagnitudeEncodingTable(const CODEBOOK *codebook, VLE *mags_table_entry, int mags_table_length, uint32_t flags)
+{
+ // Get the length of the codebook and a pointer to the entries
+ //int codebook_length = codebook->length;
+ RLV *codebook_entry = (RLV *)((uint8_t *)codebook + sizeof(CODEBOOK));
+
+ int32_t maximum_magnitude_value = 0;
+
+ uint32_t codebook_index;
+
+ int16_t cubic_table[1025];
+ int cubic_table_length = sizeof(cubic_table) / sizeof(cubic_table[0]);
+
+ int mags_table_index;
+
+ // Find the maximum coefficient magnitude in the codebook
+ for (codebook_index = 0; codebook_index < codebook->length; codebook_index++)
+ {
+ // Does this codebook entry correspond to a coefficient magnitude?
+ if (codebook_entry[codebook_index].count == 1)
+ {
+ int32_t codebook_value = codebook_entry[codebook_index].value;
+ if (maximum_magnitude_value < codebook_value) {
+ maximum_magnitude_value = codebook_value;
+ }
+ }
+ }
+ assert(maximum_magnitude_value > 0);
+
+ if (flags & CODESET_FLAGS_COMPANDING_CUBIC)
+ {
+ ComputeCubicTable(cubic_table, cubic_table_length, maximum_magnitude_value);
+ }
+
+ // Fill each table entry with the codeword for that (signed) value
+ for (mags_table_index = 0; mags_table_index < mags_table_length; mags_table_index++)
+ {
+ // Compute the magnitude that corresponds to this index
+ int32_t magnitude = mags_table_index;
+ uint32_t codeword;
+ int codesize;
+
+ // Apply the companding curve
+ if (flags & CODESET_FLAGS_COMPANDING_CUBIC)
+ {
+ // Apply a cubic companding curve
+ assert(magnitude < cubic_table_length);
+ magnitude = cubic_table[magnitude];
+ }
+ else if (flags & CODESET_FLAGS_COMPANDING_NONE)
+ {
+ // Do not apply a companding curve
+ }
+ else
+ {
+ // Apply an old-style companding curve
+ magnitude = CompandedValue(magnitude);
+ }
+
+ // Is the magnitude larger than the number of entries in the codebook?
+ if (magnitude > maximum_magnitude_value) {
+ magnitude = maximum_magnitude_value;
+ }
+
+ // Find the codebook entry corresponding to this coefficient magnitude
+ codeword = 0;
+ codesize = 0;
+ for (codebook_index = 0; codebook_index < codebook->length; codebook_index++)
+ {
+ if (codebook_entry[codebook_index].value == magnitude)
+ {
+ assert(codebook_entry[codebook_index].count == 1);
+ codeword = codebook_entry[codebook_index].bits;
+ codesize = codebook_entry[codebook_index].size;
+ break;
+ }
+ }
+ assert(0 < codesize && codesize <= 32);
+
+ mags_table_entry[mags_table_index].bits = codeword;
+ mags_table_entry[mags_table_index].size = codesize;
+
+ }
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_encoder/codebooks.h b/gpr/source/lib/vc5_encoder/codebooks.h
new file mode 100755
index 0000000..dc8757a
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/codebooks.h
@@ -0,0 +1,71 @@
+/*! @file codebooks.h
+ *
+ * @brief Declaration of the routines for computing the encoding tables from a codebook.
+
+ * A codebooks contains the variable-length codes for coefficient magnitudes, runs
+ * of zeros, and special codewords that mark entropy codec locations in bitstream.
+
+ * The codebook is used to create tables and simplify entropy coding of signed values
+ * and runs of zeros.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEBOOKS_H
+#define CODEBOOKS_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /*!
+ Codeset data structure that is used by the encoder
+ */
+ typedef struct encoder_codeset {
+
+ const char *title; //!< Identifying string for the codeset
+
+ const CODEBOOK *codebook; //!< Codebook for runs and magnitudes
+
+ uint32_t flags; //!< Encoding flags (see the codeset flags)
+
+ const MAGS_TABLE *mags_table; //!< Table for encoding coefficient magnitudes
+
+ const RUNS_TABLE *runs_table; //!< Table for encoding runs of zeros
+
+ } ENCODER_CODESET;
+
+ extern ENCODER_CODESET encoder_codeset_17;
+
+ CODEC_ERROR PrepareCodebooks(const gpr_allocator *allocator, ENCODER_CODESET *cs);
+
+ CODEC_ERROR ReleaseCodebooks(gpr_allocator *allocator, ENCODER_CODESET *cs);
+
+ CODEC_ERROR ComputeRunLengthCodeTable(const gpr_allocator *allocator,
+ RLV *input_codes, int input_length,
+ RLC *output_codes, int output_length);
+
+ CODEC_ERROR SortDecreasingRunLength(RLC *codebook, int length);
+
+ CODEC_ERROR FillRunLengthEncodingTable(RLC *codebook, int codebook_length,
+ RLC *table, int table_length);
+
+ CODEC_ERROR FillMagnitudeEncodingTable(const CODEBOOK *codebook, VLE *table, int size, uint32_t flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CODEBOOKS_H
diff --git a/gpr/source/lib/vc5_encoder/component.c b/gpr/source/lib/vc5_encoder/component.c
new file mode 100755
index 0000000..72c33ed
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/component.c
@@ -0,0 +1,403 @@
+/*! @file component.c
+ *
+ * @brief Implementation of the inverse component transform and inverse component permutation.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+/*!
+ @brief Initialize a component transform
+ */
+CODEC_ERROR InitComponentTransform(COMPONENT_TRANSFORM *transform)
+{
+ if (transform != NULL)
+ {
+ transform->component_count = 0;
+ transform->transform_matrix = NULL;
+ transform->transform_offset = NULL;
+ transform->transform_scale = NULL;
+ return CODEC_ERROR_OKAY;
+ }
+ return CODEC_ERROR_UNEXPECTED;
+}
+
+/*!
+ @brief Initialize a component permutation
+ */
+CODEC_ERROR InitComponentPermutation(COMPONENT_PERMUTATION *permutation)
+{
+ if (permutation != NULL)
+ {
+ permutation->component_count = 0;
+ permutation->permutation_array = NULL;
+ return CODEC_ERROR_OKAY;
+ }
+ return CODEC_ERROR_UNEXPECTED;
+}
+
+/*!
+ @brief Allocate the arrays in a component transform
+
+ The allocated arrays in the component transform are initialized to all zeros.
+ */
+CODEC_ERROR AllocateComponentTransform(gpr_allocator *allocator, COMPONENT_TRANSFORM *transform, int component_count)
+{
+ size_t transform_matrix_size = component_count * component_count * sizeof(uint16_t);
+ size_t transform_offset_size = component_count * sizeof(uint16_t);
+ size_t transform_scale_size = component_count * sizeof(uint16_t);
+
+ transform->transform_matrix = (uint16_t *)allocator->Alloc(transform_matrix_size);
+ transform->transform_offset = (uint16_t *)allocator->Alloc(transform_offset_size);
+ transform->transform_scale = (uint16_t *)allocator->Alloc(transform_scale_size);
+
+ if (transform->transform_matrix == NULL ||
+ transform->transform_offset == NULL ||
+ transform->transform_scale == NULL) {
+
+ //TODO: Should clean up the partially allocated transform arrays
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ transform->component_count = component_count;
+
+ memset(transform->transform_matrix, 0, transform_matrix_size);
+ memset(transform->transform_offset, 0, transform_offset_size);
+ memset(transform->transform_scale, 0, transform_scale_size);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Allocate the arrays in a component permutation
+
+ The allocated arrays in the component permutation are initialized to all zeros.
+ */
+CODEC_ERROR AllocateComponentPermutation(gpr_allocator *allocator, COMPONENT_PERMUTATION *permutation, int component_count)
+{
+ size_t permutation_array_size = component_count * sizeof(uint16_t);
+
+ permutation->permutation_array = (uint16_t *)allocator->Alloc(permutation_array_size);
+ if (permutation->permutation_array == NULL) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ permutation->component_count = component_count;
+
+ memset(permutation->permutation_array, 0, permutation_array_size);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Release the arrays in a component transform
+ */
+CODEC_ERROR ReleaseComponentTransform(gpr_allocator *allocator, COMPONENT_TRANSFORM *transform)
+{
+ if (transform != NULL)
+ {
+ allocator->Free(transform->transform_matrix);
+ allocator->Free(transform->transform_offset);
+ allocator->Free(transform->transform_scale);
+ memset(transform, 0, sizeof(COMPONENT_TRANSFORM));
+ }
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Release the arrays in a component permutation
+ */
+CODEC_ERROR ReleaseComponentPermutation(gpr_allocator *allocator, COMPONENT_PERMUTATION *permutation)
+{
+ if (permutation != NULL)
+ {
+ allocator->Free(permutation->permutation_array);
+ memset(permutation, 0, sizeof(COMPONENT_PERMUTATION));
+ }
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize a component transform to the identity transform
+ */
+CODEC_ERROR InitComponentTransformIdentity(COMPONENT_TRANSFORM *transform, int component_count, gpr_allocator *allocator)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ int component_index;
+
+ InitComponentTransform(transform);
+ error = AllocateComponentTransform(allocator, transform, component_count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ for (component_index = 0; component_index < component_count; component_index++)
+ {
+ // Compute the index to the diagonal element in the matrix
+ int array_index = component_index * component_count + component_index;
+ transform->transform_matrix[array_index] = 1;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize a component transform to the identity permutation
+
+ */
+CODEC_ERROR InitComponentPermutationIdentity(COMPONENT_PERMUTATION *permutation, int component_count, gpr_allocator *allocator)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ int component_index;
+
+ InitComponentPermutation(permutation);
+ error = AllocateComponentPermutation(allocator, permutation, component_count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ for (component_index = 0; component_index < component_count; component_index++)
+ {
+ permutation->permutation_array[component_index] = component_index;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+
+/*!
+ @brief Initialize a component transform to known values for testing
+ */
+CODEC_ERROR InitComponentTransformTesting(COMPONENT_TRANSFORM *transform, int component_count, gpr_allocator *allocator)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ int row;
+ int column;
+
+ InitComponentTransform(transform);
+ error = AllocateComponentTransform(allocator, transform, component_count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ for (row = 0; row < component_count; row++)
+ {
+ for (column = 0; column < component_count; column++)
+ {
+ // Compute the index to the element in the matrix
+ int array_index = row * component_count + column;
+ transform->transform_matrix[array_index] = array_index;
+ }
+
+ transform->transform_offset[row] = (component_count - row);
+ transform->transform_scale[row] = row + 1;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Initialize a component transform to known values for testing
+
+ */
+CODEC_ERROR InitComponentPermutationTesting(COMPONENT_PERMUTATION *permutation, int component_count, gpr_allocator *allocator)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ int component_index;
+
+ InitComponentPermutation(permutation);
+ error = AllocateComponentPermutation(allocator, permutation, component_count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ for (component_index = 0; component_index < component_count; component_index++)
+ {
+ permutation->permutation_array[component_index] = component_count - component_index - 1;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return true if the component transform is the identity transform
+ */
+bool IsComponentTransformIdentity(COMPONENT_TRANSFORM *transform)
+{
+ int component_count;
+ int component_row;
+ int component_column;
+
+ // A null transform is equivalent to the identity transform
+ if (transform == NULL) return true;
+
+ component_count = transform->component_count;
+
+ for (component_row = 0; component_row < component_count; component_row++)
+ {
+ // Is the transform matrix the identity matrix?
+ for (component_column = 0; component_column < component_count; component_column++)
+ {
+ // Compute the index to the component element in the transform matrix
+ int array_index = component_row * component_count + component_column;
+
+ if (component_row == component_column)
+ {
+ if (transform->transform_matrix[array_index] != 1) return false;
+ }
+ else
+ {
+ if (transform->transform_matrix[array_index] != 0) return false;
+ }
+ }
+
+ // Is the transform offset zero?
+ if (transform->transform_offset != 0) return false;
+
+ // Is the scale factor zero?
+ if (transform->transform_scale != 0) return false;
+ }
+
+ // The component transform is the identity transform
+ return true;
+}
+
+/*!
+ @brief Allocate the arrays in a component permutation
+ */
+bool IsComponentPermutationIdentity(COMPONENT_PERMUTATION *permutation)
+{
+ int component_count;
+ int component_index;
+
+ // A null permutation is equivalent to the identity permutation
+ if (permutation == NULL) {
+ return true;
+ }
+
+ component_count = permutation->component_count;
+
+ for (component_index = 0; component_index < component_count; component_index++)
+ {
+ if (permutation->permutation_array[component_index] != component_index) {
+ return false;
+ }
+ }
+
+ // The component permutation is the identity permutation
+ return true;
+}
+
+/*!
+ @brief Write the component transform to the bitstream
+
+ @todo Use the InverseTransform16 syntax element if any values are larger than a single byte
+ */
+CODEC_ERROR WriteComponentTransform(COMPONENT_TRANSFORM *transform, BITSTREAM *stream)
+{
+ if (transform != NULL)
+ {
+ const int component_count = transform->component_count;
+ const size_t chunk_payload_size = (component_count * component_count + 2 * component_count) * sizeof(uint8_t);
+ const size_t chunk_payload_padding = sizeof(SEGMENT) - (chunk_payload_size % sizeof(SEGMENT));
+ const int chunk_payload_length = (int)((chunk_payload_size + sizeof(SEGMENT) - 1) / sizeof(SEGMENT));
+ int i;
+
+ // Write the tag value pair for the small chunk element for the component transform
+ PutTagPair(stream, CODEC_TAG_InverseTransform, chunk_payload_length);
+
+ for (i = 0; i < component_count; i++)
+ {
+ int offset_value;
+ int scale_value;
+
+ // Write the row at this index in the transform matrix
+ int j;
+
+ for (j = 0; j < component_count; j++)
+ {
+ int array_index = i * component_count + j;
+ int array_value = transform->transform_matrix[array_index];
+
+ assert(INT8_MIN <= array_value && array_value <= INT8_MAX);
+ PutBits(stream, array_value, 8);
+ }
+
+ // Write the offset
+ offset_value = transform->transform_offset[i];
+ assert(INT8_MIN <= offset_value && offset_value <= INT8_MAX);
+ PutBits(stream, offset_value, 8);
+
+ // Write the scale
+ scale_value = transform->transform_scale[i];
+ assert(0 <= scale_value && scale_value <= UINT8_MAX);
+ PutBits(stream, scale_value, 8);
+ }
+
+ // Pad the remainer of the chunk payload with zeros
+ for (i = 0; i < (int)chunk_payload_padding; i++) {
+ PutBits(stream, 0, 8);
+ }
+
+ // Check that the bitstream is aligned on a segment boundary
+ assert(IsAlignedSegment(stream));
+ if (! (IsAlignedSegment(stream))) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_UNEXPECTED;
+}
+
+/*!
+ @brief Write the component permutation to the bitstream
+ */
+CODEC_ERROR WriteComponentPermutation(COMPONENT_PERMUTATION *permutation, BITSTREAM *stream)
+{
+ if (permutation != NULL)
+ {
+ const int component_count = permutation->component_count;
+ const size_t chunk_payload_size = component_count * sizeof(uint8_t);
+ const size_t chunk_payload_padding = sizeof(SEGMENT) - (chunk_payload_size % sizeof(SEGMENT));
+ const int chunk_payload_length = (int)((chunk_payload_size + sizeof(SEGMENT) - 1) / sizeof(SEGMENT));
+ int i;
+
+ // Write the tag value pair for the small chunk element for the component transform
+ PutTagPair(stream, CODEC_TAG_InversePermutation, chunk_payload_length);
+
+ for (i = 0; i < component_count; i++)
+ {
+ uint8_t value = (uint8_t)permutation->permutation_array[i];
+ PutBits(stream, value, 8);
+ }
+
+ // Pad the remainer of the chunk payload with zeros
+ for (i = 0; i < (int)chunk_payload_padding; i++) {
+ PutBits(stream, 0, 8);
+ }
+
+ // Check that the bitstream is aligned on a segment boundary
+ assert(IsAlignedSegment(stream));
+ if (! (IsAlignedSegment(stream))) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ return CODEC_ERROR_OKAY;
+ }
+
+ return CODEC_ERROR_UNEXPECTED;
+}
diff --git a/gpr/source/lib/vc5_encoder/component.h b/gpr/source/lib/vc5_encoder/component.h
new file mode 100755
index 0000000..1c194c4
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/component.h
@@ -0,0 +1,100 @@
+/*! @file component.h
+ *
+ * @brief Declaration of routines for the inverse component transform and permutation.
+
+ * A codebooks contains the variable-length codes for coefficient magnitudes, runs
+ * of zeros, and special codewords that mark entropy codec locations in bitstream.
+
+ * The codebook is used to create tables and simplify entropy coding of signed values
+ * and runs of zeros.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+/*!
+ @brief Data structure for the component transform (16 bit precision)
+ */
+typedef struct _component_transform
+{
+ uint16_t component_count;
+ uint16_t *transform_matrix;
+ uint16_t *transform_offset;
+ uint16_t *transform_scale;
+
+} COMPONENT_TRANSFORM;
+
+/*!
+ @brief Data structure for the component permutation
+ */
+typedef struct _component_permutation
+{
+ uint16_t component_count;
+ uint16_t *permutation_array;
+
+} COMPONENT_PERMUTATION;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InitComponentTransform(COMPONENT_TRANSFORM *transform);
+
+ CODEC_ERROR InitComponentPermutation(COMPONENT_PERMUTATION *permutation);
+
+ CODEC_ERROR AllocateComponentTransform(gpr_allocator *allocator,
+ COMPONENT_TRANSFORM *transform,
+ int component_count);
+
+ CODEC_ERROR AllocateComponentPermutation(gpr_allocator *allocator,
+ COMPONENT_PERMUTATION *permutation,
+ int component_count);
+
+ CODEC_ERROR ReleaseComponentTransform(gpr_allocator *allocator,
+ COMPONENT_TRANSFORM *transform);
+
+ CODEC_ERROR ReleaseComponentPermutation(gpr_allocator *allocator,
+ COMPONENT_PERMUTATION *permutation);
+
+ CODEC_ERROR InitComponentTransformIdentity(COMPONENT_TRANSFORM *transform,
+ int component_count,
+ gpr_allocator *allocator);
+
+ CODEC_ERROR InitComponentPermutationIdentity(COMPONENT_PERMUTATION *permutation,
+ int component_count,
+ gpr_allocator *allocator);
+
+ CODEC_ERROR InitComponentTransformTesting(COMPONENT_TRANSFORM *transform,
+ int component_count,
+ gpr_allocator *allocator);
+
+ CODEC_ERROR InitComponentPermutationTesting(COMPONENT_PERMUTATION *permutation,
+ int component_count,
+ gpr_allocator *allocator);
+
+ bool IsComponentTransformIdentity(COMPONENT_TRANSFORM *transform);
+
+ bool IsComponentPermutationIdentity(COMPONENT_PERMUTATION *permutation);
+
+ CODEC_ERROR WriteComponentTransform(COMPONENT_TRANSFORM *transform, BITSTREAM *stream);
+
+ CODEC_ERROR WriteComponentPermutation(COMPONENT_PERMUTATION *permutation, BITSTREAM *stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // COMPONENT_H
diff --git a/gpr/source/lib/vc5_encoder/encoder.c b/gpr/source/lib/vc5_encoder/encoder.c
new file mode 100755
index 0000000..0701a4d
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/encoder.c
@@ -0,0 +1,2555 @@
+/*! @file encoder.c
+ *
+ * @brief Implementation of functions for encoding samples.
+ *
+ * Encoded samples must be aligned on a four byte boundary.
+ * Any constraints on the alignment of data within the sample
+ * are handled by padding the sample to the correct alignment.
+ *
+ * Note that the encoded dimensions are the actual dimensions of each channel
+ * (or the first channel in the case of 4:2:2 sampling) in the encoded sample.
+ * The display offsets and dimensions specify the portion of the encoded frame
+ * that should be displayed, but in the case of a Bayer image the display
+ * dimensions are doubled to account for the effects of the demosaic filter.
+ * If a Bayer image is encoded to Bayer format (no demosaic filter applied),
+ * then the encoded dimensions will be the same as grid of Bayer quads, less
+ * any padding required during encoding, but the display dimensions and
+ * offset will be reported as if a demosiac filter were applied to scale the
+ * encoded frame to the display dimensions (doubling the width and height).
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+#if ENABLED(NEON)
+#include <arm_neon.h>
+#endif
+
+/*!
+ @brief Align the bitstream to a byte boundary
+
+ Enough bits are written to the bitstream to align the
+ bitstream to the next byte.
+ */
+static CODEC_ERROR AlignBitsByte(BITSTREAM *bitstream)
+{
+ if (bitstream->count > 0 && (bitstream->count % 8) != 0)
+ {
+ // Compute the number of bits of padding
+ BITCOUNT count = (8 - (bitstream->count % 8));
+ PutBits(bitstream, 0, count);
+ }
+ assert((bitstream->count % 8) == 0);
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Align the bitstream to the next segment
+
+ The corresponding function in the existing codec flushes the bitstream.
+
+ @todo Is it necessary to flush the bitstream (and the associated byte stream)
+ after aligning the bitstream to a segment boundary?
+ */
+static CODEC_ERROR AlignBitsSegment(BITSTREAM *bitstream)
+{
+ STREAM *stream = bitstream->stream;
+ size_t byte_count;
+
+ // Byte align the bitstream
+ AlignBitsByte(bitstream);
+ assert((bitstream->count % 8) == 0);
+
+ // Compute the number of bytes in the bit buffer
+ byte_count = bitstream->count / 8;
+
+ // Add the number of bytes written to the stream
+ byte_count += stream->byte_count;
+
+ while ((byte_count % sizeof(TAGVALUE)) != 0)
+ {
+ PutBits(bitstream, 0, 8);
+ byte_count++;
+ }
+
+ // The bitstream should be aligned to the next segment
+ assert((bitstream->count == 0) || (bitstream->count == bit_word_count));
+ assert((byte_count % sizeof(TAGVALUE)) == 0);
+
+ return CODEC_ERROR_OKAY;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Set default values for the pattern element structure
+
+ Some image formats imply specific parameters for the dimensions of the
+ pattern elements and the number of components per sample. If the pattern
+ element structure has not been fully specified by the command-line
+ arguments, then missing values can be filled in from the default values
+ for the image format.
+ */
+bool SetImageFormatDefaults(ENCODER *encoder)
+{
+ switch (encoder->image_format)
+ {
+#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_COLOR_SAMPLING))
+ {
+ // The components per sample parameter is not applicable to VC-5 Part 4 bitstreams
+ assert(encoder->components_per_sample == 0);
+ encoder->components_per_sample = 0;
+ }
+ else
+ {
+ // Set the default components per sample assuming no alpha channel
+ if (encoder->components_per_sample == 0) {
+ encoder->components_per_sample = 3;
+ }
+ }
+#else
+ // Set the default components per sample assuming no alpha channel
+ if (encoder->components_per_sample == 0) {
+ encoder->components_per_sample = 3;
+ }
+#endif
+ return true;
+
+ case IMAGE_FORMAT_RAW:
+ if (encoder->pattern_width == 0) {
+ encoder->pattern_width = 2;
+ }
+
+ if (encoder->pattern_height == 0) {
+ encoder->pattern_height = 2;
+ }
+
+ if (encoder->components_per_sample == 0) {
+ encoder->components_per_sample = 1;
+ }
+
+ return true;
+
+ default:
+ // Unable to set default values for the pattern elements
+ return false;
+ }
+}
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+/*!
+ @brief Check for inconsistent values for the parameters specified on the command-line
+
+ This routine looks for inconsistencies between the image format, the dimensions of the
+ pattern elements, and the number of components per sample.
+ */
+bool CheckImageFormatParameters(ENCODER *encoder)
+{
+ switch (encoder->image_format)
+ {
+ case IMAGE_FORMAT_RAW:
+
+ if (encoder->pattern_width != 2) {
+ return false;
+ }
+
+ if (encoder->pattern_height != 2) {
+ return false;
+ }
+
+ if (encoder->components_per_sample != 1) {
+ return false;
+ }
+
+ // The parameters for the Bayer image format are correct
+ return true;
+
+ default:
+ // Cannot verify the parameters for an unknown image format
+ return false;
+
+ }
+}
+#endif
+
+/*!
+ @brief Prepare the encoder state
+*/
+CODEC_ERROR PrepareEncoderState(ENCODER *encoder,
+ const UNPACKED_IMAGE *image,
+ const ENCODER_PARAMETERS *parameters)
+{
+ CODEC_STATE *codec = &encoder->codec;
+ int channel_count = image->component_count;
+ int channel_number;
+
+ // Set the default value for the number of bits per lowpass coefficient
+ PRECISION lowpass_precision = 16;
+
+ if (parameters->encoded.lowpass_precision > 0) {
+ lowpass_precision = parameters->encoded.lowpass_precision;
+ }
+
+ for (channel_number = 0; channel_number < channel_count; channel_number++)
+ {
+ DIMENSION width = image->component_array_list[channel_number].width;
+ DIMENSION height = image->component_array_list[channel_number].height;
+ PRECISION bits_per_component = image->component_array_list[channel_number].bits_per_component;
+
+ // Copy the component array parameters into the encoder state
+ encoder->channel[channel_number].width = width;
+ encoder->channel[channel_number].height = height;
+ encoder->channel[channel_number].bits_per_component = bits_per_component;
+
+ // The lowpass bands in all channels are encoded with the same precision
+ encoder->channel[channel_number].lowpass_precision = lowpass_precision;
+ }
+
+ // Record the number of channels in the encoder state
+ encoder->channel_count = channel_count;
+
+ // The encoder uses three wavelet transform levels for each channel
+ encoder->wavelet_count = 3;
+
+ // Set the channel encoding order
+ if (parameters->channel_order_count > 0)
+ {
+ // Use the channel order specified by the encoding parameters
+ encoder->channel_order_count = parameters->channel_order_count;
+ memcpy(encoder->channel_order_table, parameters->channel_order_table, sizeof(encoder->channel_order_table));
+ }
+ else
+ {
+ // Use the default channel encoding order
+ for (channel_number = 0; channel_number < channel_count; channel_number++)
+ {
+ encoder->channel_order_table[channel_number] = channel_number;
+ }
+ encoder->channel_order_count = channel_count;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ // The actual image dimensions are reported in the bitstream header (VC-5 Part 3)
+ encoder->image_width = parameters->input.width;
+ encoder->image_height = parameters->input.height;
+ encoder->pattern_width = parameters->pattern_width;
+ encoder->pattern_height = parameters->pattern_height;
+ encoder->components_per_sample = parameters->components_per_sample;
+ encoder->image_format = parameters->encoded.format;
+ encoder->max_bits_per_component = MaxBitsPerComponent(image);
+
+ // Set default parameters for the image format
+ SetImageFormatDefaults(encoder);
+
+ if (!CheckImageFormatParameters(encoder)) {
+ return CODEC_ERROR_BAD_IMAGE_FORMAT;
+ }
+#else
+ // The dimensions of the image is the maximum of the channel dimensions (VC-5 Part 1)
+ GetMaximumChannelDimensions(image, &encoder->image_width, &encoder->image_height);
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ // Interlaced images are encoded as separate layers
+ encoder->progressive = parameters->progressive;
+ encoder->top_field_first = TRUE;
+ encoder->frame_inverted = FALSE;
+ encoder->progressive = 1;
+
+ // Set the number of layers (sub-samples) in the encoded sample
+ encoder->layer_count = parameters->layer_count;
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ // by default, all sections are enabled
+ encoder->enabled_sections = parameters->enabled_sections;
+#endif
+
+ // Initialize the codec state with the default parameters used by the decoding process
+ return PrepareCodecState(codec);
+}
+
+/*!
+ @brief Initialize the encoder data structure
+
+ This routine performs the same function as a C++ constructor.
+ The encoder is initialized with default values that are replaced
+ by the parameters used to prepare the encoder (see @ref PrepareEncoder).
+
+ This routine does not perform all of the initializations required
+ to prepare the encoder data structure for decoding a sample.
+*/
+CODEC_ERROR InitEncoder(ENCODER *encoder, const gpr_allocator *allocator, const VERSION *version)
+{
+ assert(encoder != NULL);
+ if (! (encoder != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ memset(encoder, 0, sizeof(ENCODER));
+
+ // Assign a memory allocator to the encoder
+ encoder->allocator = (gpr_allocator *)allocator;
+
+ // Write debugging information to standard output
+ encoder->logfile = stdout;
+
+ if (version)
+ {
+ // Store the version number in the encoder
+ memcpy(&encoder->version, version, sizeof(encoder->version));
+ }
+ else
+ {
+ // Clear the version number in the encoder
+ memset(&encoder->version, 0, sizeof(encoder->version));
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Encode the image into the output stream
+
+ This is a convenience routine for applications that use a byte stream to
+ represent a memory buffer or binary file that will store the encoded image.
+
+ The image is unpacked into a set of component arrays by the image unpacking
+ process invoked by calling the routine @ref ImageUnpackingProcess. The image
+ unpacking process is informative and is not part of the VC-5 standard.
+
+ The main entry point for encoding the component arrays output by the image
+ unpacking process is @ref EncodingProcess.
+*/
+CODEC_ERROR EncodeImage(IMAGE *image, STREAM *stream, RGB_IMAGE *rgb_image, ENCODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Allocate data structures for the encoder state and the bitstream
+ ENCODER encoder;
+ BITSTREAM bitstream;
+
+ SetupEncoderLogCurve();
+
+ UNPACKED_IMAGE unpacked_image;
+
+ // Unpack the image into a set of component arrays
+ error = ImageUnpackingProcess(image, &unpacked_image, parameters, &parameters->allocator);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Initialize the bitstream data structure
+ InitBitstream(&bitstream);
+
+ // Bind the bitstream to the byte stream
+ error = AttachBitstream(&bitstream, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Encode the component arrays into the bitstream
+ error = EncodingProcess(&encoder, &unpacked_image, &bitstream, parameters);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ if( rgb_image != NULL && parameters->rgb_resolution == GPR_RGB_RESOLUTION_SIXTEENTH )
+ { // Thumbnail
+ SetupDecoderLogCurve();
+
+ WaveletToRGB(parameters->allocator,
+ encoder.transform[0].wavelet[2]->data[LL_BAND], encoder.transform[1].wavelet[2]->data[LL_BAND], encoder.transform[2].wavelet[2]->data[LL_BAND],
+ encoder.transform[0].wavelet[2]->width, encoder.transform[0].wavelet[2]->height, encoder.transform[0].wavelet[2]->width,
+ rgb_image, 14, 8, &parameters->rgb_gain );
+ }
+
+ error = ReleaseComponentArrays( &parameters->allocator, &unpacked_image, unpacked_image.component_count );
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Release any resources allocated by the bitstream
+ ReleaseBitstream(&bitstream);
+
+ // Release any resources allocated by the encoder
+ ReleaseEncoder(&encoder);
+
+ return error;
+}
+
+/*!
+ @brief Reference implementation of the VC-5 encoding process.
+
+ The encoder takes input image in the form of a list of component arrays
+ produced by the image unpacking process and encodes the image into the
+ bitstream.
+
+ External parameters are used to initialize the encoder state.
+
+ The encoder state determines how the image is encoded int the bitstream.
+*/
+CODEC_ERROR EncodingProcess(ENCODER *encoder,
+ const UNPACKED_IMAGE *image,
+ BITSTREAM *bitstream,
+ const ENCODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Initialize the encoder using the parameters provided by the application
+ error = PrepareEncoder(encoder, image, parameters);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (encoder->image_format == IMAGE_FORMAT_UNKNOWN) {
+ return CODEC_ERROR_BAD_IMAGE_FORMAT;
+ }
+ if ( parameters->verbose_flag )
+ {
+ LogPrint("Pattern width: %d\n", encoder->pattern_width);
+ LogPrint("Pattern height: %d\n", encoder->pattern_height);
+
+ if (!IsPartEnabled(encoder->enabled_parts, VC5_PART_COLOR_SAMPLING)) {
+ LogPrint("Components per sample: %d\n", encoder->components_per_sample);
+ }
+ LogPrint("Internal precision: %d\n", encoder->internal_precision);
+
+ LogPrint("\n");
+ }
+#endif
+
+ // Write the bitstream start marker
+ PutBitstreamStartMarker(bitstream);
+
+ // Allocate six pairs of lowpass and highpass buffers for each channel
+ AllocateEncoderHorizontalBuffers(encoder);
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+
+ if (!IsPartEnabled(encoder.enabled_parts, VC5_PART_LAYERS) || encoder.layer_count == 1)
+ {
+ // Encode the image as a single layer in the sample
+ error = EncodeSingleImage(encoder, ImageData(image), image->pitch, &bitstream);
+ }
+ else
+ {
+ // Each layer encodes a separate frame
+ IMAGE *image_array[MAX_LAYER_COUNT];
+ memset(image_array, 0, sizeof(image_array));
+
+ // The encoding parameters must include a decompositor
+ assert (parameters->decompositor != NULL);
+
+ // Decompose the frame into individual frames for each layer
+ error = parameters->decompositor(image, image_array, encoder.layer_count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Encode each frame as a separate layer in the sample
+ error = EncodeMultipleImages(encoder, image_array, encoder.layer_count, &bitstream);
+ }
+#else
+
+ // Encode one image into the bitstream
+ error = EncodeSingleImage(encoder, image, bitstream);
+
+#endif
+
+ DeallocateEncoderHorizontalBuffers(encoder);
+
+ return error;
+}
+
+/*!
+ @brief Initialize the encoder using the specified parameters
+
+ It is important to use the correct encoded image dimensions (including padding)
+ and the correct encoded format to initialize the encoder. The decoded image
+ dimensions must be adjusted to account for a lower decoded resolution if applicable.
+
+ It is expected that the parameters data structure may change over time
+ with additional or different fields, depending on the codec profile or
+ changes made to the codec during further development. The parameters
+ data structure may have a version number or may evolve into a dictionary
+ of key-value pairs with missing keys indicating that a default value
+ should be used.
+
+ @todo Add more error checking to this top-level routine
+*/
+CODEC_ERROR PrepareEncoder(ENCODER *encoder,
+ const UNPACKED_IMAGE *image,
+ const ENCODER_PARAMETERS *parameters)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ VERSION version = VERSION_INITIALIZER(VC5_VERSION_MAJOR, VC5_VERSION_MINOR, VC5_VERSION_REVISION, 0);
+ PRECISION max_bits_per_component = MaxBitsPerComponent(image);
+
+ // Initialize the encoder data structure
+ InitEncoder(encoder, &parameters->allocator, &version);
+
+ // Set the mask that specifies which parts of the VC-5 standard are supported
+ encoder->enabled_parts = parameters->enabled_parts;
+
+ // Verify that the enabled parts are correct
+ error = VerifyEnabledParts(encoder->enabled_parts);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Remember the internal precision used by the image unpacking process
+ encoder->internal_precision = minimum(max_bits_per_component, default_internal_precision);
+
+ // Initialize the encoding parameters and the codec state
+ PrepareEncoderState(encoder, image, parameters);
+
+ // Allocate the wavelet transforms
+ AllocEncoderTransforms(encoder);
+
+ // Initialize the quantizer
+ SetEncoderQuantization(encoder, parameters);
+
+ // Initialize the wavelet transforms
+ PrepareEncoderTransforms(encoder);
+
+ // Allocate the scratch buffers used for encoding
+ AllocEncoderBuffers(encoder);
+
+ // Initialize the encoding tables for magnitudes and runs of zeros
+ error = PrepareCodebooks(&parameters->allocator, &encoder_codeset_17 );
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Select the codebook for encoding
+ encoder->codeset = &encoder_codeset_17;
+
+ // The encoder is ready to decode a sample
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Free all resources allocated by the encoder
+*/
+CODEC_ERROR ReleaseEncoder(ENCODER *encoder)
+{
+ if (encoder != NULL)
+ {
+ gpr_allocator *allocator = encoder->allocator;
+ int channel;
+
+ // Free the encoding tables
+ ReleaseCodebooks(allocator, encoder->codeset);
+
+ // Free the wavelet tree for each channel
+ for (channel = 0; channel < MAX_CHANNEL_COUNT; channel++)
+ {
+ ReleaseTransform(allocator, &encoder->transform[channel]);
+ }
+
+ //TODO: Free the encoding buffers
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Encode a single image into the bitstream
+
+ This is the main entry point for encoding a single image into the bitstream.
+ The encoder must have been initialized by a call to @ref PrepareEncoder.
+
+ The unpacked image is the set of component arrays output by the image unpacking
+ process. The bitstream must be initialized and bound to a byte stream before
+ calling this routine.
+*/
+CODEC_ERROR EncodeSingleImage(ENCODER *encoder, const UNPACKED_IMAGE *image, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Write the sample header that is common to all layers
+ error = EncodeBitstreamHeader(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Write the sample extension header to the bitstream
+ error = EncodeExtensionHeader(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Encode each component array as a separate channel in the bitstream
+ error = EncodeMultipleChannels(encoder, image, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Finish the encoded sample after the last layer
+ error = EncodeBitstreamTrailer(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Force any data remaining in the bitstream to be written into the sample
+ FlushBitstream(stream);
+
+ return error;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Encode multiple frames as separate layers in a sample
+
+ The encoder must have been initialized by a call to @ref PrepareEncoder.
+
+ The bitstream must be initialized and bound to a byte stream before
+ calling this routine.
+*/
+CODEC_ERROR EncodeMultipleFrames(ENCODER *encoder, IMAGE *image_array[], int frame_count, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ //CODEC_STATE *codec = &encoder->codec;
+
+ int layer_index;
+
+ // The number of frames must match the number of layers in the sample
+ assert(frame_count == encoder->layer_count);
+
+ // Initialize the codec state
+ PrepareEncoderState(encoder);
+
+ // Write the bitstream start marker
+ error = PutBitstreamStartMarker(stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Write the bitstream header that is common to all layers
+ error = EncodeBitstreamHeader(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Write the extension header to the bitstream
+ error = EncodeExtensionHeader(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Encode each frame in a separate layer in the sample
+ for (layer_index = 0; layer_index < frame_count; layer_index++)
+ {
+ error = EncodeLayer(encoder, image_array[layer_index]->buffer, image_array[layer_index]->pitch, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+ }
+
+ error = EncodeSampleExtensionTrailer(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Finish the encoded sample after the last layer
+ error = EncodeSampleTrailer(encoder, stream);
+ assert(error == CODEC_ERROR_OKAY);
+ if (! (error == CODEC_ERROR_OKAY)) {
+ return error;
+ }
+
+ // Force any data remaining in the bitstream to be written into the sample
+ FlushBitstream(stream);
+
+ // Check that the sample offset stack has been emptied
+ assert(stream->sample_offset_count == 0);
+
+ //TODO: Any resources need to be released?
+
+ // Done encoding all layers in the sample
+ return error;
+}
+#endif
+
+/*!
+ @brief Initialize the wavelet transforms for encoding
+*/
+CODEC_ERROR PrepareEncoderTransforms(ENCODER *encoder)
+{
+ //int channel_count = encoder->channel_count;
+ int channel_number;
+
+ // Set the prescale and quantization in each wavelet transform
+ for (channel_number = 0; channel_number < encoder->channel_count; channel_number++)
+ {
+ TRANSFORM *transform = &encoder->transform[channel_number];
+
+ // Set the prescaling (may be used in setting the quantization)
+ int bits_per_component = encoder->channel[channel_number].bits_per_component;
+ SetTransformPrescale(transform, bits_per_component);
+
+ //TODO: Are the wavelet scale factors still used?
+
+ // Must set the transform scale if not calling SetTransformQuantization
+ SetTransformScale(transform);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Unpack the image into component arrays for encoding
+*/
+CODEC_ERROR ImageUnpackingProcess(const PACKED_IMAGE *input,
+ UNPACKED_IMAGE *output,
+ const ENCODER_PARAMETERS *parameters,
+ gpr_allocator *allocator)
+{
+ ENABLED_PARTS enabled_parts = parameters->enabled_parts;
+ int channel_count;
+ DIMENSION max_channel_width;
+ DIMENSION max_channel_height;
+ int bits_per_component;
+
+ // The configuration of component arrays is determined by the image format
+ switch (input->format)
+ {
+ case PIXEL_FORMAT_RAW_RGGB_12:
+ case PIXEL_FORMAT_RAW_RGGB_12P:
+ case PIXEL_FORMAT_RAW_RGGB_14:
+ case PIXEL_FORMAT_RAW_GBRG_12:
+ case PIXEL_FORMAT_RAW_GBRG_12P:
+ case PIXEL_FORMAT_RAW_RGGB_16:
+ channel_count = 4;
+ max_channel_width = input->width / 2;
+ max_channel_height = input->height / 2;
+ bits_per_component = 12;
+ break;
+
+ default:
+ assert(0);
+ return CODEC_ERROR_PIXEL_FORMAT;
+ break;
+ }
+
+ // Allocate space for the component arrays
+ AllocateComponentArrays(allocator, output, channel_count, max_channel_width, max_channel_height,
+ input->format, bits_per_component);
+
+
+ // The configuration of component arrays is determined by the image format
+ switch (input->format)
+ {
+ case PIXEL_FORMAT_RAW_RGGB_14:
+ UnpackImage_14(input, output, enabled_parts, true );
+ break;
+
+ case PIXEL_FORMAT_RAW_RGGB_12:
+ UnpackImage_12(input, output, enabled_parts, true );
+ break;
+
+ case PIXEL_FORMAT_RAW_GBRG_12:
+ UnpackImage_12(input, output, enabled_parts, false );
+ break;
+
+ case PIXEL_FORMAT_RAW_RGGB_12P:
+ UnpackImage_12P(input, output, enabled_parts, true );
+ break;
+
+ case PIXEL_FORMAT_RAW_GBRG_12P:
+ UnpackImage_12P(input, output, enabled_parts, false );
+ break;
+
+ default:
+ assert(0);
+ return CODEC_ERROR_PIXEL_FORMAT;
+ break;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+
+
+/*!
+ @brief Insert the header segments that are common to all samples
+
+ This code was derived from PutVideoIntraFrameHeader in the current codec.
+
+ @todo Need to output the channel size table.
+*/
+CODEC_ERROR EncodeBitstreamHeader(ENCODER *encoder, BITSTREAM *stream)
+{
+ CODEC_STATE *codec = &encoder->codec;
+
+ //TAGWORD subband_count = 10;
+ TAGWORD image_width = encoder->image_width;
+ TAGWORD image_height = encoder->image_height;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ TAGWORD image_format = encoder->image_format;
+ TAGWORD pattern_width = encoder->pattern_width;
+ TAGWORD pattern_height = encoder->pattern_height;
+ TAGWORD components_per_sample = encoder->components_per_sample;
+ TAGWORD max_bits_per_component = encoder->max_bits_per_component;
+ TAGWORD default_bits_per_component = max_bits_per_component;
+#else
+ TAGWORD default_bits_per_component = encoder->internal_precision;
+#endif
+
+ // Align the start of the header on a segment boundary
+ AlignBitsSegment(stream);
+
+ // The bitstream should be aligned to a segment boundary
+ assert(IsAlignedSegment(stream));
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_HEADER))
+ {
+ // Write the section header for the bitstream header into the bitstream
+ BeginHeaderSection(encoder, stream);
+ }
+#endif
+
+ // Output the number of channels
+ if (encoder->channel_count != codec->channel_count) {
+ PutTagPair(stream, CODEC_TAG_ChannelCount, encoder->channel_count);
+ codec->channel_count = encoder->channel_count;
+ }
+
+ // Inform the decoder of the maximum component array dimensions
+ PutTagPair(stream, CODEC_TAG_ImageWidth, image_width);
+ PutTagPair(stream, CODEC_TAG_ImageHeight, image_height);
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ PutTagPair(stream, CODEC_TAG_ImageFormat, image_format);
+ PutTagPair(stream, CODEC_TAG_PatternWidth, pattern_width);
+ PutTagPair(stream, CODEC_TAG_PatternHeight, pattern_height);
+ PutTagPair(stream, CODEC_TAG_ComponentsPerSample, components_per_sample);
+ PutTagPair(stream, CODEC_TAG_MaxBitsPerComponent, max_bits_per_component);
+ }
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_LAYERS))
+ {
+ // Output the number of layers in the sample (optional for backward compatibility)
+ //PutTagPairOptional(stream, CODEC_TAG_LAYER_COUNT, layer_count);
+ }
+#endif
+
+ // Record the image dimensions in the codec state
+ codec->image_width = image_width;
+ codec->image_height = image_height;
+
+ // The image dimensions determine the default channel dimensions
+ codec->channel_width = image_width;
+ codec->channel_height = image_height;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ // Record the pattern element parameters in the codec state
+ codec->image_format = image_format;
+ codec->pattern_width = pattern_width;
+ codec->pattern_height = pattern_height;
+ codec->components_per_sample = components_per_sample;
+ codec->max_bits_per_component = (PRECISION)max_bits_per_component;
+ }
+#endif
+
+ // This parameter is the default precision for each channel
+ codec->bits_per_component = default_bits_per_component;
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_HEADER))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Update the section header with the actual size of the bitstream header section
+ EndSection(stream);
+ }
+#endif
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the trailer at the end of the encoded sample
+
+ This routine updates the sample size segment in the sample extension header
+ with the actual size of the encoded sample. The size of the encoded sample
+ does not include the size of the sample header or trailer.
+
+ Note that the trailer may not be necessary as the decoder may stop
+ reading from the sample after it has decoded all of the information
+ required to reconstruct the frame.
+
+ This code was derived from PutVideoIntraFrameTrailer in the current codec.
+*/
+CODEC_ERROR EncodeBitstreamTrailer(ENCODER *encoder, BITSTREAM *stream)
+{
+ AlignBitsSegment(stream);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the unique image identifier
+
+ @todo Should the UMID instance number be a parameter to this routine?
+ */
+static CODEC_ERROR WriteUniqueImageIdentifier(ENCODER *encoder, BITSTREAM *stream)
+{
+ const int UMID_length_byte = 0x13;
+ const int UMID_instance_number = 0;
+
+ // Total length of the unique image identifier chunk payload (in segments)
+ const int identifier_chunk_payload_length = UMID_length + sequence_number_length;
+
+ // Write the tag value pair for the small chunk element for the unique image identifier
+ PutTagPairOptional(stream, CODEC_TAG_UniqueImageIdentifier, identifier_chunk_payload_length);
+
+ // Write the UMID label
+ PutByteArray(stream, UMID_label, sizeof(UMID_label));
+
+ // Write the UMID length byte
+ PutBits(stream, UMID_length_byte, 8);
+
+ // Write the UMID instance number
+ PutBits(stream, UMID_instance_number, 24);
+
+ // Write the image sequence identifier
+ PutByteArray(stream, encoder->image_sequence_identifier, sizeof(encoder->image_sequence_identifier));
+
+ // Write the image sequence number
+ PutLong(stream, encoder->image_sequence_number);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write extra information that follows the sample header into the bitstream
+
+ This routine writes metadata into the sample header extension.
+
+ Metadata includes the unique GUID for each video clip, the number of each video frame,
+ and the timecode (if available). The GUID and frame number pair uniquely identify each
+ frame in the encoded clip.
+
+ This routine also outputs additional information that describes the characterstics of
+ the encoded video in the GOP extension and sample flags.
+
+ The size of the sample extension header is provided by the sample size segment.
+*/
+CODEC_ERROR EncodeExtensionHeader(ENCODER *encoder, BITSTREAM *stream)
+{
+ ENABLED_PARTS enabled_parts = encoder->enabled_parts;
+
+ // Encode the transform prescale for the first channel (assume all channels are the same)
+ TAGWORD prescale_shift = PackTransformPrescale(&encoder->transform[0]);
+
+ // The tag-value pair is required if the encoder is not using the default values
+ //if (IsTransformPrescaleDefault(&encoder->transform[0], TRANSFORM_TYPE_SPATIAL, encoder->encoded.precision))
+ if (IsTransformPrescaleDefault(&encoder->transform[0], encoder->internal_precision))
+ {
+ PutTagPairOptional(stream, CODEC_TAG_PrescaleShift, prescale_shift);
+ }
+ else
+ {
+ PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ WriteUniqueImageIdentifier(encoder, stream);
+ }
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS) &&
+ !IsComponentTransformIdentity(encoder->component_transform))
+ {
+ WriteComponentTransform(encoder->component_transform, stream);
+ }
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(enabled_parts, VC5_PART_IMAGE_FORMATS) &&
+ !IsComponentPermutationIdentity(encoder->component_permutation))
+ {
+ WriteComponentPermutation(encoder->component_permutation, stream);
+ }
+#endif
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the sample extension trailer into the bitstream
+
+ This routine must be called after encoding the sample and before writing the
+ sample trailer, but must only be called if the sample extension header was
+ written into the bitstream.
+*/
+CODEC_ERROR EncodeExtensionTrailer(ENCODER *encoder, BITSTREAM *stream)
+{
+ return CODEC_ERROR_OKAY;
+}
+
+static int32_t GetMultiplier(QUANT divisor)
+{
+ switch (divisor)
+ {
+ case 1:
+ return (uint32_t)(1 << 16);
+
+ case 12:
+ return (1 << 16) / 12;
+
+ case 24:
+ return (1 << 16) / 24;
+
+ case 32:
+ return (1 << 16) / 32;
+
+ case 48:
+ return (1 << 16) / 48;
+
+ case 96:
+ return (1 << 16) / 96;
+
+ case 144:
+ return (1 << 16) / 144;
+
+ default:
+ return (uint32_t)(1 << 16) / divisor;
+ };
+}
+
+/*!
+ @brief Compute the rounding value for quantization
+ */
+static QUANT QuantizerMidpoint(QUANT correction, QUANT divisor)
+{
+ int32_t midpoint = 0;
+
+ if (correction == 2)
+ {
+ midpoint = divisor >> 1;
+
+ // CFEncode_Premphasis_Original
+ if (midpoint) {
+ midpoint--;
+ }
+ }
+ else if (correction > 2 && correction < 9)
+ {
+ midpoint = divisor / correction;
+ }
+
+ return midpoint;
+}
+
+static void GetQuantizationParameters(int32_t midpoint_prequant, QUANT quant[], int32_t* midpoints, int32_t* multipliers)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ midpoints[i] = QuantizerMidpoint(midpoint_prequant, quant[i]);
+ multipliers[i] = GetMultiplier(quant[i]);
+ }
+}
+
+/*!
+ @brief Shift the buffers of horizontal highpass results
+
+ The encoder contains six rows of horizontal lowpass and highpass results
+ for each channel. This routine shifts the buffers by two rows to make
+ room for two more rows of horizontal results for each channel.
+ */
+static void ShiftHorizontalResultBuffers(PIXEL **buffer)
+{
+ PIXEL *buffer01[2];
+
+ memcpy( buffer01, buffer + 0, sizeof(PIXEL*) * 2 );
+
+ memmove( buffer + 0, buffer + 2, sizeof(PIXEL*) * (ROW_BUFFER_COUNT - 2) );
+
+ memcpy( buffer + 4, buffer01, sizeof(PIXEL*) * 2 );
+}
+
+typedef struct _recursive_transform_data
+{
+ PIXEL *input_ptr;
+ DIMENSION input_width;
+ DIMENSION input_height;
+ DIMENSION input_pitch;
+
+ PIXEL *output_ptr[MAX_BAND_COUNT];
+ DIMENSION output_width;
+ DIMENSION output_pitch;
+
+ int32_t prescale;
+
+ int32_t* midpoints;
+ int32_t* multipliers;
+
+ PIXEL **lowpass_buffer;
+ PIXEL **highpass_buffer;
+
+} RECURSIVE_TRANSFORM_DATA;
+
+#define RECURSIVE 1
+
+static void ForwardWaveletTransformRecursive(RECURSIVE_TRANSFORM_DATA *transform_data, int wavelet_stage, uint32_t start_row, uint32_t end_row)
+{
+ uint32_t input_row_index = start_row;
+
+ PIXEL *input_ptr = transform_data[wavelet_stage].input_ptr;
+ DIMENSION input_width = transform_data[wavelet_stage].input_width;
+ DIMENSION input_height = transform_data[wavelet_stage].input_height;
+ DIMENSION input_pitch = transform_data[wavelet_stage].input_pitch;
+
+ PIXEL **output_ptr = transform_data[wavelet_stage].output_ptr;
+ DIMENSION output_width = transform_data[wavelet_stage].output_width;
+ DIMENSION output_pitch = transform_data[wavelet_stage].output_pitch;
+
+ int32_t* midpoints = transform_data[wavelet_stage].midpoints;
+ int32_t* multipliers = transform_data[wavelet_stage].multipliers;
+
+ PIXEL **lowpass_buffer = transform_data[wavelet_stage].lowpass_buffer;
+ PIXEL **highpass_buffer = transform_data[wavelet_stage].highpass_buffer;
+
+ int32_t prescale = transform_data[wavelet_stage].prescale;
+
+ uint32_t bottom_input_row = ((input_height % 2) == 0) ? input_height - 2 : input_height - 1;
+
+ uint32_t last_middle_row = bottom_input_row - 2;
+
+ end_row = minimum( last_middle_row, end_row);
+
+ // --- TOP ROW
+ if( input_row_index == 0 )
+ {
+ int row;
+
+ for (row = 0; row < ROW_BUFFER_COUNT; row++)
+ {
+ PIXEL *input_row_ptr = (PIXEL *)((uintptr_t)input_ptr + row * input_pitch);
+
+ FilterHorizontalRow(input_row_ptr, lowpass_buffer[row], highpass_buffer[row], input_width, prescale);
+ }
+
+ // Process the first row as a special case for the boundary condition
+ FilterVerticalTopRow(lowpass_buffer, highpass_buffer, output_ptr, output_width, output_pitch, midpoints, multipliers, input_row_index );
+ input_row_index += 2;
+ }
+
+ // --- MIDDLE ROWS
+ for (; input_row_index <= end_row; input_row_index += 2)
+ {
+ // Check for errors in the row calculation
+ assert((input_row_index % 2) == 0);
+
+ FilterVerticalMiddleRow(lowpass_buffer, highpass_buffer, output_ptr, output_width, output_pitch, midpoints, multipliers, input_row_index );
+
+ if (input_row_index < last_middle_row)
+ {
+ int row;
+
+ ShiftHorizontalResultBuffers(lowpass_buffer);
+ ShiftHorizontalResultBuffers(highpass_buffer);
+
+ // Get two more rows of horizontal lowpass and highpass results
+ for (row = 4; row < ROW_BUFFER_COUNT; row++)
+ {
+ int next_input_row = minimum( input_row_index + row, input_height - 1 );
+
+ PIXEL *input_row_ptr = (PIXEL *)((uintptr_t)input_ptr + next_input_row * input_pitch);
+
+ FilterHorizontalRow(input_row_ptr, lowpass_buffer[row], highpass_buffer[row], input_width, prescale);
+ }
+ }
+ }
+
+ // --- BOTTOM ROW
+ if( input_row_index == bottom_input_row )
+ {
+ FilterVerticalBottomRow(lowpass_buffer, highpass_buffer, output_ptr, output_width, output_pitch, midpoints, multipliers, input_row_index );
+ }
+
+ if( wavelet_stage < (MAX_WAVELET_COUNT - 1) )
+ {
+ ForwardWaveletTransformRecursive( transform_data, wavelet_stage + 1, 0, 0xFFFF );
+ }
+}
+
+static void SetRecursiveTransformData(RECURSIVE_TRANSFORM_DATA* transform_data,
+ const TRANSFORM *transform,
+ const COMPONENT_ARRAY *input_image_component,
+ int32_t midpoints[MAX_BAND_COUNT], int32_t multipliers[MAX_BAND_COUNT],
+ PIXEL *lowpass_buffer[MAX_WAVELET_COUNT][ROW_BUFFER_COUNT],
+ PIXEL *highpass_buffer[MAX_WAVELET_COUNT][ROW_BUFFER_COUNT],
+ int midpoint_prequant, int wavelet_stage )
+{
+ int i;
+
+ if( wavelet_stage == 0 )
+ {
+ transform_data->input_width = input_image_component->width;
+ transform_data->input_height = input_image_component->height;
+ transform_data->input_pitch = input_image_component->pitch;
+ transform_data->input_ptr = (PIXEL*)input_image_component->data;
+ }
+ else
+ {
+ WAVELET *input_wavelet = transform->wavelet[wavelet_stage - 1];
+
+ transform_data->input_width = input_wavelet->width;
+ transform_data->input_height = input_wavelet->height;
+ transform_data->input_pitch = input_wavelet->pitch;
+ transform_data->input_ptr = WaveletRowAddress(input_wavelet, LL_BAND, 0);
+ }
+
+ WAVELET *output_wavelet = transform->wavelet[wavelet_stage];
+ assert(output_wavelet);
+
+ transform_data->output_width = output_wavelet->width;
+ transform_data->output_pitch = output_wavelet->pitch;
+
+ for (i = 0; i < MAX_BAND_COUNT; i++)
+ {
+ transform_data->output_ptr[i] = output_wavelet->data[i];
+ }
+
+ transform_data->lowpass_buffer = lowpass_buffer[wavelet_stage];
+ transform_data->highpass_buffer = highpass_buffer[wavelet_stage];
+ transform_data->prescale = transform->prescale[wavelet_stage];
+
+ GetQuantizationParameters(midpoint_prequant, output_wavelet->quant, midpoints, multipliers );
+
+ transform_data->midpoints = midpoints;
+ transform_data->multipliers = multipliers;
+}
+
+static void ForwardWaveletTransform(TRANSFORM *transform, const COMPONENT_ARRAY *input_image_component, PIXEL *lowpass_buffer[MAX_WAVELET_COUNT][ROW_BUFFER_COUNT], PIXEL *highpass_buffer[MAX_WAVELET_COUNT][ROW_BUFFER_COUNT], int midpoint_prequant)
+{
+ RECURSIVE_TRANSFORM_DATA transform_data[MAX_WAVELET_COUNT];
+
+ int32_t midpoints[MAX_WAVELET_COUNT][MAX_BAND_COUNT]; //!< Midpoint value for each band (applied during quantization)
+ int32_t multipliers[MAX_WAVELET_COUNT][MAX_BAND_COUNT]; //!< Multiplier value for each band (applied during quantization)
+
+ SetRecursiveTransformData( &transform_data[0], transform, input_image_component, midpoints[0], multipliers[0], lowpass_buffer, highpass_buffer, midpoint_prequant, 0 );
+ SetRecursiveTransformData( &transform_data[1], transform, input_image_component, midpoints[1], multipliers[1], lowpass_buffer, highpass_buffer, midpoint_prequant, 1 );
+ SetRecursiveTransformData( &transform_data[2], transform, input_image_component, midpoints[2], multipliers[2], lowpass_buffer, highpass_buffer, midpoint_prequant, 2 );
+
+ ForwardWaveletTransformRecursive( transform_data, 0, 0, 0xFFFF );
+}
+
+/*!
+ @brief Encode the portion of a sample that corresponds to a single layer
+
+ Samples can be contain multiple subsamples. Each subsample may correspond to
+ a different view. For example, an encoded video sample may contain both the
+ left and right subsamples in a stereo pair.
+
+ Subsamples have been called tracks or channels, but this terminology can be
+ confused with separate video tracks in a multimedia container or the color
+ planes that are called channels elsewhere in this codec.
+
+ The subsamples are decoded seperately and composited to form a single frame
+ that is the output of the complete process of decoding a single video sample.
+ For this reason, the subsamples are called layers.
+
+ @todo Need to reset the codec state for each layer?
+*/
+//CODEC_ERROR EncodeLayer(ENCODER *encoder, void *buffer, size_t pitch, BITSTREAM *stream)
+CODEC_ERROR EncodeMultipleChannels(ENCODER *encoder, const UNPACKED_IMAGE *image, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ int channel_count;
+ int channel_index;
+
+ channel_count = encoder->channel_count;
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_LAYERS))
+ {
+ // Write the tag value pairs that preceed the encoded wavelet tree
+ error = EncodeLayerHeader(encoder, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+ }
+#endif
+
+
+ CODEC_STATE *codec = &encoder->codec;
+
+ // Compute the wavelet transform tree for each channel
+ for (channel_index = 0; channel_index < channel_count; channel_index++)
+ {
+ int channel_number;
+
+ ForwardWaveletTransform(&encoder->transform[channel_index], &image->component_array_list[channel_index], encoder->lowpass_buffer, encoder->highpass_buffer, encoder->midpoint_prequant );
+
+ channel_number = encoder->channel_order_table[channel_index];
+
+ // Encode the tag value pairs in the header for this channel
+ error = EncodeChannelHeader(encoder, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Encode the lowpass and highpass bands in the wavelet tree for this channel
+ error = EncodeChannelSubbands(encoder, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Encode the tag value pairs in the trailer for this channel
+ error = EncodeChannelTrailer(encoder, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Check that the bitstream is alligned to a segment boundary
+ assert(IsAlignedSegment(stream));
+
+ // Update the codec state for the next channel in the bitstream
+ //codec->channel_number++;
+ codec->channel_number = (channel_number + 1);
+ codec->subband_number = 0;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_LAYERS))
+ {
+ // Write the tag value pairs that follow the encoded wavelet tree
+ error = EncodeLayerTrailer(encoder, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+ //TODO: Need to align the bitstream between layers?
+ }
+#endif
+
+ return CODEC_ERROR_OKAY;
+}
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Write the sample layer header
+
+ The baseline profile only supports a single layer so the layer header
+ and trailer are not required.
+*/
+CODEC_ERROR EncodeLayerHeader(ENCODER *encoder, BITSTREAM *stream)
+{
+ //TODO: Write the tag-value pair for the layer number
+
+ return CODEC_ERROR_OKAY;
+}
+#endif
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+/*!
+ @brief Write the sample layer trailer
+
+ The baseline profile only supports a single layer so the layer header
+ and trailer are not required.
+
+ If more than one layer is present, the layers must be terminated by a
+ layer trailer. Otherwise, the decoder will continue to parse tag-value
+ pairs that belong to the next layer.
+*/
+CODEC_ERROR EncodeLayerTrailer(ENCODER *encoder, BITSTREAM *stream)
+{
+ // The value in the layer trailer tag-value pair is not used
+ PutTagPairOptional(stream, CODEC_TAG_LAYER_TRAILER, 0);
+
+ return CODEC_ERROR_OKAY;
+}
+#endif
+
+/*!
+ @brief Encode the channel into the bistream
+
+ This routine encodes all of the subbands (lowpass and highpass) in the
+ wavelet tree for the specified channel into the bitstream.
+*/
+CODEC_ERROR EncodeChannelWavelets(ENCODER *encoder, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &encoder->codec;
+
+ int channel_count;
+ int channel_index;
+
+ // Get the number of channels in the encoder wavelet transform
+ channel_count = encoder->channel_count;
+
+ // Compute the remaining wavelet transforms for each channel
+ //for (channel_index = 0; channel_index < channel_count; channel_index++)
+ for (channel_index = 0; channel_index < channel_count; channel_index++)
+ {
+ int channel_number = encoder->channel_order_table[channel_index];
+
+ // Encode the tag value pairs in the header for this channel
+ error = EncodeChannelHeader(encoder, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Encode the lowpass and highpass bands in the wavelet tree for this channel
+ error = EncodeChannelSubbands(encoder, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Encode the tag value pairs in the trailer for this channel
+ error = EncodeChannelTrailer(encoder, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Check that the bitstream is alligned to a segment boundary
+ assert(IsAlignedSegment(stream));
+
+ // Update the codec state for the next channel in the bitstream
+ //codec->channel_number++;
+ codec->channel_number = (channel_number + 1);
+ codec->subband_number = 0;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the channel header into the bitstream
+
+ The channel header separates channels in the encoded layer. The channel header
+ is not required before the first encoded channel because the codec state is
+ initialized for decoding the first channel.
+
+ The first channel is channel number zero.
+*/
+CODEC_ERROR EncodeChannelHeader(ENCODER *encoder,
+ int channel_number,
+ BITSTREAM *stream)
+{
+ CODEC_STATE *codec = &encoder->codec;
+ DIMENSION channel_width = encoder->channel[channel_number].width;
+ DIMENSION channel_height = encoder->channel[channel_number].height;
+ int bits_per_component = encoder->channel[channel_number].bits_per_component;
+
+ AlignBitsSegment(stream);
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_CHANNEL))
+ {
+ // Write the channel section header into the bitstream
+ BeginChannelSection(encoder, stream);
+ }
+#endif
+
+ // Write the channel number if it does not match the codec state
+ if (channel_number != codec->channel_number)
+ {
+ PutTagPair(stream, CODEC_TAG_ChannelNumber, channel_number);
+ codec->channel_number = channel_number;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ // The decoder will derive the channel width and height from the image dimensions and format
+ codec->channel_width = channel_width;
+ codec->channel_height = channel_height;
+ }
+ else
+#endif
+ {
+ // Write the component array width if it does not match the codec state
+ if (channel_width != codec->channel_width)
+ {
+ PutTagPair(stream, CODEC_TAG_ChannelWidth, channel_width);
+ codec->channel_width = channel_width;
+ }
+
+ // Write the component array height if it does not match the codec state
+ if (channel_height != codec->channel_height)
+ {
+ PutTagPair(stream, CODEC_TAG_ChannelHeight, channel_height);
+ codec->channel_height = channel_height;
+ }
+ }
+
+ // Write the component array precision if it does not match the codec state
+ if (bits_per_component != codec->bits_per_component)
+ {
+ PutTagPair(stream, CODEC_TAG_BitsPerComponent, bits_per_component);
+ codec->bits_per_component = bits_per_component;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the encoded subbands for this channel into the bitstream
+
+ This routine writes the encoded subbands in the wavelet tree for this channel
+ into the bitstream, including both the lowpass band and all of the highpass
+ bands in each wavelet in this channel.
+*/
+CODEC_ERROR EncodeChannelSubbands(ENCODER *encoder, int channel_number, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ //CODEC_STATE *codec = &encoder->codec;
+
+ int wavelet_count = encoder->wavelet_count;
+ int last_wavelet_index = wavelet_count - 1;
+ int wavelet_index;
+
+ int subband = 0;
+
+ // Start with the lowpass band in the wavelet at the highest level
+ WAVELET *wavelet = encoder->transform[channel_number].wavelet[last_wavelet_index];
+
+ // Check that the bitstream is aligned on a segment boundary
+ assert(IsAlignedSegment(stream));
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_WAVELET))
+ {
+ // Write the wavelet section header into the bitstream
+ BeginWaveletSection(encoder, stream);
+ }
+#endif
+
+ // Encode the lowpass subband in this channel
+ error = EncodeLowpassBand(encoder, wavelet, channel_number, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Advance to the first highpass subband
+ subband++;
+
+ // Encode the highpass bands in order of subband number
+ for (wavelet_index = last_wavelet_index; wavelet_index >= 0; wavelet_index--)
+ {
+ //int wavelet_type = WAVELET_TYPE_SPATIAL;
+ //int wavelet_level = wavelet_index + 1;
+ int band_index;
+
+ //int lowpass_scale = 0;
+ //int lowpass_divisor = 0;
+
+ wavelet = encoder->transform[channel_number].wavelet[wavelet_index];
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_WAVELET))
+ {
+ // Was the wavelet section header already written into the bitstream?
+ if (wavelet_index < last_wavelet_index)
+ {
+ // Write the wavelet section header into the bitstream
+ BeginWaveletSection(encoder, stream);
+ }
+ }
+#endif
+ // Encode the highpass bands in this wavelet
+ for (band_index = 1; band_index < wavelet->band_count; band_index++)
+ {
+ error = EncodeHighpassBand(encoder, wavelet, band_index, subband, stream);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Advance to the next subband
+ subband++;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_WAVELET))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Update the section header with the actual size of the wavelet section
+ EndSection(stream);
+ }
+#endif
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the channel trailer into the bitstream
+
+ A channel trailer is not required as the channel header functions as a marker
+ between channels in the bitstream.
+
+ It may be necessary to update the channel size in a sample size segment written
+ into the channel header if the channel header includes a sample size segment in
+ the future.
+*/
+CODEC_ERROR EncodeChannelTrailer(ENCODER *encoder, int channel, BITSTREAM *stream)
+{
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_CHANNEL))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Update the section header with the actual size of the channel section
+ EndSection(stream);
+ }
+#endif
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Allocate intermediate buffers for the horizontal transform results
+
+ @todo Need to return an error code if allocation fails
+*/
+CODEC_ERROR AllocateEncoderHorizontalBuffers(ENCODER *encoder)
+{
+ gpr_allocator *allocator = encoder->allocator;
+ int channel_index;
+ int wavelet_index;
+ int channel_count = encoder->channel_count;
+
+ int buffer_width = 0;
+
+ for (channel_index = 0; channel_index < channel_count; channel_index++)
+ {
+ buffer_width = maximum(buffer_width, encoder->channel[channel_index].width );
+ }
+
+ buffer_width = ((buffer_width % 2) == 0) ? buffer_width / 2 : (buffer_width + 1) / 2;
+
+ for (wavelet_index = 0; wavelet_index < MAX_WAVELET_COUNT; wavelet_index++)
+ {
+ int row;
+
+ int channel_width = encoder->transform[0].wavelet[wavelet_index]->width;
+
+ for (row = 0; row < ROW_BUFFER_COUNT; row++)
+ {
+ PIXEL *lowpass_buffer = allocator->Alloc(channel_width * sizeof(PIXEL) * 2);
+ PIXEL *highpass_buffer = lowpass_buffer + channel_width;
+
+ assert(lowpass_buffer != NULL);
+ if (! (lowpass_buffer != NULL)) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ encoder->lowpass_buffer[wavelet_index][row] = lowpass_buffer;
+ encoder->highpass_buffer[wavelet_index][row] = highpass_buffer;
+ }
+ }
+
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Deallocate the intermediate buffers for the horizontal transform results
+
+ It is possible to avoid reallocating the buffers for the horizontal transform
+ results if the buffers were not deallocated between encoded frames. In this case,
+ it would be necessary to call this routine inside @ref ReleaseEncoder and it would
+ also be necessary to modify @ref AllocateEncoderHorizontalBuffers to not allocate
+ the buffers if they are already allocated.
+*/
+CODEC_ERROR DeallocateEncoderHorizontalBuffers(ENCODER *encoder)
+{
+ gpr_allocator *allocator = encoder->allocator;
+
+ int wavelet_index;
+
+ for (wavelet_index = 0; wavelet_index < MAX_WAVELET_COUNT; wavelet_index++)
+ {
+ int row;
+
+ for (row = 0; row < ROW_BUFFER_COUNT; row++)
+ {
+ allocator->Free(encoder->lowpass_buffer[wavelet_index][row]);
+ }
+ }
+
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Allocate buffers used for computing the forward wavelet transform
+*/
+CODEC_ERROR AllocateHorizontalBuffers(gpr_allocator *allocator,
+ PIXEL *lowpass_buffer[],
+ PIXEL *highpass_buffer[],
+ int buffer_width)
+{
+ const size_t row_buffer_size = buffer_width * sizeof(PIXEL);
+
+ int row;
+
+ for (row = 0; row < ROW_BUFFER_COUNT; row++)
+ {
+ lowpass_buffer[row] = allocator->Alloc(row_buffer_size);
+ highpass_buffer[row] = allocator->Alloc(row_buffer_size);
+
+ // Check that the memory allocation was successful
+ assert(lowpass_buffer[row] != NULL);
+ if (! (lowpass_buffer[row] != NULL)) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+ assert(highpass_buffer[row] != NULL);
+ if (! (highpass_buffer[row] != NULL)) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Deallocate buffers used for computing the forward wavelet transform
+*/
+CODEC_ERROR DeallocateHorizontalBuffers(gpr_allocator *allocator,
+ PIXEL *lowpass_buffer[],
+ PIXEL *highpass_buffer[])
+{
+ int row;
+
+ for (row = 0; row < ROW_BUFFER_COUNT; row++)
+ {
+ allocator->Free(lowpass_buffer[row]);
+ allocator->Free(highpass_buffer[row]);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Allocate all of the wavelets used during encoding
+
+ This routine allocates all of the wavelets in the wavelet tree that
+ may be used during encoding.
+
+ This routine is used to preallocate the wavelets before encoding begins.
+ If the wavelet bands are allocated on demand if not preallocated.
+
+ By default, the wavelet bands are encoded into the bitstream with the bands
+ from the wavelet at the highest level (smallest wavelet) first so that the
+ bands can be processed by the encoder in the order as the sample is decoded.
+
+ @todo Do not allocate wavelets for resolutions that are larger then the
+ decoded resolution. At lower resolutions, the depth of the wavelet tree
+ can be reduced and the highpass bands in the unused wavelets to not have
+ to be decoded.
+
+ @todo Should it be an error if the wavelets are not preallocated?
+*/
+CODEC_ERROR AllocEncoderTransforms(ENCODER *encoder)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Use the default allocator for the encoder
+ gpr_allocator *allocator = encoder->allocator;
+ int channel_index;
+ int wavelet_index;
+
+ assert(encoder != NULL);
+ if (! (encoder != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ // Check that the encoded dimensions are valid
+ //assert((encoder->encoded.width % (1 << encoder->wavelet_count)) == 0);
+
+ for (channel_index = 0; channel_index < encoder->channel_count; channel_index++)
+ {
+ // The wavelet at level zero has the same dimensions as the encoded frame
+ DIMENSION wavelet_width = 0;
+ DIMENSION wavelet_height = 0;
+ error = GetChannelDimensions(encoder, channel_index, &wavelet_width, &wavelet_height);
+ assert(wavelet_width > 0 && wavelet_height > 0);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ for (wavelet_index = 0; wavelet_index < encoder->wavelet_count; wavelet_index++)
+ {
+ WAVELET *wavelet = NULL;
+
+ // Pad the wavelet width if not divisible by two
+ if ((wavelet_width % 2) != 0) {
+ wavelet_width++;
+ }
+
+ // Pad the wavelet height if not divisible by two
+ if ((wavelet_height % 2) != 0) {
+ wavelet_height++;
+ }
+
+ // Reduce the dimensions of the next wavelet by half
+ wavelet_width /= 2;
+ wavelet_height /= 2;
+
+ // Dimensions of the current wavelet must be divisible by two
+ //assert((wavelet_width % 2) == 0 && (wavelet_height % 2) == 0);
+
+ // The wavelet width must be divisible by two
+ //assert((wavelet_width % 2) == 0);
+
+ // Allocate the wavelet
+ wavelet = CreateWavelet(allocator, wavelet_width, wavelet_height);
+ if (wavelet == NULL) {
+ return CODEC_ERROR_OUTOFMEMORY;
+ }
+
+ // Add the wavelet to the transform
+ encoder->transform[channel_index].wavelet[wavelet_index] = wavelet;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Allocate all of the buffers required for encoding
+
+ This routine allocates buffers required for encoding, not including
+ the wavelet images in the wavelet tree which are allocated by
+ @ref AllocEncoderTransforms
+
+ This routine is used to preallocate buffers before encoding begins.
+ If the buffers are allocated on demand if not preallocated.
+
+ The encoding parameters, including the encoded frame dimensions,
+ resolution of the decoded frame, and the decoded pixel format, are
+ taken into account when the buffers are allocated. For example,
+ buffer space that is only used when encoding to full resolution will
+ not be allocated if the frame is decoded to a smaller size.
+
+ Note that it is not an error to preallocate more buffer space than
+ what is strictly required for encoding. For example, it is okay to
+ allocate buffer space required for full frame encoding even if the
+ encoded sample will be decoded at lower resolution. In many applications,
+ it is simpler to preallocate the maximum buffer space that may be needed.
+
+ Currently, the reference encoder allocates scratch buffers as required
+ by each routine that needs scratch space and the scratch buffers are
+ deallocated at the end each routine that allocates scratch space.
+ A custom memory allocator can make this scheme efficient. See comments
+ in the documentation for the memory allocator module.
+
+ @todo Should it be an error if the buffers are not preallocated?
+*/
+CODEC_ERROR AllocEncoderBuffers(ENCODER *encoder)
+{
+ (void)encoder;
+ return CODEC_ERROR_UNIMPLEMENTED;
+}
+
+/*!
+ @brief Set the quantization parameters in the encoder
+
+ This routine computes the parameters in the quantizer used by
+ the encoder based based on the quality setting and the desired
+ bitrate. The quantization parameters are adjsuted to compensate
+ for the precision of the input pixels.
+
+ Note that the baseline profile does not support quantization to
+ achieve a desired bitrate.
+
+*/
+CODEC_ERROR SetEncoderQuantization(ENCODER *encoder,
+ const ENCODER_PARAMETERS *parameters)
+{
+ int channel_count = encoder->channel_count;
+ int channel_number;
+
+ const int quant_table_length = sizeof(parameters->quant_table)/sizeof(parameters->quant_table[0]);
+
+ // Set the midpoint prequant parameter
+ encoder->midpoint_prequant = 2;
+
+ // Set the quantization table in each channel
+ for (channel_number = 0; channel_number < channel_count; channel_number++)
+ {
+ SetTransformQuantTable(encoder, channel_number, parameters->quant_table, quant_table_length);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Copy the quantization table into the wavelet bands
+*/
+CODEC_ERROR SetTransformQuantTable(ENCODER *encoder, int channel, const QUANT table[], int table_length)
+{
+ int wavelet_count = encoder->wavelet_count;
+ int wavelet_index;
+ int subband;
+
+ // All lowpass bands use the quantization for subband zero
+ for (wavelet_index = 0; wavelet_index < wavelet_count; wavelet_index++)
+ {
+ WAVELET *wavelet = encoder->transform[channel].wavelet[wavelet_index];
+ wavelet->quant[0] = table[0];
+ }
+
+ // Store the quantization values for the highpass bands in each wavelet
+ for (subband = 1; subband < table_length; subband++)
+ {
+ int wavelet_index = SubbandWaveletIndex(subband);
+ int band_index = SubbandBandIndex(subband);
+ WAVELET *wavelet;
+
+ assert(0 <= wavelet_index && wavelet_index < wavelet_count);
+ assert(0 <= band_index && band_index <= MAX_BAND_COUNT);
+
+ // Store the quantization value for this subband
+ wavelet = encoder->transform[channel].wavelet[wavelet_index];
+ wavelet->quant[band_index] = table[subband];
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Return the encoded dimensions for the specified channel
+
+ The encoded dimensions for each channel may differ due to color
+ difference component sampling.
+*/
+CODEC_ERROR GetChannelDimensions(ENCODER *encoder,
+ int channel_number,
+ DIMENSION *channel_width_out,
+ DIMENSION *channel_height_out)
+{
+ DIMENSION channel_width = 0;
+ DIMENSION channel_height = 0;
+
+ assert(encoder != NULL && channel_width_out != NULL && channel_height_out != NULL);
+ if (! (encoder != NULL && channel_width_out != NULL && channel_height_out != NULL)) {
+ return CODEC_ERROR_NULLPTR;
+ }
+
+ assert(0 <= channel_number && channel_number < encoder->channel_count);
+ if (! (0 <= channel_number && channel_number < encoder->channel_count)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ // Clear the output dimensions in case this routine terminates early
+ *channel_width_out = 0;
+ *channel_height_out = 0;
+
+ channel_width = encoder->channel[channel_number].width;
+ channel_height = encoder->channel[channel_number].height;
+
+ *channel_width_out = channel_width;
+ *channel_height_out = channel_height;
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Adjust the height of encoded layer
+
+ Interleaved frames are encoded as separate layers with half the height.
+*/
+DIMENSION EncodedLayerHeight(ENCODER *encoder, DIMENSION height)
+{
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ assert(encoder != NULL);
+ if (encoder->progressive == 0) {
+ height /= 2;
+ }
+#endif
+
+ return height;
+}
+
+/*!
+ @brief Compute the dimensions of the image as reported by the ImageWidth and ImageHeight parameters
+
+ The image width is the maximum width of all component arrays and the image height is the maximum height
+ of all component arrays.
+*/
+CODEC_ERROR GetMaximumChannelDimensions(const UNPACKED_IMAGE *image, DIMENSION *width_out, DIMENSION *height_out)
+{
+ DIMENSION width = 0;
+ DIMENSION height = 0;
+ int channel_number;
+
+ if (image == NULL) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ for (channel_number = 0; channel_number < image->component_count; channel_number++)
+ {
+ if (width < image->component_array_list[channel_number].width) {
+ width = image->component_array_list[channel_number].width;
+ }
+
+ if (height < image->component_array_list[channel_number].height) {
+ height = image->component_array_list[channel_number].height;
+ }
+ }
+
+ if (width_out != NULL) {
+ *width_out = width;
+ }
+
+ if (height_out != NULL) {
+ *height_out = height;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Set the bit for the specified subband in the decoded band mask
+
+ The decoded subband mask is used to track which subbands have been
+ decoded in teh current channel. It is reset at the start of each
+ channel.
+
+ The decoded subband mask is used when decoding a sample at less
+ than full resolution. The mask indicates when enough subbands
+ have been decoded for a channel and that remaining portion of the
+ encoded sample for the current channel may be skipped.
+*/
+CODEC_ERROR SetEncodedBandMask(CODEC_STATE *codec, int subband)
+{
+ if (0 <= subband && subband < MAX_SUBBAND_COUNT) {
+ codec->decoded_subband_mask |= (1 << subband);
+ }
+ return CODEC_ERROR_OKAY;
+}
+
+
+/*!
+ @brief Encoded the lowpass band from the bitstream
+
+ The wavelet at the highest level is passes as an argument.
+ This routine decodes lowpass band in the bitstream into the
+ lowpass band of the wavelet.
+*/
+CODEC_ERROR EncodeLowpassBand(ENCODER *encoder, WAVELET *wavelet, int channel_number, BITSTREAM *stream)
+{
+ CODEC_STATE *codec = &encoder->codec;
+ //FILE *logfile = encoder->logfile;
+ //int subband = 0;
+ //int level = encoder->wavelet_count;
+ int width = wavelet->width;
+ int height = wavelet->height;
+ uint8_t *lowpass_row_ptr;
+ int lowpass_pitch;
+ int row;
+
+ PRECISION lowpass_precision = encoder->channel[channel_number].lowpass_precision;
+
+ lowpass_row_ptr = (uint8_t *)wavelet->data[LL_BAND];
+ lowpass_pitch = wavelet->pitch;
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_SUBBAND))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Write the channel section header into the bitstream
+ BeginSubbandSection(encoder, stream);
+ }
+#endif
+
+ // Write the tag-value pairs for the lowpass band to the bitstream
+ PutVideoLowpassHeader(encoder, channel_number, stream);
+
+ // Check that the bitstream is tag aligned before writing the pixels
+ assert(IsAlignedSegment(stream));
+
+ for (row = 0; row < height; row++)
+ {
+ uint16_t *lowpass = (uint16_t *)lowpass_row_ptr;
+ int column;
+
+ for (column = 0; column < width; column++)
+ {
+ BITWORD coefficient = lowpass[column];
+ //assert(0 <= lowpass[column] && lowpass[column] <= COEFFICIENT_MAX);
+ assert(lowpass[column] <= COEFFICIENT_MAX);
+ assert(coefficient <= COEFFICIENT_MAX);
+ PutBits(stream, coefficient, lowpass_precision);
+ }
+
+ lowpass_row_ptr += lowpass_pitch;
+ }
+
+ // Align the bitstream to a segment boundary
+ AlignBitsSegment(stream);
+
+ PutVideoLowpassTrailer(stream);
+
+ // Update the subband number in the codec state
+ codec->subband_number++;
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_SUBBAND))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Update the section header with the actual size of the subband section
+ EndSection(stream);
+ }
+#endif
+
+ return CODEC_ERROR_OKAY;
+}
+
+CODEC_ERROR PutVideoSubbandHeader(ENCODER *encoder, int subband_number, QUANT quantization, BITSTREAM *stream)
+{
+ CODEC_STATE *codec = &encoder->codec;
+
+ if (subband_number != codec->subband_number) {
+ PutTagPair(stream, CODEC_TAG_SubbandNumber, subband_number);
+ codec->subband_number = subband_number;
+ }
+
+ if (quantization != codec->band.quantization) {
+ PutTagPair(stream, CODEC_TAG_Quantization, quantization);
+ codec->band.quantization = quantization;
+ }
+
+ // Write the chunk header for the codeblock
+ PushSampleSize(stream, CODEC_TAG_LargeCodeblock);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Encode the highpass band into the bitstream
+
+ The specified wavelet band is decoded from the bitstream
+ using the codebook and encoding method specified in the
+ bitstream.
+*/
+CODEC_ERROR EncodeHighpassBand(ENCODER *encoder, WAVELET *wavelet, int band, int subband, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ CODEC_STATE *codec = &encoder->codec;
+
+ DIMENSION band_width = wavelet->width;
+ DIMENSION band_height = wavelet->height;
+
+ void *band_data = wavelet->data[band];
+ DIMENSION band_pitch = wavelet->pitch;
+
+ QUANT quantization = wavelet->quant[band];
+ //uint16_t scale = wavelet->scale[band];
+
+ //int divisor = 0;
+ //int peaks_coding = 0;
+
+ ENCODER_CODESET *codeset = encoder->codeset;
+
+ //int encoding_method = BAND_ENCODING_RUNLENGTHS;
+
+ // Check that the band header starts on a tag boundary
+ assert(IsAlignedTag(stream));
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_SUBBAND))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Write the channel section header into the bitstream
+ BeginSubbandSection(encoder, stream);
+ }
+#endif
+
+ // Output the tag-value pairs for this subband
+ PutVideoSubbandHeader(encoder, subband, quantization, stream);
+
+ // Encode the highpass coefficients for this subband into the bitstream
+ error = EncodeHighpassBandRowRuns(stream, codeset, band_data, band_width, band_height, band_pitch);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Align the bitstream to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Output the band trailer
+ PutVideoSubbandTrailer(encoder, stream);
+
+ // Update the subband number in the codec state
+ codec->subband_number++;
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ if (IsSectionEnabled(encoder, SECTION_NUMBER_SUBBAND))
+ {
+ // Make sure that the bitstream is aligned to a segment boundary
+ AlignBitsSegment(stream);
+
+ // Update the section header with the actual size of the subband section
+ EndSection(stream);
+ }
+#endif
+
+ return CODEC_ERROR_OKAY;
+}
+
+STATIC_INLINE void write_bits(uint8_t** buffer, uint32_t bits)
+{
+ uint32_t word = Swap32(bits);
+ *( (uint32_t*)(*buffer) ) = word;
+}
+
+STATIC_INLINE VLE PutZeroBits(uint8_t** buffer, VLE stream_bits, uint_fast8_t size )
+{
+ BITCOUNT unused_bit_count = bit_word_count - stream_bits.size;
+
+ if ( size > unused_bit_count )
+ {
+ if (stream_bits.size < bit_word_count)
+ {
+ size -= unused_bit_count;
+ }
+
+ write_bits(buffer, stream_bits.bits);
+ *buffer += 4;
+
+ stream_bits.size = size;
+ stream_bits.bits = 0;
+ }
+ else
+ {
+ stream_bits.size += size;
+ }
+
+ return stream_bits;
+}
+
+STATIC_INLINE VLE PutBitsCore(uint8_t** buffer, VLE stream_bits, uint32_t bits, uint_fast8_t size )
+{
+ BITCOUNT unused_bit_count = bit_word_count - stream_bits.size;
+
+ if ( size > unused_bit_count)
+ {
+ if (stream_bits.size < bit_word_count)
+ {
+ stream_bits.bits |= (bits >> (size - unused_bit_count));
+ size -= unused_bit_count;
+ }
+
+ write_bits(buffer, stream_bits.bits);
+ *buffer += 4;
+
+ stream_bits.size = size;
+ stream_bits.bits = bits << (bit_word_count - size);
+ }
+ else
+ {
+ stream_bits.bits |= (bits << (unused_bit_count - size));
+ stream_bits.size += size;
+ }
+
+ return stream_bits;
+}
+
+STATIC_INLINE VLE PutBitsCoreWithSign(uint8_t** buffer, VLE stream_bits, uint32_t bits, uint_fast8_t size, bool positive )
+{
+ stream_bits = PutBitsCore( buffer, stream_bits, bits, size );
+
+ BITCOUNT unused_bit_count = bit_word_count - stream_bits.size;
+
+ if ( unused_bit_count == 0 )
+ {
+ write_bits(buffer, stream_bits.bits);
+ *buffer += 4;
+
+ stream_bits.size = 1;
+
+ if( positive == false )
+ stream_bits.bits = 1 << (bit_word_count - 1);
+ else
+ stream_bits.bits = 0;
+ }
+ else
+ {
+ stream_bits.size += 1;
+
+ if( positive == false )
+ stream_bits.bits |= (1 << (unused_bit_count - 1));
+ }
+
+ return stream_bits;
+}
+
+/*!
+ @brief Encode the highpass band from the bitstream
+
+ This routine does not encode runs of zeros across row boundaries.
+*/
+CODEC_ERROR EncodeHighpassBandRowRuns(BITSTREAM *stream, ENCODER_CODESET *codeset, PIXEL *data,
+ DIMENSION width, DIMENSION height, DIMENSION pitch)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ int row_padding;
+ int row = 0;
+ //int column = 0;
+ //size_t index = 0;
+
+ // The encoder uses the codebooks for magnitudes and runs of zeros
+ const MAGS_TABLE *mags_table = codeset->mags_table;
+ const RUNS_TABLE *runs_table = codeset->runs_table;
+ uint32_t runs_table_length = runs_table->length;
+ RLC *rlc = (RLC *)((uint8_t *)runs_table + sizeof(RUNS_TABLE));
+
+ // The band is terminated by the band end codeword in the codebook
+ const CODEBOOK *codebook = codeset->codebook;
+
+ PIXEL *rowptr = data;
+
+ // Convert the pitch to units of pixels
+ assert((pitch % sizeof(PIXEL)) == 0);
+ pitch /= sizeof(PIXEL);
+
+ // Check that the band dimensions are reasonable
+ assert(width <= pitch);
+
+ // Compute the number of values of padding at the end of each row
+ row_padding = pitch - width;
+
+ VLE *mags_table_entry = (VLE *)((uint8_t *)mags_table + sizeof(MAGS_TABLE));
+
+ VLE stream_bits;
+
+ stream_bits.bits = stream->buffer;
+ stream_bits.size = stream->count;
+
+ struct _stream *bit_stream = stream->stream;
+
+ int mags_table_length_minus_1 = mags_table->length - 1;
+
+ uint8_t* stream_buffer = (uint8_t *)bit_stream->location.memory.buffer + bit_stream->byte_count;
+ uint8_t* stream_buffer_orig = stream_buffer;
+
+ uint32_t count = 0;
+ for (row = 0; row < height; row++)
+ {
+ uint32_t index = 0; // Start at the beginning of the row
+
+ // Search the row for runs of zeros and nonzero values
+ while (1)
+ {
+ // Loop invariant
+ assert(index < width);
+
+ {
+ PIXEL* start = rowptr + index;
+ PIXEL* end = rowptr + width;
+
+ for (; *(start) == 0 && start != end; start++)
+ {
+
+ }
+
+ uint32_t x = start - (rowptr + index);
+
+ index += x;
+ count += x;
+ }
+
+ // Need to output a value?
+ if (index < width)
+ {
+ while (count > 0)
+ {
+ if( count < 12 )
+ {
+ stream_bits = PutZeroBits(&stream_buffer, stream_bits, count );
+ break;
+ }
+ else
+ {
+ uint32_t count_index = minimum(count, runs_table_length - 1);
+ assert(count_index < runs_table->length);
+
+ RLC rlc_val = rlc[count_index];
+
+ stream_bits = PutBitsCore(&stream_buffer, stream_bits, rlc_val.bits, rlc_val.size );
+
+ // Reduce the length of the run by the amount output
+ count -= rlc_val.count;
+ }
+ }
+
+ count = 0;
+
+ // The value zero is run length coded and handled by another routine
+ {
+ PIXEL value = rowptr[index++];
+ assert(value != 0);
+
+ PIXEL abs_value = minimum( abs(value), mags_table_length_minus_1 );
+
+ stream_bits = PutBitsCoreWithSign(&stream_buffer, stream_bits, mags_table_entry[abs_value].bits, mags_table_entry[abs_value].size, value > 0 );
+ }
+ }
+
+ // Add the end of row padding to the encoded length
+ if (index == width)
+ {
+ count += row_padding;
+ break;
+ }
+ }
+
+ // Should have processed the entire row
+ assert(index == width);
+
+ // Advance to the next row
+ rowptr += pitch;
+ }
+
+ stream->count = stream_bits.size;
+ stream->buffer = stream_bits.bits;
+ bit_stream->byte_count += (stream_buffer - stream_buffer_orig);
+
+ // // Need to output a pending run of zeros?
+ if (count > 0)
+ {
+ error = PutZeros(stream, runs_table, count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+ }
+
+ // Insert the special codeword that marks the end of the highpass band
+ error = PutSpecial(stream, codebook, SPECIAL_MARKER_BAND_END);
+
+ return error;
+}
+
+CODEC_ERROR PutVideoSubbandTrailer(ENCODER *encoder, BITSTREAM *stream)
+{
+ // Set the size of the large chunk for the highpass band codeblock
+ PopSampleSize(stream);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Read the segment at the specified offset in the bitstream
+
+ This routine is used to read a segment that was previously written at a previous
+ location in the encoded sample. This allows the encoder to update, rather than
+ overwrite, a segment that has already been written. Typically, this is done to
+ insert the size or offset to a portion of the sample (syntax element) into a
+ segment that acts as an index to the syntax element.
+ */
+CODEC_ERROR GetSampleOffsetSegment(BITSTREAM *bitstream, uint32_t offset, TAGVALUE *segment)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ uint32_t buffer;
+
+ error = GetBlock(bitstream->stream, &buffer, sizeof(buffer), offset);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Translate the segment to native byte order
+ segment->longword = Swap32(buffer);
+
+ // Cannot return a segment if the offset stack is empty
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the lowpass band header into the bitstream
+
+ Each channel is encoded separately, so the lowpass band (subband zero)
+ is the lowpass band in the wavelet at the highest level for each channel.
+
+ The last element in the lowpass band header is a segment that contains the
+ size of this subband. The actual size is updated when the lowpass trailer
+ is written (see @ref PutVideoLowpassTrailer).
+
+ The lowpass start code is used to uniquely identify the start of the lowpass
+ band header and is used by the decode to navigate to the next channel in the
+ bitstream.
+
+ @todo Consider writing a composite lowpass band for all channels with
+ interleaved rows to facilitate access to the thumbnail image in the
+ encoded sample.
+ */
+CODEC_ERROR PutVideoLowpassHeader(ENCODER *encoder, int channel_number, BITSTREAM *stream)
+{
+ CODEC_STATE *codec = &encoder->codec;
+ PRECISION lowpass_precision = encoder->channel[channel_number].lowpass_precision;
+
+ // Output the subband number
+ if (codec->subband_number != 0)
+ {
+ PutTagPair(stream, CODEC_TAG_SubbandNumber, 0);
+ codec->subband_number = 0;
+ }
+
+ // Output the lowpass precision
+ //if (encoder->lowpass.precision != codec->lowpass.precision)
+ if (lowpass_precision != codec->lowpass_precision)
+ {
+ PutTagPair(stream, CODEC_TAG_LowpassPrecision, lowpass_precision);
+ codec->lowpass_precision = lowpass_precision;
+ }
+
+ // Write the chunk header for the codeblock
+ PushSampleSize(stream, CODEC_TAG_LargeCodeblock);
+
+ return CODEC_ERROR_OKAY;
+}
+
diff --git a/gpr/source/lib/vc5_encoder/encoder.h b/gpr/source/lib/vc5_encoder/encoder.h
new file mode 100755
index 0000000..1048628
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/encoder.h
@@ -0,0 +1,333 @@
+/*! @file encoder.h
+ *
+ * @brief Declaration of the data structures and constants used for core encoding.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ENCODER_H
+#define ENCODER_H
+
+/*!
+ @brief Data structure for the pixel or picture aspect ratio
+
+ @todo Should the members of the aspect ratio data structure be unsigned?
+*/
+typedef struct _aspect_ratio
+{
+ int16_t x; //!< Numerator of the aspect ratio
+ int16_t y; //!< Denominator of the aspect ratio
+
+} ASPECT_RATIO;
+
+/*!
+ @brief Data structure for the buffers and information used by the encoder
+
+ The encoder data structure contains information that will be
+ used by the encoder for decoding every sample in the sequence.
+ Information that varies during decoding, such as the current
+ subband index or the dimensions of the bands in the wavelet that
+ is being decoded, is stored in the codec state.
+
+ The encoded dimensions are the width and height of the array of pixels
+ for each encoded channel (image plane), including padding added to
+ satisfy the requirements of the wavelet transforms. In the case
+ of 4:2:2 sampling, the encoded width and height are for the luma channel.
+
+ The display dimensions are the width and height of the display aperture,
+ the displayable portion of the decoded image with padding removed.
+
+ The display dimensions can include a row and column offset to trim
+ top rows and left columns from the decoded image prior to display.
+
+ The decoded dimensions equal the encoded dimensions at full resolution
+ and are reduced by a power of two if decoded to a lower resolution.
+ The decoded dimensions are derived from the encoded dimensions and the
+ decoded resolution.
+
+ The decoded dimensions are used to allocate the wavelet tree for the
+ lowpass and highpass coefficients decoded from the bitstream. It is
+ not necessary to allocate wavelets for larger resolutions than the
+ decoded resolution.
+
+ For Bayer encoded images, the encoded dimensions are half the width
+ and height of the input dimensions (after windowing). Typically,
+ media containers report the display dimensions as twice the encoded
+ dimensions since a demosaic algorithm must be applied to produce a
+ displayable image that looks right to most people.
+
+ @todo Consider changing the transform data structure to use a
+ vector of wavelets rather than a vector of wavelet pointers.
+*/
+typedef struct _encoder
+{
+ // CODEC codec; //!< Common fields for both the encoder and decoder
+
+ FILE *logfile; //!< File for writing debugging information
+ CODEC_ERROR error; //!< Error code from the most recent codec operation
+ gpr_allocator *allocator; //!< Memory allocator used to allocate all dyynamic data
+ CODEC_STATE codec; //!< Information gathered while decoding the current sample
+ VERSION version; //!< Codec version (major, minor, revision, build)
+
+ //! Parts of the VC-5 standard that are supported at runtime by the codec implementation
+ ENABLED_PARTS enabled_parts;
+
+ uint64_t frame_number; //!< Every sample in a clip has a unique frame number
+
+ //! Number of color channels in the input and encoded images
+ uint_fast8_t channel_count;
+
+ //! Number of wavelet transforms in each channel
+ uint_fast8_t wavelet_count;
+
+ //! Internal precision used by this encoder
+ PRECISION internal_precision;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ IMAGE_FORMAT image_format; //!< Type of the image represented by the bitstream
+ DIMENSION image_width; //!< Number of samples per row in the image represented by the bitstream
+ DIMENSION image_height; //!< Number of rows of samples in the image represented by the bitstream
+ DIMENSION pattern_width; //!< Number of samples per row in each pattern element
+ DIMENSION pattern_height; //!< Number of rows of samples in each pattern element
+ DIMENSION components_per_sample; //!< Number of components per sample in the image
+ DIMENSION max_bits_per_component; //!< Upper bound on the number of significant bits per component value
+#else
+ DIMENSION image_width; //!< Upper bound on the width of each channel
+ DIMENSION image_height; //!< Upper bound on the height of each channel
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ //! Progressive frame flag
+ BOOLEAN progressive;
+
+ // Interlaced frame with the top field encoded first
+ BOOLEAN top_field_first;
+
+ // The encoded frame is upside down (not used)
+ BOOLEAN frame_inverted;
+#endif
+
+ struct _channel
+ {
+ DIMENSION width; //!< Width of the next channel in the bitstream
+ DIMENSION height; //!< Height of the next channel in the bitstream
+
+ //! Precision of the component array for the next channel in the bitstream
+ PRECISION bits_per_component;
+
+ //! Number of bits per lowpass coefficient
+ PRECISION lowpass_precision;
+
+ } channel[MAX_CHANNEL_COUNT]; //!< Information about each channel
+
+ //! Dimensions and format of the image that was input to the encoder
+ struct _input
+ {
+ DIMENSION width; //!< Width of the image input to the encoder
+ DIMENSION height; //!< Height of the image input to the encoder
+ PIXEL_FORMAT format; //!< Pixel format of the image input to the encode
+
+ } input; //!< Information about the image input to the encoder
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ uint_least8_t layer_count; //!< Number of subsamples in each sample
+#endif
+
+ //! Wavelet tree for each channel
+ TRANSFORM transform[MAX_CHANNEL_COUNT];
+
+ //! Codebook to use for encoding
+ ENCODER_CODESET *codeset;
+
+ //! Scratch buffer for unpacking the input image
+ PIXEL *unpacked_buffer[MAX_CHANNEL_COUNT];
+
+ //! Parameter that controls the amount of rounding before quantization
+ int midpoint_prequant;
+
+ //! Table for the order in which channels are encoded into the bitstream
+ CHANNEL channel_order_table[MAX_CHANNEL_COUNT];
+
+ //! Number of entries in the channel order table (may be less than the channel count)
+ int channel_order_count;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ uint8_t image_sequence_identifier[16]; //!< UUID used for the unique image identifier
+ uint32_t image_sequence_number; //!< Number of the image in the encoded sequence
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ COMPONENT_TRANSFORM *component_transform;
+ COMPONENT_PERMUTATION *component_permutation;
+#endif
+
+ //! Six rows of horizontal lowpass results for each channel
+ PIXEL *lowpass_buffer[MAX_WAVELET_COUNT][ROW_BUFFER_COUNT];
+
+ //! Six rows of horizontal highpass results for each channel
+ PIXEL *highpass_buffer[MAX_WAVELET_COUNT][ROW_BUFFER_COUNT];
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ ENABLED_SECTIONS enabled_sections;
+#endif
+
+} ENCODER;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InitEncoder(ENCODER *encoder, const gpr_allocator *allocator, const VERSION *version);
+
+ //TAGWORD PackedEncoderVersion(ENCODER *encoder);
+
+ CODEC_ERROR PrepareEncoder(ENCODER *encoder,
+ const UNPACKED_IMAGE *image,
+ const ENCODER_PARAMETERS *parameters);
+
+ CODEC_ERROR PrepareEncoderState(ENCODER *encoder,
+ const UNPACKED_IMAGE *image,
+ const ENCODER_PARAMETERS *parameters);
+
+ CODEC_ERROR SetInputChannelFormats(ENCODER *encoder, ENCODER_PARAMETERS *parameters);
+
+ CODEC_ERROR ReleaseEncoder(ENCODER *encoder);
+
+ CODEC_ERROR AllocEncoderTransforms(ENCODER *encoder);
+
+ CODEC_ERROR AllocEncoderBuffers(ENCODER *encoder);
+
+ //CODEC_ERROR EncodeStream(IMAGE *image, STREAM *stream, PARAMETERS *parameters);
+ CODEC_ERROR EncodeImage(IMAGE *image, STREAM *stream, RGB_IMAGE *rgb_image, ENCODER_PARAMETERS *parameters);
+
+ //CODEC_ERROR EncodeSingleImage(ENCODER *encoder, IMAGE *image, BITSTREAM *stream);
+ CODEC_ERROR EncodingProcess(ENCODER *encoder,
+ const UNPACKED_IMAGE *image,
+ BITSTREAM *stream,
+ const ENCODER_PARAMETERS *parameters);
+
+ CODEC_ERROR EncodeSingleImage(ENCODER *encoder, const UNPACKED_IMAGE *image, BITSTREAM *stream);
+
+ CODEC_ERROR EncodeSingleChannel(ENCODER *encoder, void *buffer, size_t pitch, BITSTREAM *stream);
+
+ //CODEC_ERROR EncodeMultipleImages(ENCODER *encoder, IMAGE *image_array[], int frame_count, BITSTREAM *stream);
+
+ CODEC_ERROR PrepareEncoderTransforms(ENCODER *encoder);
+
+ //CODEC_ERROR ImageUnpackingProcess(ENCODER *encoder, IMAGE *image);
+ CODEC_ERROR ImageUnpackingProcess(const PACKED_IMAGE *packed_image,
+ UNPACKED_IMAGE *unpacked_image,
+ const ENCODER_PARAMETERS *parameters,
+ gpr_allocator *allocator);
+
+ CODEC_ERROR UnpackImage(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts);
+
+ CODEC_ERROR PreprocessImageRow(uint8_t *input, DIMENSION image_width, uint8_t *output);
+
+ CODEC_ERROR UnpackImageRow(uint8_t *input_row_ptr,
+ DIMENSION image_width,
+ PIXEL_FORMAT pixel_format,
+ PIXEL *output_row_ptr[],
+ PRECISION bits_per_component[],
+ int channel_count,
+ ENABLED_PARTS enabled_parts,
+ int raw_shift);
+
+ CODEC_ERROR EncodeBitstreamHeader(ENCODER *encoder, BITSTREAM *bitstream);
+
+ CODEC_ERROR EncodeBitstreamTrailer(ENCODER *encoder, BITSTREAM *bitstream);
+
+ CODEC_ERROR EncodeExtensionHeader(ENCODER *encoder, BITSTREAM *bitstream);
+
+ CODEC_ERROR EncodeExtensionTrailer(ENCODER *encoder, BITSTREAM *bitstream);
+
+ //CODEC_ERROR EncodeLayer(ENCODER *encoder, void *buffer, size_t pitch, BITSTREAM *stream);
+ CODEC_ERROR EncodeMultipleChannels(ENCODER *encoder, const UNPACKED_IMAGE *image, BITSTREAM *stream);
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ CODEC_ERROR EncodeLayerHeader(ENCODER *encoder, BITSTREAM *bitstream);
+ CODEC_ERROR EncodeLayerTrailer(ENCODER *encoder, BITSTREAM *bitstream);
+#endif
+
+ CODEC_ERROR SetEncoderQuantization(ENCODER *encoder,
+ const ENCODER_PARAMETERS *parameters);
+
+ CODEC_ERROR SetTransformQuantTable(ENCODER *encoder, int channel, const QUANT table[], int length);
+
+ CODEC_ERROR GetChannelDimensions(ENCODER *encoder,
+ int channel_number,
+ DIMENSION *channel_width_out,
+ DIMENSION *channel_height_out);
+
+ CODEC_ERROR GetMaximumChannelDimensions(const UNPACKED_IMAGE *image, DIMENSION *width_out, DIMENSION *height_out);
+
+ DIMENSION EncodedLayerHeight(ENCODER *encoder, DIMENSION height);
+
+ CODEC_ERROR SetEncodedBandMask(CODEC_STATE *codec, int subband);
+
+ CODEC_ERROR EncodeChannelSubbands(ENCODER *encoder, int channel, BITSTREAM *stream);
+
+ CODEC_ERROR EncodeChannelHeader(ENCODER *encoder,
+ int channel_number,
+ BITSTREAM *stream);
+
+ CODEC_ERROR EncodeChannelTrailer(ENCODER *encoder, int channel, BITSTREAM *stream);
+
+ //CODEC_ERROR EncodeLayerChannels(ENCODER *encoder, BITSTREAM *stream);
+ CODEC_ERROR EncodeChannelWavelets(ENCODER *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR PutVideoLowpassHeader(ENCODER *encoder, int channel_number, BITSTREAM *stream);
+
+ CODEC_ERROR PutVideoSubbandHeader(ENCODER *encoder, int subband, QUANT quantization, BITSTREAM *stream);
+ CODEC_ERROR PutVideoSubbandTrailer(ENCODER *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR TransformForwardSpatialQuantFrame(ENCODER *encoder, void *buffer, size_t pitch);
+
+ CODEC_ERROR AllocateEncoderHorizontalBuffers(ENCODER *encoder);
+
+ CODEC_ERROR DeallocateEncoderHorizontalBuffers(ENCODER *encoder);
+
+ CODEC_ERROR AllocateEncoderUnpackingBuffers(ENCODER *encoder, int frame_width);
+
+ CODEC_ERROR DeallocateEncoderUnpackingBuffers(ENCODER *encoder);
+
+ CODEC_ERROR AllocateHorizontalBuffers(gpr_allocator *allocator,
+ PIXEL *lowpass_buffer[],
+ PIXEL *highpass_buffer[],
+ int buffer_width);
+
+ CODEC_ERROR DeallocateHorizontalBuffers(gpr_allocator *allocator,
+ PIXEL *lowpass_buffer[],
+ PIXEL *highpass_buffer[]);
+
+
+ CODEC_ERROR PadWaveletBands(ENCODER *encoder, WAVELET *wavelet);
+
+ CODEC_ERROR EncodeLowpassBand(ENCODER *encoder, WAVELET *wavelet, int channel_number, BITSTREAM *stream);
+
+ CODEC_ERROR EncodeHighpassBand(ENCODER *encoder, WAVELET *wavelet, int band, int subband, BITSTREAM *stream);
+
+ CODEC_ERROR EncodeHighpassBandLongRuns(BITSTREAM *stream, ENCODER_CODESET *codeset, PIXEL *data,
+ DIMENSION width, DIMENSION height, DIMENSION pitch);
+
+ CODEC_ERROR EncodeHighpassBandRowRuns(BITSTREAM *stream, ENCODER_CODESET *codeset, PIXEL *data,
+ DIMENSION width, DIMENSION height, DIMENSION pitch);
+
+ CODEC_ERROR GetSampleOffsetSegment(BITSTREAM *bitstream, uint32_t offset, TAGVALUE *segment_out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ENCODER_H
diff --git a/gpr/source/lib/vc5_encoder/forward.c b/gpr/source/lib/vc5_encoder/forward.c
new file mode 100755
index 0000000..ab54dd8
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/forward.c
@@ -0,0 +1,851 @@
+/*! @file forward.c
+ *
+ * @brief Implementation of the forward wavelet transform functions.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+#if ENABLED(NEON)
+#include <arm_neon.h>
+#endif
+
+//! Rounding added to the highpass sum before division
+static const int32_t rounding = 4;
+
+STATIC_INLINE PIXEL QuantizeValue(int16_t value, int32_t midpoint, int32_t multiplier )
+{
+ int less_than_zero = 0;
+ int negate_less_than_zero = 0;
+
+ int16_t x = abs(value) + midpoint;
+
+ if( value < 0 )
+ {
+ less_than_zero = -1;
+ negate_less_than_zero = 1;
+ }
+
+ x = (int32_t)(x * multiplier) >> 16;
+
+ x = x ^ less_than_zero;
+ x = x + negate_less_than_zero;
+
+ return ClampPixel(x);
+}
+
+static void FilterVerticalTopBottom_Core_8x_C_(PIXEL *coefficients[], int column, int16_t* highpass, int16_t* lowpass, bool top )
+{
+ const int filter_coeffs_top[] = { 5, -11, 4, 4, -1, -1 };
+ const int filter_coeffs_bottom[] = { 1, 1, -4, -4, 11, -5 };
+
+ int low_band_index = top ? 0 : 4;
+ const int* filter_coeffs = top ? filter_coeffs_top : filter_coeffs_bottom;
+
+ int i, f;
+
+ for (i = 0; i < 8; i++)
+ {
+ lowpass[i] = coefficients[low_band_index + 0][column + i] + coefficients[low_band_index + 1][column + i];
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ int32_t sum = 0;
+
+ for (f = 0; f < 6; f++)
+ {
+ sum += filter_coeffs[f] * coefficients[f][column + i];
+ }
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ highpass[i] = sum;
+ }
+}
+
+#if ENABLED(NEON)
+
+static const uint16x8_t mask = {0x0000, 0xFFFF,0x0000,0xFFFF,0x0000,0xFFFF,0x0000, 0xFFFF};
+
+#define HorizontalFilter_Prescale2_4x HorizontalFilter_Prescale2_4x_NEON_
+void HorizontalFilter_Prescale2_4x_NEON_(PIXEL *input, PIXEL* lowpass, PIXEL* highpass )
+{
+ const int prescale_rounding = 3;
+ const int prescale = 2;
+
+ int32x4_t __pairwise_sum_0_7, __highpass;
+ int32x4_t __diff;
+ int16x8_t __input_2_9;
+
+ {
+ const int16x8_t __prescale_rounding = vdupq_n_s16 (prescale_rounding);
+ const int16x8_t __shift = vdupq_n_s16 (-prescale);
+
+ int16x8_t __input_0_7 = vld1q_s16( input );
+ __input_2_9 = vld1q_s16( input + 2 );
+ int16x8_t __input_8_15 = vld1q_s16( input + 8 );
+
+ __input_0_7 = vaddq_s16( __input_0_7, __prescale_rounding );
+ __input_0_7 = vshlq_s16( __input_0_7, __shift );
+
+ __input_8_15 = vaddq_s16( __input_8_15, __prescale_rounding );
+ __input_8_15 = vshlq_s16( __input_8_15, __shift );
+
+ __pairwise_sum_0_7 = vpaddlq_s16(__input_0_7);
+ int32x4_t __pairwise_sum_8_15 = vpaddlq_s16(__input_8_15);
+
+ __input_0_7 = vbslq_s16(mask, vnegq_s16(__input_0_7), __input_0_7);
+ __input_8_15 = vbslq_s16(mask, vnegq_s16(__input_8_15), __input_8_15);
+ __diff = vextq_s32(vpaddlq_s16( __input_0_7 ), vpaddlq_s16( __input_8_15 ), 1);
+
+ __highpass = vcombine_s32( vget_high_s32(__pairwise_sum_0_7), vget_low_s32(__pairwise_sum_8_15) );
+ }
+
+ // High pass band
+ {
+ const int32x4_t __rounding = vdupq_n_s32(rounding);
+
+ __highpass = vsubq_s32( __highpass, __pairwise_sum_0_7 );
+ __highpass = vaddq_s32( __highpass, __rounding );
+ __highpass = vshrq_n_s32( __highpass, 3 );
+ __highpass = vqaddq_s32( __highpass, __diff ); // Dont need to clamp because we are using saturating instruction
+
+ vst1_s16(highpass, vmovn_s32(__highpass) );
+ }
+
+ // Low pass band
+ {
+ const int32x4_t __prescale_rounding = vdupq_n_s32(prescale_rounding);
+ const int32x4_t __shift = vdupq_n_s32(-prescale);
+
+ int32x4_t __pairwise_sum_2_9 = vpaddlq_s16(__input_2_9);
+
+ __pairwise_sum_2_9 = vaddq_s32(__pairwise_sum_2_9, __prescale_rounding);
+ __pairwise_sum_2_9 = vshlq_s32(__pairwise_sum_2_9, __shift);
+
+ vst1_s16(lowpass, vmovn_s32(__pairwise_sum_2_9) );
+ }
+}
+
+#define HorizontalFilter_Prescale0_4x HorizontalFilter_Prescale0_4x_NEON_
+void HorizontalFilter_Prescale0_4x_NEON_(PIXEL *input, PIXEL* lowpass, PIXEL* highpass )
+{
+ int32x4_t __pairwise_sum_0_7, __highpass;
+ int32x4_t __diff;
+ int16x8_t __input_2_9;
+
+ {
+ int16x8_t __input_0_7 = vld1q_s16( input );
+ __input_2_9 = vld1q_s16( input + 2 );
+ int16x8_t __input_8_15 = vld1q_s16( input + 8 );
+
+ __pairwise_sum_0_7 = vpaddlq_s16(__input_0_7);
+ int32x4_t __pairwise_sum_8_15 = vpaddlq_s16(__input_8_15);
+
+ __input_0_7 = vbslq_s16(mask, vnegq_s16(__input_0_7), __input_0_7);
+ __input_8_15 = vbslq_s16(mask, vnegq_s16(__input_8_15), __input_8_15);
+ __diff = vextq_s32(vpaddlq_s16( __input_0_7 ), vpaddlq_s16( __input_8_15 ), 1);
+
+ __highpass = vcombine_s32( vget_high_s32(__pairwise_sum_0_7), vget_low_s32(__pairwise_sum_8_15) );
+ }
+
+ // High pass band
+ {
+ const int32x4_t __rounding = vdupq_n_s32(rounding);
+
+ __highpass = vsubq_s32( __highpass, __pairwise_sum_0_7 );
+ __highpass = vaddq_s32( __highpass, __rounding );
+ __highpass = vshrq_n_s32( __highpass, 3 );
+ __highpass = vqaddq_s32( __highpass, __diff ); // Dont need to clamp because we are using saturating instruction
+
+ vst1_s16(highpass, vmovn_s32(__highpass) );
+ }
+
+ // Low pass band
+ {
+ int32x4_t __pairwise_sum_2_9 = vpaddlq_s16(__input_2_9);
+
+ vst1_s16(lowpass, vmovn_s32(__pairwise_sum_2_9) );
+ }
+}
+
+void QuantizeBand_8x_NEON_(int16_t* wavelet_band, int16_t midpoint, int32_t multiplier, PIXEL *output )
+{
+ int16x8_t __wavelet_band = vld1q_s16( wavelet_band );
+
+ int16x8_t __wavelet_band_abs = vaddq_s16( vabsq_s16(__wavelet_band), vdupq_n_s16( midpoint ) );
+
+ int32x4_t __multipliers = vdupq_n_s32( multiplier );
+
+ int32x4_t __value_high = vmovl_s16( vget_high_s16(__wavelet_band_abs) );
+ __value_high = vmulq_s32( __value_high, __multipliers );
+
+ int32x4_t __value_low = vmovl_s16( vget_low_s16(__wavelet_band_abs) );
+ __value_low = vmulq_s32( __value_low, __multipliers );
+
+ int16x8_t __multiplied = vcombine_s16( vshrn_n_s32( __value_low, 16 ), vshrn_n_s32( __value_high, 16 ) );
+
+ uint16x8_t mask = vcltq_s16(__wavelet_band, vdupq_n_s16(0) );
+ int16x8_t __neg_output = vnegq_s16(__multiplied);
+
+ int16x8_t __result = vbslq_s16( mask, __neg_output, __multiplied );
+
+ vst1q_s16(output, __result);
+}
+
+void FilterVerticalMiddle_Core_8x_NEON_(PIXEL *coefficients[], int column, int16_t* highpass, int16_t* lowpass )
+{
+ int16x8_t __highpass, __highpass_50, __highpass_14;
+
+ {
+ int16x8_t __row_0 = vld1q_s16( &coefficients[0][column] );
+ int16x8_t __row_5 = vld1q_s16( &coefficients[5][column] );
+
+ __highpass_50 = vsubq_s16( __row_5, __row_0 );
+ }
+
+ {
+ int16x8_t __row_1 = vld1q_s16( &coefficients[1][column] );
+ int16x8_t __row_4 = vld1q_s16( &coefficients[4][column] );
+
+ __highpass_14 = vsubq_s16( __row_4, __row_1 );
+ }
+
+ {
+ int16x8_t __rounding = vdupq_n_s16 (rounding);
+
+ __highpass = vaddq_s16( __highpass_50, __highpass_14 );
+ __highpass = vaddq_s16( __highpass, __rounding );
+ __highpass = vshrq_n_s16(__highpass, 3);
+ }
+
+ {
+ int16x8_t __row_2 = vld1q_s16( &coefficients[2][column] );
+ int16x8_t __row_3 = vld1q_s16( &coefficients[3][column] );
+
+ int16x8_t __diff_23 = vsubq_s16( __row_2, __row_3 );
+ int16x8_t __sum_23 = vaddq_s16( __row_2, __row_3 );
+
+ __highpass = vaddq_s16( __highpass, __diff_23 );
+
+ vst1q_s16(lowpass, __sum_23);
+ }
+
+ vst1q_s16(highpass, __highpass);
+
+}
+
+#define FilterVerticalMiddle_8x FilterVerticalMiddle_8x_NEON_
+void FilterVerticalMiddle_8x_NEON_(PIXEL *lowpass[], PIXEL *highpass[], int column, int32_t* midpoints, int32_t* multipliers, PIXEL *result[])
+{
+ int16_t LOW[8];
+ int16_t HIGH[8];
+
+ FilterVerticalMiddle_Core_8x_NEON_( highpass, column, HIGH, LOW);
+ QuantizeBand_8x_NEON_( LOW, midpoints[LH_BAND], multipliers[LH_BAND], result[LH_BAND] + column );
+ QuantizeBand_8x_NEON_( HIGH, midpoints[HH_BAND], multipliers[HH_BAND], result[HH_BAND] + column );
+
+ FilterVerticalMiddle_Core_8x_NEON_( lowpass, column, HIGH, LOW);
+ QuantizeBand_8x_NEON_( LOW, midpoints[LL_BAND], multipliers[LL_BAND], result[LL_BAND] + column );
+ QuantizeBand_8x_NEON_( HIGH, midpoints[HL_BAND], multipliers[HL_BAND], result[HL_BAND] + column );
+}
+
+#define FilterVerticalTopBottom_8x FilterVerticalTopBottom_8x_NEON_
+void FilterVerticalTopBottom_8x_NEON_(PIXEL *lowpass[], PIXEL *highpass[], int column, int32_t* midpoints, int32_t* multipliers, PIXEL *result[], bool top )
+{
+ int16_t LOW[8];
+ int16_t HIGH[8];
+
+ FilterVerticalTopBottom_Core_8x_C_( highpass, column, HIGH, LOW, top );
+ QuantizeBand_8x_NEON_( LOW, midpoints[LH_BAND], multipliers[LH_BAND], result[LH_BAND] + column );
+ QuantizeBand_8x_NEON_( HIGH, midpoints[HH_BAND], multipliers[HH_BAND], result[HH_BAND] + column );
+
+ FilterVerticalTopBottom_Core_8x_C_( lowpass, column, HIGH, LOW, top );
+ QuantizeBand_8x_NEON_( LOW, midpoints[LL_BAND], multipliers[LL_BAND], result[LL_BAND] + column );
+ QuantizeBand_8x_NEON_( HIGH, midpoints[HL_BAND], multipliers[HL_BAND], result[HL_BAND] + column );
+}
+
+#else
+
+#define HorizontalFilter_Prescale2_4x HorizontalFilter_Prescale2_4x_C_
+void HorizontalFilter_Prescale2_4x_C_(PIXEL *input, PIXEL* lowpass, PIXEL* highpass )
+{
+ int i;
+ PIXEL input_c[16];
+ for ( i = 0; i < 12; i++)
+ {
+ input_c[i] = (input[i] + 3) >> 2;
+ }
+
+ int32_t diff_23 = input_c[2] - input_c[3];
+ int32_t diff_45 = input_c[4] - input_c[5];
+ int32_t diff_67 = input_c[6] - input_c[7];
+ int32_t diff_89 = input_c[8] - input_c[9];
+
+ int32_t sum_01 = input_c[0] + input_c[1];
+ int32_t sum_23 = input_c[2] + input_c[3];
+ int32_t sum_45 = input_c[4] + input_c[5];
+ int32_t sum_67 = input_c[6] + input_c[7];
+ int32_t sum_89 = input_c[8] + input_c[9];
+ int32_t sum_1011 = input_c[10] + input_c[11];
+
+ {
+ int32_t sum = sum_45 - sum_01;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_23;
+
+ highpass[0] = ClampPixel(sum);
+ }
+
+ {
+ int32_t sum = sum_67 - sum_23;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_45;
+
+ highpass[1] = ClampPixel(sum);
+ }
+
+ {
+ int32_t sum = sum_89 - sum_45;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_67;
+
+ highpass[2] = ClampPixel(sum);
+ }
+
+ {
+ int32_t sum = sum_1011 - sum_67;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_89;
+
+ highpass[3] = ClampPixel(sum);
+ }
+
+ lowpass[0] = (input[2] + input[3] + 3) >> 2;
+ lowpass[1] = (input[4] + input[5] + 3) >> 2;
+ lowpass[2] = (input[6] + input[7] + 3) >> 2;
+ lowpass[3] = (input[8] + input[9] + 3) >> 2;
+}
+
+#define HorizontalFilter_Prescale0_4x HorizontalFilter_Prescale0_4x_C_
+void HorizontalFilter_Prescale0_4x_C_(PIXEL *input, PIXEL* lowpass, PIXEL* highpass )
+{
+ PIXEL input_c[16];
+
+ memcpy(input_c, input, sizeof(PIXEL) * 12);
+
+ int32_t diff_23 = input_c[2] - input_c[3];
+ int32_t diff_45 = input_c[4] - input_c[5];
+ int32_t diff_67 = input_c[6] - input_c[7];
+ int32_t diff_89 = input_c[8] - input_c[9];
+
+ int32_t sum_01 = input_c[0] + input_c[1];
+ int32_t sum_23 = input_c[2] + input_c[3];
+ int32_t sum_45 = input_c[4] + input_c[5];
+ int32_t sum_67 = input_c[6] + input_c[7];
+ int32_t sum_89 = input_c[8] + input_c[9];
+ int32_t sum_1011 = input_c[10] + input_c[11];
+
+ {
+ int32_t sum = sum_45 - sum_01;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_23;
+
+ highpass[0] = ClampPixel(sum);
+ }
+
+ {
+ int32_t sum = sum_67 - sum_23;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_45;
+
+ highpass[1] = ClampPixel(sum);
+ }
+
+ {
+ int32_t sum = sum_89 - sum_45;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_67;
+
+ highpass[2] = ClampPixel(sum);
+ }
+
+ {
+ int32_t sum = sum_1011 - sum_67;
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += diff_89;
+
+ highpass[3] = ClampPixel(sum);
+ }
+
+ lowpass[0] = input[2] + input[3];
+ lowpass[1] = input[4] + input[5];
+ lowpass[2] = input[6] + input[7];
+ lowpass[3] = input[8] + input[9];
+}
+
+void FilterVerticalMiddle_Core_8x_C_(PIXEL *coefficients[], int column, int16_t* highpass, int16_t* lowpass )
+{
+ PIXEL row_0[8];
+ PIXEL row_1[8];
+ PIXEL row_2[8];
+ PIXEL row_3[8];
+ PIXEL row_4[8];
+ PIXEL row_5[8];
+
+ int i;
+
+ memcpy( row_0, &coefficients[0][column], sizeof(PIXEL) * 8 );
+ memcpy( row_1, &coefficients[1][column], sizeof(PIXEL) * 8 );
+ memcpy( row_2, &coefficients[2][column], sizeof(PIXEL) * 8 );
+ memcpy( row_3, &coefficients[3][column], sizeof(PIXEL) * 8 );
+ memcpy( row_4, &coefficients[4][column], sizeof(PIXEL) * 8 );
+ memcpy( row_5, &coefficients[5][column], sizeof(PIXEL) * 8 );
+
+ for (i = 0; i < 8; i++)
+ highpass[i] = (-1 * row_0[i] + row_5[i]);
+
+ for (i = 0; i < 8; i++)
+ highpass[i] += (-1 * row_1[i] + row_4[i]);
+
+ for (i = 0; i < 8; i++)
+ highpass[i] += rounding;
+
+ for (i = 0; i < 8; i++)
+ highpass[i] = DivideByShift(highpass[i], 3);
+
+ for (i = 0; i < 8; i++)
+ {
+ highpass[i] += (row_2[i] - row_3[i]);
+ lowpass[i] = (row_2[i] + row_3[i]);
+ }
+}
+
+
+#define FilterVerticalMiddle_8x FilterVerticalMiddle_8x_C_
+void FilterVerticalMiddle_8x_C_(PIXEL *lowpass[], PIXEL *highpass[], int column, int32_t* midpoints, int32_t* multipliers, PIXEL *result[])
+{
+ int i;
+
+ int16_t LL[8];
+ int16_t HL[8];
+ int16_t LH[8];
+ int16_t HH[8];
+
+ FilterVerticalMiddle_Core_8x_C_( highpass, column, HH, LH);
+ FilterVerticalMiddle_Core_8x_C_( lowpass, column, HL, LL);
+
+ for (i = 0; i < 8; i++)
+ {
+ result[LL_BAND][column + i] = QuantizeValue( LL[i], midpoints[LL_BAND], multipliers[LL_BAND] );
+ result[LH_BAND][column + i] = QuantizeValue( LH[i], midpoints[LH_BAND], multipliers[LH_BAND] );
+ result[HL_BAND][column + i] = QuantizeValue( HL[i], midpoints[HL_BAND], multipliers[HL_BAND] );
+ result[HH_BAND][column + i] = QuantizeValue( HH[i], midpoints[HH_BAND], multipliers[HH_BAND] );
+ }
+}
+
+#define FilterVerticalTopBottom_8x FilterVerticalTopBottom_8x_C_
+void FilterVerticalTopBottom_8x_C_(PIXEL *lowpass[], PIXEL *highpass[], int column, int32_t* midpoints, int32_t* multipliers, PIXEL *result[], bool top )
+{
+ int i;
+
+ int16_t LL[8];
+ int16_t HL[8];
+ int16_t LH[8];
+ int16_t HH[8];
+
+ FilterVerticalTopBottom_Core_8x_C_( highpass, column, HH, LH, top );
+ FilterVerticalTopBottom_Core_8x_C_( lowpass, column, HL, LL, top );
+
+ for (i = 0; i < 8; i++)
+ {
+ result[LL_BAND][column + i] = QuantizeValue( LL[i], midpoints[LL_BAND], multipliers[LL_BAND] );
+ result[LH_BAND][column + i] = QuantizeValue( LH[i], midpoints[LH_BAND], multipliers[LH_BAND] );
+ result[HL_BAND][column + i] = QuantizeValue( HL[i], midpoints[HL_BAND], multipliers[HL_BAND] );
+ result[HH_BAND][column + i] = QuantizeValue( HH[i], midpoints[HH_BAND], multipliers[HH_BAND] );
+ }
+}
+
+#endif
+
+static PIXEL HorizontalHighPassFilter_Middle(PIXEL *input, int prescale_rounding, int prescale)
+{
+ int32_t sum;
+
+ if( prescale == 0 )
+ {
+ sum = -input[0] - input[1] + (input[2] << 3) - (input[3] << 3) + input[4] + input[5];
+ }
+ else
+ {
+ sum = 0;
+ sum -= (input[0] + prescale_rounding) >> prescale;
+ sum -= (input[1] + prescale_rounding) >> prescale;
+ sum += ((input[2] + prescale_rounding) >> prescale) << 3;
+ sum -= ((input[3] + prescale_rounding) >> prescale) << 3;
+ sum += (input[4] + prescale_rounding) >> prescale;
+ sum += (input[5] + prescale_rounding) >> prescale;
+ }
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ return ClampPixel(sum);
+}
+
+static PIXEL HorizontalHighPassFilter(PIXEL *input, PIXEL *multipliers, int prescale_rounding, int prescale)
+{
+ int i;
+ int32_t sum = 0;
+
+ if( prescale == 0 )
+ {
+ for (i = 0; i < 6; i++)
+ {
+ sum += multipliers[i] * input[i];
+ }
+
+ }
+ else
+ {
+ for (i = 0; i < 6; i++)
+ {
+ sum += multipliers[i] * ( (input[i] + prescale_rounding) >> prescale);
+ }
+ }
+
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ return ClampPixel(sum);
+}
+
+/*!
+ @brief Apply the horizontal wavelet filter to a row of pixels
+*/
+CODEC_ERROR FilterHorizontalRow(PIXEL *input, PIXEL *lowpass, PIXEL *highpass, int width, int prescale)
+{
+ int column = 2;
+
+ //uint16_t *input = (uint16_t *)input_buffer;
+
+ //TODO: Check that the rounding is correct for all prescale values
+ int prescale_rounding = (1 << prescale) - 1;
+
+ const int last_input_column = ((width % 2) == 0) ? width - 2 : width - 1;
+
+ int last_input_column_tight = ( (last_input_column - 4) / 8) * 8;
+
+ //TODO Test this routine with other prescale values
+ assert(prescale == 0 || prescale == 2);
+
+ /***** Process the left border using the formula for boundary conditions *****/
+
+ // Compute the lowpass coefficient
+ lowpass[0] = (input[0] + input[1] + prescale_rounding) >> prescale;
+
+ {
+ PIXEL coefficients[6] = { 5, -11, 4, 4, -1, -1 };
+ highpass[0] = HorizontalHighPassFilter(input, coefficients, prescale_rounding, prescale );
+ }
+
+ if( prescale == 2 )
+ {
+ /***** Process the internal pixels using the normal wavelet formula *****/
+ for (; column < last_input_column_tight; column += 8) //
+ {
+ // Column index should always be divisible by two
+ assert((column % 2) == 0);
+
+ HorizontalFilter_Prescale2_4x( input + column - 2, &lowpass[column/2], &highpass[column/2] );
+ }
+ }
+ else if( prescale == 0 )
+ {
+ /***** Process the internal pixels using the normal wavelet formula *****/
+ for (; column < last_input_column_tight; column += 8) //
+ {
+ // Column index should always be divisible by two
+ assert((column % 2) == 0);
+
+ HorizontalFilter_Prescale0_4x( input + column - 2, &lowpass[column/2], &highpass[column/2] );
+ }
+ }
+ else
+ {
+ assert(0);
+ }
+
+ for (; column < last_input_column; column += 2)
+ {
+ // Column index should always be divisible by two
+ assert((column % 2) == 0);
+
+ // Compute the lowpass coefficient
+ lowpass[column/2] = (input[column + 0] + input[column + 1] + prescale_rounding) >> prescale;
+
+ // Initialize the sum for computing the highpass coefficient
+ if ((column + 3) < width)
+ {
+ highpass[column/2] = HorizontalHighPassFilter_Middle(input + column - 2, prescale_rounding, prescale );
+ }
+ else
+ {
+ int32_t sum = 0;
+
+ sum -= (input[column - 2] + prescale_rounding) >> prescale;
+ sum -= (input[column - 1] + prescale_rounding) >> prescale;
+ sum += (input[column + 2] + prescale_rounding) >> prescale;
+
+ // Duplicate the value in the last column
+ sum += (input[column + 2] + prescale_rounding) >> prescale;
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+ sum += (input[column + 0] + prescale_rounding) >> prescale;
+ sum -= (input[column + 1] + prescale_rounding) >> prescale;
+ highpass[column/2] = ClampPixel(sum);
+ }
+ }
+
+ // Should have exited the loop at the last column
+ assert(column == last_input_column);
+
+ /***** Process the right border using the formula for boundary conditions *****/
+
+ // Compute the lowpass coefficient
+ if ((column + 1) < width)
+ {
+ PIXEL coefficients[6] = { 1, 1, -4, -4, 11, -5 };
+ highpass[column/2] = HorizontalHighPassFilter(input + column - 4, coefficients, prescale_rounding, prescale );
+
+ // Use the value in the last column
+ lowpass[column/2] = (input[column + 0] + input[column + 1] + prescale_rounding) >> prescale;
+ }
+ else
+ {
+ int32_t sum = 0;
+ // Duplicate the value in the last column
+ sum -= 5 * ((input[column + 0] + prescale_rounding) >> prescale);
+
+ sum += 11 * ((input[column + 0] + prescale_rounding) >> prescale);
+ sum -= 4 * ((input[column - 1] + prescale_rounding) >> prescale);
+ sum -= 4 * ((input[column - 2] + prescale_rounding) >> prescale);
+ sum += 1 * ((input[column - 3] + prescale_rounding) >> prescale);
+ sum += 1 * ((input[column - 4] + prescale_rounding) >> prescale);
+ sum += rounding;
+ sum = DivideByShift(sum, 3);
+
+ highpass[column/2] = ClampPixel(sum);
+
+ // Duplicate the value in the last column
+ lowpass[column/2] = (input[column + 0] + input[column + 0] + prescale_rounding) >> prescale;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+static void FilterVerticalMiddle_1x(PIXEL *lowpass[], PIXEL *highpass[], int column, int32_t* midpoints, int32_t* multipliers, PIXEL *result[])
+{
+ {
+ const PIXEL coefficients_01 = lowpass[0][column] + lowpass[1][column];
+ const PIXEL coefficients_2 = lowpass[2][column];
+ const PIXEL coefficients_3 = lowpass[3][column];
+ const PIXEL coefficients_45 = lowpass[4][column] + lowpass[5][column];
+
+ int32_t sum = coefficients_45 - coefficients_01;
+ sum += 8 * (coefficients_2 - coefficients_3);
+ sum = DivideByShift(sum + rounding, 3);
+
+ result[LL_BAND][column] = QuantizeValue( coefficients_2 + coefficients_3, midpoints[LL_BAND], multipliers[LL_BAND] );
+ result[HL_BAND][column] = QuantizeValue( sum, midpoints[HL_BAND], multipliers[HL_BAND] );
+ }
+
+ {
+ const PIXEL coefficients_01 = highpass[0][column] + highpass[1][column];
+ const PIXEL coefficients_2 = highpass[2][column];
+ const PIXEL coefficients_3 = highpass[3][column];
+ const PIXEL coefficients_45 = highpass[4][column] + highpass[5][column];
+
+ int32_t sum = coefficients_45 - coefficients_01;
+ sum += 8 * (coefficients_2 - coefficients_3);
+ sum = DivideByShift(sum + rounding, 3);
+
+ result[LH_BAND][column] = QuantizeValue( coefficients_2 + coefficients_3, midpoints[LH_BAND], multipliers[LH_BAND] );
+ result[HH_BAND][column] = QuantizeValue( sum, midpoints[HH_BAND], multipliers[HH_BAND] );
+ }
+}
+
+static void FilterVerticalTopBottom_1x(PIXEL *lowpass[], PIXEL *highpass[], int column, int32_t* midpoints, int32_t* multipliers, PIXEL *result[], bool top )
+{
+ const int filter_coeffs_top[] = { 5, -11, 4, 4, -1, -1 };
+ const int filter_coeffs_bottom[] = { 1, 1, -4, -4, 11, -5 };
+
+ int low_band_index = top ? 0 : 4;
+ const int* filter_coeffs = top ? filter_coeffs_top : filter_coeffs_bottom;
+
+ int i;
+ int32_t sum_L = 0;
+ int32_t sum_H = 0;
+
+ // Apply the lowpass vertical filter to the lowpass horizontal results
+ result[LL_BAND][column] = QuantizeValue( lowpass[low_band_index + 0][column] + lowpass[low_band_index + 1][column], midpoints[LL_BAND], multipliers[LL_BAND] );
+
+ // Apply the lowpass vertical filter to the highpass horizontal results
+ result[LH_BAND][column] = QuantizeValue( highpass[low_band_index + 0][column] + highpass[low_band_index + 1][column], midpoints[LH_BAND], multipliers[LH_BAND] );
+
+ for (i = 0; i < 6; i++)
+ {
+ sum_L += filter_coeffs[i] * lowpass[i][column];
+ sum_H += filter_coeffs[i] * highpass[i][column];
+ }
+
+ sum_L += rounding;
+ sum_L = DivideByShift(sum_L, 3);
+ result[HL_BAND][column] = QuantizeValue( sum_L, midpoints[HL_BAND], multipliers[HL_BAND] );
+
+ sum_H += rounding;
+ sum_H = DivideByShift(sum_H, 3);
+ result[HH_BAND][column] = QuantizeValue( sum_H, midpoints[HH_BAND], multipliers[HH_BAND] );
+}
+
+/*!
+ @brief Apply the vertical wavelet filter to the first row
+
+ This routine uses the wavelet formulas for the top row of an image
+
+ The midpoint prequant argument is not the offset that is added to the
+ value prior to quantization. It is a setting indicating which midpoint
+ offset to use.
+
+ @todo Change the midpoint_prequant argument to midpoint_setting?
+*/
+CODEC_ERROR FilterVerticalTopRow(PIXEL **lowpass, PIXEL **highpass, PIXEL **output, int wavelet_width, int wavelet_pitch, int32_t midpoints[], int32_t multipliers[], int input_row )
+{
+ int column = 0;
+ const int wavelet_width_m8 = (wavelet_width / 8) * 8;
+
+ assert(input_row == 0);
+
+ for (; column < wavelet_width_m8; column += 8)
+ {
+ FilterVerticalTopBottom_8x( lowpass, highpass, column, midpoints, multipliers, output, true );
+
+ assert(output[LL_BAND][column] >= 0);
+ }
+
+ for (; column < wavelet_width; column++)
+ {
+ FilterVerticalTopBottom_1x( lowpass, highpass, column, midpoints, multipliers, output, true );
+
+ assert(output[LL_BAND][column] >= 0);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+
+CODEC_ERROR FilterVerticalBottomRow(PIXEL **lowpass, PIXEL **highpass, PIXEL **output, int wavelet_width, int wavelet_pitch, int32_t midpoints[], int32_t multipliers[], int input_row )
+{
+ PIXEL *result[MAX_BAND_COUNT];
+ int column = 0;
+ const int wavelet_width_m8 = (wavelet_width / 8) * 8;
+
+ int band;
+
+ //uint16_t **lowpass = (uint16_t **)lowpass_buffer;
+
+ int output_row = input_row / 2;
+
+ // Compute the address of each output row
+ for (band = 0; band < MAX_BAND_COUNT; band++)
+ {
+ uint8_t *band_row_ptr = (uint8_t *)output[band];
+ band_row_ptr += output_row * wavelet_pitch;
+ result[band] = (PIXEL *)band_row_ptr;
+ }
+
+ for (; column < wavelet_width_m8; column += 8)
+ {
+ FilterVerticalTopBottom_8x( lowpass, highpass, column, midpoints, multipliers, result, false );
+
+ assert(result[LL_BAND][column] >= 0);
+ }
+
+ for (; column < wavelet_width; column++)
+ {
+ FilterVerticalTopBottom_1x( lowpass, highpass, column, midpoints, multipliers, result, false );
+
+ assert(result[LL_BAND][column] >= 0);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Apply the vertical wavelet filter to a middle row
+
+ This routine uses the wavelet formulas for the middle rows of an image
+*/
+CODEC_ERROR FilterVerticalMiddleRow(PIXEL **lowpass, PIXEL **highpass, PIXEL **output, int wavelet_width, int wavelet_pitch, int32_t midpoints[], int32_t multipliers[], int input_row )
+{
+ PIXEL *result[MAX_BAND_COUNT];
+
+ int column = 0;
+ int band;
+
+ const int wavelet_width_m8 = (wavelet_width / 8) * 8;
+
+ //uint16_t **lowpass = (uint16_t **)lowpass_buffer;
+
+ int output_row = input_row / 2;
+
+ // Compute the address of each output row
+ for (band = 0; band < MAX_BAND_COUNT; band++)
+ {
+ uint8_t *band_row_ptr = (uint8_t *)output[band];
+ band_row_ptr += output_row * wavelet_pitch;
+ result[band] = (PIXEL *)band_row_ptr;
+ }
+
+ for (; column < wavelet_width_m8; column += 8)
+ {
+ FilterVerticalMiddle_8x(lowpass, highpass, column, midpoints, multipliers, result);
+ }
+
+ for (; column < wavelet_width; column += 1)
+ {
+ FilterVerticalMiddle_1x(lowpass, highpass, column, midpoints, multipliers, result);
+
+ assert(result[LL_BAND][column] >= 0);
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
diff --git a/gpr/source/lib/vc5_encoder/forward.h b/gpr/source/lib/vc5_encoder/forward.h
new file mode 100755
index 0000000..74e2369
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/forward.h
@@ -0,0 +1,38 @@
+/*! @file forward.h
+ *
+ * @brief Declare of the forward wavelet transform functions.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FORWARD_H
+#define FORWARD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR FilterHorizontalRow(PIXEL *input, PIXEL *lowpass, PIXEL *highpass, int width, int prescale);
+
+ CODEC_ERROR FilterVerticalTopRow(PIXEL **lowpass, PIXEL **highpass, PIXEL **output, int wavelet_width, int wavelet_pitch, int32_t midpoints[], int32_t multipliers[], int input_row );
+
+ CODEC_ERROR FilterVerticalMiddleRow(PIXEL **lowpass, PIXEL **highpass, PIXEL **output, int wavelet_width, int wavelet_pitch, int32_t midpoints[], int32_t multipliers[], int input_row );
+
+ CODEC_ERROR FilterVerticalBottomRow(PIXEL **lowpass, PIXEL **highpass, PIXEL **output, int wavelet_width, int wavelet_pitch, int32_t midpoints[], int32_t multipliers[], int input_row );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // FORWARD_H
diff --git a/gpr/source/lib/vc5_encoder/headers.h b/gpr/source/lib/vc5_encoder/headers.h
new file mode 100755
index 0000000..bdf8ad9
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/headers.h
@@ -0,0 +1,50 @@
+/*! @file headers.h
+ *
+ * @brief This file includes all of the header files that are used by the encoder.
+ *
+ * Note that some header files are only used by the main program that
+ * calls the codec or are only used for debugging are not included by this file.
+ * Only headers that are part of the reference encoder are included by this file.
+ *
+ * Including a single header file in all reference encoder source files
+ * ensures that all modules see the same header files in the same order.
+ *
+ * This file can be used for creating a pre-compiled header if the
+ * compiler supports that capabilities.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HEADERS_H
+#define HEADERS_H
+
+#include "common.h"
+
+#include "vlc.h"
+#include "bitstream.h"
+#include "raw.h"
+#include "codebooks.h"
+#include "component.h"
+#include "syntax.h"
+#include "forward.h"
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+#include "sections.h"
+#endif
+
+#include "parameters.h"
+#include "encoder.h"
+#include "vc5_encoder.h"
+
+#endif // HEADERS_H
diff --git a/gpr/source/lib/vc5_encoder/parameters.c b/gpr/source/lib/vc5_encoder/parameters.c
new file mode 100755
index 0000000..2158a71
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/parameters.c
@@ -0,0 +1,86 @@
+/*! @file parameters.c
+ *
+ * @brief Implementation of the data structure used to pass parameters
+ * to the encoder.
+ *
+ * The parameters data structure is currently a simple struct, but
+ * fields may be added, removed, or replaced. A version number is
+ * included in the parameters data structure to allow decoders to
+ * adapt to changes.
+
+ * It is contemplated that future inplementations may use a dictionary
+ * of key-value pairs which would allow the decoder to determine whether
+ * a parameter is present.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+//! Current version number of the parameters data structure
+#define PARAMETERS_VERSION 1
+
+/*!
+ @brief Initialize the parameters data structure
+
+ The version number of the parameters data structure must be
+ incremented whenever a change is made to the definition of
+ the parameters data structure.
+
+ @todo Special initialization required by the metadata?
+*/
+CODEC_ERROR InitEncoderParameters(ENCODER_PARAMETERS *parameters)
+{
+ memset(parameters, 0, sizeof(ENCODER_PARAMETERS));
+ parameters->version = PARAMETERS_VERSION;
+
+ // Set the default value for the number of bits per lowpass coefficient
+ parameters->encoded.lowpass_precision = 16;
+
+ parameters->input.width = 4000;
+ parameters->input.height = 3000;
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ // The maximum number of bits per component is the internal precision
+ //parameters->max_bits_per_component = internal_precision;
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ parameters->enabled_sections = VC5_ENABLED_SECTIONS;
+#endif
+
+ // The elementary bitstream is always enabled
+ parameters->enabled_parts = VC5_ENABLED_PARTS;
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ parameters->layer_count = 1;
+ parameters->progressive = 1;
+#endif
+
+ // Initialize the quantization table using the default values
+ {
+ // Initialize to CineForm Filmscan-2
+ QUANT quant_table[] = {1, 24, 24, 12, 24, 24, 12, 32, 32, 48};
+ memcpy(parameters->quant_table, quant_table, sizeof(parameters->quant_table));
+ }
+
+ parameters->verbose_flag = false;
+
+ gpr_rgb_gain_set_defaults(&parameters->rgb_gain);
+
+ parameters->rgb_resolution = VC5_ENCODER_RGB_RESOLUTION_DEFAULT;
+
+ return CODEC_ERROR_OKAY;
+}
+
diff --git a/gpr/source/lib/vc5_encoder/parameters.h b/gpr/source/lib/vc5_encoder/parameters.h
new file mode 100755
index 0000000..b2cac04
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/parameters.h
@@ -0,0 +1,139 @@
+/*! @file parameters.h
+ *
+ * @brief Declare a data structure for holding a table of parameters that is passed
+ * to the encoder during initialization.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PARAMETERS_H
+#define PARAMETERS_H
+
+#include "vc5_encoder.h"
+
+/*!
+ @brief Function prototype for a decompositor
+
+ A decompositor is the opposite of an image composition operator:
+ It decomposes a frame into one or more frames.
+
+ For example, an interlaced frame can be decomposed into fields or two frames
+ arranged side-by-side within a single frame can be decomposed into individual
+ frames.
+
+ Each layer in an encoded sample may correspond to a separate input frame.
+ For convenience, the reference codec stores the input to the encoder in a
+ separate file with one frame per file if the encoded sample has a single layer.
+ To allow the reference encoder to store all of the input frames that are
+ encoded as separate layers in an encoded sample in a single file, multiple
+ frames are stored in the file (often using over-under frame packing). The
+ decomposer unpacks multiple frames in a single frame into individual frames
+ for encoding with one frame per layer.
+*/
+
+typedef CODEC_ERROR (* DECOMPOSITOR)(IMAGE *packed_image, IMAGE *image_array[], int frame_count);
+
+/*!
+ @brief Declaration of a data structure for passing parameters to the encoder
+
+ The encoded dimensions are the width and height of the planes of pixels as
+ represented internally in the encoded sample. In the case where the planes
+ have different dimensions (for example YUV with 4:2:2 sampling), the first
+ encoded plane (corresponding to the luma plane, for example) is reported.
+*/
+typedef struct _encoder_parameters
+{
+ uint32_t version; //!< Version number for this definition of the parameters
+
+ // BAYER_ORDERING bayer_ordering;
+
+ ENABLED_PARTS enabled_parts; //!< Parts of the VC-5 standard that are enabled
+
+ //! Data structure for the input frame dimensions and format
+ struct _input_parameters
+ {
+ DIMENSION width; //!< Width of the frames input to the encoder
+ DIMENSION height; //!< Height of the frames input to the encoder
+ PIXEL_FORMAT format; //!< Pixel format of the input frames
+ PRECISION precision; //!< Bits per component in the input image
+
+ } input; //!< Dimensions and format of the input frame
+
+ //! Data structure for the encoded representation of the image
+ struct _encoded_parameters
+ {
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ DIMENSION width; //!< Width of the encoded frame
+ DIMENSION height; //!< Height of the encoded frame
+ IMAGE_FORMAT format; //!< Internal format of the encoded image
+ PRECISION precision; //!< Encoded precision of the image after scaling
+#endif
+ //! Number of bits used to encode lowpass coefficients
+ PRECISION lowpass_precision;
+
+ } encoded; //!< Encoded frame dimensions and the encoded format
+
+ //! Array of quantization values indexed by the subband number
+ QUANT quant_table[MAX_SUBBAND_COUNT];
+
+#if VC5_ENABLED_PART(VC5_PART_METADATA)
+ //! Metadata that controls decoding (currently not used)
+ METADATA metadata;
+#endif
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ int layer_count;
+ int progressive;
+ DECOMPOSITOR decompositor;
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+ ENABLED_SECTIONS enabled_sections;
+#endif
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ // Definition of the pattern elements
+ DIMENSION pattern_width;
+ DIMENSION pattern_height;
+ DIMENSION components_per_sample;
+ //PRECISION max_bits_per_component;
+#endif
+
+ //! Table for the order in which channels are encoded into the bitstream
+ CHANNEL channel_order_table[MAX_CHANNEL_COUNT];
+
+ //! Number of entries in the channel order table (may be less than the channel count)
+ int channel_order_count;
+
+ //! Flag that controls verbose output
+ bool verbose_flag;
+
+ gpr_allocator allocator;
+
+ GPR_RGB_RESOLUTION rgb_resolution;
+
+ gpr_rgb_gain rgb_gain;
+
+} ENCODER_PARAMETERS;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR InitEncoderParameters(ENCODER_PARAMETERS *parameters);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PARAMETERS_H
diff --git a/gpr/source/lib/vc5_encoder/raw.c b/gpr/source/lib/vc5_encoder/raw.c
new file mode 100755
index 0000000..cc1a302
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/raw.c
@@ -0,0 +1,621 @@
+/*! @file raw.c
+ *
+ * @brief Implementation of routines for packing RAW image to a row of pixels.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+#if ENABLED(NEON)
+#include <arm_neon.h>
+#endif
+
+/** ------------------- **/
+/** 14 BIT INPUT FORMAT **/
+/** ------------------- **/
+
+static void UnpackPixel_14(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ uint16_t R1, G1, G2, B1;
+ uint16_t GS, GD, RG, BG;
+
+ uint16_t *GS_output_row_ptr = (uint16_t *)output_buffer[0];
+ uint16_t *GD_output_row_ptr = (uint16_t *)output_buffer[3];
+ uint16_t *RG_output_row_ptr = (uint16_t *)output_buffer[1];
+ uint16_t *BG_output_row_ptr = (uint16_t *)output_buffer[2];
+
+ const int internal_precision = 12;
+ const int32_t midpoint = (1 << (internal_precision - 1));
+
+ if( rggb )
+ {
+ R1 = input_row1_ptr[2 * column + 0];
+ G1 = input_row1_ptr[2 * column + 1];
+ G2 = input_row2_ptr[2 * column + 0];
+ B1 = input_row2_ptr[2 * column + 1];
+ }
+ else
+ {
+ G1 = input_row1_ptr[2 * column + 0];
+ B1 = input_row1_ptr[2 * column + 1];
+ R1 = input_row2_ptr[2 * column + 0];
+ G2 = input_row2_ptr[2 * column + 1];
+ }
+
+ // Apply protune log curve
+ R1 = EncoderLogCurve[ R1 >> 2 ];
+ G1 = EncoderLogCurve[ G1 >> 2 ];
+ G2 = EncoderLogCurve[ G2 >> 2 ];
+ B1 = EncoderLogCurve[ B1 >> 2 ];
+
+ // Difference the green components and subtract green from the red and blue components
+ GS = (G1 + G2) >> 1;
+ GD = (G1 - G2 + 2 * midpoint) >> 1;
+ RG = (R1 - GS + 2 * midpoint) >> 1;
+ BG = (B1 - GS + 2 * midpoint) >> 1;
+
+ GS_output_row_ptr[column] = clamp_uint(GS, internal_precision);
+ GD_output_row_ptr[column] = clamp_uint(GD, internal_precision);
+ RG_output_row_ptr[column] = clamp_uint(RG, internal_precision);
+ BG_output_row_ptr[column] = clamp_uint(BG, internal_precision);
+}
+
+#if ENABLED(NEON)
+
+#define UnpackPixel_14_8x UnpackPixel_14_8x_NEON_
+static void UnpackPixel_14_8x_NEON_(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ int i;
+ uint16x8x2_t row_1, row_2;
+
+ const int internal_precision = 12;
+ const int32_t midpoint = (1 << (internal_precision - 1));
+
+ // Apply protune log curve
+ {
+ uint16_t input_row1_12b[16];
+ uint16_t input_row2_12b[16];
+
+ for (i = 0; i < 16; ++i)
+ {
+ input_row1_12b[i] = EncoderLogCurve[ input_row1_ptr[2 * column + i] >> 2 ];
+ input_row2_12b[i] = EncoderLogCurve[ input_row2_ptr[2 * column + i] >> 2 ];
+ }
+
+ row_1 = vld2q_u16( input_row1_12b );
+ row_2 = vld2q_u16( input_row2_12b );
+ }
+
+ int16x8_t R1, G1, G2, B1;
+
+ if( rggb )
+ {
+ R1 = vreinterpretq_s16_u16( row_1.val[0] );
+ G1 = vreinterpretq_s16_u16( row_1.val[1] );
+ G2 = vreinterpretq_s16_u16( row_2.val[0] );
+ B1 = vreinterpretq_s16_u16( row_2.val[1] );
+ }
+ else
+ {
+ G1 = vreinterpretq_s16_u16( row_1.val[0] );
+ B1 = vreinterpretq_s16_u16( row_1.val[1] );
+ R1 = vreinterpretq_s16_u16( row_2.val[0] );
+ G2 = vreinterpretq_s16_u16( row_2.val[1] );
+ }
+
+ int16x8_t GS, GD, RG, BG;
+
+ GS = vhaddq_s16(G1, G2);
+ vst1q_s16( output_buffer[0] + column, GS );
+
+ {
+ const int16x8_t __midpoint_x2 = vdupq_n_s16(midpoint * 2);
+
+ GD = vsubq_s16(G1, G2);
+ GD = vhaddq_s16(GD, __midpoint_x2);
+ vst1q_s16( output_buffer[3] + column, GD );
+
+ GS = vsubq_s16( __midpoint_x2, GS );
+ }
+
+ RG = vhaddq_s16(R1, GS);
+ vst1q_s16( output_buffer[1] + column, RG );
+
+ BG = vhaddq_s16(B1, GS);
+ vst1q_s16( output_buffer[2] + column, BG );
+}
+
+#else
+
+#define UnpackPixel_14_8x UnpackPixel_14_8x_C_
+static void UnpackPixel_14_8x_C_(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ int i;
+ for ( i = 0; i < 8; i++)
+ {
+ UnpackPixel_14(input_row1_ptr, input_row2_ptr, column + i, output_buffer, rggb );
+ }
+}
+
+#endif
+
+void UnpackImage_14(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts, bool rggb )
+{
+ uint8_t *input_buffer = (uint8_t *)input->buffer + input->offset;
+
+ const DIMENSION input_width = input->width / 2;
+ const DIMENSION input_width_m8 = (input_width / 8) * 8;
+
+ const DIMENSION input_height = input->height / 2;
+
+ size_t input_pitch = input->pitch;
+
+ PIXEL *output_row_ptr_array[MAX_CHANNEL_COUNT];
+ uint32_t output_row_ptr_array_pitch[MAX_CHANNEL_COUNT];
+
+ uint16_t *input_row_ptr = (uint16_t*)input_buffer;
+
+ int channel_number;
+
+ int row;
+
+ for (channel_number = 0; channel_number < MAX_CHANNEL_COUNT; channel_number++)
+ {
+ output_row_ptr_array[channel_number] = (PIXEL *)(output->component_array_list[channel_number].data);
+
+ // output->component_array_list[channel_number].pitch is pitch in bytes, so we need to convert it to pitch in PIXELS
+ output_row_ptr_array_pitch[channel_number] = (output->component_array_list[channel_number].pitch / sizeof(PIXEL));
+ }
+
+ for (row = 0; row < input_height; row++)
+ {
+ uint16_t* input_row2_ptr = input_row_ptr + (input_pitch / sizeof(uint16_t));
+
+ int column = 0;
+
+ // Unpack the row of Bayer components from the BYR4 pattern elements
+ for (; column < input_width_m8; column+= 8)
+ {
+ UnpackPixel_14_8x(input_row_ptr, input_row2_ptr, column, output_row_ptr_array, rggb );
+ }
+
+ // Unpack the row of Bayer components from the BYR4 pattern elements
+ for (; column < input_width; column++)
+ {
+ UnpackPixel_14(input_row_ptr, input_row2_ptr, column, output_row_ptr_array, rggb );
+ }
+
+ input_row_ptr += input_pitch;
+
+ for (channel_number = 0; channel_number < MAX_CHANNEL_COUNT; channel_number++)
+ {
+ output_row_ptr_array[channel_number] += output_row_ptr_array_pitch[channel_number];
+ }
+ }
+}
+
+/** ------------------- **/
+/** 12 BIT INPUT FORMAT **/
+/** ------------------- **/
+
+static void UnpackPixel_12(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ uint16_t R1, G1, G2, B1;
+ uint16_t GS, GD, RG, BG;
+
+ uint16_t *GS_output_row_ptr = (uint16_t *)output_buffer[0];
+ uint16_t *GD_output_row_ptr = (uint16_t *)output_buffer[3];
+ uint16_t *RG_output_row_ptr = (uint16_t *)output_buffer[1];
+ uint16_t *BG_output_row_ptr = (uint16_t *)output_buffer[2];
+
+ const int internal_precision = 12;
+ const int32_t midpoint = (1 << (internal_precision - 1));
+
+ if( rggb )
+ {
+ R1 = input_row1_ptr[2 * column + 0];
+ G1 = input_row1_ptr[2 * column + 1];
+ G2 = input_row2_ptr[2 * column + 0];
+ B1 = input_row2_ptr[2 * column + 1];
+ }
+ else
+ {
+ G1 = input_row1_ptr[2 * column + 0];
+ B1 = input_row1_ptr[2 * column + 1];
+ R1 = input_row2_ptr[2 * column + 0];
+ G2 = input_row2_ptr[2 * column + 1];
+ }
+
+ // Apply protune log curve
+ R1 = EncoderLogCurve[ R1 ];
+ G1 = EncoderLogCurve[ G1 ];
+ G2 = EncoderLogCurve[ G2 ];
+ B1 = EncoderLogCurve[ B1 ];
+
+ // Difference the green components and subtract green from the red and blue components
+ GS = (G1 + G2) >> 1;
+ GD = (G1 - G2 + 2 * midpoint) >> 1;
+ RG = (R1 - GS + 2 * midpoint) >> 1;
+ BG = (B1 - GS + 2 * midpoint) >> 1;
+
+ GS_output_row_ptr[column] = clamp_uint(GS, internal_precision);
+ GD_output_row_ptr[column] = clamp_uint(GD, internal_precision);
+ RG_output_row_ptr[column] = clamp_uint(RG, internal_precision);
+ BG_output_row_ptr[column] = clamp_uint(BG, internal_precision);
+}
+
+#if ENABLED(NEON)
+
+#define UnpackPixel_12_8x UnpackPixel_12_8x_NEON_
+static void UnpackPixel_12_8x_NEON_(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ int i;
+ uint16x8x2_t row_1, row_2;
+
+ const int internal_precision = 12;
+ const int32_t midpoint = (1 << (internal_precision - 1));
+
+ // Apply protune log curve
+ {
+ uint16_t input_row1_12b[16];
+ uint16_t input_row2_12b[16];
+
+ for (i = 0; i < 16; ++i)
+ {
+ input_row1_12b[i] = EncoderLogCurve[ input_row1_ptr[2 * column + i] ];
+ input_row2_12b[i] = EncoderLogCurve[ input_row2_ptr[2 * column + i] ];
+ }
+
+ row_1 = vld2q_u16( input_row1_12b );
+ row_2 = vld2q_u16( input_row2_12b );
+ }
+
+ int16x8_t R1, G1, G2, B1;
+
+ if( rggb )
+ {
+ R1 = vreinterpretq_s16_u16( row_1.val[0] );
+ G1 = vreinterpretq_s16_u16( row_1.val[1] );
+ G2 = vreinterpretq_s16_u16( row_2.val[0] );
+ B1 = vreinterpretq_s16_u16( row_2.val[1] );
+ }
+ else
+ {
+ G1 = vreinterpretq_s16_u16( row_1.val[0] );
+ B1 = vreinterpretq_s16_u16( row_1.val[1] );
+ R1 = vreinterpretq_s16_u16( row_2.val[0] );
+ G2 = vreinterpretq_s16_u16( row_2.val[1] );
+ }
+
+ int16x8_t GS, GD, RG, BG;
+
+ GS = vhaddq_s16(G1, G2);
+ vst1q_s16( output_buffer[0] + column, GS );
+
+ {
+ const int16x8_t __midpoint_x2 = vdupq_n_s16(midpoint * 2);
+
+ GD = vsubq_s16(G1, G2);
+ GD = vhaddq_s16(GD, __midpoint_x2);
+ vst1q_s16( output_buffer[3] + column, GD );
+
+ GS = vsubq_s16( __midpoint_x2, GS );
+ }
+
+ RG = vhaddq_s16(R1, GS);
+ vst1q_s16( output_buffer[1] + column, RG );
+
+ BG = vhaddq_s16(B1, GS);
+ vst1q_s16( output_buffer[2] + column, BG );
+}
+
+#else
+
+#define UnpackPixel_12_8x UnpackPixel_12_8x_C_
+static void UnpackPixel_12_8x_C_(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ int i;
+ for ( i = 0; i < 8; i++)
+ {
+ UnpackPixel_12(input_row1_ptr, input_row2_ptr, column + i, output_buffer, rggb );
+ }
+}
+
+#endif
+
+void UnpackImage_12(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts, bool rggb )
+{
+ uint8_t *input_buffer = (uint8_t *)input->buffer + input->offset;
+
+ const DIMENSION input_width = input->width / 2;
+ const DIMENSION input_width_m8 = (input_width / 8) * 8;
+ const DIMENSION input_height = input->height / 2;
+
+ size_t input_pitch = input->pitch;
+
+ PIXEL *output_row_ptr_array[MAX_CHANNEL_COUNT];
+ uint32_t output_row_ptr_array_pitch[MAX_CHANNEL_COUNT];
+
+ uint16_t *input_row_ptr = (uint16_t*)input_buffer;
+
+ int channel_number;
+
+ int row;
+
+ for (channel_number = 0; channel_number < MAX_CHANNEL_COUNT; channel_number++)
+ {
+ output_row_ptr_array[channel_number] = (PIXEL *)(output->component_array_list[channel_number].data);
+
+ // output->component_array_list[channel_number].pitch is pitch in bytes, so we need to convert it to pitch in PIXELS
+ output_row_ptr_array_pitch[channel_number] = (output->component_array_list[channel_number].pitch / sizeof(PIXEL));
+ }
+
+ for (row = 0; row < input_height; row++)
+ {
+ uint16_t* input_row2_ptr = input_row_ptr + (input_pitch / sizeof(uint16_t));
+
+ int column = 0;
+
+ // Unpack the row of Bayer components from the BYR4 pattern elements
+ for (; column < input_width_m8; column+= 8)
+ {
+ UnpackPixel_12_8x(input_row_ptr, input_row2_ptr, column, output_row_ptr_array, rggb );
+ }
+
+ // Unpack the row of Bayer components from the BYR4 pattern elements
+ for (; column < input_width; column++)
+ {
+ UnpackPixel_12(input_row_ptr, input_row2_ptr, column, output_row_ptr_array, rggb );
+ }
+
+ input_row_ptr += input_pitch;
+
+ for (channel_number = 0; channel_number < MAX_CHANNEL_COUNT; channel_number++)
+ {
+ output_row_ptr_array[channel_number] += output_row_ptr_array_pitch[channel_number];
+ }
+ }
+}
+
+/** -------------------------- **/
+/** 12 bit PACKED INPUT FORMAT **/
+/** -------------------------- **/
+
+static void UnpackPixel_12P(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ uint16_t R1, G1, G2, B1;
+ uint16_t GS, GD, RG, BG;
+
+ const int internal_precision = 12;
+ const int32_t midpoint = (1 << (internal_precision - 1));
+
+ const unsigned int byte_offset = (column * 3);
+
+ { // read first row data
+ uint8_t* row1_ptr = (uint8_t*)input_row1_ptr;
+
+ unsigned char byte_0 = row1_ptr[byte_offset + 0];
+ unsigned char byte_1 = row1_ptr[byte_offset + 1];
+ unsigned char byte_2 = row1_ptr[byte_offset + 2];
+
+ if( rggb )
+ {
+ R1 = (byte_0) + ((byte_1 & 0x0f) << 8);
+ G1 = (byte_2 << 4) + ((byte_1 & 0xf0) >> 4);
+ }
+ else
+ {
+ G1 = (byte_0) + ((byte_1 & 0x0f) << 8);
+ B1 = (byte_2 << 4) + ((byte_1 & 0xf0) >> 4);
+ }
+ }
+
+ { // read second row data
+ uint8_t* row2_ptr = (uint8_t*)input_row2_ptr;
+
+ unsigned char byte_0 = row2_ptr[byte_offset + 0];
+ unsigned char byte_1 = row2_ptr[byte_offset + 1];
+ unsigned char byte_2 = row2_ptr[byte_offset + 2];
+
+ if( rggb )
+ {
+ G2 = (byte_0) + ((byte_1 & 0x0f) << 8);
+ B1 = (byte_2 << 4) + ((byte_1 & 0xf0) >> 4);
+ }
+ else
+ {
+ R1 = (byte_0) + ((byte_1 & 0x0f) << 8);
+ G2 = (byte_2 << 4) + ((byte_1 & 0xf0) >> 4);
+ }
+ }
+
+ // Apply protune log curve
+ G1 = EncoderLogCurve[ G1 ];
+ B1 = EncoderLogCurve[ B1 ];
+ R1 = EncoderLogCurve[ R1 ];
+ G2 = EncoderLogCurve[ G2 ];
+
+ // difference the green components and subtract green from the red and blue components
+ GS = (G1 + G2) >> 1;
+ GD = (G1 - G2 + 2 * midpoint) >> 1;
+ RG = (R1 - GS + 2 * midpoint) >> 1;
+ BG = (B1 - GS + 2 * midpoint) >> 1;
+
+ { // write output
+ uint16_t *GS_output_row_ptr = (uint16_t *)output_buffer[0];
+ uint16_t *GD_output_row_ptr = (uint16_t *)output_buffer[3];
+ uint16_t *RG_output_row_ptr = (uint16_t *)output_buffer[1];
+ uint16_t *BG_output_row_ptr = (uint16_t *)output_buffer[2];
+
+ GS_output_row_ptr[column] = clamp_uint(GS, internal_precision);
+ GD_output_row_ptr[column] = clamp_uint(GD, internal_precision);
+ RG_output_row_ptr[column] = clamp_uint(RG, internal_precision);
+ BG_output_row_ptr[column] = clamp_uint(BG, internal_precision);
+ }
+}
+
+#if ENABLED(NEON)
+
+#define UnpackPixel_12P_8x UnpackPixel_12P_8x_NEON_
+static void UnpackPixel_12P_8x_NEON_(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ int i;
+ uint16x8_t g1, b1, r1, g2;
+
+ const int internal_precision = 12;
+ const int32_t midpoint = (1 << (internal_precision - 1));
+ const unsigned int byte_offset = (column * 3)/2;
+
+ // Apply protune log curve
+ {
+ uint8_t* row1_ptr = (uint8_t*) &input_row1_ptr[byte_offset]; //Taken care: input_row1_ptr is 16-bit pointer. So halving it
+ uint8x8x3_t __byte012 = vld3_u8(row1_ptr); //Make sure you move only 24 bytes at a time
+ uint8x8_t __byte0 = __byte012.val[0];
+ uint8x8_t __byte1 = __byte012.val[1];
+ uint8x8_t __byte2 = __byte012.val[2];
+
+ if( rggb )
+ {
+ r1 = vaddw_u8(vshll_n_u8(vshl_n_u8(__byte1, 4), 4), __byte0);
+ g1 = vaddw_u8(vshll_n_u8(__byte2, 4), vshr_n_u8(__byte1, 4));
+ }
+ else
+ {
+ g1 = vaddw_u8(vshll_n_u8(vshl_n_u8(__byte1, 4), 4), __byte0);
+ b1 = vaddw_u8(vshll_n_u8(__byte2, 4), vshr_n_u8(__byte1, 4));
+ }
+ }
+ {
+ uint8_t* row2_ptr = (uint8_t*) &input_row2_ptr[byte_offset];
+ uint8x8x3_t __byte012 = vld3_u8(row2_ptr);
+ uint8x8_t __byte0 = __byte012.val[0];
+ uint8x8_t __byte1 = __byte012.val[1];
+ uint8x8_t __byte2 = __byte012.val[2];
+
+ if( rggb )
+ {
+ g2 = vaddw_u8(vshll_n_u8(vshl_n_u8(__byte1, 4), 4), __byte0);
+ b1 = vaddw_u8(vshll_n_u8(__byte2, 4), vshr_n_u8(__byte1, 4));
+ }
+ else
+ {
+ r1 = vaddw_u8(vshll_n_u8(vshl_n_u8(__byte1, 4), 4), __byte0);
+ g2 = vaddw_u8(vshll_n_u8(__byte2, 4), vshr_n_u8(__byte1, 4));
+ }
+ }
+
+ for(i = 0; i < 8; i++)
+ {
+ g1[i] = EncoderLogCurve[g1[i]];
+ b1[i] = EncoderLogCurve[b1[i]];
+ r1[i] = EncoderLogCurve[r1[i]];
+ g2[i] = EncoderLogCurve[g2[i]];
+ }
+
+ int16x8_t R1, G1, G2, B1;
+
+ G1 = vreinterpretq_s16_u16( g1 );
+ B1 = vreinterpretq_s16_u16( b1 );
+ R1 = vreinterpretq_s16_u16( r1 );
+ G2 = vreinterpretq_s16_u16( g2 );
+
+ int16x8_t GS, GD, RG, BG;
+
+ GS = vhaddq_s16(G1, G2);
+ vst1q_s16( output_buffer[0] + column, GS );
+
+ {
+ const int16x8_t __midpoint_x2 = vdupq_n_s16(midpoint * 2);
+
+ GD = vsubq_s16(G1, G2);
+ GD = vhaddq_s16(GD, __midpoint_x2);
+ vst1q_s16( output_buffer[3] + column, GD );
+ GS = vsubq_s16( __midpoint_x2, GS );
+ }
+
+ RG = vhaddq_s16(R1, GS);
+ vst1q_s16( output_buffer[1] + column, RG );
+
+ BG = vhaddq_s16(B1, GS);
+ vst1q_s16( output_buffer[2] + column, BG );
+}
+
+#else
+
+#define UnpackPixel_12P_8x UnpackPixel_12P_8x_C_
+static void UnpackPixel_12P_8x_C_(uint16_t *input_row1_ptr, uint16_t *input_row2_ptr, int column, PIXEL *output_buffer[], bool rggb )
+{
+ int i;
+ for ( i = 0; i < 8; i++)
+ {
+ UnpackPixel_12P(input_row1_ptr, input_row2_ptr, column + i, output_buffer, rggb );
+ }
+}
+
+#endif
+
+void UnpackImage_12P(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts, bool rggb )
+{
+ uint8_t *input_buffer = (uint8_t *)input->buffer + input->offset;
+
+ const DIMENSION input_width = input->width / 2;
+ const DIMENSION input_width_m8 = (input_width / 8) * 8;
+ const DIMENSION input_height = input->height / 2;
+
+ size_t input_pitch = input->pitch;
+
+ PIXEL *output_row_ptr_array[MAX_CHANNEL_COUNT];
+ uint32_t output_row_ptr_array_pitch[MAX_CHANNEL_COUNT];
+
+ uint16_t *input_row_ptr = (uint16_t*)input_buffer;
+
+ int channel_number;
+
+ int row;
+
+ for (channel_number = 0; channel_number < MAX_CHANNEL_COUNT; channel_number++)
+ {
+ output_row_ptr_array[channel_number] = (PIXEL *)(output->component_array_list[channel_number].data);
+
+ output_row_ptr_array_pitch[channel_number] = (output->component_array_list[channel_number].pitch / sizeof(PIXEL));
+ }
+
+ for (row = 0; row < input_height; row++)
+ {
+ uint16_t* input_row2_ptr = input_row_ptr + (input_pitch / sizeof(uint16_t));
+
+ int column = 0;
+
+ // Unpack the row of Bayer components from the BYR4 pattern elements
+ for (; column < input_width_m8; column+= 8)
+ {
+ UnpackPixel_12P_8x(input_row_ptr, input_row2_ptr, column, output_row_ptr_array, rggb );
+ }
+
+ // Unpack the row of Bayer components from the BYR4 pattern elements
+ for (; column < input_width; column++)
+ {
+ UnpackPixel_12P(input_row_ptr, input_row2_ptr, column, output_row_ptr_array, rggb );
+ }
+
+ input_row_ptr += input_pitch;
+
+ for (channel_number = 0; channel_number < MAX_CHANNEL_COUNT; channel_number++)
+ {
+ output_row_ptr_array[channel_number] += output_row_ptr_array_pitch[channel_number];
+ }
+ }
+}
+
diff --git a/gpr/source/lib/vc5_encoder/raw.h b/gpr/source/lib/vc5_encoder/raw.h
new file mode 100755
index 0000000..894d60e
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/raw.h
@@ -0,0 +1,36 @@
+/*! @file raw.h
+ *
+ * @brief Declaration of routines for packing RAW image to a row of pixels.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RAW_H
+#define RAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void UnpackImage_14(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts, bool rggb );
+
+ void UnpackImage_12(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts, bool rggb );
+
+ void UnpackImage_12P(const PACKED_IMAGE *input, UNPACKED_IMAGE *output, ENABLED_PARTS enabled_parts, bool rggb );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // RAW_H
diff --git a/gpr/source/lib/vc5_encoder/sections.c b/gpr/source/lib/vc5_encoder/sections.c
new file mode 100755
index 0000000..47efc0d
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/sections.c
@@ -0,0 +1,293 @@
+/*! @file sections.c
+ *
+ * @brief Implementation of code for encoding sections
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+
+/*
+ @brief Write codec state parameters used for decoding the section into the bitstream
+
+ A section element may be decoded independently from other sections of the same type.
+ Concurrent decoding implies that all codec state parameters needed to decode a section
+ element be present in that section element.
+
+ In principle, it is only necessary to write the codec state parameters that may be changed
+ as other section elements are decoded independently. This sample encoder takes the simple
+ approach and writes all non-header codec state parameters into the bitstream.
+ */
+static CODEC_ERROR PutCodecState(ENCODER *encoder, BITSTREAM *stream, SECTION_NUMBER section_number)
+{
+ CODEC_STATE *codec = &encoder->codec;
+ TAGWORD prescale_shift = 0;
+
+ switch (section_number)
+ {
+ case SECTION_NUMBER_IMAGE:
+ assert(0);
+ break;
+
+ case SECTION_NUMBER_HEADER:
+ // No codec state parameters to be written into the bitstream
+ break;
+
+ case SECTION_NUMBER_CHANNEL:
+ // Encode the transform prescale for the first channel (assume all channels are the same)
+ prescale_shift = PackTransformPrescale(&encoder->transform[0]);
+
+ PutTagPair(stream, CODEC_TAG_ChannelNumber, codec->channel_number);
+ PutTagPair(stream, CODEC_TAG_SubbandNumber, codec->subband_number);
+ PutTagPair(stream, CODEC_TAG_LowpassPrecision, codec->lowpass_precision);
+ PutTagPair(stream, CODEC_TAG_Quantization, codec->band.quantization);
+ PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
+
+#if VC5_ENABLED_PART(VC5_PART_IMAGE_FORMATS)
+ if (!IsPartEnabled(encoder->enabled_parts, VC5_PART_IMAGE_FORMATS))
+ {
+ PutTagPair(stream, CODEC_TAG_ChannelWidth, codec->channel_width);
+ PutTagPair(stream, CODEC_TAG_ChannelHeight, codec->channel_height);
+ }
+#endif
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_LAYERS))
+ {
+ PutTagPair(stream, CODEC_TAG_LayerNumber, codec->layer_number);
+ }
+#endif
+ break;
+
+ case SECTION_NUMBER_WAVELET:
+ PutTagPair(stream, CODEC_TAG_ChannelNumber, codec->channel_number);
+ PutTagPair(stream, CODEC_TAG_SubbandNumber, codec->subband_number);
+ PutTagPair(stream, CODEC_TAG_LowpassPrecision, codec->lowpass_precision);
+ //PutTagPair(stream, CODEC_TAG_Quantization, codec->band.quantization);
+ //PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
+ break;
+
+ case SECTION_NUMBER_SUBBAND:
+ PutTagPair(stream, CODEC_TAG_ChannelNumber, codec->channel_number);
+ PutTagPair(stream, CODEC_TAG_SubbandNumber, codec->subband_number);
+ PutTagPair(stream, CODEC_TAG_LowpassPrecision, codec->lowpass_precision);
+ PutTagPair(stream, CODEC_TAG_Quantization, codec->band.quantization);
+ //PutTagPair(stream, CODEC_TAG_PrescaleShift, prescale_shift);
+ break;
+
+ default:
+ assert(0);
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*
+ @brief Return true if specified type of section is enabled
+ */
+bool IsSectionEnabled(ENCODER *encoder, SECTION_NUMBER section_number)
+{
+ if (IsPartEnabled(encoder->enabled_parts, VC5_PART_SECTIONS))
+ {
+ if (SECTION_NUMBER_MINIMUM <= section_number && section_number <= SECTION_NUMBER_MAXIMUM)
+ {
+ uint32_t section_mask = SECTION_NUMBER_MASK(section_number);
+
+ if (encoder->enabled_sections & section_mask) {
+ return true;
+ }
+ }
+ }
+
+ // None of the predefined VC-5 sections are enabled
+ return false;
+}
+
+/*
+ @brief Start a new section with the specified tag
+
+ The location of the the tag-value pair that marks the beginning of the new
+ section is pushed onto a stack so that the tag-value pair can be updated with
+ the actual size of the section when the section is ended by a call to the
+ @ref EndSection function.
+ */
+CODEC_ERROR BeginSection(BITSTREAM *bitstream, TAGWORD tag)
+{
+ return PushSampleSize(bitstream, tag);
+}
+
+/*
+ @brief End a section
+
+ Update the tag-value pair that marks the section with the actual size of the section.
+ */
+CODEC_ERROR EndSection(BITSTREAM *bitstream)
+{
+ return PopSampleSize(bitstream);
+}
+
+/*!
+ @brief Write an image section header into the bitstream
+ */
+CODEC_ERROR BeginImageSection(struct _encoder *encoder, BITSTREAM *stream)
+{
+ assert(0);
+ return CODEC_ERROR_OKAY;
+}
+
+/*
+ @brief Write a section header for the bitstream header into the bitstream
+ */
+CODEC_ERROR BeginHeaderSection(struct _encoder *encoder, BITSTREAM *stream)
+{
+ // Write the section header for the bitstream header into the bitstream
+ return BeginSection(stream, CODEC_TAG_HeaderSectionTag);
+}
+
+/*
+ @brief Write a layer section header into the bitstream
+
+ Any codec state parameters that are required to decode the layer must be explicitly
+ written into the bitstream so that the layer sections and be decoded concurrently.
+ */
+CODEC_ERROR BeginLayerSection(struct _encoder *encoder, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Duplicate all codec state parameters required for decoding the layer
+ PutCodecState(encoder, stream, SECTION_NUMBER_LAYER);
+
+ // Write the section header for the layer into the bitstream
+ error = BeginSection(stream, CODEC_TAG_LayerSectionTag);
+
+ return error;
+}
+
+/*
+ @brief Write a channel section header into the bitstream
+
+ Any codec state parameters that are required to decode the channel must be explicitly
+ written into the bitstream so that the channel sections and be decoded concurrently.
+ */
+CODEC_ERROR BeginChannelSection(ENCODER *encoder, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Duplicate all codec state parameters required for decoding the channel
+ PutCodecState(encoder, stream, SECTION_NUMBER_CHANNEL);
+
+ // Write the section header for the channel into the bitstream
+ error = BeginSection(stream, CODEC_TAG_ChannelSectionTag);
+
+ return error;
+}
+
+/*
+ @brief Write a wavelet section header into the bitstream
+
+ Any codec state parameters that are required to decode the wavelet must be explicitly
+ written into the bitstream so that the wavelet sections and be decoded concurrently.
+ */
+CODEC_ERROR BeginWaveletSection(struct _encoder *encoder, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Duplicate all codec state parameters required for decoding the wavelet
+ PutCodecState(encoder, stream, SECTION_NUMBER_WAVELET);
+
+ // Write the section header for the wavelet into the bitstream
+ error = BeginSection(stream, CODEC_TAG_WaveletSectionTag);
+
+ return error;
+}
+
+/*
+ @brief Write a subband section header into the bitstream
+
+ Any codec state parameters that are required to decode the subband must be explicitly
+ written into the bitstream so that the subband sections and be decoded concurrently.
+ */
+CODEC_ERROR BeginSubbandSection(struct _encoder *encoder, BITSTREAM *stream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+ // Duplicate all codec state parameters required for decoding the subband
+ PutCodecState(encoder, stream, SECTION_NUMBER_SUBBAND);
+
+ // Write the section header for the subband into the bitstream
+ error = BeginSection(stream, CODEC_TAG_SubbandSectionTag);
+
+ return error;
+}
+
+/*!
+ @brief Set the flags that indicate which sections in VC-5 Part 6 are enabled
+
+ The argument is a list of comma-separated integers for the section numbers
+ in the VC-5 Part 2 conformance specification that are enabled for this invocation
+ of the encoder.
+
+ Note: Enabling sections at runtime has no effect unless support for sections
+ is compiled into the program by enabling the corresponding compile-time switch
+ for VC-5 part 6 (sections).
+ */
+bool GetEnabledSections(const char *string, uint32_t *enabled_sections_out)
+{
+ if (string != NULL && enabled_sections_out != NULL)
+ {
+ // No sections are enabled by default
+ ENABLED_SECTIONS enabled_sections = 0;
+
+ const char *p = string;
+ assert(p != NULL);
+ while (*p != '\0')
+ {
+ char *q = NULL;
+ long section_number;
+ if (!isdigit((int)*p)) break;
+ section_number = strtol(p, &q, 10);
+
+ // Is the section number in bounds?
+ if (SECTION_NUMBER_MINIMUM <= section_number && section_number <= SECTION_NUMBER_MAXIMUM)
+ {
+ // Set the bit that corresponds to this section number
+ enabled_sections |= SECTION_NUMBER_MASK(section_number);
+
+ // Advance to the next section number in the command-line argument
+ p = (*q != '\0') ? q + 1 : q;
+ }
+ else
+ {
+ // Invalid section number
+ assert(0);
+ return false;
+ }
+ }
+
+ // Return the bit mask for the enabled sections
+ *enabled_sections_out = enabled_sections;
+
+ // Should have parsed all section numbers in the argument string
+ assert(*p == '\0');
+ return true;
+ }
+
+ // Invalid input arguments
+ return false;
+}
+
+
+#endif
diff --git a/gpr/source/lib/vc5_encoder/sections.h b/gpr/source/lib/vc5_encoder/sections.h
new file mode 100755
index 0000000..602dd81
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/sections.h
@@ -0,0 +1,91 @@
+/*! @file sections.h
+ *
+ * @brief Declaration of routines for handling sections in the encoder.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SECTIONS_H
+#define SECTIONS_H
+
+/*
+ @brief Enumeration of the predefined section numbers
+
+ The predefined section numbers are defined in ST 2073-2.
+ */
+typedef enum _section_number
+{
+ SECTION_NUMBER_IMAGE = 1, //!< Image section
+ SECTION_NUMBER_HEADER = 2, //!< Bitstream header section
+ SECTION_NUMBER_LAYER = 3, //!< Layer section
+ SECTION_NUMBER_CHANNEL = 4, //!< Channel section
+ SECTION_NUMBER_WAVELET = 5, //!< Wavelet section
+ SECTION_NUMBER_SUBBAND = 6, //!< Subband section
+
+ //TODO: Add more section number definitions as required
+
+ //! Modify the smallest and largest section numbers as more sections are added
+ SECTION_NUMBER_MINIMUM = SECTION_NUMBER_IMAGE,
+ SECTION_NUMBER_MAXIMUM = SECTION_NUMBER_SUBBAND,
+
+} SECTION_NUMBER;
+
+/*
+ @Macro for creating a section number bit mask from a section number
+
+ The macro does not check that the section number argument is valid.
+ */
+#define SECTION_NUMBER_MASK(section_number) (1 << (section_number - 1))
+
+/*
+ @brief Data type for the bit mask that represents enabled sections
+
+ The bit mask indicates which section numbers defined in ST 2073-2 are enabled
+ at runtime.
+ */
+typedef uint32_t ENABLED_SECTIONS;
+
+#define VC5_ENABLED_SECTIONS (SECTION_NUMBER_MASK(SECTION_NUMBER_CHANNEL) | \
+ SECTION_NUMBER_MASK(SECTION_NUMBER_WAVELET) | \
+ SECTION_NUMBER_MASK(SECTION_NUMBER_SUBBAND))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ bool IsSectionEnabled(struct _encoder *encoder, SECTION_NUMBER section_number);
+
+ CODEC_ERROR BeginSection(BITSTREAM *bitstream, TAGWORD tag);
+
+ CODEC_ERROR EndSection(BITSTREAM *bitstream);
+
+ CODEC_ERROR BeginImageSection(struct _encoder *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR BeginHeaderSection(struct _encoder *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR BeginLayerSection(struct _encoder *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR BeginChannelSection(struct _encoder *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR BeginWaveletSection(struct _encoder *encoder, BITSTREAM *stream);
+
+ CODEC_ERROR BeginSubbandSection(struct _encoder *encoder, BITSTREAM *stream);
+
+ bool GetEnabledSections(const char *string, uint32_t *enabled_sections_out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SECTIONS_H
diff --git a/gpr/source/lib/vc5_encoder/syntax.c b/gpr/source/lib/vc5_encoder/syntax.c
new file mode 100755
index 0000000..14afdf1
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/syntax.c
@@ -0,0 +1,276 @@
+/*! @file syntax.c
+ *
+ * @brief Implementation of functions for writing bitstream syntax of encoded samples.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+
+/*!
+ @brief Pop the top value from the sample offset stack
+ */
+static uint32_t PopSampleOffsetStack(BITSTREAM *bitstream)
+{
+ assert(bitstream->sample_offset_count > 0);
+ return bitstream->sample_offset_stack[--bitstream->sample_offset_count];
+}
+
+#endif
+
+/*!
+ @brief Write a segment at the specified offset in the bitstream
+
+ The segment at the specified offset in the bitstream is overwritten by the new
+ segment provided as an argument. Typically this is done to update a segment that
+ is intended to provide the size or offset to a syntax element in the encoded sample.
+ */
+CODEC_ERROR PutSampleOffsetSegment(BITSTREAM *bitstream, uint32_t offset, TAGVALUE segment)
+{
+ // Translate the segment to network byte order
+ uint32_t buffer = Swap32(segment.longword);
+
+ // Must write the segment on a segment boundary
+ assert((offset % sizeof(TAGVALUE)) == 0);
+
+ // Write the segment to the byte stream at the specified offset
+ return PutBlock(bitstream->stream, &buffer, sizeof(buffer), offset);
+}
+
+static bool IsTagOptional(TAGWORD tag)
+{
+ return (tag < 0);
+}
+
+/*!
+ @brief Write the trailer for the lowpass band into the bitstream
+
+ This routine writes a marker into the bitstream that can aid in debugging,
+ but the most important function is to update the segment that contains the
+ size of this subband with the actual size of the lowpass band.
+ */
+CODEC_ERROR PutVideoLowpassTrailer(BITSTREAM *stream)
+{
+ // Check that the bitstream is tag aligned before writing the pixels
+ assert(IsAlignedSegment(stream));
+
+ // Set the size of the large chunk for the lowpass band codeblock
+ PopSampleSize(stream);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write the next tag value pair to the bitstream
+
+ @todo Change the code to use the @ref PutLong function?
+ */
+CODEC_ERROR PutTagValue(BITSTREAM *stream, TAGVALUE segment)
+{
+ CODEC_ERROR error;
+
+ // Write the tag to the bitstream
+ error = PutBits(stream, segment.tuple.tag, tagword_count);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Write the value to the bitstream
+ error = PutBits(stream, segment.tuple.value, tagword_count);
+
+ return error;
+}
+
+/*!
+ @brief Write a required tag value pair
+
+ @todo Should the tag value pair be output on a segment boundary?
+ */
+CODEC_ERROR PutTagPair(BITSTREAM *stream, int tag, int value)
+{
+ // The bitstream should be aligned on a tag word boundary
+ assert(IsAlignedTag(stream));
+
+ // The value must fit within a tag word
+ assert(((uint32_t)value & ~(uint32_t)CODEC_TAG_MASK) == 0);
+
+ PutLong(stream, ((uint32_t )tag << 16) | (value & CODEC_TAG_MASK));
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write an optional tag value pair
+
+ @todo Should the tag value pair be output on a segment boundary?
+ */
+CODEC_ERROR PutTagPairOptional(BITSTREAM *stream, int tag, int value)
+{
+ // The bitstream should be aligned on a tag word boundary
+ assert(IsAlignedTag(stream));
+
+ // The value must fit within a tag word
+ assert(((uint32_t)value & ~(uint32_t)CODEC_TAG_MASK) == 0);
+
+ // Set the optional tag bit
+ //tag |= CODEC_TAG_OPTIONAL;
+ //tag = NEG(tag);
+ tag = neg(tag);
+
+ PutLong(stream, ((uint32_t )tag << 16) | (value & CODEC_TAG_MASK));
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Write a tag value pair that specifies the size of a syntax element
+
+ The routine pushes the current position in the bitstream onto the sample offset
+ stack and writes a tag value pair for the size of the current syntax element.
+ The routine @ref PopSampleSize overwrites the segment with a tag value pair
+ that contains the actual size of the syntax element.
+
+ This routine corresponds to the routine SizeTagPush in the current codec implementation.
+ */
+CODEC_ERROR PushSampleSize(BITSTREAM *bitstream, TAGWORD tag)
+{
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+
+ size_t position = GetBitstreamPosition(bitstream);
+
+ // Check for stack overflow
+ assert(bitstream->sample_offset_count < MAX_SAMPLE_OFFSET_COUNT);
+
+ // Check that the bitstream position can be pushed onto the stack
+ assert(position <= UINT32_MAX);
+
+ // Push the current sample offset onto the stack
+ bitstream->sample_offset_stack[bitstream->sample_offset_count++] = (uint32_t)position;
+
+#endif
+
+ // Write a tag value pair for the size of this chunk
+ PutTagPairOptional(bitstream, tag, 0);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Update a sample size segment with the actual size of the syntax element
+
+ This routine pops the offset in the bitstream to the most recent tag value pair
+ that was written into the bitstream from the sample offset stack and overwrites
+ the segment with the tag value pair that contains the actual size of the syntax
+ element.
+
+ This routine corresponds to the routine SizeTagPop in the current codec implementation.
+ */
+CODEC_ERROR PopSampleSize(BITSTREAM *bitstream)
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+
+#if VC5_ENABLED_PART(VC5_PART_SECTIONS)
+
+ if (bitstream->sample_offset_count > 0)
+ {
+ TAGVALUE segment;
+ TAGWORD tag;
+
+ uint32_t current_offset;
+ uint32_t previous_offset;
+
+ uint32_t chunk_size;
+
+ size_t position = GetBitstreamPosition(bitstream);
+
+ // Get the offset to the current position in the bitstream
+ assert(position <= UINT32_MAX);
+ current_offset = (uint32_t)position;
+
+ // Pop the offset for this chunk from the sample offset stack
+ previous_offset = PopSampleOffsetStack(bitstream);
+
+ assert(previous_offset < current_offset);
+
+ // Get the segment for the chunk written at the most recent offset
+ error = GetSampleOffsetSegment(bitstream, previous_offset, &segment);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ // Get the tag for the chunk segment
+ tag = segment.tuple.tag;
+
+ // Should be an optional tag-value pair
+ assert(IsTagOptional(tag));
+ if (! (IsTagOptional(tag))) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ // Convert the tag to required
+ tag = RequiredTag(tag);
+
+ // Compute the size of the current chunk
+ chunk_size = current_offset - previous_offset;
+
+ if (chunk_size >= 4)
+ {
+ // The chunk payload should contain an integer number of segments
+ assert((chunk_size % sizeof(TAGVALUE)) == 0);
+
+ // Compute the number of segments in the chunk payload
+ chunk_size = (chunk_size / sizeof(TAGVALUE)) - 1;
+ }
+ else
+ {
+ chunk_size = 0;
+ }
+
+ // Does this chunk have a 24-bit size field?
+ if (tag & CODEC_TAG_LARGE_CHUNK)
+ {
+ // Add the most significant eight bits of the size to the tag
+ tag |= ((chunk_size >> 16) & 0xFF);
+ }
+
+ // The segment value is the least significant 16 bits of the payload size
+ chunk_size &= 0xFFFF;
+
+ // Update the segment with the optional tag and chunk size
+ segment.tuple.tag = OptionalTag(tag);
+ segment.tuple.value = chunk_size;
+
+ return PutSampleOffsetSegment(bitstream, previous_offset, segment);
+ }
+#endif
+
+ return CODEC_ERROR_UNEXPECTED;
+}
+
+/*!
+ @brief Write the bitstream start marker
+ */
+CODEC_ERROR PutBitstreamStartMarker(BITSTREAM *stream)
+{
+ assert(stream != NULL);
+ if (! (stream != NULL)) {
+ return CODEC_ERROR_UNEXPECTED;
+ }
+
+ return PutLong(stream, StartMarkerSegment);
+}
diff --git a/gpr/source/lib/vc5_encoder/syntax.h b/gpr/source/lib/vc5_encoder/syntax.h
new file mode 100755
index 0000000..3a85fe7
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/syntax.h
@@ -0,0 +1,44 @@
+/*! @file syntax.h
+ *
+ * @brief Declare functions for writing bitstream syntax of encoded samples.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ENCODER_SYNTAX_H
+#define ENCODER_SYNTAX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR PutSampleOffsetSegment(BITSTREAM *bitstream, uint32_t offset, TAGVALUE segment);
+
+ CODEC_ERROR PutVideoLowpassTrailer(BITSTREAM *stream);
+
+ CODEC_ERROR PutVideoBandTrailer(BITSTREAM *stream);
+
+ CODEC_ERROR PutTagValue(BITSTREAM *stream, TAGVALUE segment);
+
+ CODEC_ERROR PutBitstreamStartMarker(BITSTREAM *stream);
+
+ CODEC_ERROR PushSampleSize(BITSTREAM *bitstream, TAGWORD tag);
+
+ CODEC_ERROR PopSampleSize(BITSTREAM *bitstream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ENCODER_SYNTAX_H
diff --git a/gpr/source/lib/vc5_encoder/vc5_encoder.c b/gpr/source/lib/vc5_encoder/vc5_encoder.c
new file mode 100755
index 0000000..c28d904
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/vc5_encoder.c
@@ -0,0 +1,164 @@
+/*! @file vc5_encoder.c
+ *
+ * @brief Implementation of the top level vc5 encoder data structures and functions.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+void vc5_encoder_parameters_set_default(vc5_encoder_parameters* encoding_parameters)
+{
+ encoding_parameters->enabled_parts = VC5_ENABLED_PARTS;
+ encoding_parameters->input_width = 4000;
+ encoding_parameters->input_height = 3000;
+ encoding_parameters->input_pitch = 4000;
+
+ encoding_parameters->pixel_format = VC5_ENCODER_PIXEL_FORMAT_DEFAULT;
+ encoding_parameters->quality_setting = VC5_ENCODER_QUALITY_SETTING_DEFAULT;
+
+ encoding_parameters->mem_alloc = malloc;
+ encoding_parameters->mem_free = free;
+}
+
+CODEC_ERROR vc5_encoder_process(const vc5_encoder_parameters* encoding_parameters, /* vc5 encoding parameters */
+ const gpr_buffer* raw_buffer, /* raw input buffer. */
+ gpr_buffer* vc5_buffer,
+ gpr_rgb_buffer* rgb_buffer) /* rgb output buffer. */
+{
+ CODEC_ERROR error = CODEC_ERROR_OKAY;
+ IMAGE image;
+ ENCODER_PARAMETERS parameters;
+
+ STREAM bitstream_file;
+
+ const int max_vc5_buffer_size = 10000000;
+
+ // Initialize the data structure for passing parameters to the encoder
+ InitEncoderParameters(&parameters);
+
+ {
+ QUANT quant_table[VC5_ENCODER_QUALITY_SETTING_COUNT][sizeof(parameters.quant_table) / sizeof(parameters.quant_table[0])] = {
+ {1, 24, 24, 12, 64, 64, 48, 512, 512, 768}, // CineForm Low
+ {1, 24, 24, 12, 48, 48, 32, 256, 256, 384}, // CineForm Medium
+ {1, 24, 24, 12, 32, 32, 24, 128, 128, 192}, // CineForm High
+ {1, 24, 24, 12, 24, 24, 12, 96, 96, 144}, // CineForm Filmscan-1
+ {1, 24, 24, 12, 24, 24, 12, 64, 64, 96}, // CineForm Filmscan-X
+ {1, 24, 24, 12, 24, 24, 12, 32, 32, 48} // CineForm Filmscan-2
+ };
+
+ if( encoding_parameters->quality_setting < VC5_ENCODER_QUALITY_SETTING_COUNT )
+ {
+ memcpy(parameters.quant_table, quant_table[encoding_parameters->quality_setting], sizeof(parameters.quant_table));
+ }
+ }
+
+ parameters.enabled_parts = encoding_parameters->enabled_parts;
+ parameters.encoded.format = IMAGE_FORMAT_RAW;
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ // Test interlaced encoding using one layer per field
+ parameters.layer_count = 2;
+ parameters.progressive = 0;
+ parameters.decompositor = DecomposeFields;
+#endif
+
+ parameters.allocator.Alloc = encoding_parameters->mem_alloc;
+ parameters.allocator.Free = encoding_parameters->mem_free;
+
+ // Check that the enabled parts are correct
+ error = CheckEnabledParts(&parameters.enabled_parts);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ image.buffer = raw_buffer->buffer;
+
+ image.width = encoding_parameters->input_width;
+ image.height = encoding_parameters->input_height;
+ image.pitch = encoding_parameters->input_pitch;
+ image.size = image.width * image.height * 2;
+ image.offset = 0;
+
+ switch( encoding_parameters->pixel_format )
+ {
+ case VC5_ENCODER_PIXEL_FORMAT_RGGB_12:
+ image.format = PIXEL_FORMAT_RAW_RGGB_12;
+ break;
+
+ case VC5_ENCODER_PIXEL_FORMAT_RGGB_12P:
+ image.format = PIXEL_FORMAT_RAW_RGGB_12P;
+ break;
+
+ case VC5_ENCODER_PIXEL_FORMAT_RGGB_14:
+ image.format = PIXEL_FORMAT_RAW_RGGB_14;
+ break;
+
+ case VC5_ENCODER_PIXEL_FORMAT_GBRG_12:
+ image.format = PIXEL_FORMAT_RAW_GBRG_12;
+ break;
+
+ case VC5_ENCODER_PIXEL_FORMAT_GBRG_12P:
+ image.format = PIXEL_FORMAT_RAW_GBRG_12P;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ // Set the dimensions and pixel format of the packed input image
+ {
+ parameters.input.width = image.width;
+ parameters.input.height = image.height;
+ parameters.input.format = image.format;
+ }
+
+#if VC5_ENABLED_PART(VC5_PART_LAYERS)
+ // Test interlaced encoding using one layer per field
+ parameters.layer_count = 2;
+ parameters.progressive = 0;
+ parameters.decompositor = DecomposeFields;
+#endif
+
+ vc5_buffer->buffer = encoding_parameters->mem_alloc( max_vc5_buffer_size );
+
+ // Open a stream to the output file
+ error = CreateStreamBuffer(&bitstream_file, vc5_buffer->buffer, max_vc5_buffer_size );
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ RGB_IMAGE rgb_image;
+ InitRGBImage(&rgb_image);
+
+ // Encode the image into the byte stream
+ error = EncodeImage(&image, &bitstream_file, &rgb_image, &parameters);
+ if (error != CODEC_ERROR_OKAY) {
+ return error;
+ }
+
+ if( rgb_buffer )
+ {
+ rgb_buffer->buffer = rgb_image.buffer;
+ rgb_buffer->size = rgb_image.size;
+ rgb_buffer->width = rgb_image.width;
+ rgb_buffer->height = rgb_image.height;
+ }
+
+ vc5_buffer->size = bitstream_file.byte_count;
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_encoder/vc5_encoder.h b/gpr/source/lib/vc5_encoder/vc5_encoder.h
new file mode 100755
index 0000000..35a9b16
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/vc5_encoder.h
@@ -0,0 +1,103 @@
+/*! @file vc5_encoder.h
+ *
+ * @brief Declaration of the top level vc5 encoder API.
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VC5_ENCODER_H
+#define VC5_ENCODER_H
+
+#include "error.h"
+#include "types.h"
+#include "gpr_buffer.h"
+#include "gpr_rgb_buffer.h"
+#include "vc5_common.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ /*!
+ @brief Bayer pattern ordering for vc5 encoder processing
+ */
+ typedef enum
+ {
+ VC5_ENCODER_PIXEL_FORMAT_RGGB_12 = 0, // RGGB 14bit pixels packed into 16bits
+
+ VC5_ENCODER_PIXEL_FORMAT_RGGB_12P = 1, // RGGB 14bit pixels packed into 16bits
+
+ VC5_ENCODER_PIXEL_FORMAT_RGGB_14 = 2, // RGGB 14bit pixels packed into 16bits
+
+ VC5_ENCODER_PIXEL_FORMAT_GBRG_12 = 3, // GBRG 12bit pixels packed into 16bits
+
+ VC5_ENCODER_PIXEL_FORMAT_GBRG_12P = 4, // GBRG 12bit pixels packed into 12bits
+
+ VC5_ENCODER_PIXEL_FORMAT_DEFAULT = VC5_ENCODER_PIXEL_FORMAT_RGGB_14,
+
+ } VC5_ENCODER_PIXEL_FORMAT;
+
+ #define VC5_ENCODER_RGB_RESOLUTION_DEFAULT GPR_RGB_RESOLUTION_SIXTEENTH
+
+ /*!
+ @brief Quality setting of the VC5 encoder
+ */
+ typedef enum
+ {
+ VC5_ENCODER_QUALITY_SETTING_LOW = 0, // Low (Lowest Quality)
+ VC5_ENCODER_QUALITY_SETTING_MEDIUM = 1, // Medium
+ VC5_ENCODER_QUALITY_SETTING_HIGH = 2, // High
+ VC5_ENCODER_QUALITY_SETTING_FS1 = 3, // Film Scan 1
+ VC5_ENCODER_QUALITY_SETTING_FSX = 4, // Film Scan X
+ VC5_ENCODER_QUALITY_SETTING_FS2 = 5, // Film Scan 2 (Highest Quality)
+
+ VC5_ENCODER_QUALITY_SETTING_COUNT = 6,
+
+ VC5_ENCODER_QUALITY_SETTING_DEFAULT = VC5_ENCODER_QUALITY_SETTING_FSX,
+
+ } VC5_ENCODER_QUALITY_SETTING;
+
+ /*!
+ @brief vc5 encoder parameters
+ */
+ typedef struct
+ {
+ ENABLED_PARTS enabled_parts;
+
+ unsigned int input_width; // Image Width in Components (Default: 4000)
+ unsigned int input_height; // Image Height in Components (Default: 3000)
+ int input_pitch; // Image Buffer Stride in Components (Default: 4000)
+
+ VC5_ENCODER_PIXEL_FORMAT pixel_format; // Bayer Ordering Pattern (Default: VC5_ENCODER_BAYER_ORDERING_RGGB)
+
+ VC5_ENCODER_QUALITY_SETTING quality_setting; // Quality setting of the encoder (Default: VC5_ENCODER_QUALITY_SETTING_FS2)
+
+ gpr_malloc mem_alloc; // Callback function to allocate memory
+
+ gpr_free mem_free; // Callback function to free memory
+
+ } vc5_encoder_parameters;
+
+ void vc5_encoder_parameters_set_default(vc5_encoder_parameters* encoding_parameters);
+
+ CODEC_ERROR vc5_encoder_process(const vc5_encoder_parameters* encoding_parameters, /* vc5 encoding parameters */
+ const gpr_buffer* raw_buffer, /* raw input buffer. */
+ gpr_buffer* vc5_buffer,
+ gpr_rgb_buffer* rgb_buffer); /* vc5 output buffer. */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // VC5_ENCODER_H
diff --git a/gpr/source/lib/vc5_encoder/vlc.c b/gpr/source/lib/vc5_encoder/vlc.c
new file mode 100755
index 0000000..38a0ecb
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/vlc.c
@@ -0,0 +1,94 @@
+/*! @file vlc.c
+ *
+ * @brief Implementation of routines to insert variable length codes into the bitstream
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "headers.h"
+
+/*!
+ @brief Write the codewords for a run of zeros into the bitstream
+
+ The codebook contains codewords for a few runs of zeros. This routine writes
+ multiple codewords into the bitstream until the specified number of zeros has
+ been written into the bitstream.
+*/
+CODEC_ERROR PutZeros(BITSTREAM *stream, const RUNS_TABLE *runs_table, uint32_t count)
+{
+ // Get the length of the codebook and a pointer to the entries
+ uint32_t length = runs_table->length;
+ RLC *rlc = (RLC *)((uint8_t *)runs_table + sizeof(RUNS_TABLE));
+ int index;
+
+ // Output one or more run lengths until the run is finished
+ while (count > 0)
+ {
+ // Index into the codebook to get a run length code that covers most of the run
+ index = (count < length) ? count : length - 1;
+
+ // Output the run length code
+ PutBits(stream, rlc[index].bits, rlc[index].size);
+
+ // Reduce the length of the run by the amount output
+ count -= rlc[index].count;
+ }
+
+ // Should have output enough runs to cover the run of zeros
+ assert(count == 0);
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Insert a special codeword into the bitstream
+
+ The codebook contains special codewords in addition to the codebook
+ entries for coefficient magnitudes and runs of zeros. Special codewords
+ are used to mark important locations in the bitstream. Currently,
+ the only special codeword is the one that marks the end of an encoded
+ band.
+*/
+CODEC_ERROR PutSpecial(BITSTREAM *stream, const CODEBOOK *codebook, SPECIAL_MARKER marker)
+{
+ int codebook_length = codebook->length;
+ RLV *codebook_entry = (RLV *)((uint8_t *)codebook + sizeof(CODEBOOK));
+
+ int index;
+
+ // Find the special code that corresponds to the marker
+ for (index = 0; index < codebook_length; index++)
+ {
+ // Is this entry a special code?
+ if (codebook_entry[index].count != 0) {
+ continue;
+ }
+
+ // Is this entry the special code for the marker?
+ if (codebook_entry[index].value == (int32_t)marker) {
+ break;
+ }
+ }
+ assert(index < codebook_length);
+ if (! (index < codebook_length)) {
+ // Did not find the special code for the marker in the codebook
+ return CODEC_ERROR_INVALID_MARKER;
+ }
+
+ PutBits(stream, codebook_entry[index].bits, codebook_entry[index].size);
+
+ return CODEC_ERROR_OKAY;
+}
diff --git a/gpr/source/lib/vc5_encoder/vlc.h b/gpr/source/lib/vc5_encoder/vlc.h
new file mode 100755
index 0000000..4947060
--- /dev/null
+++ b/gpr/source/lib/vc5_encoder/vlc.h
@@ -0,0 +1,138 @@
+/*! @file vlc.h
+ *
+ * @brief Declaration of the data structures for variable-length encoding
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VLC_H
+#define VLC_H
+
+/*!
+ @brief Codebook entries for arbitrary runs and values
+
+ The codebook data structure allows runs of an arbitrary value,
+ but all codec implementations only use runs of zeros. The
+ codeword for a non-zero value is followed by the sign bit.
+
+ @todo Could add the sign bit to the magnitude entries in this
+ table if it improves performance or makes the code more clear.
+*/
+typedef struct _rlv {
+ uint_fast8_t size; //!< Size of code word in bits
+ uint32_t bits; //!< Code word bits right justified
+ uint32_t count; //!< Run length
+ int32_t value; //!< Run value (unsigned)
+} RLV;
+
+/*!
+ @brief Declaration of a codebook
+
+ This data structure is often called the master codebook to distinguish
+ it from the encoding tables that are derived from the codebook. The
+ codebook has a header that is immediately followed by the codebook entries.
+ Each entry is an @ref RLV data structure that contains the codeword and
+ the size of the codeword in bits. Each codeword represent a run length
+ and value. The current codec implementation only supports runs of zeros,
+ so the run length is one for non-zero values. A non-zero value is an
+ unsigned coefficient magnitude. Special codewords that mark significant
+ locations in the bitstream are indicated by a run length of zero and the
+ value indicates the type of marker.
+
+ The codebook is generated by a separate program that takes as input a table
+ of the frequencies of coefficient magnitudes and runs of zeros.
+*/
+typedef struct _codebook
+{
+ uint32_t length; //!< Number of entries in the code book
+ // The length is followed by the RLV entries
+} CODEBOOK;
+
+//! Macro used to define the codebook generated by the Huffman program
+#define RLVTABLE(n) \
+ static struct \
+ { \
+ uint32_t length; \
+ RLV entries[n]; \
+ }
+
+/*!
+ @brief Table of codewords for coefficient magnitudes
+
+ The entries in this table are indexed by the coefficient magnitude.
+
+ This table is derived from the master codebook by sorting the entries
+ for coefficient magnitudes into increasing order. Each entry in the
+ table is a codeword and its size in bits.
+*/
+typedef struct _magnitude_table
+{
+ uint32_t length; //!< Number of entries in the encoding table
+ // The length is followed by the VLE entries
+} MAGS_TABLE;
+
+/*!
+ @brief Entry in the table for encoding coefficients magnitudes
+
+ Each entry is the codeword and its size in bits. The typename VLE
+ stands for variable length encoding to distinguish this entry from
+ the data structures for variable length coding in general.
+*/
+typedef struct _vle {
+ uint_fast8_t size; //!< Size of code word in bits
+ uint32_t bits; //!< Code words bits (right justified)
+} VLE;
+
+/*!
+ @brief Table of codewords for runs of zeros
+
+ The entries in this table are indexed by length of the run of zeros.
+
+ This table is derived from the master codebook by concatenating codewords
+ for runs of zeros to form a codeword a run with the specified length.
+
+ Each entry in the table is a codeword and its size in bits and the number
+ of zeros that are that are not included in the run represented by the
+ codeword.
+*/
+typedef struct _runs_table
+{
+ uint32_t length; //!< Number of entries in the encoding table
+ // The length is followed by the RLC entries
+} RUNS_TABLE;
+
+/*!
+ @brief Entry in the table for encoding runs of zeros
+*/
+typedef struct _rlc { // Codebook entries for runs of zeros
+ uint_fast8_t size; //!< Size of code word in bits
+ uint32_t count; //!< Remaining length of the run
+ uint32_t bits; //!< Code word bits (right justified)
+} RLC;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ CODEC_ERROR PutZeros(BITSTREAM *stream, const RUNS_TABLE *codebook, uint32_t count);
+ CODEC_ERROR PutSpecial(BITSTREAM *stream, const CODEBOOK *codebook, SPECIAL_MARKER marker);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VLC_H
diff --git a/gpr/source/lib/xmp_core/BSD-License.txt b/gpr/source/lib/xmp_core/BSD-License.txt
new file mode 100644
index 0000000..07b967c
--- /dev/null
+++ b/gpr/source/lib/xmp_core/BSD-License.txt
@@ -0,0 +1,32 @@
+The BSD License
+
+Copyright (c) 1999 - 2014, Adobe Systems Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+* Neither the name of Adobe Systems Incorporated, nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/gpr/source/lib/xmp_core/CMakeLists.txt b/gpr/source/lib/xmp_core/CMakeLists.txt
new file mode 100644
index 0000000..5bee2e4
--- /dev/null
+++ b/gpr/source/lib/xmp_core/CMakeLists.txt
@@ -0,0 +1,32 @@
+# library
+set( LIB_NAME xmp_core )
+
+# get source files
+file( GLOB BASE_SRC_FILES "*.cpp" )
+
+# get include files
+file( GLOB BASE_INC_FILES "*.h" "public/include/*.h" "public/include/*.hpp" "public/include/client-glue/*.hpp" )
+
+# get all source files
+set( SRC_FILES ${BASE_SRC_FILES} )
+
+# get all include files
+set( INC_FILES ${BASE_INC_FILES} )
+
+# add include files from other folders
+include_directories( "../md5_lib" )
+include_directories( "../expat_lib" )
+include_directories( "public/include" )
+
+# library
+add_library( ${LIB_NAME} STATIC ${SRC_FILES} ${INC_FILES} )
+
+# define compile time definitions
+target_compile_definitions( ${LIB_NAME} PUBLIC XML_STATIC=1 )
+
+SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libstdc++")
+
+target_link_libraries( ${LIB_NAME} )
+
+# set the folder where to place the projects
+set_target_properties( ${LIB_NAME} PROPERTIES FOLDER lib )
diff --git a/gpr/source/lib/xmp_core/ExpatAdapter.cpp b/gpr/source/lib/xmp_core/ExpatAdapter.cpp
new file mode 100644
index 0000000..c0388c3
--- /dev/null
+++ b/gpr/source/lib/xmp_core/ExpatAdapter.cpp
@@ -0,0 +1,522 @@
+// =================================================================================================
+// Copyright 2005 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "XMPCore_Impl.hpp"
+
+#include "ExpatAdapter.hpp"
+#include "XMPMeta.hpp"
+
+#include "expat.h"
+#include <string.h>
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// *** Set memory handlers.
+
+#ifndef DumpXMLParseEvents
+ #define DumpXMLParseEvents 0
+#endif
+
+#define FullNameSeparator '@'
+
+// =================================================================================================
+
+static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri );
+static void EndNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix );
+
+static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs );
+static void EndElementHandler ( void * userData, XMP_StringPtr name );
+
+static void CharacterDataHandler ( void * userData, XMP_StringPtr cData, int len );
+static void StartCdataSectionHandler ( void * userData );
+static void EndCdataSectionHandler ( void * userData );
+
+static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data );
+static void CommentHandler ( void * userData, XMP_StringPtr comment );
+
+#if BanAllEntityUsage
+
+ // For now we do this by banning DOCTYPE entirely. This is easy and consistent with what is
+ // available in recent Java XML parsers. Another, somewhat less drastic, approach would be to
+ // ban all entity declarations. We can't allow declarations and ban references, Expat does not
+ // call the SkippedEntityHandler for references in attribute values.
+
+ // ! Standard entities (&amp;, &lt;, &gt;, &quot;, &apos;, and numeric character references) are
+ // ! not banned. Expat handles them transparently no matter what.
+
+ static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName,
+ XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset );
+
+#endif
+
+// =================================================================================================
+
+extern "C" ExpatAdapter * XMP_NewExpatAdapter ( bool useGlobalNamespaces )
+{
+
+ return new ExpatAdapter ( useGlobalNamespaces );
+
+} // XMP_NewExpatAdapter
+
+// =================================================================================================
+
+ExpatAdapter::ExpatAdapter ( bool useGlobalNamespaces ) : parser(0), registeredNamespaces(0)
+{
+
+ #if XMP_DebugBuild
+ this->elemNesting = 0;
+ #if DumpXMLParseEvents
+ if ( this->parseLog == 0 ) this->parseLog = stdout;
+ #endif
+ #endif
+
+ this->parser = XML_ParserCreateNS ( 0, FullNameSeparator );
+ if ( this->parser == 0 ) {
+ XMP_Error error(kXMPErr_NoMemory, "Failure creating Expat parser" );
+ this->NotifyClient ( kXMPErrSev_ProcessFatal, error );
+ }else{
+ if ( useGlobalNamespaces ) {
+ this->registeredNamespaces = sRegisteredNamespaces;
+ } else {
+ this->registeredNamespaces = new XMP_NamespaceTable ( *sRegisteredNamespaces );
+ }
+
+ XML_SetUserData ( this->parser, this );
+
+ XML_SetNamespaceDeclHandler ( this->parser, StartNamespaceDeclHandler, EndNamespaceDeclHandler );
+ XML_SetElementHandler ( this->parser, StartElementHandler, EndElementHandler );
+
+ XML_SetCharacterDataHandler ( this->parser, CharacterDataHandler );
+ XML_SetCdataSectionHandler ( this->parser, StartCdataSectionHandler, EndCdataSectionHandler );
+
+ XML_SetProcessingInstructionHandler ( this->parser, ProcessingInstructionHandler );
+ XML_SetCommentHandler ( this->parser, CommentHandler );
+
+ #if BanAllEntityUsage
+ XML_SetStartDoctypeDeclHandler ( this->parser, StartDoctypeDeclHandler );
+ isAborted = false;
+ #endif
+
+ this->parseStack.push_back ( &this->tree ); // Push the XML root node.
+ }
+} // ExpatAdapter::ExpatAdapter
+
+// =================================================================================================
+
+ExpatAdapter::~ExpatAdapter()
+{
+
+ if ( this->parser != 0 ) XML_ParserFree ( this->parser );
+ this->parser = 0;
+
+ if ( this->registeredNamespaces != sRegisteredNamespaces ) delete ( this->registeredNamespaces );
+ this->registeredNamespaces = 0;
+
+} // ExpatAdapter::~ExpatAdapter
+
+// =================================================================================================
+
+#if XMP_DebugBuild
+ static XMP_VarString sExpatMessage;
+#endif
+
+static const char * kOneSpace = " ";
+
+void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last /* = true */ )
+{
+ enum XML_Status status;
+
+ if ( length == 0 ) { // Expat does not like empty buffers.
+ if ( ! last ) return;
+ buffer = kOneSpace;
+ length = 1;
+ }
+
+ status = XML_Parse ( this->parser, (const char *)buffer, length, last );
+
+ #if BanAllEntityUsage
+ if ( this->isAborted ) {
+ XMP_Error error(kXMPErr_BadXML, "DOCTYPE is not allowed" )
+ this->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+ #endif
+
+ if ( status != XML_STATUS_OK ) {
+
+ XMP_StringPtr errMsg = "XML parsing failure";
+
+ #if 0 // XMP_DebugBuild // Disable for now to make test output uniform. Restore later with thread safety.
+
+ // *** This is a good candidate for a callback error notification mechanism.
+ // *** This code is not thread safe, the sExpatMessage isn't locked. But that's OK for debug usage.
+
+ enum XML_Error expatErr = XML_GetErrorCode ( this->parser );
+ const char * expatMsg = XML_ErrorString ( expatErr );
+ int errLine = XML_GetCurrentLineNumber ( this->parser );
+
+ char msgBuffer[1000];
+ // AUDIT: Use of sizeof(msgBuffer) for snprintf length is safe.
+ snprintf ( msgBuffer, sizeof(msgBuffer), "# Expat error %d at line %d, \"%s\"", expatErr, errLine, expatMsg );
+ sExpatMessage = msgBuffer;
+ errMsg = sExpatMessage.c_str();
+
+ #if DumpXMLParseEvents
+ if ( this->parseLog != 0 ) fprintf ( this->parseLog, "%s\n", errMsg, expatErr, errLine, expatMsg );
+ #endif
+
+ #endif
+
+ XMP_Error error(kXMPErr_BadXML, errMsg);
+ this->NotifyClient ( kXMPErrSev_Recoverable, error );
+
+ }
+
+} // ExpatAdapter::ParseBuffer
+
+// =================================================================================================
+// =================================================================================================
+
+#if XMP_DebugBuild & DumpXMLParseEvents
+
+ static inline void PrintIndent ( FILE * file, size_t count )
+ {
+ for ( ; count > 0; --count ) fprintf ( file, " " );
+ }
+
+#endif
+
+// =================================================================================================
+
+static void SetQualName ( ExpatAdapter * thiz, XMP_StringPtr fullName, XML_Node * node )
+{
+ // Expat delivers the full name as a catenation of namespace URI, separator, and local name.
+
+ // As a compatibility hack, an "about" or "ID" attribute of an rdf:Description element is
+ // changed to "rdf:about" or rdf:ID. Easier done here than in the RDF recognizer.
+
+ // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/.
+ // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace.
+
+ // ! This code presumes the RDF namespace prefix is "rdf".
+
+ size_t sepPos = strlen(fullName);
+ for ( --sepPos; sepPos > 0; --sepPos ) {
+ if ( fullName[sepPos] == FullNameSeparator ) break;
+ }
+
+ if ( fullName[sepPos] == FullNameSeparator ) {
+
+ XMP_StringPtr prefix;
+ XMP_StringLen prefixLen;
+ XMP_StringPtr localPart = fullName + sepPos + 1;
+
+ node->ns.assign ( fullName, sepPos );
+ if ( node->ns == "http://purl.org/dc/1.1/" ) node->ns = "http://purl.org/dc/elements/1.1/";
+
+ bool found = thiz->registeredNamespaces->GetPrefix ( node->ns.c_str(), &prefix, &prefixLen );
+ if ( ! found ) {
+ XMP_Error error(kXMPErr_ExternalFailure, "Unknown URI in Expat full name" );
+ thiz->NotifyClient ( kXMPErrSev_OperationFatal, error );
+ }
+ node->nsPrefixLen = prefixLen; // ! Includes the ':'.
+
+ node->name = prefix;
+ node->name += localPart;
+
+ } else {
+
+ node->name = fullName; // The name is not in a namespace.
+
+ if ( node->parent->name == "rdf:Description" ) {
+ if ( node->name == "about" ) {
+ node->ns = kXMP_NS_RDF;
+ node->name = "rdf:about";
+ node->nsPrefixLen = 4; // ! Include the ':'.
+ } else if ( node->name == "ID" ) {
+ node->ns = kXMP_NS_RDF;
+ node->name = "rdf:ID";
+ node->nsPrefixLen = 4; // ! Include the ':'.
+ }
+ }
+
+ }
+
+} // SetQualName
+
+// =================================================================================================
+
+static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, XMP_StringPtr uri )
+{
+ IgnoreParam(userData);
+
+ // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/.
+ // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace.
+
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace.
+ if ( uri == 0 ) return; // Ignore, have xmlns:pre="", no URI to register.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "StartNamespace: %s - \"%s\"\n", prefix, uri );
+ }
+ #endif
+
+ if ( XMP_LitMatch ( uri, "http://purl.org/dc/1.1/" ) ) uri = "http://purl.org/dc/elements/1.1/";
+ (void) thiz->registeredNamespaces->Define ( uri, prefix, 0, 0 );
+
+} // StartNamespaceDeclHandler
+
+// =================================================================================================
+
+static void EndNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "EndNamespace: %s\n", prefix );
+ }
+ #endif
+
+ // ! Nothing to do, Expat has done all of the XML processing.
+
+} // EndNamespaceDeclHandler
+
+// =================================================================================================
+
+static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_StringPtr* attrs )
+{
+ XMP_Assert ( attrs != 0 );
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ size_t attrCount = 0;
+ for ( XMP_StringPtr* a = attrs; *a != 0; ++a ) ++attrCount;
+ if ( (attrCount & 1) != 0 ) {
+ XMP_Error error(kXMPErr_ExternalFailure, "Expat attribute info has odd length");
+ thiz->NotifyClient ( kXMPErrSev_OperationFatal, error );
+ }
+ attrCount = attrCount/2; // They are name/value pairs.
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "StartElement: %s, %d attrs", name, attrCount );
+ for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {
+ XMP_StringPtr attrName = *attr;
+ XMP_StringPtr attrValue = *(attr+1);
+ fprintf ( thiz->parseLog, ", %s = \"%s\"", attrName, attrValue );
+ }
+ fprintf ( thiz->parseLog, "\n" );
+ }
+ #endif
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * elemNode = new XML_Node ( parentNode, "", kElemNode );
+
+ SetQualName ( thiz, name, elemNode );
+
+ for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) {
+
+ XMP_StringPtr attrName = *attr;
+ XMP_StringPtr attrValue = *(attr+1);
+ XML_Node * attrNode = new XML_Node ( elemNode, "", kAttrNode );
+
+ SetQualName ( thiz, attrName, attrNode );
+ attrNode->value = attrValue;
+ if ( attrNode->name == "xml:lang" ) NormalizeLangValue ( &attrNode->value );
+ elemNode->attrs.push_back ( attrNode );
+
+ }
+
+ parentNode->content.push_back ( elemNode );
+ thiz->parseStack.push_back ( elemNode );
+
+ if ( elemNode->name == "rdf:RDF" ) {
+ thiz->rootNode = elemNode;
+ ++thiz->rootCount;
+ }
+ #if XMP_DebugBuild
+ ++thiz->elemNesting;
+ #endif
+
+} // StartElementHandler
+
+// =================================================================================================
+
+static void EndElementHandler ( void * userData, XMP_StringPtr name )
+{
+ IgnoreParam(name);
+
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ #if XMP_DebugBuild
+ --thiz->elemNesting;
+ #endif
+ (void) thiz->parseStack.pop_back();
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "EndElement: %s\n", name );
+ }
+ #endif
+
+} // EndElementHandler
+
+// =================================================================================================
+
+static void CharacterDataHandler ( void * userData, XMP_StringPtr cData, int len )
+{
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ if ( (cData == 0) || (len == 0) ) { cData = ""; len = 0; }
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "CharContent: \"" );
+ for ( int i = 0; i < len; ++i ) fprintf ( thiz->parseLog, "%c", cData[i] );
+ fprintf ( thiz->parseLog, "\"\n" );
+ }
+ #endif
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * cDataNode = new XML_Node ( parentNode, "", kCDataNode );
+
+ cDataNode->value.assign ( cData, len );
+ parentNode->content.push_back ( cDataNode );
+
+} // CharacterDataHandler
+
+// =================================================================================================
+
+static void StartCdataSectionHandler ( void * userData )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "StartCDATA\n" );
+ }
+ #endif
+
+ // *** Since markup isn't recognized inside CDATA, this affects XMP's double escaping.
+
+} // StartCdataSectionHandler
+
+// =================================================================================================
+
+static void EndCdataSectionHandler ( void * userData )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "EndCDATA\n" );
+ }
+ #endif
+
+} // EndCdataSectionHandler
+
+// =================================================================================================
+
+static void ProcessingInstructionHandler ( void * userData, XMP_StringPtr target, XMP_StringPtr data )
+{
+ XMP_Assert ( target != 0 );
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ if ( ! XMP_LitMatch ( target, "xpacket" ) ) return; // Ignore all PIs except the XMP packet wrapper.
+ if ( data == 0 ) data = "";
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "PI: %s - \"%s\"\n", target, data );
+ }
+ #endif
+
+ XML_Node * parentNode = thiz->parseStack.back();
+ XML_Node * piNode = new XML_Node ( parentNode, target, kPINode );
+
+ piNode->value.assign ( data );
+ parentNode->content.push_back ( piNode );
+
+} // ProcessingInstructionHandler
+
+// =================================================================================================
+
+static void CommentHandler ( void * userData, XMP_StringPtr comment )
+{
+ IgnoreParam(userData);
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+ #endif
+
+ if ( comment == 0 ) comment = "";
+
+ #if XMP_DebugBuild & DumpXMLParseEvents
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "Comment: \"%s\"\n", comment );
+ }
+ #endif
+
+ // ! Comments are ignored.
+
+} // CommentHandler
+
+// =================================================================================================
+
+#if BanAllEntityUsage
+static void StartDoctypeDeclHandler ( void * userData, XMP_StringPtr doctypeName,
+ XMP_StringPtr sysid, XMP_StringPtr pubid, int has_internal_subset )
+{
+ IgnoreParam(userData);
+
+ ExpatAdapter * thiz = (ExpatAdapter*)userData;
+
+ #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
+ if ( thiz->parseLog != 0 ) {
+ PrintIndent ( thiz->parseLog, thiz->elemNesting );
+ fprintf ( thiz->parseLog, "DocType: \"%s\"\n", doctypeName );
+ }
+ #endif
+
+ thiz->isAborted = true; // ! Can't throw an exception across the plain C Expat frames.
+ (void) XML_StopParser ( thiz->parser, XML_FALSE /* not resumable */ );
+
+} // StartDoctypeDeclHandler
+#endif
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/ExpatAdapter.hpp b/gpr/source/lib/xmp_core/ExpatAdapter.hpp
new file mode 100644
index 0000000..4e03436
--- /dev/null
+++ b/gpr/source/lib/xmp_core/ExpatAdapter.hpp
@@ -0,0 +1,59 @@
+#ifndef __ExpatAdapter_hpp__
+#define __ExpatAdapter_hpp__
+
+// =================================================================================================
+// Copyright 2005 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "XMLParserAdapter.hpp"
+
+// =================================================================================================
+// Derived XML parser adapter for Expat.
+// =================================================================================================
+
+#ifndef BanAllEntityUsage
+ #define BanAllEntityUsage 0
+#endif
+
+struct XML_ParserStruct; // ! Hack to avoid exposing expat.h to all clients.
+typedef struct XML_ParserStruct *XML_Parser;
+
+class ExpatAdapter : public XMLParserAdapter {
+public:
+
+ XML_Parser parser;
+ XMP_NamespaceTable * registeredNamespaces;
+
+ #if BanAllEntityUsage
+ bool isAborted;
+ #endif
+
+ #if XMP_DebugBuild
+ size_t elemNesting;
+ #endif
+
+ static const bool kUseGlobalNamespaces = true;
+ static const bool kUseLocalNamespaces = false;
+
+ ExpatAdapter ( bool useGlobalNamespaces );
+ virtual ~ExpatAdapter();
+
+ void ParseBuffer ( const void * buffer, size_t length, bool last = true );
+
+private:
+
+ ExpatAdapter() : registeredNamespaces(0) {}; // ! Force use of constructor with namespace parameter.
+
+};
+
+extern "C" ExpatAdapter *
+XMP_PUBLIC XMP_NewExpatAdapter ( bool useGlobalNamespaces );
+
+// =================================================================================================
+
+#endif // __ExpatAdapter_hpp__
diff --git a/gpr/source/lib/xmp_core/ParseRDF.cpp b/gpr/source/lib/xmp_core/ParseRDF.cpp
new file mode 100644
index 0000000..0b69e31
--- /dev/null
+++ b/gpr/source/lib/xmp_core/ParseRDF.cpp
@@ -0,0 +1,1459 @@
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+#include "XMPMeta.hpp"
+#include "ExpatAdapter.hpp"
+
+#include <cstring>
+
+#if DEBUG
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4505 ) // unreferenced local function has been removed
+#endif
+
+// =================================================================================================
+
+// *** This might be faster and use less memory as a state machine. A big advantage of building an
+// *** XML tree though is easy lookahead during the recursive descent processing.
+
+// *** It would be nice to give a line number or byte offset in the exception messages.
+
+
+// 7 RDF/XML Grammar (from http://www.w3.org/TR/rdf-syntax-grammar/#section-Infoset-Grammar)
+//
+// 7.1 Grammar summary
+//
+// 7.2.2 coreSyntaxTerms
+// rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype
+//
+// 7.2.3 syntaxTerms
+// coreSyntaxTerms | rdf:Description | rdf:li
+//
+// 7.2.4 oldTerms
+// rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
+//
+// 7.2.5 nodeElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+//
+// 7.2.6 propertyElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
+//
+// 7.2.7 propertyAttributeURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+//
+// 7.2.8 doc
+// root ( document-element == RDF, children == list ( RDF ) )
+//
+// 7.2.9 RDF
+// start-element ( URI == rdf:RDF, attributes == set() )
+// nodeElementList
+// end-element()
+//
+// 7.2.10 nodeElementList
+// ws* ( nodeElement ws* )*
+//
+// 7.2.11 nodeElement
+// start-element ( URI == nodeElementURIs,
+// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.12 ws
+// A text event matching white space defined by [XML] definition White Space Rule [3] S in section Common Syntactic Constructs.
+//
+// 7.2.13 propertyEltList
+// ws* ( propertyElt ws* )*
+//
+// 7.2.14 propertyElt
+// resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
+// parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt
+//
+// 7.2.15 resourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+// ws* nodeElement ws*
+// end-element()
+//
+// 7.2.16 literalPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+// text()
+// end-element()
+//
+// 7.2.17 parseTypeLiteralPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+// literal
+// end-element()
+//
+// 7.2.18 parseTypeResourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.19 parseTypeCollectionPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+// nodeElementList
+// end-element()
+//
+// 7.2.20 parseTypeOtherPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.21 emptyPropertyElt
+// start-element ( URI == propertyElementURIs,
+// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+// end-element()
+//
+// 7.2.22 idAttr
+// attribute ( URI == rdf:ID, string-value == rdf-id )
+//
+// 7.2.23 nodeIdAttr
+// attribute ( URI == rdf:nodeID, string-value == rdf-id )
+//
+// 7.2.24 aboutAttr
+// attribute ( URI == rdf:about, string-value == URI-reference )
+//
+// 7.2.25 propertyAttr
+// attribute ( URI == propertyAttributeURIs, string-value == anyString )
+//
+// 7.2.26 resourceAttr
+// attribute ( URI == rdf:resource, string-value == URI-reference )
+//
+// 7.2.27 datatypeAttr
+// attribute ( URI == rdf:datatype, string-value == URI-reference )
+//
+// 7.2.28 parseLiteral
+// attribute ( URI == rdf:parseType, string-value == "Literal")
+//
+// 7.2.29 parseResource
+// attribute ( URI == rdf:parseType, string-value == "Resource")
+//
+// 7.2.30 parseCollection
+// attribute ( URI == rdf:parseType, string-value == "Collection")
+//
+// 7.2.31 parseOther
+// attribute ( URI == rdf:parseType, string-value == anyString - ("Resource" | "Literal" | "Collection") )
+//
+// 7.2.32 URI-reference
+// An RDF URI Reference.
+//
+// 7.2.33 literal
+// Any XML element content that is allowed according to [XML] definition Content of Elements Rule [43] content
+// in section 3.1 Start-Tags, End-Tags, and Empty-Element Tags.
+//
+// 7.2.34 rdf-id
+// An attribute string-value matching any legal [XML-NS] token NCName.
+
+
+// =================================================================================================
+// Primary Parsing Functions
+// =========================
+//
+// Each of these is responsible for recognizing an RDF syntax production and adding the appropriate
+// structure to the XMP tree. They simply return for success, failures will throw an exception. The
+// class exists only to provide access to the error notification object.
+
+class RDF_Parser {
+public:
+
+ void RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode );
+
+ void NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
+
+ void NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
+
+ void PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ void EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
+
+ RDF_Parser ( XMPMeta::ErrorCallbackInfo * ec ) : errorCallback(ec) {};
+
+private:
+
+ RDF_Parser() {
+
+ errorCallback = NULL;
+
+ }; // Hidden on purpose.
+
+ XMPMeta::ErrorCallbackInfo * errorCallback;
+
+ XMP_Node * AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel );
+
+ XMP_Node * AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value );
+
+ XMP_Node * AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr );
+
+ void FixupQualifiedNode ( XMP_Node * xmpParent );
+
+};
+
+enum { kIsTopLevel = true, kNotTopLevel = false };
+
+// =================================================================================================
+
+typedef XMP_Uns8 RDFTermKind;
+
+// *** Logic might be safer with just masks.
+
+enum {
+ kRDFTerm_Other = 0,
+ kRDFTerm_RDF = 1, // Start of coreSyntaxTerms.
+ kRDFTerm_ID = 2,
+ kRDFTerm_about = 3,
+ kRDFTerm_parseType = 4,
+ kRDFTerm_resource = 5,
+ kRDFTerm_nodeID = 6,
+ kRDFTerm_datatype = 7, // End of coreSyntaxTerms.
+ kRDFTerm_Description = 8, // Start of additions for syntaxTerms.
+ kRDFTerm_li = 9, // End of of additions for syntaxTerms.
+ kRDFTerm_aboutEach = 10, // Start of oldTerms.
+ kRDFTerm_aboutEachPrefix = 11,
+ kRDFTerm_bagID = 12, // End of oldTerms.
+
+ kRDFTerm_FirstCore = kRDFTerm_RDF,
+ kRDFTerm_LastCore = kRDFTerm_datatype,
+ kRDFTerm_FirstSyntax = kRDFTerm_FirstCore, // ! Yes, the syntax terms include the core terms.
+ kRDFTerm_LastSyntax = kRDFTerm_li,
+ kRDFTerm_FirstOld = kRDFTerm_aboutEach,
+ kRDFTerm_LastOld = kRDFTerm_bagID
+};
+
+enum {
+ kRDFMask_Other = 1 << kRDFTerm_Other,
+ kRDFMask_RDF = 1 << kRDFTerm_RDF,
+ kRDFMask_ID = 1 << kRDFTerm_ID,
+ kRDFMask_about = 1 << kRDFTerm_about,
+ kRDFMask_parseType = 1 << kRDFTerm_parseType,
+ kRDFMask_resource = 1 << kRDFTerm_resource,
+ kRDFMask_nodeID = 1 << kRDFTerm_nodeID,
+ kRDFMask_datatype = 1 << kRDFTerm_datatype,
+ kRDFMask_Description = 1 << kRDFTerm_Description,
+ kRDFMask_li = 1 << kRDFTerm_li,
+ kRDFMask_aboutEach = 1 << kRDFTerm_aboutEach,
+ kRDFMask_aboutEachPrefix = 1 << kRDFTerm_aboutEachPrefix,
+ kRDFMask_bagID = 1 << kRDFTerm_bagID
+};
+
+enum {
+ kRDF_HasValueElem = 0x10000000UL // ! Contains rdf:value child. Must fit within kXMP_ImplReservedMask!
+};
+
+// -------------------------------------------------------------------------------------------------
+// GetRDFTermKind
+// --------------
+
+static RDFTermKind
+GetRDFTermKind ( const XMP_VarString & name )
+{
+ RDFTermKind term = kRDFTerm_Other;
+
+ // Arranged to hopefully minimize the parse time for large XMP.
+
+ if ( (name.size() > 4) && (strncmp ( name.c_str(), "rdf:", 4 ) == 0) ) {
+
+ if ( name == "rdf:li" ) {
+ term = kRDFTerm_li;
+ } else if ( name == "rdf:parseType" ) {
+ term = kRDFTerm_parseType;
+ } else if ( name == "rdf:Description" ) {
+ term = kRDFTerm_Description;
+ } else if ( name == "rdf:about" ) {
+ term = kRDFTerm_about;
+ } else if ( name == "rdf:resource" ) {
+ term = kRDFTerm_resource;
+ } else if ( name == "rdf:RDF" ) {
+ term = kRDFTerm_RDF;
+ } else if ( name == "rdf:ID" ) {
+ term = kRDFTerm_ID;
+ } else if ( name == "rdf:nodeID" ) {
+ term = kRDFTerm_nodeID;
+ } else if ( name == "rdf:datatype" ) {
+ term = kRDFTerm_datatype;
+ } else if ( name == "rdf:aboutEach" ) {
+ term = kRDFTerm_aboutEach;
+ } else if ( name == "rdf:aboutEachPrefix" ) {
+ term = kRDFTerm_aboutEachPrefix;
+ } else if ( name == "rdf:bagID" ) {
+ term = kRDFTerm_bagID;
+ }
+
+ }
+
+ return term;
+
+} // GetRDFTermKind
+
+// =================================================================================================
+
+static void
+RemoveChild ( XMP_Node * xmpParent, size_t index )
+{
+ XMP_Node * child = xmpParent->children[index];
+ xmpParent->children.erase ( xmpParent->children.begin() + index );
+ delete child;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static void
+RemoveQualifier ( XMP_Node * xmpParent, size_t index )
+{
+ XMP_Node * qualifier = xmpParent->qualifiers[index];
+ xmpParent->qualifiers.erase ( xmpParent->qualifiers.begin() + index );
+ delete qualifier;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static void
+RemoveQualifier ( XMP_Node * xmpParent, XMP_NodePtrPos pos )
+{
+ XMP_Node * qualifier = *pos;
+ xmpParent->qualifiers.erase ( pos );
+ delete qualifier;
+}
+
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// IsCoreSyntaxTerm
+// ----------------
+//
+// 7.2.2 coreSyntaxTerms
+// rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype
+
+static bool
+IsCoreSyntaxTerm ( RDFTermKind term )
+{
+ if ( (kRDFTerm_FirstCore <= term) && (term <= kRDFTerm_LastCore) ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+// IsSyntaxTerm
+// ------------
+//
+// 7.2.3 syntaxTerms
+// coreSyntaxTerms | rdf:Description | rdf:li
+
+static bool
+IsSyntaxTerm ( RDFTermKind term )
+{
+ if ( (kRDFTerm_FirstSyntax <= term) && (term <= kRDFTerm_LastSyntax) ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+// IsOldTerm
+// ---------
+//
+// 7.2.4 oldTerms
+// rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
+
+static bool
+IsOldTerm ( RDFTermKind term )
+{
+ if ( (kRDFTerm_FirstOld <= term) && (term <= kRDFTerm_LastOld) ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+// IsNodeElementName
+// -----------------
+//
+// 7.2.5 nodeElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+
+static bool
+IsNodeElementName ( RDFTermKind term )
+{
+ if ( (term == kRDFTerm_li) || IsOldTerm ( term ) ) return false;
+ return (! IsCoreSyntaxTerm ( term ));
+}
+
+// -------------------------------------------------------------------------------------------------
+// IsPropertyElementName
+// ---------------------
+//
+// 7.2.6 propertyElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
+
+static bool
+IsPropertyElementName ( RDFTermKind term )
+{
+ if ( (term == kRDFTerm_Description) || IsOldTerm ( term ) ) return false;
+ return (! IsCoreSyntaxTerm ( term ));
+}
+
+// -------------------------------------------------------------------------------------------------
+// IsPropertyAttributeName
+// -----------------------
+//
+// 7.2.7 propertyAttributeURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+
+static bool
+IsPropertyAttributeName ( RDFTermKind term )
+{
+ if ( (term == kRDFTerm_Description) || (term == kRDFTerm_li) || IsOldTerm ( term ) ) return false;
+ return (! IsCoreSyntaxTerm ( term ));
+}
+
+// -------------------------------------------------------------------------------------------------
+// IsNumberedArrayItemName
+// -----------------------
+//
+// Return true for a name of the form "rdf:_n", where n is a decimal integer. We're not strict about
+// the integer part, it just has to be characters in the range '0'..'9'.
+
+static bool
+IsNumberedArrayItemName ( const std::string & name )
+{
+ if ( name.size() <= 5 ) return false;
+ if ( strncmp ( name.c_str(), "rdf:_", 5 ) != 0 ) return false;
+ for ( size_t i = 5; i < name.size(); ++i ) {
+ if ( (name[i] < '0') | (name[i] > '9') ) return false;
+ }
+ return true;
+}
+
+// =================================================================================================
+// RDF_Parser::AddChildNode
+// ========================
+
+XMP_Node * RDF_Parser::AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel )
+{
+
+ if ( xmlNode.ns.empty() ) {
+ XMP_Error error ( kXMPErr_BadRDF, "XML namespace required for all elements and attributes" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+
+ bool isArrayParent = (xmpParent->options & kXMP_PropValueIsArray) !=0;
+ bool isArrayItem = (xmlNode.name == "rdf:li");
+ bool isValueNode = (xmlNode.name == "rdf:value");
+ XMP_OptionBits childOptions = 0;
+ XMP_StringPtr childName = xmlNode.name.c_str();
+
+ if ( isTopLevel ) {
+
+ // Lookup the schema node, adjust the XMP parent pointer.
+ XMP_Assert ( xmpParent->parent == 0 ); // Incoming parent must be the tree root.
+ XMP_Node * schemaNode = FindSchemaNode ( xmpParent, xmlNode.ns.c_str(), kXMP_CreateNodes );
+ if ( schemaNode->options & kXMP_NewImplicitNode ) schemaNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ // *** Should use "opt &= ~flag" (no conditional), need runtime check for proper 32 bit code.
+ xmpParent = schemaNode;
+
+ // If this is an alias set the isAlias flag in the node and the hasAliases flag in the tree.
+ if ( sRegisteredAliasMap->find ( xmlNode.name ) != sRegisteredAliasMap->end() ) {
+ childOptions |= kXMP_PropIsAlias;
+ schemaNode->parent->options |= kXMP_PropHasAliases;
+ }
+
+ }
+
+ // Check use of rdf:li and rdf:_n names. Must be done before calling FindChildNode!
+ if ( isArrayItem ) {
+
+ // rdf:li can only be used for array children.
+ if ( ! isArrayParent ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Misplaced rdf:li element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+ childName = kXMP_ArrayItemName;
+
+ } else if ( isArrayParent ) {
+
+ // Tolerate use of rdf:_n, don't verify order.
+ if ( IsNumberedArrayItemName ( xmlNode.name ) ) {
+ childName = kXMP_ArrayItemName;
+ isArrayItem = true;
+ } else {
+ XMP_Error error ( kXMPErr_BadRDF, "Array items cannot have arbitrary child names" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+
+ }
+
+ // Make sure that this is not a duplicate of a named node.
+ if ( ! (isArrayItem | isValueNode) ) {
+ if ( FindChildNode ( xmpParent, childName, kXMP_ExistingOnly ) != 0 ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Duplicate property or field node" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+ }
+
+ // Make sure an rdf:value node is used properly.
+ if ( isValueNode ) {
+ if ( isTopLevel || (! (xmpParent->options & kXMP_PropValueIsStruct)) ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Misplaced rdf:value element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+ xmpParent->options |= kRDF_HasValueElem;
+ }
+
+ // Add the new child to the XMP parent node.
+ XMP_Node * newChild = new XMP_Node ( xmpParent, childName, value, childOptions );
+ if ( (! isValueNode) || xmpParent->children.empty() ) {
+ xmpParent->children.push_back ( newChild );
+ } else {
+ xmpParent->children.insert ( xmpParent->children.begin(), newChild );
+ }
+
+ return newChild;
+
+} // RDF_Parser::AddChildNode
+
+// =================================================================================================
+// RDF_Parser::AddQualifierNode
+// ============================
+
+XMP_Node * RDF_Parser::AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value )
+{
+
+ const bool isLang = (name == "xml:lang");
+ const bool isType = (name == "rdf:type");
+
+ XMP_Node * newQual = 0;
+
+ newQual = new XMP_Node ( xmpParent, name, value, kXMP_PropIsQualifier );
+
+ if ( ! (isLang | isType) ) {
+ xmpParent->qualifiers.push_back ( newQual );
+ } else if ( isLang ) {
+ if ( xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( newQual );
+ } else {
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), newQual );
+ }
+ xmpParent->options |= kXMP_PropHasLang;
+ } else {
+ XMP_Assert ( isType );
+ if ( xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( newQual );
+ } else {
+ size_t offset = 0;
+ if ( XMP_PropHasLang ( xmpParent->options ) ) offset = 1;
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin()+offset, newQual );
+ }
+ xmpParent->options |= kXMP_PropHasType;
+ }
+
+ xmpParent->options |= kXMP_PropHasQualifiers;
+
+ return newQual;
+
+} // RDF_Parser::AddQualifierNode
+
+// =================================================================================================
+// RDF_Parser::AddQualifierNode
+// ============================
+
+XMP_Node * RDF_Parser::AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr )
+{
+ if ( attr.ns.empty() ) {
+ XMP_Error error ( kXMPErr_BadRDF, "XML namespace required for all elements and attributes" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+
+ return this->AddQualifierNode ( xmpParent, attr.name, attr.value );
+
+} // RDF_Parser::AddQualifierNode
+
+// =================================================================================================
+// RDF_Parser::FixupQualifiedNode
+// ==============================
+//
+// The parent is an RDF pseudo-struct containing an rdf:value field. Fix the XMP data model. The
+// rdf:value node must be the first child, the other children are qualifiers. The form, value, and
+// children of the rdf:value node are the real ones. The rdf:value node's qualifiers must be added
+// to the others.
+
+void RDF_Parser::FixupQualifiedNode ( XMP_Node * xmpParent )
+{
+ size_t qualNum, qualLim;
+ size_t childNum, childLim;
+
+ XMP_Enforce ( (xmpParent->options & kXMP_PropValueIsStruct) && (! xmpParent->children.empty()) );
+
+ XMP_Node * valueNode = xmpParent->children[0];
+ XMP_Enforce ( valueNode->name == "rdf:value" );
+
+ xmpParent->qualifiers.reserve ( xmpParent->qualifiers.size() + xmpParent->children.size() + valueNode->qualifiers.size() );
+
+ // Move the qualifiers on the value node to the parent. Make sure an xml:lang qualifier stays at
+ // the front.
+
+ qualNum = 0;
+ qualLim = valueNode->qualifiers.size();
+
+ if ( valueNode->options & kXMP_PropHasLang ) {
+
+ if ( xmpParent->options & kXMP_PropHasLang ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Duplicate xml:lang for rdf:value element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ XMP_Assert ( xmpParent->qualifiers[0]->name == "xml:lang" );
+ RemoveQualifier ( xmpParent, 0 ); // Use the rdf:value node's language.
+ }
+
+ XMP_Node * langQual = valueNode->qualifiers[0];
+
+ XMP_Assert ( langQual->name == "xml:lang" );
+ langQual->parent = xmpParent;
+ xmpParent->options |= kXMP_PropHasLang;
+ XMP_ClearOption ( valueNode->options, kXMP_PropHasLang );
+
+ if ( xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( langQual ); // *** Should use utilities to add qual & set parent.
+ } else {
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), langQual );
+ }
+ valueNode->qualifiers[0] = 0; // We just moved it to the parent.
+
+ qualNum = 1; // Start the remaining copy after the xml:lang qualifier.
+
+ }
+
+ for ( ; qualNum != qualLim; ++qualNum ) {
+
+ XMP_Node * currQual = valueNode->qualifiers[qualNum];
+ XMP_NodePtrPos existingPos;
+ XMP_Node * existingQual = FindQualifierNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly, &existingPos );
+
+ if ( existingQual != 0 ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Duplicate qualifier node" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ RemoveQualifier ( xmpParent, existingPos ); // Use the rdf:value node's qualifier.
+ }
+
+ currQual->parent = xmpParent;
+ xmpParent->qualifiers.push_back ( currQual );
+ valueNode->qualifiers[qualNum] = 0; // We just moved it to the parent.
+
+ }
+
+ valueNode->qualifiers.clear(); // ! There should be nothing but null pointers.
+
+ // Change the parent's other children into qualifiers. This loop starts at 1, child 0 is the
+ // rdf:value node. Put xml:lang at the front, append all others.
+
+ for ( childNum = 1, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
+
+ XMP_Node * currQual = xmpParent->children[childNum];
+ bool isLang = (currQual->name == "xml:lang");
+
+ if ( FindQualifierNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly ) != 0 ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Duplicate qualifier" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ delete currQual;
+
+ } else {
+
+ currQual->options |= kXMP_PropIsQualifier;
+ currQual->parent = xmpParent;
+
+ if ( isLang ) {
+ xmpParent->options |= kXMP_PropHasLang;
+ } else if ( currQual->name == "rdf:type" ) {
+ xmpParent->options |= kXMP_PropHasType;
+ }
+
+ if ( (! isLang) || xmpParent->qualifiers.empty() ) {
+ xmpParent->qualifiers.push_back ( currQual );
+ } else {
+ xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), currQual );
+ }
+
+ }
+
+ xmpParent->children[childNum] = 0; // We just moved it to the qualifers, or ignored it.
+
+ }
+
+ if ( ! xmpParent->qualifiers.empty() ) xmpParent->options |= kXMP_PropHasQualifiers;
+
+ // Move the options and value last, other checks need the parent's original options. Move the
+ // value node's children to be the parent's children. Delete the now useless value node.
+
+ XMP_Assert ( xmpParent->options & (kXMP_PropValueIsStruct | kRDF_HasValueElem) );
+ xmpParent->options &= ~ (kXMP_PropValueIsStruct | kRDF_HasValueElem);
+ xmpParent->options |= valueNode->options;
+
+ xmpParent->value.swap ( valueNode->value );
+
+ xmpParent->children[0] = 0; // ! Remove the value node itself before the swap.
+ xmpParent->children.swap ( valueNode->children );
+
+ for ( childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
+ XMP_Node * currChild = xmpParent->children[childNum];
+ currChild->parent = xmpParent;
+ }
+
+ delete valueNode;
+
+} // RDF_Parser::FixupQualifiedNode
+
+// =================================================================================================
+// RDF_Parser::RDF
+// ===============
+//
+// 7.2.9 RDF
+// start-element ( URI == rdf:RDF, attributes == set() )
+// nodeElementList
+// end-element()
+//
+// The top level rdf:RDF node. It can only have xmlns attributes, which have already been removed
+// during construction of the XML tree.
+
+void RDF_Parser::RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode )
+{
+
+ if ( ! xmlNode.attrs.empty() ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid attributes of rdf:RDF element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+ this->NodeElementList ( xmpTree, xmlNode, kIsTopLevel ); // ! Attributes are ignored.
+
+} // RDF_Parser::RDF
+
+// =================================================================================================
+// RDF_Parser::NodeElementList
+// ===========================
+//
+// 7.2.10 nodeElementList
+// ws* ( nodeElement ws* )*
+
+void RDF_Parser::NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
+{
+ XMP_Assert ( isTopLevel );
+
+ XML_cNodePos currChild = xmlParent.content.begin(); // *** Change these loops to the indexed pattern.
+ XML_cNodePos endChild = xmlParent.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( (*currChild)->IsWhitespaceNode() ) continue;
+ this->NodeElement ( xmpParent, **currChild, isTopLevel );
+ }
+
+} // RDF_Parser::NodeElementList
+
+// =================================================================================================
+// RDF_Parser::NodeElement
+// =======================
+//
+// 7.2.5 nodeElementURIs
+// anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
+//
+// 7.2.11 nodeElement
+// start-element ( URI == nodeElementURIs,
+// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+// propertyEltList
+// end-element()
+//
+// A node element URI is rdf:Description or anything else that is not an RDF term.
+
+void RDF_Parser::NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
+ if ( (nodeTerm != kRDFTerm_Description) && (nodeTerm != kRDFTerm_Other) ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Node element must be rdf:Description or typedNode" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ } else if ( isTopLevel && (nodeTerm == kRDFTerm_Other) ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Top level typedNode not allowed" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ } else {
+ this->NodeElementAttrs ( xmpParent, xmlNode, isTopLevel );
+ this->PropertyElementList ( xmpParent, xmlNode, isTopLevel );
+ }
+
+} // RDF_Parser::NodeElement
+
+// =================================================================================================
+// RDF_Parser::NodeElementAttrs
+// ============================
+//
+// 7.2.7 propertyAttributeURIs
+// anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
+//
+// 7.2.11 nodeElement
+// start-element ( URI == nodeElementURIs,
+// attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
+// propertyEltList
+// end-element()
+//
+// Process the attribute list for an RDF node element. A property attribute URI is anything other
+// than an RDF term. The rdf:ID and rdf:nodeID attributes are simply ignored, as are rdf:about
+// attributes on inner nodes.
+
+static const XMP_OptionBits kExclusiveAttrMask = (kRDFMask_ID | kRDFMask_nodeID | kRDFMask_about);
+
+void RDF_Parser::NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ XMP_OptionBits exclusiveAttrs = 0; // Used to detect attributes that are mutually exclusive.
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+
+ RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
+
+ switch ( attrTerm ) {
+
+ case kRDFTerm_ID :
+ case kRDFTerm_nodeID :
+ case kRDFTerm_about :
+
+ if ( exclusiveAttrs & kExclusiveAttrMask ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Mutally exclusive about, ID, nodeID attributes" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ continue; // Skip the later mutually exclusive attributes.
+ }
+ exclusiveAttrs |= (1 << attrTerm);
+
+ if ( isTopLevel && (attrTerm == kRDFTerm_about) ) {
+ // This is the rdf:about attribute on a top level node. Set the XMP tree name if
+ // it doesn't have a name yet. Make sure this name matches the XMP tree name.
+ XMP_Assert ( xmpParent->parent == 0 ); // Must be the tree root node.
+ if ( xmpParent->name.empty() ) {
+ xmpParent->name = (*currAttr)->value;
+ } else if ( ! (*currAttr)->value.empty() ) {
+ if ( xmpParent->name != (*currAttr)->value ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Mismatched top level rdf:about values" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+ }
+ }
+
+ break;
+
+ case kRDFTerm_Other :
+ this->AddChildNode ( xmpParent, **currAttr, (*currAttr)->value.c_str(), isTopLevel );
+ break;
+
+ default :
+ {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid nodeElement attribute" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+ continue;
+
+ }
+
+ }
+
+} // RDF_Parser::NodeElementAttrs
+
+// =================================================================================================
+// RDF_Parser::PropertyElementList
+// ===============================
+//
+// 7.2.13 propertyEltList
+// ws* ( propertyElt ws* )*
+
+void RDF_Parser::PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
+{
+ XML_cNodePos currChild = xmlParent.content.begin();
+ XML_cNodePos endChild = xmlParent.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( (*currChild)->IsWhitespaceNode() ) continue;
+ if ( (*currChild)->kind != kElemNode ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Expected property element node not found" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ continue;
+ }
+ this->PropertyElement ( xmpParent, **currChild, isTopLevel );
+ }
+
+} // RDF_Parser::PropertyElementList
+
+// =================================================================================================
+// RDF_Parser::PropertyElement
+// ===========================
+//
+// 7.2.14 propertyElt
+// resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
+// parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt
+//
+// 7.2.15 resourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+// ws* nodeElement ws*
+// end-element()
+//
+// 7.2.16 literalPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+// text()
+// end-element()
+//
+// 7.2.17 parseTypeLiteralPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+// literal
+// end-element()
+//
+// 7.2.18 parseTypeResourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.19 parseTypeCollectionPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+// nodeElementList
+// end-element()
+//
+// 7.2.20 parseTypeOtherPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+// propertyEltList
+// end-element()
+//
+// 7.2.21 emptyPropertyElt
+// start-element ( URI == propertyElementURIs,
+// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+// end-element()
+//
+// The various property element forms are not distinguished by the XML element name, but by their
+// attributes for the most part. The exceptions are resourcePropertyElt and literalPropertyElt. They
+// are distinguished by their XML element content.
+//
+// NOTE: The RDF syntax does not explicitly include the xml:lang attribute although it can appear in
+// many of these. We have to allow for it in the attibute counts below.
+
+void RDF_Parser::PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
+ if ( ! IsPropertyElementName ( nodeTerm ) ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid property element name" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ if ( xmlNode.attrs.size() > 3 ) {
+
+ // Only an emptyPropertyElt can have more than 3 attributes.
+ this->EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
+
+ } else {
+
+ // Look through the attributes for one that isn't rdf:ID or xml:lang, it will usually tell
+ // what we should be dealing with. The called routines must verify their specific syntax!
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+ XMP_VarString * attrName = 0;
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ attrName = &((*currAttr)->name);
+ if ( (*attrName != "xml:lang") && (*attrName != "rdf:ID") ) break;
+ }
+
+ if ( currAttr != endAttr ) {
+
+ XMP_Assert ( attrName != 0 );
+ XMP_VarString& attrValue = (*currAttr)->value;
+
+ if ( *attrName == "rdf:datatype" ) {
+ this->LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( *attrName != "rdf:parseType" ) {
+ this->EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( attrValue == "Literal" ) {
+ this->ParseTypeLiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( attrValue == "Resource" ) {
+ this->ParseTypeResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else if ( attrValue == "Collection" ) {
+ this->ParseTypeCollectionPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else {
+ this->ParseTypeOtherPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ }
+
+ } else {
+
+ // Only rdf:ID and xml:lang, could be a resourcePropertyElt, a literalPropertyElt, or an.
+ // emptyPropertyElt. Look at the child XML nodes to decide which.
+
+ if ( xmlNode.content.empty() ) {
+
+ this->EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
+
+ } else {
+
+ XML_cNodePos currChild = xmlNode.content.begin();
+ XML_cNodePos endChild = xmlNode.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( (*currChild)->kind != kCDataNode ) break;
+ }
+
+ if ( currChild == endChild ) {
+ this->LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
+ } else {
+ this->ResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
+ }
+
+ }
+
+ }
+
+ }
+
+} // RDF_Parser::PropertyElement
+
+// =================================================================================================
+// RDF_Parser::ResourcePropertyElement
+// ===================================
+//
+// 7.2.15 resourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
+// ws* nodeElement ws*
+// end-element()
+//
+// This handles structs using an rdf:Description node, arrays using rdf:Bag/Seq/Alt, and Typed Nodes.
+// It also catches and cleans up qualified properties written with rdf:Description and rdf:value.
+
+void RDF_Parser::ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ if ( isTopLevel && (xmlNode.name == "iX:changes") ) return; // Strip old "punchcard" chaff.
+
+ XMP_Node * newCompound = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+ if ( newCompound == 0 ) return; // Ignore lower level errors.
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ XMP_VarString & attrName = (*currAttr)->name;
+ if ( attrName == "xml:lang" ) {
+ this->AddQualifierNode ( newCompound, **currAttr );
+ } else if ( attrName == "rdf:ID" ) {
+ continue; // Ignore all rdf:ID attributes.
+ } else {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid attribute for resource property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ continue;
+ }
+ }
+
+ XML_cNodePos currChild = xmlNode.content.begin();
+ XML_cNodePos endChild = xmlNode.content.end();
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( ! (*currChild)->IsWhitespaceNode() ) break;
+ }
+ if ( currChild == endChild ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Missing child of resource property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ if ( (*currChild)->kind != kElemNode ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Children of resource property element must be XML elements" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ if ( (*currChild)->name == "rdf:Bag" ) {
+ newCompound->options |= kXMP_PropValueIsArray;
+ } else if ( (*currChild)->name == "rdf:Seq" ) {
+ newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered;
+ } else if ( (*currChild)->name == "rdf:Alt" ) {
+ newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate;
+ } else {
+ // This is the Typed Node case. Add an rdf:type qualifier with a URI value.
+ if ( (*currChild)->name != "rdf:Description" ) {
+ XMP_VarString typeName ( (*currChild)->ns );
+ size_t colonPos = (*currChild)->name.find_first_of(':');
+ if ( colonPos == XMP_VarString::npos ) {
+ XMP_Error error ( kXMPErr_BadXMP, "All XML elements must be in a namespace" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ typeName.append ( (*currChild)->name, colonPos+1, XMP_VarString::npos ); // Append just the local name.
+ XMP_Node * typeQual = this->AddQualifierNode ( newCompound, XMP_VarString("rdf:type"), typeName );
+ if ( typeQual != 0 ) typeQual->options |= kXMP_PropValueIsURI;
+ }
+ newCompound->options |= kXMP_PropValueIsStruct;
+ }
+
+ this->NodeElement ( newCompound, **currChild, kNotTopLevel );
+ if ( newCompound->options & kRDF_HasValueElem ) {
+ this->FixupQualifiedNode ( newCompound );
+ } else if ( newCompound->options & kXMP_PropArrayIsAlternate ) {
+ DetectAltText ( newCompound );
+ }
+
+ for ( ++currChild; currChild != endChild; ++currChild ) {
+ if ( ! (*currChild)->IsWhitespaceNode() ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid child of resource property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ break; // Don't bother looking for more trailing errors.
+ }
+ }
+
+} // RDF_Parser::ResourcePropertyElement
+
+// =================================================================================================
+// RDF_Parser::LiteralPropertyElement
+// ==================================
+//
+// 7.2.16 literalPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
+// text()
+// end-element()
+//
+// Add a leaf node with the text value and qualifiers for the attributes.
+
+void RDF_Parser::LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ XMP_Node * newChild = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+ if ( newChild == 0 ) return; // Ignore lower level errors.
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ XMP_VarString & attrName = (*currAttr)->name;
+ if ( attrName == "xml:lang" ) {
+ this->AddQualifierNode ( newChild, **currAttr );
+ } else if ( (attrName == "rdf:ID") || (attrName == "rdf:datatype") ) {
+ continue; // Ignore all rdf:ID and rdf:datatype attributes.
+ } else {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid attribute for literal property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ continue;
+ }
+ }
+
+ XML_cNodePos currChild = xmlNode.content.begin();
+ XML_cNodePos endChild = xmlNode.content.end();
+ size_t textSize = 0;
+
+ for ( ; currChild != endChild; ++currChild ) {
+ if ( (*currChild)->kind == kCDataNode ) {
+ textSize += (*currChild)->value.size();
+ } else {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid child of literal property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+ }
+
+ newChild->value.reserve ( textSize );
+
+ for ( currChild = xmlNode.content.begin(); currChild != endChild; ++currChild ) {
+ newChild->value += (*currChild)->value;
+ }
+
+} // RDF_Parser::LiteralPropertyElement
+
+// =================================================================================================
+// RDF_Parser::ParseTypeLiteralPropertyElement
+// ===========================================
+//
+// 7.2.17 parseTypeLiteralPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
+// literal
+// end-element()
+
+void RDF_Parser::ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
+ XMP_Error error ( kXMPErr_BadXMP, "ParseTypeLiteral property element not allowed" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+
+} // RDF_Parser::ParseTypeLiteralPropertyElement
+
+// =================================================================================================
+// RDF_Parser::ParseTypeResourcePropertyElement
+// ============================================
+//
+// 7.2.18 parseTypeResourcePropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
+// propertyEltList
+// end-element()
+//
+// Add a new struct node with a qualifier for the possible rdf:ID attribute. Then process the XML
+// child nodes to get the struct fields.
+
+void RDF_Parser::ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ XMP_Node * newStruct = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+ if ( newStruct == 0 ) return; // Ignore lower level errors.
+ newStruct->options |= kXMP_PropValueIsStruct;
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+ XMP_VarString & attrName = (*currAttr)->name;
+ if ( attrName == "rdf:parseType" ) {
+ continue; // ! The caller ensured the value is "Resource".
+ } else if ( attrName == "xml:lang" ) {
+ this->AddQualifierNode ( newStruct, **currAttr );
+ } else if ( attrName == "rdf:ID" ) {
+ continue; // Ignore all rdf:ID attributes.
+ } else {
+ XMP_Error error ( kXMPErr_BadRDF, "Invalid attribute for ParseTypeResource property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ continue;
+ }
+ }
+
+ this->PropertyElementList ( newStruct, xmlNode, kNotTopLevel );
+
+ if ( newStruct->options & kRDF_HasValueElem ) this->FixupQualifiedNode ( newStruct );
+
+ // *** Need to look for arrays using rdf:Description and rdf:type.
+
+} // RDF_Parser::ParseTypeResourcePropertyElement
+
+// =================================================================================================
+// RDF_Parser::ParseTypeCollectionPropertyElement
+// ==============================================
+//
+// 7.2.19 parseTypeCollectionPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
+// nodeElementList
+// end-element()
+
+void RDF_Parser::ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
+ XMP_Error error ( kXMPErr_BadXMP, "ParseTypeCollection property element not allowed" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+
+} // RDF_Parser::ParseTypeCollectionPropertyElement
+
+// =================================================================================================
+// RDF_Parser::ParseTypeOtherPropertyElement
+// =========================================
+//
+// 7.2.20 parseTypeOtherPropertyElt
+// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
+// propertyEltList
+// end-element()
+
+void RDF_Parser::ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
+ XMP_Error error ( kXMPErr_BadXMP, "ParseTypeOther property element not allowed" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+
+} // RDF_Parser::ParseTypeOtherPropertyElement
+
+// =================================================================================================
+// RDF_Parser::EmptyPropertyElement
+// ================================
+//
+// 7.2.21 emptyPropertyElt
+// start-element ( URI == propertyElementURIs,
+// attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
+// end-element()
+//
+// <ns:Prop1/> <!-- a simple property with an empty value -->
+// <ns:Prop2 rdf:resource="http://www.adobe.com/"/> <!-- a URI value -->
+// <ns:Prop3 rdf:value="..." ns:Qual="..."/> <!-- a simple qualified property -->
+// <ns:Prop4 ns:Field1="..." ns:Field2="..."/> <!-- a struct with simple fields -->
+//
+// An emptyPropertyElt is an element with no contained content, just a possibly empty set of
+// attributes. An emptyPropertyElt can represent three special cases of simple XMP properties: a
+// simple property with an empty value (ns:Prop1), a simple property whose value is a URI
+// (ns:Prop2), or a simple property with simple qualifiers (ns:Prop3). An emptyPropertyElt can also
+// represent an XMP struct whose fields are all simple and unqualified (ns:Prop4).
+//
+// It is an error to use both rdf:value and rdf:resource - that can lead to invalid RDF in the
+// verbose form written using a literalPropertyElt.
+//
+// The XMP mapping for an emptyPropertyElt is a bit different from generic RDF, partly for
+// design reasons and partly for historical reasons. The XMP mapping rules are:
+// 1. If there is an rdf:value attribute then this is a simple property with a text value.
+// All other attributes are qualifiers.
+// 2. If there is an rdf:resource attribute then this is a simple property with a URI value.
+// All other attributes are qualifiers.
+// 3. If there are no attributes other than xml:lang, rdf:ID, or rdf:nodeID then this is a simple
+// property with an empty value.
+// 4. Otherwise this is a struct, the attributes other than xml:lang, rdf:ID, or rdf:nodeID are fields.
+
+void RDF_Parser::EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
+{
+ bool hasPropertyAttrs = false;
+ bool hasResourceAttr = false;
+ bool hasNodeIDAttr = false;
+ bool hasValueAttr = false;
+
+ const XML_Node * valueNode = 0; // ! Can come from rdf:value or rdf:resource.
+
+ if ( ! xmlNode.content.empty() ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Nested content not allowed with rdf:resource or property attributes" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+
+ // First figure out what XMP this maps to and remember the XML node for a simple value.
+
+ XML_cNodePos currAttr = xmlNode.attrs.begin();
+ XML_cNodePos endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+
+ RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
+
+ switch ( attrTerm ) {
+
+ case kRDFTerm_ID :
+ // Nothing to do.
+ break;
+
+ case kRDFTerm_resource :
+ if ( hasNodeIDAttr ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Empty property element can't have both rdf:resource and rdf:nodeID" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ if ( hasValueAttr ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Empty property element can't have both rdf:value and rdf:resource" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ hasResourceAttr = true;
+ if ( ! hasValueAttr ) valueNode = *currAttr;
+ break;
+
+ case kRDFTerm_nodeID :
+ if ( hasResourceAttr ) {
+ XMP_Error error ( kXMPErr_BadRDF, "Empty property element can't have both rdf:resource and rdf:nodeID" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ hasNodeIDAttr = true;
+ break;
+
+ case kRDFTerm_Other :
+ if ( (*currAttr)->name == "rdf:value" ) {
+ if ( hasResourceAttr ) {
+ XMP_Error error ( kXMPErr_BadXMP, "Empty property element can't have both rdf:value and rdf:resource" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ return;
+ }
+ hasValueAttr = true;
+ valueNode = *currAttr;
+ } else if ( (*currAttr)->name != "xml:lang" ) {
+ hasPropertyAttrs = true;
+ }
+ break;
+
+ default :
+ {
+ XMP_Error error ( kXMPErr_BadRDF, "Unrecognized attribute of empty property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+
+ return;
+
+ }
+
+ }
+
+ // Create the right kind of child node and visit the attributes again to add the fields or qualifiers.
+ // ! Because of implementation vagaries, the xmpParent is the tree root for top level properties.
+ // ! The schema is found, created if necessary, by AddChildNode.
+
+ XMP_Node * childNode = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
+ if ( childNode == 0 ) return; // Ignore lower level errors.
+ bool childIsStruct = false;
+
+ if ( hasValueAttr | hasResourceAttr ) {
+ childNode->value = valueNode->value;
+ if ( ! hasValueAttr ) childNode->options |= kXMP_PropValueIsURI; // ! Might have both rdf:value and rdf:resource.
+ } else if ( hasPropertyAttrs ) {
+ childNode->options |= kXMP_PropValueIsStruct;
+ childIsStruct = true;
+ }
+
+ currAttr = xmlNode.attrs.begin();
+ endAttr = xmlNode.attrs.end();
+
+ for ( ; currAttr != endAttr; ++currAttr ) {
+
+ if ( *currAttr == valueNode ) continue; // Skip the rdf:value or rdf:resource attribute holding the value.
+ RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
+
+ switch ( attrTerm ) {
+
+ case kRDFTerm_ID :
+ case kRDFTerm_nodeID :
+ break; // Ignore all rdf:ID and rdf:nodeID attributes.
+
+ case kRDFTerm_resource :
+ this->AddQualifierNode ( childNode, **currAttr );
+ break;
+
+ case kRDFTerm_Other :
+ if ( (! childIsStruct) || (*currAttr)->name == "xml:lang" ) {
+ this->AddQualifierNode ( childNode, **currAttr );
+ } else {
+ this->AddChildNode ( childNode, **currAttr, (*currAttr)->value.c_str(), false );
+ }
+ break;
+
+ default :
+ {
+ XMP_Error error ( kXMPErr_BadRDF, "Unrecognized attribute of empty property element" );
+ this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
+ }
+ continue;
+
+ }
+
+ }
+
+} // RDF_Parser::EmptyPropertyElement
+
+// =================================================================================================
+// XMPMeta::ProcessRDF
+// ===================
+//
+// Parse the XML tree of the RDF and build the corresponding XMP tree.
+
+void XMPMeta::ProcessRDF ( const XML_Node & rdfNode, XMP_OptionBits options )
+{
+ IgnoreParam(options);
+
+ RDF_Parser parser ( &this->errorCallback );
+
+ parser.RDF ( &this->tree, rdfNode );
+
+} // XMPMeta::ProcessRDF
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/UnicodeConversions.cpp b/gpr/source/lib/xmp_core/UnicodeConversions.cpp
new file mode 100644
index 0000000..f9863cd
--- /dev/null
+++ b/gpr/source/lib/xmp_core/UnicodeConversions.cpp
@@ -0,0 +1,1654 @@
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Const.h"
+
+#define UC_Assert(cond) /* Nothing for now, should be XMP_Assert. */
+#define UC_Throw(msg,id) throw XMP_Error ( id, msg )
+
+#include "UnicodeConversions.hpp"
+
+#if SUNOS_SPARC || XMP_IOS_ARM
+ #include "string.h"
+#endif
+
+using namespace std;
+
+// =================================================================================================
+
+// *** Look into using asm inlines, e.g. count-leading bits for multi-byte UTF-8.
+
+CodePoint_to_UTF16_Proc CodePoint_to_UTF16BE = 0;
+CodePoint_to_UTF16_Proc CodePoint_to_UTF16LE = 0;
+
+CodePoint_from_UTF16_Proc CodePoint_from_UTF16BE = 0;
+CodePoint_from_UTF16_Proc CodePoint_from_UTF16LE = 0;
+
+UTF8_to_UTF16_Proc UTF8_to_UTF16BE = 0;
+UTF8_to_UTF16_Proc UTF8_to_UTF16LE = 0;
+UTF8_to_UTF32_Proc UTF8_to_UTF32BE = 0;
+UTF8_to_UTF32_Proc UTF8_to_UTF32LE = 0;
+
+UTF16_to_UTF8_Proc UTF16BE_to_UTF8 = 0;
+UTF16_to_UTF8_Proc UTF16LE_to_UTF8 = 0;
+UTF32_to_UTF8_Proc UTF32BE_to_UTF8 = 0;
+UTF32_to_UTF8_Proc UTF32LE_to_UTF8 = 0;
+
+UTF8_to_UTF16_Proc UTF8_to_UTF16Native = 0;
+UTF8_to_UTF32_Proc UTF8_to_UTF32Native = 0;
+UTF16_to_UTF8_Proc UTF16Native_to_UTF8 = 0;
+UTF32_to_UTF8_Proc UTF32Native_to_UTF8 = 0;
+
+UTF16_to_UTF32_Proc UTF16BE_to_UTF32BE = 0;
+UTF16_to_UTF32_Proc UTF16BE_to_UTF32LE = 0;
+UTF16_to_UTF32_Proc UTF16LE_to_UTF32BE = 0;
+UTF16_to_UTF32_Proc UTF16LE_to_UTF32LE = 0;
+
+UTF32_to_UTF16_Proc UTF32BE_to_UTF16BE = 0;
+UTF32_to_UTF16_Proc UTF32BE_to_UTF16LE = 0;
+UTF32_to_UTF16_Proc UTF32LE_to_UTF16BE = 0;
+UTF32_to_UTF16_Proc UTF32LE_to_UTF16LE = 0;
+
+// -------------------------------------------------------------------------------------------------
+
+static size_t swap32to16Offset = 0; // Offset to "convert" a swapped UTF32 pointer into a swapped UTF16 pointer.
+
+// -------------------------------------------------------------------------------------------------
+
+static void CodePoint_to_UTF16Nat ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written );
+static void CodePoint_to_UTF16Swp ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written );
+
+static void CodePoint_from_UTF16Nat ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read );
+static void CodePoint_from_UTF16Swp ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF8_to_UTF16Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written );
+
+static void UTF8_to_UTF16Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written );
+
+static void UTF8_to_UTF32Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written );
+
+static void UTF8_to_UTF32Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF16Nat_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written );
+
+static void UTF16Swp_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written );
+
+static void UTF32Nat_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written );
+
+static void UTF32Swp_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF16Nat_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+static void UTF16Nat_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+static void UTF16Swp_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+static void UTF16Swp_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+// -------------------------------------------------------------------------------------------------
+
+static void UTF32Nat_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+static void UTF32Nat_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+static void UTF32Swp_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+static void UTF32Swp_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+// =================================================================================================
+
+void InitializeUnicodeConversions()
+{
+ UC_Assert ( (sizeof(UTF8Unit) == 1) && (sizeof(UTF16Unit) == 2) && (sizeof(UTF32Unit) == 4) );
+
+ UTF16Unit u16 = 0x00FF;
+ bool bigEndian = (*((UTF8Unit*)&u16) == 0);
+
+ UTF8_to_UTF16Native = UTF8_to_UTF16Nat;
+ UTF8_to_UTF32Native = UTF8_to_UTF32Nat;
+ UTF16Native_to_UTF8 = UTF16Nat_to_UTF8;
+ UTF32Native_to_UTF8 = UTF32Nat_to_UTF8;
+
+ if ( bigEndian ) {
+
+ swap32to16Offset = 0;
+
+ CodePoint_to_UTF16BE = CodePoint_to_UTF16Nat;
+ CodePoint_to_UTF16LE = CodePoint_to_UTF16Swp;
+
+ CodePoint_from_UTF16BE = CodePoint_from_UTF16Nat;
+ CodePoint_from_UTF16LE = CodePoint_from_UTF16Swp;
+
+ UTF8_to_UTF16BE = UTF8_to_UTF16Nat;
+ UTF8_to_UTF16LE = UTF8_to_UTF16Swp;
+ UTF8_to_UTF32BE = UTF8_to_UTF32Nat;
+ UTF8_to_UTF32LE = UTF8_to_UTF32Swp;
+
+ UTF16BE_to_UTF8 = UTF16Nat_to_UTF8;
+ UTF16LE_to_UTF8 = UTF16Swp_to_UTF8;
+ UTF32BE_to_UTF8 = UTF32Nat_to_UTF8;
+ UTF32LE_to_UTF8 = UTF32Swp_to_UTF8;
+
+ UTF16BE_to_UTF32BE = UTF16Nat_to_UTF32Nat;
+ UTF16BE_to_UTF32LE = UTF16Nat_to_UTF32Swp;
+ UTF16LE_to_UTF32BE = UTF16Swp_to_UTF32Nat;
+ UTF16LE_to_UTF32LE = UTF16Swp_to_UTF32Swp;
+
+ UTF32BE_to_UTF16BE = UTF32Nat_to_UTF16Nat;
+ UTF32BE_to_UTF16LE = UTF32Nat_to_UTF16Swp;
+ UTF32LE_to_UTF16BE = UTF32Swp_to_UTF16Nat;
+ UTF32LE_to_UTF16LE = UTF32Swp_to_UTF16Swp;
+
+ } else {
+
+ swap32to16Offset = 1; // ! Offset in UTF16 units!
+
+ CodePoint_to_UTF16BE = CodePoint_to_UTF16Swp;
+ CodePoint_to_UTF16LE = CodePoint_to_UTF16Nat;
+
+ CodePoint_from_UTF16BE = CodePoint_from_UTF16Swp;
+ CodePoint_from_UTF16LE = CodePoint_from_UTF16Nat;
+
+ UTF8_to_UTF16BE = UTF8_to_UTF16Swp;
+ UTF8_to_UTF16LE = UTF8_to_UTF16Nat;
+ UTF8_to_UTF32BE = UTF8_to_UTF32Swp;
+ UTF8_to_UTF32LE = UTF8_to_UTF32Nat;
+
+ UTF16BE_to_UTF8 = UTF16Swp_to_UTF8;
+ UTF16LE_to_UTF8 = UTF16Nat_to_UTF8;
+ UTF32BE_to_UTF8 = UTF32Swp_to_UTF8;
+ UTF32LE_to_UTF8 = UTF32Nat_to_UTF8;
+
+ UTF16BE_to_UTF32BE = UTF16Swp_to_UTF32Swp;
+ UTF16BE_to_UTF32LE = UTF16Swp_to_UTF32Nat;
+ UTF16LE_to_UTF32BE = UTF16Nat_to_UTF32Swp;
+ UTF16LE_to_UTF32LE = UTF16Nat_to_UTF32Nat;
+
+ UTF32BE_to_UTF16BE = UTF32Swp_to_UTF16Swp;
+ UTF32BE_to_UTF16LE = UTF32Swp_to_UTF16Nat;
+ UTF32LE_to_UTF16BE = UTF32Nat_to_UTF16Swp;
+ UTF32LE_to_UTF16LE = UTF32Nat_to_UTF16Nat;
+
+ }
+
+} // InitializeUnicodeConversions
+
+// =================================================================================================
+
+#if SUNOS_SPARC || XMP_IOS_ARM
+ #define DefineAndGetValue(type,inPtr) type inUnit; memcpy ( &inUnit, inPtr, sizeof(type) );
+#else
+ #define DefineAndGetValue(type,inPtr) type inUnit = *((type *)inPtr);
+#endif
+
+static inline UTF16Unit UTF16InSwap ( const void * inPtr )
+{
+ DefineAndGetValue ( UTF16Unit, inPtr );
+ return (inUnit << 8) | (inUnit >> 8);
+}
+static inline UTF32Unit UTF32InSwap ( const void * inPtr )
+{
+ DefineAndGetValue ( UTF32Unit, inPtr );
+ return (inUnit << 24) | ((inUnit << 8) & 0x00FF0000) | ((inUnit >> 8) & 0x0000FF00) | (inUnit >> 24);
+}
+
+static inline void UTF16OutSwap ( UTF16Unit * outPtr, const UTF16Unit value )
+{
+ UTF16Unit outUnit = (value << 8) | (value >> 8);
+ *outPtr = outUnit;
+}
+
+static inline void UTF32OutSwap ( UTF32Unit * outPtr, const UTF32Unit value )
+{
+ UTF32Unit outUnit = (value << 24) | ((value << 8) & 0x00FF0000) | ((value >> 8) & 0x0000FF00) | (value >> 24);
+ *outPtr = outUnit;
+}
+
+// =================================================================================================
+
+void SwapUTF16 ( const UTF16Unit * utf16In, UTF16Unit * utf16Out, const size_t utf16Len )
+{
+ for ( size_t i = 0; i < utf16Len; ++i ) utf16Out[i] = UTF16InSwap(utf16In+i);
+}
+
+void SwapUTF32 ( const UTF32Unit * utf32In, UTF32Unit * utf32Out, const size_t utf32Len ) {
+ for ( size_t i = 0; i < utf32Len; ++i ) utf32Out[i] = UTF32InSwap(utf32In+i);
+}
+
+// =================================================================================================
+
+extern void ToUTF16 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str, bool bigEndian )
+{
+ UTF8_to_UTF16_Proc Converter = UTF8_to_UTF16LE;
+ if ( bigEndian ) Converter = UTF8_to_UTF16BE;
+
+ enum { kBufferSize = 8*1024 };
+ UTF16Unit u16Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf16Str->erase();
+ utf16Str->reserve ( 2*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ Converter ( utf8In, utf8Len, u16Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf16Str->append ( (const char *)u16Buffer, writeCount*2 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF16
+
+// =================================================================================================
+
+extern void ToUTF16Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str )
+{
+ enum { kBufferSize = 8*1024 };
+ UTF16Unit u16Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf16Str->erase();
+ utf16Str->reserve ( 2*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ UTF8_to_UTF16Nat ( utf8In, utf8Len, u16Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf16Str->append ( (const char *)u16Buffer, writeCount*2 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF16Native
+
+// =================================================================================================
+
+extern void ToUTF32 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str, bool bigEndian )
+{
+ UTF8_to_UTF32_Proc Converter = UTF8_to_UTF32LE;
+ if ( bigEndian ) Converter = UTF8_to_UTF32BE;
+
+ enum { kBufferSize = 4*1024 };
+ UTF32Unit u32Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf32Str->erase();
+ utf32Str->reserve ( 4*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ Converter ( utf8In, utf8Len, u32Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf32Str->append ( (const char *)u32Buffer, writeCount*4 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF32
+
+// =================================================================================================
+
+extern void ToUTF32Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str )
+{
+ enum { kBufferSize = 4*1024 };
+ UTF32Unit u32Buffer[kBufferSize]; // 16K bytes
+ size_t readCount, writeCount;
+
+ utf32Str->erase();
+ utf32Str->reserve ( 4*utf8Len ); // As good a guess as any.
+
+ while ( utf8Len > 0 ) {
+ UTF8_to_UTF32Nat ( utf8In, utf8Len, u32Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf32Str->append ( (const char *)u32Buffer, writeCount*4 );
+ utf8In += readCount;
+ utf8Len -= readCount;
+ }
+
+} // ToUTF32Native
+
+// =================================================================================================
+
+extern void FromUTF16 ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str, bool bigEndian )
+{
+ UTF16_to_UTF8_Proc Converter = UTF16LE_to_UTF8;
+ if ( bigEndian ) Converter = UTF16BE_to_UTF8;
+
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf16Len ); // As good a guess as any.
+
+ while ( utf16Len > 0 ) {
+ Converter ( utf16In, utf16Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf16In += readCount;
+ utf16Len -= readCount;
+ }
+
+} // FromUTF16
+
+// =================================================================================================
+
+extern void FromUTF16Native ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str )
+{
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf16Len ); // As good a guess as any.
+
+ while ( utf16Len > 0 ) {
+ UTF16Nat_to_UTF8 ( utf16In, utf16Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf16In += readCount;
+ utf16Len -= readCount;
+ }
+
+} // FromUTF16Native
+
+// =================================================================================================
+
+extern void FromUTF32 ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str, bool bigEndian )
+{
+ UTF32_to_UTF8_Proc Converter = UTF32LE_to_UTF8;
+ if ( bigEndian ) Converter = UTF32BE_to_UTF8;
+
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf32Len ); // As good a guess as any.
+
+ while ( utf32Len > 0 ) {
+ Converter ( utf32In, utf32Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf32In += readCount;
+ utf32Len -= readCount;
+ }
+
+} // FromUTF32
+
+// =================================================================================================
+
+extern void FromUTF32Native ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str )
+{
+ enum { kBufferSize = 16*1024 };
+ UTF8Unit u8Buffer[kBufferSize];
+ size_t readCount, writeCount;
+
+ utf8Str->erase();
+ utf8Str->reserve ( 2*utf32Len ); // As good a guess as any.
+
+ while ( utf32Len > 0 ) {
+ UTF32Nat_to_UTF8 ( utf32In, utf32Len, u8Buffer, kBufferSize, &readCount, &writeCount );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadXML );
+ utf8Str->append ( (const char *)u8Buffer, writeCount );
+ utf32In += readCount;
+ utf32Len -= readCount;
+ }
+
+} // FromUTF32Native
+
+// =================================================================================================
+
+static void CodePoint_to_UTF8_Multi ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written )
+{
+ size_t unitCount = 0;
+
+ if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam );
+ if ( (0xD800 <= cpIn) && (cpIn <= 0xDFFF) ) UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam );
+
+ // Compute the number of bytes using 6 data bits each. Then see if the highest order bits will
+ // fit into the leading byte. Write the UTF-8 sequence if there is enough room.
+
+ UTF32Unit temp, mask;
+ size_t bytesNeeded = 0;
+ for ( temp = cpIn; temp != 0; temp = temp >> 6 ) ++bytesNeeded;
+
+ temp = cpIn >> ((bytesNeeded-1)*6); // The highest order data bits.
+ mask = (0x80 >> bytesNeeded) - 1; // Available data bits in the leading byte.
+ if ( temp > mask ) ++bytesNeeded;
+
+ if ( bytesNeeded > utf8Len ) goto Done; // Not enough room for the output.
+ unitCount = bytesNeeded;
+
+ temp = cpIn;
+ for ( --bytesNeeded; bytesNeeded > 0; --bytesNeeded ) {
+ utf8Out[bytesNeeded] = 0x80 | UTF8Unit ( temp & 0x3F );
+ temp = temp >> 6;
+ }
+
+ mask = ~((1 << (8-unitCount)) - 1);
+ utf8Out[0] = UTF8Unit ( mask | temp );
+
+Done:
+ *utf8Written = unitCount;
+ return;
+
+} // CodePoint_to_UTF8_Multi
+
+// =================================================================================================
+
+void CodePoint_to_UTF8 ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written )
+{
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf8Out != 0) && (utf8Written != 0) );
+ if ( utf8Len == 0 ) goto Done;
+ if ( cpIn > 0x7F ) goto MultiByte; // ! Force linear execution path for ASCII.
+
+ unitCount = 1;
+ *utf8Out = UTF8Unit(cpIn);
+
+Done:
+ *utf8Written = unitCount;
+ return;
+
+MultiByte:
+ CodePoint_to_UTF8_Multi( cpIn, utf8Out, utf8Len, utf8Written );
+ return;
+
+} // CodePoint_to_UTF8
+
+// =================================================================================================
+
+static void CodePoint_from_UTF8_Multi ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read )
+{
+ UTF8Unit inUnit = *utf8In;
+ size_t unitCount = 0;
+ UTF32Unit cp; // ! Avoid gcc complaints about declarations after goto's.
+ const UTF8Unit * utf8Pos;
+
+ // -------------------------------------------------------------------------------------
+ // We've got a multibyte UTF-8 character. The first byte has the number of bytes and the
+ // highest order data bits. The other bytes each add 6 more data bits.
+
+ #if 0 // This might be a more effcient way to count the bytes.
+ static XMP_Uns8 kByteCounts[16] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 3, 4 };
+ size_t bytesNeeded = kByteCounts [ inUnit >> 4 ];
+ if ( (bytesNeeded < 2) || ((bytesNeeded == 4) && ((inUnit & 0x08) != 0)) ) {
+ UC_Throw ( "Invalid UTF-8 sequence length", kXMPErr_BadParam );
+ }
+ #endif
+
+ size_t bytesNeeded = 0; // Count the leading 1 bits in the first byte.
+ for ( UTF8Unit temp = inUnit; temp > 0x7F; temp = temp << 1 ) ++bytesNeeded;
+ // *** Consider CPU-specific assembly inline, e.g. cntlzw on PowerPC.
+
+ if ( (bytesNeeded < 2) || (bytesNeeded > 4) ) UC_Throw ( "Invalid UTF-8 sequence length", kXMPErr_BadParam );
+ if ( bytesNeeded > utf8Len ) goto Done; // Not enough input in this buffer.
+ unitCount = bytesNeeded;
+
+ cp = inUnit & ((1 << (7-unitCount)) - 1); // Isolate the initial data bits in the bottom of cp.
+
+ utf8Pos = utf8In + 1; // We've absorbed the first byte.
+ for ( --bytesNeeded; bytesNeeded > 0; --bytesNeeded, ++utf8Pos ) {
+ inUnit = *utf8Pos;
+ if ( (inUnit & UTF8Unit(0xC0)) != UTF8Unit(0x80) ) UC_Throw ( "Invalid UTF-8 data byte", kXMPErr_BadParam );
+ cp = (cp << 6) | (inUnit & 0x3F);
+ }
+
+ if ( cp >= 0xD800 ) { // Skip the next comparisons most of the time.
+ if ( (0xD800 <= cp) && (cp <= 0xDFFF) ) UC_Throw ( "Bad UTF-8 - surrogate code point", kXMPErr_BadParam );
+ if ( cp > 0x10FFFF ) UC_Throw ( "Bad UTF-8 - out of range", kXMPErr_BadParam );
+ }
+
+ *cpOut = cp; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf8Read = unitCount;
+ return;
+
+} // CodePoint_from_UTF8_Multi
+
+// =================================================================================================
+
+void CodePoint_from_UTF8 ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read )
+{
+ UTF8Unit inUnit; // ! Don't read until we know there is input.
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf8In != 0) && (cpOut != 0) && (utf8Read != 0) );
+ if ( utf8Len == 0 ) goto Done;
+ inUnit = *utf8In;
+ if ( inUnit >= 0x80 ) goto MultiByte; // ! Force linear execution path for ASCII.
+
+ unitCount = 1;
+ *cpOut = inUnit; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf8Read = unitCount;
+ return;
+
+MultiByte:
+ CodePoint_from_UTF8_Multi ( utf8In, utf8Len, cpOut, utf8Read );
+ return;
+
+} // CodePoint_from_UTF8
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Nat_Surrogate ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+ UTF32Unit temp; // ! Avoid gcc complaints about declarations after goto's.
+
+ if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough room for the output.
+
+ unitCount = 2;
+ temp = cpIn - 0x10000;
+ utf16Out[0] = 0xD800 | UTF16Unit ( temp >> 10 );
+ utf16Out[1] = 0xDC00 | UTF16Unit ( temp & 0x3FF );
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+} // CodePoint_to_UTF16Nat_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Nat ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16Out != 0) && (utf16Written != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP.
+
+InBMP:
+ unitCount = 1;
+ *utf16Out = UTF16Unit(cpIn);
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+CheckSurrogate:
+ if ( cpIn > 0xFFFF ) goto SurrogatePair;
+ if ( cpIn > 0xDFFF ) goto InBMP;
+ UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam );
+
+SurrogatePair:
+ CodePoint_to_UTF16Nat_Surrogate ( cpIn, utf16Out, utf16Len, utf16Written );
+ return;
+
+} // CodePoint_to_UTF16Nat
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Nat_Surrogate ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit hiUnit = *utf16In;
+ size_t unitCount = 0;
+ UTF16Unit loUnit; // ! Avoid gcc complaints about declarations after goto's.
+ UTF32Unit cp;
+
+ // ----------------------------------
+ // We've got a UTF-16 surrogate pair.
+
+ if ( hiUnit > 0xDBFF ) UC_Throw ( "Bad UTF-16 - leading low surrogate", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough input in this buffer.
+
+ loUnit = *(utf16In+1);
+ if ( (loUnit < 0xDC00) || (0xDFFF < loUnit) ) UC_Throw ( "Bad UTF-16 - missing low surrogate", kXMPErr_BadParam );
+
+ unitCount = 2;
+ cp = (((hiUnit & 0x3FF) << 10) | (loUnit & 0x3FF)) + 0x10000;
+
+ *cpOut = cp; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+} // CodePoint_from_UTF16Nat_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Nat ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit inUnit; // ! Don't read until we know there is input.
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16In != 0) && (cpOut != 0) && (utf16Read != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ inUnit = *utf16In;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) goto SurrogatePair; // ! Force linear execution path for the BMP.
+
+ unitCount = 1;
+ *cpOut = inUnit; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+SurrogatePair:
+ CodePoint_from_UTF16Nat_Surrogate ( utf16In, utf16Len, cpOut, utf16Read );
+ return;
+
+} // CodePoint_from_UTF16Nat
+
+// =================================================================================================
+
+static void UTF8_to_UTF16Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf8In != 0) && (utf16Out != 0) && (utf8Read != 0) && (utf16Written != 0) );
+
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf16Pos = inUnit;
+ ++utf8Pos;
+ ++utf16Pos;
+ }
+ utf8Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-ASCII, it copies multiple input units into 1 or 2 output units.
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+ UTF32Unit cp;
+ size_t len8, len16;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len8 );
+ if ( len8 == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ if ( cp <= 0xFFFF ) {
+ *utf16Pos = UTF16Unit(cp);
+ len16 = 1;
+ } else {
+ CodePoint_to_UTF16Nat_Surrogate ( cp, utf16Pos, utf16Left, &len16 );
+ if ( len16 == 0 ) goto Done; // Not enough room in the output buffer.
+ }
+ utf8Left -= len8;
+ utf8Pos += len8;
+ utf16Left -= len16;
+ utf16Pos += len16;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF8_to_UTF16Nat
+
+// =================================================================================================
+
+static void UTF8_to_UTF32Nat ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf8In != 0) && (utf32Out != 0) && (utf8Read != 0) && (utf32Written != 0) );
+
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf32Pos = inUnit;
+ ++utf8Pos;
+ ++utf32Pos;
+ }
+ utf8Left -= i;
+ utf32Left -= i;
+
+ // Do a run of non-ASCII, it copies variable input into 1 output unit.
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, utf32Pos, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ utf8Left -= len;
+ utf8Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF8_to_UTF32Nat
+
+// =================================================================================================
+
+static void UTF16Nat_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf16In != 0) && (utf8Out != 0) && (utf16Read != 0) && (utf8Written != 0) );
+
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = *utf16Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf8Pos = UTF8Unit(inUnit);
+ ++utf16Pos;
+ ++utf8Pos;
+ }
+ utf16Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII inside the BMP, it copies 1 input unit into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ size_t len8;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( inUnit <= 0x7F ) break;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= 1;
+ utf16Pos += 1;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ // Do a run of surrogate pairs, it copies 2 input units into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ UTF32Unit cp;
+ size_t len16, len8;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, &cp, &len16 );
+ if ( len16 == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len16 == 2 );
+ CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= len16;
+ utf16Pos += len16;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF16Nat_to_UTF8
+
+// =================================================================================================
+
+static void UTF32Nat_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf32In != 0) && (utf8Out != 0) && (utf32Read != 0) && (utf8Written != 0) );
+
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf8Pos = UTF8Unit(inUnit);
+ ++utf32Pos;
+ ++utf8Pos;
+ }
+ utf32Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII, it copies 1 input unit into multiple output units.
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf8Left -= len;
+ utf8Pos += len;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF32Nat_to_UTF8
+
+// =================================================================================================
+
+static void UTF16Nat_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ *utf32Pos = inUnit;
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, utf32Pos, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len == 2 );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Nat_to_UTF32Nat
+
+// =================================================================================================
+
+static void UTF32Nat_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit > 0xFFFF ) break;
+ *utf16Pos = UTF16Unit(inUnit);
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Nat_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Nat_to_UTF16Nat
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Swp_Surrogate ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+ UTF32Unit temp; // ! Avoid gcc complaints about declarations after goto's.
+
+ if ( cpIn > 0x10FFFF ) UC_Throw ( "Bad UTF-32 - out of range", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough room for the output.
+
+ unitCount = 2;
+ temp = cpIn - 0x10000;
+ UTF16OutSwap ( &utf16Out[0], (0xD800 | UTF16Unit ( temp >> 10 )) );
+ UTF16OutSwap ( &utf16Out[1], (0xDC00 | UTF16Unit ( temp & 0x3FF)) );
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+} // CodePoint_to_UTF16Swp_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_to_UTF16Swp ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written )
+{
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16Out != 0) && (utf16Written != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP.
+
+InBMP:
+ unitCount = 1;
+ UTF16OutSwap ( utf16Out, UTF16Unit(cpIn) );
+
+Done:
+ *utf16Written = unitCount;
+ return;
+
+CheckSurrogate:
+ if ( cpIn > 0xFFFF ) goto SurrogatePair;
+ if ( cpIn > 0xDFFF ) goto InBMP;
+ UC_Throw ( "Bad UTF-32 - surrogate code point", kXMPErr_BadParam );
+
+SurrogatePair:
+ CodePoint_to_UTF16Swp_Surrogate ( cpIn, utf16Out, utf16Len, utf16Written );
+ return;
+
+} // CodePoint_to_UTF16Swp
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Swp_Surrogate ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit hiUnit = UTF16InSwap(utf16In);
+ size_t unitCount = 0;
+ UTF16Unit loUnit; // ! Avoid gcc complaints about declarations after goto's.
+ UTF32Unit cp;
+
+ // ----------------------------------
+ // We've got a UTF-16 surrogate pair.
+
+ if ( hiUnit > 0xDBFF ) UC_Throw ( "Bad UTF-16 - leading low surrogate", kXMPErr_BadParam );
+ if ( utf16Len < 2 ) goto Done; // Not enough input in this buffer.
+
+ loUnit = UTF16InSwap(utf16In+1);
+ if ( (loUnit < 0xDC00) || (0xDFFF < loUnit) ) UC_Throw ( "Bad UTF-16 - missing low surrogate", kXMPErr_BadParam );
+
+ unitCount = 2;
+ cp = (((hiUnit & 0x3FF) << 10) | (loUnit & 0x3FF)) + 0x10000;
+
+ *cpOut = cp; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+} // CodePoint_from_UTF16Swp_Surrogate
+
+// =================================================================================================
+
+static void CodePoint_from_UTF16Swp ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read )
+{
+ UTF16Unit inUnit; // ! Don't read until we know there is input.
+ size_t unitCount = 0;
+
+ UC_Assert ( (utf16In != 0) && (cpOut != 0) && (utf16Read != 0) );
+ if ( utf16Len == 0 ) goto Done;
+ inUnit = UTF16InSwap(utf16In);
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) goto SurrogatePair; // ! Force linear execution path for the BMP.
+
+ unitCount = 1;
+ *cpOut = inUnit; // ! Don't put after Done, don't write if no input.
+
+Done:
+ *utf16Read = unitCount;
+ return;
+
+SurrogatePair:
+ CodePoint_from_UTF16Swp_Surrogate ( utf16In, utf16Len, cpOut, utf16Read );
+ return;
+
+} // CodePoint_from_UTF16Swp
+
+// =================================================================================================
+
+static void UTF8_to_UTF16Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf8In != 0) && (utf16Out != 0) && (utf8Read != 0) && (utf16Written != 0) );
+
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf16Pos = UTF16Unit(inUnit) << 8; // Better than: UTF16OutSwap ( utf16Pos, inUnit );
+ ++utf8Pos;
+ ++utf16Pos;
+ }
+ utf8Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-ASCII, it copies multiple input units into 1 or 2 output units.
+ while ( (utf8Left > 0) && (utf16Left > 0) ) {
+ UTF32Unit cp;
+ size_t len8, len16;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len8 );
+ if ( len8 == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ if ( cp <= 0xFFFF ) {
+ UTF16OutSwap ( utf16Pos, UTF16Unit(cp) );
+ len16 = 1;
+ } else {
+ CodePoint_to_UTF16Swp_Surrogate ( cp, utf16Pos, utf16Left, &len16 );
+ if ( len16 == 0 ) goto Done; // Not enough room in the output buffer.
+ }
+ utf8Left -= len8;
+ utf8Pos += len8;
+ utf16Left -= len16;
+ utf16Pos += len16;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF8_to_UTF16Swp
+
+// =================================================================================================
+
+static void UTF8_to_UTF32Swp ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written )
+{
+ const UTF8Unit * utf8Pos = utf8In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf8Left = utf8Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf8In != 0) && (utf32Out != 0) && (utf8Read != 0) && (utf32Written != 0) );
+
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf8Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit > 0x7F ) break;
+ *utf32Pos = UTF32Unit(inUnit) << 24; // Better than: UTF32OutSwap ( utf32Pos, inUnit );
+ ++utf8Pos;
+ ++utf32Pos;
+ }
+ utf8Left -= i;
+ utf32Left -= i;
+
+ // Do a run of non-ASCII, it copies variable input into 1 output unit.
+ while ( (utf8Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF32Unit cp;
+ UTF8Unit inUnit = *utf8Pos;
+ if ( inUnit <= 0x7F ) break;
+ CodePoint_from_UTF8_Multi ( utf8Pos, utf8Left, &cp, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a character.
+ UTF32OutSwap ( utf32Pos, cp );
+ utf8Left -= len;
+ utf8Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf8Read = utf8Len - utf8Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF8_to_UTF32Swp
+
+// =================================================================================================
+
+static void UTF16Swp_to_UTF8 ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf16In != 0) && (utf8Out != 0) && (utf16Read != 0) && (utf8Written != 0) );
+
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( inUnit > 0x7F ) break;
+ *utf8Pos = UTF8Unit(inUnit);
+ ++utf16Pos;
+ ++utf8Pos;
+ }
+ utf16Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII inside the BMP, it copies 1 input unit into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ size_t len8;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( inUnit <= 0x7F ) break;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ CodePoint_to_UTF8_Multi ( inUnit, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= 1;
+ utf16Pos += 1;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ // Do a run of surrogate pairs, it copies 2 input units into multiple output units.
+ while ( (utf16Left > 0) && (utf8Left > 0) ) {
+ UTF32Unit cp;
+ size_t len16, len8;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, &cp, &len16 );
+ if ( len16 == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len16 == 2 );
+ CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len8 );
+ if ( len8 == 0 ) goto Done; // Not enough room in the output buffer.
+ utf16Left -= len16;
+ utf16Pos += len16;
+ utf8Left -= len8;
+ utf8Pos += len8;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF16Swp_to_UTF8
+
+// =================================================================================================
+
+static void UTF32Swp_to_UTF8 ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF8Unit * utf8Pos = utf8Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf8Left = utf8Len;
+
+ UC_Assert ( (utf32In != 0) && (utf8Out != 0) && (utf32Read != 0) && (utf8Written != 0) );
+
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+
+ // Do a run of ASCII, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf8Left ) limit = utf8Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit cp = UTF32InSwap(utf32Pos);
+ if ( cp > 0x7F ) break;
+ *utf8Pos = UTF8Unit(cp);
+ ++utf32Pos;
+ ++utf8Pos;
+ }
+ utf32Left -= i;
+ utf8Left -= i;
+
+ // Do a run of non-ASCII, it copies 1 input unit into multiple output units.
+ while ( (utf32Left > 0) && (utf8Left > 0) ) {
+ size_t len;
+ UTF32Unit cp = UTF32InSwap(utf32Pos);
+ if ( cp <= 0x7F ) break;
+ CodePoint_to_UTF8_Multi ( cp, utf8Pos, utf8Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf8Left -= len;
+ utf8Pos += len;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf8Written = utf8Len - utf8Left;
+
+} // UTF32Swp_to_UTF8
+
+// =================================================================================================
+
+static void UTF16Swp_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ *utf32Pos = UTF32Unit(*utf16Pos) << 16; // Better than: UTF32OutSwap ( utf32Pos, inUnit );
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF32Unit cp;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, &cp, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UTF32OutSwap ( utf32Pos, cp );
+ UC_Assert ( len == 2 );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Swp_to_UTF32Swp
+
+// =================================================================================================
+
+static void UTF32Swp_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ const size_t k32to16Offset = swap32to16Offset; // ! Make sure compiler treats as an invariant.
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit > 0xFFFF ) break;
+ *utf16Pos = *(((UTF16Unit*)utf32Pos) + k32to16Offset); // Better than: UTF16OutSwap ( utf16Pos, UTF16Unit(inUnit) );
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Swp_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Swp_to_UTF16Swp
+
+// =================================================================================================
+
+static void UTF16Nat_to_UTF32Swp ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ UTF32OutSwap ( utf32Pos, inUnit );
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF32Unit cp;
+ UTF16Unit inUnit = *utf16Pos;
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Nat_Surrogate ( utf16Pos, utf16Left, &cp, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len == 2 );
+ UTF32OutSwap ( utf32Pos, cp );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Nat_to_UTF32Swp
+
+// =================================================================================================
+
+static void UTF16Swp_to_UTF32Nat ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written )
+{
+ const UTF16Unit * utf16Pos = utf16In;
+ UTF32Unit * utf32Pos = utf32Out;
+
+ size_t utf16Left = utf16Len;
+ size_t utf32Left = utf32Len;
+
+ UC_Assert ( (utf16In != 0) && (utf32Out != 0) && (utf16Read != 0) && (utf32Written != 0) );
+
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf16Left;
+ if ( limit > utf32Left ) limit = utf32Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (0xD800 <= inUnit) && (inUnit <= 0xDFFF) ) break;
+ *utf32Pos = inUnit;
+ ++utf16Pos;
+ ++utf32Pos;
+ }
+ utf16Left -= i;
+ utf32Left -= i;
+
+ // Do a run of surrogate pairs, it copies 2 input units into 1 output unit.
+ while ( (utf16Left > 0) && (utf32Left > 0) ) {
+ size_t len;
+ UTF16Unit inUnit = UTF16InSwap(utf16Pos);
+ if ( (inUnit < 0xD800) || (0xDFFF < inUnit) ) break;
+ CodePoint_from_UTF16Swp_Surrogate ( utf16Pos, utf16Left, utf32Pos, &len );
+ if ( len == 0 ) goto Done; // The input buffer ends in the middle of a surrogate pair.
+ UC_Assert ( len == 2 );
+ utf16Left -= len;
+ utf16Pos += len;
+ utf32Left -= 1;
+ utf32Pos += 1;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf16Read = utf16Len - utf16Left;
+ *utf32Written = utf32Len - utf32Left;
+
+} // UTF16Swp_to_UTF32Nat
+
+// =================================================================================================
+
+static void UTF32Nat_to_UTF16Swp ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit > 0xFFFF ) break;
+ UTF16OutSwap ( utf16Pos, UTF16Unit(inUnit) );
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = *utf32Pos;
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Swp_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Nat_to_UTF16Swp
+
+// =================================================================================================
+
+static void UTF32Swp_to_UTF16Nat ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written )
+{
+ const UTF32Unit * utf32Pos = utf32In;
+ UTF16Unit * utf16Pos = utf16Out;
+
+ size_t utf32Left = utf32Len;
+ size_t utf16Left = utf16Len;
+
+ UC_Assert ( (utf32In != 0) && (utf16Out != 0) && (utf32Read != 0) && (utf16Written != 0) );
+
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+
+ // Do a run of BMP, it copies 1 input unit into 1 output unit.
+ size_t i, limit = utf32Left;
+ if ( limit > utf16Left ) limit = utf16Left;
+ for ( i = 0; i < limit; ++i ) {
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit > 0xFFFF ) break;
+ *utf16Pos = UTF16Unit(inUnit);
+ ++utf32Pos;
+ ++utf16Pos;
+ }
+ utf32Left -= i;
+ utf16Left -= i;
+
+ // Do a run of non-BMP, it copies 1 input unit into 2 output units.
+ while ( (utf32Left > 0) && (utf16Left > 0) ) {
+ size_t len;
+ UTF32Unit inUnit = UTF32InSwap(utf32Pos);
+ if ( inUnit <= 0xFFFF ) break;
+ CodePoint_to_UTF16Nat_Surrogate ( inUnit, utf16Pos, utf16Left, &len );
+ if ( len == 0 ) goto Done; // Not enough room in the output buffer.
+ UC_Assert ( len == 2 );
+ utf32Left -= 1;
+ utf32Pos += 1;
+ utf16Left -= 2;
+ utf16Pos += 2;
+ }
+
+ }
+
+Done: // Set the output lengths.
+ *utf32Read = utf32Len - utf32Left;
+ *utf16Written = utf16Len - utf16Left;
+
+} // UTF32Swp_to_UTF16Nat
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/UnicodeConversions.hpp b/gpr/source/lib/xmp_core/UnicodeConversions.hpp
new file mode 100644
index 0000000..f09437c
--- /dev/null
+++ b/gpr/source/lib/xmp_core/UnicodeConversions.hpp
@@ -0,0 +1,115 @@
+#ifndef __UnicodeConversions_h__
+#define __UnicodeConversions_h__
+
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <string>
+
+// =================================================================================================
+
+typedef XMP_Uns8 UTF8Unit;
+typedef XMP_Uns16 UTF16Unit;
+typedef XMP_Uns32 UTF32Unit;
+
+// -------------------------------------------------------------------------------------------------
+
+// ! The UTF16 and UTF32 counts are in storage units, not bytes! CodePoint values are always native.
+
+// *** MIght be better to return a status than throw an exception for errors?
+
+typedef void (*CodePoint_to_UTF16_Proc) ( const UTF32Unit cpIn, UTF16Unit * utf16Out, const size_t utf16Len, size_t * utf16Written );
+
+typedef void (*CodePoint_from_UTF16_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len, UTF32Unit * cpOut, size_t * utf16Read );
+
+typedef void (*UTF8_to_UTF16_Proc) ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf8Read, size_t * utf16Written );
+
+typedef void (*UTF8_to_UTF32_Proc) ( const UTF8Unit * utf8In, const size_t utf8Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf8Read, size_t * utf32Written );
+
+typedef void (*UTF16_to_UTF8_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf16Read, size_t * utf8Written );
+
+typedef void (*UTF32_to_UTF8_Proc) ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF8Unit * utf8Out, const size_t utf8Len,
+ size_t * utf32Read, size_t * utf8Written );
+
+typedef void (*UTF16_to_UTF32_Proc) ( const UTF16Unit * utf16In, const size_t utf16Len,
+ UTF32Unit * utf32Out, const size_t utf32Len,
+ size_t * utf16Read, size_t * utf32Written );
+
+typedef void (*UTF32_to_UTF16_Proc) ( const UTF32Unit * utf32In, const size_t utf32Len,
+ UTF16Unit * utf16Out, const size_t utf16Len,
+ size_t * utf32Read, size_t * utf16Written );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void CodePoint_to_UTF8 ( const UTF32Unit cpIn, UTF8Unit * utf8Out, const size_t utf8Len, size_t * utf8Written );
+
+extern void CodePoint_from_UTF8 ( const UTF8Unit * utf8In, const size_t utf8Len, UTF32Unit * cpOut, size_t * utf8Read );
+
+extern CodePoint_to_UTF16_Proc CodePoint_to_UTF16BE;
+extern CodePoint_to_UTF16_Proc CodePoint_to_UTF16LE;
+
+extern CodePoint_from_UTF16_Proc CodePoint_from_UTF16BE;
+extern CodePoint_from_UTF16_Proc CodePoint_from_UTF16LE;
+
+extern UTF8_to_UTF16_Proc UTF8_to_UTF16BE;
+extern UTF8_to_UTF16_Proc UTF8_to_UTF16LE;
+
+extern UTF8_to_UTF32_Proc UTF8_to_UTF32BE;
+extern UTF8_to_UTF32_Proc UTF8_to_UTF32LE;
+
+extern UTF16_to_UTF8_Proc UTF16BE_to_UTF8;
+extern UTF16_to_UTF8_Proc UTF16LE_to_UTF8;
+
+extern UTF32_to_UTF8_Proc UTF32BE_to_UTF8;
+extern UTF32_to_UTF8_Proc UTF32LE_to_UTF8;
+
+extern UTF8_to_UTF16_Proc UTF8_to_UTF16Native;
+extern UTF8_to_UTF32_Proc UTF8_to_UTF32Native;
+
+extern UTF16_to_UTF8_Proc UTF16Native_to_UTF8;
+extern UTF32_to_UTF8_Proc UTF32Native_to_UTF8;
+
+extern UTF16_to_UTF32_Proc UTF16BE_to_UTF32BE;
+extern UTF16_to_UTF32_Proc UTF16BE_to_UTF32LE;
+
+extern UTF16_to_UTF32_Proc UTF16LE_to_UTF32BE;
+extern UTF16_to_UTF32_Proc UTF16LE_to_UTF32LE;
+
+extern UTF32_to_UTF16_Proc UTF32BE_to_UTF16BE;
+extern UTF32_to_UTF16_Proc UTF32BE_to_UTF16LE;
+
+extern UTF32_to_UTF16_Proc UTF32LE_to_UTF16BE;
+extern UTF32_to_UTF16_Proc UTF32LE_to_UTF16LE;
+
+extern void SwapUTF16 ( const UTF16Unit * utf16In, UTF16Unit * utf16Out, const size_t utf16Len );
+extern void SwapUTF32 ( const UTF32Unit * utf32In, UTF32Unit * utf32Out, const size_t utf32Len );
+
+extern void ToUTF16 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str, bool bigEndian );
+extern void ToUTF32 ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str, bool bigEndian );
+
+extern void FromUTF16 ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str, bool bigEndian );
+extern void FromUTF32 ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str, bool bigEndian );
+
+extern void ToUTF16Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf16Str );
+extern void ToUTF32Native ( const UTF8Unit * utf8In, size_t utf8Len, std::string * utf32Str );
+
+extern void FromUTF16Native ( const UTF16Unit * utf16In, size_t utf16Len, std::string * utf8Str );
+extern void FromUTF32Native ( const UTF32Unit * utf32In, size_t utf32Len, std::string * utf8Str );
+
+extern void InitializeUnicodeConversions();
+
+// =================================================================================================
+
+#endif // __UnicodeConversions_h__
diff --git a/gpr/source/lib/xmp_core/UnicodeInlines.incl_cpp b/gpr/source/lib/xmp_core/UnicodeInlines.incl_cpp
new file mode 100644
index 0000000..d96d370
--- /dev/null
+++ b/gpr/source/lib/xmp_core/UnicodeInlines.incl_cpp
@@ -0,0 +1,129 @@
+#ifndef __UnicodeInlines_incl_cpp__
+#define __UnicodeInlines_incl_cpp__
+
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "UnicodeConversions.hpp"
+
+// =================================================================================================
+// Inner loop utilities that need to be inlined.
+// =================================================================================================
+
+static inline XMP_Uns32 GetCodePoint ( const XMP_Uns8 ** utf8Str_io )
+{
+ const XMP_Uns8 * u8Ptr = *utf8Str_io;
+ XMP_Uns32 cp;
+ size_t u8Len;
+ CodePoint_from_UTF8 ( u8Ptr, 4, &cp, &u8Len ); // Throws an exception for errors.
+ *utf8Str_io = u8Ptr + u8Len;
+ return cp;
+}
+
+// =================================================================================================
+
+static inline bool IsStartChar_ASCII ( XMP_Uns32 cp )
+{
+ // ASCII starting characters for an XML name.
+ if ( (('a' <= cp) && (cp <= 'z')) || (('A' <= cp) && (cp <= 'Z')) || (cp == '_') ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool IsStartChar_NonASCII ( XMP_Uns32 cp )
+{
+ // Non-ASCII starting characters for an XML name.
+
+ if ( ((0xC0 <= cp) && (cp <= 0xD6)) || ((0xD8 <= cp) && (cp <= 0xF6)) ) return true;
+ if ( ((0xF8 <= cp) && (cp <= 0x2FF)) || ((0x370 <= cp) && (cp <= 0x37D)) ) return true;
+
+ if ( ((0x37F <= cp) && (cp <= 0x1FFF)) || ((0x200C <= cp) && (cp <= 0x200D)) ) return true;
+ if ( ((0x2070 <= cp) && (cp <= 0x218F)) || ((0x2C00 <= cp) && (cp <= 0x2FEF)) ) return true;
+ if ( ((0x3001 <= cp) && (cp <= 0xD7FF)) || ((0xF900 <= cp) && (cp <= 0xFDCF)) ) return true;
+ if ( ((0xFDF0 <= cp) && (cp <= 0xFFFD)) || ((0x10000 <= cp) && (cp <= 0xEFFFF)) ) return true;
+
+ return false;
+
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool IsOtherChar_ASCII ( XMP_Uns32 cp )
+{
+ // ASCII following characters for an XML name.
+ if ( (('0' <= cp) && (cp <= '9')) || (cp == '-') || (cp == '.') ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline bool IsOtherChar_NonASCII ( XMP_Uns32 cp )
+{
+ // Non-ASCII following characters for an XML name.
+ if ( (cp == 0xB7) || ((0x300 <= cp) && (cp <= 0x36F)) || ((0x203F <= cp) && (cp <= 0x2040)) ) return true;
+ return false;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void VerifyUTF8 ( XMP_StringPtr str )
+{
+ const XMP_Uns8 * utf8Str = (XMP_Uns8*)str;
+ while ( *utf8Str != 0 ) {
+ while ( (*utf8Str != 0) && (*utf8Str < 0x80) ) ++utf8Str;
+ if ( *utf8Str >= 0x80 ) (void) GetCodePoint ( &utf8Str ); // Throws for bad UTF-8.
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void VerifySimpleXMLName ( XMP_StringPtr _nameStart, XMP_StringPtr _nameEnd )
+{
+
+ const XMP_Uns8 * nameStart = (const XMP_Uns8 *) _nameStart;
+ const XMP_Uns8 * nameEnd = (const XMP_Uns8 *) _nameEnd;
+ const XMP_Uns8 * namePos = nameStart;
+ XMP_Uns32 cp;
+
+ // The first character is more restricted.
+
+ if ( nameStart >= nameEnd ) XMP_Throw ( "Empty XML name", kXMPErr_BadXPath );
+
+ cp = *namePos;
+ if ( cp < 0x80 ) {
+ ++namePos;
+ if ( ! IsStartChar_ASCII(cp) ) goto NameError;
+ } else {
+ cp = GetCodePoint ( &namePos );
+ if ( ! IsStartChar_NonASCII(cp) ) goto NameError;
+ }
+
+ // Check the rest of the name.
+
+ while ( namePos < nameEnd ) {
+ cp = *namePos;
+ if ( cp < 0x80 ) {
+ ++namePos;
+ if ( (! IsStartChar_ASCII(cp)) && (! IsOtherChar_ASCII(cp)) ) goto NameError;
+ } else {
+ cp = GetCodePoint ( &namePos );
+ if ( (! IsStartChar_NonASCII(cp)) && (! IsOtherChar_NonASCII(cp)) ) goto NameError;
+ }
+ }
+
+ return;
+
+NameError:
+ XMP_Throw ( "Bad XML name", kXMPErr_BadXPath );
+
+} // VerifySimpleXMLName
+
+// =================================================================================================
+
+#endif // __UnicodeInlines_incl_cpp__
diff --git a/gpr/source/lib/xmp_core/WXMPIterator.cpp b/gpr/source/lib/xmp_core/WXMPIterator.cpp
new file mode 100644
index 0000000..f96323f
--- /dev/null
+++ b/gpr/source/lib/xmp_core/WXMPIterator.cpp
@@ -0,0 +1,170 @@
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "public/include/XMP_Const.h"
+
+#include "public/include/client-glue/WXMPIterator.hpp"
+
+#include "XMPCore_Impl.hpp"
+#include "XMPIterator.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4101 ) // unreferenced local variable
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+// CTor/DTor Wrappers
+// ==================
+
+void
+WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPIterator_PropCTor_1" ) // No lib object yet, use the static entry.
+
+ if ( schemaNS == 0 ) schemaNS = "";
+ if ( propName == 0 ) propName = "";
+
+ const XMPMeta & xmpObj = WtoXMPMeta_Ref ( xmpRef );
+ XMP_AutoLock metaLock ( &xmpObj.lock, kXMP_ReadLock );
+
+ XMPIterator * iter = new XMPIterator ( xmpObj, schemaNS, propName, options );
+ ++iter->clientRefs;
+ XMP_Assert ( iter->clientRefs == 1 );
+ wResult->ptrResult = XMPIteratorRef ( iter );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPIterator_TableCTor_1" ) // No lib object yet, use the static entry.
+
+ if ( schemaNS == 0 ) schemaNS = "";
+ if ( propName == 0 ) propName = "";
+
+ XMPIterator * iter = new XMPIterator ( schemaNS, propName, options );
+ ++iter->clientRefs;
+ XMP_Assert ( iter->clientRefs == 1 );
+ wResult->ptrResult = XMPIteratorRef ( iter );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef xmpObjRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_IncrementRefCount_1" )
+
+ ++thiz->clientRefs;
+ XMP_Assert ( thiz->clientRefs > 1 );
+
+ XMP_EXIT_NoThrow
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef xmpObjRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_DecrementRefCount_1" )
+
+ XMP_Assert ( thiz->clientRefs > 0 );
+ --thiz->clientRefs;
+ if ( thiz->clientRefs <= 0 ) {
+ objLock.Release();
+ delete ( thiz );
+ }
+
+ XMP_EXIT_NoThrow
+}
+
+// =================================================================================================
+// Class Method Wrappers
+// =====================
+
+void
+WXMPIterator_Next_1 ( XMPIteratorRef xmpObjRef,
+ void * schemaNS,
+ void * propPath,
+ void * propValue,
+ XMP_OptionBits * propOptions,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_Next_1" )
+
+ XMP_StringPtr schemaPtr = 0;
+ XMP_StringLen schemaLen = 0;
+ XMP_StringPtr pathPtr = 0;
+ XMP_StringLen pathLen = 0;
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueLen = 0;
+
+ if ( propOptions == 0 ) propOptions = &voidOptionBits;
+
+ XMP_Assert( thiz->info.xmpObj != NULL );
+ XMP_AutoLock metaLock ( &thiz->info.xmpObj->lock, kXMP_ReadLock, (thiz->info.xmpObj != 0) );
+
+ XMP_Bool found = thiz->Next ( &schemaPtr, &schemaLen, &pathPtr, &pathLen, &valuePtr, &valueLen, propOptions );
+ wResult->int32Result = found;
+
+ if ( found ) {
+ if ( schemaNS != 0 ) (*SetClientString) ( schemaNS, schemaPtr, schemaLen );
+ if ( propPath != 0 ) (*SetClientString) ( propPath, pathPtr, pathLen );
+ if ( propValue != 0 ) (*SetClientString) ( propValue, valuePtr, valueLen );
+ }
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPIterator_Skip_1 ( XMPIteratorRef xmpObjRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_Skip_1" )
+
+ XMP_Assert( thiz->info.xmpObj != NULL );
+ XMP_AutoLock metaLock ( &thiz->info.xmpObj->lock, kXMP_ReadLock, (thiz->info.xmpObj != 0) );
+
+ thiz->Skip ( options );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/gpr/source/lib/xmp_core/WXMPMeta.cpp b/gpr/source/lib/xmp_core/WXMPMeta.cpp
new file mode 100644
index 0000000..956f08f
--- /dev/null
+++ b/gpr/source/lib/xmp_core/WXMPMeta.cpp
@@ -0,0 +1,1191 @@
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "public/include/XMP_Const.h"
+
+#include "public/include/client-glue/WXMPMeta.hpp"
+
+#include "XMPCore_Impl.hpp"
+#include "XMPMeta.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4101 ) // unreferenced local variable
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+// Init/Term Wrappers
+// ==================
+
+/* class static */ void
+WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_NoLock ( "WXMPMeta_GetVersionInfo_1" )
+
+ XMPMeta::GetVersionInfo ( info );
+
+ XMP_EXIT_NoThrow
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_Initialize_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_NoLock ( "WXMPMeta_Initialize_1" )
+
+ wResult->int32Result = XMPMeta::Initialize();
+
+ XMP_EXIT
+}
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_Terminate_1()
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_NoLock ( "WXMPMeta_Terminate_1" )
+
+ XMPMeta::Terminate();
+
+ XMP_EXIT_NoThrow
+}
+
+// =================================================================================================
+// CTor/DTor Wrappers
+// ==================
+
+void
+WXMPMeta_CTor_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_CTor_1" ) // No lib object yet, use the static entry.
+
+ XMPMeta * xmpObj = new XMPMeta();
+ ++xmpObj->clientRefs;
+ XMP_Assert ( xmpObj->clientRefs == 1 );
+ wResult->ptrResult = XMPMetaRef ( xmpObj );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpObjRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_IncrementRefCount_1" )
+
+ ++thiz->clientRefs;
+ XMP_Assert ( thiz->clientRefs > 0 );
+
+ XMP_EXIT_NoThrow
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpObjRef )
+{
+ WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DecrementRefCount_1" )
+
+ XMP_Assert ( thiz->clientRefs > 0 );
+ --thiz->clientRefs;
+ if ( thiz->clientRefs <= 0 ) {
+ objLock.Release();
+ delete ( thiz );
+ }
+
+ XMP_EXIT_NoThrow
+}
+
+// =================================================================================================
+// Class Static Wrappers
+// =====================
+
+/* class static */ void
+WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_GetGlobalOptions_1" )
+
+ XMP_OptionBits options = XMPMeta::GetGlobalOptions();
+ wResult->int32Result = options;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_SetGlobalOptions_1" )
+
+ XMPMeta::SetGlobalOptions ( options );
+
+ XMP_EXIT
+}
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_DumpNamespaces_1" )
+
+ if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
+
+ XMP_Status status = XMPMeta::DumpNamespaces ( outProc, refCon );
+ wResult->int32Result = status;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ void * actualPrefix,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_RegisterNamespace_1" )
+
+ if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
+ if ( (suggestedPrefix == 0) || (*suggestedPrefix == 0) ) XMP_Throw ( "Empty suggested prefix", kXMPErr_BadSchema );
+
+ XMP_StringPtr prefixPtr = 0;
+ XMP_StringLen prefixSize = 0;
+
+ bool prefixMatch = XMPMeta::RegisterNamespace ( namespaceURI, suggestedPrefix, &prefixPtr, &prefixSize );
+ wResult->int32Result = prefixMatch;
+
+ if ( actualPrefix != 0 ) (*SetClientString) ( actualPrefix, prefixPtr, prefixSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
+ void * namespacePrefix,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_GetNamespacePrefix_1" )
+
+ if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
+
+ XMP_StringPtr prefixPtr = 0;
+ XMP_StringLen prefixSize = 0;
+
+ bool found = XMPMeta::GetNamespacePrefix ( namespaceURI, &prefixPtr, &prefixSize );
+ wResult->int32Result = found;
+
+ if ( found && (namespacePrefix != 0) ) (*SetClientString) ( namespacePrefix, prefixPtr, prefixSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
+ void * namespaceURI,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_GetNamespaceURI_1" )
+
+ if ( (namespacePrefix == 0) || (*namespacePrefix == 0) ) XMP_Throw ( "Empty namespace prefix", kXMPErr_BadSchema );
+
+ XMP_StringPtr uriPtr = 0;
+ XMP_StringLen uriSize = 0;
+
+ bool found = XMPMeta::GetNamespaceURI ( namespacePrefix, &uriPtr, &uriSize );
+ wResult->int32Result = found;
+
+ if ( found && (namespaceURI != 0) ) (*SetClientString) ( namespaceURI, uriPtr, uriSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+/* class static */ void
+WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_DeleteNamespace_1" )
+
+ if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
+
+ XMPMeta::DeleteNamespace ( namespaceURI );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+// Class Method Wrappers
+// =====================
+
+void
+WXMPMeta_GetProperty_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ void * propValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueSize = 0;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetProperty ( schemaNS, propName, &valuePtr, &valueSize, options );
+ wResult->int32Result = found;
+
+ if ( found && (propValue != 0) ) (*SetClientString) ( propValue, valuePtr, valueSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ void * itemValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueSize = 0;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetArrayItem ( schemaNS, arrayName, itemIndex, &valuePtr, &valueSize, options );
+ wResult->int32Result = found;
+
+ if ( found && (itemValue != 0) ) (*SetClientString) ( itemValue, valuePtr, valueSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetStructField_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ void * fieldValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetStructField_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueSize = 0;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetStructField ( schemaNS, structName, fieldNS, fieldName, &valuePtr, &valueSize, options );
+ wResult->int32Result = found;
+
+ if ( found && (fieldValue != 0) ) (*SetClientString) ( fieldValue, valuePtr, valueSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ void * qualValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetQualifier_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueSize = 0;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetQualifier ( schemaNS, propName, qualNS, qualName, &valuePtr, &valueSize, options );
+ wResult->int32Result = found;
+
+ if ( found && (qualValue != 0) ) (*SetClientString) ( qualValue, valuePtr, valueSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->SetProperty ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ thiz->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_AppendArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ thiz->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetStructField_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetStructField_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ thiz->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetQualifier_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ thiz->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteProperty_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->DeleteProperty ( schemaNS, propName );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteArrayItem_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ thiz->DeleteArrayItem ( schemaNS, arrayName, itemIndex );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteStructField_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ thiz->DeleteStructField ( schemaNS, structName, fieldNS, fieldName );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteQualifier_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ thiz->DeleteQualifier ( schemaNS, propName, qualNS, qualName );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesPropertyExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ bool found = thiz.DoesPropertyExist ( schemaNS, propName );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesArrayItemExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ bool found = thiz.DoesArrayItemExist ( schemaNS, arrayName, itemIndex );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesStructFieldExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ bool found = thiz.DoesStructFieldExist ( schemaNS, structName, fieldNS, fieldName );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesQualifierExist_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ bool found = thiz.DoesQualifierExist ( schemaNS, propName, qualNS, qualName );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ void * actualLang,
+ void * itemValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetLocalizedText_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( genericLang == 0 ) genericLang = "";
+ if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam );
+
+ XMP_StringPtr langPtr = 0;
+ XMP_StringLen langSize = 0;
+ XMP_StringPtr valuePtr = 0;
+ XMP_StringLen valueSize = 0;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetLocalizedText ( schemaNS, arrayName, genericLang, specificLang,
+ &langPtr, &langSize, &valuePtr, &valueSize, options );
+ wResult->int32Result = found;
+
+ if ( found ) {
+ if ( actualLang != 0 ) (*SetClientString) ( actualLang, langPtr, langSize );
+ if ( itemValue != 0 ) (*SetClientString) ( itemValue, valuePtr, valueSize );
+ }
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetLocalizedText_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( genericLang == 0 ) genericLang = "";
+ if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam );
+ if ( itemValue == 0 ) itemValue = "";
+
+ thiz->SetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, itemValue, options );
+
+ XMP_EXIT
+}
+
+void
+WXMPMeta_DeleteLocalizedText_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteLocalizedText_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( genericLang == 0 ) genericLang = "";
+ if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam );
+
+ thiz->DeleteLocalizedText ( schemaNS, arrayName, genericLang, specificLang );
+
+ XMP_EXIT
+}
+
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Bool_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidByte;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool value;
+ bool found = thiz.GetProperty_Bool ( schemaNS, propName, &value, options );
+ if ( propValue != 0 ) *propValue = value;
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Int_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidInt32;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetProperty_Int ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Int64_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidInt64;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetProperty_Int64 ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Float_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidDouble;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetProperty_Float ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Date_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ if ( propValue == 0 ) propValue = &voidDateTime;
+ if ( options == 0 ) options = &voidOptionBits;
+
+ bool found = thiz.GetProperty_Date ( schemaNS, propName, propValue, options );
+ wResult->int32Result = found;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Bool_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->SetProperty_Bool ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Int_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->SetProperty_Int ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Int64_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->SetProperty_Int64 ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Float_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->SetProperty_Float ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Date_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+
+ thiz->SetProperty_Date ( schemaNS, propName, propValue, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_DumpObject_1 ( XMPMetaRef xmpObjRef,
+ XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DumpObject_1" )
+
+ if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
+
+ thiz.DumpObject ( outProc, refCon );
+ wResult->int32Result = 0;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_Sort_1 ( XMPMetaRef xmpObjRef,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_Sort_1" )
+
+ thiz->Sort();
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_Erase_1 ( XMPMetaRef xmpObjRef,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_Erase_1" )
+
+ thiz->Erase();
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_Clone_1 ( XMPMetaRef xmpObjRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_Clone_1" )
+
+ XMPMeta * xClone = new XMPMeta; // ! Don't need an output lock, final ref assignment in client glue.
+ thiz.Clone ( xClone, options );
+ XMP_Assert ( xClone->clientRefs == 0 ); // ! Gets incremented in TXMPMeta::Clone.
+ wResult->ptrResult = xClone;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_CountArrayItems_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ XMP_Index count = thiz.CountArrayItems ( schemaNS, arrayName );
+ wResult->int32Result = count;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpObjRef,
+ void * objName,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetObjectName_1" )
+
+ XMP_StringPtr namePtr = 0;
+ XMP_StringLen nameSize = 0;
+
+ thiz.GetObjectName ( &namePtr, &nameSize );
+ if ( objName != 0 ) (*SetClientString) ( objName, namePtr, nameSize );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr name,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetObjectName_1" )
+
+ if ( name == 0 ) name = "";
+
+ thiz->SetObjectName ( name );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpObjRef,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetObjectOptions_1" )
+
+ XMP_OptionBits options = thiz.GetObjectOptions();
+ wResult->int32Result = options;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpObjRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetObjectOptions_1" )
+
+ thiz->SetObjectOptions ( options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpObjRef,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_ParseFromBuffer_1" )
+
+ thiz->ParseFromBuffer ( buffer, bufferSize, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpObjRef,
+ void * pktString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */
+{
+ XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_SerializeToBuffer_1" )
+
+ XMP_VarString localStr;
+
+ if ( newline == 0 ) newline = "";
+ if ( indent == 0 ) indent = "";
+
+ thiz.SerializeToBuffer ( &localStr, options, padding, newline, indent, baseIndent );
+ if ( pktString != 0 ) (*SetClientString) ( pktString, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetDefaultErrorCallback_1 ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPMeta_SetDefaultErrorCallback_1" )
+
+ XMPMeta::SetDefaultErrorCallback ( wrapperProc, clientProc, context, limit );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_SetErrorCallback_1 ( XMPMetaRef xmpObjRef,
+ XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetErrorCallback_1" )
+
+ thiz->SetErrorCallback ( wrapperProc, clientProc, context, limit );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPMeta_ResetErrorCallbackLimit_1 ( XMPMetaRef xmpObjRef,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_ResetErrorCallbackLimit_1" )
+
+ thiz->ResetErrorCallbackLimit ( limit );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/gpr/source/lib/xmp_core/WXMPUtils.cpp b/gpr/source/lib/xmp_core/WXMPUtils.cpp
new file mode 100644
index 0000000..fc7ca17
--- /dev/null
+++ b/gpr/source/lib/xmp_core/WXMPUtils.cpp
@@ -0,0 +1,634 @@
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// *** Should change "type * inParam" to "type & inParam"
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "public/include/XMP_Const.h"
+
+#include "public/include/client-glue/WXMPUtils.hpp"
+
+#include "XMPCore_Impl.hpp"
+#include "XMPUtils.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4101 ) // unreferenced local variable
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #if XMP_DebugBuild
+ #pragma warning ( disable : 4297 ) // function assumed not to throw an exception but does
+ #endif
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+// Class Static Wrappers
+// =====================
+
+void
+WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ void * itemPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ComposeArrayItemPath_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ XMP_VarString localStr;
+
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &localStr );
+ if ( itemPath != 0 ) (*SetClientString) ( itemPath, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ void * fieldPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ComposeStructFieldPath_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+
+ XMP_VarString localStr;
+
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &localStr );
+ if ( fieldPath != 0 ) (*SetClientString) ( fieldPath, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ void * qualPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ComposeQualifierPath_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath );
+ if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema );
+ if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath );
+
+ XMP_VarString localStr;
+
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &localStr );
+ if ( qualPath != 0 ) (*SetClientString) ( qualPath, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ void * selPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ComposeLangSelector_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( (langName == 0) || (*langName == 0) ) XMP_Throw ( "Empty language name", kXMPErr_BadParam );
+
+ XMP_VarString localStr;
+
+ XMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName, &localStr );
+ if ( selPath != 0 ) (*SetClientString) ( selPath, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ void * selPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ComposeFieldSelector_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema );
+ if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath );
+ if ( fieldValue == 0 ) fieldValue = "";
+
+ XMP_VarString localStr;
+
+ XMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, &localStr );
+ if ( selPath != 0 ) (*SetClientString) ( selPath, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertFromBool_1" )
+
+ XMP_VarString localStr;
+
+ XMPUtils::ConvertFromBool ( binValue, &localStr );
+ if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertFromInt_1" )
+
+ if ( format == 0 ) format = "";
+
+ XMP_VarString localStr;
+
+ XMPUtils::ConvertFromInt ( binValue, format, &localStr );
+ if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertFromInt64_1" )
+
+ if ( format == 0 ) format = "";
+
+ XMP_VarString localStr;
+
+ XMPUtils::ConvertFromInt64 ( binValue, format, &localStr );
+ if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromFloat_1 ( double binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertFromFloat_1" )
+
+ if ( format == 0 ) format = "";
+
+ XMP_VarString localStr;
+
+ XMPUtils::ConvertFromFloat ( binValue, format, &localStr );
+ if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertFromDate_1" )
+
+ XMP_VarString localStr;
+
+ XMPUtils::ConvertFromDate( binValue, &localStr );
+ if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToBool_1" )
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ XMP_Bool result = XMPUtils::ConvertToBool ( strValue );
+ wResult->int32Result = result;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToInt_1" )
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ XMP_Int32 result = XMPUtils::ConvertToInt ( strValue );
+ wResult->int32Result = result;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToInt64_1" )
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ XMP_Int64 result = XMPUtils::ConvertToInt64 ( strValue );
+ wResult->int64Result = result;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToFloat_1")
+
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam);
+ double result = XMPUtils::ConvertToFloat ( strValue );
+ wResult->floatResult = result;
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToDate_1" )
+
+ if ( binValue == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); // ! Pointer is from the client.
+ XMPUtils::ConvertToDate ( strValue, binValue );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_CurrentDateTime_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::CurrentDateTime ( time );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_SetTimeZone_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::SetTimeZone ( time );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToUTCTime_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::ConvertToUTCTime ( time );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ConvertToLocalTime_1" )
+
+ if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
+ XMPUtils::ConvertToLocalTime ( time );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
+ const XMP_DateTime & right,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_CompareDateTime_1" )
+
+ int result = XMPUtils::CompareDateTime ( left, right );
+ wResult->int32Result = result;
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ void * encodedStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_EncodeToBase64_1" )
+
+ XMP_VarString localStr;
+
+ XMPUtils::EncodeToBase64 ( rawStr, rawLen, &localStr );
+ if ( encodedStr != 0 ) (*SetClientString) ( encodedStr, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ void * rawStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_DecodeFromBase64_1" )
+
+ XMP_VarString localStr;
+
+ XMPUtils::DecodeFromBase64 ( encodedStr, encodedLen, &localStr );
+ if ( rawStr != 0 ) (*SetClientString) ( rawStr, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_PackageForJPEG_1 ( XMPMetaRef wxmpObj,
+ void * stdStr,
+ void * extStr,
+ void * digestStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_PackageForJPEG_1" )
+
+ XMP_VarString localStdStr;
+ XMP_VarString localExtStr;
+ XMP_VarString localDigestStr;
+
+ const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj );
+ XMP_AutoLock metaLock ( &xmpObj.lock, kXMP_ReadLock );
+
+ XMPUtils::PackageForJPEG ( xmpObj, &localStdStr, &localExtStr, &localDigestStr );
+ if ( stdStr != 0 ) (*SetClientString) ( stdStr, localStdStr.c_str(), localStdStr.size() );
+ if ( extStr != 0 ) (*SetClientString) ( extStr, localExtStr.c_str(), localExtStr.size() );
+ if ( digestStr != 0 ) (*SetClientString) ( digestStr, localDigestStr.c_str(), localDigestStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef wfullXMP,
+ XMPMetaRef wextendedXMP,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_MergeFromJPEG_1" )
+
+ if ( wfullXMP == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( wfullXMP == wextendedXMP ) XMP_Throw ( "Full and extended XMP pointers match", kXMPErr_BadParam );
+
+ XMPMeta * fullXMP = WtoXMPMeta_Ptr ( wfullXMP );
+ XMP_AutoLock fullXMPLock ( &fullXMP->lock, kXMP_WriteLock );
+
+ const XMPMeta & extendedXMP = WtoXMPMeta_Ref ( wextendedXMP );
+ XMP_AutoLock extendedXMPLock ( &extendedXMP.lock, kXMP_ReadLock );
+
+ XMPUtils::MergeFromJPEG ( fullXMP, extendedXMP );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+void
+WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ void * catedStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_CatenateArrayItems_1" )
+
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+
+ if ( separator == 0 ) separator = "; ";
+ if ( quotes == 0 ) quotes = "\"";
+
+ XMP_VarString localStr;
+
+ const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj );
+ XMP_AutoLock metaLock ( &xmpObj.lock, kXMP_ReadLock );
+
+ XMPUtils::CatenateArrayItems ( xmpObj, schemaNS, arrayName, separator, quotes, options, &localStr );
+ if ( catedStr != 0 ) (*SetClientString) ( catedStr, localStr.c_str(), localStr.size() );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_SeparateArrayItems_1" )
+
+ if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema );
+ if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath );
+ if ( catedStr == 0 ) catedStr = "";
+
+ XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj );
+ XMP_AutoLock metaLock ( &xmpObj->lock, kXMP_WriteLock );
+
+ XMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_ApplyTemplate_1 ( XMPMetaRef wWorkingXMP,
+ XMPMetaRef wTemplateXMP,
+ XMP_OptionBits actions,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_ApplyTemplate_1" )
+
+ XMP_Assert ( (wWorkingXMP != 0) && (wTemplateXMP != 0) ); // Client glue enforced.
+
+ XMPMeta * workingXMP = WtoXMPMeta_Ptr ( wWorkingXMP );
+ XMP_AutoLock workingLock ( &workingXMP->lock, kXMP_WriteLock );
+
+ const XMPMeta & templateXMP = WtoXMPMeta_Ref ( wTemplateXMP );
+ XMP_AutoLock templateLock ( &templateXMP.lock, kXMP_ReadLock );
+
+ XMPUtils::ApplyTemplate ( workingXMP, templateXMP, actions );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_RemoveProperties_1 ( XMPMetaRef wxmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_RemoveProperties_1" )
+
+ if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( schemaNS == 0 ) schemaNS = "";
+ if ( propName == 0 ) propName = "";
+
+ XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj );
+ XMP_AutoLock metaLock ( &xmpObj->lock, kXMP_WriteLock );
+
+ XMPUtils::RemoveProperties ( xmpObj, schemaNS, propName, options );
+
+ XMP_EXIT
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+void
+WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef wSource,
+ XMPMetaRef wDest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_Static ( "WXMPUtils_DuplicateSubtree_1" )
+
+ if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
+ if ( (sourceNS == 0) || (*sourceNS == 0) ) XMP_Throw ( "Empty source schema URI", kXMPErr_BadSchema );
+ if ( (sourceRoot == 0) || (*sourceRoot == 0) ) XMP_Throw ( "Empty source root name", kXMPErr_BadXPath );
+ if ( destNS == 0 ) destNS = sourceNS;
+ if ( destRoot == 0 ) destRoot = sourceRoot;
+
+ const XMPMeta & source = WtoXMPMeta_Ref ( wSource );
+ XMP_AutoLock sourceLock ( &source.lock, kXMP_ReadLock, (wSource != wDest) );
+
+ XMPMeta * dest = WtoXMPMeta_Ptr ( wDest );
+ XMP_AutoLock destLock ( &dest->lock, kXMP_WriteLock );
+
+ XMPUtils::DuplicateSubtree ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options );
+
+ XMP_EXIT
+}
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/gpr/source/lib/xmp_core/XMLParserAdapter.hpp b/gpr/source/lib/xmp_core/XMLParserAdapter.hpp
new file mode 100644
index 0000000..ff9b877
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMLParserAdapter.hpp
@@ -0,0 +1,155 @@
+#ifndef __XMLParserAdapter_hpp__
+#define __XMLParserAdapter_hpp__
+
+// =================================================================================================
+// Copyright 2005 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "public/include/XMP_Const.h"
+
+#include "XMP_LibUtils.hpp"
+
+#include <string>
+#include <vector>
+
+// =================================================================================================
+// XML_Node details
+//
+// The XML_Nodes are used only during the XML/RDF parsing process. This presently uses an XML parser
+// to create an XML tree, then a recursive descent RDF recognizer to build the corresponding XMP.
+// This makes it easier to swap XML parsers and provides a clean separation of XML and RDF issues.
+// The overall parsing would be faster and use less memory if the RDF recognition were done on the
+// fly using a state machine. But it was much easier to write the recursive descent version. The
+// current implementation is pretty fast in absolute terms, so being faster might not be crucial.
+//
+// Like the XMP tree, the XML tree contains vectors of pointers for down links, and offspring have
+// a pointer to their parent. Unlike the XMP tree, this is an exact XML document tree. There are no
+// introduced top level namespace nodes or rearrangement of the nodes..
+//
+// The exact state of namespaces can vary during the XML parsing, depending on the parser in use.
+// By the time the RDF recognition is done though, the namespaces must be normalized. All of the
+// used namespaces must be registered, this is done automatically if necessary. All of the "live"
+// namespace prefixes will be unique. The ns field of an XML_Node is the namespace URI, the name
+// field contains a qualified name (prefix:local). This includes default namespace mapping, the
+// URI and prefix will be missing only for elements and attributes in no namespace.
+
+class XML_Node;
+
+typedef XML_Node * XML_NodePtr; // Handy for things like: XML_Node * a, b; - b is XML_Node, not XML_Node*!
+
+enum { kRootNode = 0, kElemNode = 1, kAttrNode = 2, kCDataNode = 3, kPINode = 4 };
+
+#define IsWhitespaceChar(ch) ( ((ch) == ' ') || ((ch) == 0x09) || ((ch) == 0x0A) || ((ch) == 0x0D) )
+
+typedef std::vector<XML_NodePtr> XML_NodeVector;
+typedef XML_NodeVector::iterator XML_NodePos;
+typedef XML_NodeVector::const_iterator XML_cNodePos;
+
+#if 0 // Pattern for iterating over the children or attributes:
+ for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) {
+ const XML_NodePtr _curr_ = _node_->_offspring_[xxNum];
+ }
+#endif
+
+class XML_Node {
+public:
+
+ // Intended for lightweight internal use. Clients are expected to use the data directly.
+
+ XMP_Uns8 kind;
+ std::string ns, name, value;
+ size_t nsPrefixLen;
+ XML_NodePtr parent;
+ XML_NodeVector attrs;
+ XML_NodeVector content;
+
+ bool IsWhitespaceNode() const;
+ bool IsLeafContentNode() const; // An empty element or one with a single character data child node.
+ bool IsEmptyLeafNode() const;
+
+ XMP_StringPtr GetAttrValue ( XMP_StringPtr attrName ) const;
+ void SetAttrValue ( XMP_StringPtr attrName, XMP_StringPtr attrValue );
+
+ XMP_StringPtr GetLeafContentValue() const;
+ std::string* GetLeafContentPtr() const;
+ void SetLeafContentValue ( XMP_StringPtr value );
+
+ size_t CountNamedElements ( XMP_StringPtr nsURI, XMP_StringPtr localName ) const; // Number of child elements with this name.
+ XML_NodePtr GetNamedElement ( XMP_StringPtr nsURI, XMP_StringPtr localName, size_t which = 0 );
+
+ void Dump ( std::string * buffer );
+ void Serialize ( std::string * buffer );
+
+ void RemoveAttrs();
+ void RemoveContent();
+ void ClearNode();
+
+ XML_Node ( XML_NodePtr _parent, XMP_StringPtr _name, XMP_Uns8 _kind )
+ : kind(_kind), name(_name), parent(_parent), nsPrefixLen(0) {};
+
+ XML_Node ( XML_NodePtr _parent, const std::string & _name, XMP_Uns8 _kind )
+ : kind(_kind), name(_name), parent(_parent), nsPrefixLen(0) {};
+
+ virtual ~XML_Node() { RemoveAttrs(); RemoveContent(); };
+
+private:
+
+ XML_Node() : kind(0), parent(0) {}; // ! Hidden to make sure parent pointer is always set.
+
+};
+
+// =================================================================================================
+// Abstract base class for XML parser adapters used by the XMP toolkit.
+
+enum { kXMLPendingInputMax = 16 };
+
+class XMLParserAdapter {
+public:
+
+ XMLParserAdapter() : tree(0,"",kRootNode), rootNode(0), rootCount(0),
+ charEncoding(XMP_OptionBits(-1)), pendingCount(0),
+ errorCallback(0)
+ {
+ #if XMP_DebugBuild
+ parseLog = 0;
+ #endif
+ };
+
+ virtual ~XMLParserAdapter() {};
+
+ virtual void ParseBuffer ( const void * buffer, size_t length, bool last ) = 0;
+
+ virtual void SetErrorCallback ( GenericErrorCallback * ec )
+ { this->errorCallback = ec; };
+
+ virtual void NotifyClient ( XMP_ErrorSeverity severity, XMP_Error & error )
+ {
+ if (this->errorCallback)
+ this->errorCallback->NotifyClient( severity, error );
+ }
+
+ XML_Node tree;
+ XML_NodeVector parseStack;
+ XML_NodePtr rootNode;
+ size_t rootCount;
+
+ XMP_OptionBits charEncoding;
+ size_t pendingCount;
+ unsigned char pendingInput[kXMLPendingInputMax]; // Buffered input for character encoding checks.
+
+ GenericErrorCallback * errorCallback; // Set if the relevant XMPCore or XMPFiles object has one.
+
+ #if XMP_DebugBuild
+ FILE * parseLog;
+ #endif
+
+};
+
+// =================================================================================================
+
+#endif // __XMLParserAdapter_hpp__
diff --git a/gpr/source/lib/xmp_core/XML_Node.cpp b/gpr/source/lib/xmp_core/XML_Node.cpp
new file mode 100644
index 0000000..c7ac1ce
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XML_Node.cpp
@@ -0,0 +1,473 @@
+// =================================================================================================
+// Copyright 2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "XMLParserAdapter.hpp"
+
+#include <map>
+#include <cstring>
+#include <cstdio>
+
+// ! Can't include XMP..._Impl.hpp - used by both Core and Files.
+#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0)
+
+#if XMP_WinBuild
+ #define snprintf _snprintf
+ #pragma warning ( disable : 4996 ) // snprintf is safe
+#endif
+
+// =================================================================================================
+
+#if 0 // Pattern for iterating over the children or attributes:
+ for ( size_t xxNum = 0, xxLim = _node_->_offspring_->size(); xxNum < xxLim; ++xxNum ) {
+ const XML_NodePtr _curr_ = _node_->_offspring_[xxNum];
+ }
+#endif
+
+// =================================================================================================
+// XML_Node::IsWhitespaceNode
+//===========================
+
+bool XML_Node::IsWhitespaceNode() const
+{
+ if ( this->kind != kCDataNode ) return false;
+
+ for ( size_t i = 0; i < this->value.size(); ++i ) {
+ unsigned char ch = this->value[i];
+ if ( IsWhitespaceChar ( ch ) ) continue;
+ // *** Add checks for other whitespace characters.
+ return false; // All the checks failed, this isn't whitespace.
+ }
+
+ return true;
+
+} // XML_Node::IsWhitespaceNode
+
+// =================================================================================================
+// XML_Node::IsLeafContentNode
+//============================
+
+bool XML_Node::IsLeafContentNode() const
+{
+ if ( this->kind != kElemNode ) return false;
+ if ( this->content.size() == 0 ) return true;
+ if ( this->content.size() > 1 ) return false;
+ if ( this->content[0]->kind != kCDataNode ) return false;
+
+ return true;
+
+} // XML_Node::IsLeafContentNode
+
+// =================================================================================================
+// XML_Node::IsEmptyLeafNode
+//==========================
+
+bool XML_Node::IsEmptyLeafNode() const
+{
+
+ if ( (this->kind != kElemNode) || (this->content.size() != 0) ) return false;
+ return true;
+
+} // XML_Node::IsEmptyLeafNode
+
+// =================================================================================================
+// XML_Node::GetAttrValue
+//=======================
+
+XMP_StringPtr XML_Node::GetAttrValue ( XMP_StringPtr attrName ) const
+{
+
+ for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) {
+ XML_Node * attrPtr = this->attrs[i];
+ if ( ! attrPtr->ns.empty() ) continue; // This form of GetAttrValue is for attrs in no namespace.
+ if ( attrPtr->name == attrName ) return attrPtr->value.c_str();
+ }
+
+ return 0; // Not found.
+
+} // XML_Node::GetAttrValue
+
+// =================================================================================================
+// XML_Node::SetAttrValue
+//=======================
+
+void XML_Node::SetAttrValue ( XMP_StringPtr attrName, XMP_StringPtr attrValue )
+{
+
+ for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) {
+ XML_Node * attrPtr = this->attrs[i];
+ if ( ! attrPtr->ns.empty() ) continue; // This form of SetAttrValue is for attrs in no namespace.
+ if ( attrPtr->name == attrName ) {
+ attrPtr->value = attrValue;
+ return;
+ }
+ }
+
+} // XML_Node::SetAttrValue
+
+// =================================================================================================
+// XML_Node::GetLeafContentValue
+//==============================
+
+XMP_StringPtr XML_Node::GetLeafContentValue() const
+{
+ if ( (! this->IsLeafContentNode()) || this->content.empty() ) return "";
+
+ return this->content[0]->value.c_str();
+
+} // XML_Node::GetLeafContentValue
+
+// =================================================================================================
+// XML_Node::GetLeafContentValue
+//==============================
+
+std::string* XML_Node::GetLeafContentPtr() const
+{
+ if ( (! this->IsLeafContentNode()) || this->content.empty() ) return 0;
+
+ return &this->content[0]->value;
+
+} // XML_Node::GetLeafContentValue
+
+// =================================================================================================
+// XML_Node::SetLeafContentValue
+//==============================
+
+void XML_Node::SetLeafContentValue ( XMP_StringPtr newValue )
+{
+ XML_Node * valueNode;
+
+ if ( ! this->content.empty() ) {
+ valueNode = this->content[0];
+ } else {
+ valueNode = new XML_Node ( this, "", kCDataNode );
+ this->content.push_back ( valueNode );
+ }
+
+ valueNode->value = newValue;
+
+} // XML_Node::SetLeafContentValue
+
+// =================================================================================================
+// XML_Node::CountNamedElements
+//=============================
+
+size_t XML_Node::CountNamedElements ( XMP_StringPtr nsURI, XMP_StringPtr localName ) const
+{
+ size_t count = 0;
+
+ for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) {
+ const XML_Node & child = *this->content[i];
+ if ( child.ns != nsURI ) continue;
+ if ( strcmp ( localName, child.name.c_str()+child.nsPrefixLen ) != 0 ) continue;
+ ++count;
+ }
+
+ return count;
+
+} // XML_Node::CountNamedElements
+
+// =================================================================================================
+// XML_Node::GetNamedElement
+//==========================
+
+XML_NodePtr XML_Node::GetNamedElement ( XMP_StringPtr nsURI, XMP_StringPtr localName, size_t which /* = 0 */ )
+{
+
+ for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) {
+ XML_Node * childPtr = this->content[i];
+ if ( childPtr->ns != nsURI ) continue;
+ if ( strcmp ( localName, childPtr->name.c_str()+childPtr->nsPrefixLen ) != 0 ) continue;
+ if ( which == 0 ) return childPtr;
+ --which;
+ }
+
+ return 0; /// Not found.
+
+} // XML_Node::GetNamedElement
+
+// =================================================================================================
+// DumpNodeList
+// ============
+
+static const char * kNodeKinds[] = { "root", "elem", "attr", "cdata", "pi" };
+
+static void DumpNodeList ( std::string * buffer, const XML_NodeVector & list, int indent )
+{
+
+ for ( size_t i = 0, limit = list.size(); i < limit; ++i ) {
+
+ const XML_Node * node = list[i];
+
+ for ( int t = indent; t > 0; --t ) *buffer += " ";
+ if ( node->IsWhitespaceNode() ) {
+ *buffer += "-- whitespace --\n";
+ continue;
+ }
+
+ *buffer += node->name;
+ *buffer += " - ";
+ *buffer += kNodeKinds[node->kind];
+ if ( ! node->value.empty() ) {
+ *buffer += ", value=\"";
+ *buffer += node->value;
+ *buffer += "\"";
+ }
+ if ( ! node->ns.empty() ) {
+ *buffer += ", ns=\"";
+ *buffer += node->ns;
+ *buffer += "\"";
+ }
+ if ( node->nsPrefixLen != 0 ) {
+ *buffer += ", prefixLen=";
+ char numBuf [20];
+ snprintf ( numBuf, sizeof(numBuf), "%d", (int)node->nsPrefixLen );
+ *buffer += numBuf;
+ }
+ *buffer += "\n";
+
+ if ( ! node->attrs.empty() ) {
+ for ( int t = indent+1; t > 0; --t ) *buffer += " ";
+ *buffer += "attrs:\n";
+ DumpNodeList ( buffer, node->attrs, indent+2 );
+ }
+
+ if ( ! node->content.empty() ) {
+ DumpNodeList ( buffer, node->content, indent+1 );
+ }
+
+ }
+
+} // DumpNodeList
+
+// =================================================================================================
+// XML_Node::Dump
+//===============
+
+void XML_Node::Dump ( std::string * buffer )
+{
+
+ *buffer = "Dump of XML_Node tree\n";
+
+ *buffer += "Root info: name=\"";
+ *buffer += this->name;
+ *buffer += "\", value=\"";
+ *buffer += this->value;
+ *buffer += "\", ns=\"";
+ *buffer += this->ns;
+ *buffer += "\", kind=";
+ *buffer += kNodeKinds[this->kind];
+ *buffer += "\n";
+
+ if ( ! this->attrs.empty() ) {
+ *buffer += " attrs:\n";
+ DumpNodeList ( buffer, this->attrs, 2 );
+ }
+ *buffer += "\n";
+
+ DumpNodeList ( buffer, this->content, 0 );
+
+} // XML_Node::Dump
+
+// =================================================================================================
+// SerializeOneNode
+// ================
+
+static void SerializeOneNode ( std::string * buffer, const XML_Node & node )
+{
+ size_t i, limit;
+ XMP_StringPtr namePtr = node.name.c_str();
+ if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces.
+
+ switch ( node.kind ) {
+
+ case kElemNode:
+ *buffer += '<';
+ *buffer += namePtr;
+ for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) {
+ SerializeOneNode ( buffer, *node.attrs[i] );
+ }
+ if ( node.content.empty() ) {
+ *buffer += "/>";
+ } else {
+ *buffer += '>';
+ for ( i = 0, limit = node.content.size(); i < limit; ++i ) {
+ SerializeOneNode ( buffer, *node.content[i] );
+ }
+ *buffer += "</";
+ *buffer += namePtr;
+ *buffer += '>';
+ }
+ break;
+
+ case kAttrNode:
+ *buffer += ' ';
+ *buffer += namePtr;
+ *buffer += "=\"";
+ *buffer += node.value;
+ *buffer += '"';
+ break;
+
+ case kCDataNode:
+ *buffer += node.value;
+ break;
+
+ case kPINode:
+ *buffer += node.value; // *** Note that we're dropping PIs during the Expat parse.
+ break;
+
+ }
+
+} // SerializeOneNode
+
+// =================================================================================================
+// CollectNamespaceDecls
+// =====================
+
+typedef std::map < std::string, std::string > NamespaceMap;
+
+static void CollectNamespaceDecls ( NamespaceMap * nsMap, const XML_Node & node )
+{
+ size_t i, limit;
+
+ if ( ! node.ns.empty() ) {
+ size_t nameMid = 0;
+ while ( node.name[nameMid] != ':' ) ++nameMid;
+ std::string prefix = node.name.substr ( 0, nameMid );
+ (*nsMap)[prefix] = node.ns;
+ }
+
+ if ( node.kind == kElemNode ) {
+
+ for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) {
+ CollectNamespaceDecls ( nsMap, *node.attrs[i] );
+ }
+
+ for ( i = 0, limit = node.content.size(); i < limit; ++i ) {
+ const XML_Node & content = *node.content[i];
+ if ( content.kind == kElemNode ) CollectNamespaceDecls ( nsMap, content );
+ }
+
+ }
+
+} // CollectNamespaceDecls
+
+// =================================================================================================
+// XML_Node::Serialize
+//====================
+
+void XML_Node::Serialize ( std::string * buffer )
+{
+ buffer->erase();
+
+ if ( this->kind != kRootNode ) {
+
+ SerializeOneNode ( buffer, *this );
+
+ } else {
+
+ // Do the outermost level here, in order to add the XML version and namespace declarations.
+
+ *buffer += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+
+ for ( size_t outer = 0, oLimit = this->content.size(); outer < oLimit; ++outer ) {
+
+ const XML_Node & node = *this->content[outer];
+
+ if ( node.kind != kElemNode ) {
+
+ SerializeOneNode ( buffer, node );
+
+ } else {
+
+ XMP_StringPtr namePtr = node.name.c_str();
+ if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces.
+
+ *buffer += '<';
+ *buffer += namePtr;
+
+ NamespaceMap nsMap;
+ CollectNamespaceDecls ( &nsMap, node );
+ NamespaceMap::iterator nsDecl = nsMap.begin();
+ NamespaceMap::iterator nsEnd = nsMap.end();
+ for ( ; nsDecl != nsEnd; ++nsDecl ) {
+ const std::string & prefix = nsDecl->first;
+ *buffer += " xmlns";
+ if ( prefix != "_dflt_" ) { *buffer += ':'; *buffer += prefix; }
+ *buffer += "=\"";
+ *buffer += nsDecl->second;
+ *buffer += '"';
+ }
+
+ for ( size_t attr = 0, aLimit = node.attrs.size(); attr < aLimit; ++attr ) {
+ SerializeOneNode ( buffer, *node.attrs[attr] );
+ }
+
+ if ( node.content.empty() ) {
+ *buffer += "/>";
+ } else {
+ *buffer += '>';
+ for ( size_t child = 0, cLimit = node.content.size(); child < cLimit; ++child ) {
+ SerializeOneNode ( buffer, *node.content[child] );
+ }
+ *buffer += "</";
+ *buffer += namePtr;
+ *buffer += '>';
+ }
+
+ }
+
+ }
+
+ }
+
+
+} // XML_Node::Serialize
+
+// =================================================================================================
+// XML_Node::RemoveAttrs
+//======================
+
+void XML_Node::RemoveAttrs()
+{
+
+ for ( size_t i = 0, vLim = this->attrs.size(); i < vLim; ++i ) delete this->attrs[i];
+ this->attrs.clear();
+
+} // XML_Node::RemoveAttrs
+
+// =================================================================================================
+// XML_Node::RemoveContent
+//========================
+
+void XML_Node::RemoveContent()
+{
+
+ for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) delete this->content[i];
+ this->content.clear();
+
+} // XML_Node::RemoveContent
+
+// =================================================================================================
+// XML_Node::ClearNode
+//====================
+
+void XML_Node::ClearNode()
+{
+
+ this->kind = 0;
+ this->ns.erase();
+ this->name.erase();
+ this->value.erase();
+
+ this->RemoveAttrs();
+ this->RemoveContent();
+
+} // XML_Node::ClearNode
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPCore_Impl.cpp b/gpr/source/lib/xmp_core/XMPCore_Impl.cpp
new file mode 100644
index 0000000..f98b717
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPCore_Impl.cpp
@@ -0,0 +1,1390 @@
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <algorithm>
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "public/include/XMP_Version.h"
+#include "XMPCore_Impl.hpp"
+#include "XMPMeta.hpp" // *** For use of GetNamespacePrefix in FindSchemaNode.
+
+#include "UnicodeInlines.incl_cpp"
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4290 ) // C++ exception specification ignored except ... not __declspec(nothrow)
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+// =================================================================================================
+// Static Variables
+// ================
+
+XMP_Int32 sXMP_InitCount = 0;
+
+XMP_NamespaceTable * sRegisteredNamespaces = 0;
+
+XMP_AliasMap * sRegisteredAliasMap = 0;
+
+void * voidVoidPtr = 0; // Used to backfill null output parameters.
+XMP_StringPtr voidStringPtr = 0;
+XMP_StringLen voidStringLen = 0;
+XMP_OptionBits voidOptionBits = 0;
+XMP_Uns8 voidByte = 0;
+bool voidBool = 0;
+XMP_Int32 voidInt32 = 0;
+XMP_Int64 voidInt64 = 0;
+double voidDouble = 0.0;
+XMP_DateTime voidDateTime;
+WXMP_Result void_wResult;
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+// -------------------------------------------------------------------------------------------------
+// VerifyXPathRoot
+// ---------------
+//
+// Set up the first 2 components of the expanded XPath. Normalizes the various cases of using the
+// full schema URI and/or a qualified root property name. Returns true for normal processing. If
+// allowUnknownSchemaNS is true and the schema namespace is not registered, false is returned. If
+// allowUnknownSchemaNS is false and the schema namespace is not registered, an exception is thrown.
+
+// *** Should someday check the full syntax.
+
+static void
+VerifyXPathRoot ( XMP_StringPtr schemaURI,
+ XMP_StringPtr propName,
+ XMP_ExpandedXPath * expandedXPath )
+{
+ // Do some basic checks on the URI and name. Try to lookup the URI. See if the name is qualified.
+
+ XMP_Assert ( (schemaURI != 0) && (propName != 0) && (*propName != 0) );
+ XMP_Assert ( (expandedXPath != 0) && (expandedXPath->empty()) );
+
+ if ( *schemaURI == 0 ) XMP_Throw ( "Schema namespace URI is required", kXMPErr_BadSchema );
+
+ if ( (*propName == '?') || (*propName == '@') ) {
+ XMP_Throw ( "Top level name must not be a qualifier", kXMPErr_BadXPath );
+ }
+ for ( XMP_StringPtr ch = propName; *ch != 0; ++ch ) {
+ if ( (*ch == '/') || (*ch == '[') ) {
+ XMP_Throw ( "Top level name must be simple", kXMPErr_BadXPath );
+ }
+ }
+
+ XMP_StringPtr schemaPrefix;
+ bool nsFound = sRegisteredNamespaces->GetPrefix ( schemaURI, &schemaPrefix, 0 );
+ if ( ! nsFound ) XMP_Throw ( "Unregistered schema namespace URI", kXMPErr_BadSchema );
+
+ XMP_StringPtr colonPos = propName;
+ while ( (*colonPos != 0) && (*colonPos != ':') ) ++colonPos;
+ VerifySimpleXMLName ( propName, colonPos ); // Verify the part before any colon.
+
+ // Verify the various URI and prefix combinations. Initialize the expanded XPath.
+
+ if ( *colonPos == 0 ) {
+
+ // The propName is unqualified, use the schemaURI and associated prefix.
+
+ expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) );
+ expandedXPath->push_back ( XPathStepInfo ( schemaPrefix, 0 ) );
+ (*expandedXPath)[kRootPropStep].step += propName;
+
+ } else {
+
+ // The propName is qualified. Make sure the prefix is legit. Use the associated URI and qualified name.
+
+ size_t prefixLen = colonPos - propName + 1; // ! Include the colon.
+ VerifySimpleXMLName ( colonPos+1, colonPos+strlen(colonPos) );
+
+ XMP_VarString prefix ( propName, prefixLen );
+ if ( prefix != schemaPrefix ) XMP_Throw ( "Schema namespace URI and prefix mismatch", kXMPErr_BadSchema );
+
+ expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) );
+ expandedXPath->push_back ( XPathStepInfo ( propName, 0 ) );
+
+ }
+
+} // VerifyXPathRoot
+
+// -------------------------------------------------------------------------------------------------
+// VerifyQualName
+// --------------
+
+static void
+VerifyQualName ( XMP_StringPtr qualName, XMP_StringPtr nameEnd )
+{
+ if ( qualName >= nameEnd ) XMP_Throw ( "Empty qualified name", kXMPErr_BadXPath );
+
+ XMP_StringPtr colonPos = qualName;
+ while ( (colonPos < nameEnd) && (*colonPos != ':') ) ++colonPos;
+ if ( (colonPos == qualName) || (colonPos >= nameEnd) ) XMP_Throw ( "Ill-formed qualified name", kXMPErr_BadXPath );
+
+ VerifySimpleXMLName ( qualName, colonPos );
+ VerifySimpleXMLName ( colonPos+1, nameEnd );
+
+ size_t prefixLen = colonPos - qualName + 1; // ! Include the colon.
+ XMP_VarString prefix ( qualName, prefixLen );
+ bool nsFound = sRegisteredNamespaces->GetURI ( prefix.c_str(), 0, 0 );
+ if ( ! nsFound ) XMP_Throw ( "Unknown namespace prefix for qualified name", kXMPErr_BadXPath );
+
+} // VerifyQualName
+
+// -------------------------------------------------------------------------------------------------
+// FindIndexedItem
+// ---------------
+//
+// [index] An element of an array.
+//
+// Support the implicit creation of a new last item.
+
+static XMP_Index
+FindIndexedItem ( XMP_Node * arrayNode, const XMP_VarString & indexStep, bool createNodes )
+{
+ XMP_Index index = 0;
+ size_t chLim = indexStep.size() - 1;
+
+ XMP_Assert ( (chLim >= 2) && (indexStep[0] == '[') && (indexStep[chLim] == ']') );
+
+ for ( size_t chNum = 1; chNum != chLim; ++chNum ) {
+ XMP_Assert ( ('0' <= indexStep[chNum]) && (indexStep[chNum] <= '9') );
+ index = (index * 10) + (indexStep[chNum] - '0');
+ if ( index < 0 ) {
+ XMP_Throw ( "Array index overflow", kXMPErr_BadXPath ); // ! Overflow, not truly negative.
+ }
+ }
+
+ --index; // Change to a C-style, zero based index.
+ if ( index < 0 ) XMP_Throw ( "Array index must be larger than zero", kXMPErr_BadXPath );
+
+ if ( (index == (XMP_Index)arrayNode->children.size()) && createNodes ) { // Append a new last+1 node.
+ XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, kXMP_NewImplicitNode );
+ arrayNode->children.push_back ( newItem );
+ }
+
+ // ! Don't throw here for a too large index. SetProperty will throw, GetProperty will not.
+ if ( index >= (XMP_Index)arrayNode->children.size() ) index = -1;
+ return index;
+
+} // FindIndexedItem
+
+// -------------------------------------------------------------------------------------------------
+// SplitNameAndValue
+// -----------------
+//
+// Split the name and value parts for field and qualifier selectors:
+//
+// [qualName="value"] An element in an array of structs, chosen by a field value.
+// [?qualName="value"] An element in an array, chosen by a qualifier value.
+//
+// The value portion is a string quoted by ''' or '"'. The value may contain any character including
+// a doubled quoting character. The value may be empty.
+
+static void
+SplitNameAndValue ( const XMP_VarString & selStep, XMP_VarString * nameStr, XMP_VarString * valueStr )
+{
+ XMP_StringPtr partBegin = selStep.c_str();
+ XMP_StringPtr partEnd;
+
+ const XMP_StringPtr valueEnd = partBegin + (selStep.size() - 2);
+ const char quote = *valueEnd;
+
+ XMP_Assert ( (*partBegin == '[') && (*(valueEnd+1) == ']') );
+ XMP_Assert ( (selStep.size() >= 6) && ((quote == '"') || (quote == '\'')) );
+
+ // Extract the name part.
+
+ ++partBegin; // Skip the opening '['.
+ if ( *partBegin == '?' ) ++partBegin;
+ for ( partEnd = partBegin+1; *partEnd != '='; ++partEnd ) {};
+
+ nameStr->assign ( partBegin, (partEnd - partBegin) );
+
+ // Extract the value part, reducing doubled quotes.
+
+ XMP_Assert ( *(partEnd+1) == quote );
+
+ partBegin = partEnd + 2;
+ valueStr->erase();
+ valueStr->reserve ( valueEnd - partBegin ); // Maximum length, don't optimize doubled quotes.
+
+ for ( partEnd = partBegin; partEnd < valueEnd; ++partEnd ) {
+ if ( (*partEnd == quote) && (*(partEnd+1) == quote) ) {
+ ++partEnd;
+ valueStr->append ( partBegin, (partEnd - partBegin) );
+ partBegin = partEnd+1; // ! Loop will increment partEnd again.
+ }
+ }
+
+ valueStr->append ( partBegin, (partEnd - partBegin) ); // ! The loop does not add the last part.
+
+} // SplitNameAndValue
+
+// -------------------------------------------------------------------------------------------------
+// LookupQualSelector
+// ------------------
+//
+// [?qualName="value"] An element in an array, chosen by a qualifier value.
+//
+// Note that we don't create implicit nodes for qualifier selectors, so no CreateNodes parameter.
+
+static XMP_Index
+LookupQualSelector ( XMP_Node * arrayNode, const XMP_VarString & qualName, XMP_VarString & qualValue )
+{
+ XMP_Index index;
+
+ if ( qualName == "xml:lang" ) {
+
+ // *** Should check that the value is legit RFC 1766/3066.
+ NormalizeLangValue ( &qualValue );
+ index = LookupLangItem ( arrayNode, qualValue ) ;
+
+ } else {
+
+ XMP_Index itemLim;
+ for ( index = 0, itemLim = arrayNode->children.size(); index != itemLim; ++index ) {
+
+ const XMP_Node * currItem = arrayNode->children[index];
+ XMP_Assert ( currItem->parent == arrayNode );
+
+ size_t q, qualLim;
+ for ( q = 0, qualLim = currItem->qualifiers.size(); q != qualLim; ++q ) {
+ const XMP_Node * currQual = currItem->qualifiers[q];
+ XMP_Assert ( currQual->parent == currItem );
+ if ( currQual->name != qualName ) continue;
+ if ( currQual->value == qualValue ) break; // Exit qual loop.
+ }
+ if ( q != qualLim ) break; // Exit child loop, found an item with a matching qualifier.
+
+ }
+ if ( index == itemLim ) index = -1;
+
+ }
+
+ return index;
+
+} // LookupQualSelector
+
+// -------------------------------------------------------------------------------------------------
+// FollowXPathStep
+// ---------------
+//
+// After processing by ExpandXPath, a step can be of these forms:
+// qualName A top level property or struct field.
+// [index] An element of an array.
+// [last()] The last element of an array.
+// [qualName="value"] An element in an array of structs, chosen by a field value.
+// [?qualName="value"] An element in an array, chosen by a qualifier value.
+// ?qualName A general qualifier.
+//
+// Find the appropriate child node, resolving aliases, and optionally creating nodes.
+
+static XMP_Node *
+FollowXPathStep ( XMP_Node * parentNode,
+ const XMP_ExpandedXPath & fullPath,
+ size_t stepNum,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos,
+ bool aliasedArrayItem = false )
+{
+ XMP_Node * nextNode = 0;
+ const XPathStepInfo & nextStep = fullPath[stepNum];
+ XMP_Index index = 0;
+ XMP_OptionBits stepKind = nextStep.options & kXMP_StepKindMask;
+
+ XMP_Assert ( (kXMP_StructFieldStep <= stepKind) && (stepKind <= kXMP_FieldSelectorStep) );
+
+ if ( stepKind == kXMP_StructFieldStep ) {
+
+ nextNode = FindChildNode ( parentNode, nextStep.step.c_str(), createNodes, ptrPos );
+
+ } else if ( stepKind == kXMP_QualifierStep ) {
+
+ XMP_StringPtr qualStep = nextStep.step.c_str();
+ XMP_Assert ( *qualStep == '?' );
+ ++qualStep;
+ nextNode = FindQualifierNode ( parentNode, qualStep, createNodes, ptrPos );
+
+ } else {
+
+ // This is an array indexing step. First get the index, then get the node.
+
+ if ( ! (parentNode->options & kXMP_PropValueIsArray) ) {
+ XMP_Throw ( "Indexing applied to non-array", kXMPErr_BadXPath );
+ }
+
+ if ( stepKind == kXMP_ArrayIndexStep ) {
+ index = FindIndexedItem ( parentNode, nextStep.step, createNodes );
+ } else if ( stepKind == kXMP_ArrayLastStep ) {
+ index = parentNode->children.size() - 1;
+ } else if ( stepKind == kXMP_FieldSelectorStep ) {
+ XMP_VarString fieldName, fieldValue;
+ SplitNameAndValue ( nextStep.step, &fieldName, &fieldValue );
+ index = LookupFieldSelector ( parentNode, fieldName.c_str(), fieldValue.c_str() );
+ } else if ( stepKind == kXMP_QualSelectorStep ) {
+ XMP_VarString qualName, qualValue;
+ SplitNameAndValue ( nextStep.step, &qualName, &qualValue );
+ index = LookupQualSelector ( parentNode, qualName, qualValue );
+ } else {
+ XMP_Throw ( "Unknown array indexing step in FollowXPathStep", kXMPErr_InternalFailure );
+ }
+
+ if ( (0 <= index) && (index <= (XMP_Index)parentNode->children.size()) ) nextNode = parentNode->children[index];
+
+ if ( (index == -1) && createNodes && aliasedArrayItem && (stepKind == kXMP_QualSelectorStep) ) {
+
+ // An ugly special case without an obvious better place to be. We have an alias to the
+ // x-default item of an alt-text array. A simple reference via SetProperty must create
+ // the x-default item if it does not yet exist.
+
+ XMP_Assert ( parentNode->options & kXMP_PropArrayIsAltText );
+ XMP_Assert ( (stepNum == 2) && (nextStep.step == "[?xml:lang=\"x-default\"]") );
+
+ nextNode = new XMP_Node ( parentNode, kXMP_ArrayItemName,
+ (kXMP_PropHasQualifiers | kXMP_PropHasLang | kXMP_NewImplicitNode) );
+
+ XMP_Node * langQual = new XMP_Node ( nextNode, "xml:lang", "x-default", kXMP_PropIsQualifier );
+ nextNode->qualifiers.push_back ( langQual );
+
+ if ( parentNode->children.empty() ) {
+ parentNode->children.push_back ( nextNode );
+ } else {
+ parentNode->children.insert ( parentNode->children.begin(), nextNode );
+ }
+
+ index = 0; // ! C-style index! The x-default item is always first.
+
+ }
+
+ if ( (nextNode != 0) && (ptrPos != 0) ) *ptrPos = parentNode->children.begin() + index;
+
+ }
+
+ if ( (nextNode != 0) && (nextNode->options & kXMP_NewImplicitNode) ) {
+ nextNode->options |= (nextStep.options & kXMP_PropArrayFormMask);
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (nextNode == 0) || (nextNode == **ptrPos) );
+ XMP_Assert ( (nextNode != 0) || (! createNodes) );
+ return nextNode;
+
+} // FollowXPathStep
+
+// -------------------------------------------------------------------------------------------------
+// CheckImplicitStruct
+// -------------------
+
+static inline void
+CheckImplicitStruct ( XMP_Node * node,
+ const XMP_ExpandedXPath & expandedXPath,
+ size_t stepNum,
+ size_t stepLim )
+{
+
+ if ( (stepNum < stepLim) &&
+ ((node->options & kXMP_PropCompositeMask) == 0) &&
+ (GetStepKind ( expandedXPath[stepNum].options ) == kXMP_StructFieldStep) ) {
+
+ node->options |= kXMP_PropValueIsStruct;
+
+ }
+
+} // CheckImplicitStruct
+
+// -------------------------------------------------------------------------------------------------
+// DeleteSubtree
+// -------------
+
+void
+DeleteSubtree ( XMP_NodePtrPos rootNodePos )
+{
+ XMP_Node * rootNode = *rootNodePos;
+ XMP_Node * rootParent = rootNode->parent;
+
+ if ( ! (rootNode->options & kXMP_PropIsQualifier) ) {
+
+ rootParent->children.erase ( rootNodePos );
+
+ } else {
+
+ rootParent->qualifiers.erase ( rootNodePos );
+
+ XMP_Assert ( rootParent->options & kXMP_PropHasQualifiers);
+ if ( rootParent->qualifiers.empty() ) rootParent->options ^= kXMP_PropHasQualifiers;
+
+ if ( rootNode->name == "xml:lang" ) {
+ XMP_Assert ( rootParent->options & kXMP_PropHasLang);
+ rootParent->options ^= kXMP_PropHasLang;
+ } else if ( rootNode->name == "rdf:type" ) {
+ XMP_Assert ( rootParent->options & kXMP_PropHasType);
+ rootParent->options ^= kXMP_PropHasType;
+ }
+
+ }
+
+ delete rootNode;
+
+} // DeleteSubtree
+
+// =================================================================================================
+// =================================================================================================
+
+// =================================================================================================
+// VerifySetOptions
+// ================
+//
+// Normalize and verify the option flags for SetProperty and similar functions. The allowed options
+// here are just those that apply to the property, that would be kept in the XMP_Node. Others that
+// affect the selection of the node or other processing must be removed by now. These are:
+// kXMP_InsertBeforeItem
+// kXMP_InsertAfterItem
+// kXMP_KeepQualifiers
+// kXMPUtil_AllowCommas
+
+enum {
+ kXMP_AllSetOptionsMask = (kXMP_PropValueIsURI |
+ kXMP_PropValueIsStruct |
+ kXMP_PropValueIsArray |
+ kXMP_PropArrayIsOrdered |
+ kXMP_PropArrayIsAlternate |
+ kXMP_PropArrayIsAltText |
+ kXMP_DeleteExisting)
+};
+
+XMP_OptionBits
+VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue )
+{
+
+ if ( options & kXMP_PropArrayIsAltText ) options |= kXMP_PropArrayIsAlternate;
+ if ( options & kXMP_PropArrayIsAlternate ) options |= kXMP_PropArrayIsOrdered;
+ if ( options & kXMP_PropArrayIsOrdered ) options |= kXMP_PropValueIsArray;
+
+ if ( options & ~kXMP_AllSetOptionsMask ) {
+ XMP_Throw ( "Unrecognized option flags", kXMPErr_BadOptions );
+ }
+
+ if ( (options & kXMP_PropValueIsStruct) && (options & kXMP_PropValueIsArray) ) {
+ XMP_Throw ( "IsStruct and IsArray options are mutually exclusive", kXMPErr_BadOptions );
+ }
+
+ if ( (options & kXMP_PropValueOptionsMask) && (options & kXMP_PropCompositeMask) ) {
+ XMP_Throw ( "Structs and arrays can't have \"value\" options", kXMPErr_BadOptions );
+ }
+
+ if ( (propValue != 0) && (options & kXMP_PropCompositeMask) ) {
+ XMP_Throw ( "Structs and arrays can't have string values", kXMPErr_BadOptions );
+ }
+
+ return options;
+
+} // VerifySetOptions
+
+// =================================================================================================
+// ComposeXPath
+// ============
+//
+// Compose the canonical string form of an expanded XPath expression.
+
+extern void
+ComposeXPath ( const XMP_ExpandedXPath & expandedXPath,
+ XMP_VarString * stringXPath )
+{
+ *stringXPath = expandedXPath[kRootPropStep].step;
+
+ for ( size_t index = kRootPropStep+1; index < expandedXPath.size(); ++index ) {
+ const XPathStepInfo & currStep = expandedXPath[index];
+
+ switch ( currStep.options & kXMP_StepKindMask ) {
+
+ case kXMP_StructFieldStep :
+ case kXMP_QualifierStep :
+ *stringXPath += '/';
+ *stringXPath += currStep.step;
+ break;
+
+ case kXMP_ArrayIndexStep :
+ case kXMP_ArrayLastStep :
+ case kXMP_QualSelectorStep :
+ case kXMP_FieldSelectorStep :
+ *stringXPath += currStep.step;
+ break;
+
+ default:
+ XMP_Throw ( "Unexpected", kXMPErr_InternalFailure );
+
+ }
+
+ }
+
+} // ComposeXPath
+
+// =================================================================================================
+// ExpandXPath
+// ===========
+//
+// Split an XPath expression apart at the conceptual steps, adding the root namespace prefix to the
+// first property component. The schema URI is put in the first (0th) slot in the expanded XPath.
+// Check if the top level component is an alias, but don't resolve it.
+//
+// In the most verbose case steps are separated by '/', and each step can be of these forms:
+//
+// qualName A top level property or struct field.
+// *[index] An element of an array.
+// *[last()] The last element of an array.
+// *[fieldName="value"] An element in an array of structs, chosen by a field value.
+// *[@xml:lang="value"] An element in an alt-text array, chosen by the xml:lang qualifier.
+// *[?qualName="value"] An element in an array, chosen by a qualifier value.
+// @xml:lang An xml:lang qualifier.
+// ?qualName A general qualifier.
+//
+// The logic is complicated though by shorthand for arrays, the separating '/' and leading '*'
+// are optional. These are all equivalent: array/*[2] array/[2] array*[2] array[2]
+// All of these are broken into the 2 steps "array" and "[2]".
+//
+// The value portion in the array selector forms is a string quoted by ''' or '"'. The value
+// may contain any character including a doubled quoting character. The value may be empty.
+//
+// The syntax isn't checked, but an XML name begins with a letter or '_', and contains letters,
+// digits, '.', '-', '_', and a bunch of special non-ASCII Unicode characters. An XML qualified
+// name is a pair of names separated by a colon.
+
+void
+ExpandXPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propPath,
+ XMP_ExpandedXPath * expandedXPath )
+{
+ XMP_Assert ( (schemaNS != 0) && (propPath != 0) && (*propPath != 0) && (expandedXPath != 0) );
+
+ XMP_StringPtr stepBegin, stepEnd;
+ XMP_StringPtr qualName, nameEnd;
+ XMP_VarString currStep;
+
+ size_t resCount = 2; // Guess at the number of steps. At least 2, plus 1 for each '/' or '['.
+ for ( stepEnd = propPath; *stepEnd != 0; ++stepEnd ) {
+ if ( (*stepEnd == '/') || (*stepEnd == '[') ) ++resCount;
+ }
+
+ expandedXPath->clear();
+ expandedXPath->reserve ( resCount );
+
+ // -------------------------------------------------------------------------------------------
+ // Pull out the first component and do some special processing on it: add the schema namespace
+ // prefix and see if it is an alias. The start must be a qualName.
+
+ stepBegin = propPath;
+ stepEnd = stepBegin;
+ while ( (*stepEnd != 0) && (*stepEnd != '/') && (*stepEnd != '[') && (*stepEnd != '*') ) ++stepEnd;
+ if ( stepEnd == stepBegin ) XMP_Throw ( "Empty initial XPath step", kXMPErr_BadXPath );
+ currStep.assign ( stepBegin, (stepEnd - stepBegin) );
+
+ VerifyXPathRoot ( schemaNS, currStep.c_str(), expandedXPath );
+
+ XMP_OptionBits stepFlags = kXMP_StructFieldStep;
+ if ( sRegisteredAliasMap->find ( (*expandedXPath)[kRootPropStep].step ) != sRegisteredAliasMap->end() ) {
+ stepFlags |= kXMP_StepIsAlias;
+ }
+ (*expandedXPath)[kRootPropStep].options |= stepFlags;
+
+ // -----------------------------------------------------
+ // Now continue to process the rest of the XPath string.
+
+ while ( *stepEnd != 0 ) {
+
+ stepBegin = stepEnd;
+ if ( *stepBegin == '/' ) ++stepBegin;
+ if ( *stepBegin == '*' ) {
+ ++stepBegin;
+ if ( *stepBegin != '[' ) XMP_Throw ( "Missing '[' after '*'", kXMPErr_BadXPath );
+ }
+ stepEnd = stepBegin;
+
+ if ( *stepBegin != '[' ) {
+
+ // A struct field or qualifier.
+ qualName = stepBegin;
+ while ( (*stepEnd != 0) && (*stepEnd != '/') && (*stepEnd != '[') && (*stepEnd != '*') ) ++stepEnd;
+ nameEnd = stepEnd;
+ stepFlags = kXMP_StructFieldStep; // ! Touch up later, also changing '@' to '?'.
+
+ } else {
+
+ // One of the array forms.
+
+ ++stepEnd; // Look at the character after the leading '['.
+
+ if ( ('0' <= *stepEnd) && (*stepEnd <= '9') ) {
+
+ // A numeric (decimal integer) array index.
+ while ( (*stepEnd != 0) && ('0' <= *stepEnd) && (*stepEnd <= '9') ) ++stepEnd;
+ if ( *stepEnd != ']' ) XMP_Throw ( "Missing ']' for integer array index", kXMPErr_BadXPath );
+ stepFlags = kXMP_ArrayIndexStep;
+
+ } else {
+
+ // Could be "[last()]" or one of the selector forms. Find the ']' or '='.
+
+ while ( (*stepEnd != 0) && (*stepEnd != ']') && (*stepEnd != '=') ) ++stepEnd;
+ if ( *stepEnd == 0 ) XMP_Throw ( "Missing ']' or '=' for array index", kXMPErr_BadXPath );
+
+ if ( *stepEnd == ']' ) {
+
+ if ( strncmp ( "[last()", stepBegin, (stepEnd - stepBegin) ) != 0 ) {
+ XMP_Throw ( "Invalid non-numeric array index", kXMPErr_BadXPath );
+ }
+ stepFlags = kXMP_ArrayLastStep;
+
+ } else {
+
+ qualName = stepBegin+1;
+ nameEnd = stepEnd;
+ ++stepEnd; // Absorb the '=', remember the quote.
+ const char quote = *stepEnd;
+ if ( (quote != '\'') && (quote != '"') ) {
+ XMP_Throw ( "Invalid quote in array selector", kXMPErr_BadXPath );
+ }
+
+ ++stepEnd; // Absorb the leading quote.
+ while ( *stepEnd != 0 ) {
+ if ( *stepEnd == quote ) {
+ if ( *(stepEnd+1) != quote ) break;
+ ++stepEnd;
+ }
+ ++stepEnd;
+ }
+ if ( *stepEnd == 0 ) {
+ XMP_Throw ( "No terminating quote for array selector", kXMPErr_BadXPath );
+ }
+ ++stepEnd; // Absorb the trailing quote.
+
+ stepFlags = kXMP_FieldSelectorStep; // ! Touch up later, also changing '@' to '?'.
+
+ }
+
+ }
+
+ if ( *stepEnd != ']' ) XMP_Throw ( "Missing ']' for array index", kXMPErr_BadXPath );
+ ++stepEnd;
+
+ }
+
+ if ( stepEnd == stepBegin ) XMP_Throw ( "Empty XPath step", kXMPErr_BadXPath );
+ currStep.assign ( stepBegin, (stepEnd - stepBegin) );
+
+ if ( GetStepKind ( stepFlags ) == kXMP_StructFieldStep ) {
+
+ if ( currStep[0] == '@' ) {
+ currStep[0] = '?';
+ if ( currStep != "?xml:lang" ) XMP_Throw ( "Only xml:lang allowed with '@'", kXMPErr_BadXPath );
+ }
+ if ( currStep[0] == '?' ) {
+ ++qualName;
+ stepFlags = kXMP_QualifierStep;
+ }
+ VerifyQualName ( qualName, nameEnd );
+
+ } else if ( GetStepKind ( stepFlags ) == kXMP_FieldSelectorStep ) {
+
+ if ( currStep[1] == '@' ) {
+ currStep[1] = '?';
+ if ( strncmp ( currStep.c_str(), "[?xml:lang=", 11 ) != 0 ) {
+ XMP_Throw ( "Only xml:lang allowed with '@'", kXMPErr_BadXPath );
+ }
+ }
+ if ( currStep[1] == '?' ) {
+ ++qualName;
+ stepFlags = kXMP_QualSelectorStep;
+ }
+ VerifyQualName ( qualName, nameEnd );
+
+ }
+
+ expandedXPath->push_back ( XPathStepInfo ( currStep, stepFlags ) );
+
+ }
+
+} // ExpandXPath
+
+// =================================================================================================
+// FindSchemaNode
+// ==============
+//
+// Find or create a schema node. Returns a pointer to the node, and optionally an iterator for the
+// node's position in the top level vector of schema nodes. The iterator is unchanged if no schema
+// node (null) is returned.
+
+XMP_Node *
+FindSchemaNode ( XMP_Node * xmpTree,
+ XMP_StringPtr nsURI,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos /* = 0 */ )
+{
+ XMP_Node * schemaNode = 0;
+
+ XMP_Assert ( xmpTree->parent == 0 );
+
+ for ( size_t schemaNum = 0, schemaLim = xmpTree->children.size(); schemaNum != schemaLim; ++schemaNum ) {
+ XMP_Node * currSchema = xmpTree->children[schemaNum];
+ XMP_Assert ( currSchema->parent == xmpTree );
+ if ( currSchema->name == nsURI ) {
+ schemaNode = currSchema;
+ if ( ptrPos != 0 ) *ptrPos = xmpTree->children.begin() + schemaNum;
+ break;
+ }
+ }
+
+ if ( (schemaNode == 0) && createNodes ) {
+
+ schemaNode = new XMP_Node ( xmpTree, nsURI, (kXMP_SchemaNode | kXMP_NewImplicitNode) );
+
+ try {
+ XMP_StringPtr prefixPtr;
+ XMP_StringLen prefixLen;
+ bool found = XMPMeta::GetNamespacePrefix ( nsURI, &prefixPtr, &prefixLen ); // *** Use map directly?
+ XMP_Assert ( found );
+ schemaNode->value.assign ( prefixPtr, prefixLen );
+ } catch (...) { // Don't leak schemaNode in case of an exception before adding it to the children vector.
+ delete schemaNode;
+ throw;
+ }
+
+ xmpTree->children.push_back ( schemaNode );
+ if ( ptrPos != 0 ) *ptrPos = xmpTree->children.end() - 1;
+
+ #if 0 // *** XMP_DebugBuild
+ schemaNode->_valuePtr = schemaNode->value.c_str();
+ #endif
+
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (schemaNode == 0) || (schemaNode == **ptrPos) );
+ XMP_Assert ( (schemaNode != 0) || (! createNodes) );
+ return schemaNode;
+
+} // FindSchemaNode
+
+// =================================================================================================
+// FindChildNode
+// =============
+//
+// Find or create a child node under a given parent node. Returns a pointer to the child node, and
+// optionally an iterator for the node's position in the parent's vector of children. The iterator
+// is unchanged if no child node (null) is returned.
+
+XMP_Node *
+FindChildNode ( XMP_Node * parent,
+ XMP_StringPtr childName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos /* = 0 */ )
+{
+ XMP_Node * childNode = 0;
+
+ if ( ! (parent->options & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) {
+ if ( ! (parent->options & kXMP_NewImplicitNode) ) {
+ XMP_Throw ( "Named children only allowed for schemas and structs", kXMPErr_BadXPath );
+ }
+ if ( parent->options & kXMP_PropValueIsArray ) {
+ XMP_Throw ( "Named children not allowed for arrays", kXMPErr_BadXPath );
+ }
+ if ( ! createNodes ) { // *** Should be assert? If !createNodes, why is the parent a new implicit node?
+ XMP_Throw ( "Parent is new implicit node, but createNodes is false", kXMPErr_InternalFailure );
+ }
+ parent->options |= kXMP_PropValueIsStruct;
+ }
+
+ for ( size_t childNum = 0, childLim = parent->children.size(); childNum != childLim; ++childNum ) {
+ XMP_Node * currChild = parent->children[childNum];
+ XMP_Assert ( currChild->parent == parent );
+ if ( currChild->name == childName ) {
+ childNode = currChild;
+ if ( ptrPos != 0 ) *ptrPos = parent->children.begin() + childNum;
+ break;
+ }
+ }
+
+ if ( (childNode == 0) && createNodes ) {
+ childNode = new XMP_Node ( parent, childName, kXMP_NewImplicitNode );
+ parent->children.push_back ( childNode );
+ if ( ptrPos != 0 ) *ptrPos = parent->children.end() - 1;
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (childNode == 0) || (childNode == **ptrPos) );
+ XMP_Assert ( (childNode != 0) || (! createNodes) );
+ return childNode;
+
+} // FindChildNode
+
+// =================================================================================================
+// FindQualifierNode
+// =================
+//
+// Find or create a qualifier node under a given parent node. Returns a pointer to the qualifier node,
+// and optionally an iterator for the node's position in the parent's vector of qualifiers. The iterator
+// is unchanged if no qualifier node (null) is returned.
+//
+// ! On entry, the qualName parameter must not have the leading '?' from the XPath step.
+
+XMP_Node *
+FindQualifierNode ( XMP_Node * parent,
+ XMP_StringPtr qualName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos /* = 0 */ ) // *** Require ptrPos internally & remove checks?
+{
+ XMP_Node * qualNode = 0;
+
+ XMP_Assert ( *qualName != '?' );
+
+ for ( size_t qualNum = 0, qualLim = parent->qualifiers.size(); qualNum != qualLim; ++qualNum ) {
+ XMP_Node * currQual = parent->qualifiers[qualNum];
+ XMP_Assert ( currQual->parent == parent );
+ if ( currQual->name == qualName ) {
+ qualNode = currQual;
+ if ( ptrPos != 0 ) *ptrPos = parent->qualifiers.begin() + qualNum;
+ break;
+ }
+ }
+
+ if ( (qualNode == 0) && createNodes ) {
+
+ qualNode = new XMP_Node ( parent, qualName, (kXMP_PropIsQualifier | kXMP_NewImplicitNode) );
+ parent->options |= kXMP_PropHasQualifiers;
+
+ const bool isLang = XMP_LitMatch ( qualName, "xml:lang" );
+ const bool isType = XMP_LitMatch ( qualName, "rdf:type" );
+ const bool isSpecial = isLang | isType;
+
+ if ( isLang ) {
+ parent->options |= kXMP_PropHasLang;
+ } else if ( isType ) {
+ parent->options |= kXMP_PropHasType;
+ }
+
+ if ( parent->qualifiers.empty() || (! isSpecial) ) {
+ parent->qualifiers.push_back ( qualNode );
+ if ( ptrPos != 0 ) *ptrPos = parent->qualifiers.end() - 1;
+ } else {
+ XMP_NodePtrPos insertPos = parent->qualifiers.begin(); // ! Lang goes first, type after.
+ if ( isType && (parent->options & kXMP_PropHasLang) ) ++insertPos; // *** Does insert at end() work?
+ insertPos = parent->qualifiers.insert ( insertPos, qualNode );
+ if ( ptrPos != 0 ) *ptrPos = insertPos;
+ }
+
+ }
+
+ XMP_Assert ( (ptrPos == 0) || (qualNode == 0) || (qualNode == **ptrPos) );
+ XMP_Assert ( (qualNode != 0) || (! createNodes) );
+ return qualNode;
+
+} // FindQualifierNode
+
+// =================================================================================================
+// LookupFieldSelector
+// ===================
+//
+// [fieldName="value"] An element in an array of structs, chosen by a field value.
+//
+// Note that we don't create implicit nodes for field selectors, so no CreateNodes parameter.
+
+XMP_Index
+LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue )
+{
+ XMP_Index index, itemLim;
+
+ for ( index = 0, itemLim = arrayNode->children.size(); index != itemLim; ++index ) {
+
+ const XMP_Node * currItem = arrayNode->children[index];
+ XMP_Assert ( currItem->parent == arrayNode );
+
+ if ( ! (currItem->options & kXMP_PropValueIsStruct) ) {
+ XMP_Throw ( "Field selector must be used on array of struct", kXMPErr_BadXPath );
+ }
+
+ size_t f, fieldLim;
+ for ( f = 0, fieldLim = currItem->children.size(); f != fieldLim; ++f ) {
+ const XMP_Node * currField = currItem->children[f];
+ XMP_Assert ( currField->parent == currItem );
+ if ( currField->name != fieldName ) continue;
+ if ( currField->value == fieldValue ) break; // Exit qual loop.
+ }
+ if ( f != fieldLim ) break; // Exit child loop, found an item with a matching qualifier.
+
+ }
+
+ if ( index == itemLim ) index = -1;
+ return index;
+
+} // LookupFieldSelector
+
+// =================================================================================================
+// LookupLangItem
+// ==============
+//
+// ! Assumes that the language value is already normalized.
+
+XMP_Index
+LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang )
+{
+ if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) { // *** Check for alt-text?
+ XMP_Throw ( "Language item must be used on array", kXMPErr_BadXPath );
+ }
+
+ XMP_Index index = 0;
+ XMP_Index itemLim = arrayNode->children.size();
+
+ for ( ; index != itemLim; ++index ) {
+ const XMP_Node * currItem = arrayNode->children[index];
+ XMP_Assert ( currItem->parent == arrayNode );
+ if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) continue;
+ if ( currItem->qualifiers[0]->value == lang ) break;
+ }
+
+ if ( index == itemLim ) index = -1;
+ return index;
+
+} // LookupLangItem
+
+// =================================================================================================
+// FindNode
+// ========
+//
+// Follow an expanded path expression to find or create a node. Returns a pointer to the node, and
+// optionally an iterator for the node's position in the parent's vector of children or qualifiers.
+// The iterator is unchanged if no child node (null) is returned.
+
+XMP_Node *
+FindNode ( XMP_Node * xmpTree,
+ const XMP_ExpandedXPath & expandedXPath,
+ bool createNodes,
+ XMP_OptionBits leafOptions /* = 0 */,
+ XMP_NodePtrPos * ptrPos /* = 0 */ )
+{
+ XMP_Node * currNode = 0;
+ XMP_NodePtrPos currPos;
+ XMP_NodePtrPos newSubPos; // Root of implicitly created subtree. Valid only if leaf is new.
+ bool leafIsNew = false;
+
+ XMP_Assert ( (leafOptions == 0) || createNodes );
+
+ if ( expandedXPath.empty() ) XMP_Throw ( "Empty XPath", kXMPErr_BadXPath );
+
+ size_t stepNum = 1; // By default start calling FollowXPathStep for the top level property step.
+ size_t stepLim = expandedXPath.size();
+
+ // The start of processing deals with the schema node and top level alias. If the top level step
+ // is not an alias, lookup the expanded path's schema URI. Otherwise, lookup the expanded path
+ // for the actual. While tempting, don't substitute the actual's path into the local one, don't
+ // risk messing with the caller's use of that. Also don't call FindNode recursively, we need to
+ // keep track of the root of the implicitly created subtree as we move down the path.
+
+ if ( ! (expandedXPath[kRootPropStep].options & kXMP_StepIsAlias) ) {
+
+ currNode = FindSchemaNode ( xmpTree, expandedXPath[kSchemaStep].step.c_str(), createNodes, &currPos );
+ if ( currNode == 0 ) return 0;
+
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+
+ } else {
+
+ stepNum = 2; // ! Continue processing the original path at the second level step.
+
+ XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find ( expandedXPath[kRootPropStep].step );
+ XMP_Assert ( aliasPos != sRegisteredAliasMap->end() );
+
+ currNode = FindSchemaNode ( xmpTree, aliasPos->second[kSchemaStep].step.c_str(), createNodes, &currPos );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+
+ currNode = FollowXPathStep ( currNode, aliasPos->second, 1, createNodes, &currPos );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ CheckImplicitStruct ( currNode, expandedXPath, 2, stepLim );
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+
+ XMP_OptionBits arrayForm = aliasPos->second[kRootPropStep].options & kXMP_PropArrayFormMask;
+ XMP_Assert ( (arrayForm == 0) || (arrayForm & kXMP_PropValueIsArray) );
+ XMP_Assert ( (arrayForm == 0) ? (aliasPos->second.size() == 2) : (aliasPos->second.size() == 3) );
+
+ if ( arrayForm != 0 ) {
+ currNode = FollowXPathStep ( currNode, aliasPos->second, 2, createNodes, &currPos, true );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ CheckImplicitStruct ( currNode, expandedXPath, 2, stepLim );
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+ }
+
+ }
+
+ // Now follow the remaining steps of the original XPath.
+
+ // *** ??? Change all the num/lim loops back to num<lim? Probably safer.
+
+ try {
+ for ( ; stepNum < stepLim; ++stepNum ) {
+ currNode = FollowXPathStep ( currNode, expandedXPath, stepNum, createNodes, &currPos );
+ if ( currNode == 0 ) goto EXIT;
+ if ( currNode->options & kXMP_NewImplicitNode ) {
+ currNode->options ^= kXMP_NewImplicitNode; // Clear the implicit node bit.
+ CheckImplicitStruct ( currNode, expandedXPath, stepNum+1, stepLim );
+ if ( ! leafIsNew ) newSubPos = currPos; // Save the top most implicit node.
+ leafIsNew = true; // If any parent is new, the leaf will be new also.
+ }
+ }
+ } catch ( ... ) {
+ if ( leafIsNew ) DeleteSubtree ( newSubPos );
+ throw;
+ }
+
+ // Done. Delete the implicitly created subtree if the eventual node was not found.
+
+EXIT:
+
+ XMP_Assert ( (currNode == 0) || (currNode == *currPos) );
+ XMP_Assert ( (currNode != 0) || (! createNodes) );
+
+ if ( leafIsNew ) {
+ if ( currNode != 0 ) {
+ currNode->options |= leafOptions;
+ } else {
+ DeleteSubtree ( newSubPos );
+ }
+ }
+
+ if ( (currNode != 0) && (ptrPos != 0) ) *ptrPos = currPos;
+ return currNode;
+
+} // FindNode
+
+// =================================================================================================
+// CloneOffspring
+// ==============
+
+void
+CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent, bool skipEmpty /* = false */ )
+{
+ size_t qualCount = origParent->qualifiers.size();
+ size_t childCount = origParent->children.size();
+
+ if ( qualCount > 0 ) {
+
+ cloneParent->qualifiers.reserve ( qualCount );
+
+ for ( size_t qualNum = 0, qualLim = qualCount; qualNum != qualLim; ++qualNum ) {
+ const XMP_Node * origQual = origParent->qualifiers[qualNum];
+ if ( skipEmpty && origQual->value.empty() && origQual->children.empty() ) continue;
+ XMP_Node * cloneQual = new XMP_Node ( cloneParent, origQual->name, origQual->value, origQual->options );
+ CloneOffspring ( origQual, cloneQual, skipEmpty );
+ if ( skipEmpty && cloneQual->value.empty() && cloneQual->children.empty() ) {
+ // Check again, might have had an array or struct with all empty children.
+ delete cloneQual;
+ continue;
+ }
+ cloneParent->qualifiers.push_back ( cloneQual );
+ }
+
+ }
+
+ if ( childCount > 0 ) {
+
+ cloneParent->children.reserve ( childCount );
+
+ for ( size_t childNum = 0, childLim = childCount; childNum != childLim; ++childNum ) {
+ const XMP_Node * origChild = origParent->children[childNum];
+ if ( skipEmpty && origChild->value.empty() && origChild->children.empty() ) continue;
+ XMP_Node * cloneChild = new XMP_Node ( cloneParent, origChild->name, origChild->value, origChild->options );
+ CloneOffspring ( origChild, cloneChild, skipEmpty );
+ if ( skipEmpty && cloneChild->value.empty() && cloneChild->children.empty() ) {
+ // Check again, might have had an array or struct with all empty children.
+ delete cloneChild;
+ continue;
+ }
+ cloneParent->children.push_back ( cloneChild );
+ }
+
+ }
+
+} // CloneOffspring
+
+// =================================================================================================
+// CloneSubtree
+// ============
+
+XMP_Node *
+CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent, bool skipEmpty /* = false */ )
+{
+ #if XMP_DebugBuild
+ if ( cloneParent->parent == 0 ) {
+ XMP_Assert ( origRoot->options & kXMP_SchemaNode );
+ XMP_Assert ( FindConstSchema ( cloneParent, origRoot->name.c_str() ) == 0 );
+ } else {
+ XMP_Assert ( ! (origRoot->options & kXMP_SchemaNode) );
+ if ( cloneParent->options & kXMP_PropValueIsStruct ) { // Might be an array.
+ XMP_Assert ( FindConstChild ( cloneParent, origRoot->name.c_str() ) == 0 );
+ }
+ }
+ #endif
+
+ XMP_Node * cloneRoot = new XMP_Node ( cloneParent, origRoot->name, origRoot->value, origRoot->options );
+ CloneOffspring ( origRoot, cloneRoot, skipEmpty ) ;
+
+ if ( skipEmpty && cloneRoot->value.empty() && cloneRoot->children.empty() ) {
+ // ! Can't do earlier, CloneOffspring might be skipping empty children.
+ delete cloneRoot;
+ return 0;
+ }
+
+ cloneParent->children.push_back ( cloneRoot );
+ return cloneRoot;
+
+} // CloneSubtree
+
+// =================================================================================================
+// CompareSubtrees
+// ===============
+//
+// Compare 2 subtrees for semantic equality. The comparison includes value, qualifiers, and form.
+// Schemas, top level properties, struct fields, and qualifiers are allowed to have differing order,
+// the appropriate right node is found from the left node's name. Alt-text arrays are allowed to be
+// in differing language order, other arrays are compared in order.
+
+// *** Might someday consider sorting unordered arrays.
+// *** Should expose this through XMPUtils.
+
+bool
+CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode )
+{
+ // Don't compare the names here, we want to allow the outermost roots to have different names.
+ if ( (leftNode.value != rightNode.value) ||
+ (leftNode.options != rightNode.options) ||
+ (leftNode.children.size() != rightNode.children.size()) ||
+ (leftNode.qualifiers.size() != rightNode.qualifiers.size()) ) return false;
+
+ // Compare the qualifiers, allowing them to be out of order.
+ for ( size_t qualNum = 0, qualLim = leftNode.qualifiers.size(); qualNum != qualLim; ++qualNum ) {
+ const XMP_Node * leftQual = leftNode.qualifiers[qualNum];
+ const XMP_Node * rightQual = FindConstQualifier ( &rightNode, leftQual->name.c_str() );
+ if ( (rightQual == 0) || (! CompareSubtrees ( *leftQual, *rightQual )) ) return false;
+ }
+
+ if ( (leftNode.parent == 0) || (leftNode.options & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) {
+
+ // The parent node is a tree root, a schema, or a struct.
+ for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * leftChild = leftNode.children[childNum];
+ const XMP_Node * rightChild = FindConstChild ( &rightNode, leftChild->name.c_str() );
+ if ( (rightChild == 0) || (! CompareSubtrees ( *leftChild, *rightChild )) ) return false;
+ }
+
+ } else if ( leftNode.options & kXMP_PropArrayIsAltText ) {
+
+ // The parent node is an alt-text array.
+ for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * leftChild = leftNode.children[childNum];
+ XMP_Assert ( (! leftChild->qualifiers.empty()) && (leftChild->qualifiers[0]->name == "xml:lang") );
+ XMP_Index rightIndex = LookupLangItem ( &rightNode, leftChild->qualifiers[0]->value );
+ if ( rightIndex == -1 ) return false;
+ const XMP_Node * rightChild = rightNode.children[rightIndex];
+ if ( ! CompareSubtrees ( *leftChild, *rightChild ) ) return false;
+ }
+
+ } else {
+
+ // The parent must be simple or some other (not alt-text) kind of array.
+ XMP_Assert ( (! (leftNode.options & kXMP_PropCompositeMask)) || (leftNode.options & kXMP_PropValueIsArray) );
+ for ( size_t childNum = 0, childLim = leftNode.children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * leftChild = leftNode.children[childNum];
+ const XMP_Node * rightChild = rightNode.children[childNum];
+ if ( ! CompareSubtrees ( *leftChild, *rightChild ) ) return false;
+ }
+
+ }
+
+ return true;
+
+} // CompareSubtrees
+
+// =================================================================================================
+// DeleteEmptySchema
+// =================
+
+void
+DeleteEmptySchema ( XMP_Node * schemaNode )
+{
+
+ if ( XMP_NodeIsSchema ( schemaNode->options ) && schemaNode->children.empty() ) {
+
+ XMP_Node * xmpTree = schemaNode->parent;
+
+ size_t schemaNum = 0;
+ size_t schemaLim = xmpTree->children.size();
+ while ( (schemaNum < schemaLim) && (xmpTree->children[schemaNum] != schemaNode) ) ++schemaNum;
+ XMP_Assert ( schemaNum < schemaLim );
+
+ XMP_NodePtrPos schemaPos = xmpTree->children.begin() + schemaNum;
+ XMP_Assert ( *schemaPos == schemaNode );
+
+ xmpTree->children.erase ( schemaPos );
+ delete schemaNode;
+
+ }
+
+} // DeleteEmptySchema
+
+// =================================================================================================
+// NormalizeLangValue
+// ==================
+//
+// Normalize an xml:lang value so that comparisons are effectively case insensitive as required by
+// RFC 3066 (which superceeds RFC 1766). The normalization rules:
+//
+// - The primary subtag is lower case, the suggested practice of ISO 639.
+// - All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166.
+// - All other subtags are lower case.
+
+void
+NormalizeLangValue ( XMP_VarString * value )
+{
+ char * tagStart;
+ char * tagEnd;
+
+ // Find and process the primary subtag.
+
+ tagStart = (char*) value->c_str();
+ for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) {
+ if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20;
+ }
+
+ // Find and process the secondary subtag.
+
+ tagStart = tagEnd;
+ if ( *tagStart == '-' ) ++tagStart;
+ for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) {
+ if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20;
+ }
+ if ( tagEnd == tagStart+2 ) {
+ if ( ('a' <= *tagStart) && (*tagStart <= 'z') ) *tagStart -= 0x20;
+ ++tagStart;
+ if ( ('a' <= *tagStart) && (*tagStart <= 'z') ) *tagStart -= 0x20;
+ }
+
+ // Find and process the remaining subtags.
+
+ while ( true ) {
+ tagStart = tagEnd;
+ if ( *tagStart == '-' ) ++tagStart;
+ if ( *tagStart == 0 ) break;
+ for ( tagEnd = tagStart; (*tagEnd != 0) && (*tagEnd != '-'); ++tagEnd ) {
+ if ( ('A' <= *tagEnd) && (*tagEnd <= 'Z') ) *tagEnd += 0x20;
+ }
+ }
+
+} // NormalizeLangValue
+
+// =================================================================================================
+// NormalizeLangArray
+// ==================
+//
+// Make sure the x-default item is first. Touch up "single value" arrays that have a default plus
+// one real language. This case should have the same value for both items. Older Adobe apps were
+// hardwired to only use the 'x-default' item, so we copy that value to the other item.
+
+void
+NormalizeLangArray ( XMP_Node * array )
+{
+ XMP_Assert ( XMP_ArrayIsAltText(array->options) );
+
+ size_t itemNum;
+ size_t itemLim = array->children.size();
+ bool hasDefault = false;
+
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+
+ if ( array->children[itemNum]->qualifiers.empty() ||
+ (array->children[itemNum]->qualifiers[0]->name != "xml:lang") ) {
+ XMP_Throw ( "AltText array items must have an xml:lang qualifier", kXMPErr_BadXMP );
+ }
+
+ if ( array->children[itemNum]->qualifiers[0]->value == "x-default" ) {
+ hasDefault = true;
+ break;
+ }
+
+ }
+
+ if ( hasDefault ) {
+
+ if ( itemNum != 0 ) {
+ XMP_Node * temp = array->children[0];
+ array->children[0] = array->children[itemNum];
+ array->children[itemNum] = temp;
+ }
+
+ if ( itemLim == 2 ) array->children[1]->value = array->children[0]->value;
+
+ }
+
+} // NormalizeLangArray
+
+// =================================================================================================
+// DetectAltText
+// =============
+//
+// See if an array is an alt-text array. If so, make sure the x-default item is first.
+
+void
+DetectAltText ( XMP_Node * xmpParent )
+{
+ XMP_Assert ( XMP_ArrayIsAlternate(xmpParent->options) );
+
+ size_t itemNum, itemLim;
+
+ for ( itemNum = 0, itemLim = xmpParent->children.size(); itemNum < itemLim; ++itemNum ) {
+ XMP_OptionBits currOptions = xmpParent->children[itemNum]->options;
+ if ( (currOptions & kXMP_PropCompositeMask) || (! (currOptions & kXMP_PropHasLang)) ) break;
+ }
+
+ if ( (itemLim != 0) && (itemNum == itemLim) ) {
+ xmpParent->options |= kXMP_PropArrayIsAltText;
+ NormalizeLangArray ( xmpParent );
+ }
+
+} // DetectAltText
+
+// =================================================================================================
+// SortNamedNodes
+// ==============
+//
+// Sort the pointers in an XMP_NodeOffspring vector by name.
+
+static inline bool Compare ( const XMP_Node * left, const XMP_Node * right )
+{
+ return (left->name < right->name);
+}
+
+void
+SortNamedNodes ( XMP_NodeOffspring & nodeVector )
+{
+ sort ( nodeVector.begin(), nodeVector.end(), Compare );
+} // SortNamedNodes
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPCore_Impl.hpp b/gpr/source/lib/xmp_core/XMPCore_Impl.hpp
new file mode 100644
index 0000000..d900ef8
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPCore_Impl.hpp
@@ -0,0 +1,392 @@
+#ifndef __XMPCore_Impl_hpp__
+#define __XMPCore_Impl_hpp__ 1
+
+// =================================================================================================
+// Copyright 2004 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "public/include/XMP_Const.h"
+#include "XMP_BuildInfo.h"
+#include "XMP_LibUtils.hpp"
+
+// #include "XMPCore/source/XMPMeta.hpp"
+
+#include "public/include/client-glue/WXMP_Common.hpp"
+
+#include <vector>
+#include <string>
+#include <map>
+#include <cassert>
+#include <cstring>
+#include <cstdlib>
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4244 ) // possible loss of data (temporary for 64 bit builds)
+ #pragma warning ( disable : 4267 ) // possible loss of data (temporary for 64 bit builds)
+#endif
+
+// =================================================================================================
+// Primary internal types
+
+class XMP_Node;
+class XML_Node;
+class XPathStepInfo;
+
+typedef XMP_Node * XMP_NodePtr;
+
+typedef std::vector<XMP_Node*> XMP_NodeOffspring;
+typedef XMP_NodeOffspring::iterator XMP_NodePtrPos;
+
+typedef XMP_VarString::iterator XMP_VarStringPos;
+typedef XMP_VarString::const_iterator XMP_cVarStringPos;
+
+typedef std::vector < XPathStepInfo > XMP_ExpandedXPath;
+typedef XMP_ExpandedXPath::iterator XMP_ExpandedXPathPos;
+typedef XMP_ExpandedXPath::const_iterator XMP_cExpandedXPathPos;
+
+typedef std::map < XMP_VarString, XMP_ExpandedXPath > XMP_AliasMap; // Alias name to actual path.
+typedef XMP_AliasMap::iterator XMP_AliasMapPos;
+typedef XMP_AliasMap::const_iterator XMP_cAliasMapPos;
+
+// =================================================================================================
+// General global variables and macros
+
+extern XMP_Int32 sXMP_InitCount;
+
+extern XMP_NamespaceTable * sRegisteredNamespaces;
+
+extern XMP_AliasMap * sRegisteredAliasMap;
+
+#define WtoXMPMeta_Ref(xmpRef) (const XMPMeta &) (*((XMPMeta*)(xmpRef)))
+#define WtoXMPMeta_Ptr(xmpRef) ((XMPMeta*)(xmpRef))
+
+#define WtoXMPDocOps_Ptr(docRef) ((XMPDocOps*)(docRef))
+
+extern void * voidVoidPtr; // Used to backfill null output parameters.
+extern XMP_StringPtr voidStringPtr;
+extern XMP_StringLen voidStringLen;
+extern XMP_OptionBits voidOptionBits;
+extern XMP_Bool voidByte;
+extern bool voidBool;
+extern XMP_Int32 voidInt32;
+extern XMP_Int64 voidInt64;
+extern double voidDouble;
+extern XMP_DateTime voidDateTime;
+extern WXMP_Result void_wResult;
+
+#define kHexDigits "0123456789ABCDEF"
+
+#define XMP_LitMatch(s,l) (strcmp((s),(l)) == 0)
+#define XMP_LitNMatch(s,l,n) (strncmp((s),(l),(n)) == 0)
+ // *** Use the above macros!
+
+#if XMP_WinBuild
+ #define snprintf _snprintf
+#endif
+
+// =================================================================================================
+// Version info
+
+#if XMP_DebugBuild
+ #define kXMPCore_DebugFlag 1
+#else
+ #define kXMPCore_DebugFlag 0
+#endif
+
+#define kXMPCore_VersionNumber ( (kXMPCore_DebugFlag << 31) | \
+ (XMP_API_VERSION_MAJOR << 24) | \
+ (XMP_API_VERSION_MINOR << 16) | \
+ (XMP_API_VERSION_MICRO << 8) )
+
+ #define kXMPCoreName "XMP Core"
+ #define kXMPCore_VersionMessage kXMPCoreName " " XMPCORE_API_VERSION_STRING
+// =================================================================================================
+// Support for call tracing
+
+#ifndef XMP_TraceCoreCalls
+ #define XMP_TraceCoreCalls 0
+ #define XMP_TraceCoreCallsToFile 0
+#endif
+
+#if XMP_TraceCoreCalls
+
+ #undef AnnounceThrow
+ #undef AnnounceCatch
+
+ #undef AnnounceEntry
+ #undef AnnounceNoLock
+ #undef AnnounceExit
+
+ extern FILE * xmpCoreLog;
+
+ #define AnnounceThrow(msg) \
+ fprintf ( xmpCoreLog, "XMP_Throw: %s\n", msg ); fflush ( xmpCoreLog )
+ #define AnnounceCatch(msg) \
+ fprintf ( xmpCoreLog, "Catch in %s: %s\n", procName, msg ); fflush ( xmpCoreLog )
+
+ #define AnnounceEntry(proc) \
+ const char * procName = proc; \
+ fprintf ( xmpCoreLog, "Entering %s\n", procName ); fflush ( xmpCoreLog )
+ #define AnnounceNoLock(proc) \
+ const char * procName = proc; \
+ fprintf ( xmpCoreLog, "Entering %s (no lock)\n", procName ); fflush ( xmpCoreLog )
+ #define AnnounceExit() \
+ fprintf ( xmpCoreLog, "Exiting %s\n", procName ); fflush ( xmpCoreLog )
+
+#endif
+
+// =================================================================================================
+// ExpandXPath, FindNode, and related support
+
+// *** Normalize the use of "const xx &" for input params
+
+#define kXMP_ArrayItemName "[]"
+
+#define kXMP_CreateNodes true
+#define kXMP_ExistingOnly false
+
+#define FindConstSchema(t,u) FindSchemaNode ( const_cast<XMP_Node*>(t), u, kXMP_ExistingOnly, 0 )
+#define FindConstChild(p,c) FindChildNode ( const_cast<XMP_Node*>(p), c, kXMP_ExistingOnly, 0 )
+#define FindConstQualifier(p,c) FindQualifierNode ( const_cast<XMP_Node*>(p), c, kXMP_ExistingOnly, 0 )
+#define FindConstNode(t,p) FindNode ( const_cast<XMP_Node*>(t), p, kXMP_ExistingOnly, 0 )
+
+extern XMP_OptionBits
+VerifySetOptions ( XMP_OptionBits options, XMP_StringPtr propValue );
+
+extern void
+ComposeXPath ( const XMP_ExpandedXPath & expandedXPath,
+ XMP_VarString * stringXPath );
+
+extern void
+ExpandXPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propPath,
+ XMP_ExpandedXPath * expandedXPath );
+
+extern XMP_Node *
+FindSchemaNode ( XMP_Node * xmpTree,
+ XMP_StringPtr nsURI,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Node *
+FindChildNode ( XMP_Node * parent,
+ XMP_StringPtr childName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Node *
+FindQualifierNode ( XMP_Node * parent,
+ XMP_StringPtr qualName,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Node *
+FindNode ( XMP_Node * xmpTree,
+ const XMP_ExpandedXPath & expandedXPath,
+ bool createNodes,
+ XMP_OptionBits leafOptions = 0,
+ XMP_NodePtrPos * ptrPos = 0 );
+
+extern XMP_Index
+LookupLangItem ( const XMP_Node * arrayNode, XMP_VarString & lang ); // ! Lang must be normalized!
+
+extern XMP_Index
+LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue );
+
+extern void
+CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent, bool skipEmpty = false );
+
+extern XMP_Node *
+CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent, bool skipEmpty = false );
+
+extern bool
+CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode );
+
+extern void
+DeleteSubtree ( XMP_NodePtrPos rootNodePos );
+
+extern void
+DeleteEmptySchema ( XMP_Node * schemaNode );
+
+extern void
+NormalizeLangValue ( XMP_VarString * value );
+
+extern void
+NormalizeLangArray ( XMP_Node * array );
+
+extern void
+DetectAltText ( XMP_Node * xmpParent );
+
+extern void
+SortNamedNodes ( XMP_NodeOffspring & nodeVector );
+
+static inline bool
+IsPathPrefix ( XMP_StringPtr fullPath, XMP_StringPtr prefix )
+{
+ bool isPrefix = false;
+ XMP_StringLen prefixLen = strlen(prefix);
+ if ( XMP_LitNMatch ( prefix, fullPath, prefixLen ) ) {
+ char separator = fullPath[prefixLen];
+ if ( (separator == 0) || (separator == '/') ||
+ (separator == '[') || (separator == '*') ) isPrefix = true;
+ }
+ return isPrefix;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+class XPathStepInfo {
+public:
+ XMP_VarString step;
+ XMP_OptionBits options;
+ XPathStepInfo ( XMP_StringPtr _step, XMP_OptionBits _options ) : step(_step), options(_options) {};
+ XPathStepInfo ( XMP_VarString _step, XMP_OptionBits _options ) : step(_step), options(_options) {};
+private:
+ XPathStepInfo() : options(0) {}; // ! Hide the default constructor.
+};
+
+enum { kSchemaStep = 0, kRootPropStep = 1, kAliasIndexStep = 2 };
+
+enum { // Bits for XPathStepInfo options. // *** Add mask check to init code.
+ kXMP_StepKindMask = 0x0F, // ! The step kinds are mutually exclusive numbers.
+ kXMP_StructFieldStep = 0x01, // Also for top level nodes (schema "fields").
+ kXMP_QualifierStep = 0x02, // ! Order is significant to separate struct/qual from array kinds!
+ kXMP_ArrayIndexStep = 0x03, // ! The kinds must not overlay array form bits!
+ kXMP_ArrayLastStep = 0x04,
+ kXMP_QualSelectorStep = 0x05,
+ kXMP_FieldSelectorStep = 0x06,
+ kXMP_StepIsAlias = 0x10
+};
+
+#define GetStepKind(f) ((f) & kXMP_StepKindMask)
+
+#define kXMP_NewImplicitNode kXMP_InsertAfterItem
+
+// =================================================================================================
+// XMP_Node details
+
+#if 0 // Pattern for iterating over the children or qualifiers:
+ for ( size_t xxNum = 0, xxLim = _node_->_offspring_.size(); xxNum < xxLim; ++xxNum ) {
+ const XMP_Node * _curr_ = _node_->_offspring_[xxNum];
+ }
+#endif
+
+class XMP_Node {
+public:
+
+ XMP_OptionBits options;
+ XMP_VarString name, value;
+ XMP_Node * parent;
+ XMP_NodeOffspring children;
+ XMP_NodeOffspring qualifiers;
+ #if XMP_DebugBuild
+ // *** XMP_StringPtr _namePtr, _valuePtr; // *** Not working, need operator=?
+ #endif
+
+ XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options )
+ : options(_options), name(_name), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options )
+ : options(_options), name(_name), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ XMP_Node ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options )
+ : options(_options), name(_name), value(_value), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ XMP_Node ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options )
+ : options(_options), name(_name), value(_value), parent(_parent)
+ {
+ #if XMP_DebugBuild
+ XMP_Assert ( (name.find ( ':' ) != XMP_VarString::npos) || (name == kXMP_ArrayItemName) ||
+ (options & kXMP_SchemaNode) || (parent == 0) );
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+ void GetLocalURI ( XMP_StringPtr * uriStr, XMP_StringLen * uriSize ) const;
+
+ void RemoveChildren()
+ {
+ for ( size_t i = 0, vLim = children.size(); i < vLim; ++i ) {
+ if ( children[i] != 0 ) delete children[i];
+ }
+ children.clear();
+ }
+
+ void RemoveQualifiers()
+ {
+ for ( size_t i = 0, vLim = qualifiers.size(); i < vLim; ++i ) {
+ if ( qualifiers[i] != 0 ) delete qualifiers[i];
+ }
+ qualifiers.clear();
+ }
+
+ void ClearNode()
+ {
+ options = 0;
+ name.erase();
+ value.erase();
+ this->RemoveChildren();
+ this->RemoveQualifiers();
+ }
+
+ virtual ~XMP_Node() { RemoveChildren(); RemoveQualifiers(); };
+
+private:
+ XMP_Node() : options(0), parent(0) // ! Make sure parent pointer is always set.
+ {
+ #if XMP_DebugBuild
+ // *** _namePtr = name.c_str();
+ // *** _valuePtr = value.c_str();
+ #endif
+ };
+
+};
+
+class XMP_AutoNode { // Used to hold a child during subtree construction.
+public:
+ XMP_Node * nodePtr;
+ XMP_AutoNode() : nodePtr(0) {};
+ ~XMP_AutoNode() { if ( nodePtr != 0 ) delete ( nodePtr ); nodePtr = 0; };
+ XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {};
+ XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _options ) ) {};
+ XMP_AutoNode ( XMP_Node * _parent, XMP_StringPtr _name, XMP_StringPtr _value, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {};
+ XMP_AutoNode ( XMP_Node * _parent, const XMP_VarString & _name, const XMP_VarString & _value, XMP_OptionBits _options )
+ : nodePtr ( new XMP_Node ( _parent, _name, _value, _options ) ) {};
+};
+
+// =================================================================================================
+
+#endif // __XMPCore_Impl_hpp__
diff --git a/gpr/source/lib/xmp_core/XMPIterator.cpp b/gpr/source/lib/xmp_core/XMPIterator.cpp
new file mode 100644
index 0000000..229cd8f
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPIterator.cpp
@@ -0,0 +1,637 @@
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPIterator.hpp"
+
+#include <string>
+#include <stdio.h> // For snprintf.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+// Support Routines
+// =================================================================================================
+
+
+#ifndef TraceIterators
+ #define TraceIterators 0
+#endif
+
+#if TraceIterators
+ static const char * sStageNames[] = { "before", "self", "qualifiers", "children" };
+#endif
+
+static XMP_Node * sDummySchema = 0; // ! Used for some ugliness with aliases.
+
+// -------------------------------------------------------------------------------------------------
+// AddSchemaProps
+// --------------
+//
+// Add the top level properties to the IterNode for a schema.
+
+static void
+AddSchemaProps ( IterInfo & info, IterNode & iterSchema, const XMP_Node * xmpSchema )
+{
+ #if TraceIterators
+ printf ( " Adding properties of %s\n", xmpSchema->name.c_str() );
+ #endif
+
+ for ( size_t propNum = 0, propLim = xmpSchema->children.size(); propNum != propLim; ++propNum ) {
+ const XMP_Node * xmpProp = xmpSchema->children[propNum];
+ // *** set the has-aliases bit when appropriate
+ iterSchema.children.push_back ( IterNode ( xmpProp->options, xmpProp->name, 0 ) );
+ #if TraceIterators
+ printf ( " %s\n", xmpProp->name.c_str() );
+ #endif
+ }
+
+} // AddSchemaProps
+
+// -------------------------------------------------------------------------------------------------
+// AddNodeOffspring
+// ----------------
+//
+// Add the immediate children and qualifiers to an IterNode.
+
+static void
+AddNodeOffspring ( IterInfo & info, IterNode & iterParent, const XMP_Node * xmpParent )
+{
+ XMP_VarString currPath ( iterParent.fullPath );
+ size_t leafOffset = iterParent.fullPath.size();
+
+ if ( (! xmpParent->qualifiers.empty()) && (! (info.options & kXMP_IterOmitQualifiers)) ) {
+
+ #if TraceIterators
+ printf ( " Adding qualifiers of %s\n", currPath.c_str() );
+ #endif
+
+ currPath += "/?"; // All qualifiers are named and use paths like "Prop/?Qual".
+ leafOffset += 2;
+
+ for ( size_t qualNum = 0, qualLim = xmpParent->qualifiers.size(); qualNum != qualLim; ++qualNum ) {
+ const XMP_Node * xmpQual = xmpParent->qualifiers[qualNum];
+ currPath += xmpQual->name;
+ iterParent.qualifiers.push_back ( IterNode ( xmpQual->options, currPath, leafOffset ) );
+ currPath.erase ( leafOffset );
+ #if TraceIterators
+ printf ( " %s\n", xmpQual->name.c_str() );
+ #endif
+ }
+
+ leafOffset -= 2;
+ currPath.erase ( leafOffset );
+
+ }
+
+ if ( ! xmpParent->children.empty() ) {
+
+ #if TraceIterators
+ printf ( " Adding children of %s\n", currPath.c_str() );
+ #endif
+
+ XMP_Assert ( xmpParent->options & kXMP_PropCompositeMask );
+
+ if ( xmpParent->options & kXMP_PropValueIsStruct ) {
+ currPath += '/';
+ leafOffset += 1;
+ }
+
+ for ( size_t childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
+ const XMP_Node * xmpChild = xmpParent->children[childNum];
+ if ( ! (xmpParent->options & kXMP_PropValueIsArray) ) {
+ currPath += xmpChild->name;
+ } else {
+ char buffer [32]; // AUDIT: Using sizeof(buffer) below for snprintf length is safe.
+ snprintf ( buffer, sizeof(buffer), "[%lu]", childNum+1 ); // ! XPath indices are one-based.
+ currPath += buffer;
+ }
+ iterParent.children.push_back ( IterNode ( xmpChild->options, currPath, leafOffset ) );
+ currPath.erase ( leafOffset );
+ #if TraceIterators
+ printf ( " %s\n", (iterParent.children.back().fullPath.c_str() + leafOffset) );
+ #endif
+ }
+
+ }
+
+} // AddNodeOffspring
+
+// -------------------------------------------------------------------------------------------------
+// SetCurrSchema
+// -------------
+
+static inline void
+SetCurrSchema ( IterInfo & info, XMP_StringPtr schemaName )
+{
+
+ info.currSchema = schemaName;
+ #if 0 // *** XMP_DebugBuild
+ info._schemaPtr = info.currSchema.c_str();
+ #endif
+
+} // SetCurrSchema
+
+static inline void
+SetCurrSchema ( IterInfo & info, XMP_VarString & schemaName )
+{
+
+ info.currSchema = schemaName;
+ #if 0 // *** XMP_DebugBuild
+ info._schemaPtr = info.currSchema.c_str();
+ #endif
+
+} // SetCurrSchema
+
+// -------------------------------------------------------------------------------------------------
+// AdvanceIterPos
+// --------------
+//
+// Adjust currPos and possibly endPos for the next step in a pre-order depth-first traversal. The
+// current node has just been visited, move on to its qualifiers, children, then siblings, or back
+// up to an ancestor. AdvanceIterPos either moves to a property or qualifier node that can be
+// visited, or to the end of the entire iteration.
+
+static void
+AdvanceIterPos ( IterInfo & info )
+{
+ // -------------------------------------------------------------------------------------------
+ // Keep looking until we find a node to visit or the end of everything. The first time through
+ // the current node will exist, we just visited it. But we have to keep looking if the current
+ // node was the last of its siblings or is an empty schema.
+
+ // ! It is possible that info.currPos == info.endPos on entry. Don't dereference info.currPos yet!
+
+ while ( true ) {
+
+ if ( info.currPos == info.endPos ) {
+
+ // ------------------------------------------------------------------------------------
+ // At the end of a set of siblings, move up to an ancestor. We've either just finished
+ // the qualifiers and will move to the children, or have just finished the children and
+ // will move on to the next sibling.
+
+ if ( info.ancestors.empty() ) break; // We're at the end of the schema list.
+
+ IterPosPair & parent = info.ancestors.back();
+ info.currPos = parent.first;
+ info.endPos = parent.second;
+ info.ancestors.pop_back();
+
+ #if TraceIterators
+ printf ( " Moved up to %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+ } else {
+
+ // -------------------------------------------------------------------------------------------
+ // Decide what to do with this iteration node based on its state. Don't use a switch statment,
+ // some of the cases want to break from the loop. A break in a switch just exits the case.
+
+ #if TraceIterators
+ printf ( " Moving from %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+ if ( info.currPos->visitStage == kIter_BeforeVisit ) { // Visit this node now.
+ if ( info.currPos->options & kXMP_SchemaNode ) SetCurrSchema ( info, info.currPos->fullPath );
+ break;
+ }
+
+ if ( info.currPos->visitStage == kIter_VisitSelf ) { // Just finished visiting the value portion.
+ info.currPos->visitStage = kIter_VisitQualifiers; // Start visiting the qualifiers.
+ if ( ! info.currPos->qualifiers.empty() ) {
+ info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) );
+ info.endPos = info.currPos->qualifiers.end(); // ! Set the parent's endPos before changing currPos!
+ info.currPos = info.currPos->qualifiers.begin();
+ break;
+ }
+ }
+
+ if ( info.currPos->visitStage == kIter_VisitQualifiers ) { // Just finished visiting the qualifiers.
+ info.currPos->qualifiers.clear();
+ info.currPos->visitStage = kIter_VisitChildren; // Start visiting the children.
+ if ( ! info.currPos->children.empty() ) {
+ info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) );
+ info.endPos = info.currPos->children.end(); // ! Set the parent's endPos before changing currPos!
+ info.currPos = info.currPos->children.begin();
+ break;
+ }
+ }
+
+ if ( info.currPos->visitStage == kIter_VisitChildren ) { // Just finished visiting the children.
+ info.currPos->children.clear();
+ ++info.currPos; // Move to the next sibling.
+ continue;
+ }
+
+ #if TraceIterators
+ if ( info.currPos != info.endPos ) {
+ printf ( " Moved to %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ }
+ #endif
+
+ }
+
+ } // Loop to find the next node.
+
+ XMP_Assert ( (info.currPos == info.endPos) || (info.currPos->visitStage == kIter_BeforeVisit) );
+
+} // AdvanceIterPos
+
+// -------------------------------------------------------------------------------------------------
+// GetNextXMPNode
+// --------------
+//
+// Used by XMPIterator::Next to obtain the next XMP node, ignoring the kXMP_IterJustLeafNodes flag.
+// This isolates some messy code, allowing a clean loop in Next if kXMP_IterJustLeafNodes is set.
+
+static const XMP_Node *
+GetNextXMPNode ( IterInfo & info )
+{
+ const XMP_Node * xmpNode = 0;
+
+ // ----------------------------------------------------------------------------------------------
+ // On entry currPos points to an iteration node whose state is either before-visit or visit-self.
+ // If it is before-visit then we will return that node's value part now. If it is visit-self it
+ // means the previous iteration returned the value portion of that node, so we can advance to the
+ // next node in the iteration tree. Then we find the corresponding XMP node, allowing for the XMP
+ // tree to have been modified since that part of the iteration tree was constructed.
+
+ // ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP
+ // ! node for the schema, but we still have to visit it because of possible aliases. The static
+ // ! sDummySchema is returned if there is no real schema node.
+
+ if ( info.currPos->visitStage != kIter_BeforeVisit ) AdvanceIterPos ( info );
+
+ bool isSchemaNode = false;
+ XMP_ExpandedXPath expPath; // Keep outside the loop to avoid constant construct/destruct.
+
+ while ( info.currPos != info.endPos ) {
+
+ isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
+ if ( isSchemaNode ) {
+ SetCurrSchema ( info, info.currPos->fullPath );
+ xmpNode = FindConstSchema ( &info.xmpObj->tree, info.currPos->fullPath.c_str() );
+ if ( xmpNode == 0 ) xmpNode = sDummySchema;
+ } else {
+ ExpandXPath ( info.currSchema.c_str(), info.currPos->fullPath.c_str(), &expPath );
+ xmpNode = FindConstNode ( &info.xmpObj->tree, expPath );
+ }
+ if ( xmpNode != 0 ) break; // Exit the loop, we found a live XMP node.
+
+ info.currPos->visitStage = kIter_VisitChildren; // Make AdvanceIterPos move to the next sibling.
+ info.currPos->children.clear();
+ info.currPos->qualifiers.clear();
+ AdvanceIterPos ( info );
+
+ }
+
+ if ( info.currPos == info.endPos ) return 0;
+
+ // -------------------------------------------------------------------------------------------
+ // Now we've got the iteration node and corresponding XMP node. Add the iteration children for
+ // structs and arrays. The children of schema were added when the iterator was constructed.
+
+ XMP_Assert ( info.currPos->visitStage == kIter_BeforeVisit );
+
+ if ( info.currPos->visitStage == kIter_BeforeVisit ) {
+ if ( (! isSchemaNode) && (! (info.options & kXMP_IterJustChildren)) ) {
+ AddNodeOffspring ( info, *info.currPos, xmpNode );
+ }
+ info.currPos->visitStage = kIter_VisitSelf;
+ }
+
+ return xmpNode;
+
+} // GetNextXMPNode
+
+// =================================================================================================
+// Init/Term
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// Initialize
+// ----------
+
+/* class static */ bool
+XMPIterator::Initialize()
+{
+ sDummySchema = new XMP_Node ( 0, "dummy:schema/", kXMP_SchemaNode);
+ return true;
+
+} // Initialize
+
+// -------------------------------------------------------------------------------------------------
+// Terminate
+// ----------
+
+/* class static */ void
+XMPIterator::Terminate() RELEASE_NO_THROW
+{
+ delete ( sDummySchema );
+ sDummySchema = 0;
+ return;
+
+} // Terminate
+
+// =================================================================================================
+// Constructors
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// XMPIterator
+// -----------
+//
+// Constructor for iterations over the nodes in an XMPMeta object. This builds a tree of iteration
+// nodes that caches the existing node names of the XMPMeta object. The iteration tree is a partial
+// replica of the XMPMeta tree. The initial iteration tree normally has just the root node, all of
+// the schema nodes for a full object iteration. Lower level nodes (children and qualifiers) are
+// added when the parent is visited. If the kXMP_IterJustChildren option is passed then the initial
+// iterator includes the children and the parent is marked as done. The iteration tree nodes are
+// pruned when they are no longer needed.
+
+XMPIterator::XMPIterator ( const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options ) : info(IterInfo(options,&xmpObj)), clientRefs(0)
+{
+ if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) {
+ XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions );
+ }
+
+ // *** Lock the XMPMeta object if we ever stop using a full DLL lock.
+
+ if ( *propName != 0 ) {
+
+ // An iterator rooted at a specific node.
+
+ #if TraceIterators
+ printf ( "\nNew XMP property iterator for \"%s\", options = %X\n Schema = %s, root = %s\n",
+ xmpObj.tree.name.c_str(), options, schemaNS, propName );
+ #endif
+
+ XMP_ExpandedXPath propPath;
+ ExpandXPath ( schemaNS, propName, &propPath );
+ XMP_Node * propNode = FindConstNode ( &xmpObj.tree, propPath ); // If not found get empty iteration.
+
+ if ( propNode != 0 ) {
+
+ XMP_VarString rootName ( propPath[1].step ); // The schema is [0].
+ for ( size_t i = 2; i < propPath.size(); ++i ) {
+ XMP_OptionBits stepKind = GetStepKind ( propPath[i].options );
+ if ( stepKind <= kXMP_QualifierStep ) rootName += '/';
+ rootName += propPath[i].step;
+ }
+
+ propName = rootName.c_str();
+ size_t leafOffset = rootName.size();
+ while ( (leafOffset > 0) && (propName[leafOffset] != '/') && (propName[leafOffset] != '[') ) --leafOffset;
+ if ( propName[leafOffset] == '/' ) ++leafOffset;
+
+ info.tree.children.push_back ( IterNode ( propNode->options, propName, leafOffset ) );
+ SetCurrSchema ( info, propPath[kSchemaStep].step.c_str() );
+ if ( info.options & kXMP_IterJustChildren ) {
+ AddNodeOffspring ( info, info.tree.children.back(), propNode );
+ }
+
+ }
+
+ } else if ( *schemaNS != 0 ) {
+
+ // An iterator for all properties in one schema.
+
+ #if TraceIterators
+ printf ( "\nNew XMP schema iterator for \"%s\", options = %X\n Schema = %s\n",
+ xmpObj.tree.name.c_str(), options, schemaNS );
+ #endif
+
+ info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaNS, 0 ) );
+ IterNode & iterSchema = info.tree.children.back();
+
+ XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS );
+ if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema );
+
+ if ( iterSchema.children.empty() ) {
+ info.tree.children.pop_back(); // No properties, remove the schema node.
+ } else {
+ SetCurrSchema ( info, schemaNS );
+ }
+
+ } else {
+
+ // An iterator for all properties in all schema. First add schema that exist (have children),
+ // adding aliases from them if appropriate. Then add schema that have no actual properties
+ // but do have aliases to existing properties, if we're including aliases in the iteration.
+
+ #if TraceIterators
+ printf ( "\nNew XMP tree iterator for \"%s\", options = %X\n",
+ xmpObj.tree.name.c_str(), options );
+ #endif
+
+ // First pick up the schema that exist.
+
+ for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {
+
+ const XMP_Node * xmpSchema = xmpObj.tree.children[schemaNum];
+ info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, xmpSchema->name, 0 ) );
+ IterNode & iterSchema = info.tree.children.back();
+
+ if ( ! (info.options & kXMP_IterJustChildren) ) {
+ AddSchemaProps ( info, iterSchema, xmpSchema );
+ if ( iterSchema.children.empty() ) info.tree.children.pop_back(); // No properties, remove the schema node.
+ }
+
+ }
+
+ }
+
+ // Set the current iteration position to the first node to be visited.
+
+ info.currPos = info.tree.children.begin();
+ info.endPos = info.tree.children.end();
+
+ if ( (info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0) ) {
+ info.currPos->visitStage = kIter_VisitSelf;
+ }
+
+ #if TraceIterators
+ if ( info.currPos == info.endPos ) {
+ printf ( " ** Empty iteration **\n" );
+ } else {
+ printf ( " Initial node %s, stage = %s, iterator @ %.8X\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
+ }
+ #endif
+
+} // XMPIterator for XMPMeta objects
+
+// -------------------------------------------------------------------------------------------------
+// XMPIterator
+// -----------
+//
+// Constructor for iterations over global tables such as registered namespaces or aliases.
+
+XMPIterator::XMPIterator ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options ) : info(IterInfo(options,0)), clientRefs(0)
+{
+
+ XMP_Throw ( "Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented );
+ void * p; p = &schemaNS; p = &propName; p = &options; // Avoid unused param warnings.
+
+} // XMPIterator for global tables
+
+// -------------------------------------------------------------------------------------------------
+// ~XMPIterator
+// -----------
+
+XMPIterator::~XMPIterator() RELEASE_NO_THROW
+{
+ XMP_Assert ( this->clientRefs <= 0 );
+ // Let everything else default.
+
+} // ~XMPIterator
+
+// =================================================================================================
+// Iteration Methods
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// Next
+// ----
+//
+// Do a preorder traversal of the cached nodes.
+
+// *** Need to document the relationships between currPos, endPos, and visitStage.
+
+bool
+XMPIterator::Next ( XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions )
+{
+ // *** Lock the XMPMeta object if we ever stop using a full DLL lock.
+
+ // ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP
+ // ! node for the schema, but we still have to visit it because of possible aliases.
+
+ if ( info.currPos == info.endPos ) return false; // Happens at the start of an empty iteration.
+
+ #if TraceIterators
+ printf ( "Next iteration from %s, stage = %s, iterator @ %.8X\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
+ #endif
+
+ const XMP_Node * xmpNode = GetNextXMPNode ( info );
+ if ( xmpNode == 0 ) return false;
+ bool isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
+
+ if ( info.options & kXMP_IterJustLeafNodes ) {
+ while ( isSchemaNode || (! xmpNode->children.empty()) ) {
+ info.currPos->visitStage = kIter_VisitQualifiers; // Skip to this node's children.
+ xmpNode = GetNextXMPNode ( info );
+ if ( xmpNode == 0 ) return false;
+ isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
+ }
+ }
+
+ *schemaNS = info.currSchema.c_str();
+ *nsSize = info.currSchema.size();
+
+ *propOptions = info.currPos->options;
+
+ *propPath = "";
+ *pathSize = 0;
+ *propValue = "";
+ *valueSize = 0;
+
+ if ( ! (*propOptions & kXMP_SchemaNode) ) {
+
+ *propPath = info.currPos->fullPath.c_str();
+ *pathSize = info.currPos->fullPath.size();
+
+ if ( info.options & kXMP_IterJustLeafName ) {
+ *propPath += info.currPos->leafOffset;
+ *pathSize -= info.currPos->leafOffset;
+ xmpNode->GetLocalURI ( schemaNS, nsSize ); // Use the leaf namespace, not the top namespace.
+ }
+
+ if ( ! (*propOptions & kXMP_PropCompositeMask) ) {
+ *propValue = xmpNode->value.c_str();
+ *valueSize = xmpNode->value.size();
+ }
+
+ }
+
+ #if TraceIterators
+ printf ( " Next node %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+ return true;
+
+} // Next
+
+// -------------------------------------------------------------------------------------------------
+// Skip
+// ----
+//
+// Skip some portion of the traversal related to the last visited node. We skip either that node's
+// children, or those children and the previous node's siblings. The implementation might look a bit
+// awkward because info.currNode always points to the next node to be visited. We might already have
+// moved past the things to skip, e.g. if the previous node was simple and the last of its siblings.
+
+enum {
+ kXMP_ValidIterSkipOptions = kXMP_IterSkipSubtree | kXMP_IterSkipSiblings
+};
+
+void
+XMPIterator::Skip ( XMP_OptionBits iterOptions )
+{
+// if ( (info.currPos == kIter_NullPos) ) XMP_Throw ( "No prior postion to skip from", kXMPErr_BadIterPosition );
+ if ( iterOptions == 0 ) XMP_Throw ( "Must specify what to skip", kXMPErr_BadOptions );
+ if ( (iterOptions & ~kXMP_ValidIterSkipOptions) != 0 ) XMP_Throw ( "Undefined options", kXMPErr_BadOptions );
+
+ #if TraceIterators
+ printf ( "Skipping from %s, stage = %s, iterator @ %.8X",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
+ #endif
+
+ if ( iterOptions & kXMP_IterSkipSubtree ) {
+ #if TraceIterators
+ printf ( ", mode = subtree\n" );
+ #endif
+ info.currPos->visitStage = kIter_VisitChildren;
+ } else if ( iterOptions & kXMP_IterSkipSiblings ) {
+ #if TraceIterators
+ printf ( ", mode = siblings\n" );
+ #endif
+ info.currPos = info.endPos;
+ AdvanceIterPos ( info );
+ }
+ #if TraceIterators
+ printf ( " Skipped to %s, stage = %s\n",
+ info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
+ #endif
+
+
+} // Skip
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPIterator.hpp b/gpr/source/lib/xmp_core/XMPIterator.hpp
new file mode 100644
index 0000000..30146ae
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPIterator.hpp
@@ -0,0 +1,144 @@
+#ifndef __XMPIterator_hpp__
+#define __XMPIterator_hpp__
+
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h"
+#include "public/include/XMP_Const.h"
+#include "XMPMeta.hpp"
+
+// =================================================================================================
+
+struct IterNode;
+typedef std::vector < IterNode > IterOffspring;
+typedef IterOffspring::iterator IterPos;
+
+typedef std::pair < IterPos, IterPos > IterPosPair;
+typedef std::vector < IterPosPair > IterPosStack;
+
+enum { // Values for the visitStage field, used to decide how to proceed past a node.
+ kIter_BeforeVisit = 0, // Have not visited this node at all.
+ kIter_VisitSelf = 1, // Have visited this node and returned its value/options portion.
+ kIter_VisitQualifiers = 2, // In the midst of visiting this node's qualifiers.
+ kIter_VisitChildren = 3 // In the midst of visiting this node's children.
+};
+
+struct IterNode {
+
+ XMP_OptionBits options;
+ XMP_VarString fullPath;
+ size_t leafOffset;
+ IterOffspring children, qualifiers;
+ XMP_Uns8 visitStage;
+ #if 0 // *** XMP_DebugBuild
+ XMP_StringPtr _pathPtr, _leafPtr; // *** Not working, need operator=?
+ #endif
+
+ IterNode() : options(0), leafOffset(0), visitStage(kIter_BeforeVisit)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _pathPtr = _leafPtr = 0;
+ #endif
+ };
+
+ IterNode ( XMP_OptionBits _options, const XMP_VarString& _fullPath, size_t _leafOffset )
+ : options(_options), fullPath(_fullPath), leafOffset(_leafOffset), visitStage(kIter_BeforeVisit)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _pathPtr = fullPath.c_str();
+ _leafPtr = _pathPtr + leafOffset;
+ #endif
+ };
+
+};
+
+struct IterInfo {
+
+ XMP_OptionBits options;
+ const XMPMeta * xmpObj;
+ XMP_VarString currSchema;
+ IterPos currPos, endPos;
+ IterPosStack ancestors;
+ IterNode tree;
+ #if 0 // *** XMP_DebugBuild
+ XMP_StringPtr _schemaPtr; // *** Not working, need operator=?
+ #endif
+
+ IterInfo() : options(0), xmpObj(0)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _schemaPtr = 0;
+ #endif
+ };
+
+ IterInfo ( XMP_OptionBits _options, const XMPMeta * _xmpObj ) : options(_options), xmpObj(_xmpObj)
+ {
+ #if 0 // *** XMP_DebugBuild
+ _schemaPtr = 0;
+ #endif
+ };
+
+};
+
+// =================================================================================================
+
+class XMPIterator {
+public:
+
+ static bool
+ Initialize(); // ! For internal use only!
+
+ static void
+ Terminate() RELEASE_NO_THROW; // ! For internal use only!
+
+ XMPIterator ( const XMPMeta & xmpObj, // Construct a property iterator.
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ XMPIterator ( XMP_StringPtr schemaNS, // Construct a table iterator.
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ virtual ~XMPIterator() RELEASE_NO_THROW;
+
+ bool
+ Next ( XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions );
+
+ void
+ Skip ( XMP_OptionBits options );
+
+ // ! Expose so that wrappers and file static functions can see the data.
+
+ XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0.
+ XMP_ReadWriteLock lock;
+
+ IterInfo info;
+
+private:
+
+ // ! These are hidden on purpose:
+ XMPIterator() : clientRefs(0)
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ XMPIterator ( const XMPIterator & /* original */ ) : clientRefs(0)
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ void operator= ( const XMPIterator & /* rhs */ )
+ { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); };
+
+};
+
+// =================================================================================================
+
+#endif // __XMPIterator_hpp__
diff --git a/gpr/source/lib/xmp_core/XMPMeta-GetSet.cpp b/gpr/source/lib/xmp_core/XMPMeta-GetSet.cpp
new file mode 100644
index 0000000..44f10a4
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPMeta-GetSet.cpp
@@ -0,0 +1,1309 @@
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "XMPIterator.hpp"
+#include "XMPUtils.hpp"
+
+#include "public/include/XMP_Version.h"
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+#include "ExpatAdapter.hpp"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+typedef unsigned char XMP_CLTMatch;
+
+enum { // Values for XMP_CLTMatch.
+ kXMP_CLT_NoValues,
+ kXMP_CLT_SpecificMatch,
+ kXMP_CLT_SingleGeneric,
+ kXMP_CLT_MultipleGeneric,
+ kXMP_CLT_XDefault,
+ kXMP_CLT_FirstItem
+};
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+// -------------------------------------------------------------------------------------------------
+// SetNodeValue
+// ------------
+
+static inline void
+SetNodeValue ( XMP_Node * node, XMP_StringPtr value )
+{
+
+ #if XMP_DebugBuild // ! Hack to force an assert.
+ if ( (node->name == "xmp:TestAssertNotify") && XMP_LitMatch ( value, "DoIt!" ) ) {
+ XMP_Assert ( node->name != "xmp:TestAssertNotify" );
+ }
+ #endif
+
+ std::string newValue = value; // Need a local copy to tweak and not change node.value for errors.
+
+ XMP_Uns8* chPtr = (XMP_Uns8*) newValue.c_str(); // Check for valid UTF-8, replace ASCII controls with a space.
+ while ( *chPtr != 0 ) {
+
+ while ( (*chPtr != 0) && (*chPtr < 0x80) ) {
+ if ( *chPtr < 0x20 ) {
+ if ( (*chPtr != kTab) && (*chPtr != kLF) && (*chPtr != kCR) ) *chPtr = 0x20;
+ } else if (*chPtr == 0x7F ) {
+ *chPtr = 0x20;
+ }
+ ++chPtr;
+ }
+
+ XMP_Assert ( (*chPtr == 0) || (*chPtr >= 0x80) );
+
+ if ( *chPtr != 0 ) {
+ XMP_Uns32 cp = GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8.
+ if ( (cp == 0xFFFE) || (cp == 0xFFFF) ) {
+ XMP_Throw ( "U+FFFE and U+FFFF are not allowed in XML", kXMPErr_BadXML );
+ }
+ }
+
+ }
+
+ if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &newValue );
+
+ node->value.swap ( newValue );
+
+ #if 0 // *** XMP_DebugBuild
+ node->_valuePtr = node->value.c_str();
+ #endif
+
+} // SetNodeValue
+
+
+// -------------------------------------------------------------------------------------------------
+// SetNode
+// -------
+//
+// The internals for SetProperty and related calls, used after the node is found or created.
+
+static void
+SetNode ( XMP_Node * node, XMP_StringPtr value, XMP_OptionBits options )
+{
+ if ( options & kXMP_DeleteExisting ) {
+ XMP_ClearOption ( options, kXMP_DeleteExisting );
+ node->options = options;
+ node->value.erase();
+ node->RemoveChildren();
+ node->RemoveQualifiers();
+ }
+
+ node->options |= options; // Keep options set by FindNode when creating a new node.
+
+ if ( value != 0 ) {
+
+ // This is setting the value of a leaf node.
+ if ( node->options & kXMP_PropCompositeMask ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
+ XMP_Assert ( node->children.empty() );
+ SetNodeValue ( node, value );
+
+ } else {
+
+ // This is setting up an array or struct.
+ if ( ! node->value.empty() ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
+ if ( node->options & kXMP_PropCompositeMask ) { // Can't change an array to a struct, or vice versa.
+ if ( (options & kXMP_PropCompositeMask) != (node->options & kXMP_PropCompositeMask) ) {
+ XMP_Throw ( "Requested and existing composite form mismatch", kXMPErr_BadXPath );
+ }
+ }
+ node->RemoveChildren();
+
+ }
+
+} // SetNode
+
+
+// -------------------------------------------------------------------------------------------------
+// DoSetArrayItem
+// --------------
+
+static void
+DoSetArrayItem ( XMP_Node * arrayNode,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_OptionBits itemLoc = options & kXMP_PropArrayLocationMask;
+ XMP_Index arraySize = arrayNode->children.size();
+
+ options &= ~kXMP_PropArrayLocationMask;
+ options = VerifySetOptions ( options, itemValue );
+
+ // Now locate or create the item node and set the value. Note the index parameter is one-based!
+ // The index can be in the range [0..size+1] or "last", normalize it and check the insert flags.
+ // The order of the normalization checks is important. If the array is empty we end up with an
+ // index and location to set item size+1.
+
+ XMP_Node * itemNode = 0;
+
+ if ( itemIndex == kXMP_ArrayLastItem ) itemIndex = arraySize;
+ if ( (itemIndex == 0) && (itemLoc == kXMP_InsertAfterItem) ) {
+ itemIndex = 1;
+ itemLoc = kXMP_InsertBeforeItem;
+ }
+ if ( (itemIndex == arraySize) && (itemLoc == kXMP_InsertAfterItem) ) {
+ itemIndex += 1;
+ itemLoc = 0;
+ }
+ if ( (itemIndex == arraySize+1) && (itemLoc == kXMP_InsertBeforeItem) ) itemLoc = 0;
+
+ if ( itemIndex == arraySize+1 ) {
+
+ if ( itemLoc != 0 ) XMP_Throw ( "Can't insert before or after implicit new item", kXMPErr_BadIndex );
+ itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 );
+ arrayNode->children.push_back ( itemNode );
+
+ } else {
+
+ if ( (itemIndex < 1) || (itemIndex > arraySize) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadIndex );
+ --itemIndex; // ! Convert the index to a C zero-based value!
+ if ( itemLoc == 0 ) {
+ itemNode = arrayNode->children[itemIndex];
+ } else {
+ XMP_NodePtrPos itemPos = arrayNode->children.begin() + itemIndex;
+ if ( itemLoc == kXMP_InsertAfterItem ) ++itemPos;
+ itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 );
+ itemPos = arrayNode->children.insert ( itemPos, itemNode );
+ }
+
+ }
+
+ SetNode ( itemNode, itemValue, options );
+
+} // DoSetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// ChooseLocalizedText
+// -------------------
+//
+// 1. Look for an exact match with the specific language.
+// 2. If a generic language is given, look for partial matches.
+// 3. Look for an "x-default" item.
+// 4. Choose the first item.
+
+static XMP_CLTMatch
+ChooseLocalizedText ( const XMP_Node * arrayNode,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ const XMP_Node * * itemNode )
+{
+ const XMP_Node * currItem = 0;
+ const size_t itemLim = arrayNode->children.size();
+ size_t itemNum;
+
+ // See if the array has the right form. Allow empty alt arrays, that is what parsing returns.
+ // *** Should check alt-text bit when that is reliably maintained.
+
+ if ( ! ( XMP_ArrayIsAltText(arrayNode->options) ||
+ (arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options)) ) ) {
+ XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
+ }
+ if ( arrayNode->children.empty() ) {
+ *itemNode = 0;
+ return kXMP_CLT_NoValues;
+ }
+
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ if ( currItem->options & kXMP_PropCompositeMask ) {
+ XMP_Throw ( "Alt-text array item is not simple", kXMPErr_BadXPath );
+ }
+ if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) {
+ XMP_Throw ( "Alt-text array item has no language qualifier", kXMPErr_BadXPath );
+ }
+ }
+
+ // Look for an exact match with the specific language.
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ if ( currItem->qualifiers[0]->value == specificLang ) {
+ *itemNode = currItem;
+ return kXMP_CLT_SpecificMatch;
+ }
+ }
+
+ if ( *genericLang != 0 ) {
+
+ // Look for the first partial match with the generic language.
+ const size_t genericLen = strlen ( genericLang );
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str();
+ const size_t currLangSize = currItem->qualifiers[0]->value.size();
+ if ( (currLangSize >= genericLen) &&
+ XMP_LitNMatch ( currLang, genericLang, genericLen ) &&
+ ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) {
+ *itemNode = currItem;
+ break; // ! Don't return, need to look for other matches.
+ }
+ }
+
+ if ( itemNum < itemLim ) {
+
+ // Look for a second partial match with the generic language.
+ for ( ++itemNum; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str();
+ const size_t currLangSize = currItem->qualifiers[0]->value.size();
+ if ( (currLangSize >= genericLen) &&
+ XMP_LitNMatch ( currLang, genericLang, genericLen ) &&
+ ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) {
+ return kXMP_CLT_MultipleGeneric; // ! Leave itemNode with the first partial match.
+ }
+ }
+ return kXMP_CLT_SingleGeneric; // No second partial match was found.
+
+ }
+
+ }
+
+ // Look for an 'x-default' item.
+ for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
+ currItem = arrayNode->children[itemNum];
+ if ( currItem->qualifiers[0]->value == "x-default" ) {
+ *itemNode = currItem;
+ return kXMP_CLT_XDefault;
+ }
+ }
+
+ // Everything failed, choose the first item.
+ *itemNode = arrayNode->children[0];
+ return kXMP_CLT_FirstItem;
+
+} // ChooseLocalizedText
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendLangItem
+// --------------
+
+static void
+AppendLangItem ( XMP_Node * arrayNode, XMP_StringPtr itemLang, XMP_StringPtr itemValue )
+{
+ XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, (kXMP_PropHasQualifiers | kXMP_PropHasLang) );
+ XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", kXMP_PropIsQualifier );
+
+ try { // ! Use SetNodeValue, not constructors above, to get the character checks.
+ SetNodeValue ( newItem, itemValue );
+ SetNodeValue ( langQual, itemLang );
+ } catch (...) {
+ delete newItem;
+ delete langQual;
+ throw;
+ }
+
+ newItem->qualifiers.push_back ( langQual );
+
+ if ( (arrayNode->children.empty()) || (langQual->value != "x-default") ) {
+ arrayNode->children.push_back ( newItem );
+ } else {
+ arrayNode->children.insert ( arrayNode->children.begin(), newItem );
+ }
+
+} // AppendLangItem
+
+
+// =================================================================================================
+// Class Methods
+// =============
+//
+//
+// =================================================================================================
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty
+// -----------
+
+bool
+XMPMeta::GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_Node * propNode = FindConstNode ( &tree, expPath );
+ if ( propNode == 0 ) return false;
+
+ *propValue = propNode->value.c_str();
+ *valueSize = propNode->value.size();
+ *options = propNode->options;
+
+ return true;
+
+} // GetProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// GetArrayItem
+// ------------
+
+bool
+XMPMeta::GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (itemValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ // ! Special case check to make errors consistent if the array does not exist. The other array
+ // ! functions and existing array here (empty or not) already throw.
+ if ( (itemIndex <= 0) && (itemIndex != kXMP_ArrayLastItem) ) XMP_Throw ( "Array index must be larger than zero", kXMPErr_BadXPath );
+
+ XMP_VarString itemPath;
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath );
+ return GetProperty ( schemaNS, itemPath.c_str(), itemValue, valueSize, options );
+
+} // GetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// GetStructField
+// --------------
+
+bool
+XMPMeta::GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fieldValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_VarString fieldPath;
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath );
+ return GetProperty ( schemaNS, fieldPath.c_str(), fieldValue, valueSize, options );
+
+} // GetStructField
+
+
+// -------------------------------------------------------------------------------------------------
+// GetQualifier
+// ------------
+
+bool
+XMPMeta::GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (qualValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_VarString qualPath;
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath );
+ return GetProperty ( schemaNS, qualPath.c_str(), qualValue, valueSize, options );
+
+} // GetQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty
+// -----------
+
+// *** Should handle array items specially, calling SetArrayItem.
+
+void
+XMPMeta::SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ options = VerifySetOptions ( options, propValue );
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_CreateNodes, options );
+ if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
+
+ SetNode ( propNode, propValue, options );
+
+} // SetProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// SetArrayItem
+// ------------
+
+void
+XMPMeta::SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create.
+ if ( arrayNode == 0 ) XMP_Throw ( "Specified array does not exist", kXMPErr_BadXPath );
+
+ DoSetArrayItem ( arrayNode, itemIndex, itemValue, options );
+
+} // SetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendArrayItem
+// ---------------
+
+void
+XMPMeta::AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ arrayOptions = VerifySetOptions ( arrayOptions, 0 );
+ if ( (arrayOptions & ~kXMP_PropArrayFormMask) != 0 ) {
+ XMP_Throw ( "Only array form flags allowed for arrayOptions", kXMPErr_BadOptions );
+ }
+
+ // Locate or create the array. If it already exists, make sure the array form from the options
+ // parameter is compatible with the current state.
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create.
+
+ if ( arrayNode != 0 ) {
+ // The array exists, make sure the form is compatible. Zero arrayForm means take what exists.
+ if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) {
+ XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
+ }
+ #if 0
+ // *** Disable for now. Need to do some general rethinking of semantic checks.
+ if ( (arrayOptions != 0) && (arrayOptions != (arrayNode->options & kXMP_PropArrayFormMask)) ) {
+ XMP_Throw ( "Mismatch of existing and specified array form", kXMPErr_BadOptions );
+ }
+ #endif
+ } else {
+ // The array does not exist, try to create it.
+ if ( arrayOptions == 0 ) XMP_Throw ( "Explicit arrayOptions required to create new array", kXMPErr_BadOptions );
+ arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes, arrayOptions );
+ if ( arrayNode == 0 ) XMP_Throw ( "Failure creating array node", kXMPErr_BadXPath );
+ }
+
+ DoSetArrayItem ( arrayNode, kXMP_ArrayLastItem, itemValue, (options | kXMP_InsertAfterItem) );
+
+} // AppendArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// SetStructField
+// --------------
+
+void
+XMPMeta::SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString fieldPath;
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath );
+ SetProperty ( schemaNS, fieldPath.c_str(), fieldValue, options );
+
+} // SetStructField
+
+
+// -------------------------------------------------------------------------------------------------
+// SetQualifier
+// ------------
+
+void
+XMPMeta::SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+ XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly );
+ if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
+
+ XMP_VarString qualPath;
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath );
+ SetProperty ( schemaNS, qualPath.c_str(), qualValue, options );
+
+} // SetQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteProperty
+// --------------
+
+void
+XMPMeta::DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_NodePtrPos ptrPos;
+ XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly, kXMP_NoOptions, &ptrPos );
+ if ( propNode == 0 ) return;
+ XMP_Node * parentNode = propNode->parent;
+
+ // Erase the pointer from the parent's vector, then delete the node and all below it.
+
+ if ( ! (propNode->options & kXMP_PropIsQualifier) ) {
+
+ parentNode->children.erase ( ptrPos );
+ DeleteEmptySchema ( parentNode );
+
+ } else {
+
+ if ( propNode->name == "xml:lang" ) {
+ XMP_Assert ( parentNode->options & kXMP_PropHasLang ); // *** &= ~flag would be safer
+ parentNode->options ^= kXMP_PropHasLang;
+ } else if ( propNode->name == "rdf:type" ) {
+ XMP_Assert ( parentNode->options & kXMP_PropHasType );
+ parentNode->options ^= kXMP_PropHasType;
+ }
+
+ parentNode->qualifiers.erase ( ptrPos );
+ XMP_Assert ( parentNode->options & kXMP_PropHasQualifiers );
+ if ( parentNode->qualifiers.empty() ) parentNode->options ^= kXMP_PropHasQualifiers;
+
+ }
+
+ delete propNode; // ! The destructor takes care of the whole subtree.
+
+} // DeleteProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteArrayItem
+// ---------------
+
+void
+XMPMeta::DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString itemPath;
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath );
+ DeleteProperty ( schemaNS, itemPath.c_str() );
+
+} // DeleteArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteStructField
+// -----------------
+
+void
+XMPMeta::DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName )
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString fieldPath;
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath );
+ DeleteProperty ( schemaNS, fieldPath.c_str() );
+
+} // DeleteStructField
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteQualifier
+// ---------------
+
+void
+XMPMeta::DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString qualPath;
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath );
+ DeleteProperty ( schemaNS, qualPath.c_str() );
+
+} // DeleteQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesPropertyExist
+// -----------------
+
+bool
+XMPMeta::DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_Node * propNode = FindConstNode ( &tree, expPath );
+ return (propNode != 0);
+
+} // DoesPropertyExist
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesArrayItemExist
+// ------------------
+
+bool
+XMPMeta::DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString itemPath;
+ XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath );
+ return DoesPropertyExist ( schemaNS, itemPath.c_str() );
+
+} // DoesArrayItemExist
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesStructFieldExist
+// --------------------
+
+bool
+XMPMeta::DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString fieldPath;
+ XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath );
+ return DoesPropertyExist ( schemaNS, fieldPath.c_str() );
+
+} // DoesStructFieldExist
+
+
+// -------------------------------------------------------------------------------------------------
+// DoesQualifierExist
+// ------------------
+
+bool
+XMPMeta::DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString qualPath;
+ XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath );
+ return DoesPropertyExist ( schemaNS, qualPath.c_str() );
+
+} // DoesQualifierExist
+
+
+// -------------------------------------------------------------------------------------------------
+// GetLocalizedText
+// ----------------
+
+bool
+XMPMeta::GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _genericLang,
+ XMP_StringPtr _specificLang,
+ XMP_StringPtr * actualLang,
+ XMP_StringLen * langSize,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (actualLang != 0) && (langSize != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_VarString zGenericLang ( _genericLang );
+ XMP_VarString zSpecificLang ( _specificLang );
+ NormalizeLangValue ( &zGenericLang );
+ NormalizeLangValue ( &zSpecificLang );
+
+ XMP_StringPtr genericLang = zGenericLang.c_str();
+ XMP_StringPtr specificLang = zSpecificLang.c_str();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ const XMP_Node * arrayNode = FindConstNode ( &tree, arrayPath ); // *** This expand/find idiom is used in 3 Getters.
+ if ( arrayNode == 0 ) return false; // *** Should extract it into a local utility.
+
+ XMP_CLTMatch match;
+ const XMP_Node * itemNode;
+
+ match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &itemNode );
+ if ( match == kXMP_CLT_NoValues ) return false;
+
+ *actualLang = itemNode->qualifiers[0]->value.c_str();
+ *langSize = itemNode->qualifiers[0]->value.size();
+ *itemValue = itemNode->value.c_str();
+ *valueSize = itemNode->value.size();
+ *options = itemNode->options;
+
+ return true;
+
+} // GetLocalizedText
+
+
+// -------------------------------------------------------------------------------------------------
+// SetLocalizedText
+// ----------------
+
+void
+XMPMeta::SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _genericLang,
+ XMP_StringPtr _specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ IgnoreParam(options);
+
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
+
+ XMP_VarString zGenericLang ( _genericLang );
+ XMP_VarString zSpecificLang ( _specificLang );
+ NormalizeLangValue ( &zGenericLang );
+ NormalizeLangValue ( &zSpecificLang );
+
+ XMP_StringPtr genericLang = zGenericLang.c_str();
+ XMP_StringPtr specificLang = zSpecificLang.c_str();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ // Find the array node and set the options if it was just created.
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes,
+ (kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate) );
+ if ( arrayNode == 0 ) XMP_Throw ( "Failed to find or create array node", kXMPErr_BadXPath );
+ if ( ! XMP_ArrayIsAltText(arrayNode->options) ) {
+ if ( arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options) ) {
+ arrayNode->options |= kXMP_PropArrayIsAltText;
+ } else {
+ XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
+ }
+ }
+
+ // Make sure the x-default item, if any, is first.
+
+ size_t itemNum, itemLim;
+ XMP_Node * xdItem = 0;
+ bool haveXDefault = false;
+
+ for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) {
+ XMP_Node * currItem = arrayNode->children[itemNum];
+ XMP_Assert ( XMP_PropHasLang(currItem->options) );
+ if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) {
+ XMP_Throw ( "Language qualifier must be first", kXMPErr_BadXPath );
+ }
+ if ( currItem->qualifiers[0]->value == "x-default" ) {
+ xdItem = currItem;
+ haveXDefault = true;
+ break;
+ }
+ }
+
+ if ( haveXDefault && (itemNum != 0) ) {
+ XMP_Assert ( arrayNode->children[itemNum]->qualifiers[0]->value == "x-default" );
+ XMP_Node * temp = arrayNode->children[0];
+ arrayNode->children[0] = arrayNode->children[itemNum];
+ arrayNode->children[itemNum] = temp;
+ }
+
+ // Find the appropriate item. ChooseLocalizedText will make sure the array is a language alternative.
+
+ const XMP_Node * cItemNode; // ! ChooseLocalizedText returns a pointer to a const node.
+ XMP_CLTMatch match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &cItemNode );
+ XMP_Node * itemNode = const_cast<XMP_Node*> ( cItemNode );
+
+ const bool specificXDefault = XMP_LitMatch ( specificLang, "x-default" );
+
+ switch ( match ) {
+
+ case kXMP_CLT_NoValues :
+
+ // Create the array items for the specificLang and x-default, with x-default first.
+ AppendLangItem ( arrayNode, "x-default", itemValue );
+ haveXDefault = true;
+ if ( ! specificXDefault ) AppendLangItem ( arrayNode, specificLang, itemValue );
+ break;
+
+ case kXMP_CLT_SpecificMatch :
+
+ if ( ! specificXDefault ) {
+ // Update the specific item, update x-default if it matches the old value.
+ if ( xdItem != NULL && haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) {
+ SetNodeValue ( xdItem, itemValue );
+ }
+ SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check!
+ } else {
+ // Update all items whose values match the old x-default value.
+ XMP_Assert ( xdItem != NULL && haveXDefault && (xdItem == itemNode) );
+ for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) {
+ XMP_Node * currItem = arrayNode->children[itemNum];
+ if ( (currItem == xdItem) || (currItem->value != xdItem->value) ) continue;
+ SetNodeValue ( currItem, itemValue );
+ }
+ SetNodeValue ( xdItem, itemValue ); // And finally do the x-default item.
+ }
+ break;
+
+ case kXMP_CLT_SingleGeneric :
+
+ // Update the generic item, update x-default if it matches the old value.
+ if ( xdItem != NULL && haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) {
+ SetNodeValue ( xdItem, itemValue );
+ }
+ SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check!
+ break;
+
+ case kXMP_CLT_MultipleGeneric :
+
+ // Create the specific language, ignore x-default.
+ AppendLangItem ( arrayNode, specificLang, itemValue );
+ if ( specificXDefault ) haveXDefault = true;
+ break;
+
+ case kXMP_CLT_XDefault :
+
+ // Create the specific language, update x-default if it was the only item.
+ if ( arrayNode->children.size() == 1 ) SetNodeValue ( xdItem, itemValue );
+ AppendLangItem ( arrayNode, specificLang, itemValue );
+ break;
+
+ case kXMP_CLT_FirstItem :
+
+ // Create the specific language, don't add an x-default item.
+ AppendLangItem ( arrayNode, specificLang, itemValue );
+ if ( specificXDefault ) haveXDefault = true;
+ break;
+
+ default :
+ XMP_Throw ( "Unexpected result from ChooseLocalizedText", kXMPErr_InternalFailure );
+
+ }
+
+ // Add an x-default at the front if needed.
+ if ( (! haveXDefault) && (arrayNode->children.size() == 1) ) {
+ AppendLangItem ( arrayNode, "x-default", itemValue );
+ }
+
+} // SetLocalizedText
+
+// -------------------------------------------------------------------------------------------------
+// DeleteLocalizedText
+// -------------------
+
+void
+XMPMeta::DeleteLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _genericLang,
+ XMP_StringPtr _specificLang )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
+
+ XMP_VarString zGenericLang ( _genericLang );
+ XMP_VarString zSpecificLang ( _specificLang );
+ NormalizeLangValue ( &zGenericLang );
+ NormalizeLangValue ( &zSpecificLang );
+
+ XMP_StringPtr genericLang = zGenericLang.c_str();
+ XMP_StringPtr specificLang = zSpecificLang.c_str();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ // Find the LangAlt array and the selected array item.
+
+ XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly );
+ if ( arrayNode == 0 ) return;
+ size_t arraySize = arrayNode->children.size();
+
+ XMP_CLTMatch match;
+ XMP_Node * itemNode;
+
+ match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, (const XMP_Node **) &itemNode );
+ if ( match != kXMP_CLT_SpecificMatch ) return;
+
+ size_t itemIndex = 0;
+ for ( ; itemIndex < arraySize; ++itemIndex ) {
+ if ( arrayNode->children[itemIndex] == itemNode ) break;
+ }
+ XMP_Enforce ( itemIndex < arraySize );
+
+ // Decide if the selected item is x-default or not, find relevant matching item.
+
+ bool itemIsXDefault = false;
+ if ( ! itemNode->qualifiers.empty() ) {
+ XMP_Node * qualNode = itemNode->qualifiers[0];
+ if ( (qualNode->name == "xml:lang") && (qualNode->value == "x-default") ) itemIsXDefault = true;
+ }
+
+ if ( itemIsXDefault && (itemIndex != 0) ) { // Enforce the x-default is first policy.
+ XMP_Node * temp = arrayNode->children[0];
+ arrayNode->children[0] = arrayNode->children[itemIndex];
+ arrayNode->children[itemIndex] = temp;
+ itemIndex = 0;
+ }
+
+ XMP_Node * assocNode = 0;
+ size_t assocIndex;
+ size_t assocIsXDefault = false;
+
+ if ( itemIsXDefault ) {
+
+ for ( assocIndex = 1; assocIndex < arraySize; ++assocIndex ) {
+ if ( arrayNode->children[assocIndex]->value == itemNode->value ) {
+ assocNode = arrayNode->children[assocIndex];
+ break;
+ }
+ }
+
+ } else if ( itemIndex > 0 ) {
+
+ XMP_Node * itemZero = arrayNode->children[0];
+ if ( itemZero->value == itemNode->value ) {
+ XMP_Node * qualNode = itemZero->qualifiers[0];
+ if ( (qualNode->name == "xml:lang") && (qualNode->value == "x-default") ) {
+ assocNode = arrayNode->children[0];
+ assocIndex = 0;
+ assocIsXDefault = true;
+ }
+ }
+
+ }
+
+ // Delete the appropriate nodes.
+
+ XMP_NodePtrPos arrayBegin = arrayNode->children.begin();
+
+ if ( assocNode == 0 ) {
+ arrayNode->children.erase ( arrayBegin + itemIndex );
+ } else if ( itemIndex < assocIndex ) {
+ arrayNode->children.erase ( arrayBegin + assocIndex );
+ arrayNode->children.erase ( arrayBegin + itemIndex );
+ } else {
+ arrayNode->children.erase ( arrayBegin + itemIndex );
+ arrayNode->children.erase ( arrayBegin + assocIndex );
+ }
+
+ delete itemNode;
+ if ( assocNode != 0 ) delete assocNode;
+
+} // DeleteLocalizedText
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Bool
+// ----------------
+
+bool
+XMPMeta::GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ *propValue = XMPUtils::ConvertToBool ( valueStr );
+ }
+ return found;
+
+} // GetProperty_Bool
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Int
+// ---------------
+
+bool
+XMPMeta::GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Int64 tempValue64 = 0;
+ if ( GetProperty_Int64( schemaNS, propName, &tempValue64, options ) ) {
+ if ( tempValue64 < (XMP_Int64) Min_XMP_Int32 || tempValue64 > (XMP_Int64) Max_XMP_Int32 ) {
+ // overflow condition
+ XMP_Throw ( "Overflow condition", kXMPErr_BadValue );
+ } else {
+ *propValue = (XMP_Int32) tempValue64;
+ return true;
+ }
+ }
+ return false;
+
+} // GetProperty_Int
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Int64
+// -----------------
+
+bool
+XMPMeta::GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ std::string propValueStr;
+ propValueStr.append( valueStr, valueLen );
+ XMPUtils::Trim( propValueStr );
+ *propValue = XMPUtils::ConvertToInt64 ( propValueStr.c_str() );
+ }
+ return found;
+
+} // GetProperty_Int64
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Float
+// -----------------
+
+bool
+XMPMeta::GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ std::string propValueStr;
+ propValueStr.append( valueStr, valueLen );
+ XMPUtils::Trim( propValueStr );
+ *propValue = XMPUtils::ConvertToFloat ( propValueStr.c_str() );
+ }
+ return found;
+
+} // GetProperty_Float
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty_Date
+// ----------------
+
+bool
+XMPMeta::GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
+
+ XMP_StringPtr valueStr;
+ XMP_StringLen valueLen;
+
+ bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
+ if ( found ) {
+ if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
+ XMPUtils::ConvertToDate ( valueStr, propValue );
+ }
+ return found;
+
+} // GetProperty_Date
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Bool
+// ----------------
+
+void
+XMPMeta::SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString valueStr;
+ XMPUtils::ConvertFromBool ( propValue, &valueStr );
+ SetProperty ( schemaNS, propName, valueStr.c_str(), options );
+
+} // SetProperty_Bool
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Int
+// ---------------
+
+void
+XMPMeta::SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString valueStr;
+ XMPUtils::ConvertFromInt ( propValue, "", &valueStr );
+ SetProperty ( schemaNS, propName, valueStr.c_str(), options );
+
+} // SetProperty_Int
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Int64
+// -----------------
+
+void
+XMPMeta::SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString valueStr;
+ XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr );
+ SetProperty ( schemaNS, propName, valueStr.c_str(), options );
+
+} // SetProperty_Int64
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Float
+// -----------------
+
+void
+XMPMeta::SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString valueStr;
+ XMPUtils::ConvertFromFloat ( propValue, "", &valueStr );
+ SetProperty ( schemaNS, propName, valueStr.c_str(), options );
+
+} // SetProperty_Float
+
+
+// -------------------------------------------------------------------------------------------------
+// SetProperty_Date
+// ----------------
+
+void
+XMPMeta::SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_VarString valueStr;
+ XMPUtils::ConvertFromDate ( propValue, &valueStr );
+ SetProperty ( schemaNS, propName, valueStr.c_str(), options );
+
+} // SetProperty_Date
+
+// =================================================================================================
+
diff --git a/gpr/source/lib/xmp_core/XMPMeta-Parse.cpp b/gpr/source/lib/xmp_core/XMPMeta-Parse.cpp
new file mode 100644
index 0000000..28f628a
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPMeta-Parse.cpp
@@ -0,0 +1,1277 @@
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "XMPUtils.hpp"
+
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+#include "ExpatAdapter.hpp"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+#ifndef Trace_ParsingHackery
+ #define Trace_ParsingHackery 0
+#endif
+
+static const char * kReplaceLatin1[128] =
+ {
+
+ // The 0x80..0x9F range is undefined in Latin-1, but is defined in Windows code page 1252.
+ // The bytes 0x81, 0x8D, 0x8F, 0x90, and 0x9D are formally undefined by Windows 1252, but
+ // their conversion API maps them to U+0081, etc. These are in XML's RestrictedChar set, so
+ // we map them to a space.
+
+ "\xE2\x82\xAC", " ", "\xE2\x80\x9A", "\xC6\x92", // 0x80 .. 0x83
+ "\xE2\x80\x9E", "\xE2\x80\xA6", "\xE2\x80\xA0", "\xE2\x80\xA1", // 0x84 .. 0x87
+ "\xCB\x86", "\xE2\x80\xB0", "\xC5\xA0", "\xE2\x80\xB9", // 0x88 .. 0x8B
+ "\xC5\x92", " ", "\xC5\xBD", " ", // 0x8C .. 0x8F
+
+ " ", "\xE2\x80\x98", "\xE2\x80\x99", "\xE2\x80\x9C", // 0x90 .. 0x93
+ "\xE2\x80\x9D", "\xE2\x80\xA2", "\xE2\x80\x93", "\xE2\x80\x94", // 0x94 .. 0x97
+ "\xCB\x9C", "\xE2\x84\xA2", "\xC5\xA1", "\xE2\x80\xBA", // 0x98 .. 0x9B
+ "\xC5\x93", " ", "\xC5\xBE", "\xC5\xB8", // 0x9C .. 0x9F
+
+ // These are the UTF-8 forms of the official Latin-1 characters in the range 0xA0..0xFF. Not
+ // too surprisingly these map to U+00A0, etc. Which is the Unicode Latin Supplement range.
+
+ "\xC2\xA0", "\xC2\xA1", "\xC2\xA2", "\xC2\xA3", "\xC2\xA4", "\xC2\xA5", "\xC2\xA6", "\xC2\xA7", // 0xA0 .. 0xA7
+ "\xC2\xA8", "\xC2\xA9", "\xC2\xAA", "\xC2\xAB", "\xC2\xAC", "\xC2\xAD", "\xC2\xAE", "\xC2\xAF", // 0xA8 .. 0xAF
+
+ "\xC2\xB0", "\xC2\xB1", "\xC2\xB2", "\xC2\xB3", "\xC2\xB4", "\xC2\xB5", "\xC2\xB6", "\xC2\xB7", // 0xB0 .. 0xB7
+ "\xC2\xB8", "\xC2\xB9", "\xC2\xBA", "\xC2\xBB", "\xC2\xBC", "\xC2\xBD", "\xC2\xBE", "\xC2\xBF", // 0xB8 .. 0xBF
+
+ "\xC3\x80", "\xC3\x81", "\xC3\x82", "\xC3\x83", "\xC3\x84", "\xC3\x85", "\xC3\x86", "\xC3\x87", // 0xC0 .. 0xC7
+ "\xC3\x88", "\xC3\x89", "\xC3\x8A", "\xC3\x8B", "\xC3\x8C", "\xC3\x8D", "\xC3\x8E", "\xC3\x8F", // 0xC8 .. 0xCF
+
+ "\xC3\x90", "\xC3\x91", "\xC3\x92", "\xC3\x93", "\xC3\x94", "\xC3\x95", "\xC3\x96", "\xC3\x97", // 0xD0 .. 0xD7
+ "\xC3\x98", "\xC3\x99", "\xC3\x9A", "\xC3\x9B", "\xC3\x9C", "\xC3\x9D", "\xC3\x9E", "\xC3\x9F", // 0xD8 .. 0xDF
+
+ "\xC3\xA0", "\xC3\xA1", "\xC3\xA2", "\xC3\xA3", "\xC3\xA4", "\xC3\xA5", "\xC3\xA6", "\xC3\xA7", // 0xE0 .. 0xE7
+ "\xC3\xA8", "\xC3\xA9", "\xC3\xAA", "\xC3\xAB", "\xC3\xAC", "\xC3\xAD", "\xC3\xAE", "\xC3\xAF", // 0xE8 .. 0xEF
+
+ "\xC3\xB0", "\xC3\xB1", "\xC3\xB2", "\xC3\xB3", "\xC3\xB4", "\xC3\xB5", "\xC3\xB6", "\xC3\xB7", // 0xF0 .. 0xF7
+ "\xC3\xB8", "\xC3\xB9", "\xC3\xBA", "\xC3\xBB", "\xC3\xBC", "\xC3\xBD", "\xC3\xBE", "\xC3\xBF", // 0xF8 .. 0xFF
+
+ };
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) )
+#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) )
+
+
+// -------------------------------------------------------------------------------------------------
+// PickBestRoot
+// ------------
+//
+// Pick the first x:xmpmeta among multiple root candidates. If there aren't any, pick the first bare
+// rdf:RDF if that is allowed. The returned root is the rdf:RDF child if an x:xmpmeta element was
+// chosen. The search is breadth first, so a higher level candiate is chosen over a lower level one
+// that was textually earlier in the serialized XML.
+
+static const XML_Node * PickBestRoot ( const XML_Node & xmlParent, XMP_OptionBits options )
+{
+
+ // Look among this parent's content for x:xmpmeta. The recursion for x:xmpmeta is broader than
+ // the strictly defined choice, but gives us smaller code.
+ for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) {
+ const XML_Node * childNode = xmlParent.content[childNum];
+ if ( childNode->kind != kElemNode ) continue;
+ if ( (childNode->name == "x:xmpmeta") || (childNode->name == "x:xapmeta") ) return PickBestRoot ( *childNode, 0 );
+ }
+ // Look among this parent's content for a bare rdf:RDF if that is allowed.
+ if ( ! (options & kXMP_RequireXMPMeta) ) {
+ for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) {
+ const XML_Node * childNode = xmlParent.content[childNum];
+ if ( childNode->kind != kElemNode ) continue;
+ if ( childNode->name == "rdf:RDF" ) return childNode;
+ }
+ }
+
+ // Recurse into the content.
+ for ( size_t childNum = 0, childLim = xmlParent.content.size(); childNum < childLim; ++childNum ) {
+ const XML_Node * foundRoot = PickBestRoot ( *xmlParent.content[childNum], options );
+ if ( foundRoot != 0 ) return foundRoot;
+ }
+
+ return 0;
+
+} // PickBestRoot
+
+// -------------------------------------------------------------------------------------------------
+// FindRootNode
+// ------------
+//
+// Find the XML node that is the root of the XMP data tree. Generally this will be an outer node,
+// but it could be anywhere if a general XML document is parsed (e.g. SVG). The XML parser counted
+// all possible root nodes, and kept a pointer to the last one. If there is more than one possible
+// root use PickBestRoot to choose among them.
+//
+// If there is a root node, try to extract the version of the previous XMP toolkit.
+
+static const XML_Node * FindRootNode ( const XMLParserAdapter & xmlParser, XMP_OptionBits options )
+{
+ const XML_Node * rootNode = xmlParser.rootNode;
+
+ if ( xmlParser.rootCount > 1 ) rootNode = PickBestRoot ( xmlParser.tree, options );
+ if ( rootNode == 0 ) return 0;
+
+ XMP_Assert ( rootNode->name == "rdf:RDF" );
+
+ if ( (options & kXMP_RequireXMPMeta) &&
+ ((rootNode->parent == 0) ||
+ ((rootNode->parent->name != "x:xmpmeta") && (rootNode->parent->name != "x:xapmeta"))) ) return 0;
+
+ return rootNode;
+
+} // FindRootNode
+
+// -------------------------------------------------------------------------------------------------
+// NormalizeDCArrays
+// -----------------
+//
+// Undo the denormalization performed by the XMP used in Acrobat 5. If a Dublin Core array had only
+// one item, it was serialized as a simple property. The xml:lang attribute was dropped from an
+// alt-text item if the language was x-default.
+
+// *** This depends on the dc: namespace prefix.
+
+static void
+NormalizeDCArrays ( XMP_Node * xmpTree )
+{
+ XMP_Node * dcSchema = FindSchemaNode ( xmpTree, kXMP_NS_DC, kXMP_ExistingOnly );
+ if ( dcSchema == 0 ) return;
+
+ for ( size_t propNum = 0, propLimit = dcSchema->children.size(); propNum < propLimit; ++propNum ) {
+ XMP_Node * currProp = dcSchema->children[propNum];
+ XMP_OptionBits arrayForm = 0;
+
+ if ( ! XMP_PropIsSimple ( currProp->options ) ) continue; // Nothing to do if not simple.
+
+ if ( (currProp->name == "dc:creator" ) || // See if it is supposed to be an array.
+ (currProp->name == "dc:date" ) ) { // *** Think about an array of char* and a loop.
+ arrayForm = kXMP_PropArrayIsOrdered;
+ } else if (
+ (currProp->name == "dc:description" ) ||
+ (currProp->name == "dc:rights" ) ||
+ (currProp->name == "dc:title" ) ) {
+ arrayForm = kXMP_PropArrayIsAltText;
+ } else if (
+ (currProp->name == "dc:contributor" ) ||
+ (currProp->name == "dc:language" ) ||
+ (currProp->name == "dc:publisher" ) ||
+ (currProp->name == "dc:relation" ) ||
+ (currProp->name == "dc:subject" ) ||
+ (currProp->name == "dc:type" ) ) {
+ arrayForm = kXMP_PropValueIsArray;
+ }
+ if ( arrayForm == 0 ) continue; // Nothing to do if it isn't supposed to be an array.
+
+ arrayForm = VerifySetOptions ( arrayForm, 0 ); // Set the implicit array bits.
+ XMP_Node * newArray = new XMP_Node ( dcSchema, currProp->name.c_str(), arrayForm );
+ dcSchema->children[propNum] = newArray;
+
+ if ( currProp->value.empty() ) { // Don't add an empty item, leave the array empty.
+
+ delete ( currProp );
+
+ } else {
+
+ newArray->children.push_back ( currProp );
+ currProp->parent = newArray;
+ currProp->name = kXMP_ArrayItemName;
+
+ if ( XMP_ArrayIsAltText ( arrayForm ) && (! (currProp->options & kXMP_PropHasLang)) ) {
+ XMP_Node * newLang = new XMP_Node ( currProp, "xml:lang", "x-default", kXMP_PropIsQualifier );
+ currProp->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+ if ( currProp->qualifiers.empty() ) { // *** Need a util?
+ currProp->qualifiers.push_back ( newLang );
+ } else {
+ currProp->qualifiers.insert ( currProp->qualifiers.begin(), newLang );
+ }
+ }
+
+ }
+
+ }
+
+} // NormalizeDCArrays
+
+
+// -------------------------------------------------------------------------------------------------
+// CompareAliasedSubtrees
+// ----------------------
+
+// *** Change to do some alias-specific setup, then use CompareSubtrees. One special case for
+// *** aliases is a simple to x-default alias, the options and qualifiers obviously differ.
+
+static void
+CompareAliasedSubtrees ( XMP_Node * aliasNode, XMP_Node * baseNode,
+ XMPMeta::ErrorCallbackInfo & errorCallback, bool outerCall = true )
+{
+ // ! The outermost call is special. The names almost certainly differ. The qualifiers (and
+ // ! hence options) will differ for an alias to the x-default item of a langAlt array.
+
+ if ( (aliasNode->value != baseNode->value) ||
+ (aliasNode->children.size() != baseNode->children.size()) ) {
+ // Keep things simple for now. Aliases are virtually unused, so this is very unlikely to
+ // happen. Recovery can be added later if it becomes important.
+ XMP_Error error(kXMPErr_BadXMP, "Mismatch between alias and base nodes");
+ errorCallback.NotifyClient ( kXMPErrSev_OperationFatal, error );
+ }
+
+ if ( ! outerCall ) {
+ if ( (aliasNode->name != baseNode->name) ||
+ (aliasNode->options != baseNode->options) ||
+ (aliasNode->qualifiers.size() != baseNode->qualifiers.size()) ) {
+ // Keep things simple for now. Aliases are virtually unused, so this is very unlikely to
+ // happen. Recovery can be added later if it becomes important.
+ XMP_Error error(kXMPErr_BadXMP, "Mismatch between alias and base nodes");
+ errorCallback.NotifyClient ( kXMPErrSev_OperationFatal, error );
+ }
+ }
+
+ for ( size_t childNum = 0, childLim = aliasNode->children.size(); childNum < childLim; ++childNum ) {
+ XMP_Node * aliasChild = aliasNode->children[childNum];
+ XMP_Node * baseChild = baseNode->children[childNum];
+ CompareAliasedSubtrees ( aliasChild, baseChild, errorCallback, false );
+ }
+
+ for ( size_t qualNum = 0, qualLim = aliasNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ XMP_Node * aliasQual = aliasNode->qualifiers[qualNum];
+ XMP_Node * baseQual = baseNode->qualifiers[qualNum];
+ CompareAliasedSubtrees ( aliasQual, baseQual, errorCallback, false );
+ }
+
+} // CompareAliasedSubtrees
+
+
+// -------------------------------------------------------------------------------------------------
+// TransplantArrayItemAlias
+// ------------------------
+
+static void
+TransplantArrayItemAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent,
+ XMPMeta::ErrorCallbackInfo & errorCallback )
+{
+ XMP_Node * childNode = oldParent->children[oldNum];
+
+ if ( newParent->options & kXMP_PropArrayIsAltText ) {
+ if ( childNode->options & kXMP_PropHasLang ) {
+ // Keep things simple for now. Aliases are virtually unused, so this is very unlikely to
+ // happen. Recovery can be added later if it becomes important.
+ XMP_Error error(kXMPErr_BadXMP, "Alias to x-default already has a language qualifier");
+ errorCallback.NotifyClient ( kXMPErrSev_OperationFatal, error ); // *** Allow x-default.
+ }
+ childNode->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+ XMP_Node * langQual = new XMP_Node ( childNode, "xml:lang", "x-default", kXMP_PropIsQualifier ); // *** AddLangQual util?
+ if ( childNode->qualifiers.empty() ) {
+ childNode->qualifiers.push_back ( langQual );
+ } else {
+ childNode->qualifiers.insert ( childNode->qualifiers.begin(), langQual );
+ }
+ }
+
+ oldParent->children.erase ( oldParent->children.begin() + oldNum );
+ childNode->name = kXMP_ArrayItemName;
+ childNode->parent = newParent;
+ if ( newParent->children.empty() ) {
+ newParent->children.push_back ( childNode );
+ } else {
+ newParent->children.insert ( newParent->children.begin(), childNode );
+ }
+
+} // TransplantArrayItemAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// TransplantNamedAlias
+// --------------------
+
+static void
+TransplantNamedAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent, XMP_VarString & newName )
+{
+ XMP_Node * childNode = oldParent->children[oldNum];
+
+ oldParent->children.erase ( oldParent->children.begin() + oldNum );
+ childNode->name = newName;
+ childNode->parent = newParent;
+ newParent->children.push_back ( childNode );
+
+} // TransplantNamedAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// MoveExplicitAliases
+// -------------------
+
+static void
+MoveExplicitAliases ( XMP_Node * tree, XMP_OptionBits parseOptions, XMPMeta::ErrorCallbackInfo & errorCallback )
+{
+ tree->options ^= kXMP_PropHasAliases;
+ const bool strictAliasing = ((parseOptions & kXMP_StrictAliasing) != 0);
+
+ // Visit all of the top level nodes looking for aliases. If there is no base, transplant the
+ // alias subtree. If there is a base and strict aliasing is on, make sure the alias and base
+ // subtrees match.
+
+ // ! Use "while" loops not "for" loops since both the schema and property loops can remove the
+ // ! current item from the vector being traversed. And don't increment the counter for a delete.
+
+ size_t schemaNum = 0;
+ while ( schemaNum < tree->children.size() ) {
+ XMP_Node * currSchema = tree->children[schemaNum];
+
+ size_t propNum = 0;
+ while ( propNum < currSchema->children.size() ) {
+ XMP_Node * currProp = currSchema->children[propNum];
+ if ( ! (currProp->options & kXMP_PropIsAlias) ) {
+ ++propNum;
+ continue;
+ }
+ currProp->options ^= kXMP_PropIsAlias;
+
+ // Find the base path, look for the base schema and root node.
+
+ XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find ( currProp->name );
+ XMP_Assert ( aliasPos != sRegisteredAliasMap->end() );
+ XMP_ExpandedXPath & basePath = aliasPos->second;
+ XMP_OptionBits arrayOptions = (basePath[kRootPropStep].options & kXMP_PropArrayFormMask);
+
+ XMP_Node * baseSchema = FindSchemaNode ( tree, basePath[kSchemaStep].step.c_str(), kXMP_CreateNodes );
+ if ( baseSchema->options & kXMP_NewImplicitNode ) baseSchema->options ^= kXMP_NewImplicitNode;
+ XMP_Node * baseNode = FindChildNode ( baseSchema, basePath[kRootPropStep].step.c_str(), kXMP_ExistingOnly );
+
+ if ( baseNode == 0 ) {
+
+ if ( basePath.size() == 2 ) {
+ // A top-to-top alias, transplant the property.
+ TransplantNamedAlias ( currSchema, propNum, baseSchema, basePath[kRootPropStep].step );
+ } else {
+ // An alias to an array item, create the array and transplant the property.
+ baseNode = new XMP_Node ( baseSchema, basePath[kRootPropStep].step.c_str(), arrayOptions );
+ baseSchema->children.push_back ( baseNode );
+ TransplantArrayItemAlias ( currSchema, propNum, baseNode, errorCallback );
+ }
+
+ } else if ( basePath.size() == 2 ) {
+
+ // The base node does exist and this is a top-to-top alias. Check for conflicts if
+ // strict aliasing is on. Remove and delete the alias subtree.
+ if ( strictAliasing ) CompareAliasedSubtrees ( currProp, baseNode, errorCallback );
+ currSchema->children.erase ( currSchema->children.begin() + propNum );
+ delete currProp;
+
+ } else {
+
+ // This is an alias to an array item and the array exists. Look for the aliased item.
+ // Then transplant or check & delete as appropriate.
+
+ XMP_Node * itemNode = 0;
+ if ( arrayOptions & kXMP_PropArrayIsAltText ) {
+ XMP_Index xdIndex = LookupLangItem ( baseNode, *xdefaultName );
+ if ( xdIndex != -1 ) itemNode = baseNode->children[xdIndex];
+ } else if ( ! baseNode->children.empty() ) {
+ itemNode = baseNode->children[0];
+ }
+
+ if ( itemNode == 0 ) {
+ TransplantArrayItemAlias ( currSchema, propNum, baseNode, errorCallback );
+ } else {
+ if ( strictAliasing ) CompareAliasedSubtrees ( currProp, itemNode, errorCallback );
+ currSchema->children.erase ( currSchema->children.begin() + propNum );
+ delete currProp;
+ }
+
+ }
+
+ } // Property loop
+
+ // Increment the counter or remove an empty schema node.
+ if ( currSchema->children.size() > 0 ) {
+ ++schemaNum;
+ } else {
+ delete tree->children[schemaNum]; // ! Delete the schema node itself.
+ tree->children.erase ( tree->children.begin() + schemaNum );
+ }
+
+ } // Schema loop
+
+} // MoveExplicitAliases
+
+
+// -------------------------------------------------------------------------------------------------
+// FixGPSTimeStamp
+// ---------------
+
+static void
+FixGPSTimeStamp ( XMP_Node * exifSchema, XMP_Node * gpsDateTime )
+{
+ XMP_DateTime binGPSStamp;
+ try {
+ XMPUtils::ConvertToDate ( gpsDateTime->value.c_str(), &binGPSStamp );
+ } catch ( ... ) {
+ return; // Don't let a bad date stop other things.
+ }
+ if ( (binGPSStamp.year != 0) || (binGPSStamp.month != 0) || (binGPSStamp.day != 0) ) return;
+
+ XMP_Node * otherDate = FindChildNode ( exifSchema, "exif:DateTimeOriginal", kXMP_ExistingOnly );
+ if ( otherDate == 0 ) otherDate = FindChildNode ( exifSchema, "exif:DateTimeDigitized", kXMP_ExistingOnly );
+ if ( otherDate == 0 ) return;
+
+ XMP_DateTime binOtherDate;
+ try {
+ XMPUtils::ConvertToDate ( otherDate->value.c_str(), &binOtherDate );
+ } catch ( ... ) {
+ return; // Don't let a bad date stop other things.
+ }
+
+ binGPSStamp.year = binOtherDate.year;
+ binGPSStamp.month = binOtherDate.month;
+ binGPSStamp.day = binOtherDate.day;
+
+ XMPUtils::ConvertFromDate ( binGPSStamp, &gpsDateTime->value );
+
+} // FixGPSTimeStamp
+
+
+// -------------------------------------------------------------------------------------------------
+// MigrateAudioCopyright
+// ---------------------
+//
+// The initial support for WAV files mapped a legacy ID3 audio copyright into a new xmpDM:copyright
+// property. This is special case code to migrate that into dc:rights['x-default']. The rules:
+//
+// 1. If there is no dc:rights array, or an empty array -
+// Create one with dc:rights['x-default'] set from double linefeed and xmpDM:copyright.
+//
+// 2. If there is a dc:rights array but it has no x-default item -
+// Create an x-default item as a copy of the first item then apply rule #3.
+//
+// 3. If there is a dc:rights array with an x-default item, look for a double linefeed in the value.
+// A. If no double linefeed, compare the x-default value to the xmpDM:copyright value.
+// A1. If they match then leave the x-default value alone.
+// A2. Otherwise, append a double linefeed and the xmpDM:copyright value to the x-default value.
+// B. If there is a double linefeed, compare the trailing text to the xmpDM:copyright value.
+// B1. If they match then leave the x-default value alone.
+// B2. Otherwise, replace the trailing x-default text with the xmpDM:copyright value.
+//
+// 4. In all cases, delete the xmpDM:copyright property.
+
+static void
+MigrateAudioCopyright ( XMPMeta * xmp, XMP_Node * dmCopyright )
+{
+
+ try {
+
+ std::string & dmValue = dmCopyright->value;
+ static const char * kDoubleLF = "\xA\xA";
+
+ XMP_Node * dcSchema = FindSchemaNode ( &xmp->tree, kXMP_NS_DC, kXMP_CreateNodes );
+ XMP_Node * dcRightsArray = FindChildNode ( dcSchema, "dc:rights", kXMP_ExistingOnly );
+
+ if ( (dcRightsArray == 0) || dcRightsArray->children.empty() ) {
+
+ // 1. No dc:rights array, create from double linefeed and xmpDM:copyright.
+ dmValue.insert ( 0, kDoubleLF );
+ xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", dmValue.c_str(), 0 );
+
+ } else {
+
+ std::string xdefaultStr ( "x-default" );
+
+ XMP_Index xdIndex = LookupLangItem ( dcRightsArray, xdefaultStr );
+
+ if ( xdIndex < 0 ) {
+ // 2. No x-default item, create from the first item.
+ XMP_StringPtr firstValue = dcRightsArray->children[0]->value.c_str();
+ xmp->SetLocalizedText ( kXMP_NS_DC, "rights", "", "x-default", firstValue, 0 );
+ xdIndex = LookupLangItem ( dcRightsArray, xdefaultStr );
+ }
+
+ // 3. Look for a double linefeed in the x-default value.
+ XMP_Assert ( xdIndex == 0 );
+ std::string & defaultValue = dcRightsArray->children[xdIndex]->value;
+ XMP_Index lfPos = defaultValue.find ( kDoubleLF );
+
+ if ( lfPos < 0 ) {
+
+ // 3A. No double LF, compare whole values.
+ if ( dmValue != defaultValue ) {
+ // 3A2. Append the xmpDM:copyright to the x-default item.
+ defaultValue += kDoubleLF;
+ defaultValue += dmValue;
+ }
+
+ } else {
+
+ // 3B. Has double LF, compare the tail.
+ if ( defaultValue.compare ( lfPos+2, std::string::npos, dmValue ) != 0 ) {
+ // 3B2. Replace the x-default tail.
+ defaultValue.replace ( lfPos+2, std::string::npos, dmValue );
+ }
+
+ }
+
+ }
+
+ // 4. Get rid of the xmpDM:copyright.
+ xmp->DeleteProperty ( kXMP_NS_DM, "copyright" );
+
+ } catch ( ... ) {
+ // Don't let failures (like a bad dc:rights form) stop other cleanup.
+ }
+
+} // MigrateAudioCopyright
+
+
+// -------------------------------------------------------------------------------------------------
+// RepairAltText
+// -------------
+//
+// Make sure that the array is well-formed AltText. Each item must be simple and have an xml:lang
+// qualifier. If repairs are needed, keep simple non-empty items by adding the xml:lang.
+
+static void
+RepairAltText ( XMP_Node & tree, XMP_StringPtr schemaNS, XMP_StringPtr arrayName )
+{
+ XMP_Node * schemaNode = FindSchemaNode ( &tree, schemaNS, kXMP_ExistingOnly );
+ if ( schemaNode == 0 ) return;
+
+ XMP_Node * arrayNode = FindChildNode ( schemaNode, arrayName, kXMP_ExistingOnly );
+ if ( (arrayNode == 0) || XMP_ArrayIsAltText ( arrayNode->options ) ) return; // Already OK.
+
+ if ( ! XMP_PropIsArray ( arrayNode->options ) ) return; // ! Not even an array, leave it alone.
+ // *** Should probably change simple values to LangAlt with 'x-default' item.
+
+ arrayNode->options |= (kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText);
+
+ for ( int i = arrayNode->children.size()-1; i >= 0; --i ) { // ! Need a signed index type.
+
+ XMP_Node * currChild = arrayNode->children[i];
+
+ if ( ! XMP_PropIsSimple ( currChild->options ) ) {
+
+ // Delete non-simple children.
+ delete ( currChild );
+ arrayNode->children.erase ( arrayNode->children.begin() + i );
+
+ } else if ( ! XMP_PropHasLang ( currChild->options ) ) {
+
+ if ( currChild->value.empty() ) {
+
+ // Delete empty valued children that have no xml:lang.
+ delete ( currChild );
+ arrayNode->children.erase ( arrayNode->children.begin() + i );
+
+ } else {
+
+ // Add an xml:lang qualifier with the value "x-repair".
+ XMP_Node * repairLang = new XMP_Node ( currChild, "xml:lang", "x-repair", kXMP_PropIsQualifier );
+ if ( currChild->qualifiers.empty() ) {
+ currChild->qualifiers.push_back ( repairLang );
+ } else {
+ currChild->qualifiers.insert ( currChild->qualifiers.begin(), repairLang );
+ }
+ currChild->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+
+ }
+
+ }
+
+ }
+
+} // RepairAltText
+
+
+// -------------------------------------------------------------------------------------------------
+// TouchUpDataModel
+// ----------------
+
+static void
+TouchUpDataModel ( XMPMeta * xmp, XMPMeta::ErrorCallbackInfo & errorCallback )
+{
+ XMP_Node & tree = xmp->tree;
+
+ // Do special case touch ups for certain schema.
+
+ XMP_Node * currSchema = 0;
+
+ currSchema = FindSchemaNode ( &tree, kXMP_NS_EXIF, kXMP_ExistingOnly );
+ if ( currSchema != 0 ) {
+
+ // Do a special case fix for exif:GPSTimeStamp.
+ XMP_Node * gpsDateTime = FindChildNode ( currSchema, "exif:GPSTimeStamp", kXMP_ExistingOnly );
+ if ( gpsDateTime != 0 ) FixGPSTimeStamp ( currSchema, gpsDateTime );
+
+ // *** Should probably have RepairAltText change simple values to LangAlt with 'x-default' item.
+ // *** For now just do this for exif:UserComment, the one case we know about, late in cycle fix.
+ XMP_Node * userComment = FindChildNode ( currSchema, "exif:UserComment", kXMP_ExistingOnly );
+ if ( (userComment != 0) && XMP_PropIsSimple ( userComment->options ) ) {
+ XMP_Node * newChild = new XMP_Node ( userComment, kXMP_ArrayItemName,
+ userComment->value.c_str(), userComment->options );
+ newChild->qualifiers.swap ( userComment->qualifiers );
+ if ( ! XMP_PropHasLang ( newChild->options ) ) {
+ XMP_Node * langQual = new XMP_Node ( newChild, "xml:lang", "x-default", kXMP_PropIsQualifier );
+ newChild->qualifiers.insert ( newChild->qualifiers.begin(), langQual );
+ newChild->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang);
+ }
+ userComment->value.erase();
+ userComment->options = kXMP_PropArrayFormMask; // ! Happens to have all the right bits.
+ userComment->children.push_back ( newChild );
+ }
+
+ }
+
+ currSchema = FindSchemaNode ( &tree, kXMP_NS_DM, kXMP_ExistingOnly );
+ if ( currSchema != 0 ) {
+ // Do a special case migration of xmpDM:copyright to dc:rights['x-default']. Do this before
+ // the dc: touch up since it can affect the dc: schema.
+ XMP_Node * dmCopyright = FindChildNode ( currSchema, "xmpDM:copyright", kXMP_ExistingOnly );
+ if ( dmCopyright != 0 ) MigrateAudioCopyright ( xmp, dmCopyright );
+ }
+
+ currSchema = FindSchemaNode ( &tree, kXMP_NS_DC, kXMP_ExistingOnly );
+ if ( currSchema != 0 ) {
+ // Do a special case fix for dc:subject, make sure it is an unordered array.
+ XMP_Node * dcSubject = FindChildNode ( currSchema, "dc:subject", kXMP_ExistingOnly );
+ if ( dcSubject != 0 ) {
+ XMP_OptionBits keepMask = ~(kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText);
+ dcSubject->options &= keepMask; // Make sure any ordered array bits are clear.
+ }
+ }
+
+ // Fix any broken AltText arrays that we know about.
+
+ RepairAltText ( tree, kXMP_NS_DC, "dc:description" ); // ! Note inclusion of prefixes for direct node lookup!
+ RepairAltText ( tree, kXMP_NS_DC, "dc:rights" );
+ RepairAltText ( tree, kXMP_NS_DC, "dc:title" );
+ RepairAltText ( tree, kXMP_NS_XMP_Rights, "xmpRights:UsageTerms" );
+ RepairAltText ( tree, kXMP_NS_EXIF, "exif:UserComment" );
+
+ // Tweak old XMP: Move an instance ID from rdf:about to the xmpMM:InstanceID property. An old
+ // instance ID usually looks like "uuid:bac965c4-9d87-11d9-9a30-000d936b79c4", plus InDesign
+ // 3.0 wrote them like "bac965c4-9d87-11d9-9a30-000d936b79c4". If the name looks like a UUID
+ // simply move it to xmpMM:InstanceID, don't worry about any existing xmpMM:InstanceID. Both
+ // will only be present when a newer file with the xmpMM:InstanceID property is updated by an
+ // old app that uses rdf:about.
+
+ if ( ! tree.name.empty() ) {
+
+ bool nameIsUUID = false;
+ XMP_StringPtr nameStr = tree.name.c_str();
+
+ if ( XMP_LitNMatch ( nameStr, "uuid:", 5 ) ) {
+
+ nameIsUUID = true;
+
+ } else if ( tree.name.size() == 36 ) {
+
+ nameIsUUID = true; // ! Assume true, we'll set it to false below if not.
+ for ( int i = 0; i < 36; ++i ) {
+ char ch = nameStr[i];
+ if ( ch == '-' ) {
+ if ( (i == 8) || (i == 13) || (i == 18) || (i == 23) ) continue;
+ nameIsUUID = false;
+ break;
+ } else {
+ if ( (('0' <= ch) && (ch <= '9')) || (('a' <= ch) && (ch <= 'z')) ) continue;
+ nameIsUUID = false;
+ break;
+ }
+ }
+
+ }
+
+ if ( nameIsUUID ) {
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( kXMP_NS_XMP_MM, "InstanceID", &expPath );
+ XMP_Node * idNode = FindNode ( &tree, expPath, kXMP_CreateNodes, 0 );
+ if ( idNode == 0 ) XMP_Throw ( "Failure creating xmpMM:InstanceID", kXMPErr_InternalFailure );
+
+ idNode->options = 0; // Clobber any existing xmpMM:InstanceID.
+ idNode->value = tree.name;
+ idNode->RemoveChildren();
+ idNode->RemoveQualifiers();
+
+ tree.name.erase();
+
+ }
+
+ }
+
+} // TouchUpDataModel
+
+
+// -------------------------------------------------------------------------------------------------
+// DetermineInputEncoding
+// ----------------------
+//
+// Try to determine the character encoding, making a guess if the input is too short. We make some
+// simplifying assumtions: the first character must be U+FEFF or ASCII, U+0000 is not allowed. The
+// XML 1.1 spec is even more strict, UTF-16 XML documents must begin with U+FEFF, and the first
+// "real" character must be '<'. Ignoring the XML declaration, the first XML character could be '<',
+// space, tab, CR, or LF.
+//
+// The possible input sequences are:
+//
+// Cases with U+FEFF
+// EF BB BF -- - UTF-8
+// FE FF -- -- - Big endian UTF-16
+// 00 00 FE FF - Big endian UTF 32
+// FF FE 00 00 - Little endian UTF-32
+// FF FE -- -- - Little endian UTF-16
+//
+// Cases with ASCII
+// nn mm -- -- - UTF-8 -
+// 00 00 00 nn - Big endian UTF-32
+// 00 nn -- -- - Big endian UTF-16
+// nn 00 00 00 - Little endian UTF-32
+// nn 00 -- -- - Little endian UTF-16
+//
+// ! We don't check for full patterns, or for errors. We just check enough to determine what the
+// ! only possible (or reasonable) case would be.
+
+static XMP_OptionBits
+DetermineInputEncoding ( const XMP_Uns8 * buffer, size_t length )
+{
+ if ( length < 2 ) return kXMP_EncodeUTF8;
+
+ XMP_Uns8 * uniChar = (XMP_Uns8*)buffer; // ! Make sure comparisons are unsigned.
+
+ if ( uniChar[0] == 0 ) {
+
+ // These cases are:
+ // 00 nn -- -- - Big endian UTF-16
+ // 00 00 00 nn - Big endian UTF-32
+ // 00 00 FE FF - Big endian UTF 32
+
+ if ( (length < 4) || (uniChar[1] != 0) ) return kXMP_EncodeUTF16Big;
+ return kXMP_EncodeUTF32Big;
+
+ } else if ( uniChar[0] < 0x80 ) {
+
+ // These cases are:
+ // nn mm -- -- - UTF-8, includes EF BB BF case
+ // nn 00 00 00 - Little endian UTF-32
+ // nn 00 -- -- - Little endian UTF-16
+
+ if ( uniChar[1] != 0 ) return kXMP_EncodeUTF8;
+ if ( (length < 4) || (uniChar[2] != 0) ) return kXMP_EncodeUTF16Little;
+ return kXMP_EncodeUTF32Little;
+
+ } else {
+
+ // These cases are:
+ // EF BB BF -- - UTF-8
+ // FE FF -- -- - Big endian UTF-16
+ // FF FE 00 00 - Little endian UTF-32
+ // FF FE -- -- - Little endian UTF-16
+
+ if ( uniChar[0] == 0xEF ) return kXMP_EncodeUTF8;
+ if ( uniChar[0] == 0xFE ) return kXMP_EncodeUTF16Big;
+ if ( (length < 4) || (uniChar[2] != 0) ) return kXMP_EncodeUTF16Little;
+ return kXMP_EncodeUTF32Little;
+
+ }
+
+} // DetermineInputEncoding
+
+
+// -------------------------------------------------------------------------------------------------
+// CountUTF8
+// ---------
+//
+// Look for a valid multi-byte UTF-8 sequence and return its length. Returns 0 for an invalid UTF-8
+// sequence. Returns a negative value for a partial valid sequence at the end of the buffer.
+//
+// The checking is not strict. We simply count the number of high order 1 bits in the first byte,
+// then look for n-1 following bytes whose high order 2 bits are 1 and 0. We do not check for a
+// minimal length representation of the codepoint, or that the codepoint is defined by Unicode.
+
+static int
+CountUTF8 ( const XMP_Uns8 * charStart, const XMP_Uns8 * bufEnd )
+{
+ XMP_Assert ( charStart < bufEnd ); // Catch this in debug builds.
+ if ( charStart >= bufEnd ) return 0; // Don't run-on in release builds.
+ if ( (*charStart & 0xC0) != 0xC0 ) return 0; // Must have at least 2 high bits set.
+
+ int byteCount = 2;
+ XMP_Uns8 firstByte = *charStart;
+ for ( firstByte = firstByte << 2; (firstByte & 0x80) != 0; firstByte = firstByte << 1 ) ++byteCount;
+
+ if ( (charStart + byteCount) > bufEnd ) return -byteCount;
+
+ for ( int i = 1; i < byteCount; ++i ) {
+ if ( (charStart[i] & 0xC0) != 0x80 ) return 0;
+ }
+
+ return byteCount;
+
+} // CountUTF8
+
+
+// -------------------------------------------------------------------------------------------------
+// CountControlEscape
+// ------------------
+//
+// Look for a numeric escape sequence for a "prohibited" ASCII control character. These are 0x7F,
+// and the range 0x00..0x1F except for tab/LF/CR. Return 0 if this is definitely not a numeric
+// escape, the length of the escape if found, or a negative value for a partial escape.
+
+static int
+CountControlEscape ( const XMP_Uns8 * escStart, const XMP_Uns8 * bufEnd )
+{
+ XMP_Assert ( escStart < bufEnd ); // Catch this in debug builds.
+ if ( escStart >= bufEnd ) return 0; // Don't run-on in release builds.
+ XMP_Assert ( *escStart == '&' );
+
+ size_t tailLen = bufEnd - escStart;
+ if ( tailLen < 5 ) return -1; // Don't need a more thorough check, we'll catch it on the next pass.
+
+ if ( strncmp ( (char*)escStart, "&#x", 3 ) != 0 ) return 0;
+
+ XMP_Uns8 escValue = 0;
+ const XMP_Uns8 * escPos = escStart + 3;
+
+ if ( ('0' <= *escPos) && (*escPos <= '9') ) {
+ escValue = *escPos - '0';
+ ++escPos;
+ } else if ( ('A' <= *escPos) && (*escPos <= 'F') ) {
+ escValue = *escPos - 'A' + 10;
+ ++escPos;
+ } else if ( ('a' <= *escPos) && (*escPos <= 'f') ) {
+ escValue = *escPos - 'a' + 10;
+ ++escPos;
+ }
+
+ if ( ('0' <= *escPos) && (*escPos <= '9') ) {
+ escValue = (escValue << 4) + (*escPos - '0');
+ ++escPos;
+ } else if ( ('A' <= *escPos) && (*escPos <= 'F') ) {
+ escValue = (escValue << 4) + (*escPos - 'A' + 10);
+ ++escPos;
+ } else if ( ('a' <= *escPos) && (*escPos <= 'f') ) {
+ escValue = (escValue << 4) + (*escPos - 'a' + 10);
+ ++escPos;
+ }
+
+ if ( escPos == bufEnd ) return -1; // Partial escape.
+ if ( *escPos != ';' ) return 0;
+
+ size_t escLen = escPos - escStart + 1;
+ if ( escLen < 5 ) return 0; // ! Catch "&#x;".
+
+ if ( (escValue == kTab) || (escValue == kLF) || (escValue == kCR) ) return 0; // An allowed escape.
+
+ return escLen; // Found a full "prohibited" numeric escape.
+
+} // CountControlEscape
+
+
+// -------------------------------------------------------------------------------------------------
+// ProcessUTF8Portion
+// ------------------
+//
+// Early versions of the XMP spec mentioned allowing ISO Latin-1 input. There are also problems with
+// some clients placing ASCII control characters within XMP values. This is an XML problem, the XML
+// spec only allows tab (0x09), LF (0x0A), and CR (0x0D) from the 0x00..0x1F range. As a concession
+// to this we scan 8-bit input for byte sequences that are not valid UTF-8 or in the 0x00..0x1F
+// range and replace each byte as follows:
+// 0x00..0x1F - Replace with a space, except for tab, CR, and LF.
+// 0x7F - Replace with a space. This is ASCII Delete, not allowed by ISO Latin-1.
+// 0x80..0x9F - Replace with the UTF-8 for a corresponding Unicode character.
+// 0xA0..0XFF - Replace with the UTF-8 for a corresponding Unicode character.
+//
+// The 0x80..0x9F range is not defined by Latin-1. But the Windows 1252 code page defines these and
+// is otherwise the same as Latin-1.
+//
+// For at least historical compatibility reasons we also find and replace singly escaped ASCII
+// control characters. The Expat parser we're using does not allow numeric escapes like "&#x10;".
+// The XML spec is clear that raw controls are not allowed (in the RestrictedChar set), but it isn't
+// as clear about numeric escapes for them. At any rate, Expat complains, so we treat the numeric
+// escapes like raw characters and replace them with a space.
+//
+// We check for 1 or 2 hex digits ("&#x9;" or "&#x09;") and upper or lower case ("&#xA;" or "&#xa;").
+// The full escape sequence is 5 or 6 bytes.
+
+static size_t
+ProcessUTF8Portion ( XMLParserAdapter * xmlParser,
+ const XMP_Uns8 * buffer,
+ size_t length,
+ bool last )
+{
+ const XMP_Uns8 * bufEnd = buffer + length;
+
+ const XMP_Uns8 * spanStart = buffer;
+ const XMP_Uns8 * spanEnd;
+
+ for ( spanEnd = spanStart; spanEnd < bufEnd; ++spanEnd ) {
+
+ if ( (0x20 <= *spanEnd) && (*spanEnd <= 0x7E) && (*spanEnd != '&') ) continue; // A regular ASCII character.
+
+ if ( *spanEnd >= 0x80 ) {
+
+ // See if this is a multi-byte UTF-8 sequence, or a Latin-1 character to replace.
+
+ int uniLen = CountUTF8 ( spanEnd, bufEnd );
+
+ if ( uniLen > 0 ) {
+
+ // A valid UTF-8 character, keep it as-is.
+ spanEnd += uniLen - 1; // ! The loop increment will put back the +1.
+
+ } else if ( (uniLen < 0) && (! last) ) {
+
+ // Have a partial UTF-8 character at the end of the buffer and more input coming.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ return (spanEnd - buffer);
+
+ } else {
+
+ // Not a valid UTF-8 sequence. Replace the first byte with the Latin-1 equivalent.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ const char * replacement = kReplaceLatin1 [ *spanEnd - 0x80 ];
+ xmlParser->ParseBuffer ( replacement, strlen ( replacement ), false );
+ spanStart = spanEnd + 1; // ! The loop increment will do "spanEnd = spanStart".
+
+ }
+
+ } else if ( (*spanEnd < 0x20) || (*spanEnd == 0x7F) ) {
+
+ // Replace ASCII controls other than tab, LF, and CR with a space.
+
+ if ( (*spanEnd == kTab) || (*spanEnd == kLF) || (*spanEnd == kCR) ) continue;
+
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ xmlParser->ParseBuffer ( " ", 1, false );
+ spanStart = spanEnd + 1; // ! The loop increment will do "spanEnd = spanStart".
+
+ } else {
+
+ // See if this is a numeric escape sequence for a prohibited ASCII control.
+
+ XMP_Assert ( *spanEnd == '&' );
+ int escLen = CountControlEscape ( spanEnd, bufEnd );
+
+ if ( escLen < 0 ) {
+
+ // Have a partial numeric escape in this buffer, wait for more input.
+ if ( last ) continue; // No more buffers, not an escape, absorb as normal input.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ return (spanEnd - buffer);
+
+ } else if ( escLen > 0 ) {
+
+ // Have a complete numeric escape to replace.
+ xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ xmlParser->ParseBuffer ( " ", 1, false );
+ spanStart = spanEnd + escLen;
+ spanEnd = spanStart - 1; // ! The loop continuation will increment spanEnd!
+
+ }
+
+ }
+
+ }
+
+ XMP_Assert ( spanEnd == bufEnd );
+
+ if ( spanStart < bufEnd ) xmlParser->ParseBuffer ( spanStart, (spanEnd - spanStart), false );
+ if ( last ) xmlParser->ParseBuffer ( " ", 1, true );
+
+ return length;
+
+} // ProcessUTF8Portion
+
+
+// -------------------------------------------------------------------------------------------------
+// ProcessXMLBuffer
+// ----------------
+//
+// Process one buffer of XML. Returns false if this input is put into the pending input buffer.
+
+bool XMPMeta::ProcessXMLBuffer ( XMP_StringPtr buffer, XMP_StringLen xmpSize, bool lastClientCall )
+{
+
+ // Determine the character encoding before doing any real parsing. This is needed to do the
+ // 8-bit special processing. This has to be checked on every call, not just the first, in
+ // order to handle the edge case of single byte buffers.
+
+ XMLParserAdapter & parser = *this->xmlParser;
+
+ if ( parser.charEncoding == XMP_OptionBits(-1) ) {
+
+ if ( (parser.pendingCount == 0) && (xmpSize >= kXMLPendingInputMax) ) {
+
+ // This ought to be the common case, the first buffer is big enough.
+ parser.charEncoding = DetermineInputEncoding ( (XMP_Uns8*)buffer, xmpSize );
+
+ } else {
+
+ // Try to fill the pendingInput buffer before calling DetermineInputEncoding.
+
+ size_t pendingOverlap = kXMLPendingInputMax - parser.pendingCount;
+ if ( pendingOverlap > xmpSize ) pendingOverlap = xmpSize;
+
+ memcpy ( &parser.pendingInput[parser.pendingCount], buffer, pendingOverlap ); // AUDIT: Count is safe.
+ buffer += pendingOverlap;
+ xmpSize -= pendingOverlap;
+ parser.pendingCount += pendingOverlap;
+
+ if ( (! lastClientCall) && (parser.pendingCount < kXMLPendingInputMax) ) return false; // Wait for the next buffer.
+ parser.charEncoding = DetermineInputEncoding ( parser.pendingInput, parser.pendingCount );
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, "XMP Character encoding is %d\n", parser.charEncoding );
+ #endif
+
+ }
+
+ }
+
+ // We have the character encoding. Process UTF-16 and UTF-32 as is. UTF-8 needs special
+ // handling to take care of things like ISO Latin-1 or unescaped ASCII controls.
+
+ XMP_Assert ( parser.charEncoding != XMP_OptionBits(-1) );
+
+ if ( parser.charEncoding != kXMP_EncodeUTF8 ) {
+
+ if ( parser.pendingCount > 0 ) {
+ // Might have pendingInput from the above portion to determine the character encoding.
+ parser.ParseBuffer ( parser.pendingInput, parser.pendingCount, false );
+ }
+ parser.ParseBuffer ( buffer, xmpSize, lastClientCall );
+
+ } else {
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, "Parsing %d bytes @ %.8X, %s, %d pending, context: %.8s\n",
+ xmpSize, buffer, (lastClientCall ? "last" : "not last"), parser.pendingCount, buffer );
+ #endif
+
+ // The UTF-8 processing is a bit complex due to the need to tolerate ISO Latin-1 input.
+ // This is done by scanning the input for byte sequences that are not valid UTF-8,
+ // assuming they are Latin-1 characters in the range 0x80..0xFF. This requires saving a
+ // pending input buffer to handle partial UTF-8 sequences at the end of a buffer.
+
+ while ( parser.pendingCount > 0 ) {
+
+ // We've got some leftover input, process it first then continue with the current
+ // buffer. Try to fill the pendingInput buffer before parsing further. We use a loop
+ // for wierd edge cases like a 2 byte input buffer, using 1 byte for pendingInput,
+ // then having a partial UTF-8 end and need to absorb more.
+
+ size_t pendingOverlap = kXMLPendingInputMax - parser.pendingCount;
+ if ( pendingOverlap > xmpSize ) pendingOverlap = xmpSize;
+
+ memcpy ( &parser.pendingInput[parser.pendingCount], buffer, pendingOverlap ); // AUDIT: Count is safe.
+ parser.pendingCount += pendingOverlap;
+ buffer += pendingOverlap;
+ xmpSize -= pendingOverlap;
+
+ if ( (! lastClientCall) && (parser.pendingCount < kXMLPendingInputMax) ) return false; // Wait for the next buffer.
+ size_t bytesDone = ProcessUTF8Portion ( xmlParser, parser.pendingInput, parser.pendingCount, lastClientCall );
+ size_t bytesLeft = parser.pendingCount - bytesDone;
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, " ProcessUTF8Portion handled %d pending bytes\n", bytesDone );
+ #endif
+
+ if ( bytesDone == parser.pendingCount ) {
+
+ // Done with all of the pending input, move on to the current buffer.
+ parser.pendingCount = 0;
+
+ } else if ( bytesLeft <= pendingOverlap ) {
+
+ // The leftover pending input all came from the current buffer. Exit this loop.
+ buffer -= bytesLeft;
+ xmpSize += bytesLeft;
+ parser.pendingCount = 0;
+
+ } else if ( xmpSize > 0 ) {
+
+ // Pull more of the current buffer into the pending input and try again.
+ // Backup by this pass's overlap so the loop entry code runs OK.
+ parser.pendingCount -= pendingOverlap;
+ buffer -= pendingOverlap;
+ xmpSize += pendingOverlap;
+
+ } else {
+
+ // There is no more of the current buffer. Wait for more. Partial sequences at
+ // the end of the last buffer should be treated as Latin-1 by ProcessUTF8Portion.
+ XMP_Assert ( ! lastClientCall );
+ parser.pendingCount = bytesLeft;
+ memcpy ( &parser.pendingInput[0], &parser.pendingInput[bytesDone], bytesLeft ); // AUDIT: Count is safe.
+ return false; // Wait for the next buffer.
+
+ }
+
+ }
+
+ // Done with the pending input, process the current buffer.
+
+ size_t bytesDone = ProcessUTF8Portion ( xmlParser, (XMP_Uns8*)buffer, xmpSize, lastClientCall );
+
+ #if Trace_ParsingHackery
+ fprintf ( stderr, " ProcessUTF8Portion handled %d additional bytes\n", bytesDone );
+ #endif
+
+ if ( bytesDone < xmpSize ) {
+
+ XMP_Assert ( ! lastClientCall );
+ size_t bytesLeft = xmpSize - bytesDone;
+ if ( bytesLeft > kXMLPendingInputMax ) XMP_Throw ( "Parser bytesLeft too large", kXMPErr_InternalFailure );
+
+ memcpy ( parser.pendingInput, &buffer[bytesDone], bytesLeft ); // AUDIT: Count is safe.
+ parser.pendingCount = bytesLeft;
+ return false; // Wait for the next buffer.
+
+ }
+
+ }
+
+ return true; // This buffer has been processed.
+
+} // ProcessXMLBuffer
+
+
+// -------------------------------------------------------------------------------------------------
+// ProcessXMLTree
+// --------------
+
+void XMPMeta::ProcessXMLTree ( XMP_OptionBits options )
+{
+
+ #if XMP_DebugBuild && DumpXMLParseTree
+ if ( this->xmlParser->parseLog == 0 ) this->xmlParser->parseLog = stdout;
+ DumpXMLTree ( this->xmlParser->parseLog, this->xmlParser->tree, 0 );
+ #endif
+
+ const XML_Node * xmlRoot = FindRootNode ( *this->xmlParser, options );
+
+ if ( xmlRoot != 0 ) {
+
+ this->ProcessRDF ( *xmlRoot, options );
+
+ NormalizeDCArrays ( &this->tree );
+ if ( this->tree.options & kXMP_PropHasAliases ) MoveExplicitAliases ( &this->tree, options, this->errorCallback );
+ TouchUpDataModel ( this, this->errorCallback );
+
+ // Delete empty schema nodes. Do this last, other cleanup can make empty schema.
+ size_t schemaNum = 0;
+ while ( schemaNum < this->tree.children.size() ) {
+ XMP_Node * currSchema = this->tree.children[schemaNum];
+ if ( currSchema->children.size() > 0 ) {
+ ++schemaNum;
+ } else {
+ delete this->tree.children[schemaNum]; // ! Delete the schema node itself.
+ this->tree.children.erase ( this->tree.children.begin() + schemaNum );
+ }
+ }
+
+ }
+
+} // ProcessXMLTree
+
+
+// -------------------------------------------------------------------------------------------------
+// ParseFromBuffer
+// ---------------
+//
+// Although most clients will probably parse everything in one call, we have a buffered API model
+// and need to support even the extreme case of 1 byte at a time parsing. This is considerably
+// complicated by some special cases for 8-bit input. Because of this, the first thing we do is
+// determine whether the input is 8-bit, UTF-16, or UTF-32.
+//
+// Both the 8-bit special cases and the encoding determination are easier to do with 8 bytes or more
+// of input. The XMLParserAdapter class has a pending-input buffer for this. At the start of parsing
+// we (might) try to fill this buffer before determining the input character encoding. After that,
+// we (might) use this buffer with the current input to simplify the logic in Process8BitInput. The
+// "(might)" part means that we don't actually use the pending-input buffer unless we have to. In
+// particular, the common case of single-buffer parsing won't use it.
+
+void
+XMPMeta::ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen xmpSize,
+ XMP_OptionBits options )
+{
+ if ( (buffer == 0) && (xmpSize != 0) ) XMP_Throw ( "Null parse buffer", kXMPErr_BadParam );
+ if ( xmpSize == kXMP_UseNullTermination ) xmpSize = strlen ( buffer );
+
+ const bool lastClientCall = ((options & kXMP_ParseMoreBuffers) == 0); // *** Could use FlagIsSet & FlagIsClear macros.
+
+ if ( this->xmlParser == 0 ) {
+ this->tree.ClearNode(); // Make sure the target XMP object is totally empty.
+ if ( (xmpSize == 0) && lastClientCall ) return; // Tolerate empty parse. Expat complains if there are no XML elements.
+ this->xmlParser = XMP_NewExpatAdapter ( ExpatAdapter::kUseGlobalNamespaces );
+ this->xmlParser->SetErrorCallback ( &this->errorCallback );
+ }
+
+ try { // Cleanup the tree and xmlParser if anything fails.
+
+ bool done = this->ProcessXMLBuffer ( buffer, xmpSize, lastClientCall );
+ if ( ! done ) return; // Wait for the next buffer.
+
+ if ( lastClientCall ) {
+ this->ProcessXMLTree ( options );
+ delete this->xmlParser;
+ this->xmlParser = 0;
+ }
+
+ } catch ( ... ) {
+
+ delete this->xmlParser;
+ this->xmlParser = 0;
+ throw;
+
+ }
+
+} // ParseFromBuffer
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPMeta-Serialize.cpp b/gpr/source/lib/xmp_core/XMPMeta-Serialize.cpp
new file mode 100644
index 0000000..3c46269
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPMeta-Serialize.cpp
@@ -0,0 +1,1396 @@
+// =================================================================================================
+// Copyright 2003-2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+
+#include "public/include/XMP_Version.h"
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+
+#include "md5.h"
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+static const char * kPacketHeader = "<?xpacket begin=\"\xEF\xBB\xBF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
+static const char * kPacketTrailer = "<?xpacket end=\"w\"?>"; // ! The w/r is at [size-4].
+
+static const char * kTXMP_SchemaGroup = "XMP_SchemaGroup";
+
+static const char * kRDF_XMPMetaStart = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"";
+static const char * kRDF_XMPMetaEnd = "</x:xmpmeta>";
+
+static const char * kRDF_RDFStart = "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">";
+static const char * kRDF_RDFEnd = "</rdf:RDF>";
+
+static const char * kRDF_SchemaStart = "<rdf:Description rdf:about=";
+static const char * kRDF_SchemaEnd = "</rdf:Description>";
+
+static const char * kRDF_StructStart = "<rdf:Description>";
+static const char * kRDF_StructEnd = "</rdf:Description>";
+
+static const char * kRDF_BagStart = "<rdf:Bag>";
+static const char * kRDF_BagEnd = "</rdf:Bag>";
+
+static const char * kRDF_SeqStart = "<rdf:Seq>";
+static const char * kRDF_SeqEnd = "</rdf:Seq>";
+
+static const char * kRDF_AltStart = "<rdf:Alt>";
+static const char * kRDF_AltEnd = "</rdf:Alt>";
+
+static const char * kRDF_ItemStart = "<rdf:li>";
+static const char * kRDF_ItemEnd = "</rdf:li>";
+
+static const char * kRDF_ValueStart = "<rdf:value>";
+static const char * kRDF_ValueEnd = "</rdf:value>";
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+// -------------------------------------------------------------------------------------------------
+// EstimateRDFSize
+// ---------------
+
+// *** Pull the strlen(kXyz) calls into constants.
+
+static size_t
+EstimateRDFSize ( const XMP_Node * currNode, XMP_Index indent, size_t indentLen )
+{
+ size_t outputLen = 2 * (indent*indentLen + currNode->name.size() + 4); // The property element tags.
+
+ if ( ! currNode->qualifiers.empty() ) {
+ // This node has qualifiers, assume it is written using rdf:value and estimate the qualifiers.
+
+ indent += 2; // Everything else is indented inside the rdf:Description element.
+ outputLen += 2 * ((indent-1)*indentLen + strlen(kRDF_StructStart) + 2); // The rdf:Description tags.
+ outputLen += 2 * (indent*indentLen + strlen(kRDF_ValueStart) + 2); // The rdf:value tags.
+
+ for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = currNode->qualifiers[qualNum];
+ outputLen += EstimateRDFSize ( currQual, indent, indentLen );
+ }
+
+ }
+
+ if ( currNode->options & kXMP_PropValueIsStruct ) {
+ indent += 1;
+ outputLen += 2 * (indent*indentLen + strlen(kRDF_StructStart) + 2); // The rdf:Description tags.
+ } else if ( currNode->options & kXMP_PropValueIsArray ) {
+ indent += 2;
+ outputLen += 2 * ((indent-1)*indentLen + strlen(kRDF_BagStart) + 2); // The rdf:Bag/Seq/Alt tags.
+ outputLen += 2 * currNode->children.size() * (strlen(kRDF_ItemStart) + 2); // The rdf:li tags, indent counted in children.
+ } else if ( ! (currNode->options & kXMP_SchemaNode) ) {
+ outputLen += currNode->value.size(); // This is a leaf value node.
+ }
+
+ for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = currNode->children[childNum];
+ outputLen += EstimateRDFSize ( currChild, indent+1, indentLen );
+ }
+
+ return outputLen;
+
+} // EstimateRDFSize
+
+
+// -------------------------------------------------------------------------------------------------
+// DeclareOneNamespace
+// -------------------
+
+static void
+DeclareOneNamespace ( XMP_StringPtr nsPrefix,
+ XMP_StringPtr nsURI,
+ XMP_VarString & usedNS, // ! A catenation of the prefixes with colons.
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ XMP_VarString boundedPrefix = ":";
+ boundedPrefix += nsPrefix;
+ size_t nsPos = usedNS.find ( boundedPrefix );
+
+ if ( nsPos == XMP_VarString::npos ) {
+
+ outputStr += newline;
+ for ( ; indent > 0; --indent ) outputStr += indentStr;
+ outputStr += "xmlns:";
+ outputStr += nsPrefix;
+ outputStr[outputStr.size()-1] = '='; // Change the colon to =.
+ outputStr += '"';
+ outputStr += nsURI;
+ outputStr += '"';
+
+ usedNS += nsPrefix;
+
+ }
+
+} // DeclareOneNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// DeclareElemNamespace
+// --------------------
+
+static void
+DeclareElemNamespace ( const XMP_VarString & elemName,
+ XMP_VarString & usedNS,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ size_t colonPos = elemName.find ( ':' );
+
+ if ( colonPos != XMP_VarString::npos ) {
+ XMP_VarString nsPrefix ( elemName.substr ( 0, colonPos+1 ) );
+ XMP_StringPtr nsURI;
+ bool nsFound = sRegisteredNamespaces->GetURI ( nsPrefix.c_str(), &nsURI, 0 );
+ XMP_Enforce ( nsFound );
+ DeclareOneNamespace ( nsPrefix.c_str(), nsURI, usedNS, outputStr, newline, indentStr, indent );
+ }
+
+} // DeclareElemNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// DeclareUsedNamespaces
+// ---------------------
+
+static void
+DeclareUsedNamespaces ( const XMP_Node * currNode,
+ XMP_VarString & usedNS,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+
+ if ( currNode->options & kXMP_SchemaNode ) {
+ // The schema node name is the URI, the value is the prefix.
+ DeclareOneNamespace ( currNode->value.c_str(), currNode->name.c_str(), usedNS, outputStr, newline, indentStr, indent );
+ } else if ( currNode->options & kXMP_PropValueIsStruct ) {
+ for ( size_t fieldNum = 0, fieldLim = currNode->children.size(); fieldNum < fieldLim; ++fieldNum ) {
+ const XMP_Node * currField = currNode->children[fieldNum];
+ DeclareElemNamespace ( currField->name, usedNS, outputStr, newline, indentStr, indent );
+ }
+ }
+
+ for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = currNode->children[childNum];
+ DeclareUsedNamespaces ( currChild, usedNS, outputStr, newline, indentStr, indent );
+ }
+
+ for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = currNode->qualifiers[qualNum];
+ DeclareElemNamespace ( currQual->name, usedNS, outputStr, newline, indentStr, indent );
+ DeclareUsedNamespaces ( currQual, usedNS, outputStr, newline, indentStr, indent );
+ }
+
+} // DeclareUsedNamespaces
+
+// -------------------------------------------------------------------------------------------------
+// EmitRDFArrayTag
+// ---------------
+
+enum {
+ kIsStartTag = true,
+ kIsEndTag = false
+};
+
+static void
+EmitRDFArrayTag ( XMP_OptionBits arrayForm,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent,
+ XMP_Index arraySize,
+ bool isStartTag )
+{
+ if ( (! isStartTag) && (arraySize == 0) ) return;
+
+ for ( XMP_Index level = indent; level > 0; --level ) outputStr += indentStr;
+ if ( isStartTag ) {
+ outputStr += "<rdf:";
+ } else {
+ outputStr += "</rdf:";
+ }
+
+ if ( arrayForm & kXMP_PropArrayIsAlternate ) {
+ outputStr += "Alt";
+ } else if ( arrayForm & kXMP_PropArrayIsOrdered ) {
+ outputStr += "Seq";
+ } else {
+ outputStr += "Bag";
+ }
+
+ if ( isStartTag && (arraySize == 0) ) outputStr += '/';
+ outputStr += '>';
+ outputStr += newline;
+
+} // EmitRDFArrayTag
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendNodeValue
+// ---------------
+//
+// Append a property or qualifier value to the output with appropriate XML escaping. The escaped
+// characters for elements and attributes are '&', '<', '>', and ASCII controls (tab, LF, CR). In
+// addition, '"' is escaped for attributes. For efficiency, this is done in a double loop. The outer
+// loop makes sure the whole value is processed. The inner loop does a contiguous unescaped run
+// followed by one escaped character (if we're not at the end).
+//
+// We depend on parsing and SetProperty logic to make sure there are no invalid ASCII controls in
+// the XMP values. The XML spec only allows tab, LF, and CR. Others are not even allowed as
+// numeric escape sequences.
+
+enum {
+ kForAttribute = true,
+ kForElement = false
+};
+
+static void
+AppendNodeValue ( XMP_VarString & outputStr, const XMP_VarString & value, bool forAttribute )
+{
+
+ unsigned char * runStart = (unsigned char *) value.c_str();
+ unsigned char * runLimit = runStart + value.size();
+ unsigned char * runEnd;
+ unsigned char ch;
+
+ while ( runStart < runLimit ) {
+
+ for ( runEnd = runStart; runEnd < runLimit; ++runEnd ) {
+ ch = *runEnd;
+ if ( forAttribute && (ch == '"') ) break;
+ if ( (ch < 0x20) || (ch == '&') || (ch == '<') || (ch == '>') ) break;
+ }
+
+ outputStr.append ( (char *) runStart, (runEnd - runStart) );
+
+ if ( runEnd < runLimit ) {
+
+ if ( ch < 0x20 ) {
+
+ XMP_Assert ( (ch == kTab) || (ch == kLF) || (ch == kCR) );
+
+ char hexBuf[16];
+ memcpy ( hexBuf, "&#xn;", 6 ); // AUDIT: Length of "&#xn;" is 5, hexBuf size is 16.
+ hexBuf[3] = kHexDigits[ch&0xF];
+ outputStr.append ( hexBuf, 5 );
+
+ } else {
+
+ if ( ch == '"' ) {
+ outputStr += "&quot;";
+ } else if ( ch == '<' ) {
+ outputStr += "&lt;";
+ } else if ( ch == '>' ) {
+ outputStr += "&gt;";
+ } else {
+ XMP_Assert ( ch == '&' );
+ outputStr += "&amp;";
+ }
+
+ }
+
+ ++runEnd;
+
+ }
+
+ runStart = runEnd;
+
+ }
+
+} // AppendNodeValue
+
+
+// -------------------------------------------------------------------------------------------------
+// CanBeRDFAttrProp
+// ----------------
+
+static bool
+CanBeRDFAttrProp ( const XMP_Node * propNode )
+{
+
+ if ( propNode->name[0] == '[' ) return false;
+ if ( ! propNode->qualifiers.empty() ) return false;
+ if ( propNode->options & kXMP_PropValueIsURI ) return false;
+ if ( propNode->options & kXMP_PropCompositeMask ) return false;
+
+ return true;
+
+} // CanBeRDFAttrProp
+
+
+// -------------------------------------------------------------------------------------------------
+// IsRDFAttrQualifier
+// ------------------
+
+static XMP_StringPtr sAttrQualifiers[] = { "xml:lang", "rdf:resource", "rdf:ID", "rdf:bagID", "rdf:nodeID", "" };
+
+static bool
+IsRDFAttrQualifier ( XMP_VarString qualName )
+{
+
+ for ( size_t i = 0; *sAttrQualifiers[i] != 0; ++i ) {
+ if ( qualName == sAttrQualifiers[i] ) return true;
+ }
+
+ return false;
+
+} // IsRDFAttrQualifier
+
+
+// -------------------------------------------------------------------------------------------------
+// StartOuterRDFDescription
+// ------------------------
+//
+// Start the outer rdf:Description element, including all needed xmlns attributes. Leave the element
+// open so that the compact form can add proprtty attributes.
+
+static void
+StartOuterRDFDescription ( const XMP_Node & xmpTree,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent )
+{
+
+ // Begin the outer rdf:Description start tag.
+
+ for ( XMP_Index level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaStart;
+ outputStr += '"';
+ outputStr += xmpTree.name;
+ outputStr += '"';
+
+ // Write all necessary xmlns attributes.
+
+ XMP_VarString usedNS;
+ usedNS.reserve ( 400 ); // The predefined prefixes add up to about 320 bytes.
+ usedNS = ":xml:rdf:";
+
+ for ( size_t schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
+ const XMP_Node * currSchema = xmpTree.children[schema];
+ DeclareUsedNamespaces ( currSchema, usedNS, outputStr, newline, indentStr, baseIndent+4 );
+ }
+
+} // StartOuterRDFDescription
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCanonicalRDFProperty
+// -----------------------------
+//
+// Recursively handles the "value" for a node. It does not matter if it is a top level property, a
+// field of a struct, or an item of an array. The indent is that for the property element. An
+// xml:lang qualifier is written as an attribute of the property start tag, not by itself forcing
+// the qualified property form. The patterns below mostly ignore attribute qualifiers like xml:lang.
+// Except for the one struct case, attribute qualifiers don't affect the output form.
+//
+// <ns:UnqualifiedSimpleProperty>value</ns:UnqualifiedSimpleProperty>
+//
+// <ns:UnqualifiedStructProperty> (If no rdf:resource qualifier)
+// <rdf:Description>
+// ... Fields, same forms as top level properties
+// </rdf:Description>
+// </ns:UnqualifiedStructProperty>
+//
+// <ns:ResourceStructProperty rdf:resource="URI"
+// ... Fields as attributes
+// >
+//
+// <ns:UnqualifiedArrayProperty>
+// <rdf:Bag> or Seq or Alt
+// ... Array items as rdf:li elements, same forms as top level properties
+// </rdf:Bag>
+// </ns:UnqualifiedArrayProperty>
+//
+// <ns:QualifiedProperty>
+// <rdf:Description>
+// <rdf:value> ... Property "value" following the unqualified forms ... </rdf:value>
+// ... Qualifiers looking like named struct fields
+// </rdf:Description>
+// </ns:QualifiedProperty>
+
+enum { kUseCanonicalRDF = true, kUseAdobeVerboseRDF = false };
+enum { kEmitAsRDFValue = true, kEmitAsNormalValue = false };
+
+static void
+SerializeCanonicalRDFProperty ( const XMP_Node * propNode,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent,
+ bool useCanonicalRDF,
+ bool emitAsRDFValue )
+{
+ XMP_Index level;
+ bool emitEndTag = true;
+ bool indentEndTag = true;
+
+ XMP_OptionBits propForm = propNode->options & kXMP_PropCompositeMask;
+
+ // ------------------------------------------------------------------------------------------
+ // Determine the XML element name. Open the start tag with the name and attribute qualifiers.
+
+ XMP_StringPtr elemName = propNode->name.c_str();
+ if ( emitAsRDFValue ) {
+ elemName= "rdf:value";
+ } else if ( *elemName == '[' ) {
+ elemName = "rdf:li";
+ }
+
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += '<';
+ outputStr += elemName;
+
+ bool hasGeneralQualifiers = false;
+ bool hasRDFResourceQual = false;
+
+ for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ if ( ! IsRDFAttrQualifier ( currQual->name ) ) {
+ hasGeneralQualifiers = true;
+ } else {
+ if ( currQual->name == "rdf:resource" ) hasRDFResourceQual = true;
+ if ( ! emitAsRDFValue ) {
+ outputStr += ' ';
+ outputStr += currQual->name;
+ outputStr += "=\"";
+ AppendNodeValue ( outputStr, currQual->value, kForAttribute );
+ outputStr += '"';
+ }
+ }
+ }
+
+ // --------------------------------------------------------
+ // Process the property according to the standard patterns.
+
+ if ( hasGeneralQualifiers && (! emitAsRDFValue) ) {
+
+ // -----------------------------------------------------------------------------------------
+ // This node has general, non-attribute, qualifiers. Emit using the qualified property form.
+ // ! The value is output by a recursive call ON THE SAME NODE with emitAsRDFValue set.
+
+ if ( hasRDFResourceQual ) {
+ XMP_Throw ( "Can't mix rdf:resource and general qualifiers", kXMPErr_BadRDF );
+ }
+
+ if ( ! useCanonicalRDF ) {
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+ } else {
+ outputStr += '>';
+ outputStr += newline;
+ indent += 1;
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "<rdf:Description>";
+ outputStr += newline;
+ }
+
+ SerializeCanonicalRDFProperty ( propNode, outputStr, newline, indentStr, indent+1,
+ useCanonicalRDF, kEmitAsRDFValue );
+
+ for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ if ( IsRDFAttrQualifier ( currQual->name ) ) continue;
+ SerializeCanonicalRDFProperty ( currQual, outputStr, newline, indentStr, indent+1,
+ useCanonicalRDF, kEmitAsNormalValue );
+ }
+
+ if ( useCanonicalRDF ) {
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "</rdf:Description>";
+ outputStr += newline;
+ indent -= 1;
+ }
+
+ } else {
+
+ // --------------------------------------------------------------------
+ // This node has no general qualifiers. Emit using an unqualified form.
+
+ if ( propForm == 0 ) {
+
+ // --------------------------
+ // This is a simple property.
+
+ if ( propNode->options & kXMP_PropValueIsURI ) {
+ outputStr += " rdf:resource=\"";
+ AppendNodeValue ( outputStr, propNode->value, kForAttribute );
+ outputStr += "\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else if ( propNode->value.empty() ) {
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else {
+ outputStr += '>';
+ AppendNodeValue ( outputStr, propNode->value, kForElement );
+ indentEndTag = false;
+ }
+
+ } else if ( propForm & kXMP_PropValueIsArray ) {
+
+ // This is an array.
+ outputStr += '>';
+ outputStr += newline;
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsStartTag );
+ if ( XMP_ArrayIsAltText(propNode->options) ) NormalizeLangArray ( (XMP_Node*)propNode );
+ for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = propNode->children[childNum];
+ SerializeCanonicalRDFProperty ( currChild, outputStr, newline, indentStr, indent+2,
+ useCanonicalRDF, kEmitAsNormalValue );
+ }
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag );
+
+
+ } else if ( ! hasRDFResourceQual ) {
+
+ // This is a "normal" struct, use the nested field element form form.
+ XMP_Assert ( propForm & kXMP_PropValueIsStruct );
+ if ( propNode->children.size() == 0 ) {
+ if ( ! useCanonicalRDF ) {
+ outputStr += " rdf:parseType=\"Resource\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else {
+ outputStr += '>';
+ outputStr += newline;
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += "<rdf:Description/>";
+ outputStr += newline;
+ }
+ } else {
+ if ( ! useCanonicalRDF ) {
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+ } else {
+ outputStr += '>';
+ outputStr += newline;
+ indent += 1;
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "<rdf:Description>";
+ outputStr += newline;
+ }
+ for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = propNode->children[childNum];
+ SerializeCanonicalRDFProperty ( currChild, outputStr, newline, indentStr, indent+1,
+ useCanonicalRDF, kEmitAsNormalValue );
+ }
+ if ( useCanonicalRDF ) {
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "</rdf:Description>";
+ outputStr += newline;
+ indent -= 1;
+ }
+ }
+
+ } else {
+
+ // This is a struct with an rdf:resource attribute, use the "empty property element" form.
+ XMP_Assert ( propForm & kXMP_PropValueIsStruct );
+ for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
+ const XMP_Node * currChild = propNode->children[childNum];
+ if ( ! CanBeRDFAttrProp ( currChild ) ) {
+ XMP_Throw ( "Can't mix rdf:resource and complex fields", kXMPErr_BadRDF );
+ }
+ outputStr += newline;
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += ' ';
+ outputStr += currChild->name;
+ outputStr += "=\"";
+ outputStr += currChild->value;
+ outputStr += '"';
+ }
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+
+ }
+
+ }
+
+ // ----------------------------------
+ // Emit the property element end tag.
+
+ if ( emitEndTag ) {
+ if ( indentEndTag ) for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "</";
+ outputStr += elemName;
+ outputStr += '>';
+ outputStr += newline;
+ }
+
+} // SerializeCanonicalRDFProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCanonicalRDFSchemas
+// ----------------------------
+//
+// Each schema's properties are written to the single rdf:Description element. All of the necessary
+// namespaces are declared in the rdf:Description element. The baseIndent is the base level for the
+// entire serialization, that of the x:xmpmeta element. An xml:lang qualifier is written as an
+// attribute of the property start tag, not by itself forcing the qualified property form.
+//
+// <rdf:Description rdf:about="TreeName"
+// xmlns:ns="URI" ... >
+//
+// ... The actual properties of the schema, see SerializeCanonicalRDFProperty
+//
+// <!-- ns1:Alias is aliased to ns2:Actual --> ... If alias comments are wanted
+//
+// </rdf:Description>
+
+static void
+SerializeCanonicalRDFSchemas ( const XMP_Node & xmpTree,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent,
+ bool useCanonicalRDF )
+{
+
+ StartOuterRDFDescription ( xmpTree, outputStr, newline, indentStr, baseIndent );
+
+ if ( xmpTree.children.size() > 0 ) {
+ outputStr += ">";
+ outputStr += newline;
+ } else {
+ outputStr += "/>";
+ outputStr += newline;
+ return; // ! Done if there are no XMP properties.
+ }
+
+ for ( size_t schemaNum = 0, schemaLim = xmpTree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
+ const XMP_Node * currSchema = xmpTree.children[schemaNum];
+ for ( size_t propNum = 0, propLim = currSchema->children.size(); propNum < propLim; ++propNum ) {
+ const XMP_Node * currProp = currSchema->children[propNum];
+ SerializeCanonicalRDFProperty ( currProp, outputStr, newline, indentStr, baseIndent+3,
+ useCanonicalRDF, kEmitAsNormalValue );
+ }
+ }
+
+ // Write the rdf:Description end tag.
+ for ( XMP_Index level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaEnd;
+ outputStr += newline;
+
+} // SerializeCanonicalRDFSchemas
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCompactRDFAttrProps
+// ----------------------------
+//
+// Write each of the parent's simple unqualified properties as an attribute. Returns true if all
+// of the properties are written as attributes.
+
+static bool
+SerializeCompactRDFAttrProps ( const XMP_Node * parentNode,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ size_t prop, propLim;
+ bool allAreAttrs = true;
+
+ for ( prop = 0, propLim = parentNode->children.size(); prop != propLim; ++prop ) {
+
+ const XMP_Node * currProp = parentNode->children[prop];
+ if ( ! CanBeRDFAttrProp ( currProp ) ) {
+ allAreAttrs = false;
+ continue;
+ }
+
+ outputStr += newline;
+ for ( XMP_Index level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += currProp->name;
+ outputStr += "=\"";
+ AppendNodeValue ( outputStr, currProp->value, kForAttribute );
+ outputStr += '"';
+
+ }
+
+ return allAreAttrs;
+
+} // SerializeCompactRDFAttrProps
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCompactRDFElemProps
+// ----------------------------
+//
+// Recursively handles the "value" for a node that must be written as an RDF property element. It
+// does not matter if it is a top level property, a field of a struct, or an item of an array. The
+// indent is that for the property element. The patterns bwlow ignore attribute qualifiers such as
+// xml:lang, they don't affect the output form.
+//
+// <ns:UnqualifiedStructProperty-1
+// ... The fields as attributes, if all are simple and unqualified
+// />
+//
+// <ns:UnqualifiedStructProperty-2 rdf:parseType="Resource">
+// ... The fields as elements, if none are simple and unqualified
+// </ns:UnqualifiedStructProperty-2>
+//
+// <ns:UnqualifiedStructProperty-3>
+// <rdf:Description
+// ... The simple and unqualified fields as attributes
+// >
+// ... The compound or qualified fields as elements
+// </rdf:Description>
+// </ns:UnqualifiedStructProperty-3>
+//
+// <ns:UnqualifiedArrayProperty>
+// <rdf:Bag> or Seq or Alt
+// ... Array items as rdf:li elements, same forms as top level properties
+// </rdf:Bag>
+// </ns:UnqualifiedArrayProperty>
+//
+// <ns:QualifiedProperty rdf:parseType="Resource">
+// <rdf:value> ... Property "value" following the unqualified forms ... </rdf:value>
+// ... Qualifiers looking like named struct fields
+// </ns:QualifiedProperty>
+
+// *** Consider numbered array items, but has compatibility problems.
+// *** Consider qualified form with rdf:Description and attributes.
+
+static void
+SerializeCompactRDFElemProps ( const XMP_Node * parentNode,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index indent )
+{
+ XMP_Index level;
+
+ for ( size_t prop = 0, propLim = parentNode->children.size(); prop != propLim; ++prop ) {
+
+ const XMP_Node * propNode = parentNode->children[prop];
+ if ( CanBeRDFAttrProp ( propNode ) ) continue;
+
+ bool emitEndTag = true;
+ bool indentEndTag = true;
+
+ XMP_OptionBits propForm = propNode->options & kXMP_PropCompositeMask;
+
+ // -----------------------------------------------------------------------------------
+ // Determine the XML element name, write the name part of the start tag. Look over the
+ // qualifiers to decide on "normal" versus "rdf:value" form. Emit the attribute
+ // qualifiers at the same time.
+
+ XMP_StringPtr elemName = propNode->name.c_str();
+ if ( *elemName == '[' ) elemName = "rdf:li";
+
+ for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += '<';
+ outputStr += elemName;
+
+ bool hasGeneralQualifiers = false;
+ bool hasRDFResourceQual = false;
+
+ for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ if ( ! IsRDFAttrQualifier ( currQual->name ) ) {
+ hasGeneralQualifiers = true;
+ } else {
+ if ( currQual->name == "rdf:resource" ) hasRDFResourceQual = true;
+ outputStr += ' ';
+ outputStr += currQual->name;
+ outputStr += "=\"";
+ AppendNodeValue ( outputStr, currQual->value, kForAttribute );
+ outputStr += '"';
+ }
+ }
+
+ // --------------------------------------------------------
+ // Process the property according to the standard patterns.
+
+ if ( hasGeneralQualifiers ) {
+
+ // -------------------------------------------------------------------------------------
+ // The node has general qualifiers, ones that can't be attributes on a property element.
+ // Emit using the qualified property pseudo-struct form. The value is output by a call
+ // to SerializeCanonicalRDFProperty with emitAsRDFValue set.
+
+ // *** We're losing compactness in the calls to SerializeCanonicalRDFProperty.
+ // *** Should refactor to have SerializeCompactRDFProperty that does one node.
+
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+
+ SerializeCanonicalRDFProperty ( propNode, outputStr, newline, indentStr, indent+1,
+ kUseAdobeVerboseRDF, kEmitAsRDFValue );
+
+ size_t qualNum = 0;
+ size_t qualLim = propNode->qualifiers.size();
+ if ( propNode->options & kXMP_PropHasLang ) ++qualNum;
+
+ for ( ; qualNum < qualLim; ++qualNum ) {
+ const XMP_Node * currQual = propNode->qualifiers[qualNum];
+ SerializeCanonicalRDFProperty ( currQual, outputStr, newline, indentStr, indent+1,
+ kUseAdobeVerboseRDF, kEmitAsNormalValue );
+ }
+
+ } else {
+
+ // --------------------------------------------------------------------
+ // This node has only attribute qualifiers. Emit as a property element.
+
+ if ( propForm == 0 ) {
+
+ // --------------------------
+ // This is a simple property.
+
+ if ( propNode->options & kXMP_PropValueIsURI ) {
+ outputStr += " rdf:resource=\"";
+ AppendNodeValue ( outputStr, propNode->value, kForAttribute );
+ outputStr += "\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else if ( propNode->value.empty() ) {
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+ } else {
+ outputStr += '>';
+ AppendNodeValue ( outputStr, propNode->value, kForElement );
+ indentEndTag = false;
+ }
+
+ } else if ( propForm & kXMP_PropValueIsArray ) {
+
+ // -----------------
+ // This is an array.
+
+ outputStr += '>';
+ outputStr += newline;
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsStartTag );
+
+ if ( XMP_ArrayIsAltText(propNode->options) ) NormalizeLangArray ( (XMP_Node*)propNode );
+ SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+2 );
+
+ EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag );
+
+ } else {
+
+ // ----------------------
+ // This must be a struct.
+
+ XMP_Assert ( propForm & kXMP_PropValueIsStruct );
+
+ bool hasAttrFields = false;
+ bool hasElemFields = false;
+
+ size_t field, fieldLim;
+ for ( field = 0, fieldLim = propNode->children.size(); field != fieldLim; ++field ) {
+ XMP_Node * currField = propNode->children[field];
+ if ( CanBeRDFAttrProp ( currField ) ) {
+ hasAttrFields = true;
+ if ( hasElemFields ) break; // No sense looking further.
+ } else {
+ hasElemFields = true;
+ if ( hasAttrFields ) break; // No sense looking further.
+ }
+ }
+
+ if ( hasRDFResourceQual && hasElemFields ) {
+ XMP_Throw ( "Can't mix rdf:resource qualifier and element fields", kXMPErr_BadRDF );
+ }
+
+ if ( propNode->children.size() == 0 ) {
+
+ // Catch an empty struct as a special case. The case below would emit an empty
+ // XML element, which gets reparsed as a simple property with an empty value.
+ outputStr += " rdf:parseType=\"Resource\"/>";
+ outputStr += newline;
+ emitEndTag = false;
+
+ } else if ( ! hasElemFields ) {
+
+ // All fields can be attributes, use the emptyPropertyElt form.
+ SerializeCompactRDFAttrProps ( propNode, outputStr, newline, indentStr, indent+1 );
+ outputStr += "/>";
+ outputStr += newline;
+ emitEndTag = false;
+
+ } else if ( ! hasAttrFields ) {
+
+ // All fields must be elements, use the parseTypeResourcePropertyElt form.
+ outputStr += " rdf:parseType=\"Resource\">";
+ outputStr += newline;
+ SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+1 );
+
+ } else {
+
+ // Have a mix of attributes and elements, use an inner rdf:Description.
+ outputStr += '>';
+ outputStr += newline;
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += "<rdf:Description";
+ SerializeCompactRDFAttrProps ( propNode, outputStr, newline, indentStr, indent+2 );
+ outputStr += ">";
+ outputStr += newline;
+ SerializeCompactRDFElemProps ( propNode, outputStr, newline, indentStr, indent+1 );
+ for ( level = indent+1; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_StructEnd;
+ outputStr += newline;
+
+ }
+
+ }
+
+ }
+
+ // ----------------------------------
+ // Emit the property element end tag.
+
+ if ( emitEndTag ) {
+ if ( indentEndTag ) for ( level = indent; level > 0; --level ) outputStr += indentStr;
+ outputStr += "</";
+ outputStr += elemName;
+ outputStr += '>';
+ outputStr += newline;
+ }
+
+ }
+
+} // SerializeCompactRDFElemProps
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeCompactRDFSchemas
+// --------------------------
+//
+// All properties from all schema are written in a single rdf:Description element, as are all of the
+// necessary namespace declarations. The baseIndent is the base level for the entire serialization,
+// that of the x:xmpmeta element. The x:xmpmeta and rdf:RDF elements have already been written.
+//
+// Top level simple unqualified properties are written as attributes of the (only) rdf:Description
+// element. Structs, arrays, and qualified properties are written by SerializeCompactRDFElemProp. An
+// xml:lang qualifier on a simple property prevents the attribute form.
+//
+// <rdf:Description rdf:about="TreeName"
+// xmlns:ns="URI" ...
+// ns:UnqualifiedSimpleProperty="value" ... >
+// ... The remaining properties of the schema, see SerializeCompactRDFElemProps
+// </rdf:Description>
+
+static void
+SerializeCompactRDFSchemas ( const XMP_Node & xmpTree,
+ XMP_VarString & outputStr,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent )
+{
+ XMP_Index level;
+ size_t schema, schemaLim;
+
+ StartOuterRDFDescription ( xmpTree, outputStr, newline, indentStr, baseIndent );
+
+ // Write the top level "attrProps" and close the rdf:Description start tag.
+ bool allAreAttrs = true;
+ for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
+ const XMP_Node * currSchema = xmpTree.children[schema];
+ allAreAttrs &= SerializeCompactRDFAttrProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 );
+ }
+ if ( ! allAreAttrs ) {
+ outputStr += ">";
+ outputStr += newline;
+ } else {
+ outputStr += "/>";
+ outputStr += newline;
+ return; // ! Done if all properties in all schema are written as attributes.
+ }
+
+ // Write the remaining properties for each schema.
+ for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
+ const XMP_Node * currSchema = xmpTree.children[schema];
+ SerializeCompactRDFElemProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 );
+ }
+
+ // Write the rdf:Description end tag.
+ for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
+ outputStr += kRDF_SchemaEnd;
+ outputStr += newline;
+
+} // SerializeCompactRDFSchemas
+
+// -------------------------------------------------------------------------------------------------
+// SerializeAsRDF
+// --------------
+//
+// <?xpacket begin... ?>
+// <x:xmpmeta xmlns:x=... >
+// <rdf:RDF xmlns:rdf=... >
+//
+// ... The properties, see SerializeCanonicalRDFSchema or SerializeCompactRDFSchemas
+//
+// </rdf:RDF>
+// </x:xmpmeta>
+// <?xpacket end... ?>
+
+// *** Need to strip empty arrays?
+// *** Option to strip/keep empty structs?
+// *** Need to verify handling of rdf:type qualifiers in canonical and compact.
+// *** Need to verify round tripping of rdf:ID and similar qualifiers, see RDF 7.2.21.
+// *** Check cases of rdf:resource plus explicit attr qualifiers (like xml:lang).
+
+static void
+SerializeAsRDF ( const XMPMeta & xmpObj,
+ XMP_VarString & headStr, // Everything up to the padding.
+ XMP_VarString & tailStr, // Everything after the padding.
+ XMP_OptionBits options,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent )
+{
+ const size_t treeNameLen = xmpObj.tree.name.size();
+ const size_t indentLen = strlen ( indentStr );
+
+ // First estimate the worst case space and reserve room in the output string. This optimization
+ // avoids reallocating and copying the output as it grows. The initial count does not look at
+ // the values of properties, so it does not account for character entities, e.g. &#xA; for newline.
+ // Since there can be a lot of these in things like the base 64 encoding of a large thumbnail,
+ // inflate the count by 1/4 (easy to do) to accommodate.
+
+ // *** Need to include estimate for alias comments.
+
+ size_t outputLen = 2 * (strlen(kPacketHeader) + strlen(kRDF_XMPMetaStart) + strlen(kRDF_RDFStart) + 3*baseIndent*indentLen);
+
+ for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
+ const XMP_Node * currSchema = xmpObj.tree.children[schemaNum];
+ outputLen += 2*(baseIndent+2)*indentLen + strlen(kRDF_SchemaStart) + treeNameLen + strlen(kRDF_SchemaEnd) + 2;
+ outputLen += EstimateRDFSize ( currSchema, baseIndent+2, indentLen );
+ }
+
+ outputLen += (outputLen >> 2); // Inflate by 1/4, an empirical fudge factor.
+
+ // Now generate the RDF into the head string as UTF-8.
+
+ XMP_Index level;
+
+ std::string rdfstring;
+ headStr.erase();
+ rdfstring.reserve ( outputLen );
+
+ // Write the rdf:RDF start tag.
+ rdfstring += kRDF_RDFStart;
+ rdfstring += newline;
+
+ // Write all of the properties.
+ if ( options & kXMP_UseCompactFormat ) {
+ SerializeCompactRDFSchemas ( xmpObj.tree, rdfstring, newline, indentStr, baseIndent );
+ } else {
+ bool useCanonicalRDF = XMP_OptionIsSet ( options, kXMP_UseCanonicalFormat );
+ SerializeCanonicalRDFSchemas ( xmpObj.tree, rdfstring, newline, indentStr, baseIndent, useCanonicalRDF );
+ }
+
+ // Write the rdf:RDF end tag.
+ for ( level = baseIndent+1; level > 0; --level ) rdfstring += indentStr;
+ rdfstring += kRDF_RDFEnd;
+ // Write the packet header PI.
+ if ( ! (options & kXMP_OmitPacketWrapper) ) {
+ for ( level = baseIndent; level > 0; --level ) headStr += indentStr;
+ headStr += kPacketHeader;
+ headStr += newline;
+ }
+
+ // Write the xmpmeta element's start tag.
+ if ( ! (options & kXMP_OmitXMPMetaElement) ) {
+ for ( level = baseIndent; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_XMPMetaStart;
+ headStr += kXMPCore_VersionMessage "\"";
+ std::string digestStr;
+ unsigned char digestBin [16];
+ if (options & kXMP_IncludeRDFHash)
+ {
+ std::string hashrdf;
+
+ {
+ context_md5_t ctx;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char*)rdfstring.c_str(), (unsigned int)rdfstring.size() );
+ MD5Final(digestBin, &ctx);
+ }
+
+ char buffer [40];
+ for ( int in = 0, out = 0; in < 16; in += 1, out += 2 ) {
+ XMP_Uns8 byte = digestBin[in];
+ buffer[out] = kHexDigits [ byte >> 4 ];
+ buffer[out+1] = kHexDigits [ byte & 0xF ];
+ }
+ buffer[32] = 0;
+ digestStr.append ( buffer );
+ headStr += " rdfhash=\"";
+ headStr += digestStr + "\"";
+ headStr += " merged=\"0\"";
+ }
+ headStr += ">";
+ headStr += newline;
+ }
+
+ for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr;
+ headStr+= rdfstring ;
+ headStr += newline;
+
+ // Write the xmpmeta end tag.
+ if ( ! (options & kXMP_OmitXMPMetaElement) ) {
+ for ( level = baseIndent; level > 0; --level ) headStr += indentStr;
+ headStr += kRDF_XMPMetaEnd;
+ headStr += newline;
+ }
+
+ // Write the packet trailer PI into the tail string as UTF-8.
+ tailStr.erase();
+ if ( ! (options & kXMP_OmitPacketWrapper) ) {
+ tailStr.reserve ( strlen(kPacketTrailer) + (strlen(indentStr) * baseIndent) );
+ for ( level = baseIndent; level > 0; --level ) tailStr += indentStr;
+ tailStr += kPacketTrailer;
+ if ( options & kXMP_ReadOnlyPacket ) tailStr[tailStr.size()-4] = 'r';
+ }
+
+} // SerializeAsRDF
+
+
+// -------------------------------------------------------------------------------------------------
+// SerializeToBuffer
+// -----------------
+
+void
+XMPMeta::SerializeToBuffer ( XMP_VarString * rdfString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indentStr,
+ XMP_Index baseIndent ) const
+{
+ XMP_Enforce( rdfString != 0 );
+ XMP_Assert ( (newline != 0) && (indentStr != 0) );
+ rdfString->erase();
+
+ // Fix up some default parameters.
+
+ enum { kDefaultPad = 2048 };
+ size_t unicodeUnitSize = 1;
+ XMP_OptionBits charEncoding = options & kXMP_EncodingMask;
+
+ if ( charEncoding != kXMP_EncodeUTF8 ) {
+ if ( options & _XMP_UTF16_Bit ) {
+ if ( options & _XMP_UTF32_Bit ) XMP_Throw ( "Can't use both _XMP_UTF16_Bit and _XMP_UTF32_Bit", kXMPErr_BadOptions );
+ unicodeUnitSize = 2;
+ } else if ( options & _XMP_UTF32_Bit ) {
+ unicodeUnitSize = 4;
+ } else {
+ XMP_Throw ( "Can't use _XMP_LittleEndian_Bit by itself", kXMPErr_BadOptions );
+ }
+ }
+
+ if ( options & kXMP_OmitAllFormatting ) {
+ newline = " "; // ! Yes, a space for "newline". This ensures token separation.
+ indentStr = "";
+ } else {
+ if ( *newline == 0 ) newline = "\xA"; // Linefeed
+ if ( *indentStr == 0 ) {
+ indentStr = " ";
+ if ( ! (options & kXMP_UseCompactFormat) ) indentStr = " ";
+ }
+ }
+
+ if ( options & kXMP_ExactPacketLength ) {
+ if ( options & (kXMP_OmitPacketWrapper | kXMP_IncludeThumbnailPad) ) {
+ XMP_Throw ( "Inconsistent options for exact size serialize", kXMPErr_BadOptions );
+ }
+ if ( (padding & (unicodeUnitSize-1)) != 0 ) {
+ XMP_Throw ( "Exact size must be a multiple of the Unicode element", kXMPErr_BadOptions );
+ }
+ } else if ( options & kXMP_ReadOnlyPacket ) {
+ if ( options & (kXMP_OmitPacketWrapper | kXMP_IncludeThumbnailPad) ) {
+ XMP_Throw ( "Inconsistent options for read-only packet", kXMPErr_BadOptions );
+ }
+ padding = 0;
+ } else if ( options & kXMP_OmitPacketWrapper ) {
+ if ( options & kXMP_IncludeThumbnailPad ) {
+ XMP_Throw ( "Inconsistent options for non-packet serialize", kXMPErr_BadOptions );
+ }
+ padding = 0;
+ } else if ( options & kXMP_OmitXMPMetaElement ) {
+ if ( options & kXMP_IncludeRDFHash ) {
+ XMP_Throw ( "Inconsistent options for x:xmpmeta serialize", kXMPErr_BadOptions );
+ }
+ padding = 0;
+ } else {
+ if ( padding == 0 ) {
+ padding = kDefaultPad * unicodeUnitSize;
+ } else if ( (padding >> 28) != 0 ) {
+ XMP_Throw ( "Outrageously large padding size", kXMPErr_BadOptions ); // Bigger than 256 MB.
+ }
+ if ( options & kXMP_IncludeThumbnailPad ) {
+ if ( ! this->DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) padding += (10000 * unicodeUnitSize); // *** Need a better estimate.
+ }
+ }
+
+ // Serialize as UTF-8, then convert to UTF-16 or UTF-32 if necessary, and assemble with the padding and tail.
+
+ std::string tailStr;
+
+ SerializeAsRDF ( *this, *rdfString, tailStr, options, newline, indentStr, baseIndent );
+
+ if ( charEncoding == kXMP_EncodeUTF8 ) {
+
+ if ( options & kXMP_ExactPacketLength ) {
+ size_t minSize = rdfString->size() + tailStr.size();
+ if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize );
+ padding -= minSize; // Now the actual amount of padding to add.
+ }
+
+ size_t newlineLen = strlen ( newline );
+
+ if ( padding < newlineLen ) {
+ rdfString->append ( padding, ' ' );
+ } else {
+ padding -= newlineLen; // Write this newline last.
+ while ( padding >= (100 + newlineLen) ) {
+ rdfString->append ( 100, ' ' );
+ *rdfString += newline;
+ padding -= (100 + newlineLen);
+ }
+ rdfString->append ( padding, ' ' );
+ *rdfString += newline;
+ }
+
+ *rdfString += tailStr;
+
+ } else {
+
+ // Need to convert the encoding. Swap the UTF-8 into a local string and convert back. Assemble everything.
+
+ XMP_VarString utf8Str, newlineStr;
+ bool bigEndian = ((charEncoding & _XMP_LittleEndian_Bit) == 0);
+
+ if ( charEncoding & _XMP_UTF16_Bit ) {
+
+ std::string padStr ( " " ); padStr[0] = 0; // Assume big endian.
+
+ utf8Str.swap ( *rdfString );
+ ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), rdfString, bigEndian );
+ utf8Str.swap ( tailStr );
+ ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian );
+
+ if ( options & kXMP_ExactPacketLength ) {
+ size_t minSize = rdfString->size() + tailStr.size();
+ if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize );
+ padding -= minSize; // Now the actual amount of padding to add (in bytes).
+ }
+
+ utf8Str.assign ( newline );
+ ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &newlineStr, bigEndian );
+ size_t newlineLen = newlineStr.size();
+
+ if ( padding < newlineLen ) {
+ for ( int i = padding/2; i > 0; --i ) *rdfString += padStr;
+ } else {
+ padding -= newlineLen; // Write this newline last.
+ while ( padding >= (200 + newlineLen) ) {
+ for ( int i = 100; i > 0; --i ) *rdfString += padStr;
+ *rdfString += newlineStr;
+ padding -= (200 + newlineLen);
+ }
+ for ( int i = padding/2; i > 0; --i ) *rdfString += padStr;
+ *rdfString += newlineStr;
+ }
+
+ *rdfString += tailStr;
+
+ } else {
+
+ std::string padStr ( " " ); padStr[0] = padStr[1] = padStr[2] = 0; // Assume big endian.
+ UTF8_to_UTF32_Proc Converter = UTF8_to_UTF32BE;
+
+ if ( charEncoding & _XMP_LittleEndian_Bit ) {
+ padStr[0] = ' '; padStr[1] = padStr[2] = padStr[3] = 0;
+ Converter = UTF8_to_UTF32LE;
+ }
+
+ utf8Str.swap ( *rdfString );
+ ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), rdfString, bigEndian );
+ utf8Str.swap ( tailStr );
+ ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian );
+
+ if ( options & kXMP_ExactPacketLength ) {
+ size_t minSize = rdfString->size() + tailStr.size();
+ if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize );
+ padding -= minSize; // Now the actual amount of padding to add (in bytes).
+ }
+
+ utf8Str.assign ( newline );
+ ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &newlineStr, bigEndian );
+ size_t newlineLen = newlineStr.size();
+
+ if ( padding < newlineLen ) {
+ for ( int i = padding/4; i > 0; --i ) *rdfString += padStr;
+ } else {
+ padding -= newlineLen; // Write this newline last.
+ while ( padding >= (400 + newlineLen) ) {
+ for ( int i = 100; i > 0; --i ) *rdfString += padStr;
+ *rdfString += newlineStr;
+ padding -= (400 + newlineLen);
+ }
+ for ( int i = padding/4; i > 0; --i ) *rdfString += padStr;
+ *rdfString += newlineStr;
+ }
+
+ *rdfString += tailStr;
+
+ }
+
+ }
+
+} // SerializeToBuffer
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPMeta.cpp b/gpr/source/lib/xmp_core/XMPMeta.cpp
new file mode 100644
index 0000000..62bcb60
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPMeta.cpp
@@ -0,0 +1,1381 @@
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+//
+// Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
+// one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
+// =================================================================================================
+
+#include <algorithm> // For sort and stable_sort.
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPMeta.hpp"
+#include "XMPIterator.hpp"
+#include "XMPUtils.hpp"
+#include "public/include/XMP_Version.h"
+#include "UnicodeInlines.incl_cpp"
+#include "UnicodeConversions.hpp"
+
+#include <cstdio> // For snprintf.
+
+#if XMP_DebugBuild
+ #include <iostream>
+#endif
+
+using namespace std;
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+
+// *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
+
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+
+// =================================================================================================
+// Static Variables
+// ================
+
+XMP_VarString * xdefaultName = 0; // Needed in XMPMeta-Parse.cpp, MoveExplicitAliases.
+
+static XMPMeta::ErrorCallbackInfo sDefaultErrorCallback;
+
+// These are embedded version strings.
+
+const char * kXMPCore_EmbeddedVersion = kXMPCore_VersionMessage;
+const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr;
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpNodeOptions
+// ---------------
+
+static void
+DumpNodeOptions ( XMP_OptionBits options,
+ XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
+ memset(buffer, 0, 32);
+
+ static const char * optNames[] = { " schema", // 0x8000_0000
+ " ?30",
+ " ?29",
+ " -COMMAS-",
+ " ?27", // 0x0800_0000
+ " ?26",
+ " ?25",
+ " ?24",
+ " ?23", // 0x0080_0000
+ " isStale",
+ " isDerived",
+ " isStable",
+ " ?19", // 0x0008_0000
+ " isInternal",
+ " hasAliases",
+ " isAlias",
+ " -AFTER-", // 0x0000_8000
+ " -BEFORE-",
+ " isCompact",
+ " isLangAlt",
+ " isAlt", // 0x0000_0800
+ " isOrdered",
+ " isArray",
+ " isStruct",
+ " hasType", // 0x0000_0080
+ " hasLang",
+ " isQual",
+ " hasQual",
+ " ?3", // 0x0000_0008
+ " ?2",
+ " URI",
+ " ?0" };
+
+ if ( options == 0 ) {
+
+ OutProcNChars ( "(0x0)", 5 );
+
+ } else {
+
+ OutProcNChars ( "(0x", 3 );
+ OutProcHexInt ( options );
+ OutProcNChars ( " :", 2 );
+
+ XMP_OptionBits mask = 0x80000000;
+ for ( int b = 0; b < 32; ++b ) {
+ if ( options & mask ) OutProcLiteral ( optNames[b] );
+ mask = mask >> 1;
+ }
+ OutProcNChars ( ")", 1 );
+
+ }
+
+} // DumpNodeOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpPropertyTree
+// ----------------
+
+// *** Extract the validation code into a separate routine to call on exit in debug builds.
+
+static void
+DumpPropertyTree ( const XMP_Node * currNode,
+ int indent,
+ size_t itemIndex,
+ XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
+
+ OutProcIndent ( (size_t)indent );
+ if ( itemIndex == 0 ) {
+ if ( currNode->options & kXMP_PropIsQualifier ) OutProcNChars ( "? ", 2 );
+ DumpClearString ( currNode->name, outProc, refCon );
+ } else {
+ OutProcNChars ( "[", 1 );
+ OutProcDecInt ( itemIndex );
+ OutProcNChars ( "]", 1 );
+ }
+
+ if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
+ OutProcNChars ( " = \"", 4 );
+ DumpClearString ( currNode->value, outProc, refCon );
+ OutProcNChars ( "\"", 1 );
+ }
+
+ if ( currNode->options != 0 ) {
+ OutProcNChars ( " ", 2 );
+ DumpNodeOptions ( currNode->options, outProc, refCon );
+ }
+
+ if ( currNode->options & kXMP_PropHasLang ) {
+ if ( currNode->qualifiers.empty() || (currNode->qualifiers[0]->name != "xml:lang") ) {
+ OutProcLiteral ( " ** bad lang flag **" );
+ }
+ }
+ // *** Check rdf:type also.
+
+ if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
+ if ( ! currNode->children.empty() ) OutProcLiteral ( " ** bad children **" );
+ } else if ( currNode->options & kXMP_PropValueIsArray ) {
+ if ( currNode->options & kXMP_PropValueIsStruct ) OutProcLiteral ( " ** bad comp flags **" );
+ } else if ( (currNode->options & kXMP_PropCompositeMask) != kXMP_PropValueIsStruct ) {
+ OutProcLiteral ( " ** bad comp flags **" );
+ }
+
+ #if 0 // *** XMP_DebugBuild
+ if ( (currNode->_namePtr != currNode->name.c_str()) ||
+ (currNode->_valuePtr != currNode->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
+ #endif
+
+ OutProcNewline();
+
+ for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+
+ const XMP_Node * currQual = currNode->qualifiers[qualNum];
+
+ if ( currQual->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
+ if ( currQual->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad qual name => " );
+ if ( ! (currQual->options & kXMP_PropIsQualifier) ) OutProcLiteral ( "** bad qual flag => " );
+ if ( currQual->name == "xml:lang" ) {
+ if ( (qualNum != 0) || (! (currNode->options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " );
+ }
+
+ DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon );
+
+ }
+
+ for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
+
+ const XMP_Node * currChild = currNode->children[childNum];
+
+ if ( currChild->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
+ if ( currChild->options & kXMP_PropIsQualifier ) OutProcLiteral ( "** bad qual flag => " );
+
+ if ( currNode->options & kXMP_PropValueIsArray ) {
+ itemIndex = childNum+1;
+ if ( currChild->name != kXMP_ArrayItemName ) OutProcLiteral ( "** bad item name => " );
+ } else {
+ itemIndex = 0;
+ if ( currChild->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad field name => " );
+ }
+
+ DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon );
+
+ }
+
+} // DumpPropertyTree
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpXMLTree
+// -----------
+
+#if DumpXMLParseTree
+
+static inline void PutHexByte ( FILE * log, unsigned char ch )
+{
+
+ fprintf ( log, "\\x" );
+ if ( ch < 0x10 ) {
+ fprintf ( log, "%c", kHexDigits[ch] );
+ } else {
+ fprintf ( log, "%c%c", kHexDigits[ch>>4], kHexDigits[ch&0xF] );
+ }
+
+} // PutHexByte
+
+// -------------------------------------------------------------------------------------------------
+
+static void PutClearString ( FILE * log, const std::string & str )
+{
+
+ for ( size_t i = 0; i != str.size(); ++i ) {
+ unsigned char ch = str[i];
+ if ( (0x20 <= ch) && (ch <= 0x7F) ) {
+ fprintf ( log, "%c", ch );
+ } else {
+ PutHexByte ( log, ch );
+ }
+ }
+
+} // PutClearString
+
+// -------------------------------------------------------------------------------------------------
+
+static void DumpXMLTree ( FILE * log, const XML_Node & node, int indent )
+{
+ size_t i;
+
+ #if 0 // *** XMP_DebugBuild
+ if ( (node._namePtr != node.name.c_str()) ||
+ (node._valuePtr != node.value.c_str()) ) fprintf ( log, "*** bad debug string ***\n" );
+ #endif
+
+ for ( i = 0; i != (size_t)indent; ++i ) fprintf ( log, " " );
+
+ switch ( node.kind ) {
+
+ case kRootNode :
+ fprintf ( log, "\nStart of XML tree dump\n\n" );
+ if ( (indent != 0) || (! node.attrs.empty()) ||
+ (! node.ns.empty()) || (! node.name.empty()) || (!node.value.empty()) ) fprintf ( log, " ** invalid root ** \n" );
+ for ( i = 0; i < node.children.size(); ++i ) {
+ XMP_Uns8 kind = node.children[i]->kind;
+ if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
+ DumpXMLTree ( log, *node.children[i], indent+1 );
+ }
+ fprintf ( log, "\nEnd of XML tree dump\n" );
+ break;
+
+ case kElemNode :
+ fprintf ( log, "Elem %s", node.name.c_str() );
+ if ( indent == 0 ) fprintf ( log, " ** invalid elem ** " );
+ if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
+ fprintf ( log, "\n" );
+ for ( i = 0; i < node.attrs.size(); ++i ) {
+ XMP_Uns8 kind = node.attrs[i]->kind;
+ if ( kind != kAttrNode ) fprintf ( log, " ** invalid attr ** \n" );
+ DumpXMLTree ( log, *node.attrs[i], indent+2 );
+ }
+ for ( i = 0; i < node.children.size(); ++i ) {
+ XMP_Uns8 kind = node.children[i]->kind;
+ if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
+ DumpXMLTree ( log, *node.children[i], indent+1 );
+ }
+ break;
+
+ case kAttrNode :
+ fprintf ( log, "Attr %s", node.name.c_str() );
+ if ( (indent == 0) || node.name.empty() || (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid attr ** " );
+ fprintf ( log, " = \"" );
+ PutClearString ( log, node.value );
+ fprintf ( log, "\"" );
+ if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
+ fprintf ( log, "\n" );
+ break;
+
+ case kCDataNode :
+ if ( (indent == 0) || (! node.ns.empty()) || (! node.name.empty()) ||
+ (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid cdata ** \n" );
+ fprintf ( log, "\"" );
+ PutClearString ( log, node.value );
+ fprintf ( log, "\"\n" );
+ break;
+
+ case kPINode :
+ fprintf ( log, "PI %s", node.name.c_str() );
+ if ( (indent == 0) || node.name.empty() || (! node.children.empty()) ) fprintf ( log, " ** invalid pi ** \n" );
+ if ( ! node.value.empty() ) {
+ fprintf ( log, " <? " );
+ PutClearString ( log, node.value );
+ fprintf ( log, " ?>" );
+ }
+ fprintf ( log, "\n" );
+ break;
+
+ }
+
+} // DumpXMLTree
+
+#endif // DumpXMLParseTree
+
+
+// -------------------------------------------------------------------------------------------------
+// CompareNodeNames
+// ----------------
+//
+// Comparison routine for sorting XMP nodes by name. The name "xml:lang" is less than anything else,
+// and "rdf:type" is less than anything except "xml:lang". This preserves special rules for qualifiers.
+
+static bool
+CompareNodeNames ( XMP_Node * left, XMP_Node * right )
+{
+
+ if ( left->name == "xml:lang" ) return true;
+ if ( right->name == "xml:lang" ) return false;
+
+ if ( left->name == "rdf:type" ) return true;
+ if ( right->name == "rdf:type" ) return false;
+
+ return ( left->name < right->name );
+
+} // CompareNodeNames
+
+
+// -------------------------------------------------------------------------------------------------
+// CompareNodeValues
+// -----------------
+//
+// Comparison routine for sorting XMP nodes by value.
+
+static bool
+CompareNodeValues ( XMP_Node * left, XMP_Node * right )
+{
+
+ if ( XMP_PropIsSimple ( left->options ) && XMP_PropIsSimple ( right->options ) ) {
+ return ( left->value < right->value );
+ }
+
+ XMP_OptionBits leftForm = left->options & kXMP_PropCompositeMask;
+ XMP_OptionBits rightForm = right->options & kXMP_PropCompositeMask;
+
+ return ( leftForm < rightForm );
+
+} // CompareNodeValues
+
+
+// -------------------------------------------------------------------------------------------------
+// CompareNodeLangs
+// ----------------
+//
+// Comparison routine for sorting XMP nodes by xml:lang qualifier. An "x-default" value is less than
+// any other language.
+
+static bool
+CompareNodeLangs ( XMP_Node * left, XMP_Node * right )
+{
+
+ if ( left->qualifiers.empty() || (left->qualifiers[0]->name != "xml:lang") ) return false;
+ if ( right->qualifiers.empty() || (right->qualifiers[0]->name != "xml:lang") ) return false;
+
+ if ( left->qualifiers[0]->value == "x-default" ) return true;
+ if ( right->qualifiers[0]->value == "x-default" ) return false;
+
+ return ( left->qualifiers[0]->value < right->qualifiers[0]->value );
+
+} // CompareNodeLangs
+
+
+// -------------------------------------------------------------------------------------------------
+// SortWithinOffspring
+// -------------------
+//
+// Sort one level down, within the elements of a node vector. This sorts the qualifiers of each
+// node. If the node is a struct it sorts the fields by names. If the node is an unordered array it
+// sorts the elements by value. If the node is an AltText array it sorts the elements by language.
+
+static void
+SortWithinOffspring ( XMP_NodeOffspring & nodeVec )
+{
+
+ for ( size_t i = 0, limit = nodeVec.size(); i < limit; ++i ) {
+
+ XMP_Node * currPos = nodeVec[i];
+
+ if ( ! currPos->qualifiers.empty() ) {
+ sort ( currPos->qualifiers.begin(), currPos->qualifiers.end(), CompareNodeNames );
+ SortWithinOffspring ( currPos->qualifiers );
+ }
+
+ if ( ! currPos->children.empty() ) {
+
+ if ( XMP_PropIsStruct ( currPos->options ) || XMP_NodeIsSchema ( currPos->options ) ) {
+ sort ( currPos->children.begin(), currPos->children.end(), CompareNodeNames );
+ } else if ( XMP_PropIsArray ( currPos->options ) ) {
+ if ( XMP_ArrayIsUnordered ( currPos->options ) ) {
+ stable_sort ( currPos->children.begin(), currPos->children.end(), CompareNodeValues );
+ } else if ( XMP_ArrayIsAltText ( currPos->options ) ) {
+ sort ( currPos->children.begin(), currPos->children.end(), CompareNodeLangs );
+ }
+ }
+
+ SortWithinOffspring ( currPos->children );
+
+ }
+
+ }
+
+} // SortWithinOffspring
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterAlias
+// -------------
+//
+// Allow 3 kinds of alias:
+// TopProp => TopProp
+// TopProp => TopArray[1]
+// TopProp => TopArray[@xml:lang='x-default']
+//
+// A new alias can be made to something that is already aliased, as long as the net result is one of
+// the legitimate forms. The new alias can already have aliases to it, also as long as result of
+// adjusting all of the exiting aliases leaves them legal.
+//
+// ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any
+// ! conflicts will result in later references throwing bad XPath exceptions.
+
+static void
+RegisterAlias ( XMP_StringPtr aliasNS,
+ XMP_StringPtr aliasProp,
+ XMP_StringPtr actualNS,
+ XMP_StringPtr actualProp,
+ XMP_OptionBits arrayForm )
+{
+ XMP_ExpandedXPath expAlias, expActual;
+ XMP_AliasMapPos mapPos;
+ XMP_ExpandedXPath * regActual = 0;
+
+ XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) ); // Enforced by wrapper.
+
+ // Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting
+ // the expanded XPath size remember that the schema URI is the first component. We don't have to
+ // compare the schema URIs though, the (unique) prefix is part of the top property name.
+
+ ExpandXPath ( aliasNS, aliasProp, &expAlias );
+ ExpandXPath ( actualNS, actualProp, &expActual );
+ if ( (expAlias.size() != 2) || (expActual.size() != 2) ) {
+ XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath );
+ }
+
+ arrayForm = VerifySetOptions ( arrayForm, 0 );
+ if ( arrayForm != 0 ) {
+ if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions );
+ expActual[1].options |= arrayForm; // Set the array form for the top level step.
+ if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) {
+ expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) );
+ } else {
+ expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) );
+ }
+ }
+
+ // See if there are any conflicts with existing aliases. A couple of the checks are easy. If the
+ // alias is already aliased it is only OK to reregister an identical alias. If the actual is
+ // already aliased to something else and the new chain is legal, just swap in the old base.
+
+ mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step );
+ if ( mapPos != sRegisteredAliasMap->end() ) {
+
+ // This alias is already registered to something, make sure it is the same something.
+
+ regActual = &mapPos->second;
+ if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) {
+ XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam );
+ }
+ if ( expActual.size() != regActual->size() ) {
+ XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam );
+ }
+ if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) {
+ XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam );
+ }
+ if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) {
+ XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam );
+ }
+ return;
+
+ }
+
+ mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step );
+ if ( mapPos != sRegisteredAliasMap->end() ) {
+
+ // The actual is already aliased to something else.
+
+ regActual = &mapPos->second;
+ if ( expActual.size() == 2 ) {
+ expActual = *regActual; // TopProp => TopProp => anything : substitute the entire old base.
+ } else if ( regActual->size() != 2 ) {
+ XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); // TopProp => TopArray[] => TopArray[] : nope.
+ } else {
+ expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step; // TopProp => TopArray[] => TopProp :
+ expActual[kRootPropStep].step = (*regActual)[kRootPropStep].step; // substitute the old base name.
+ }
+
+ }
+
+ // Checking for existing aliases to this one is touchier. This involves updating the alias map,
+ // which must not be done unless all of the changes are legal. So we need 2 loops, one to verify
+ // that everything is OK, and one to make the changes. The bad case is:
+ // TopProp => TopArray[] => TopArray[]
+ // In the valid cases we back substitute the new base.
+
+ for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
+ regActual = &mapPos->second;
+ if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
+ if ( (regActual->size() == 2) && (expAlias.size() == 2) ) {
+ XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam );
+ }
+ }
+ }
+
+ for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
+ regActual = &mapPos->second;
+ if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
+
+ if ( regActual->size() == 1 ) {
+ *regActual = expActual; // TopProp => TopProp => anything : substitute the entire new base.
+ } else {
+ (*regActual)[kSchemaStep].step = expActual[kSchemaStep].step; // TopProp => TopArray[] => TopProp :
+ (*regActual)[kRootPropStep].step = expActual[kRootPropStep].step; // substitute the new base name.
+ }
+
+ }
+ }
+
+ // Finally, all is OK to register the new alias.
+
+ (void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) );
+
+} // RegisterAlias
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterStandardAliases
+// -----------------------
+
+static void
+RegisterStandardAliases()
+{
+
+ // Aliases from XMP to DC.
+ RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
+ RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 );
+ RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 );
+ RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 );
+ RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 );
+ RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 );
+ RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 );
+ RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 );
+
+ // Aliases from PDF to DC and XMP.
+ RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
+ RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 );
+ RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 );
+ RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 );
+ RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 );
+ RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
+ RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
+
+ // Aliases from Photoshop to DC and XMP.
+ RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
+ RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
+ RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText );
+ RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 );
+ RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 );
+ RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
+ RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 );
+
+ // Aliases from TIFF and EXIF to DC and XMP.
+ RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
+ RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 );
+ RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 );
+ RegisterAlias ( kXMP_NS_EXIF, "DateTimeDigitized", kXMP_NS_XMP, "CreateDate", 0 );
+ RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 );
+ RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
+
+ // Aliases from PNG to DC and XMP.
+ RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
+ RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText);
+ RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 );
+ RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText);
+ RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 );
+ RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
+ RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText);
+
+} // RegisterStandardAliases
+
+
+// =================================================================================================
+// Constructors
+// ============
+
+
+XMPMeta::XMPMeta() : tree(XMP_Node(0,"",0)), clientRefs(0), xmlParser(0)
+{
+ #if XMP_TraceCTorDTor
+ printf ( "Default construct XMPMeta @ %.8X\n", this );
+ #endif
+
+ if ( sDefaultErrorCallback.clientProc != 0 ) {
+ this->errorCallback.wrapperProc = sDefaultErrorCallback.wrapperProc;
+ this->errorCallback.clientProc = sDefaultErrorCallback.clientProc;
+ this->errorCallback.context = sDefaultErrorCallback.context;
+ this->errorCallback.limit = sDefaultErrorCallback.limit;
+ }
+
+} // XMPMeta
+
+// -------------------------------------------------------------------------------------------------
+
+XMPMeta::~XMPMeta() RELEASE_NO_THROW
+{
+ #if XMP_TraceCTorDTor
+ printf ( "Destruct XMPMeta @ %.8X\n", this );
+ #endif
+
+ XMP_Assert ( this->clientRefs <= 0 );
+ if ( xmlParser != 0 ) delete ( xmlParser );
+ xmlParser = 0;
+
+} // ~XMPMeta
+
+
+// =================================================================================================
+// Class Static Functions
+// ======================
+//
+//
+// =================================================================================================
+
+// -------------------------------------------------------------------------------------------------
+// GetVersionInfo
+// --------------
+
+/* class-static */ void
+XMPMeta::GetVersionInfo ( XMP_VersionInfo * info )
+{
+
+ memset ( info, 0, sizeof(*info) ); // AUDIT: Safe, using sizeof the destination.
+ XMP_Assert ( sizeof(*info) == sizeof(XMP_VersionInfo) );
+
+ info->major = XMPCORE_API_VERSION_MAJOR;
+ info->minor = XMPCORE_API_VERSION_MINOR;
+ info->micro = 0; //no longer used
+ info->isDebug = kXMPCore_DebugFlag;
+ info->flags = 0; // ! None defined yet.
+ info->message = kXMPCore_VersionMessage;
+
+} // GetVersionInfo
+
+// -------------------------------------------------------------------------------------------------
+// Initialize
+// ----------
+
+#if XMP_TraceCoreCalls
+ FILE * xmpCoreLog = stderr;
+#endif
+
+#if UseGlobalLibraryLock
+ XMP_BasicMutex sLibraryLock;
+#endif
+
+/* class-static */ bool
+XMPMeta::Initialize()
+{
+ // Allocate and initialize static objects.
+
+ ++sXMP_InitCount;
+ if ( sXMP_InitCount > 1 ) return true;
+
+ #if XMP_TraceCoreCallsToFile
+ xmpCoreLog = fopen ( "XMPCoreLog.txt", "w" );
+ if ( xmpCoreLog == 0 ) xmpCoreLog = stderr;
+ #endif
+
+ #if UseGlobalLibraryLock
+ InitializeBasicMutex ( sLibraryLock );
+ #endif
+
+ if ( ! Initialize_LibUtils() ) return false;
+ xdefaultName = new XMP_VarString ( "x-default" );
+
+ sRegisteredNamespaces = new XMP_NamespaceTable;
+ sRegisteredAliasMap = new XMP_AliasMap;
+
+ InitializeUnicodeConversions();
+
+
+ // Register standard namespaces and aliases.
+
+ XMP_StringPtr voidPtr;
+ XMP_StringLen voidLen;
+
+ (void) RegisterNamespace ( kXMP_NS_XML, "xml", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_RDF, "rdf", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_DC, "dc", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP, "xmp", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDF, "pdf", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_Photoshop, "photoshop", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PSAlbum, "album", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_EXIF, "exif", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_EXIF_Aux, "aux", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_ExifEX, "exifEX", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_TIFF, "tiff", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PNG, "png", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_JPEG, "jpeg", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_JP2K, "jp2k", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_CameraRaw, "crs", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_ASF, "asf", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_WAV, "wav", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_AdobeStockPhoto, "bmsp", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_CreatorAtom, "creatorAtom", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP_Rights, "xmpRights", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_MM, "xmpMM", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_BJ, "xmpBJ", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Note, "xmpNote", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_DM, "xmpDM", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_Script, "xmpScript", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_BWF, "bext", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_AEScart, "AEScart", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_RIFFINFO, "riffinfo", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Text, "xmpT", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_PagedFile, "xmpTPg", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Graphics, "xmpG", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Image, "xmpGImg", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP_Font, "stFnt", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_Dimensions, "stDim", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ResourceEvent, "stEvt", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ResourceRef, "stRef", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ST_Version, "stVer", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ST_Job, "stJob", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_XMP_ManifestItem, "stMfs", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_XMP_IdentifierQual, "xmpidq", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_IPTCCore, "Iptc4xmpCore", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_IPTCExt, "Iptc4xmpExt", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_DICOM, "DICOM", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PLUS, "plus", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Schema, "pdfaSchema", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Property, "pdfaProperty", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Type, "pdfaType", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Field, "pdfaField", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_ID, "pdfaid", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFA_Extension, "pdfaExtension", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( kXMP_NS_PDFX, "pdfx", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( kXMP_NS_PDFX_ID, "pdfxid", &voidPtr, &voidLen );
+
+ (void) RegisterNamespace ( "adobe:ns:meta/", "x", &voidPtr, &voidLen );
+ (void) RegisterNamespace ( "http://ns.adobe.com/iX/1.0/", "iX", &voidPtr, &voidLen );
+
+ RegisterStandardAliases();
+
+ // Initialize the other core classes.
+
+ if ( ! XMPIterator::Initialize() ) XMP_Throw ( "Failure from XMPIterator::Initialize", kXMPErr_InternalFailure );
+ if ( ! XMPUtils::Initialize() ) XMP_Throw ( "Failure from XMPUtils::Initialize", kXMPErr_InternalFailure );
+ // Do miscelaneous semantic checks of types and arithmetic.
+
+ XMP_Assert ( sizeof(XMP_Int8) == 1 );
+ XMP_Assert ( sizeof(XMP_Int16) == 2 );
+ XMP_Assert ( sizeof(XMP_Int32) == 4 );
+ XMP_Assert ( sizeof(XMP_Int64) == 8 );
+ XMP_Assert ( sizeof(XMP_Uns8) == 1 );
+ XMP_Assert ( sizeof(XMP_Uns16) == 2 );
+ XMP_Assert ( sizeof(XMP_Uns32) == 4 );
+ XMP_Assert ( sizeof(XMP_Uns64) == 8 );
+ XMP_Assert ( sizeof(XMP_Bool) == 1 );
+
+ XMP_Assert ( sizeof(XMP_OptionBits) == 4 ); // Check that option masking work on all 32 bits.
+ XMP_OptionBits flag = (XMP_OptionBits) (~0UL);
+ XMP_Assert ( flag == (XMP_OptionBits)(-1L) );
+ XMP_Assert ( (flag ^ kXMP_PropHasLang) == 0xFFFFFFBFUL );
+ XMP_Assert ( (flag & ~kXMP_PropHasLang) == 0xFFFFFFBFUL );
+
+ XMP_OptionBits opt1 = 0; // Check the general option bit macros.
+ XMP_OptionBits opt2 = (XMP_OptionBits)~0UL;
+ XMP_SetOption ( opt1, kXMP_PropValueIsArray );
+ XMP_ClearOption ( opt2, kXMP_PropValueIsArray );
+ XMP_Assert ( opt1 == ~opt2 );
+ XMP_Assert ( XMP_TestOption ( opt1, kXMP_PropValueIsArray ) );
+ XMP_Assert ( ! XMP_TestOption ( opt2, kXMP_PropValueIsArray ) );
+
+ XMP_Assert ( XMP_PropIsSimple ( ~kXMP_PropCompositeMask ) ); // Check the special option bit macros.
+ XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsStruct ) );
+ XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsArray ) );
+
+ XMP_Assert ( XMP_PropIsStruct ( kXMP_PropValueIsStruct ) );
+ XMP_Assert ( XMP_PropIsArray ( kXMP_PropValueIsArray ) );
+ XMP_Assert ( ! XMP_PropIsStruct ( ~kXMP_PropValueIsStruct ) );
+ XMP_Assert ( ! XMP_PropIsArray ( ~kXMP_PropValueIsArray ) );
+
+ XMP_Assert ( XMP_ArrayIsUnordered ( ~kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( XMP_ArrayIsOrdered ( kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( XMP_ArrayIsAlternate ( kXMP_PropArrayIsAlternate ) );
+ XMP_Assert ( XMP_ArrayIsAltText ( kXMP_PropArrayIsAltText ) );
+ XMP_Assert ( ! XMP_ArrayIsUnordered ( kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( ! XMP_ArrayIsOrdered ( ~kXMP_PropArrayIsOrdered ) );
+ XMP_Assert ( ! XMP_ArrayIsAlternate ( ~kXMP_PropArrayIsAlternate ) );
+ XMP_Assert ( ! XMP_ArrayIsAltText ( ~kXMP_PropArrayIsAltText ) );
+
+ XMP_Assert ( XMP_PropHasQualifiers ( kXMP_PropHasQualifiers ) );
+ XMP_Assert ( XMP_PropIsQualifier ( kXMP_PropIsQualifier ) );
+ XMP_Assert ( XMP_PropHasLang ( kXMP_PropHasLang ) );
+ XMP_Assert ( ! XMP_PropHasQualifiers ( ~kXMP_PropHasQualifiers ) );
+ XMP_Assert ( ! XMP_PropIsQualifier ( ~kXMP_PropIsQualifier ) );
+ XMP_Assert ( ! XMP_PropHasLang ( ~kXMP_PropHasLang ) );
+
+ XMP_Assert ( XMP_NodeIsSchema ( kXMP_SchemaNode ) );
+ XMP_Assert ( XMP_PropIsAlias ( kXMP_PropIsAlias ) );
+ XMP_Assert ( ! XMP_NodeIsSchema ( ~kXMP_SchemaNode ) );
+ XMP_Assert ( ! XMP_PropIsAlias ( ~kXMP_PropIsAlias ) );
+
+ #if 0 // Generally off, enable to hand check generated code.
+ extern XMP_OptionBits opt3, opt4;
+ if ( XMP_TestOption ( opt3, kXMP_PropValueIsArray ) ) opt4 = opt3;
+ if ( ! XMP_TestOption ( opt3, kXMP_PropValueIsStruct ) ) opt4 = opt3;
+ static bool ok1 = XMP_TestOption ( opt4, kXMP_PropValueIsArray );
+ static bool ok2 = ! XMP_TestOption ( opt4, kXMP_PropValueIsStruct );
+ #endif
+
+ // Make sure the embedded info strings are referenced and kept.
+ if ( (kXMPCore_EmbeddedVersion[0] == 0) || (kXMPCore_EmbeddedCopyright[0] == 0) ) return false;
+ return true;
+
+} // Initialize
+
+
+// -------------------------------------------------------------------------------------------------
+// Terminate
+// ---------
+
+/* class-static */ void
+XMPMeta::Terminate() RELEASE_NO_THROW
+{
+ --sXMP_InitCount;
+ if ( sXMP_InitCount != 0 ) return; // Not ready to terminate, or already terminated.
+
+ XMPIterator::Terminate();
+ XMPUtils::Terminate();
+#if ENABLE_NEW_DOM_MODEL
+ NS_XMPCOMMON::ITSingleton< NS_INT_XMPCORE::IXMPCoreObjectFactory >::DestroyInstance();
+ NS_INT_XMPCOMMON::TerminateXMPCommonFramework();
+#endif
+
+ EliminateGlobal ( sRegisteredNamespaces );
+ EliminateGlobal ( sRegisteredAliasMap );
+
+ EliminateGlobal ( xdefaultName );
+
+ Terminate_LibUtils();
+
+ #if UseGlobalLibraryLock
+ TerminateBasicMutex ( sLibraryLock );
+ #endif
+
+ #if XMP_TraceCoreCallsToFile
+ if ( xmpCoreLog != stderr ) fclose ( xmpCoreLog );
+ xmpCoreLog = stderr;
+ #endif
+
+ // reset static variables
+ sDefaultErrorCallback.Clear();
+} // Terminate
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpNamespaces
+// --------------
+//
+// Dump the prefix to URI map (easier to read) and verify that both are consistent and legit.
+
+// *** Should put checks in a separate routine for regular calling in debug builds.
+
+/* class-static */ XMP_Status
+XMPMeta::DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon )
+{
+
+ sRegisteredNamespaces->Dump ( outProc, refCon );
+ return 0;
+
+} // DumpNamespaces
+
+
+// -------------------------------------------------------------------------------------------------
+// GetGlobalOptions
+// ----------------
+
+/* class-static */ XMP_OptionBits
+XMPMeta::GetGlobalOptions()
+{
+ XMP_OptionBits options = 0;
+
+ return options;
+
+} // GetGlobalOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// SetGlobalOptions
+// ----------------
+
+/* class-static */ void
+XMPMeta::SetGlobalOptions ( XMP_OptionBits options )
+{
+
+ XMP_Throw ( "Unimplemented method XMPMeta::SetGlobalOptions", kXMPErr_Unimplemented );
+ void * p; p = &options; // Avoid unused param warnings.
+
+} // SetGlobalOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterNamespace
+// -----------------
+
+/* class-static */ bool
+XMPMeta::RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize )
+{
+
+ return sRegisteredNamespaces->Define ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize );
+
+} // RegisterNamespace
+
+
+// -------------------------------------------------------------------------------------------------
+// GetNamespacePrefix
+// ------------------
+
+/* class-static */ bool
+XMPMeta::GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr * namespacePrefix,
+ XMP_StringLen * prefixSize )
+{
+
+ return sRegisteredNamespaces->GetPrefix ( namespaceURI, namespacePrefix, prefixSize );
+
+} // GetNamespacePrefix
+
+
+// -------------------------------------------------------------------------------------------------
+// GetNamespaceURI
+// ---------------
+
+/* class-static */ bool
+XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ XMP_StringPtr * namespaceURI,
+ XMP_StringLen * uriSize )
+{
+
+ return sRegisteredNamespaces->GetURI ( namespacePrefix, namespaceURI, uriSize );
+
+} // GetNamespaceURI
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteNamespace
+// ---------------
+
+// *** Don't allow standard namespaces to be deleted.
+// *** We would be better off not having this. Instead, have local namespaces from parsing be
+// *** restricted to the object that introduced them.
+
+/* class-static */ void
+XMPMeta::DeleteNamespace ( XMP_StringPtr namespaceURI )
+{
+
+ XMP_Throw ( "Unimplemented method XMPMeta::DeleteNamespace", kXMPErr_Unimplemented );
+
+} // DeleteNamespace
+
+
+// =================================================================================================
+// Class Methods
+// =============
+//
+//
+// =================================================================================================
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpObject
+// ----------
+
+void
+XMPMeta::DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const
+{
+ XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
+
+ OutProcLiteral ( "Dumping XMPMeta object \"" );
+ DumpClearString ( tree.name, outProc, refCon );
+ OutProcNChars ( "\" ", 3 );
+ DumpNodeOptions ( tree.options, outProc, refCon );
+ #if 0 // *** XMP_DebugBuild
+ if ( (tree._namePtr != tree.name.c_str()) ||
+ (tree._valuePtr != tree.value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
+ #endif
+ OutProcNewline();
+
+ if ( ! tree.value.empty() ) {
+ OutProcLiteral ( "** bad root value ** \"" );
+ DumpClearString ( tree.value, outProc, refCon );
+ OutProcNChars ( "\"", 1 );
+ OutProcNewline();
+ }
+
+ if ( ! tree.qualifiers.empty() ) {
+ OutProcLiteral ( "** bad root qualifiers **" );
+ OutProcNewline();
+ for ( size_t qualNum = 0, qualLim = tree.qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon );
+ }
+ }
+
+ if ( ! tree.children.empty() ) {
+
+ for ( size_t childNum = 0, childLim = tree.children.size(); childNum < childLim; ++childNum ) {
+
+ const XMP_Node * currSchema = tree.children[childNum];
+
+ OutProcNewline();
+ OutProcIndent ( 1 );
+ DumpClearString ( currSchema->value, outProc, refCon );
+ OutProcNChars ( " ", 2 );
+ DumpClearString ( currSchema->name, outProc, refCon );
+ OutProcNChars ( " ", 2 );
+ DumpNodeOptions ( currSchema->options, outProc, refCon );
+ #if 0 // *** XMP_DebugBuild
+ if ( (currSchema->_namePtr != currSchema->name.c_str()) ||
+ (currSchema->_valuePtr != currSchema->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
+ #endif
+ OutProcNewline();
+
+ if ( ! (currSchema->options & kXMP_SchemaNode) ) {
+ OutProcLiteral ( "** bad schema options **" );
+ OutProcNewline();
+ }
+
+ if ( ! currSchema->qualifiers.empty() ) {
+ OutProcLiteral ( "** bad schema qualifiers **" );
+ OutProcNewline();
+ for ( size_t qualNum = 0, qualLim = currSchema->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
+ DumpPropertyTree ( currSchema->qualifiers[qualNum], 3, 0, outProc, refCon );
+ }
+ }
+
+ for ( size_t numChild = 0, childLimit = currSchema->children.size(); numChild < childLimit; ++numChild ) {
+ DumpPropertyTree ( currSchema->children[numChild], 2, 0, outProc, refCon );
+ }
+
+ }
+
+ }
+
+} // DumpObject
+
+
+// -------------------------------------------------------------------------------------------------
+// CountArrayItems
+// ---------------
+
+XMP_Index
+XMPMeta::CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ const XMP_Node * arrayNode = FindConstNode ( &tree, expPath );
+
+ if ( arrayNode == 0 ) return 0;
+ if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
+ return arrayNode->children.size();
+
+} // CountArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// GetObjectName
+// -------------
+
+void
+XMPMeta::GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const
+{
+
+ *namePtr = tree.name.c_str();
+ *nameLen = tree.name.size();
+
+} // GetObjectName
+
+
+// -------------------------------------------------------------------------------------------------
+// SetObjectName
+// -------------
+
+void
+XMPMeta::SetObjectName ( XMP_StringPtr name )
+{
+ VerifyUTF8 ( name ); // Throws if the string is not legit UTF-8.
+ tree.name = name;
+
+} // SetObjectName
+
+
+// -------------------------------------------------------------------------------------------------
+// GetObjectOptions
+// ----------------
+
+XMP_OptionBits
+XMPMeta::GetObjectOptions() const
+{
+ XMP_OptionBits options = 0;
+
+ return options;
+
+} // GetObjectOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// SetObjectOptions
+// ----------------
+
+void
+XMPMeta::SetObjectOptions ( XMP_OptionBits options )
+{
+
+ XMP_Throw ( "Unimplemented method XMPMeta::SetObjectOptions", kXMPErr_Unimplemented );
+ void * p; p = &options; // Avoid unused param warnings.
+
+} // SetObjectOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// Sort
+// ----
+//
+// At the top level the namespaces are sorted by their prefixes. Within a namespace, the top level
+// properties are sorted by name. Within a struct, the fields are sorted by their qualified name,
+// i.e. their XML prefix:local form. Unordered arrays of simple items are sorted by value. Language
+// Alternative arrays are sorted by the xml:lang qualifiers, with the "x-default" item placed first.
+
+void
+XMPMeta::Sort()
+{
+
+ if ( ! this->tree.qualifiers.empty() ) {
+ sort ( this->tree.qualifiers.begin(), this->tree.qualifiers.end(), CompareNodeNames );
+ SortWithinOffspring ( this->tree.qualifiers );
+ }
+
+ if ( ! this->tree.children.empty() ) {
+ // The schema prefixes are the node's value, the name is the URI, so we sort schemas by value.
+ sort ( this->tree.children.begin(), this->tree.children.end(), CompareNodeValues );
+ SortWithinOffspring ( this->tree.children );
+ }
+
+} // Sort
+
+
+// -------------------------------------------------------------------------------------------------
+// Erase
+// -----
+//
+// Clear everything except for clientRefs.
+
+void
+XMPMeta::Erase()
+{
+
+ if ( this->xmlParser != 0 ) {
+ delete ( this->xmlParser );
+ this->xmlParser = 0;
+ }
+ this->tree.ClearNode();
+
+} // Erase
+
+
+// -------------------------------------------------------------------------------------------------
+// Clone
+// -----
+
+void
+XMPMeta::Clone ( XMPMeta * clone, XMP_OptionBits options ) const
+{
+ if ( clone == 0 ) XMP_Throw ( "Null clone pointer", kXMPErr_BadParam );
+ if ( options != 0 ) XMP_Throw ( "No options are defined yet", kXMPErr_BadOptions );
+ XMP_Assert ( this->tree.parent == 0 );
+
+ clone->tree.ClearNode();
+
+ clone->tree.options = this->tree.options;
+ clone->tree.name = this->tree.name;
+ clone->tree.value = this->tree.value;
+ clone->errorCallback = this->errorCallback;
+
+ #if 0 // *** XMP_DebugBuild
+ clone->tree._namePtr = clone->tree.name.c_str();
+ clone->tree._valuePtr = clone->tree.value.c_str();
+ #endif
+
+ CloneOffspring ( &this->tree, &clone->tree );
+
+} // Clone
+
+// =================================================================================================
+// XMP_Node::GetLocalURI
+// =====================
+//
+// This has to be someplace where XMPMeta::GetNamespaceURI is visible.
+
+void XMP_Node::GetLocalURI ( XMP_StringPtr * uriStr, XMP_StringLen * uriSize ) const
+{
+
+ if ( uriStr != 0 ) *uriStr = ""; // Set up empty defaults.
+ if ( uriSize != 0 ) *uriSize = 0;
+
+ if ( this->name.empty() ) return;
+
+ if ( XMP_NodeIsSchema ( this->options ) ) {
+
+ if ( uriStr != 0 ) *uriStr = this->name.c_str();
+ if ( uriSize != 0 ) *uriSize = this->name.size();
+
+ } else {
+
+ size_t colonPos = this->name.find_first_of(':');
+ if ( colonPos == XMP_VarString::npos ) return; // ! Name of array items is "[]".
+
+ XMP_VarString prefix ( this->name, 0, colonPos );
+ XMPMeta::GetNamespaceURI ( prefix.c_str(), uriStr, uriSize );
+
+ }
+
+}
+
+// =================================================================================================
+// Error notifications
+// ===================
+
+// -------------------------------------------------------------------------------------------------
+// SetDefaultErrorCallback
+// -----------------------
+
+/* class-static */ void
+XMPMeta::SetDefaultErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit )
+{
+ XMP_Assert ( wrapperProc != 0 ); // Must always be set by the glue;
+
+ sDefaultErrorCallback.wrapperProc = wrapperProc;
+ sDefaultErrorCallback.clientProc = clientProc;
+ sDefaultErrorCallback.context = context;
+ sDefaultErrorCallback.limit = limit;
+
+} // SetDefaultErrorCallback
+
+// -------------------------------------------------------------------------------------------------
+// SetErrorCallback
+// ----------------
+
+void
+XMPMeta::SetErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit )
+{
+ XMP_Assert ( wrapperProc != 0 ); // Must always be set by the glue;
+
+ this->errorCallback.Clear();
+ this->errorCallback.wrapperProc = wrapperProc;
+ this->errorCallback.clientProc = clientProc;
+ this->errorCallback.context = context;
+ this->errorCallback.limit = limit;
+
+} // SetErrorCallback
+
+// -------------------------------------------------------------------------------------------------
+// ResetErrorCallbackLimit
+// -----------------------
+
+void
+XMPMeta::ResetErrorCallbackLimit ( XMP_Uns32 limit )
+{
+
+ this->errorCallback.limit = limit;
+ this->errorCallback.notifications = 0;
+ this->errorCallback.topSeverity = kXMPErrSev_Recoverable;
+
+} // ResetErrorCallbackLimit
+
+// -------------------------------------------------------------------------------------------------
+// ErrorCallbackInfo::CanNotify
+// -------------------------------
+//
+// This is const just to be usable from const XMPMeta functions.
+
+bool XMPMeta::ErrorCallbackInfo::CanNotify() const
+{
+ XMP_Assert ( (this->clientProc == 0) || (this->wrapperProc != 0) );
+ return ( this->clientProc != 0);
+}
+
+// -------------------------------------------------------------------------------------------------
+// ErrorCallbackInfo::ClientCallbackWrapper
+// -------------------------------
+//
+// This is const just to be usable from const XMPMeta functions.
+
+bool XMPMeta::ErrorCallbackInfo::ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const
+{
+ XMP_Bool retValue = (*this->wrapperProc) ( this->clientProc, this->context, severity, cause, messsage );
+ return ConvertXMP_BoolToBool(retValue);
+}
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPMeta.hpp b/gpr/source/lib/xmp_core/XMPMeta.hpp
new file mode 100644
index 0000000..2542f79
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPMeta.hpp
@@ -0,0 +1,428 @@
+#ifndef __XMPMeta_hpp__
+#define __XMPMeta_hpp__
+
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h"
+#include "public/include/XMP_Const.h"
+#include "XMPCore_Impl.hpp"
+#include "XMLParserAdapter.hpp"
+
+// -------------------------------------------------------------------------------------------------
+
+#ifndef DumpXMLParseTree
+ #define DumpXMLParseTree 0
+#endif
+
+extern XMP_VarString * xdefaultName; // Needed in XMPMeta-Parse.cpp, MoveExplicitAliases.
+
+class XMPIterator;
+class XMPUtils;
+
+// -------------------------------------------------------------------------------------------------
+
+class XMPMeta {
+public:
+
+ static void
+ GetVersionInfo ( XMP_VersionInfo * info );
+
+ static bool
+ Initialize();
+ static void
+ Terminate() RELEASE_NO_THROW;
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMPMeta();
+
+ virtual ~XMPMeta() RELEASE_NO_THROW;
+
+ // ---------------------------------------------------------------------------------------------
+
+ static XMP_OptionBits
+ GetGlobalOptions();
+
+ static void
+ SetGlobalOptions ( XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static XMP_Status
+ DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static bool
+ RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize );
+
+ static bool
+ GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr * namespacePrefix,
+ XMP_StringLen * prefixSize );
+
+ static bool
+ GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ XMP_StringPtr * namespaceURI,
+ XMP_StringLen * uriSize );
+
+ static void
+ DeleteNamespace ( XMP_StringPtr namespaceURI );
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options );
+
+ void
+ SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ void
+ AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ void
+ SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options );
+
+ void
+ SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName );
+
+ void
+ DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex );
+
+ void
+ DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName );
+
+ void
+ DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName );
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const;
+
+ bool
+ DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const;
+
+ bool
+ DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const;
+
+ bool
+ DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr * actualLang,
+ XMP_StringLen * langSize,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ void
+ SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ void
+ DeleteLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang);
+
+ // ---------------------------------------------------------------------------------------------
+
+ bool
+ GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const;
+
+ bool
+ GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options );
+
+ void
+ SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const;
+
+ void
+ SetObjectName ( XMP_StringPtr name );
+
+ XMP_OptionBits
+ GetObjectOptions() const;
+
+ void
+ SetObjectOptions ( XMP_OptionBits options );
+
+ void
+ Sort();
+
+ void
+ Erase();
+
+ void
+ Clone ( XMPMeta * clone, XMP_OptionBits options ) const;
+
+ XMP_Index
+ CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const;
+
+ void
+ DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ void
+ ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options );
+
+ void
+ SerializeToBuffer ( XMP_VarString * rdfString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ SetDefaultErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit );
+
+ void
+ SetErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit );
+
+ void
+ ResetErrorCallbackLimit ( XMP_Uns32 limit );
+
+ class ErrorCallbackInfo : public GenericErrorCallback {
+ public:
+
+ XMPMeta_ErrorCallbackWrapper wrapperProc;
+ XMPMeta_ErrorCallbackProc clientProc;
+ void * context;
+
+ ErrorCallbackInfo() : wrapperProc(0), clientProc(0), context(0) {};
+
+ void Clear() { this->wrapperProc = 0; this->clientProc = 0; this->context = 0;
+ GenericErrorCallback::Clear(); };
+
+ bool CanNotify() const;
+ bool ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const;
+ };
+
+ // =============================================================================================
+
+ // ---------------------------------------------------------------------------------------------
+ // - Everything is built out of standard nodes. Each node has a name, value, option flags, a
+ // vector of child nodes, and a vector of qualifier nodes.
+ //
+ // - The option flags are those passed to SetProperty and returned from GetProperty. They tell
+ // if the node is simple, a struct or an array; whether it has qualifiers, etc.
+ //
+ // - The name of the node is an XML qualified name, of the form "prefix:simple-name". Since we
+ // force all namespaces to be known and to have unique prefixes, this is semantically equivalent
+ // to using a URI and simple name pair.
+ //
+ // - Although the value part is only for leaf properties and the children part is only for
+ // structs and arrays, it is easier to simply have them in every node. This keeps things visible
+ // so that debugging is easier
+ //
+ // - The top level node children are the namespaces that contain properties, the next level are
+ // the top level properties, lower levels are the fields of structs or items of arrays. The name
+ // of the top level nodes is just the namespace prefix, with the colon terminator. The name of
+ // top level properties includes the namespace prefix.
+ //
+ // - Any property node, at any level, can have qualifiers. These are themselves general property
+ // nodes. And could in fact themselves have qualifiers!
+
+ // ! Expose the implementation so that file static functions can see the data.
+
+ XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0.
+ XMP_ReadWriteLock lock;
+
+ // ! Any data member changes must be propagted to the Clone function!
+
+ XMP_Node tree;
+ XMLParserAdapter * xmlParser;
+ ErrorCallbackInfo errorCallback;
+
+ friend class XMPIterator;
+ friend class XMPUtils;
+
+private:
+
+ // ! These are hidden on purpose:
+ XMPMeta ( const XMPMeta & /* original */ ) : tree(XMP_Node(0,"",0)), clientRefs(0), xmlParser(0)
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ void operator= ( const XMPMeta & /* rhs */ )
+ { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); };
+
+ // Special support routines for parsing, here to be able to access the errorCallback.
+ void ProcessXMLTree ( XMP_OptionBits options );
+ bool ProcessXMLBuffer ( XMP_StringPtr buffer, XMP_StringLen xmpSize, bool lastClientCall );
+ void ProcessRDF ( const XML_Node & xmlTree, XMP_OptionBits options );
+
+}; // class XMPMeta
+
+// =================================================================================================
+
+#endif // __XMPMeta_hpp__
diff --git a/gpr/source/lib/xmp_core/XMPUtils-FileInfo.cpp b/gpr/source/lib/xmp_core/XMPUtils-FileInfo.cpp
new file mode 100644
index 0000000..19096dc
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPUtils-FileInfo.cpp
@@ -0,0 +1,1493 @@
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include <algorithm> // For binary_search.
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPUtils.hpp"
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <stdio.h> // For snprintf.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+typedef unsigned long UniCodePoint;
+
+enum UniCharKind {
+ UCK_normal,
+ UCK_space,
+ UCK_comma,
+ UCK_semicolon,
+ UCK_quote,
+ UCK_control
+};
+typedef enum UniCharKind UniCharKind;
+
+#define UnsByte(c) ((unsigned char)(c))
+#define UCP(u) ((UniCodePoint)(u))
+ // ! Needed on Windows (& PC Linux?) for inequalities with literals ito avoid sign extension.
+
+#ifndef TraceMultiFile
+ #define TraceMultiFile 0
+#endif
+
+// =================================================================================================
+// Static Variables
+// ================
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+// -------------------------------------------------------------------------------------------------
+// ClassifyCharacter
+// -----------------
+
+static void
+ClassifyCharacter ( XMP_StringPtr fullString, size_t offset,
+ UniCharKind * charKind, size_t * charSize, UniCodePoint * uniChar )
+{
+ *charKind = UCK_normal; // Assume typical case.
+
+ unsigned char currByte = UnsByte ( fullString[offset] );
+
+ if ( currByte < UnsByte(0x80) ) {
+
+ // ----------------------------------------
+ // We've got a single byte ASCII character.
+
+ *charSize = 1;
+ *uniChar = currByte;
+
+ if ( currByte > UnsByte(0x22) ) {
+
+ if ( currByte == UnsByte(0x2C) ) {
+ *charKind = UCK_comma;
+ } else if ( currByte == UnsByte(0x3B) ) {
+ *charKind = UCK_semicolon;
+ }
+ // [2674672] Discontinue to interpret square brackets
+ // as Asian quotes in XMPUtils::SeparateArrayItems(..))
+ // *** else if ( (currByte == UnsByte(0x5B)) || (currByte == UnsByte(0x5D)) ) {
+ // *** *charKind = UCK_quote; // ! ASCII '[' and ']' are used as quotes in Chinese and Korean.
+ // *** }
+
+ } else { // currByte <= 0x22
+
+ if ( currByte == UnsByte(0x22) ) {
+ *charKind = UCK_quote;
+ } else if ( currByte == UnsByte(0x21) ) {
+ *charKind = UCK_normal;
+ } else if ( currByte == UnsByte(0x20) ) {
+ *charKind = UCK_space;
+ } else {
+ *charKind = UCK_control;
+ }
+
+ }
+
+ } else { // currByte >= 0x80
+
+ // ---------------------------------------------------------------------------------------
+ // We've got a multibyte Unicode character. The first byte has the number of bytes and the
+ // highest order bits. The other bytes each add 6 more bits. Compose the UTF-32 form so we
+ // can classify directly with the Unicode code points. Order the upperBits tests to be
+ // fastest for Japan, probably the most common non-ASCII usage.
+
+ *charSize = 0;
+ *uniChar = currByte;
+ while ( (*uniChar & 0x80) != 0 ) { // Count the leading 1 bits in the byte.
+ ++(*charSize);
+ *uniChar = *uniChar << 1;
+ }
+ XMP_Assert ( (offset + *charSize) <= strlen(fullString) );
+
+ *uniChar = *uniChar & 0x7F; // Put the character bits in the bottom of uniChar.
+ *uniChar = *uniChar >> *charSize;
+
+ for ( size_t i = (offset + 1); i < (offset + *charSize); ++i ) {
+ *uniChar = (*uniChar << 6) | (UnsByte(fullString[i]) & 0x3F);
+ }
+
+ XMP_Uns32 upperBits = *uniChar >> 8; // First filter on just the high order 24 bits.
+
+ if ( upperBits == 0xFF ) { // U+FFxx
+
+ if ( *uniChar == UCP(0xFF0C) ) {
+ *charKind = UCK_comma; // U+FF0C, full width comma.
+ } else if ( *uniChar == UCP(0xFF1B) ) {
+ *charKind = UCK_semicolon; // U+FF1B, full width semicolon.
+ } else if ( *uniChar == UCP(0xFF64) ) {
+ *charKind = UCK_comma; // U+FF64, half width ideographic comma.
+ }
+
+ } else if ( upperBits == 0xFE ) { // U+FE--
+
+ if ( *uniChar == UCP(0xFE50) ) {
+ *charKind = UCK_comma; // U+FE50, small comma.
+ } else if ( *uniChar == UCP(0xFE51) ) {
+ *charKind = UCK_comma; // U+FE51, small ideographic comma.
+ } else if ( *uniChar == UCP(0xFE54) ) {
+ *charKind = UCK_semicolon; // U+FE54, small semicolon.
+ }
+
+ } else if ( upperBits == 0x30 ) { // U+30--
+
+ if ( *uniChar == UCP(0x3000) ) {
+ *charKind = UCK_space; // U+3000, ideographic space.
+ } else if ( *uniChar == UCP(0x3001) ) {
+ *charKind = UCK_comma; // U+3001, ideographic comma.
+ } else if ( (UCP(0x3008) <= *uniChar) && (*uniChar <= UCP(0x300F)) ) {
+ *charKind = UCK_quote; // U+3008..U+300F, various quotes.
+ } else if ( *uniChar == UCP(0x303F) ) {
+ *charKind = UCK_space; // U+303F, ideographic half fill space.
+ } else if ( (UCP(0x301D) <= *uniChar) && (*uniChar <= UCP(0x301F)) ) {
+ *charKind = UCK_quote; // U+301D..U+301F, double prime quotes.
+ }
+
+ } else if ( upperBits == 0x20 ) { // U+20--
+
+ if ( (UCP(0x2000) <= *uniChar) && (*uniChar <= UCP(0x200B)) ) {
+ *charKind = UCK_space; // U+2000..U+200B, en quad through zero width space.
+ } else if ( *uniChar == UCP(0x2015) ) {
+ *charKind = UCK_quote; // U+2015, dash quote.
+ } else if ( (UCP(0x2018) <= *uniChar) && (*uniChar <= UCP(0x201F)) ) {
+ *charKind = UCK_quote; // U+2018..U+201F, various quotes.
+ } else if ( *uniChar == UCP(0x2028) ) {
+ *charKind = UCK_control; // U+2028, line separator.
+ } else if ( *uniChar == UCP(0x2029) ) {
+ *charKind = UCK_control; // U+2029, paragraph separator.
+ } else if ( (*uniChar == UCP(0x2039)) || (*uniChar == UCP(0x203A)) ) {
+ *charKind = UCK_quote; // U+2039 and U+203A, guillemet quotes.
+ }
+
+ } else if ( upperBits == 0x06 ) { // U+06--
+
+ if ( *uniChar == UCP(0x060C) ) {
+ *charKind = UCK_comma; // U+060C, Arabic comma.
+ } else if ( *uniChar == UCP(0x061B) ) {
+ *charKind = UCK_semicolon; // U+061B, Arabic semicolon.
+ }
+
+ } else if ( upperBits == 0x05 ) { // U+05--
+
+ if ( *uniChar == UCP(0x055D) ) {
+ *charKind = UCK_comma; // U+055D, Armenian comma.
+ }
+
+ } else if ( upperBits == 0x03 ) { // U+03--
+
+ if ( *uniChar == UCP(0x037E) ) {
+ *charKind = UCK_semicolon; // U+037E, Greek "semicolon" (really a question mark).
+ }
+
+ } else if ( upperBits == 0x00 ) { // U+00--
+
+ if ( (*uniChar == UCP(0x00AB)) || (*uniChar == UCP(0x00BB)) ) {
+ *charKind = UCK_quote; // U+00AB and U+00BB, guillemet quotes.
+ }
+
+ }
+
+ }
+
+} // ClassifyCharacter
+
+
+// -------------------------------------------------------------------------------------------------
+// IsClosingingQuote
+// -----------------
+
+static inline bool
+IsClosingingQuote ( UniCodePoint uniChar, UniCodePoint openQuote, UniCodePoint closeQuote )
+{
+
+ if ( (uniChar == closeQuote) ||
+ ( (openQuote == UCP(0x301D)) && ((uniChar == UCP(0x301E)) || (uniChar == UCP(0x301F))) ) ) {
+ return true;
+ } else {
+ return false;
+ }
+
+} // IsClosingingQuote
+
+
+// -------------------------------------------------------------------------------------------------
+// IsSurroundingQuote
+// ------------------
+
+static inline bool
+IsSurroundingQuote ( UniCodePoint uniChar, UniCodePoint openQuote, UniCodePoint closeQuote )
+{
+
+ if ( (uniChar == openQuote) || IsClosingingQuote ( uniChar, openQuote, closeQuote ) ) {
+ return true;
+ } else {
+ return false;
+ }
+
+} // IsSurroundingQuote
+
+
+// -------------------------------------------------------------------------------------------------
+// GetClosingQuote
+// ---------------
+
+static UniCodePoint
+GetClosingQuote ( UniCodePoint openQuote )
+{
+ UniCodePoint closeQuote;
+
+ switch ( openQuote ) {
+
+ case UCP(0x0022) : closeQuote = UCP(0x0022); // ! U+0022 is both opening and closing.
+ break;
+ // *** [2674672] Discontinue to interpret square brackets
+ // *** as Asian quotes in XMPUtils::SeparateArrayItems(..))
+ // *** case UCP(0x005B) : closeQuote = UCP(0x005D);
+ // *** break;
+ case UCP(0x00AB) : closeQuote = UCP(0x00BB); // ! U+00AB and U+00BB are reversible.
+ break;
+ case UCP(0x00BB) : closeQuote = UCP(0x00AB);
+ break;
+ case UCP(0x2015) : closeQuote = UCP(0x2015); // ! U+2015 is both opening and closing.
+ break;
+ case UCP(0x2018) : closeQuote = UCP(0x2019);
+ break;
+ case UCP(0x201A) : closeQuote = UCP(0x201B);
+ break;
+ case UCP(0x201C) : closeQuote = UCP(0x201D);
+ break;
+ case UCP(0x201E) : closeQuote = UCP(0x201F);
+ break;
+ case UCP(0x2039) : closeQuote = UCP(0x203A); // ! U+2039 and U+203A are reversible.
+ break;
+ case UCP(0x203A) : closeQuote = UCP(0x2039);
+ break;
+ case UCP(0x3008) : closeQuote = UCP(0x3009);
+ break;
+ case UCP(0x300A) : closeQuote = UCP(0x300B);
+ break;
+ case UCP(0x300C) : closeQuote = UCP(0x300D);
+ break;
+ case UCP(0x300E) : closeQuote = UCP(0x300F);
+ break;
+ case UCP(0x301D) : closeQuote = UCP(0x301F); // ! U+301E also closes U+301D.
+ break;
+ default : closeQuote = 0;
+ break;
+
+ }
+
+ return closeQuote;
+
+} // GetClosingQuote
+
+
+// -------------------------------------------------------------------------------------------------
+// CodePointToUTF8
+// ---------------
+
+static void
+CodePointToUTF8 ( UniCodePoint uniChar, XMP_VarString & utf8Str )
+{
+ size_t i, byteCount;
+ XMP_Uns8 buffer [8];
+ UniCodePoint cpTemp;
+
+ if ( uniChar <= 0x7F ) {
+
+ i = 7;
+ byteCount = 1;
+ buffer[7] = char(uniChar);
+
+ } else {
+
+ // ---------------------------------------------------------------------------------------
+ // Copy the data bits from the low order end to the high order end, include the 0x80 mask.
+
+ i = 8;
+ cpTemp = uniChar;
+ while ( cpTemp != 0 ) {
+ -- i; // Exit with i pointing to the last byte stored.
+ buffer[i] = UnsByte(0x80) | (UnsByte(cpTemp) & 0x3F);
+ cpTemp = cpTemp >> 6;
+ }
+ byteCount = 8 - i; // The total number of bytes needed.
+ XMP_Assert ( (2 <= byteCount) && (byteCount <= 6) );
+
+ // -------------------------------------------------------------------------------------
+ // Make sure the high order byte can hold the byte count mask, compute and set the mask.
+
+ size_t bitCount = 0; // The number of data bits in the first byte.
+ for ( cpTemp = (buffer[i] & UnsByte(0x3F)); cpTemp != 0; cpTemp = cpTemp >> 1 ) bitCount += 1;
+ if ( bitCount > (8 - (byteCount + 1)) ) byteCount += 1;
+
+ i = 8 - byteCount; // First byte index and mask shift count.
+ XMP_Assert ( (0 <= i) && (i <= 6) );
+ buffer[i] |= (UnsByte(0xFF) << i) & UnsByte(0xFF); // AUDIT: Safe, i is between 0 and 6.
+
+ }
+
+ utf8Str.assign ( (char*)(&buffer[i]), byteCount );
+
+} // CodePointToUTF8
+
+
+// -------------------------------------------------------------------------------------------------
+// ApplyQuotes
+// -----------
+
+static void
+ApplyQuotes ( XMP_VarString * item, UniCodePoint openQuote, UniCodePoint closeQuote, bool allowCommas )
+{
+ bool prevSpace = false;
+ size_t charOffset, charLen;
+ UniCharKind charKind;
+ UniCodePoint uniChar;
+
+ // -----------------------------------------------------------------------------------------
+ // See if there are any separators in the value. Stop at the first occurrance. This is a bit
+ // tricky in order to make typical typing work conveniently. The purpose of applying quotes
+ // is to preserve the values when splitting them back apart. That is CatenateContainerItems
+ // and SeparateContainerItems must round trip properly. For the most part we only look for
+ // separators here. Internal quotes, as in -- Irving "Bud" Jones -- won't cause problems in
+ // the separation. An initial quote will though, it will make the value look quoted.
+
+ charOffset = 0;
+ ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar );
+
+ if ( charKind != UCK_quote ) {
+
+ for ( charOffset = 0; size_t(charOffset) < item->size(); charOffset += charLen ) {
+
+ ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar );
+
+ if ( charKind == UCK_space ) {
+ if ( prevSpace ) break; // Multiple spaces are a separator.
+ prevSpace = true;
+ } else {
+ prevSpace = false;
+ if ( (charKind == UCK_semicolon) || (charKind == UCK_control) ) break;
+ if ( (charKind == UCK_comma) && (! allowCommas) ) break;
+ }
+
+ }
+
+ }
+
+ if ( size_t(charOffset) < item->size() ) {
+
+ // --------------------------------------------------------------------------------------
+ // Create a quoted copy, doubling any internal quotes that match the outer ones. Internal
+ // quotes did not stop the "needs quoting" search, but they do need doubling. So we have
+ // to rescan the front of the string for quotes. Handle the special case of U+301D being
+ // closed by either U+301E or U+301F.
+
+ XMP_VarString newItem;
+ size_t splitPoint;
+
+ for ( splitPoint = 0; splitPoint <= charOffset; ++splitPoint ) {
+ ClassifyCharacter ( item->c_str(), splitPoint, &charKind, &charLen, &uniChar );
+ if ( charKind == UCK_quote ) break;
+ }
+
+ CodePointToUTF8 ( openQuote, newItem );
+ newItem.append ( *item, 0, splitPoint ); // Copy the leading "normal" portion.
+
+ for ( charOffset = splitPoint; size_t(charOffset) < item->size(); charOffset += charLen ) {
+ ClassifyCharacter ( item->c_str(), charOffset, &charKind, &charLen, &uniChar );
+ newItem.append ( *item, charOffset, charLen );
+ if ( (charKind == UCK_quote) && IsSurroundingQuote ( uniChar, openQuote, closeQuote ) ) {
+ newItem.append ( *item, charOffset, charLen );
+ }
+ }
+
+ XMP_VarString closeStr;
+ CodePointToUTF8 ( closeQuote, closeStr );
+ newItem.append ( closeStr );
+
+ *item = newItem;
+
+ }
+
+} // ApplyQuotes
+
+
+// -------------------------------------------------------------------------------------------------
+// IsInternalProperty
+// ------------------
+
+// *** Need static checks of the schema prefixes!
+
+static const char * kExternalxmpDM[] =
+ { "xmpDM:album",
+ "xmpDM:altTapeName",
+ "xmpDM:altTimecode",
+ "xmpDM:artist",
+ "xmpDM:cameraAngle",
+ "xmpDM:cameraLabel",
+ "xmpDM:cameraModel",
+ "xmpDM:cameraMove",
+ "xmpDM:client",
+ "xmpDM:comment",
+ "xmpDM:composer",
+ "xmpDM:director",
+ "xmpDM:directorPhotography",
+ "xmpDM:engineer",
+ "xmpDM:genre",
+ "xmpDM:good",
+ "xmpDM:instrument",
+ "xmpDM:logComment",
+ "xmpDM:projectName",
+ "xmpDM:releaseDate",
+ "xmpDM:scene",
+ "xmpDM:shotDate",
+ "xmpDM:shotDay",
+ "xmpDM:shotLocation",
+ "xmpDM:shotName",
+ "xmpDM:shotNumber",
+ "xmpDM:shotSize",
+ "xmpDM:speakerPlacement",
+ "xmpDM:takeNumber",
+ "xmpDM:tapeName",
+ "xmpDM:trackNumber",
+ "xmpDM:videoAlphaMode",
+ "xmpDM:videoAlphaPremultipleColor",
+ 0 }; // ! Must have zero sentinel!
+
+typedef const char ** CharStarIterator; // Used for binary search of kExternalxmpDM;
+static const char ** kLastExternalxmpDM = 0; // Set on first use.
+static int CharStarLess (const char * left, const char * right )
+ { return (strcmp ( left, right ) < 0); }
+
+#define IsExternalProperty(s,p) (! IsInternalProperty ( s, p ))
+
+static bool
+IsInternalProperty ( const XMP_VarString & schema, const XMP_VarString & prop )
+{
+ bool isInternal = false;
+
+ if ( schema == kXMP_NS_DC ) {
+
+ if ( (prop == "dc:format") ||
+ (prop == "dc:language") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_XMP ) {
+
+ if ( (prop == "xmp:BaseURL") ||
+ (prop == "xmp:CreatorTool") ||
+ (prop == "xmp:Format") ||
+ (prop == "xmp:Locale") ||
+ (prop == "xmp:MetadataDate") ||
+ (prop == "xmp:ModifyDate") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_PDF ) {
+
+ if ( (prop == "pdf:BaseURL") ||
+ (prop == "pdf:Creator") ||
+ (prop == "pdf:ModDate") ||
+ (prop == "pdf:PDFVersion") ||
+ (prop == "pdf:Producer") ) {
+ isInternal = true;
+ }
+
+ } else if ( schema == kXMP_NS_TIFF ) {
+
+ isInternal = true; // ! The TIFF properties are internal by default.
+ if ( (prop == "tiff:ImageDescription") || // ! ImageDescription, Artist, and Copyright are aliased.
+ (prop == "tiff:Artist") ||
+ (prop == "tiff:Copyright") ) {
+ isInternal = false;
+ }
+
+ } else if ( schema == kXMP_NS_EXIF ) {
+
+ isInternal = true; // ! The EXIF properties are internal by default.
+ if ( prop == "exif:UserComment" ) isInternal = false;
+
+ } else if ( schema == kXMP_NS_EXIF_Aux ) {
+
+ isInternal = true; // ! The EXIF Aux properties are internal by default.
+
+ } else if ( schema == kXMP_NS_Photoshop ) {
+
+ if ( (prop == "photoshop:ICCProfile") ||
+ (prop == "photoshop:TextLayers") ) isInternal = true;
+
+ } else if ( schema == kXMP_NS_CameraRaw ) {
+
+ isInternal = true; // All of crs: is internal, they are processing settings.
+
+ } else if ( schema == kXMP_NS_DM ) {
+
+ // ! Most of the xmpDM schema is internal, and unknown properties default to internal.
+ if ( kLastExternalxmpDM == 0 ) {
+ for ( kLastExternalxmpDM = &kExternalxmpDM[0]; *kLastExternalxmpDM != 0; ++kLastExternalxmpDM ) {}
+ }
+ isInternal = (! std::binary_search ( &kExternalxmpDM[0], kLastExternalxmpDM, prop.c_str(), CharStarLess ));
+
+ } else if ( schema == kXMP_NS_Script ) {
+
+ isInternal = true; // ! Most of the xmpScript schema is internal, and unknown properties default to internal.
+ if ( (prop == "xmpScript:action") || (prop == "xmpScript:character") || (prop == "xmpScript:dialog") ||
+ (prop == "xmpScript:sceneSetting") || (prop == "xmpScript:sceneTimeOfDay") ) {
+ isInternal = false;
+ }
+
+ } else if ( schema == kXMP_NS_BWF ) {
+
+ if ( prop == "bext:version" ) isInternal = true;
+
+ } else if ( schema == kXMP_NS_AdobeStockPhoto ) {
+
+ isInternal = true; // ! The bmsp schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_MM ) {
+
+ isInternal = true; // ! The xmpMM schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Text ) {
+
+ isInternal = true; // ! The xmpT schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_PagedFile ) {
+
+ isInternal = true; // ! The xmpTPg schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Graphics ) {
+
+ isInternal = true; // ! The xmpG schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Image ) {
+
+ isInternal = true; // ! The xmpGImg schema has only internal properties.
+
+ } else if ( schema == kXMP_NS_XMP_Font ) {
+
+ isInternal = true; // ! The stFNT schema has only internal properties.
+
+ }
+
+ return isInternal;
+
+} // IsInternalProperty
+
+
+// -------------------------------------------------------------------------------------------------
+// RemoveSchemaChildren
+// --------------------
+
+static void
+RemoveSchemaChildren ( XMP_NodePtrPos schemaPos, bool doAll )
+{
+ XMP_Node * schemaNode = *schemaPos;
+ XMP_Assert ( XMP_NodeIsSchema ( schemaNode->options ) );
+
+ // ! Iterate backwards to reduce shuffling as children are erased and to simplify the logic for
+ // ! denoting the current child. (Erasing child n makes the old n+1 now be n.)
+
+ size_t propCount = schemaNode->children.size();
+ XMP_NodePtrPos beginPos = schemaNode->children.begin();
+
+ for ( size_t propNum = propCount-1, propLim = (size_t)(-1); propNum != propLim; --propNum ) {
+ XMP_NodePtrPos currProp = beginPos + propNum;
+ if ( doAll || IsExternalProperty ( schemaNode->name, (*currProp)->name ) ) {
+ delete *currProp; // ! Both delete the node and erase the pointer from the parent.
+ schemaNode->children.erase ( currProp );
+ }
+ }
+
+ if ( schemaNode->children.empty() ) {
+ XMP_Node * tree = schemaNode->parent;
+ tree->children.erase ( schemaPos );
+ delete schemaNode;
+ }
+
+} // RemoveSchemaChildren
+
+
+// -------------------------------------------------------------------------------------------------
+// ItemValuesMatch
+// ---------------
+//
+// Does the value comparisons for array merging as part of XMPUtils::AppendProperties.
+
+static bool
+ItemValuesMatch ( const XMP_Node * leftNode, const XMP_Node * rightNode )
+{
+ const XMP_OptionBits leftForm = leftNode->options & kXMP_PropCompositeMask;
+ const XMP_OptionBits rightForm = leftNode->options & kXMP_PropCompositeMask;
+
+ if ( leftForm != rightForm ) return false;
+
+ if ( leftForm == 0 ) {
+
+ // Simple nodes, check the values and xml:lang qualifiers.
+
+ if ( leftNode->value != rightNode->value ) return false;
+ if ( (leftNode->options & kXMP_PropHasLang) != (rightNode->options & kXMP_PropHasLang) ) return false;
+ if ( leftNode->options & kXMP_PropHasLang ) {
+ if ( leftNode->qualifiers[0]->value != rightNode->qualifiers[0]->value ) return false;
+ }
+
+ } else if ( leftForm == kXMP_PropValueIsStruct ) {
+
+ // Struct nodes, see if all fields match, ignoring order.
+
+ if ( leftNode->children.size() != rightNode->children.size() ) return false;
+
+ for ( size_t leftNum = 0, leftLim = leftNode->children.size(); leftNum != leftLim; ++leftNum ) {
+ const XMP_Node * leftField = leftNode->children[leftNum];
+ const XMP_Node * rightField = FindConstChild ( rightNode, leftField->name.c_str() );
+ if ( (rightField == 0) || (! ItemValuesMatch ( leftField, rightField )) ) return false;
+ }
+
+ } else {
+
+ // Array nodes, see if the "leftNode" values are present in the "rightNode", ignoring order, duplicates,
+ // and extra values in the rightNode-> The rightNode is the destination for AppendProperties.
+
+ XMP_Assert ( leftForm & kXMP_PropValueIsArray );
+
+ for ( size_t leftNum = 0, leftLim = leftNode->children.size(); leftNum != leftLim; ++leftNum ) {
+
+ const XMP_Node * leftItem = leftNode->children[leftNum];
+
+ size_t rightNum, rightLim;
+ for ( rightNum = 0, rightLim = rightNode->children.size(); rightNum != rightLim; ++rightNum ) {
+ const XMP_Node * rightItem = rightNode->children[rightNum];
+ if ( ItemValuesMatch ( leftItem, rightItem ) ) break;
+ }
+ if ( rightNum == rightLim ) return false;
+
+ }
+
+ }
+
+ return true; // All of the checks passed.
+
+} // ItemValuesMatch
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendSubtree
+// -------------
+//
+// The main implementation of XMPUtils::AppendProperties. See the description in TXMPMeta.hpp.
+
+static void
+AppendSubtree ( const XMP_Node * sourceNode, XMP_Node * destParent,
+ const bool mergeCompound, const bool replaceOld, const bool deleteEmpty )
+{
+ XMP_NodePtrPos destPos;
+ XMP_Node * destNode = FindChildNode ( destParent, sourceNode->name.c_str(), kXMP_ExistingOnly, &destPos );
+
+ bool valueIsEmpty = false;
+ if ( XMP_PropIsSimple ( sourceNode->options ) ) {
+ valueIsEmpty = sourceNode->value.empty();
+ } else {
+ valueIsEmpty = sourceNode->children.empty();
+ }
+
+ if ( valueIsEmpty ) {
+ if ( deleteEmpty && (destNode != 0) ) {
+ delete ( destNode );
+ destParent->children.erase ( destPos );
+ }
+ return; // ! Done, empty values are either ignored or cause deletions.
+ }
+
+ if ( destNode == 0 ) {
+ // The one easy case, the destination does not exist.
+ destNode = CloneSubtree ( sourceNode, destParent, true /* skipEmpty */ );
+ XMP_Assert ( (destNode == 0) || (! destNode->value.empty()) || (! destNode->children.empty()) );
+ return;
+ }
+
+ // If we get here we're going to modify an existing property, either replacing or merging.
+
+ XMP_Assert ( (! valueIsEmpty) && (destNode != 0) );
+
+ XMP_OptionBits sourceForm = sourceNode->options & kXMP_PropCompositeMask;
+ XMP_OptionBits destForm = destNode->options & kXMP_PropCompositeMask;
+
+ bool replaceThis = replaceOld; // ! Don't modify replaceOld, it gets passed to inner calls.
+ if ( mergeCompound && (! XMP_PropIsSimple ( sourceForm )) ) replaceThis = false;
+
+ if ( replaceThis ) {
+
+ destNode->value = sourceNode->value; // *** Should use SetNode.
+ destNode->options = sourceNode->options;
+ destNode->RemoveChildren();
+ destNode->RemoveQualifiers();
+ CloneOffspring ( sourceNode, destNode, true /* skipEmpty */ );
+
+ if ( (! XMP_PropIsSimple ( destNode->options )) && destNode->children.empty() ) {
+ // Don't keep an empty array or struct. The source might be implicitly empty due to
+ // all children being empty. In this case CloneOffspring should skip them.
+ DeleteSubtree ( destPos );
+ }
+
+ return;
+
+ }
+
+ // From here on are cases for merging arrays or structs.
+
+ if ( XMP_PropIsSimple ( sourceForm ) || (sourceForm != destForm) ) return;
+
+ if ( sourceForm == kXMP_PropValueIsStruct ) {
+
+ // To merge a struct process the fields recursively. E.g. add simple missing fields. The
+ // recursive call to AppendSubtree will handle deletion for fields with empty values.
+
+ for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim && destNode!= NULL; ++sourceNum ) {
+ const XMP_Node * sourceField = sourceNode->children[sourceNum];
+ AppendSubtree ( sourceField, destNode, mergeCompound, replaceOld, deleteEmpty );
+ if ( deleteEmpty && destNode->children.empty() ) {
+ delete ( destNode );
+ destParent->children.erase ( destPos );
+ }
+ }
+
+ } else if ( sourceForm & kXMP_PropArrayIsAltText ) {
+
+ // Merge AltText arrays by the xml:lang qualifiers. Make sure x-default is first. Make a
+ // special check for deletion of empty values. Meaningful in AltText arrays because the
+ // xml:lang qualifier provides unambiguous source/dest correspondence.
+
+ XMP_Assert ( mergeCompound );
+
+ for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim && destNode!= NULL; ++sourceNum ) {
+
+ const XMP_Node * sourceItem = sourceNode->children[sourceNum];
+ if ( sourceItem->qualifiers.empty() || (sourceItem->qualifiers[0]->name != "xml:lang") ) continue;
+
+ XMP_Index destIndex = LookupLangItem ( destNode, sourceItem->qualifiers[0]->value );
+
+ if ( sourceItem->value.empty() ) {
+
+ if ( deleteEmpty && (destIndex != -1) ) {
+ delete ( destNode->children[destIndex] );
+ destNode->children.erase ( destNode->children.begin() + destIndex );
+ if ( destNode->children.empty() ) {
+ delete ( destNode );
+ destParent->children.erase ( destPos );
+ }
+ }
+
+ } else {
+
+ if ( destIndex != -1 ) {
+
+ // The source and dest arrays both have this language item.
+
+ if ( replaceOld ) { // ! Yes, check replaceOld not replaceThis!
+ destNode->children[destIndex]->value = sourceItem->value;
+ }
+
+ } else {
+
+ // The dest array does not have this language item, add it.
+
+ if ( (sourceItem->qualifiers[0]->value != "x-default") || destNode->children.empty() ) {
+ // Typical case, empty dest array or not "x-default". Non-empty should always have "x-default".
+ CloneSubtree ( sourceItem, destNode, true /* skipEmpty */ );
+ } else {
+ // Edge case, non-empty dest array had no "x-default", insert that at the beginning.
+ XMP_Node * destItem = new XMP_Node ( destNode, sourceItem->name, sourceItem->value, sourceItem->options );
+ CloneOffspring ( sourceItem, destItem, true /* skipEmpty */ );
+ destNode->children.insert ( destNode->children.begin(), destItem );
+ }
+
+ }
+
+ }
+
+ }
+
+ } else if ( sourceForm & kXMP_PropValueIsArray ) {
+
+ // Merge other arrays by item values. Don't worry about order or duplicates. Source
+ // items with empty values do not cause deletion, that conflicts horribly with merging.
+
+ for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) {
+ const XMP_Node * sourceItem = sourceNode->children[sourceNum];
+
+ size_t destNum, destLim;
+ for ( destNum = 0, destLim = destNode->children.size(); destNum != destLim; ++destNum ) {
+ const XMP_Node * destItem = destNode->children[destNum];
+ if ( ItemValuesMatch ( sourceItem, destItem ) ) break;
+ }
+ if ( destNum == destLim ) CloneSubtree ( sourceItem, destNode, true /* skipEmpty */ );
+
+ }
+
+ }
+
+} // AppendSubtree
+
+
+// =================================================================================================
+// Class Static Functions
+// ======================
+
+// -------------------------------------------------------------------------------------------------
+// CatenateArrayItems
+// ------------------
+
+/* class static */ void
+XMPUtils::CatenateArrayItems ( const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_VarString * catedStr )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // ! Enforced by wrapper.
+ XMP_Assert ( (separator != 0) && (quotes != 0) && (catedStr != 0) ); // ! Enforced by wrapper.
+
+ size_t strLen, strPos, charLen;
+ UniCharKind charKind;
+ UniCodePoint currUCP, openQuote, closeQuote;
+
+ const bool allowCommas = ((options & kXMPUtil_AllowCommas) != 0);
+
+ const XMP_Node * arrayNode = 0; // ! Move up to avoid gcc complaints.
+ XMP_OptionBits arrayForm = 0;
+ const XMP_Node * currItem = 0;
+
+ // Make sure the separator is OK. It must be one semicolon surrounded by zero or more spaces.
+ // Any of the recognized semicolons or spaces are allowed.
+
+ strPos = 0;
+ strLen = strlen ( separator );
+ bool haveSemicolon = false;
+
+ while ( strPos < strLen ) {
+ ClassifyCharacter ( separator, strPos, &charKind, &charLen, &currUCP );
+ strPos += charLen;
+ if ( charKind == UCK_semicolon ) {
+ if ( haveSemicolon ) XMP_Throw ( "Separator can have only one semicolon", kXMPErr_BadParam );
+ haveSemicolon = true;
+ } else if ( charKind != UCK_space ) {
+ XMP_Throw ( "Separator can have only spaces and one semicolon", kXMPErr_BadParam );
+ }
+ };
+ if ( ! haveSemicolon ) XMP_Throw ( "Separator must have one semicolon", kXMPErr_BadParam );
+
+ // Make sure the open and close quotes are a legitimate pair.
+
+ strLen = strlen ( quotes );
+ ClassifyCharacter ( quotes, 0, &charKind, &charLen, &openQuote );
+ if ( charKind != UCK_quote ) XMP_Throw ( "Invalid quoting character", kXMPErr_BadParam );
+
+ if ( charLen == strLen ) {
+ closeQuote = openQuote;
+ } else {
+ strPos = charLen;
+ ClassifyCharacter ( quotes, strPos, &charKind, &charLen, &closeQuote );
+ if ( charKind != UCK_quote ) XMP_Throw ( "Invalid quoting character", kXMPErr_BadParam );
+ if ( (strPos + charLen) != strLen ) XMP_Throw ( "Quoting string too long", kXMPErr_BadParam );
+ }
+ if ( closeQuote != GetClosingQuote ( openQuote ) ) XMP_Throw ( "Mismatched quote pair", kXMPErr_BadParam );
+
+ // Return an empty result if the array does not exist, hurl if it isn't the right form.
+
+ catedStr->erase();
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+
+ arrayNode = FindConstNode ( &xmpObj.tree, arrayPath );
+ if ( arrayNode == 0 ) return;
+
+ arrayForm = arrayNode->options & kXMP_PropCompositeMask;
+ if ( (! (arrayForm & kXMP_PropValueIsArray)) || (arrayForm & kXMP_PropArrayIsAlternate) ) {
+ XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadParam );
+ }
+ if ( arrayNode->children.empty() ) return;
+
+ // Build the result, quoting the array items, adding separators. Hurl if any item isn't simple.
+ // Start the result with the first value, then add the rest with a preceeding separator.
+
+ currItem = arrayNode->children[0];
+
+ if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam );
+ *catedStr = currItem->value;
+ ApplyQuotes ( catedStr, openQuote, closeQuote, allowCommas );
+
+ for ( size_t itemNum = 1, itemLim = arrayNode->children.size(); itemNum != itemLim; ++itemNum ) {
+ const XMP_Node * item = arrayNode->children[itemNum];
+ if ( (item->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam );
+ XMP_VarString tempStr ( item->value );
+ ApplyQuotes ( &tempStr, openQuote, closeQuote, allowCommas );
+ *catedStr += separator;
+ *catedStr += tempStr;
+ }
+
+} // CatenateArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// SeparateArrayItems
+// ------------------
+
+/* class static */ void
+XMPUtils::SeparateArrayItems ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr )
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (catedStr != 0) ); // ! Enforced by wrapper.
+
+ XMP_VarString itemValue;
+ size_t itemStart, itemEnd;
+ size_t nextSize, charSize = 0; // Avoid VS uninit var warnings.
+ UniCharKind nextKind, charKind = UCK_normal;
+ UniCodePoint nextChar, uniChar = 0;
+
+ // Extract "special" option bits, verify and normalize the others.
+
+ bool preserveCommas = false;
+ if ( options & kXMPUtil_AllowCommas ) {
+ preserveCommas = true;
+ options ^= kXMPUtil_AllowCommas;
+ }
+
+ options = VerifySetOptions ( options, 0 ); // Keep a zero value, has special meaning below.
+ if ( options & ~kXMP_PropArrayFormMask ) XMP_Throw ( "Options can only provide array form", kXMPErr_BadOptions );
+
+ // Find the array node, make sure it is OK. Move the current children aside, to be readded later if kept.
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ XMP_Node * arrayNode = FindNode ( &xmpObj->tree, arrayPath, kXMP_ExistingOnly );
+
+ if ( arrayNode != 0 ) {
+ // The array exists, make sure the form is compatible. Zero arrayForm means take what exists.
+ XMP_OptionBits arrayForm = arrayNode->options & kXMP_PropArrayFormMask;
+ if ( (arrayForm == 0) || (arrayForm & kXMP_PropArrayIsAlternate) ) {
+ XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadXPath );
+ }
+ if ( (options != 0) && (options != arrayForm) ) XMP_Throw ( "Mismatch of specified and existing array form", kXMPErr_BadXPath ); // *** Right error?
+ } else {
+ // The array does not exist, try to create it.
+ arrayNode = FindNode ( &xmpObj->tree, arrayPath, kXMP_CreateNodes, (options | kXMP_PropValueIsArray) );
+ if ( arrayNode == 0 ) XMP_Throw ( "Failed to create named array", kXMPErr_BadXPath );
+ }
+
+ XMP_NodeOffspring oldChildren ( arrayNode->children );
+ size_t oldChildCount = oldChildren.size();
+ arrayNode->children.clear();
+
+ // Extract the item values one at a time, until the whole input string is done. Be very careful
+ // in the extraction about the string positions. They are essentially byte pointers, while the
+ // contents are UTF-8. Adding or subtracting 1 does not necessarily move 1 Unicode character!
+
+ size_t endPos = strlen ( catedStr );
+
+ itemEnd = 0;
+ while ( itemEnd < endPos ) {
+
+ // Skip any leading spaces and separation characters. Always skip commas here. They can be
+ // kept when within a value, but not when alone between values.
+
+ for ( itemStart = itemEnd; itemStart < endPos; itemStart += charSize ) {
+ ClassifyCharacter ( catedStr, itemStart, &charKind, &charSize, &uniChar );
+ if ( (charKind == UCK_normal) || (charKind == UCK_quote) ) break;
+ }
+ if ( itemStart >= endPos ) break;
+
+ if ( charKind != UCK_quote ) {
+
+ // This is not a quoted value. Scan for the end, create an array item from the substring.
+
+ for ( itemEnd = itemStart; itemEnd < endPos; itemEnd += charSize ) {
+
+ ClassifyCharacter ( catedStr, itemEnd, &charKind, &charSize, &uniChar );
+
+ if ( (charKind == UCK_normal) || (charKind == UCK_quote) ) continue;
+ if ( (charKind == UCK_comma) && preserveCommas ) continue;
+ if ( charKind != UCK_space ) break;
+
+ if ( (itemEnd + charSize) >= endPos ) break; // Anything left?
+ ClassifyCharacter ( catedStr, (itemEnd+charSize), &nextKind, &nextSize, &nextChar );
+ if ( (nextKind == UCK_normal) || (nextKind == UCK_quote) ) continue;
+ if ( (nextKind == UCK_comma) && preserveCommas ) continue;
+ break; // Have multiple spaces, or a space followed by a separator.
+
+ }
+
+ itemValue.assign ( catedStr, itemStart, (itemEnd - itemStart) );
+
+ } else {
+
+ // Accumulate quoted values into a local string, undoubling internal quotes that
+ // match the surrounding quotes. Do not undouble "unmatching" quotes.
+
+ UniCodePoint openQuote = uniChar;
+ UniCodePoint closeQuote = GetClosingQuote ( openQuote );
+
+ itemStart += charSize; // Skip the opening quote;
+ itemValue.erase();
+
+ for ( itemEnd = itemStart; itemEnd < endPos; itemEnd += charSize ) {
+
+ ClassifyCharacter ( catedStr, itemEnd, &charKind, &charSize, &uniChar );
+
+ if ( (charKind != UCK_quote) || (! IsSurroundingQuote ( uniChar, openQuote, closeQuote)) ) {
+
+ // This is not a matching quote, just append it to the item value.
+ itemValue.append ( catedStr, itemEnd, charSize );
+
+ } else {
+
+ // This is a "matching" quote. Is it doubled, or the final closing quote? Tolerate
+ // various edge cases like undoubled opening (non-closing) quotes, or end of input.
+
+ if ( (itemEnd + charSize) < endPos ) {
+ ClassifyCharacter ( catedStr, itemEnd+charSize, &nextKind, &nextSize, &nextChar );
+ } else {
+ nextKind = UCK_semicolon; nextSize = 0; nextChar = 0x3B;
+ }
+
+ if ( uniChar == nextChar ) {
+ // This is doubled, copy it and skip the double.
+ itemValue.append ( catedStr, itemEnd, charSize );
+ itemEnd += nextSize; // Loop will add in charSize.
+ } else if ( ! IsClosingingQuote ( uniChar, openQuote, closeQuote ) ) {
+ // This is an undoubled, non-closing quote, copy it.
+ itemValue.append ( catedStr, itemEnd, charSize );
+ } else {
+ // This is an undoubled closing quote, skip it and exit the loop.
+ itemEnd += charSize;
+ break;
+ }
+
+ }
+
+ } // Loop to accumulate the quoted value.
+
+ }
+
+ // Add the separated item to the array. Keep a matching old value in case it had separators.
+
+ size_t oldChild;
+ for ( oldChild = 0; oldChild < oldChildCount; ++oldChild ) {
+ if ( (oldChildren[oldChild] != 0) && (itemValue == oldChildren[oldChild]->value) ) break;
+ }
+
+ XMP_Node * newItem = 0;
+ if ( oldChild == oldChildCount ) {
+ newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue.c_str(), 0 );
+ } else {
+ newItem = oldChildren[oldChild];
+ oldChildren[oldChild] = 0; // ! Don't match again, let duplicates be seen.
+ }
+ arrayNode->children.push_back ( newItem );
+
+ } // Loop through all of the returned items.
+
+ // Delete any of the old children that were not kept.
+ for ( size_t i = 0; i < oldChildCount; ++i ) {
+ if ( oldChildren[i] != 0 ) delete oldChildren[i];
+ }
+
+} // SeparateArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// ApplyTemplate
+// -------------
+
+/* class static */ void
+XMPUtils::ApplyTemplate ( XMPMeta * workingXMP,
+ const XMPMeta & templateXMP,
+ XMP_OptionBits actions )
+{
+ bool doClear = XMP_OptionIsSet ( actions, kXMPTemplate_ClearUnnamedProperties );
+ bool doAdd = XMP_OptionIsSet ( actions, kXMPTemplate_AddNewProperties );
+ bool doReplace = XMP_OptionIsSet ( actions, kXMPTemplate_ReplaceExistingProperties );
+
+ bool deleteEmpty = XMP_OptionIsSet ( actions, kXMPTemplate_ReplaceWithDeleteEmpty );
+ doReplace |= deleteEmpty; // Delete-empty implies Replace.
+ deleteEmpty &= (! doClear); // Clear implies not delete-empty, but keep the implicit Replace.
+
+ bool doAll = XMP_OptionIsSet ( actions, kXMPTemplate_IncludeInternalProperties );
+
+ // ! In several places we do loops backwards so that deletions do not perturb the remaining indices.
+ // ! These loops use ordinals (size .. 1), we must use a zero based index inside the loop.
+
+ if ( doClear ) {
+
+ // Visit the top level working properties, delete if not in the template.
+
+ for ( size_t schemaOrdinal = workingXMP->tree.children.size(); schemaOrdinal > 0; --schemaOrdinal ) {
+
+ size_t schemaNum = schemaOrdinal-1; // ! Convert ordinal to index!
+ XMP_Node * workingSchema = workingXMP->tree.children[schemaNum];
+ const XMP_Node * templateSchema = FindConstSchema ( &templateXMP.tree, workingSchema->name.c_str() );
+
+ if ( templateSchema == 0 ) {
+
+ // The schema is not in the template, delete all properties or just all external ones.
+
+ if ( doAll ) {
+
+ workingSchema->RemoveChildren(); // Remove the properties here, delete the schema below.
+
+ } else {
+
+ for ( size_t propOrdinal = workingSchema->children.size(); propOrdinal > 0; --propOrdinal ) {
+ size_t propNum = propOrdinal-1; // ! Convert ordinal to index!
+ XMP_Node * workingProp = workingSchema->children[propNum];
+ if ( IsExternalProperty ( workingSchema->name, workingProp->name ) ) {
+ delete ( workingProp );
+ workingSchema->children.erase ( workingSchema->children.begin() + propNum );
+ }
+ }
+
+ }
+
+ } else {
+
+ // Check each of the working XMP's properties to see if it is in the template.
+
+ for ( size_t propOrdinal = workingSchema->children.size(); propOrdinal > 0; --propOrdinal ) {
+ size_t propNum = propOrdinal-1; // ! Convert ordinal to index!
+ XMP_Node * workingProp = workingSchema->children[propNum];
+ if ( (doAll || IsExternalProperty ( workingSchema->name, workingProp->name )) &&
+ (FindConstChild ( templateSchema, workingProp->name.c_str() ) == 0) ) {
+ delete ( workingProp );
+ workingSchema->children.erase ( workingSchema->children.begin() + propNum );
+ }
+ }
+
+ }
+
+ if ( workingSchema->children.empty() ) {
+ delete ( workingSchema );
+ workingXMP->tree.children.erase ( workingXMP->tree.children.begin() + schemaNum );
+ }
+
+ }
+
+ }
+
+ if ( doAdd | doReplace ) {
+
+ for ( size_t schemaNum = 0, schemaLim = templateXMP.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
+
+ const XMP_Node * templateSchema = templateXMP.tree.children[schemaNum];
+
+ // Make sure we have an output schema node, then process the top level template properties.
+
+ XMP_NodePtrPos workingSchemaPos;
+ XMP_Node * workingSchema = FindSchemaNode ( &workingXMP->tree, templateSchema->name.c_str(),
+ kXMP_ExistingOnly, &workingSchemaPos );
+ if ( workingSchema == 0 ) {
+ workingSchema = new XMP_Node ( &workingXMP->tree, templateSchema->name, templateSchema->value, kXMP_SchemaNode );
+ workingXMP->tree.children.push_back ( workingSchema );
+ workingSchemaPos = workingXMP->tree.children.end() - 1;
+ }
+
+ for ( size_t propNum = 0, propLim = templateSchema->children.size(); propNum < propLim; ++propNum ) {
+ const XMP_Node * templateProp = templateSchema->children[propNum];
+ if ( doAll || IsExternalProperty ( templateSchema->name, templateProp->name ) ) {
+ AppendSubtree ( templateProp, workingSchema, doAdd, doReplace, deleteEmpty );
+ }
+ }
+
+ if ( workingSchema->children.empty() ) {
+ delete ( workingSchema );
+ workingXMP->tree.children.erase ( workingSchemaPos );
+ }
+
+ }
+
+ }
+
+} // ApplyTemplate
+
+
+// -------------------------------------------------------------------------------------------------
+// RemoveProperties
+// ----------------
+
+/* class static */ void
+XMPUtils::RemoveProperties ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options )
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // ! Enforced by wrapper.
+
+ const bool doAll = XMP_TestOption (options, kXMPUtil_DoAllProperties );
+ const bool includeAliases = XMP_TestOption ( options, kXMPUtil_IncludeAliases );
+
+ if ( *propName != 0 ) {
+
+ // Remove just the one indicated property. This might be an alias, the named schema might
+ // not actually exist. So don't lookup the schema node.
+
+ if ( *schemaNS == 0 ) XMP_Throw ( "Property name requires schema namespace", kXMPErr_BadParam );
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_NodePtrPos propPos;
+ XMP_Node * propNode = FindNode ( &(xmpObj->tree), expPath, kXMP_ExistingOnly, kXMP_NoOptions, &propPos );
+ if ( propNode != 0 ) {
+ if ( doAll || IsExternalProperty ( expPath[kSchemaStep].step, expPath[kRootPropStep].step ) ) {
+ XMP_Node * parent = propNode->parent; // *** Should have XMP_Node::RemoveChild(pos).
+ delete propNode; // ! Both delete the node and erase the pointer from the parent.
+ parent->children.erase ( propPos );
+ DeleteEmptySchema ( parent );
+ }
+ }
+
+ } else if ( *schemaNS != 0 ) {
+
+ // Remove all properties from the named schema. Optionally include aliases, in which case
+ // there might not be an actual schema node.
+
+ XMP_NodePtrPos schemaPos;
+ XMP_Node * schemaNode = FindSchemaNode ( &xmpObj->tree, schemaNS, kXMP_ExistingOnly, &schemaPos );
+ if ( schemaNode != 0 ) RemoveSchemaChildren ( schemaPos, doAll );
+
+ if ( includeAliases ) {
+
+ // We're removing the aliases also. Look them up by their namespace prefix. Yes, the
+ // alias map is sorted so we could process just that portion. But that takes more code
+ // and the extra speed isn't worth it. (Plus this way we avoid a dependence on the map
+ // implementation.) Lookup the XMP node from the alias, to make sure the actual exists.
+
+ XMP_StringPtr nsPrefix;
+ XMP_StringLen nsLen;
+ (void) XMPMeta::GetNamespacePrefix ( schemaNS, &nsPrefix, &nsLen );
+
+ XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin();
+ XMP_AliasMapPos endAlias = sRegisteredAliasMap->end();
+
+ for ( ; currAlias != endAlias; ++currAlias ) {
+ if ( strncmp ( currAlias->first.c_str(), nsPrefix, nsLen ) == 0 ) {
+ XMP_NodePtrPos actualPos;
+ XMP_Node * actualProp = FindNode ( &xmpObj->tree, currAlias->second, kXMP_ExistingOnly, kXMP_NoOptions, &actualPos );
+ if ( actualProp != 0 ) {
+ XMP_Node * rootProp = actualProp;
+ while ( ! XMP_NodeIsSchema ( rootProp->parent->options ) ) rootProp = rootProp->parent;
+ if ( doAll || IsExternalProperty ( rootProp->parent->name, rootProp->name ) ) {
+ XMP_Node * parent = actualProp->parent;
+ delete actualProp; // ! Both delete the node and erase the pointer from the parent.
+ parent->children.erase ( actualPos );
+ DeleteEmptySchema ( parent );
+ }
+ }
+ }
+ }
+
+ }
+
+ } else {
+
+ // Remove all appropriate properties from all schema. In this case we don't have to be
+ // concerned with aliases, they are handled implicitly from the actual properties.
+
+ // ! Iterate backwards to reduce shuffling if schema are erased and to simplify the logic
+ // ! for denoting the current schema. (Erasing schema n makes the old n+1 now be n.)
+
+ size_t schemaCount = xmpObj->tree.children.size();
+ XMP_NodePtrPos beginPos = xmpObj->tree.children.begin();
+
+ for ( size_t schemaNum = schemaCount-1, schemaLim = (size_t)(-1); schemaNum != schemaLim; --schemaNum ) {
+ XMP_NodePtrPos currSchema = beginPos + schemaNum;
+ RemoveSchemaChildren ( currSchema, doAll );
+ }
+
+ }
+
+} // RemoveProperties
+
+
+// -------------------------------------------------------------------------------------------------
+// DuplicateSubtree
+// ----------------
+
+/* class static */ void
+XMPUtils::DuplicateSubtree ( const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options )
+{
+ IgnoreParam(options);
+
+ bool fullSourceTree = false;
+ bool fullDestTree = false;
+
+ XMP_ExpandedXPath sourcePath, destPath;
+
+ const XMP_Node * sourceNode = 0;
+ XMP_Node * destNode = 0;
+
+ XMP_Assert ( (sourceNS != 0) && (*sourceNS != 0) );
+ XMP_Assert ( (sourceRoot != 0) && (*sourceRoot != 0) );
+ XMP_Assert ( (dest != 0) && (destNS != 0) && (destRoot != 0) );
+
+ if ( *destNS == 0 ) destNS = sourceNS;
+ if ( *destRoot == 0 ) destRoot = sourceRoot;
+
+ if ( XMP_LitMatch ( sourceNS, "*" ) ) fullSourceTree = true;
+ if ( XMP_LitMatch ( destNS, "*" ) ) fullDestTree = true;
+
+ if ( (&source == dest) && (fullSourceTree | fullDestTree) ) {
+ XMP_Throw ( "Can't duplicate tree onto itself", kXMPErr_BadParam );
+ }
+
+ if ( fullSourceTree & fullDestTree ) XMP_Throw ( "Use Clone for full tree to full tree", kXMPErr_BadParam );
+
+ if ( fullSourceTree ) {
+
+ // The destination must be an existing empty struct, copy all of the source top level as fields.
+
+ ExpandXPath ( destNS, destRoot, &destPath );
+ destNode = FindNode ( &dest->tree, destPath, kXMP_ExistingOnly );
+
+ if ( (destNode == 0) || (! XMP_PropIsStruct ( destNode->options )) ) {
+ XMP_Throw ( "Destination must be an existing struct", kXMPErr_BadXPath );
+ }
+
+ if ( ! destNode->children.empty() ) {
+ if ( options & kXMP_DeleteExisting ) {
+ destNode->RemoveChildren();
+ } else {
+ XMP_Throw ( "Destination must be an empty struct", kXMPErr_BadXPath );
+ }
+ }
+
+ for ( size_t schemaNum = 0, schemaLim = source.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
+
+ const XMP_Node * currSchema = source.tree.children[schemaNum];
+
+ for ( size_t propNum = 0, propLim = currSchema->children.size(); propNum < propLim; ++propNum ) {
+ sourceNode = currSchema->children[propNum];
+ XMP_Node * copyNode = new XMP_Node ( destNode, sourceNode->name, sourceNode->value, sourceNode->options );
+ destNode->children.push_back ( copyNode );
+ CloneOffspring ( sourceNode, copyNode );
+ }
+
+ }
+
+ } else if ( fullDestTree ) {
+
+ // The source node must be an existing struct, copy all of the fields to the dest top level.
+
+ XMP_ExpandedXPath srcPath;
+ ExpandXPath ( sourceNS, sourceRoot, &srcPath );
+ sourceNode = FindConstNode ( &source.tree, srcPath );
+
+ if ( (sourceNode == 0) || (! XMP_PropIsStruct ( sourceNode->options )) ) {
+ XMP_Throw ( "Source must be an existing struct", kXMPErr_BadXPath );
+ }
+
+ destNode = &dest->tree;
+
+ if ( ! destNode->children.empty() ) {
+ if ( options & kXMP_DeleteExisting ) {
+ destNode->RemoveChildren();
+ } else {
+ XMP_Throw ( "Destination tree must be empty", kXMPErr_BadXPath );
+ }
+ }
+
+ std::string nsPrefix;
+ XMP_StringPtr nsURI;
+ XMP_StringLen nsLen;
+
+ for ( size_t fieldNum = 0, fieldLim = sourceNode->children.size(); fieldNum < fieldLim; ++fieldNum ) {
+
+ const XMP_Node * currField = sourceNode->children[fieldNum];
+
+ size_t colonPos = currField->name.find ( ':' );
+ if ( colonPos == std::string::npos ) continue;
+ nsPrefix.assign ( currField->name.c_str(), colonPos );
+ bool nsOK = XMPMeta::GetNamespaceURI ( nsPrefix.c_str(), &nsURI, &nsLen );
+ if ( ! nsOK ) XMP_Throw ( "Source field namespace is not global", kXMPErr_BadSchema );
+
+ XMP_Node * destSchema = FindSchemaNode ( &dest->tree, nsURI, kXMP_CreateNodes );
+ if ( destSchema == 0 ) XMP_Throw ( "Failed to find destination schema", kXMPErr_BadSchema );
+
+ XMP_Node * copyNode = new XMP_Node ( destSchema, currField->name, currField->value, currField->options );
+ destSchema->children.push_back ( copyNode );
+ CloneOffspring ( currField, copyNode );
+
+ }
+
+ } else {
+
+ // Find the root nodes for the source and destination subtrees.
+
+ ExpandXPath ( sourceNS, sourceRoot, &sourcePath );
+ ExpandXPath ( destNS, destRoot, &destPath );
+
+ sourceNode = FindConstNode ( &source.tree, sourcePath );
+ if ( sourceNode == 0 ) XMP_Throw ( "Can't find source subtree", kXMPErr_BadXPath );
+
+ destNode = FindNode ( &dest->tree, destPath, kXMP_ExistingOnly ); // Dest must not yet exist.
+ if ( destNode != 0 ) XMP_Throw ( "Destination subtree must not exist", kXMPErr_BadXPath );
+
+ destNode = FindNode ( &dest->tree, destPath, kXMP_CreateNodes ); // Now create the dest.
+ if ( destNode == 0 ) XMP_Throw ( "Can't create destination root node", kXMPErr_BadXPath );
+
+ // Make sure the destination is not within the source! The source can't be inside the destination
+ // because the source already existed and the destination was just created.
+
+ if ( &source == dest ) {
+ for ( XMP_Node * testNode = destNode; testNode != 0; testNode = testNode->parent ) {
+ if ( testNode == sourceNode ) {
+ // *** delete the just-created dest root node
+ XMP_Throw ( "Destination subtree is within the source subtree", kXMPErr_BadXPath );
+ }
+ }
+ }
+
+ // *** Could use a CloneTree util here and maybe elsewhere.
+
+ destNode->value = sourceNode->value; // *** Should use SetNode.
+ destNode->options = sourceNode->options;
+ CloneOffspring ( sourceNode, destNode );
+
+ }
+
+} // DuplicateSubtree
+
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPUtils.cpp b/gpr/source/lib/xmp_core/XMPUtils.cpp
new file mode 100644
index 0000000..af65dc9
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPUtils.cpp
@@ -0,0 +1,2000 @@
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore_Impl.hpp"
+
+#include "XMPUtils.hpp"
+
+#include "md5.h"
+
+#include <map>
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <stdio.h> // For snprintf.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+// Local Types and Constants
+// =========================
+
+static const char * sBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// =================================================================================================
+// Local Utilities
+// ===============
+
+// -------------------------------------------------------------------------------------------------
+// ANSI Time Functions
+// -------------------
+//
+// A bit of hackery to use the best available time functions. Mac, UNIX and iOS have thread safe versions
+// of gmtime and localtime.
+
+#if XMP_MacBuild | XMP_UNIXBuild | XMP_iOSBuild
+
+ typedef time_t ansi_tt;
+ typedef struct tm ansi_tm;
+
+ #define ansi_time time
+ #define ansi_mktime mktime
+ #define ansi_difftime difftime
+
+ #define ansi_gmtime gmtime_r
+ #define ansi_localtime localtime_r
+
+#elif XMP_WinBuild
+
+ // ! VS.Net 2003 (VC7) does not provide thread safe versions of gmtime and localtime.
+ // ! VS.Net 2005 (VC8) inverts the parameters for the safe versions of gmtime and localtime.
+
+ typedef time_t ansi_tt;
+ typedef struct tm ansi_tm;
+
+ #define ansi_time time
+ #define ansi_mktime mktime
+ #define ansi_difftime difftime
+
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ #define ansi_gmtime(tt,tm) gmtime_s ( tm, tt )
+ #define ansi_localtime(tt,tm) localtime_s ( tm, tt )
+ #else
+ static inline void ansi_gmtime ( const ansi_tt * ttTime, ansi_tm * tmTime )
+ {
+ ansi_tm * tmx = gmtime ( ttTime ); // ! Hope that there is no race!
+ if ( tmx == 0 ) XMP_Throw ( "Failure from ANSI C gmtime function", kXMPErr_ExternalFailure );
+ *tmTime = *tmx;
+ }
+ static inline void ansi_localtime ( const ansi_tt * ttTime, ansi_tm * tmTime )
+ {
+ ansi_tm * tmx = localtime ( ttTime ); // ! Hope that there is no race!
+ if ( tmx == 0 ) XMP_Throw ( "Failure from ANSI C localtime function", kXMPErr_ExternalFailure );
+ *tmTime = *tmx;
+ }
+ #endif
+
+#endif
+
+// -------------------------------------------------------------------------------------------------
+// VerifyDateTimeFlags
+// -------------------
+
+static void
+VerifyDateTimeFlags ( XMP_DateTime * dt )
+{
+
+ if ( (dt->year != 0) || (dt->month != 0) || (dt->day != 0) ) dt->hasDate = true;
+ if ( (dt->hour != 0) || (dt->minute != 0) || (dt->second != 0) || (dt->nanoSecond != 0) ) dt->hasTime = true;
+ if ( (dt->tzSign != 0) || (dt->tzHour != 0) || (dt->tzMinute != 0) ) dt->hasTimeZone = true;
+ if ( dt->hasTimeZone ) dt->hasTime = true; // ! Don't combine with above line, UTC has zero values.
+
+} // VerifyDateTimeFlags
+
+// -------------------------------------------------------------------------------------------------
+// IsLeapYear
+// ----------
+
+static bool
+IsLeapYear ( long year )
+{
+
+ if ( year < 0 ) year = -year + 1; // Fold the negative years, assuming there is a year 0.
+
+ if ( (year % 4) != 0 ) return false; // Not a multiple of 4.
+ if ( (year % 100) != 0 ) return true; // A multiple of 4 but not a multiple of 100.
+ if ( (year % 400) == 0 ) return true; // A multiple of 400.
+
+ return false; // A multiple of 100 but not a multiple of 400.
+
+} // IsLeapYear
+
+// -------------------------------------------------------------------------------------------------
+// DaysInMonth
+// -----------
+
+static int
+DaysInMonth ( XMP_Int32 year, XMP_Int32 month )
+{
+
+ static short daysInMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
+
+ int days = daysInMonth [ month ];
+ if ( (month == 2) && IsLeapYear ( year ) ) days += 1;
+
+ return days;
+
+} // DaysInMonth
+
+// -------------------------------------------------------------------------------------------------
+// AdjustTimeOverflow
+// ------------------
+
+static void
+AdjustTimeOverflow ( XMP_DateTime * time )
+{
+ enum { kBillion = 1000*1000*1000L };
+
+ // ----------------------------------------------------------------------------------------------
+ // To be safe against pathalogical overflow we first adjust from month to second, then from
+ // nanosecond back up to month. This leaves each value closer to zero before propagating into it.
+ // For example if the hour and minute are both near max, adjusting minutes first can cause the
+ // hour to overflow.
+
+ // ! Photoshop 8 creates "time only" values with zeros for year, month, and day.
+
+ if ( (time->year != 0) || (time->month != 0) || (time->day != 0) ) {
+
+ while ( time->month < 1 ) {
+ time->year -= 1;
+ time->month += 12;
+ }
+
+ while ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+
+ while ( time->day < 1 ) {
+ time->month -= 1;
+ if ( time->month < 1 ) { // ! Keep the months in range for indexing daysInMonth!
+ time->year -= 1;
+ time->month += 12;
+ }
+ time->day += DaysInMonth ( time->year, time->month ); // ! Decrement month before so index here is right!
+ }
+
+ while ( time->day > DaysInMonth ( time->year, time->month ) ) {
+ time->day -= DaysInMonth ( time->year, time->month ); // ! Increment month after so index here is right!
+ time->month += 1;
+ if ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+ }
+
+ }
+
+ while ( time->hour < 0 ) {
+ time->day -= 1;
+ time->hour += 24;
+ }
+
+ while ( time->hour >= 24 ) {
+ time->day += 1;
+ time->hour -= 24;
+ }
+
+ while ( time->minute < 0 ) {
+ time->hour -= 1;
+ time->minute += 60;
+ }
+
+ while ( time->minute >= 60 ) {
+ time->hour += 1;
+ time->minute -= 60;
+ }
+
+ while ( time->second < 0 ) {
+ time->minute -= 1;
+ time->second += 60;
+ }
+
+ while ( time->second >= 60 ) {
+ time->minute += 1;
+ time->second -= 60;
+ }
+
+ while ( time->nanoSecond < 0 ) {
+ time->second -= 1;
+ time->nanoSecond += kBillion;
+ }
+
+ while ( time->nanoSecond >= kBillion ) {
+ time->second += 1;
+ time->nanoSecond -= kBillion;
+ }
+
+ while ( time->second < 0 ) {
+ time->minute -= 1;
+ time->second += 60;
+ }
+
+ while ( time->second >= 60 ) {
+ time->minute += 1;
+ time->second -= 60;
+ }
+
+ while ( time->minute < 0 ) {
+ time->hour -= 1;
+ time->minute += 60;
+ }
+
+ while ( time->minute >= 60 ) {
+ time->hour += 1;
+ time->minute -= 60;
+ }
+
+ while ( time->hour < 0 ) {
+ time->day -= 1;
+ time->hour += 24;
+ }
+
+ while ( time->hour >= 24 ) {
+ time->day += 1;
+ time->hour -= 24;
+ }
+
+ if ( (time->year != 0) || (time->month != 0) || (time->day != 0) ) {
+
+ while ( time->month < 1 ) { // Make sure the months are OK first, for DaysInMonth.
+ time->year -= 1;
+ time->month += 12;
+ }
+
+ while ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+
+ while ( time->day < 1 ) {
+ time->month -= 1;
+ if ( time->month < 1 ) {
+ time->year -= 1;
+ time->month += 12;
+ }
+ time->day += DaysInMonth ( time->year, time->month );
+ }
+
+ while ( time->day > DaysInMonth ( time->year, time->month ) ) {
+ time->day -= DaysInMonth ( time->year, time->month );
+ time->month += 1;
+ if ( time->month > 12 ) {
+ time->year += 1;
+ time->month -= 12;
+ }
+ }
+
+ }
+
+} // AdjustTimeOverflow
+
+// -------------------------------------------------------------------------------------------------
+// GatherInt
+// ---------
+//
+// Gather into a 64-bit value in order to easily check for overflow. Using a 32-bit value and
+// checking for negative isn't reliable, the "*10" part can wrap around to a low positive value.
+
+static XMP_Int32
+GatherInt ( XMP_StringPtr strValue, size_t * _pos, const char * errMsg )
+{
+ size_t pos = *_pos;
+ XMP_Int64 value = 0;
+
+ enum { kMaxSInt32 = 0x7FFFFFFF };
+
+ for ( char ch = strValue[pos]; ('0' <= ch) && (ch <= '9'); ++pos, ch = strValue[pos] ) {
+ value = (value * 10) + (ch - '0');
+ if ( value > kMaxSInt32 ) XMP_Throw ( errMsg, kXMPErr_BadValue );
+ }
+
+ if ( pos == *_pos ) XMP_Throw ( errMsg, kXMPErr_BadParam );
+ *_pos = pos;
+ return (XMP_Int32)value;
+
+} // GatherInt
+
+// -------------------------------------------------------------------------------------------------
+
+static void FormatFullDateTime ( XMP_DateTime & tempDate, char * buffer, size_t bufferLen )
+{
+
+ AdjustTimeOverflow ( &tempDate ); // Make sure all time parts are in range.
+
+ if ( (tempDate.second == 0) && (tempDate.nanoSecond == 0) ) {
+
+ // Output YYYY-MM-DDThh:mmTZD.
+ snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d", // AUDIT: Callers pass sizeof(buffer).
+ tempDate.year, tempDate.month, tempDate.day, tempDate.hour, tempDate.minute );
+
+ } else if ( tempDate.nanoSecond == 0 ) {
+
+ // Output YYYY-MM-DDThh:mm:ssTZD.
+ snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d:%02d", // AUDIT: Callers pass sizeof(buffer).
+ tempDate.year, tempDate.month, tempDate.day,
+ tempDate.hour, tempDate.minute, tempDate.second );
+
+ } else {
+
+ // Output YYYY-MM-DDThh:mm:ss.sTZD.
+ snprintf ( buffer, bufferLen, "%.4d-%02d-%02dT%02d:%02d:%02d.%09d", // AUDIT: Callers pass sizeof(buffer).
+ tempDate.year, tempDate.month, tempDate.day,
+ tempDate.hour, tempDate.minute, tempDate.second, tempDate.nanoSecond );
+ buffer[bufferLen - 1] = 0; // AUDIT warning C6053: make sure string is terminated. buffer is already filled with 0 from caller
+ for ( size_t i = strlen(buffer)-1; buffer[i] == '0'; --i ) buffer[i] = 0; // Trim excess digits.
+ }
+
+} // FormatFullDateTime
+
+// -------------------------------------------------------------------------------------------------
+// DecodeBase64Char
+// ----------------
+
+// The decode mapping:
+//
+// encoded encoded raw
+// char value value
+// ------- ------- -----
+// A .. Z 0x41 .. 0x5A 0 .. 25
+// a .. z 0x61 .. 0x7A 26 .. 51
+// 0 .. 9 0x30 .. 0x39 52 .. 61
+// + 0x2B 62
+// / 0x2F 63
+
+static unsigned char
+DecodeBase64Char ( XMP_Uns8 ch )
+{
+
+ if ( ('A' <= ch) && (ch <= 'Z') ) {
+ ch = ch - 'A';
+ } else if ( ('a' <= ch) && (ch <= 'z') ) {
+ ch = ch - 'a' + 26;
+ } else if ( ('0' <= ch) && (ch <= '9') ) {
+ ch = ch - '0' + 52;
+ } else if ( ch == '+' ) {
+ ch = 62;
+ } else if ( ch == '/' ) {
+ ch = 63;
+ } else if ( (ch == ' ') || (ch == kTab) || (ch == kLF) || (ch == kCR) ) {
+ ch = 0xFF; // Will be ignored by the caller.
+ } else {
+ XMP_Throw ( "Invalid base-64 encoded character", kXMPErr_BadParam );
+ }
+
+ return ch;
+
+} // DecodeBase64Char ();
+
+// -------------------------------------------------------------------------------------------------
+// EstimateSizeForJPEG
+// -------------------
+//
+// Estimate the serialized size for the subtree of an XMP_Node. Support for PackageForJPEG.
+
+static size_t
+EstimateSizeForJPEG ( const XMP_Node * xmpNode )
+{
+
+ size_t estSize = 0;
+ size_t nameSize = xmpNode->name.size();
+ bool includeName = (! XMP_PropIsArray ( xmpNode->parent->options ));
+
+ if ( XMP_PropIsSimple ( xmpNode->options ) ) {
+
+ if ( includeName ) estSize += (nameSize + 3); // Assume attribute form.
+ estSize += xmpNode->value.size();
+
+ } else if ( XMP_PropIsArray ( xmpNode->options ) ) {
+
+ // The form of the value portion is: <rdf:Xyz><rdf:li>...</rdf:li>...</rdf:Xyx>
+ if ( includeName ) estSize += (2*nameSize + 5);
+ size_t arraySize = xmpNode->children.size();
+ estSize += 9 + 10; // The rdf:Xyz tags.
+ estSize += arraySize * (8 + 9); // The rdf:li tags.
+ for ( size_t i = 0; i < arraySize; ++i ) {
+ estSize += EstimateSizeForJPEG ( xmpNode->children[i] );
+ }
+
+ } else {
+
+ // The form is: <headTag rdf:parseType="Resource">...fields...</tailTag>
+ if ( includeName ) estSize += (2*nameSize + 5);
+ estSize += 25; // The rdf:parseType="Resource" attribute.
+ size_t fieldCount = xmpNode->children.size();
+ for ( size_t i = 0; i < fieldCount; ++i ) {
+ estSize += EstimateSizeForJPEG ( xmpNode->children[i] );
+ }
+
+ }
+
+ return estSize;
+
+} // EstimateSizeForJPEG
+
+// -------------------------------------------------------------------------------------------------
+// MoveOneProperty
+// ---------------
+
+static bool MoveOneProperty ( XMPMeta & stdXMP, XMPMeta * extXMP,
+ XMP_StringPtr schemaURI, XMP_StringPtr propName )
+{
+
+ XMP_Node * propNode = 0;
+ XMP_NodePtrPos stdPropPos;
+
+ XMP_Node * stdSchema = FindSchemaNode ( &stdXMP.tree, schemaURI, kXMP_ExistingOnly, 0 );
+ if ( stdSchema != 0 ) {
+ propNode = FindChildNode ( stdSchema, propName, kXMP_ExistingOnly, &stdPropPos );
+ }
+ if ( propNode == 0 ) return false;
+
+ XMP_Node * extSchema = FindSchemaNode ( &extXMP->tree, schemaURI, kXMP_CreateNodes );
+
+ propNode->parent = extSchema;
+
+ extSchema->options &= ~kXMP_NewImplicitNode;
+ extSchema->children.push_back ( propNode );
+
+ stdSchema->children.erase ( stdPropPos );
+ DeleteEmptySchema ( stdSchema );
+
+ return true;
+
+} // MoveOneProperty
+
+// -------------------------------------------------------------------------------------------------
+// CreateEstimatedSizeMap
+// ----------------------
+
+#ifndef Trace_PackageForJPEG
+ #define Trace_PackageForJPEG 0
+#endif
+
+typedef std::pair < XMP_VarString*, XMP_VarString* > StringPtrPair;
+typedef std::multimap < size_t, StringPtrPair > PropSizeMap;
+
+static void CreateEstimatedSizeMap ( XMPMeta & stdXMP, PropSizeMap * propSizes )
+{
+ #if Trace_PackageForJPEG
+ printf ( " Creating top level property map:\n" );
+ #endif
+
+ for ( size_t s = stdXMP.tree.children.size(); s > 0; --s ) {
+
+ XMP_Node * stdSchema = stdXMP.tree.children[s-1];
+
+ for ( size_t p = stdSchema->children.size(); p > 0; --p ) {
+
+ XMP_Node * stdProp = stdSchema->children[p-1];
+ if ( (stdSchema->name == kXMP_NS_XMP_Note) &&
+ (stdProp->name == "xmpNote:HasExtendedXMP") ) continue; // ! Don't move xmpNote:HasExtendedXMP.
+
+ size_t propSize = EstimateSizeForJPEG ( stdProp );
+ StringPtrPair namePair ( &stdSchema->name, &stdProp->name );
+ PropSizeMap::value_type mapValue ( propSize, namePair );
+
+ (void) propSizes->insert ( propSizes->upper_bound ( propSize ), mapValue );
+ #if Trace_PackageForJPEG
+ printf ( " %d bytes, %s in %s\n", propSize, stdProp->name.c_str(), stdSchema->name.c_str() );
+ #endif
+
+ }
+
+ }
+
+} // CreateEstimatedSizeMap
+
+// -------------------------------------------------------------------------------------------------
+// MoveLargestProperty
+// -------------------
+
+static size_t MoveLargestProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, PropSizeMap & propSizes )
+{
+ XMP_Assert ( ! propSizes.empty() );
+
+ #if 0
+ // *** Xocde 2.3 on Mac OS X 10.4.7 seems to have a bug where this does not pick the last
+ // *** item in the map. We'll just avoid it on all platforms until thoroughly tested.
+ PropSizeMap::iterator lastPos = propSizes.end();
+ --lastPos; // Move to the actual last item.
+ #else
+ PropSizeMap::iterator lastPos = propSizes.begin();
+ PropSizeMap::iterator nextPos = lastPos;
+ for ( ++nextPos; nextPos != propSizes.end(); ++nextPos ) lastPos = nextPos;
+ #endif
+
+ size_t propSize = lastPos->first;
+ const char * schemaURI = lastPos->second.first->c_str();
+ const char * propName = lastPos->second.second->c_str();
+
+ #if Trace_PackageForJPEG
+ printf ( " Move %s, %d bytes\n", propName, propSize );
+ #endif
+
+ bool moved = MoveOneProperty ( stdXMP, extXMP, schemaURI, propName );
+ XMP_Assert ( moved );
+
+ propSizes.erase ( lastPos );
+ return propSize;
+
+} // MoveLargestProperty
+
+// =================================================================================================
+// Class Static Functions
+// ======================
+
+// -------------------------------------------------------------------------------------------------
+// Initialize
+// ----------
+
+/* class static */ bool
+XMPUtils::Initialize()
+{
+
+ if ( WhiteSpaceStrPtr == NULL ) {
+ WhiteSpaceStrPtr = new std::string();
+ WhiteSpaceStrPtr->append( " \t\n\r" );
+ }
+ return true;
+
+} // Initialize
+
+// -------------------------------------------------------------------------------------------------
+// Terminate
+// ---------
+
+/* class static */ void
+XMPUtils::Terminate() RELEASE_NO_THROW
+{
+
+ delete WhiteSpaceStrPtr;
+ WhiteSpaceStrPtr = NULL;
+ return;
+
+} // Terminate
+
+// -------------------------------------------------------------------------------------------------
+// ComposeArrayItemPath
+// --------------------
+//
+// Return "arrayName[index]".
+
+/* class static */ void
+XMPUtils::ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_VarString * _fullPath )
+{
+ XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
+ XMP_Assert ( (arrayName != 0) && (*arrayName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ if ( (itemIndex < 0) && (itemIndex != kXMP_ArrayLastItem) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadParam );
+
+ XMP_StringLen reserveLen = strlen(arrayName) + 2 + 32; // Room plus padding.
+
+ XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str().
+ fullPath.reserve ( reserveLen );
+ fullPath = arrayName;
+
+ if ( itemIndex == kXMP_ArrayLastItem ) {
+ fullPath += "[last()]";
+ } else {
+ // AUDIT: Using sizeof(buffer) for the snprintf length is safe.
+ char buffer [32]; // A 32 byte buffer is plenty, even for a 64-bit integer.
+ snprintf ( buffer, sizeof(buffer), "[%d]", itemIndex );
+ fullPath += buffer;
+ }
+
+ *_fullPath = fullPath;
+
+} // ComposeArrayItemPath
+
+// -------------------------------------------------------------------------------------------------
+// ComposeStructFieldPath
+// ----------------------
+//
+// Return "structName/ns:fieldName".
+
+/* class static */ void
+XMPUtils::ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_VarString * _fullPath )
+{
+ XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (structName != 0) && (*structName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (fieldName != 0) && (*fieldName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, structName, &expPath );
+
+ XMP_ExpandedXPath fieldPath;
+ ExpandXPath ( fieldNS, fieldName, &fieldPath );
+ if ( fieldPath.size() != 2 ) XMP_Throw ( "The fieldName must be simple", kXMPErr_BadXPath );
+
+ XMP_StringLen reserveLen = strlen(structName) + fieldPath[kRootPropStep].step.size() + 1;
+
+ XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str().
+ fullPath.reserve ( reserveLen );
+ fullPath = structName;
+ fullPath += '/';
+ fullPath += fieldPath[kRootPropStep].step;
+
+ *_fullPath = fullPath;
+
+} // ComposeStructFieldPath
+
+// -------------------------------------------------------------------------------------------------
+// ComposeQualifierPath
+// --------------------
+//
+// Return "propName/?ns:qualName".
+
+/* class static */ void
+XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_VarString * _fullPath )
+{
+ XMP_Assert ( (schemaNS != 0) && (qualNS != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (propName != 0) && (*propName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (qualName != 0) && (*qualName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, propName, &expPath );
+
+ XMP_ExpandedXPath qualPath;
+ ExpandXPath ( qualNS, qualName, &qualPath );
+ if ( qualPath.size() != 2 ) XMP_Throw ( "The qualifier name must be simple", kXMPErr_BadXPath );
+
+ XMP_StringLen reserveLen = strlen(propName) + qualPath[kRootPropStep].step.size() + 2;
+
+ XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str().
+ fullPath.reserve ( reserveLen );
+ fullPath = propName;
+ fullPath += "/?";
+ fullPath += qualPath[kRootPropStep].step;
+
+ *_fullPath = fullPath;
+
+} // ComposeQualifierPath
+
+// -------------------------------------------------------------------------------------------------
+// ComposeLangSelector
+// -------------------
+//
+// Return "arrayName[?xml:lang="lang"]".
+
+// *** #error "handle quotes in the lang - or verify format"
+
+/* class static */ void
+XMPUtils::ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _langName,
+ XMP_VarString * _fullPath )
+{
+ XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
+ XMP_Assert ( (arrayName != 0) && (*arrayName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (_langName != 0) && (*_langName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ XMP_VarString langName ( _langName );
+ NormalizeLangValue ( &langName );
+
+ XMP_StringLen reserveLen = strlen(arrayName) + langName.size() + 14;
+
+ XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str().
+ fullPath.reserve ( reserveLen );
+ fullPath = arrayName;
+ fullPath += "[?xml:lang=\"";
+ fullPath += langName;
+ fullPath += "\"]";
+
+ *_fullPath = fullPath;
+
+} // ComposeLangSelector
+
+// -------------------------------------------------------------------------------------------------
+// ComposeFieldSelector
+// --------------------
+//
+// Return "arrayName[ns:fieldName="fieldValue"]".
+
+// *** #error "handle quotes in the value"
+
+/* class static */ void
+XMPUtils::ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_VarString * _fullPath )
+{
+ XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) && (fieldValue != 0) ); // Enforced by wrapper.
+ XMP_Assert ( (*arrayName != 0) && (*fieldName != 0) ); // Enforced by wrapper.
+ XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path.
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ XMP_ExpandedXPath fieldPath;
+ ExpandXPath ( fieldNS, fieldName, &fieldPath );
+ if ( fieldPath.size() != 2 ) XMP_Throw ( "The fieldName must be simple", kXMPErr_BadXPath );
+
+ XMP_StringLen reserveLen = strlen(arrayName) + fieldPath[kRootPropStep].step.size() + strlen(fieldValue) + 5;
+
+ XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str().
+ fullPath.reserve ( reserveLen );
+ fullPath = arrayName;
+ fullPath += '[';
+ fullPath += fieldPath[kRootPropStep].step;
+ fullPath += "=\"";
+ fullPath += fieldValue;
+ fullPath += "\"]";
+
+ *_fullPath = fullPath;
+
+} // ComposeFieldSelector
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromBool
+// ---------------
+
+/* class static */ void
+XMPUtils::ConvertFromBool ( bool binValue,
+ XMP_VarString * strValue )
+{
+ XMP_Assert ( strValue != 0 ); // Enforced by wrapper.
+
+ if ( binValue ) {
+ *strValue = kXMP_TrueStr;
+ } else {
+ *strValue = kXMP_FalseStr;
+ }
+
+} // ConvertFromBool
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromInt
+// --------------
+
+/* class static */ void
+XMPUtils::ConvertFromInt ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ XMP_VarString * strValue )
+{
+ XMP_Assert ( (format != 0) && (strValue != 0) ); // Enforced by wrapper.
+
+ strValue->erase();
+ if ( *format == 0 ) format = "%d";
+
+ // AUDIT: Using sizeof(buffer) for the snprintf length is safe.
+ char buffer [32]; // Big enough for a 64-bit integer;
+ snprintf ( buffer, sizeof(buffer), format, binValue );
+
+ *strValue = buffer;
+
+} // ConvertFromInt
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromInt64
+// ----------------
+
+/* class static */ void
+XMPUtils::ConvertFromInt64 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ XMP_VarString * strValue )
+{
+ XMP_Assert ( (format != 0) && (strValue != 0) ); // Enforced by wrapper.
+
+ strValue->erase();
+ if ( *format == 0 ) format = "%lld";
+
+ // AUDIT: Using sizeof(buffer) for the snprintf length is safe.
+ char buffer [32]; // Big enough for a 64-bit integer;
+ snprintf ( buffer, sizeof(buffer), format, binValue );
+
+ *strValue = buffer;
+
+} // ConvertFromInt64
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromFloat
+// ----------------
+
+/* class static */ void
+XMPUtils::ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ XMP_VarString * strValue )
+{
+ XMP_Assert ( (format != 0) && (strValue != 0) ); // Enforced by wrapper.
+
+ strValue->erase();
+ if ( *format == 0 ) format = "%f";
+
+ // AUDIT: Using sizeof(buffer) for the snprintf length is safe.
+ char buffer [64]; // Ought to be plenty big enough.
+ snprintf ( buffer, sizeof(buffer), format, binValue );
+
+ *strValue = buffer;
+
+} // ConvertFromFloat
+
+// -------------------------------------------------------------------------------------------------
+// ConvertFromDate
+// ---------------
+//
+// Format a date-time string according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
+// YYYY
+// YYYY-MM
+// YYYY-MM-DD
+// YYYY-MM-DDThh:mmTZD
+// YYYY-MM-DDThh:mm:ssTZD
+// YYYY-MM-DDThh:mm:ss.sTZD
+//
+// YYYY = four-digit year
+// MM = two-digit month (01=January, etc.)
+// DD = two-digit day of month (01 through 31)
+// hh = two digits of hour (00 through 23)
+// mm = two digits of minute (00 through 59)
+// ss = two digits of second (00 through 59)
+// s = one or more digits representing a decimal fraction of a second
+// TZD = time zone designator (Z or +hh:mm or -hh:mm)
+//
+// Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow
+// any year, even negative ones. The year is formatted as "%.4d". The TZD is also optional in XMP,
+// even though required in the W3C profile. Finally, Photoshop 8 (CS) sometimes created time-only
+// values so we tolerate that.
+
+/* class static */ void
+XMPUtils::ConvertFromDate ( const XMP_DateTime & _inValue,
+ XMP_VarString * strValue )
+{
+ XMP_Assert ( strValue != 0 ); // Enforced by wrapper.
+
+ char buffer [100]; // Plenty long enough.
+ memset( buffer, 0, 100);
+
+ // Pick the format, use snprintf to format into a local buffer, assign to static output string.
+ // Don't use AdjustTimeOverflow at the start, that will wipe out zero month or day values.
+
+ // ! Photoshop 8 creates "time only" values with zeros for year, month, and day.
+
+ XMP_DateTime binValue = _inValue;
+ VerifyDateTimeFlags ( &binValue );
+
+ // Temporary fix for bug 1269463, silently fix out of range month or day.
+
+ if ( binValue.month == 0 ) {
+ if ( (binValue.day != 0) || binValue.hasTime ) binValue.month = 1;
+ } else {
+ if ( binValue.month < 1 ) binValue.month = 1;
+ if ( binValue.month > 12 ) binValue.month = 12;
+ }
+
+ if ( binValue.day == 0 ) {
+ if ( binValue.hasTime ) binValue.day = 1;
+ } else {
+ if ( binValue.day < 1 ) binValue.day = 1;
+ if ( binValue.day > 31 ) binValue.day = 31;
+ }
+
+ // Now carry on with the original logic.
+
+ if ( binValue.month == 0 ) {
+
+ // Output YYYY if all else is zero, otherwise output a full string for the quasi-bogus
+ // "time only" values from Photoshop CS.
+ if ( (binValue.day == 0) && (! binValue.hasTime) ) {
+ snprintf ( buffer, sizeof(buffer), "%.4d", binValue.year ); // AUDIT: Using sizeof for snprintf length is safe.
+ } else if ( (binValue.year == 0) && (binValue.day == 0) ) {
+ FormatFullDateTime ( binValue, buffer, sizeof(buffer) );
+ } else {
+ XMP_Throw ( "Invalid partial date", kXMPErr_BadParam);
+ }
+
+ } else if ( binValue.day == 0 ) {
+
+ // Output YYYY-MM.
+ if ( (binValue.month < 1) || (binValue.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam);
+ if ( binValue.hasTime ) XMP_Throw ( "Invalid partial date, non-zeros after zero month and day", kXMPErr_BadParam);
+ snprintf ( buffer, sizeof(buffer), "%.4d-%02d", binValue.year, binValue.month ); // AUDIT: Using sizeof for snprintf length is safe.
+
+ } else if ( ! binValue.hasTime ) {
+
+ // Output YYYY-MM-DD.
+ if ( (binValue.month < 1) || (binValue.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam);
+ if ( (binValue.day < 1) || (binValue.day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam);
+ snprintf ( buffer, sizeof(buffer), "%.4d-%02d-%02d", binValue.year, binValue.month, binValue.day ); // AUDIT: Using sizeof for snprintf length is safe.
+
+ } else {
+
+ FormatFullDateTime ( binValue, buffer, sizeof(buffer) );
+
+ }
+
+ strValue->assign ( buffer );
+
+ if ( binValue.hasTimeZone ) {
+
+ if ( (binValue.tzHour < 0) || (binValue.tzHour > 23) ||
+ (binValue.tzMinute < 0 ) || (binValue.tzMinute > 59) ||
+ (binValue.tzSign < -1) || (binValue.tzSign > +1) ||
+ ((binValue.tzSign == 0) && ((binValue.tzHour != 0) || (binValue.tzMinute != 0))) ) {
+ XMP_Throw ( "Invalid time zone values", kXMPErr_BadParam );
+ }
+
+ if ( binValue.tzSign == 0 ) {
+ *strValue += 'Z';
+ } else {
+ snprintf ( buffer, sizeof(buffer), "+%02d:%02d", binValue.tzHour, binValue.tzMinute ); // AUDIT: Using sizeof for snprintf length is safe.
+ if ( binValue.tzSign < 0 ) buffer[0] = '-';
+ *strValue += buffer;
+ }
+
+ }
+
+} // ConvertFromDate
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToBool
+// -------------
+//
+// Formally the string value should be "True" or "False", but we should be more flexible here. Map
+// the string to lower case. Allow any of "true", "false", "t", "f", "1", or "0".
+
+/* class static */ bool
+XMPUtils::ConvertToBool ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ bool result = false;
+ XMP_VarString strObj ( strValue );
+
+ for ( XMP_VarStringPos ch = strObj.begin(); ch != strObj.end(); ++ch ) {
+ if ( ('A' <= *ch) && (*ch <= 'Z') ) *ch += 0x20;
+ }
+
+ if ( (strObj == "true") || (strObj == "t") || (strObj == "1") ) {
+ result = true;
+ } else if ( (strObj == "false") || (strObj == "f") || (strObj == "0") ) {
+ result = false;
+ } else {
+ XMP_Throw ( "Invalid Boolean string", kXMPErr_BadParam );
+ }
+
+ return result;
+
+} // ConvertToBool
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToInt
+// ------------
+
+/* class static */ XMP_Int32
+XMPUtils::ConvertToInt ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ int count;
+ char nextCh;
+ XMP_Int32 result;
+
+ if ( ! XMP_LitNMatch ( strValue, "0x", 2 ) ) {
+ count = sscanf ( strValue, "%d%c", &result, &nextCh );
+ } else {
+ count = sscanf ( strValue, "%x%c", &result, &nextCh );
+ }
+
+ if ( count != 1 ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam );
+
+ return result;
+
+} // ConvertToInt
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToInt64
+// --------------
+
+/* class static */ XMP_Int64
+XMPUtils::ConvertToInt64 ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ int count;
+ char nextCh;
+ XMP_Int64 result;
+
+ if ( ! XMP_LitNMatch ( strValue, "0x", 2 ) ) {
+ count = sscanf ( strValue, "%lld%c", &result, &nextCh );
+ } else {
+ count = sscanf ( strValue, "%llx%c", &result, &nextCh );
+ }
+
+ if ( count != 1 ) XMP_Throw ( "Invalid integer string", kXMPErr_BadParam );
+
+ return result;
+
+} // ConvertToInt64
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToFloat
+// --------------
+
+/* class static */ double
+XMPUtils::ConvertToFloat ( XMP_StringPtr strValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue );
+
+ XMP_VarString oldLocale; // Try to make sure number conversion uses '.' as the decimal point.
+ XMP_StringPtr oldLocalePtr = setlocale ( LC_ALL, 0 );
+ if ( oldLocalePtr != 0 ) {
+ oldLocale.assign ( oldLocalePtr ); // Save the locale to be reset when exiting.
+ setlocale ( LC_ALL, "C" );
+ }
+
+ errno = 0;
+ char * numEnd;
+ double result = strtod ( strValue, &numEnd );
+ int errnoSave = errno; // The setlocale call below might change errno.
+
+ if ( ! oldLocale.empty() ) setlocale ( LC_ALL, oldLocale.c_str() ); // ! Reset locale before possible throw!
+ if ( (errnoSave != 0) || (*numEnd != 0) ) XMP_Throw ( "Invalid float string", kXMPErr_BadParam );
+
+ return result;
+
+} // ConvertToFloat
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToDate
+// -------------
+//
+// Parse a date-time string according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
+// YYYY
+// YYYY-MM
+// YYYY-MM-DD
+// YYYY-MM-DDThh:mmTZD
+// YYYY-MM-DDThh:mm:ssTZD
+// YYYY-MM-DDThh:mm:ss.sTZD
+//
+// YYYY = four-digit year
+// MM = two-digit month (01=January, etc.)
+// DD = two-digit day of month (01 through 31)
+// hh = two digits of hour (00 through 23)
+// mm = two digits of minute (00 through 59)
+// ss = two digits of second (00 through 59)
+// s = one or more digits representing a decimal fraction of a second
+// TZD = time zone designator (Z or +hh:mm or -hh:mm)
+//
+// Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow
+// any year, even negative ones. The year is formatted as "%.4d". The TZD is also optional in XMP,
+// even though required in the W3C profile. Finally, Photoshop 8 (CS) sometimes created time-only
+// values so we tolerate that.
+
+// *** Put the ISO format comments in the header documentation.
+
+/* class static */ void
+XMPUtils::ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue )
+{
+ if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue);
+
+ size_t pos = 0;
+ XMP_Int32 temp;
+
+ XMP_Assert ( sizeof(*binValue) == sizeof(XMP_DateTime) );
+ (void) memset ( binValue, 0, sizeof(*binValue) ); // AUDIT: Safe, using sizeof destination.
+
+ size_t strSize = strlen ( strValue );
+ bool timeOnly = ( (strValue[0] == 'T') ||
+ ((strSize >= 2) && (strValue[1] == ':')) ||
+ ((strSize >= 3) && (strValue[2] == ':')) );
+
+ if ( ! timeOnly ) {
+
+ binValue->hasDate = true;
+
+ if ( strValue[0] == '-' ) pos = 1;
+
+ temp = GatherInt ( strValue, &pos, "Invalid year in date string" ); // Extract the year.
+ if ( (strValue[pos] != 0) && (strValue[pos] != '-') ) XMP_Throw ( "Invalid date string, after year", kXMPErr_BadParam );
+ if ( strValue[0] == '-' ) temp = -temp;
+ binValue->year = temp;
+ if ( strValue[pos] == 0 ) return;
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid month in date string" ); // Extract the month.
+ if ( (strValue[pos] != 0) && (strValue[pos] != '-') ) XMP_Throw ( "Invalid date string, after month", kXMPErr_BadParam );
+ binValue->month = temp;
+ if ( strValue[pos] == 0 ) return;
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid day in date string" ); // Extract the day.
+ if ( (strValue[pos] != 0) && (strValue[pos] != 'T') ) XMP_Throw ( "Invalid date string, after day", kXMPErr_BadParam );
+ binValue->day = temp;
+ if ( strValue[pos] == 0 ) return;
+
+ // Allow year, month, and day to all be zero; implies the date portion is missing.
+ if ( (binValue->year != 0) || (binValue->month != 0) || (binValue->day != 0) ) {
+ // Temporary fix for bug 1269463, silently fix out of range month or day.
+ // if ( (binValue->month < 1) || (binValue->month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam );
+ // if ( (binValue->day < 1) || (binValue->day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam );
+ if ( binValue->month < 1 ) binValue->month = 1;
+ if ( binValue->month > 12 ) binValue->month = 12;
+ if ( binValue->day < 1 ) binValue->day = 1;
+ if ( binValue->day > 31 ) binValue->day = 31;
+ }
+
+ }
+
+ // If we get here there is more of the string, otherwise we would have returned above.
+
+ if ( strValue[pos] == 'T' ) {
+ ++pos;
+ } else if ( ! timeOnly ) {
+ XMP_Throw ( "Invalid date string, missing 'T' after date", kXMPErr_BadParam );
+ }
+
+ binValue->hasTime = true;
+
+ temp = GatherInt ( strValue, &pos, "Invalid hour in date string" ); // Extract the hour.
+ if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after hour", kXMPErr_BadParam );
+ if ( temp > 23 ) temp = 23; // *** 1269463: XMP_Throw ( "Hour is out of range", kXMPErr_BadParam );
+ binValue->hour = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid minute in date string" ); // And the minute.
+ if ( (strValue[pos] != ':') && (strValue[pos] != 'Z') &&
+ (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) XMP_Throw ( "Invalid date string, after minute", kXMPErr_BadParam );
+ if ( temp > 59 ) temp = 59; // *** 1269463: XMP_Throw ( "Minute is out of range", kXMPErr_BadParam );
+ binValue->minute = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ if ( strValue[pos] == ':' ) {
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid whole seconds in date string" ); // Extract the whole seconds.
+ if ( (strValue[pos] != '.') && (strValue[pos] != 'Z') &&
+ (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) {
+ XMP_Throw ( "Invalid date string, after whole seconds", kXMPErr_BadParam );
+ }
+ if ( temp > 59 ) temp = 59; // *** 1269463: XMP_Throw ( "Whole second is out of range", kXMPErr_BadParam );
+ binValue->second = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ if ( strValue[pos] == '.' ) {
+
+ ++pos;
+ size_t digits = pos; // Will be the number of digits later.
+
+ temp = GatherInt ( strValue, &pos, "Invalid fractional seconds in date string" ); // Extract the fractional seconds.
+ if ( (strValue[pos] != 'Z') && (strValue[pos] != '+') && (strValue[pos] != '-') && (strValue[pos] != 0) ) {
+ XMP_Throw ( "Invalid date string, after fractional second", kXMPErr_BadParam );
+ }
+
+ digits = pos - digits;
+ for ( ; digits > 9; --digits ) temp = temp / 10;
+ for ( ; digits < 9; ++digits ) temp = temp * 10;
+
+ if ( temp >= 1000*1000*1000 ) XMP_Throw ( "Fractional second is out of range", kXMPErr_BadParam );
+ binValue->nanoSecond = temp;
+ // Don't check for done, we have to work up to the time zone.
+
+ }
+
+ }
+
+ if ( strValue[pos] == 0 ) return;
+
+ binValue->hasTimeZone = true;
+
+ if ( strValue[pos] == 'Z' ) {
+
+ ++pos;
+
+ } else {
+
+ if ( strValue[pos] == '+' ) {
+ binValue->tzSign = kXMP_TimeEastOfUTC;
+ } else if ( strValue[pos] == '-' ) {
+ binValue->tzSign = kXMP_TimeWestOfUTC;
+ } else {
+ XMP_Throw ( "Time zone must begin with 'Z', '+', or '-'", kXMPErr_BadParam );
+ }
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid time zone hour in date string" ); // Extract the time zone hour.
+ if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after time zone hour", kXMPErr_BadParam );
+ if ( temp > 23 ) XMP_Throw ( "Time zone hour is out of range", kXMPErr_BadParam );
+ binValue->tzHour = temp;
+
+ ++pos;
+ temp = GatherInt ( strValue, &pos, "Invalid time zone minute in date string" ); // Extract the time zone minute.
+ if ( temp > 59 ) XMP_Throw ( "Time zone minute is out of range", kXMPErr_BadParam );
+ binValue->tzMinute = temp;
+
+ }
+
+ if ( strValue[pos] != 0 ) XMP_Throw ( "Invalid date string, extra chars at end", kXMPErr_BadParam );
+
+} // ConvertToDate
+
+// -------------------------------------------------------------------------------------------------
+// EncodeToBase64
+// --------------
+//
+// Encode a string of raw data bytes in base 64 according to RFC 2045. For the encoding definition
+// see section 6.8 in <http://www.ietf.org/rfc/rfc2045.txt>. Although it isn't needed for RDF, we
+// do insert a linefeed character as a newline for every 76 characters of encoded output.
+
+/* class static */ void
+XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ XMP_VarString * encodedStr )
+{
+ if ( (rawStr == 0) && (rawLen != 0) ) XMP_Throw ( "Null raw data buffer", kXMPErr_BadParam );
+ XMP_Assert ( encodedStr != 0 ); // Enforced by wrapper.
+
+ encodedStr->erase();
+ if ( rawLen == 0 ) return;
+
+ char encChunk[4];
+
+ unsigned long in, out;
+ unsigned char c1, c2, c3;
+ unsigned long merge;
+
+ const size_t outputSize = (rawLen / 3) * 4; // Approximate, might be small.
+
+ encodedStr->reserve ( outputSize );
+
+ // ----------------------------------------------------------------------------------------
+ // Each 6 bits of input produces 8 bits of output, so 3 input bytes become 4 output bytes.
+ // Process the whole chunks of 3 bytes first, then deal with any remainder. Be careful with
+ // the loop comparison, size-2 could be negative!
+
+ for ( in = 0, out = 0; (in+2) < rawLen; in += 3, out += 4 ) {
+
+ c1 = rawStr[in];
+ c2 = rawStr[in+1];
+ c3 = rawStr[in+2];
+
+ merge = (c1 << 16) + (c2 << 8) + c3;
+
+ encChunk[0] = sBase64Chars [ merge >> 18 ];
+ encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ];
+ encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ];
+ encChunk[3] = sBase64Chars [ merge & 0x3F ];
+
+ if ( out >= 76 ) {
+ encodedStr->append ( 1, kLF );
+ out = 0;
+ }
+ encodedStr->append ( encChunk, 4 );
+
+ }
+
+ // ------------------------------------------------------------------------------------------
+ // The output must always be a multiple of 4 bytes. If there is a 1 or 2 byte input remainder
+ // we need to create another chunk. Zero pad with bits to a 6 bit multiple, then add one or
+ // two '=' characters to pad out to 4 bytes.
+
+ switch ( rawLen - in ) {
+
+ case 0: // Done, no remainder.
+ break;
+
+ case 1: // One input byte remains.
+
+ c1 = rawStr[in];
+ merge = c1 << 16;
+
+ encChunk[0] = sBase64Chars [ merge >> 18 ];
+ encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ];
+ encChunk[2] = encChunk[3] = '=';
+
+ if ( out >= 76 ) encodedStr->append ( 1, kLF );
+ encodedStr->append ( encChunk, 4 );
+ break;
+
+ case 2: // Two input bytes remain.
+
+ c1 = rawStr[in];
+ c2 = rawStr[in+1];
+ merge = (c1 << 16) + (c2 << 8);
+
+ encChunk[0] = sBase64Chars [ merge >> 18 ];
+ encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ];
+ encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ];
+ encChunk[3] = '=';
+
+ if ( out >= 76 ) encodedStr->append ( 1, kLF );
+ encodedStr->append ( encChunk, 4 );
+ break;
+
+ }
+
+} // EncodeToBase64
+
+// -------------------------------------------------------------------------------------------------
+// DecodeFromBase64
+// ----------------
+//
+// Decode a string of raw data bytes from base 64 according to RFC 2045. For the encoding definition
+// see section 6.8 in <http://www.ietf.org/rfc/rfc2045.txt>. RFC 2045 talks about ignoring all "bad"
+// input but warning about non-whitespace. For XMP use we ignore space, tab, LF, and CR. Any other
+// bad input is rejected.
+
+/* class static */ void
+XMPUtils::DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ XMP_VarString * rawStr )
+{
+ if ( (encodedStr == 0) && (encodedLen != 0) ) XMP_Throw ( "Null encoded data buffer", kXMPErr_BadParam );
+ XMP_Assert ( rawStr != 0 ); // Enforced by wrapper.
+
+ rawStr->erase();
+ if ( encodedLen == 0 ) return;
+
+ unsigned char ch, rawChunk[3];
+ unsigned long inStr, inChunk, inLimit, merge, padding;
+
+ XMP_StringLen outputSize = (encodedLen / 4) * 3; // Only a close approximation.
+
+ rawStr->reserve ( outputSize );
+
+
+ // ----------------------------------------------------------------------------------------
+ // Each 8 bits of input produces 6 bits of output, so 4 input bytes become 3 output bytes.
+ // Process all but the last 4 data bytes first, then deal with the final chunk. Whitespace
+ // in the input must be ignored. The first loop finds where the last 4 data bytes start and
+ // counts the number of padding equal signs.
+
+ padding = 0;
+ for ( inStr = 0, inLimit = encodedLen; (inStr < 4) && (inLimit > 0); ) {
+ inLimit -= 1; // ! Don't do in the loop control, the decr/test order is wrong.
+ ch = encodedStr[inLimit];
+ if ( ch == '=' ) {
+ padding += 1; // The equal sign padding is a data byte.
+ } else if ( DecodeBase64Char(ch) == 0xFF ) {
+ continue; // Ignore whitespace, don't increment inStr.
+ } else {
+ inStr += 1;
+ }
+ }
+
+ // ! Be careful to count whitespace that is immediately before the final data. Otherwise
+ // ! middle portion will absorb the final data and mess up the final chunk processing.
+
+ while ( (inLimit > 0) && (DecodeBase64Char(encodedStr[inLimit-1]) == 0xFF) ) --inLimit;
+
+ if ( inStr == 0 ) return; // Nothing but whitespace.
+ if ( padding > 2 ) XMP_Throw ( "Invalid encoded string", kXMPErr_BadParam );
+
+ // -------------------------------------------------------------------------------------------
+ // Now process all but the last chunk. The limit ensures that we have at least 4 data bytes
+ // left when entering the output loop, so the inner loop will succeed without overrunning the
+ // end of the data. At the end of the outer loop we might be past inLimit though.
+
+ inStr = 0;
+ while ( inStr < inLimit ) {
+
+ merge = 0;
+ for ( inChunk = 0; inChunk < 4; ++inStr ) { // ! Yes, increment inStr on each pass.
+ ch = DecodeBase64Char ( encodedStr [inStr] );
+ if ( ch == 0xFF ) continue; // Ignore whitespace.
+ merge = (merge << 6) + ch;
+ inChunk += 1;
+ }
+
+ rawChunk[0] = (unsigned char) (merge >> 16);
+ rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF);
+ rawChunk[2] = (unsigned char) (merge & 0xFF);
+
+ rawStr->append ( (char*)rawChunk, 3 );
+
+ }
+
+ // -------------------------------------------------------------------------------------------
+ // Process the final, possibly partial, chunk of data. The input is always a multiple 4 bytes,
+ // but the raw data can be any length. The number of padding '=' characters determines if the
+ // final chunk has 1, 2, or 3 raw data bytes.
+
+ XMP_Assert ( inStr < encodedLen );
+
+ merge = 0;
+ for ( inChunk = 0; inChunk < 4-padding; ++inStr ) { // ! Yes, increment inStr on each pass.
+ ch = DecodeBase64Char ( encodedStr[inStr] );
+ if ( ch == 0xFF ) continue; // Ignore whitespace.
+ merge = (merge << 6) + ch;
+ inChunk += 1;
+ }
+
+ if ( padding == 2 ) {
+
+ rawChunk[0] = (unsigned char) (merge >> 4);
+ rawStr->append ( (char*)rawChunk, 1 );
+
+ } else if ( padding == 1 ) {
+
+ rawChunk[0] = (unsigned char) (merge >> 10);
+ rawChunk[1] = (unsigned char) ((merge >> 2) & 0xFF);
+ rawStr->append ( (char*)rawChunk, 2 );
+
+ } else {
+
+ rawChunk[0] = (unsigned char) (merge >> 16);
+ rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF);
+ rawChunk[2] = (unsigned char) (merge & 0xFF);
+ rawStr->append ( (char*)rawChunk, 3 );
+
+ }
+
+} // DecodeFromBase64
+
+// -------------------------------------------------------------------------------------------------
+// PackageForJPEG
+// --------------
+
+/* class static */ void
+XMPUtils::PackageForJPEG ( const XMPMeta & origXMP,
+ XMP_VarString * stdStr,
+ XMP_VarString * extStr,
+ XMP_VarString * digestStr )
+{
+ XMP_Assert ( (stdStr != 0) && (extStr != 0) && (digestStr != 0) ); // ! Enforced by wrapper.
+
+ enum { kStdXMPLimit = 65000 };
+ static const char * kPacketTrailer = "<?xpacket end=\"w\"?>";
+ static size_t kTrailerLen = strlen ( kPacketTrailer );
+
+ XMP_VarString tempStr;
+ XMPMeta stdXMP, extXMP;
+ XMP_OptionBits keepItSmall = kXMP_UseCompactFormat | kXMP_OmitAllFormatting;
+
+ stdStr->erase();
+ extStr->erase();
+ digestStr->erase();
+
+ // Try to serialize everything. Note that we're making internal calls to SerializeToBuffer, so
+ // we'll be getting back the pointer and length for its internal string.
+
+ origXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( "\nXMPUtils::PackageForJPEG - Full serialize %d bytes\n", tempStr.size() );
+ #endif
+
+ if ( tempStr.size() > kStdXMPLimit ) {
+
+ // Couldn't fit everything, make a copy of the input XMP and make sure there is no xmp:Thumbnails property.
+
+ stdXMP.tree.options = origXMP.tree.options;
+ stdXMP.tree.name = origXMP.tree.name;
+ stdXMP.tree.value = origXMP.tree.value;
+ CloneOffspring ( &origXMP.tree, &stdXMP.tree );
+
+ if ( stdXMP.DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) {
+ stdXMP.DeleteProperty ( kXMP_NS_XMP, "Thumbnails" );
+ stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( " Delete xmp:Thumbnails, %d bytes left\n", tempStr.size() );
+ #endif
+ }
+
+ }
+
+ if ( tempStr.size() > kStdXMPLimit ) {
+
+ // Still doesn't fit, move all of the Camera Raw namespace. Add a dummy value for xmpNote:HasExtendedXMP.
+
+ stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", "123456789-123456789-123456789-12", 0 );
+
+ XMP_NodePtrPos crSchemaPos;
+ XMP_Node * crSchema = FindSchemaNode ( &stdXMP.tree, kXMP_NS_CameraRaw, kXMP_ExistingOnly, &crSchemaPos );
+
+ if ( crSchema != 0 ) {
+ crSchema->parent = &extXMP.tree;
+ extXMP.tree.children.push_back ( crSchema );
+ stdXMP.tree.children.erase ( crSchemaPos );
+ stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( " Move Camera Raw schema, %d bytes left\n", tempStr.size() );
+ #endif
+ }
+
+ }
+
+ if ( tempStr.size() > kStdXMPLimit ) {
+
+ // Still doesn't fit, move photoshop:History.
+
+ bool moved = MoveOneProperty ( stdXMP, &extXMP, kXMP_NS_Photoshop, "photoshop:History" );
+
+ if ( moved ) {
+ stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 );
+ #if Trace_PackageForJPEG
+ printf ( " Move photoshop:History, %d bytes left\n", tempStr.size() );
+ #endif
+ }
+
+ }
+
+ if ( tempStr.size() > kStdXMPLimit ) {
+
+ // Still doesn't fit, move top level properties in order of estimated size. This is done by
+ // creating a multi-map that maps the serialized size to the string pair for the schema URI
+ // and top level property name. Since maps are inherently ordered, a reverse iteration of
+ // the map can be done to move the largest things first. We use a double loop to keep going
+ // until the serialization actually fits, in case the estimates are off.
+
+ PropSizeMap propSizes;
+ CreateEstimatedSizeMap ( stdXMP, &propSizes );
+
+ #if Trace_PackageForJPEG
+ if ( ! propSizes.empty() ) {
+ printf ( " Top level property map, smallest to largest:\n" );
+ PropSizeMap::iterator mapPos = propSizes.begin();
+ PropSizeMap::iterator mapEnd = propSizes.end();
+ for ( ; mapPos != mapEnd; ++mapPos ) {
+ size_t propSize = mapPos->first;
+ const char * schemaName = mapPos->second.first->c_str();
+ const char * propName = mapPos->second.second->c_str();
+ printf ( " %d bytes, %s in %s\n", propSize, propName, schemaName );
+ }
+ }
+ #endif
+
+ #if 0 // Trace_PackageForJPEG *** Xcode 2.3 on 10.4.7 has bugs in backwards iteration
+ if ( ! propSizes.empty() ) {
+ printf ( " Top level property map, largest to smallest:\n" );
+ PropSizeMap::iterator mapPos = propSizes.end();
+ PropSizeMap::iterator mapBegin = propSizes.begin();
+ for ( --mapPos; true; --mapPos ) {
+ size_t propSize = mapPos->first;
+ const char * schemaName = mapPos->second.first->c_str();
+ const char * propName = mapPos->second.second->c_str();
+ printf ( " %d bytes, %s in %s\n", propSize, propName, schemaName );
+ if ( mapPos == mapBegin ) break;
+ }
+ }
+ #endif
+
+ // Outer loop to make sure enough is actually moved.
+
+ while ( (tempStr.size() > kStdXMPLimit) && (! propSizes.empty()) ) {
+
+ // Inner loop, move what seems to be enough according to the estimates.
+
+ size_t tempLen = tempStr.size();
+ while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) {
+
+ size_t propSize = MoveLargestProperty ( stdXMP, &extXMP, propSizes );
+ XMP_Assert ( propSize > 0 );
+
+ if ( propSize > tempLen ) propSize = tempLen; // ! Don't go negative.
+ tempLen -= propSize;
+
+ }
+
+ // Reserialize the remaining standard XMP.
+
+ stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 );
+
+ }
+
+ }
+
+ if ( tempStr.size() > kStdXMPLimit ) {
+ // Still doesn't fit, throw an exception and let the client decide what to do.
+ // ! This should never happen with the policy of moving any and all top level properties.
+ XMP_Throw ( "Can't reduce XMP enough for JPEG file", kXMPErr_TooLargeForJPEG );
+ }
+
+ // Set the static output strings.
+
+ if ( extXMP.tree.children.empty() ) {
+
+ // Just have the standard XMP.
+ *stdStr = tempStr;
+
+ } else {
+
+ // Have extended XMP. Serialize it, compute the digest, reset xmpNote:HasExtendedXMP, and
+ // reserialize the standard XMP.
+
+ extXMP.SerializeToBuffer ( &tempStr, (keepItSmall | kXMP_OmitPacketWrapper), 0, "", "", 0 );
+ *extStr = tempStr;
+
+ XMP_Uns8 digest [16];
+
+ {
+ context_md5_t ctx;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char*)tempStr.c_str(), (unsigned int)tempStr.size() );
+ MD5Final(digest, &ctx);
+ }
+
+ digestStr->reserve ( 32 );
+ for ( size_t i = 0; i < 16; ++i ) {
+ XMP_Uns8 byte = digest[i];
+ digestStr->push_back ( kHexDigits [ byte>>4 ] );
+ digestStr->push_back ( kHexDigits [ byte&0xF ] );
+ }
+
+ stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", digestStr->c_str(), 0 );
+ stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 );
+ *stdStr = tempStr;
+
+ }
+
+ // Adjust the standard XMP padding to be up to 2KB.
+
+ XMP_Assert ( (stdStr->size() > kTrailerLen) && (stdStr->size() <= kStdXMPLimit) );
+ const char * packetEnd = stdStr->c_str() + stdStr->size() - kTrailerLen;
+ XMP_Assert ( XMP_LitMatch ( packetEnd, kPacketTrailer ) );
+
+ size_t extraPadding = kStdXMPLimit - stdStr->size(); // ! Do this before erasing the trailer.
+ if ( extraPadding > 2047 ) extraPadding = 2047;
+ stdStr->erase ( stdStr->size() - kTrailerLen );
+ stdStr->append ( extraPadding, ' ' );
+ stdStr->append ( kPacketTrailer );
+
+} // PackageForJPEG
+
+// -------------------------------------------------------------------------------------------------
+// MergeFromJPEG
+// -------------
+//
+// Copy all of the top level properties from extendedXMP to fullXMP, replacing any duplicates.
+// Delete the xmpNote:HasExtendedXMP property from fullXMP.
+
+/* class static */ void
+XMPUtils::MergeFromJPEG ( XMPMeta * fullXMP,
+ const XMPMeta & extendedXMP )
+{
+
+ XMP_OptionBits apFlags = (kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties);
+ XMPUtils::ApplyTemplate ( fullXMP, extendedXMP, apFlags );
+ fullXMP->DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" );
+
+} // MergeFromJPEG
+
+// -------------------------------------------------------------------------------------------------
+// CurrentDateTime
+// ---------------
+
+/* class static */ void
+XMPUtils::CurrentDateTime ( XMP_DateTime * xmpTime )
+{
+ XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper.
+
+ ansi_tt binTime = ansi_time(0);
+ if ( binTime == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure );
+ ansi_tm currTime;
+ ansi_localtime ( &binTime, &currTime );
+
+ xmpTime->year = currTime.tm_year + 1900;
+ xmpTime->month = currTime.tm_mon + 1;
+ xmpTime->day = currTime.tm_mday;
+ xmpTime->hasDate = true;
+
+ xmpTime->hour = currTime.tm_hour;
+ xmpTime->minute = currTime.tm_min;
+ xmpTime->second = currTime.tm_sec;
+ xmpTime->nanoSecond = 0;
+ xmpTime->hasTime = true;
+
+ xmpTime->tzSign = 0;
+ xmpTime->tzHour = 0;
+ xmpTime->tzMinute = 0;
+ xmpTime->hasTimeZone = false; // ! Needed for SetTimeZone.
+ XMPUtils::SetTimeZone ( xmpTime );
+
+} // CurrentDateTime
+
+// -------------------------------------------------------------------------------------------------
+// SetTimeZone
+// -----------
+//
+// Sets just the time zone part of the time. Useful for determining the local time zone or for
+// converting a "zone-less" time to a proper local time. The ANSI C time functions are smart enough
+// to do all the right stuff, as long as we call them properly!
+
+/* class static */ void
+XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime )
+{
+ XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper.
+
+ VerifyDateTimeFlags ( xmpTime );
+
+ if ( xmpTime->hasTimeZone ) {
+ XMP_Throw ( "SetTimeZone can only be used on zone-less times", kXMPErr_BadParam );
+ }
+
+ // Create ansi_tt form of the input time. Need the ansi_tm form to make the ansi_tt form.
+
+ ansi_tt ttTime;
+ ansi_tm tmLocal, tmUTC;
+
+ if ( (xmpTime->year == 0) && (xmpTime->month == 0) && (xmpTime->day == 0) ) {
+ ansi_tt now = ansi_time(0);
+ if ( now == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure );
+ ansi_localtime ( &now, &tmLocal );
+ } else {
+ tmLocal.tm_year = xmpTime->year - 1900;
+ while ( tmLocal.tm_year < 70 ) tmLocal.tm_year += 4; // ! Some versions of mktime barf on years before 1970.
+ tmLocal.tm_mon = xmpTime->month - 1;
+ tmLocal.tm_mday = xmpTime->day;
+ }
+
+ tmLocal.tm_hour = xmpTime->hour;
+ tmLocal.tm_min = xmpTime->minute;
+ tmLocal.tm_sec = xmpTime->second;
+ tmLocal.tm_isdst = -1; // Don't know if daylight time is in effect.
+
+ ttTime = ansi_mktime ( &tmLocal );
+ if ( ttTime == -1 ) XMP_Throw ( "Failure from ANSI C mktime function", kXMPErr_ExternalFailure );
+
+ // Convert back to a localized ansi_tm time and get the corresponding UTC ansi_tm time.
+
+ ansi_localtime ( &ttTime, &tmLocal );
+ ansi_gmtime ( &ttTime, &tmUTC );
+
+ // Get the offset direction and amount.
+
+ ansi_tm tmx = tmLocal; // ! Note that mktime updates the ansi_tm parameter, messing up difftime!
+ ansi_tm tmy = tmUTC;
+ tmx.tm_isdst = tmy.tm_isdst = 0;
+ ansi_tt ttx = ansi_mktime ( &tmx );
+ ansi_tt tty = ansi_mktime ( &tmy );
+ double diffSecs;
+
+ if ( (ttx != -1) && (tty != -1) ) {
+ diffSecs = ansi_difftime ( ttx, tty );
+ } else {
+ #if XMP_MacBuild | XMP_iOSBuild
+ // Looks like Apple's mktime is buggy - see W1140533. But the offset is visible.
+ diffSecs = tmLocal.tm_gmtoff;
+ #else
+ // Win and UNIX don't have a visible offset. Make sure we know about the failure,
+ // then try using the current date/time as a close fallback.
+ ttTime = ansi_time(0);
+ if ( ttTime == -1 ) XMP_Throw ( "Failure from ANSI C time function", kXMPErr_ExternalFailure );
+ ansi_localtime ( &ttTime, &tmx );
+ ansi_gmtime ( &ttTime, &tmy );
+ tmx.tm_isdst = tmy.tm_isdst = 0;
+ ttx = ansi_mktime ( &tmx );
+ tty = ansi_mktime ( &tmy );
+ if ( (ttx == -1) || (tty == -1) ) XMP_Throw ( "Failure from ANSI C mktime function", kXMPErr_ExternalFailure );
+ diffSecs = ansi_difftime ( ttx, tty );
+ #endif
+ }
+
+ if ( diffSecs > 0.0 ) {
+ xmpTime->tzSign = kXMP_TimeEastOfUTC;
+ } else if ( diffSecs == 0.0 ) {
+ xmpTime->tzSign = kXMP_TimeIsUTC;
+ } else {
+ xmpTime->tzSign = kXMP_TimeWestOfUTC;
+ diffSecs = -diffSecs;
+ }
+ xmpTime->tzHour = XMP_Int32 ( diffSecs / 3600.0 );
+ xmpTime->tzMinute = XMP_Int32 ( (diffSecs / 60.0) - (xmpTime->tzHour * 60.0) );
+
+ xmpTime->hasTimeZone = xmpTime->hasTime = true;
+
+ // *** Save the tm_isdst flag in a qualifier?
+
+ XMP_Assert ( (0 <= xmpTime->tzHour) && (xmpTime->tzHour <= 23) );
+ XMP_Assert ( (0 <= xmpTime->tzMinute) && (xmpTime->tzMinute <= 59) );
+ XMP_Assert ( (-1 <= xmpTime->tzSign) && (xmpTime->tzSign <= +1) );
+ XMP_Assert ( (xmpTime->tzSign == 0) ? ((xmpTime->tzHour == 0) && (xmpTime->tzMinute == 0)) :
+ ((xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0)) );
+
+} // SetTimeZone
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToUTCTime
+// ----------------
+
+/* class static */ void
+XMPUtils::ConvertToUTCTime ( XMP_DateTime * time )
+{
+ XMP_Assert ( time != 0 ); // ! Enforced by wrapper.
+
+ VerifyDateTimeFlags ( time );
+
+ if ( ! time->hasTimeZone ) return; // Do nothing if there is no current time zone.
+
+ XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) );
+ XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) );
+ XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) );
+ XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) :
+ ((time->tzHour != 0) || (time->tzMinute != 0)) );
+
+ if ( time->tzSign == kXMP_TimeEastOfUTC ) {
+ // We are before (east of) GMT, subtract the offset from the time.
+ time->hour -= time->tzHour;
+ time->minute -= time->tzMinute;
+ } else if ( time->tzSign == kXMP_TimeWestOfUTC ) {
+ // We are behind (west of) GMT, add the offset to the time.
+ time->hour += time->tzHour;
+ time->minute += time->tzMinute;
+ }
+
+ AdjustTimeOverflow ( time );
+ time->tzSign = time->tzHour = time->tzMinute = 0;
+
+} // ConvertToUTCTime
+
+// -------------------------------------------------------------------------------------------------
+// ConvertToLocalTime
+// ------------------
+
+/* class static */ void
+XMPUtils::ConvertToLocalTime ( XMP_DateTime * time )
+{
+ XMP_Assert ( time != 0 ); // ! Enforced by wrapper.
+
+ VerifyDateTimeFlags ( time );
+
+ if ( ! time->hasTimeZone ) return; // Do nothing if there is no current time zone.
+
+ XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) );
+ XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) );
+ XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) );
+ XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) :
+ ((time->tzHour != 0) || (time->tzMinute != 0)) );
+
+ ConvertToUTCTime ( time ); // The existing time zone might not be the local one.
+ time->hasTimeZone = false; // ! Needed for SetTimeZone.
+ SetTimeZone ( time ); // Fill in the local timezone offset, then adjust the time.
+
+ if ( time->tzSign > 0 ) {
+ // We are before (east of) GMT, add the offset to the time.
+ time->hour += time->tzHour;
+ time->minute += time->tzMinute;
+ } else if ( time->tzSign < 0 ) {
+ // We are behind (west of) GMT, subtract the offset from the time.
+ time->hour -= time->tzHour;
+ time->minute -= time->tzMinute;
+ }
+
+ AdjustTimeOverflow ( time );
+
+} // ConvertToLocalTime
+
+// -------------------------------------------------------------------------------------------------
+// CompareDateTime
+// ---------------
+
+/* class static */ int
+XMPUtils::CompareDateTime ( const XMP_DateTime & _in_left,
+ const XMP_DateTime & _in_right )
+{
+ int result = 0;
+
+ XMP_DateTime left = _in_left;
+ XMP_DateTime right = _in_right;
+
+ VerifyDateTimeFlags ( &left );
+ VerifyDateTimeFlags ( &right );
+
+ // Can't compare if one has a date and the other does not.
+ if ( left.hasDate != right.hasDate ) return 0; // Throw?
+
+ if ( left.hasTimeZone & right.hasTimeZone ) {
+ // If both times have zones then convert them to UTC, otherwise assume the same zone.
+ ConvertToUTCTime ( &left );
+ ConvertToUTCTime ( &right );
+ }
+
+ if ( left.hasDate ) {
+
+ XMP_Assert ( right.hasDate );
+
+ if ( left.year < right.year ) {
+ result = -1;
+ } else if ( left.year > right.year ) {
+ result = +1;
+ } else if ( left.month < right.month ) {
+ result = -1;
+ } else if ( left.month > right.month ) {
+ result = +1;
+ } else if ( left.day < right.day ) {
+ result = -1;
+ } else if ( left.day > right.day ) {
+ result = +1;
+ }
+
+ if ( result != 0 ) return result;
+
+ }
+
+ if ( left.hasTime & right.hasTime ) {
+
+ // Ignore the time parts if either value is date-only.
+
+ if ( left.hour < right.hour ) {
+ result = -1;
+ } else if ( left.hour > right.hour ) {
+ result = +1;
+ } else if ( left.minute < right.minute ) {
+ result = -1;
+ } else if ( left.minute > right.minute ) {
+ result = +1;
+ } else if ( left.second < right.second ) {
+ result = -1;
+ } else if ( left.second > right.second ) {
+ result = +1;
+ } else if ( left.nanoSecond < right.nanoSecond ) {
+ result = -1;
+ } else if ( left.nanoSecond > right.nanoSecond ) {
+ result = +1;
+ } else {
+ result = 0;
+ }
+
+ }
+
+ return result;
+
+} // CompareDateTime
+
+// =================================================================================================
+
+std::string& XMPUtils::Trim( std::string& string )
+{
+ size_t pos = string.find_last_not_of( *WhiteSpaceStrPtr );
+
+ if ( pos != std::string::npos ) {
+ string.erase( pos + 1 );
+ pos = string.find_first_not_of( *WhiteSpaceStrPtr );
+ if(pos != std::string::npos) string.erase(0, pos);
+ } else {
+ string.erase( string.begin(), string.end() );
+ }
+ return string;
+}
+
+std::string * XMPUtils::WhiteSpaceStrPtr = NULL;
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMPUtils.hpp b/gpr/source/lib/xmp_core/XMPUtils.hpp
new file mode 100644
index 0000000..1c99041
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMPUtils.hpp
@@ -0,0 +1,198 @@
+#ifndef __XMPUtils_hpp__
+#define __XMPUtils_hpp__
+
+// =================================================================================================
+// Copyright 2003 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h"
+#include "public/include/XMP_Const.h"
+
+#include "XMPMeta.hpp"
+#include "XMPCore_Impl.hpp"
+#include "public/include/client-glue/WXMPUtils.hpp"
+
+// -------------------------------------------------------------------------------------------------
+
+class XMPUtils {
+public:
+
+ static bool
+ Initialize(); // ! For internal use only!
+
+ static void
+ Terminate() RELEASE_NO_THROW; // ! For internal use only!
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_VarString * fullPath );
+
+ static void
+ ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_VarString * fullPath );
+
+ static void
+ ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_VarString * fullPath );
+
+ static void
+ ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ XMP_VarString * fullPath );
+
+ static void
+ ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_VarString * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ ConvertFromBool ( bool binValue,
+ XMP_VarString * strValue );
+
+ static void
+ ConvertFromInt ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ XMP_VarString * strValue );
+
+ static void
+ ConvertFromInt64 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ XMP_VarString * strValue );
+
+ static void
+ ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ XMP_VarString * strValue );
+
+ static void
+ ConvertFromDate ( const XMP_DateTime & binValue,
+ XMP_VarString * strValue );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static bool
+ ConvertToBool ( XMP_StringPtr strValue );
+
+ static XMP_Int32
+ ConvertToInt ( XMP_StringPtr strValue );
+
+ static XMP_Int64
+ ConvertToInt64 ( XMP_StringPtr strValue );
+
+ static double
+ ConvertToFloat ( XMP_StringPtr strValue );
+
+ static void
+ ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ CurrentDateTime ( XMP_DateTime * time );
+
+ static void
+ SetTimeZone ( XMP_DateTime * time );
+
+ static void
+ ConvertToUTCTime ( XMP_DateTime * time );
+
+ static void
+ ConvertToLocalTime ( XMP_DateTime * time );
+
+ static int
+ CompareDateTime ( const XMP_DateTime & left,
+ const XMP_DateTime & right );
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ XMP_VarString * encodedStr );
+
+ static void
+ DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ XMP_VarString * rawStr );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ PackageForJPEG ( const XMPMeta & xmpObj,
+ XMP_VarString * stdStr,
+ XMP_VarString * extStr,
+ XMP_VarString * digestStr );
+
+ static void
+ MergeFromJPEG ( XMPMeta * fullXMP,
+ const XMPMeta & extendedXMP );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static void
+ CatenateArrayItems ( const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_VarString * catedStr );
+
+ static void
+ SeparateArrayItems ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr );
+
+ static void
+ ApplyTemplate ( XMPMeta * workingXMP,
+ const XMPMeta & templateXMP,
+ XMP_OptionBits actions );
+
+ static void
+ RemoveProperties ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ static void
+ DuplicateSubtree ( const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ static std::string& Trim(std::string& string);
+
+ static std::string * WhiteSpaceStrPtr;
+
+}; // XMPUtils
+
+// =================================================================================================
+
+#endif // __XMPUtils_hpp__
diff --git a/gpr/source/lib/xmp_core/XMP_BuildInfo.h b/gpr/source/lib/xmp_core/XMP_BuildInfo.h
new file mode 100644
index 0000000..35fe00e
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMP_BuildInfo.h
@@ -0,0 +1,17 @@
+#ifndef __XMP_BuildInfo_h__
+#define __XMP_BuildInfo_h__ 1
+
+/*
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+*/
+
+#define kXMP_Copyright Copyright (c) 2013
+#define kXMP_CopyrightStr "Copyright (c) 2013"
+
+#endif /* __XMP_BuildInfo_h__ */
diff --git a/gpr/source/lib/xmp_core/XMP_LibUtils.cpp b/gpr/source/lib/xmp_core/XMP_LibUtils.cpp
new file mode 100644
index 0000000..507294e
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMP_LibUtils.cpp
@@ -0,0 +1,705 @@
+// =================================================================================================
+// Copyright 2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h"
+
+#include "XMP_LibUtils.hpp"
+
+#include "UnicodeInlines.incl_cpp"
+
+#include <cstdio>
+#include <cstring>
+
+// =================================================================================================
+
+#ifndef TraceThreadLocks
+ #define TraceThreadLocks 0
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+extern "C" bool Initialize_LibUtils()
+{
+ return true;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+extern "C" void Terminate_LibUtils(){
+ // Nothing to do.
+}
+
+// =================================================================================================
+// Error notifications
+// =================================================================================================
+
+bool GenericErrorCallback::CheckLimitAndSeverity ( XMP_ErrorSeverity severity ) const
+{
+
+ if ( this->limit == 0 ) return true; // Always notify if the limit is zero.
+ if ( severity < this->topSeverity ) return false; // Don't notify, don't count.
+
+ if ( severity > this->topSeverity ) {
+ this->topSeverity = severity;
+ this->notifications = 0;
+ }
+
+ this->notifications += 1;
+ return (this->notifications <= this->limit);
+
+} // GenericErrorCallback::CheckLimitAndSeverity
+
+// =================================================================================================
+
+void GenericErrorCallback::NotifyClient ( XMP_ErrorSeverity severity, XMP_Error & error, XMP_StringPtr filePath /*= 0 */ ) const
+{
+ bool notifyClient = CanNotify() && !error.IsNotified();
+ bool returnAndRecover (severity == kXMPErrSev_Recoverable);
+
+ if ( notifyClient ) {
+ error.SetNotified();
+ notifyClient = CheckLimitAndSeverity ( severity );
+ if ( notifyClient ) {
+ returnAndRecover &= ClientCallbackWrapper( filePath, severity, error.GetID(), error.GetErrMsg() );
+ }
+ }
+
+ if ( ! returnAndRecover ) XMP_Error_Throw ( error );
+
+}
+
+// =================================================================================================
+// Thread synchronization locks
+// =================================================================================================
+
+XMP_ReadWriteLock::XMP_ReadWriteLock() : beingWritten(false)
+{
+ #if XMP_DebugBuild && HaveAtomicIncrDecr
+ this->lockCount = 0;
+ // Atomic counter must be 32 or 64 bits and naturally aligned.
+ size_t counterSize = sizeof ( XMP_AtomicCounter );
+ size_t counterOffset = XMP_OffsetOf ( XMP_ReadWriteLock, lockCount );
+ XMP_Assert ( (counterSize == 4) || (counterSize == 8) ); // Counter must be 32 or 64 bits.
+ XMP_Assert ( (counterOffset & (counterSize-1)) == 0 ); // Counter must be naturally aligned.
+ #endif
+ XMP_BasicRWLock_Initialize ( this->lock );
+ #if TraceThreadLocks
+ fprintf ( stderr, "Created lock %.8X\n", this );
+ #endif
+}
+
+// ---------------------------------------------------------------------------------------------
+
+XMP_ReadWriteLock::~XMP_ReadWriteLock()
+{
+ #if TraceThreadLocks
+ fprintf ( stderr, "Deleting lock %.8X\n", this );
+ #endif
+ #if XMP_DebugBuild && HaveAtomicIncrDecr
+ XMP_Assert ( this->lockCount == 0 );
+ #endif
+ XMP_BasicRWLock_Terminate ( this->lock );
+}
+
+// ---------------------------------------------------------------------------------------------
+
+void XMP_ReadWriteLock::Acquire ( bool forWriting )
+{
+ #if TraceThreadLocks
+ fprintf ( stderr, "Acquiring lock %.8X for %s, count %d%s\n",
+ this, (forWriting ? "writing" : "reading"), this->lockCount, (this->beingWritten ? ", being written" : "") );
+ #endif
+
+ if ( forWriting ) {
+ XMP_BasicRWLock_AcquireForWrite ( this->lock );
+ #if XMP_DebugBuild && HaveAtomicIncrDecr
+ XMP_Assert ( this->lockCount == 0 );
+ #endif
+ } else {
+ XMP_BasicRWLock_AcquireForRead ( this->lock );
+ XMP_Assert ( ! this->beingWritten );
+ }
+ #if XMP_DebugBuild && HaveAtomicIncrDecr
+ XMP_AtomicIncrement ( this->lockCount );
+ #endif
+ this->beingWritten = forWriting;
+
+ #if TraceThreadLocks
+ fprintf ( stderr, "Acquired lock %.8X for %s, count %d%s\n",
+ this, (forWriting ? "writing" : "reading"), this->lockCount, (this->beingWritten ? ", being written" : "") );
+ #endif
+}
+
+// ---------------------------------------------------------------------------------------------
+
+void XMP_ReadWriteLock::Release()
+{
+ #if TraceThreadLocks
+ fprintf ( stderr, "Releasing lock %.8X, count %d%s\n", this, this->lockCount, (this->beingWritten ? ", being written" : "") );
+ #endif
+
+ #if XMP_DebugBuild && HaveAtomicIncrDecr
+ XMP_Assert ( this->lockCount > 0 );
+ XMP_AtomicDecrement ( this->lockCount ); // ! Do these before unlocking, that might release a waiting thread.
+ #endif
+ bool forWriting = this->beingWritten;
+ this->beingWritten = false;
+
+ if ( forWriting ) {
+ XMP_BasicRWLock_ReleaseFromWrite ( this->lock );
+ } else {
+ XMP_BasicRWLock_ReleaseFromRead ( this->lock );
+ }
+
+ #if TraceThreadLocks
+ fprintf ( stderr, "Released lock %.8X, count %d%s\n", this, this->lockCount, (this->beingWritten ? ", being written" : "") );
+ #endif
+}
+
+// =================================================================================================
+
+#if UseHomeGrownLock
+
+ #if XMP_MacBuild | XMP_UNIXBuild | XMP_iOSBuild
+
+ // -----------------------------------------------------------------------------------------
+
+ // About pthread mutexes and conditions:
+ //
+ // The mutex protecting the condition must be locked before waiting for the condition. A
+ // thread can wait for a condition to be signaled by calling the pthread_cond_wait
+ // subroutine. The subroutine atomically unlocks the mutex and blocks the calling thread
+ // until the condition is signaled. When the call returns, the mutex is locked again.
+
+ #define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); }
+ #define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); }
+
+ #define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); }
+ #define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); }
+
+ #define InitializeBasicQueue(queue) { int err = pthread_cond_init ( &queue, 0 ); XMP_Enforce ( err == 0 ); }
+ #define TerminateBasicQueue(queue) { int err = pthread_cond_destroy ( &queue ); XMP_Enforce ( err == 0 ); }
+
+ #define WaitOnBasicQueue(queue,mutex) { int err = pthread_cond_wait ( &queue, &mutex ); XMP_Enforce ( err == 0 ); }
+ #define ReleaseOneBasicQueue(queue) { int err = pthread_cond_signal ( &queue ); XMP_Enforce ( err == 0 ); }
+ #define ReleaseAllBasicQueue(queue) { int err = pthread_cond_broadcast ( &queue ); XMP_Enforce ( err == 0 ); }
+
+ // -----------------------------------------------------------------------------------------
+
+ #elif XMP_WinBuild
+
+ // -----------------------------------------------------------------------------------------
+
+ #define InitializeBasicMutex(mutex) { InitializeCriticalSection ( &mutex ); }
+ #define TerminateBasicMutex(mutex) { DeleteCriticalSection ( &mutex ); }
+
+ #define AcquireBasicMutex(mutex) { EnterCriticalSection ( &mutex ); }
+ #define ReleaseBasicMutex(mutex) { LeaveCriticalSection ( &mutex ); }
+
+ #if ! BuildLocksForWinXP
+
+ // About Win32 condition variables (not on XP):
+ //
+ // Condition variables enable threads to atomically release a lock and enter the
+ // sleeping state. They can be used with critical sections or slim reader/writer (SRW)
+ // locks. Condition variables support operations that "wake one" or "wake all" waiting
+ // threads. After a thread is woken, it re-acquires the lock it released when the thread
+ // entered the sleeping state.
+
+ #define InitializeBasicQueue(queue) { InitializeConditionVariable ( &queue ); }
+ #define TerminateBasicQueue(queue) /* Do nothing. */
+
+ #define WaitOnBasicQueue(queue,mutex) \
+ { BOOL ok = SleepConditionVariableCS ( &queue, &mutex, INFINITE /* timeout */ ); XMP_Enforce ( ok ); }
+
+ #define ReleaseOneBasicQueue(queue) { WakeConditionVariable ( &queue ); }
+ #define ReleaseAllBasicQueue(queue) { WakeAllConditionVariable ( &queue ); }
+
+ #else
+
+ // Need to create our own queue for Windows XP. This is not a general queue, it depends
+ // on the usage inside XMP_HomeGrownLock where the queueMutex guarantees that the
+ // queueing operations are done single threaded.
+
+ #define InitializeBasicQueue(queue) /* Do nothing. */
+ #define TerminateBasicQueue(queue) /* Do nothing. */
+
+ #define WaitOnBasicQueue(queue,mutex) { queue.Wait ( mutex ); }
+ #define ReleaseOneBasicQueue(queue) { queue.ReleaseOne(); }
+ #define ReleaseAllBasicQueue(queue) { queue.ReleaseAll(); }
+
+ // -------------------------------------------------------------------------------------
+
+ XMP_WinXP_HGQueue::XMP_WinXP_HGQueue() : queueEvent(0), waitCount(0), releaseAll(false)
+ {
+ this->queueEvent = CreateEvent ( NULL, FALSE, TRUE, NULL ); // Auto reset, initially clear.
+ XMP_Enforce ( this->queueEvent != 0 );
+ }
+
+ // -------------------------------------------------------------------------------------
+
+ XMP_WinXP_HGQueue::~XMP_WinXP_HGQueue()
+ {
+ CloseHandle ( this->queueEvent );
+ }
+
+ // -------------------------------------------------------------------------------------
+
+ void XMP_WinXP_HGQueue::Wait ( XMP_BasicMutex & queueMutex )
+ {
+ ++this->waitCount; // ! Does not need atomic increment, protected by queue mutex.
+ ReleaseBasicMutex ( queueMutex );
+ DWORD status = WaitForSingleObject ( this->queueEvent, INFINITE );
+ if ( status != WAIT_OBJECT_0 ) XMP_Throw ( "Failure from WaitForSingleObject", kXMPErr_ExternalFailure );
+ AcquireBasicMutex ( queueMutex );
+ --this->waitCount; // ! Does not need atomic decrement, protected by queue mutex.
+
+ if ( this->releaseAll ) {
+ if ( this->waitCount == 0 ) {
+ this->releaseAll = false;
+ } else {
+ BOOL ok = SetEvent ( this->queueEvent );
+ if ( ! ok ) XMP_Throw ( "Failure from SetEvent", kXMPErr_ExternalFailure );
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+
+ void XMP_WinXP_HGQueue::ReleaseOne()
+ {
+ XMP_Assert ( ! this->releaseAll );
+ BOOL ok = SetEvent ( this->queueEvent );
+ if ( ! ok ) XMP_Throw ( "Failure from SetEvent", kXMPErr_ExternalFailure );
+ }
+
+ // -------------------------------------------------------------------------------------
+
+ void XMP_WinXP_HGQueue::ReleaseAll()
+ {
+ this->releaseAll = true;
+ BOOL ok = SetEvent ( this->queueEvent );
+ if ( ! ok ) XMP_Throw ( "Failure from SetEvent", kXMPErr_ExternalFailure );
+ }
+
+ #endif
+
+ // -----------------------------------------------------------------------------------------
+
+ #endif
+
+ // =============================================================================================
+
+ XMP_HomeGrownLock::XMP_HomeGrownLock() : lockCount(0), readersWaiting(0), writersWaiting(0), beingWritten(false)
+ {
+ InitializeBasicMutex ( this->queueMutex );
+ InitializeBasicQueue ( this->writerQueue );
+ InitializeBasicQueue ( this->readerQueue );
+ }
+
+ // =============================================================================================
+
+ XMP_HomeGrownLock::~XMP_HomeGrownLock()
+ {
+ TerminateBasicMutex ( this->queueMutex );
+ TerminateBasicQueue ( this->writerQueue );
+ TerminateBasicQueue ( this->readerQueue );
+ }
+
+ // =============================================================================================
+
+ void XMP_HomeGrownLock::AcquireForRead()
+ {
+ XMP_AutoMutex autoMutex ( &this->queueMutex );
+
+ ++this->readersWaiting; // ! Does not need atomic increment, protected by queue mutex.
+ while ( (this->beingWritten) || (this->writersWaiting > 0) ) {
+ // Don't allow more readers if writers are waiting.
+ WaitOnBasicQueue ( this->readerQueue, this->queueMutex );
+ }
+ --this->readersWaiting; // ! Does not need atomic decrement, protected by queue mutex.
+ XMP_Assert ( ! this->beingWritten );
+
+ ++this->lockCount; // ! Does not need atomic increment, protected by queue mutex.
+ }
+
+ // =============================================================================================
+
+ void XMP_HomeGrownLock::AcquireForWrite()
+ {
+ XMP_AutoMutex autoMutex ( &this->queueMutex );
+
+ ++this->writersWaiting; // ! Does not need atomic increment, protected by queue mutex.
+ while ( this->lockCount > 0 ) {
+ WaitOnBasicQueue ( this->writerQueue, this->queueMutex );
+ }
+ --this->writersWaiting; // ! Does not need atomic decrement, protected by queue mutex.
+ XMP_Assert ( (! this->beingWritten) && (this->lockCount == 0) );
+
+ ++this->lockCount; // ! Does not need atomic increment, protected by queue mutex.
+ this->beingWritten = true;
+ }
+
+ // =============================================================================================
+
+ void XMP_HomeGrownLock::ReleaseFromRead()
+ {
+ XMP_AutoMutex autoMutex ( &this->queueMutex );
+
+ XMP_Assert ( (! this->beingWritten) && (this->lockCount > 0) );
+ --this->lockCount; // ! Does not need atomic decrement, protected by queue mutex.
+
+ if ( this->writersWaiting > 0 ) {
+ ReleaseOneBasicQueue ( this->writerQueue );
+ } else if ( this->readersWaiting > 0 ) {
+ ReleaseAllBasicQueue ( this->readerQueue );
+ }
+
+ }
+
+ // =============================================================================================
+
+ void XMP_HomeGrownLock::ReleaseFromWrite()
+ {
+ XMP_AutoMutex autoMutex ( &this->queueMutex );
+
+ XMP_Assert ( this->beingWritten && (this->lockCount == 1) );
+ --this->lockCount; // ! Does not need atomic decrement, protected by queue mutex.
+ this->beingWritten = false;
+
+ if ( this->writersWaiting > 0 ) {
+ ReleaseOneBasicQueue ( this->writerQueue );
+ } else if ( this->readersWaiting > 0 ) {
+ ReleaseAllBasicQueue ( this->readerQueue );
+ }
+ }
+
+ // =============================================================================================
+
+#endif
+
+// =================================================================================================
+// Data structure dumping utilities
+// ================================
+
+void
+DumpClearString ( const XMP_VarString & value, XMP_TextOutputProc outProc, void * refCon )
+{
+
+ char buffer [20];
+ bool prevNormal;
+ XMP_Status status = 0;
+
+ XMP_StringPtr spanStart, spanEnd;
+ XMP_StringPtr valueEnd = &value[0] + value.size();
+
+ spanStart = &value[0];
+ while ( spanStart < valueEnd ) {
+
+ // Output the next span of regular characters.
+ for ( spanEnd = spanStart; spanEnd < valueEnd; ++spanEnd ) {
+ if ( *spanEnd > 0x7F ) break;
+ if ( (*spanEnd < 0x20) && (*spanEnd != kTab) && (*spanEnd != kLF) ) break;
+ }
+ if ( spanStart != spanEnd ) status = (*outProc) ( refCon, spanStart, (XMP_StringLen)(spanEnd-spanStart) );
+ if ( status != 0 ) break;
+ spanStart = spanEnd;
+
+ // Output the next span of irregular characters.
+ prevNormal = true;
+ for ( spanEnd = spanStart; spanEnd < valueEnd; ++spanEnd ) {
+ if ( ((0x20 <= *spanEnd) && (*spanEnd <= 0x7F)) || (*spanEnd == kTab) || (*spanEnd == kLF) ) break;
+ char space = ' ';
+ if ( prevNormal ) space = '<';
+ status = (*outProc) ( refCon, &space, 1 );
+ if ( status != 0 ) break;
+ OutProcHexByte ( *spanEnd );
+ prevNormal = false;
+ }
+ if ( ! prevNormal ) {
+ status = (*outProc) ( refCon, ">", 1 );
+ if ( status != 0 ) return;
+ }
+ spanStart = spanEnd;
+
+ }
+
+} // DumpClearString
+
+// -------------------------------------------------------------------------------------------------
+
+static void
+DumpStringMap ( const XMP_StringMap & map, XMP_StringPtr label, XMP_TextOutputProc outProc, void * refCon )
+{
+ XMP_cStringMapPos currPos;
+ XMP_cStringMapPos endPos = map.end();
+
+ size_t maxLen = 0;
+ for ( currPos = map.begin(); currPos != endPos; ++currPos ) {
+ size_t currLen = currPos->first.size();
+ if ( currLen > maxLen ) maxLen = currLen;
+ }
+
+ OutProcNewline();
+ OutProcLiteral ( label );
+ OutProcNewline();
+
+ for ( currPos = map.begin(); currPos != endPos; ++currPos ) {
+ OutProcNChars ( " ", 2 );
+ DumpClearString ( currPos->first, outProc, refCon );
+ OutProcPadding ( maxLen - currPos->first.size() );
+ OutProcNChars ( " => ", 4 );
+ DumpClearString ( currPos->second, outProc, refCon );
+ OutProcNewline();
+ }
+
+} // DumpStringMap
+
+// =================================================================================================
+// Namespace Tables
+// =================================================================================================
+
+XMP_NamespaceTable::XMP_NamespaceTable ( const XMP_NamespaceTable & presets )
+{
+ XMP_AutoLock presetLock ( &presets.lock, kXMP_ReadLock );
+
+ this->uriToPrefixMap = presets.uriToPrefixMap;
+ this->prefixToURIMap = presets.prefixToURIMap;
+
+} // XMP_NamespaceTable::XMP_NamespaceTable
+
+// =================================================================================================
+
+bool XMP_NamespaceTable::Define ( XMP_StringPtr _uri, XMP_StringPtr _suggPrefix,
+ XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen )
+{
+ XMP_AutoLock tableLock ( &this->lock, kXMP_WriteLock );
+ bool prefixMatches = false;
+
+ XMP_Assert ( (_uri != 0) && (*_uri != 0) && (_suggPrefix != 0) && (*_suggPrefix != 0) );
+
+ XMP_VarString uri ( _uri );
+ XMP_VarString suggPrefix ( _suggPrefix );
+ if ( suggPrefix[suggPrefix.size()-1] != ':' ) suggPrefix += ':';
+ VerifySimpleXMLName ( _suggPrefix, _suggPrefix+suggPrefix.size()-1 ); // Exclude the colon.
+
+ XMP_StringMapPos uriPos = this->uriToPrefixMap.find ( uri );
+
+ if ( uriPos == this->uriToPrefixMap.end() ) {
+
+ // The URI is not yet registered, make sure we use a unique prefix.
+
+ XMP_VarString uniqPrefix ( suggPrefix );
+ int suffix = 0;
+ char buffer [32]; // AUDIT: Plenty of room for the "_%d_" suffix.
+
+ while ( true ) {
+ if ( this->prefixToURIMap.find ( uniqPrefix ) == this->prefixToURIMap.end() ) break;
+ ++suffix;
+ snprintf ( buffer, sizeof(buffer), "_%d_:", suffix ); // AUDIT: Using sizeof for snprintf length is safe.
+ uniqPrefix = suggPrefix;
+ uniqPrefix.erase ( uniqPrefix.size()-1 ); // ! Remove the trailing ':'.
+ uniqPrefix += buffer;
+ }
+
+ // Add the new namespace to both maps.
+
+ XMP_StringPair newNS ( uri, uniqPrefix );
+ uriPos = this->uriToPrefixMap.insert ( this->uriToPrefixMap.end(), newNS );
+
+ newNS.first.swap ( newNS.second );
+ (void) this->prefixToURIMap.insert ( this->prefixToURIMap.end(), newNS );
+
+ }
+
+ // Return the actual prefix and see if it matches the suggested prefix.
+
+ if ( prefixPtr != 0 ) *prefixPtr = uriPos->second.c_str();
+ if ( prefixLen != 0 ) *prefixLen = (XMP_StringLen)uriPos->second.size();
+
+ prefixMatches = ( uriPos->second == suggPrefix );
+ return prefixMatches;
+
+} // XMP_NamespaceTable::Define
+
+// =================================================================================================
+
+bool XMP_NamespaceTable::GetPrefix ( XMP_StringPtr _uri, XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen ) const
+{
+ XMP_AutoLock tableLock ( &this->lock, kXMP_ReadLock );
+ bool found = false;
+
+ XMP_Assert ( (_uri != 0) && (*_uri != 0) );
+
+ XMP_VarString uri ( _uri );
+ XMP_cStringMapPos uriPos = this->uriToPrefixMap.find ( uri );
+
+ if ( uriPos != this->uriToPrefixMap.end() ) {
+ if ( prefixPtr != 0 ) *prefixPtr = uriPos->second.c_str();
+ if ( prefixLen != 0 ) *prefixLen = (XMP_StringLen)uriPos->second.size();
+ found = true;
+ }
+
+ return found;
+
+} // XMP_NamespaceTable::GetPrefix
+
+// =================================================================================================
+
+bool XMP_NamespaceTable::GetURI ( XMP_StringPtr _prefix, XMP_StringPtr * uriPtr, XMP_StringLen * uriLen ) const
+{
+ XMP_AutoLock tableLock ( &this->lock, kXMP_ReadLock );
+
+ bool found = false;
+
+ XMP_Assert ( (_prefix != 0) && (*_prefix != 0) );
+
+ XMP_VarString prefix ( _prefix );
+ if ( prefix[prefix.size()-1] != ':' ) prefix += ':';
+ XMP_cStringMapPos prefixPos = this->prefixToURIMap.find ( prefix );
+
+ if ( prefixPos != this->prefixToURIMap.end() ) {
+ if ( uriPtr != 0 ) *uriPtr = prefixPos->second.c_str();
+ if ( uriLen != 0 ) *uriLen = (XMP_StringLen)prefixPos->second.size();
+ found = true;
+ }
+
+ return found;
+
+} // XMP_NamespaceTable::GetURI
+
+// =================================================================================================
+
+void XMP_NamespaceTable::Dump ( XMP_TextOutputProc outProc, void * refCon ) const
+{
+ XMP_AutoLock tableLock ( &this->lock, kXMP_ReadLock );
+
+ XMP_cStringMapPos p2uEnd = this->prefixToURIMap.end(); // ! Move up to avoid gcc complaints.
+ XMP_cStringMapPos u2pEnd = this->uriToPrefixMap.end();
+
+ DumpStringMap ( this->prefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon );
+
+ if ( this->prefixToURIMap.size() != this->uriToPrefixMap.size() ) {
+ OutProcLiteral ( "** bad namespace map sizes **" );
+ XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
+ }
+
+ for ( XMP_cStringMapPos nsLeft = this->prefixToURIMap.begin(); nsLeft != p2uEnd; ++nsLeft ) {
+
+ XMP_cStringMapPos nsOther = this->uriToPrefixMap.find ( nsLeft->second );
+ if ( (nsOther == u2pEnd) || (nsLeft != this->prefixToURIMap.find ( nsOther->second )) ) {
+ OutProcLiteral ( " ** bad namespace URI ** " );
+ DumpClearString ( nsLeft->second, outProc, refCon );
+ break;
+ }
+
+ for ( XMP_cStringMapPos nsRight = nsLeft; nsRight != p2uEnd; ++nsRight ) {
+ if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+!
+ if ( nsLeft->second == nsRight->second ) {
+ OutProcLiteral ( " ** duplicate namespace URI ** " );
+ DumpClearString ( nsLeft->second, outProc, refCon );
+ break;
+ }
+ }
+
+ }
+
+ for ( XMP_cStringMapPos nsLeft = this->uriToPrefixMap.begin(); nsLeft != u2pEnd; ++nsLeft ) {
+
+ XMP_cStringMapPos nsOther = this->prefixToURIMap.find ( nsLeft->second );
+ if ( (nsOther == p2uEnd) || (nsLeft != this->uriToPrefixMap.find ( nsOther->second )) ) {
+ OutProcLiteral ( " ** bad namespace prefix ** " );
+ DumpClearString ( nsLeft->second, outProc, refCon );
+ break;
+ }
+
+ for ( XMP_cStringMapPos nsRight = nsLeft; nsRight != u2pEnd; ++nsRight ) {
+ if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+!
+ if ( nsLeft->second == nsRight->second ) {
+ OutProcLiteral ( " ** duplicate namespace prefix ** " );
+ DumpClearString ( nsLeft->second, outProc, refCon );
+ break;
+ }
+ }
+
+ }
+
+} // XMP_NamespaceTable::Dump
+
+// =================================================================================================
+static XMP_Bool matchdigit ( XMP_StringPtr text ) {
+ if ( *text >= '0' && *text <= '9' )
+ return true;
+ return false;
+}
+
+static XMP_Bool matchUpperCase ( XMP_StringPtr text ) {
+ if ( *text >= 'A' && *text <= 'Z' )
+ return true;
+ return false;
+}
+
+static XMP_Bool matchLowerCase ( XMP_StringPtr text ) {
+ if ( *text >= 'a' && *text <= 'z' )
+ return true;
+ return false;
+}
+
+/* matchhere: search for regexp at beginning of text */
+static XMP_Bool matchhere ( XMP_StringPtr regexp, XMP_StringPtr text ) {
+ if ( regexp[0] == '\0' )
+ return true;
+ if ( regexp[0] == '\\' ) {
+ if ( regexp[1] == 'd' ) {
+ if ( matchdigit(text) )
+ return matchhere ( regexp+2, text+1 );
+ else
+ return false;
+ }
+ else if ( regexp[1] == 'W' ) {
+ if ( matchUpperCase(text) )
+ return matchhere ( regexp+2, text+1 );
+ else
+ return false;
+ }
+ else if ( regexp[1] == 'w' ) {
+ if ( matchLowerCase(text) )
+ return matchhere ( regexp+2, text+1 );
+ else
+ return false;
+ }
+ }
+
+ if ( regexp[0] == '$' && regexp[1] == '\0' )
+ return *text == '\0';
+
+ if ( *text != '\0' && regexp[0] == *text )
+ return matchhere ( regexp+1, text+1 );
+ return 0;
+}
+
+/* match: search for regexp anywhere in text */
+static XMP_Bool match ( XMP_StringPtr regexp, XMP_StringPtr text ) {
+ if ( regexp[0] == '^' )
+ return matchhere ( regexp+1, text );
+ do { /* must look even if string is empty */
+ if ( matchhere ( regexp, text ) )
+ return true;
+ } while ( *text++ != '\0' );
+ return false;
+}
+
+XMP_Bool XMP_RegExp::Match ( XMP_StringPtr s )
+{
+ if ( regExpStr.size() == 0 )
+ return true;
+ if ( s == NULL )
+ return false;
+ return match ( this->regExpStr.c_str(), s );
+}
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/XMP_LibUtils.hpp b/gpr/source/lib/xmp_core/XMP_LibUtils.hpp
new file mode 100644
index 0000000..b7a9e8f
--- /dev/null
+++ b/gpr/source/lib/xmp_core/XMP_LibUtils.hpp
@@ -0,0 +1,619 @@
+#ifndef __XMP_LibUtils_hpp__
+#define __XMP_LibUtils_hpp__ 1
+
+// =================================================================================================
+// Copyright 2009 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! Must be the first include.
+#include "public/include/XMP_Const.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#if XMP_DebugBuild
+ #include <cassert>
+#endif
+
+#if XMP_WinBuild
+ #ifndef snprintf
+ #define snprintf _snprintf
+ #endif
+#endif
+
+// =================================================================================================
+// Basic types, constants
+// ======================
+
+#define kTab ((char)0x09)
+#define kLF ((char)0x0A)
+#define kCR ((char)0x0D)
+
+#if XMP_WinBuild
+ #define kDirChar '\\'
+#else
+ #define kDirChar '/'
+#endif
+
+typedef std::string XMP_VarString;
+
+#define EliminateGlobal(g) delete ( g ); g = 0
+
+extern "C" bool Initialize_LibUtils();
+extern "C" void Terminate_LibUtils();
+
+#define IgnoreParam(p) (void)p
+
+// The builtin offsetof macro sometimes violates C++ data member rules.
+#define XMP_OffsetOf(struct,field) ( (char*)(&((struct*)0x100)->field) - (char*)0x100 )
+
+// =================================================================================================
+// Support for exceptions and asserts
+// ==================================
+
+#define AnnounceThrow(msg) /* Do nothing. */
+#define AnnounceCatch(msg) /* Do nothing. */
+
+#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); }
+
+#if XMP_DebugBuild
+#define XMP_Throw_Verbose(msg,e,id) \
+{ \
+ char tmpMsg[255]; \
+ snprintf(tmpMsg, sizeof(tmpMsg), #msg "( %d )", e); \
+ XMP_Throw( tmpMsg, id); \
+}
+#else
+ #define XMP_Throw_Verbose(msg,e,id) XMP_Throw(msg, id)
+#endif
+
+class GenericErrorCallback {
+public:
+ // Abstract base class for XMPCore and XMPFiles internal error notification support. Needed so
+ // that the XMLParserAdapter (used by both XMPCore and XMPFiles) can send error notifications,
+ // and so that utility parts of just XMPCore or XMPFiles can avoid dependence on XMPCore.hpp or
+ // XMPFiles.hpp if that is appropriate.
+
+ XMP_Uns32 limit;
+ mutable XMP_Uns32 notifications;
+ mutable XMP_ErrorSeverity topSeverity;
+
+ GenericErrorCallback() : notifications(0), limit(1), topSeverity(kXMPErrSev_Recoverable) {};
+ virtual ~GenericErrorCallback() {};
+
+ void Clear() { this->notifications = 0; this->limit = 1; this->topSeverity = kXMPErrSev_Recoverable; };
+
+ bool CheckLimitAndSeverity (XMP_ErrorSeverity severity ) const;
+
+ // Const so they can be used with const XMPMeta and XMPFiles objects.
+ void NotifyClient ( XMP_ErrorSeverity severity, XMP_Error & error, XMP_StringPtr filePath = 0 ) const;
+
+ virtual bool CanNotify ( ) const = 0;
+ virtual bool ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const = 0;
+
+};
+
+#define XMP_Error_Throw(error) { AnnounceThrow (error.GetErrMsg()); throw error; }
+
+
+// -------------------------------------------------------------------------------------------------
+
+#define _MakeStr(p) #p
+#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l)
+#define _ExplicitMsg(msg,c,e) #e " " #msg ": " #c
+
+#define XMP_Validate(c,msg,e) \
+ if ( ! (c) ) { \
+ const char * validate_msg = _ExplicitMsg ( msg, c, e ); \
+ XMP_Throw ( validate_msg, e ); \
+ }
+
+// This statement is needed in XMP_Assert definition to reduce warnings from
+// static analysis tool in Visual Studio. Defined here, as platform fork not
+// possible within macro definition below
+#if XMP_WinBuild
+ #define analysis_assume(c) __analysis_assume( c );
+#else
+ #define analysis_assume(c) ((void) 0)
+#endif
+
+#if ! XMP_DebugBuild
+ #define XMP_Assert(c) ((void) 0)
+#else
+ #define XMP_Assert(c) assert ( c )
+#endif
+
+ #define XMP_Enforce(c) \
+ if ( ! (c) ) { \
+ const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \
+ XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \
+ }
+// =================================================================================================
+// Thread synchronization locks
+// ============================
+
+// About XMP and thread synchronization
+//
+// A variety of choices are provided for thread synchronization. Exactly one method must be chosen
+// by defining the appropriate symbol to 1.
+//
+// * UseNoLock - This choice turns the synchronization functions into no-ops. It must only be used
+// by single threaded clients, or clients providing their own control at a higher level.
+//
+// * UseGlobalLibraryLock - This choice uses a single per-library lock. The result is thread safe
+// but unfriendly behavior, no true concurrency. This should only be used as a debugging fallback.
+//
+// * UseBoostLock - This choice uses the Boost shared_mutex mechanism. It has the advantage of being
+// robust and being available on pretty much all platforms. It has the disadvantage of requiring
+// the developer to download, integrate, and build the Boost thread library.
+//
+// * UsePThreadLock - This choice uses the POSIX pthread rwlock mechanism. It has the advantage of
+// being robust and being available on any modern UNIX platform, including Mac OS X.
+//
+// * UseWinSlimLock - This choice uses the Windows slim reader/writer mechanism. It is robust but
+// only available on Vista and newer versions of Windows, it is not available on XP.
+//
+// * UseHomeGrownLock - This choice uses local code plus lower level synchronization primitives. It
+// has the advantage of being usable on all platforms, and having exposed and tunable policy. It
+// has the disadvantage of possibly being less robust than Boost or the O/S provided mechanisms.
+// The lower level synchronization primitives are pthread mutex and condition for UNIX (including
+// Mac OS X). For Windows there is a choice of critical section and condition variable for Vista
+// and newer; or critical section, event, and semaphore for XP and newer.
+
+#define UseNoLock 1
+
+// -------------------------------------------------------------------------------------------------
+// A basic exclusive access mutex and atomic increment/decrement operations.
+
+#if XMP_WinBuild
+
+ #include <Windows.h>
+
+ #define HaveAtomicIncrDecr 1
+ typedef LONG XMP_AtomicCounter;
+
+ #define XMP_AtomicIncrement(x) InterlockedIncrement ( &(x) )
+ #define XMP_AtomicDecrement(x) InterlockedDecrement ( &(x) )
+
+ typedef CRITICAL_SECTION XMP_BasicMutex;
+
+ #define InitializeBasicMutex(mutex) { InitializeCriticalSection ( &mutex ); }
+ #define TerminateBasicMutex(mutex) { DeleteCriticalSection ( &mutex ); }
+ #define AcquireBasicMutex(mutex) { EnterCriticalSection ( &mutex ); }
+ #define ReleaseBasicMutex(mutex) { LeaveCriticalSection ( &mutex ); }
+
+#elif XMP_MacBuild | XMP_iOSBuild
+
+ #include <pthread.h>
+ #include <libkern/OSAtomic.h>
+
+ #define HaveAtomicIncrDecr 1
+ typedef int32_t XMP_AtomicCounter;
+
+ #define XMP_AtomicIncrement(x) OSAtomicIncrement32 ( &(x) )
+ #define XMP_AtomicDecrement(x) OSAtomicDecrement32 ( &(x) )
+
+ typedef pthread_mutex_t XMP_BasicMutex;
+
+ #define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); }
+ #define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); }
+ #define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); }
+ #define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); }
+
+#elif XMP_UNIXBuild
+
+ #include <pthread.h>
+
+ // Atomic increment/decrement intrinsics should be in gcc 4.1, but Solaris seems to lack them.
+ #ifndef HaveAtomicIncrDecr
+ #define HaveAtomicIncrDecr 1
+ #endif
+ #if HaveAtomicIncrDecr
+ typedef XMP_Uns32 XMP_AtomicCounter;
+ #define XMP_AtomicIncrement(x) __sync_add_and_fetch ( &(x), 1 )
+ #define XMP_AtomicDecrement(x) __sync_sub_and_fetch ( &(x), 1 )
+ #endif
+
+ typedef pthread_mutex_t XMP_BasicMutex;
+
+ #define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); }
+ #define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); }
+ #define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); }
+ #define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); }
+
+#elif XMP_BanzaiBuild
+
+ #include <rtos_mutex.h>
+
+ // Atomic increment/decrement intrinsics should be in gcc 4.1, but Solaris seems to lack them.
+ #ifndef HaveAtomicIncrDecr
+ #define HaveAtomicIncrDecr 1
+ #endif
+ #if HaveAtomicIncrDecr
+ typedef XMP_Uns32 XMP_AtomicCounter;
+ #define XMP_AtomicIncrement(x) __sync_add_and_fetch ( &(x), 1 )
+ #define XMP_AtomicDecrement(x) __sync_sub_and_fetch ( &(x), 1 )
+ #endif
+
+ typedef rtos_mutex_t XMP_BasicMutex;
+
+ #define InitializeBasicMutex(mutex) { int err = rtos_mutex_create ( &mutex, "mutex"); XMP_Enforce ( err == 0 ); }
+ #define TerminateBasicMutex(mutex) { int err = rtos_mutex_delete ( &mutex ); XMP_Enforce ( err == 0 ); }
+ #define AcquireBasicMutex(mutex) { int err = rtos_mutex_acquire ( &mutex, RTOS_WAIT_FOREVER ); XMP_Enforce ( err == 0 ); }
+ #define ReleaseBasicMutex(mutex) { int err = rtos_mutex_release ( &mutex ); XMP_Enforce ( err == 0 ); }
+
+#endif
+
+class XMP_AutoMutex {
+public:
+ XMP_AutoMutex ( XMP_BasicMutex * _mutex ) : mutex(_mutex) { AcquireBasicMutex ( *this->mutex ); }
+ ~XMP_AutoMutex() { this->Release(); }
+ void Release() { if ( this->mutex != 0 ) ReleaseBasicMutex ( *this->mutex ); this->mutex = 0; }
+private:
+ XMP_BasicMutex * mutex;
+ XMP_AutoMutex() {}; // ! Must not be used.
+};
+
+// -------------------------------------------------------------------------------------------------
+// Details for the various locking mechanisms.
+
+#if UseNoLock
+
+ typedef void* XMP_BasicRWLock; // For single threaded clients that want maximum performance.
+
+ #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
+
+ #define XMP_BasicRWLock_AcquireForRead(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_AcquireForWrite(lck) /* Do nothing. */
+
+ #define XMP_BasicRWLock_ReleaseFromRead(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_ReleaseFromWrite(lck) /* Do nothing. */
+
+#elif UseGlobalLibraryLock
+
+ extern XMP_BasicMutex sLibraryLock;
+
+ typedef void* XMP_BasicRWLock; // Use the old thread-unfriendly per-DLL mutex.
+
+ #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
+
+ #define XMP_BasicRWLock_AcquireForRead(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_AcquireForWrite(lck) /* Do nothing. */
+
+ #define XMP_BasicRWLock_ReleaseFromRead(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_ReleaseFromWrite(lck) /* Do nothing. */
+
+#elif UseBoostLock
+
+ #include <boost/thread/shared_mutex.hpp>
+ typedef boost::shared_mutex XMP_BasicRWLock;
+
+ #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
+
+ #define XMP_BasicRWLock_AcquireForRead(lck) lck.lock_shared()
+ #define XMP_BasicRWLock_AcquireForWrite(lck) lck.lock()
+
+ #define XMP_BasicRWLock_ReleaseFromRead(lck) lck.unlock_shared()
+ #define XMP_BasicRWLock_ReleaseFromWrite(lck) lck.unlock()
+
+#elif UsePThreadLock
+
+ #include <pthread.h>
+ typedef pthread_rwlock_t XMP_BasicRWLock;
+
+ #define XMP_BasicRWLock_Initialize(lck) \
+ { int err = pthread_rwlock_init ( &lck, 0 ); \
+ if ( err != 0 ) XMP_Throw ( "Initialize pthread rwlock failed", kXMPErr_ExternalFailure ); }
+ #define XMP_BasicRWLock_Terminate(lck) \
+ { int err = pthread_rwlock_destroy ( &lck ); XMP_Assert ( err == 0 ); }
+
+ #define XMP_BasicRWLock_AcquireForRead(lck) \
+ { int err = pthread_rwlock_rdlock ( &lck ); \
+ if ( err != 0 ) XMP_Throw ( "Acquire pthread read lock failed", kXMPErr_ExternalFailure ); }
+ #define XMP_BasicRWLock_AcquireForWrite(lck) \
+ { int err = pthread_rwlock_wrlock ( &lck ); \
+ if ( err != 0 ) XMP_Throw ( "Acquire pthread write lock failed", kXMPErr_ExternalFailure ); }
+
+ #define XMP_BasicRWLock_ReleaseFromRead(lck) \
+ { int err = pthread_rwlock_unlock ( &lck ); \
+ if ( err != 0 ) XMP_Throw ( "Release pthread read lock failed", kXMPErr_ExternalFailure ); }
+ #define XMP_BasicRWLock_ReleaseFromWrite(lck) \
+ { int err = pthread_rwlock_unlock ( &lck ); \
+ if ( err != 0 ) XMP_Throw ( "Release pthread write lock failed", kXMPErr_ExternalFailure ); }
+
+#elif UseWinSlimLock
+
+ #include <Windows.h>
+ typedef SRWLOCK XMP_BasicRWLock;
+
+ #define XMP_BasicRWLock_Initialize(lck) InitializeSRWLock ( &lck )
+ #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
+
+ #define XMP_BasicRWLock_AcquireForRead(lck) AcquireSRWLockShared ( &lck )
+ #define XMP_BasicRWLock_AcquireForWrite(lck) AcquireSRWLockExclusive ( &lck )
+
+ #define XMP_BasicRWLock_ReleaseFromRead(lck) ReleaseSRWLockShared ( &lck )
+ #define XMP_BasicRWLock_ReleaseFromWrite(lck) ReleaseSRWLockExclusive ( &lck )
+
+#elif UseHomeGrownLock
+
+ class XMP_HomeGrownLock;
+ typedef XMP_HomeGrownLock XMP_BasicRWLock;
+
+ #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
+ #define XMP_BasicRWLock_AcquireForRead(lck) lck.AcquireForRead()
+ #define XMP_BasicRWLock_AcquireForWrite(lck) lck.AcquireForWrite()
+ #define XMP_BasicRWLock_ReleaseFromRead(lck) lck.ReleaseFromRead()
+ #define XMP_BasicRWLock_ReleaseFromWrite(lck) lck.ReleaseFromWrite()
+
+ #if XMP_MacBuild | XMP_UNIXBuild | XMP_iOSBuild
+
+ #include <pthread.h>
+
+ typedef pthread_cond_t XMP_BasicQueue;
+
+ #elif XMP_WinBuild
+
+ #include <Windows.h>
+ #ifndef BuildLocksForWinXP
+ #define BuildLocksForWinXP 1
+ #endif
+
+ #if ! BuildLocksForWinXP
+ typedef CONDITION_VARIABLE XMP_BasicQueue; // ! Requires Vista or newer.
+ #else
+ class XMP_WinXP_HGQueue {
+ public:
+ XMP_WinXP_HGQueue();
+ ~XMP_WinXP_HGQueue();
+ void Wait ( XMP_BasicMutex & queueMutex );
+ void ReleaseOne();
+ void ReleaseAll();
+ private:
+ HANDLE queueEvent;
+ volatile XMP_Uns32 waitCount; // ! Does not need to be XMP_AtomicCounter.
+ volatile bool releaseAll;
+ };
+ typedef XMP_WinXP_HGQueue XMP_BasicQueue;
+ #endif
+
+ #endif
+
+ class XMP_HomeGrownLock {
+ public:
+ XMP_HomeGrownLock();
+ ~XMP_HomeGrownLock();
+ void AcquireForRead();
+ void AcquireForWrite();
+ void ReleaseFromRead();
+ void ReleaseFromWrite();
+ private:
+ XMP_BasicMutex queueMutex; // Used to protect queueing operations.
+ XMP_BasicQueue readerQueue, writerQueue;
+ volatile XMP_Uns32 lockCount, readersWaiting, writersWaiting; // ! Does not need to be XMP_AtomicCounter.
+ volatile bool beingWritten;
+ };
+
+#else
+
+ #error "No locking mechanism chosen"
+
+#endif
+
+class XMP_ReadWriteLock { // For the lock objects, use XMP_AutoLock to do the locking.
+public:
+ XMP_ReadWriteLock();
+ ~XMP_ReadWriteLock();
+ void Acquire ( bool forWriting );
+ void Release();
+private:
+ XMP_BasicRWLock lock;
+ #if XMP_DebugBuild && HaveAtomicIncrDecr
+ volatile XMP_AtomicCounter lockCount; // ! Only for debug checks, must be XMP_AtomicCounter.
+ #endif
+ volatile bool beingWritten;
+};
+
+#define kXMP_ReadLock false
+#define kXMP_WriteLock true
+
+class XMP_AutoLock {
+public:
+ XMP_AutoLock ( const XMP_ReadWriteLock * _lock, bool forWriting, bool cond = true ) : lock(0)
+ {
+ if ( cond ) {
+ // The cast below is needed because the _lock parameter might come from something
+ // like "const XMPMeta &", which would make the lock itself const. But we need to
+ // modify the lock (to acquire and release) even if the owning object is const.
+ this->lock = (XMP_ReadWriteLock*)_lock;
+ this->lock->Acquire ( forWriting );
+ }
+ }
+ ~XMP_AutoLock() { this->Release(); }
+ void Release() { if ( this->lock != 0 ) this->lock->Release(); this->lock = 0; }
+private:
+ XMP_ReadWriteLock * lock;
+ XMP_AutoLock() {}; // ! Must not be used.
+};
+
+// =================================================================================================
+// Support for wrappers
+// ====================
+
+#define AnnounceStaticEntry(proc) /* Do nothing. */
+#define AnnounceObjectEntry(proc,rwMode) /* Do nothing. */
+
+#define AnnounceExit() /* Do nothing. */
+
+// -------------------------------------------------------------------------------------------------
+
+#if UseGlobalLibraryLock
+ #define AcquireLibraryLock(lck) XMP_AutoMutex libLock ( &lck )
+#else
+ #define AcquireLibraryLock(lck) /* nothing */
+#endif
+
+#define XMP_ENTER_NoLock(Proc) \
+ AnnounceStaticEntry ( Proc ); \
+ try { \
+ wResult->errMessage = 0;
+
+#define XMP_ENTER_Static(Proc) \
+ AnnounceStaticEntry ( Proc ); \
+ AcquireLibraryLock ( sLibraryLock ); \
+ try { \
+ wResult->errMessage = 0;
+
+#define XMP_ENTER_ObjRead(XMPClass,Proc) \
+ AnnounceObjectEntry ( Proc, "reader" ); \
+ AcquireLibraryLock ( sLibraryLock ); \
+ const XMPClass & thiz = *((XMPClass*)xmpObjRef); \
+ XMP_AutoLock objLock ( &thiz.lock, kXMP_ReadLock ); \
+ try { \
+ wResult->errMessage = 0;
+
+#define XMP_ENTER_ObjWrite(XMPClass,Proc) \
+ AnnounceObjectEntry ( Proc, "writer" ); \
+ AcquireLibraryLock ( sLibraryLock ); \
+ XMPClass * thiz = (XMPClass*)xmpObjRef; \
+ XMP_AutoLock objLock ( &thiz->lock, kXMP_WriteLock ); \
+ try { \
+ wResult->errMessage = 0;
+
+#define XMP_EXIT \
+ XMP_CATCH_EXCEPTIONS \
+ AnnounceExit();
+
+#define XMP_EXIT_NoThrow \
+ } catch ( ... ) { \
+ AnnounceCatch ( "no-throw catch-all" ); \
+ /* Do nothing. */ \
+ } \
+ AnnounceExit();
+
+#define XMP_CATCH_EXCEPTIONS \
+ } catch ( XMP_Error & xmpErr ) { \
+ wResult->int32Result = xmpErr.GetID(); \
+ wResult->ptrResult = (void*)"XMP"; \
+ wResult->errMessage = xmpErr.GetErrMsg(); \
+ if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \
+ AnnounceCatch ( wResult->errMessage ); \
+ } catch ( std::exception & stdErr ) { \
+ wResult->int32Result = kXMPErr_StdException; \
+ wResult->errMessage = stdErr.what(); \
+ if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \
+ AnnounceCatch ( wResult->errMessage ); \
+ } catch ( ... ) { \
+ wResult->int32Result = kXMPErr_UnknownException; \
+ wResult->errMessage = "Caught unknown exception"; \
+ AnnounceCatch ( wResult->errMessage ); \
+ }
+
+#if XMP_DebugBuild
+ #define RELEASE_NO_THROW /* empty */
+#else
+ #define RELEASE_NO_THROW throw()
+#endif
+
+// =================================================================================================
+// Data structure dumping utilities
+// ================================
+
+#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) )
+#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) )
+
+static const char * kTenSpaces = " ";
+#define OutProcPadding(pad) { size_t padLen = (pad); \
+ for ( ; padLen >= 10; padLen -= 10 ) OutProcNChars ( kTenSpaces, 10 ); \
+ for ( ; padLen > 0; padLen -= 1 ) OutProcNChars ( " ", 1 ); }
+
+
+#define OutProcNewline() { XMP_Status status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) return; }
+
+#define OutProcNChars(p,n) { XMP_Status status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) return; }
+
+#define OutProcLiteral(lit) { XMP_Status _status = (*outProc) ( refCon, (lit), (XMP_StringLen)strlen(lit) ); if ( _status != 0 ) return; }
+
+#define OutProcString(str) { XMP_Status _status = (*outProc) ( refCon, (str).c_str(), (XMP_StringLen)(str).size() ); if ( _status != 0 ) return; }
+
+#define OutProcDecInt(num) { snprintf ( buffer, sizeof(buffer), "%ld", (long)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
+ buffer[sizeof(buffer) -1] = 0; /* AUDIT warning C6053: Make sure buffer is terminated */ \
+ XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; }
+
+#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%lX", (long)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
+ buffer[sizeof(buffer) -1] = 0; /* AUDIT warning C6053: Make sure buffer is terminated */ \
+ XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; }
+
+#define OutProcHexByte(num) { snprintf ( buffer, sizeof(buffer), "%.2X", (unsigned char)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
+ XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; }
+
+static const char * kIndent = " ";
+#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); }
+
+void DumpClearString ( const XMP_VarString & value, XMP_TextOutputProc outProc, void * refCon );
+
+// =================================================================================================
+// Namespace Tables
+// ================
+typedef std::vector <XMP_VarString> XMP_StringVector;
+typedef XMP_StringVector::iterator XMP_StringVectorPos;
+typedef XMP_StringVector::const_iterator XMP_StringVectorCPos;
+
+typedef std::pair < XMP_VarString, XMP_VarString > XMP_StringPair;
+
+typedef std::map < XMP_VarString, XMP_VarString > XMP_StringMap;
+typedef XMP_StringMap::iterator XMP_StringMapPos;
+typedef XMP_StringMap::const_iterator XMP_cStringMapPos;
+
+class XMP_NamespaceTable {
+public:
+
+ XMP_NamespaceTable() {};
+ XMP_NamespaceTable ( const XMP_NamespaceTable & presets );
+ virtual ~XMP_NamespaceTable() {};
+
+ bool Define ( XMP_StringPtr uri, XMP_StringPtr suggPrefix,
+ XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen);
+
+ bool GetPrefix ( XMP_StringPtr uri, XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen ) const;
+ bool GetURI ( XMP_StringPtr prefix, XMP_StringPtr * uriPtr, XMP_StringLen * uriLen ) const;
+
+ void Dump ( XMP_TextOutputProc outProc, void * refCon ) const;
+
+private:
+
+ XMP_ReadWriteLock lock;
+ XMP_StringMap uriToPrefixMap, prefixToURIMap;
+
+};
+
+
+// Right now it supports only ^, $ and \d, in future we should use it as a wrapper over
+// regex object once mac and Linux compilers start supporting them.
+
+class XMP_RegExp {
+public:
+ XMP_RegExp ( XMP_StringPtr regExp )
+ {
+ if ( regExp )
+ regExpStr = regExp;
+ }
+
+ XMP_Bool Match ( XMP_StringPtr s );
+
+private:
+ XMP_VarString regExpStr;
+};
+
+// =================================================================================================
+
+#endif // __XMP_LibUtils_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/TXMPFiles.hpp b/gpr/source/lib/xmp_core/public/include/TXMPFiles.hpp
new file mode 100644
index 0000000..27ee413
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/TXMPFiles.hpp
@@ -0,0 +1,855 @@
+#ifndef __TXMPFiles_hpp__
+#define __TXMPFiles_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// =================================================================================================
+/// \file TXMPFiles.hpp
+/// \brief API for access to the main (document-level) metadata in a file_.
+///
+/// The Adobe XMP Toolkit's file handling component, XMPFiles, is a front end to a set of
+/// format-specific file handlers that support file I/O for XMP. The file handlers implement smart,
+/// efficient support for those file formats for which the means to embed XMP is defined in the XMP
+/// Specification. Where possible, this support allows:
+/// \li Injection of XMP where none currently exists
+/// \li Expansion of XMP without regard to existing padding
+/// \li Reconciliation of the XMP and other legacy forms of metadata.
+///
+/// \c TXMPFiles is designed for use by clients interested in the metadata and not in the primary
+/// file content; the Adobe Bridge application is a typical example. \c TXMPFiles is not intended to
+/// be appropriate for files authored by an application; that is, those files for which the
+/// application has explicit knowledge of the file format.
+// =================================================================================================
+
+
+// =================================================================================================
+/// \class TXMPFiles TXMPFiles.hpp
+/// \brief API for access to the main (document-level) metadata in a file.
+///
+/// \c TXMPFiles is a template class that provides the API for the Adobe XMP Toolkit's XMPFiles
+/// component. This provides convenient access to the main, or document level, XMP for a file. Use
+/// it to obtain metadata from a file, which you can then manipulate with the XMP Core component
+/// (the classes \c TXMPMeta, \c TXMPUtils, and \c TXMPIterator); and to write new or changed
+/// metadata back out to a file.
+///
+/// The functions allow you to open a file, read and write the metadata, then close the file.
+/// While open, portions of the file might be maintained in RAM data structures. Memory
+/// usage can vary considerably depending onfile format and access options.
+///
+/// A file can be opened for read-only or read-write access, with typical exclusion for both
+/// modes. Errors result in the throw of an \c XMPError exception.
+///
+/// \c TXMPFiles is the template class. It must be instantiated with a string class such as
+/// \c std::string. Read the Toolkit Overview for information about the overall architecture of the XMP
+/// API, and the documentation for \c XMP.hpp for specific instantiation instructions.
+///
+/// Access these functions through the concrete class, \c SXMPFiles.
+// =================================================================================================
+
+
+#if XMP_StaticBuild // ! Client XMP_IO objects can only be used in static builds.
+ #include "XMP_IO.hpp"
+#endif
+
+
+template <class tStringObj>
+class TXMPFiles {
+
+public:
+
+ // =============================================================================================
+ /// \name Initialization and termination
+ /// @{
+ ///
+ /// A \c TXMPFiles object must be initialized before use and can be terminated when done.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetVersionInfo() retrieves version information for the XMPFiles component.
+ ///
+ /// Can be called before \c #Initialize(). This function is static; make the call directly from
+ /// the concrete class (\c SXMPFiles).
+ ///
+ /// @param versionInfo [out] A buffer in which to return the version information.
+
+ static void GetVersionInfo ( XMP_VersionInfo * versionInfo );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
+ ///
+ /// The main action is to activate the available smart file handlers. Must be called before
+ /// using any methods except \c GetVersionInfo().
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
+ ///
+ /// @return True on success.
+
+ static bool Initialize();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
+ ///
+ /// This overload of TXMPFiles::Initialize() accepts option bits to customize the initialization
+ /// actions. At this time no option is defined.
+ ///
+ /// The main action is to activate the available smart file handlers. Must be called before
+ /// using any methods except \c GetVersionInfo().
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
+ ///
+ /// @param options Option flags to control the initialization actions.
+ ///
+ /// @return True on success.
+
+ static bool Initialize ( XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
+ ///
+ /// This overload of TXMPFiles::Initialize() accepts plugin directory and name of the plug-ins
+ /// as a comma separated list to load the file handler plug-ins. If plugins == NULL, then all
+ /// plug-ins present in the plug-in directory will be loaded.
+ ///
+ /// The main action is to activate the available smart file handlers. Must be called before
+ /// using any methods except \c GetVersionInfo().
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
+ ///
+ /// @param pluginFolder Pugin directorty to load the file handler plug-ins.
+ /// @param plugins Comma sepearted list of plug-ins which should be loaded from the plug-in directory.
+ /// If plugin == NULL, then all plug-ins availbale in the plug-in directory will be loaded.
+ ///
+ /// @return True on success.
+
+ static bool Initialize ( const char* pluginFolder, const char* plugins = NULL );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Initializes the XMPFiles library; must be called before creating an \c SXMPFiles object.
+ ///
+ /// This overload of TXMPFiles::Initialize( XMP_OptionBits options ) accepts plugin directory and
+ /// name of the plug-ins as a comma separated list to load the file handler plug-ins.
+ /// If plugins == NULL, then all plug-ins present in the plug-in directory will be loaded.
+ ///
+ /// The main action is to activate the available smart file handlers. Must be called before
+ /// using any methods except \c GetVersionInfo().
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
+ ///
+ /// @param options Option flags to control the initialization actions.
+ /// @param pluginFolder Pugin directorty to load the file handler plug-ins.
+ /// @param plugins Comma sepearted list of plug-ins which should be loaded from the plug-in directory.
+ /// If plugin == NULL, then all plug-ins availbale in the plug-in directory will be loaded.
+ ///
+ /// @return True on success.
+
+ static bool Initialize ( XMP_OptionBits options, const char* pluginFolder, const char* plugins = NULL );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Terminates use of the XMPFiles library.
+ ///
+ /// Optional. Deallocates global data structures created by intialization. Its main action is to
+ /// deallocate heap-allocated global storage, for the benefit of client leak checkers.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPFiles).
+
+ static void Terminate();
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Constructors and destructor
+ /// @{
+ ///
+ /// The default constructor initializes an object that is associated with no file. The alternate
+ /// constructors call \c OpenFile().
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Default constructor initializes an object that is associated with no file.
+
+ TXMPFiles();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Destructor; typical virtual destructor.
+ ///
+ /// The destructor does not call \c CloseFile(); pending updates are lost when the destructor is run.
+ ///
+ /// @see \c OpenFile(), \c CloseFile()
+
+ virtual ~TXMPFiles() throw();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Alternate constructor associates the new \c XMPFiles object with a specific file.
+ ///
+ /// Calls \c OpenFile() to open the specified file after performing a default construct.
+ ///
+ /// @param filePath The path for the file, specified as a nul-terminated UTF-8 string.
+ ///
+ /// @param format A format hint for the file, if known.
+ ///
+ /// @param openFlags Options for how the file is to be opened (for read or read/write, for
+ /// example). Use a logical OR of these bit-flag constants:
+ ///
+ /// \li \c #kXMPFiles_OpenForRead
+ /// \li \c #kXMPFiles_OpenForUpdate
+ /// \li \c #kXMPFiles_OpenOnlyXMP
+ /// \li \c #kXMPFiles_OpenStrictly
+ /// \li \c #kXMPFiles_OpenUseSmartHandler
+ /// \li \c #kXMPFiles_OpenUsePacketScanning
+ /// \li \c #kXMPFiles_OpenLimitedScanning
+ ///
+ /// @return The new \c TXMPFiles object.
+
+ TXMPFiles ( XMP_StringPtr filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Alternate constructor associates the new \c XMPFiles object with a specific file,
+ /// using a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object
+ /// for the file path. It is otherwise identical; see details in the canonical form.
+
+ TXMPFiles ( const tStringObj & filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Copy constructor
+ ///
+ /// Increments an internal reference count but does not perform a deep copy.
+ ///
+ /// @param original The existing \c TXMPFiles object to copy.
+ ///
+ /// @return The new \c TXMPFiles object.
+
+ TXMPFiles ( const TXMPFiles<tStringObj> & original );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Assignment operator
+ ///
+ /// Increments an internal reference count but does not perform a deep copy.
+ ///
+ /// @param rhs The existing \c TXMPFiles object.
+
+ void operator= ( const TXMPFiles<tStringObj> & rhs );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Reconstructs a \c TXMPFiles object from an internal reference.
+ ///
+ /// This constructor creates a new \c TXMPFiles object that refers to the underlying reference
+ /// object of an existing \c TXMPFiles object. Use to safely pass \c SXMPFiles references across
+ /// DLL boundaries.
+ ///
+ /// @param xmpFilesObj The underlying reference object, obtained from some other XMP object
+ /// with \c TXMPFiles::GetInternalRef().
+ ///
+ /// @return The new object.
+
+ TXMPFiles ( XMPFilesRef xmpFilesObj );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief GetInternalRef() retrieves an internal reference that can be safely passed across DLL
+ /// boundaries and reconstructed.
+ ///
+ /// Use with the reconstruction constructor to safely pass \c SXMPFiles references across DLL
+ /// boundaries where the clients might have used different string types when instantiating
+ /// \c TXMPFiles.
+ ///
+ /// @return The internal reference.
+ ///
+ /// @see \c TXMPMeta::GetInternalRef() for usage.
+
+ XMPFilesRef GetInternalRef();
+
+ /// @}
+
+ // =============================================================================================
+ /// \name File handler information
+ /// @{
+ ///
+ /// Call this static function from the concrete class, \c SXMPFiles, to obtain information about
+ /// the file handlers for the XMPFiles component.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief GetFormatInfo() reports what features are supported for a specific file format.
+ ///
+ /// The file handlers for different file formats vary considerably in what features they
+ /// support. Support depends on both the general capabilities of the format and the
+ /// implementation of the handler for that format.
+ ///
+ ///This function is static; make the call directly from the concrete class (\c SXMPFiles).
+ ///
+ /// @param format The file format whose support flags are desired.
+ ///
+ /// @param handlerFlags [out] A buffer in which to return a logical OR of option bit flags.
+ /// The following constants are defined:
+ ///
+ /// \li \c #kXMPFiles_CanInjectXMP - Can inject first-time XMP into an existing file.
+ /// \li \c #kXMPFiles_CanExpand - Can expand XMP or other metadata in an existing file.
+ /// \li \c #kXMPFiles_CanRewrite - Can copy one file to another, writing new metadata (as in SaveAs)
+ /// \li \c #kXMPFiles_CanReconcile - Supports reconciliation between XMP and other forms.
+ /// \li \c #kXMPFiles_AllowsOnlyXMP - Allows access to just the XMP, ignoring other forms.
+ /// This is only meaningful if \c #kXMPFiles_CanReconcile is set.
+ /// \li \c #kXMPFiles_ReturnsRawPacket - File handler returns raw XMP packet information and string.
+ ///
+ /// Even if \c #kXMPFiles_ReturnsRawPacket is set, the returned packet information might have an
+ /// offset of -1 to indicate an unknown offset. While all file handlers should be able to return
+ /// the raw packet, some might not know the offset of the packet within the file. This is
+ /// typical in cases where external libraries are used. These cases might not even allow return
+ /// of the raw packet.
+ ///
+ /// @return True if the format has explicit "smart" support, false if the format is handled by
+ /// the default packet scanning plus heuristics. */
+
+
+ static bool GetFormatInfo ( XMP_FileFormat format,
+ XMP_OptionBits * handlerFlags = 0 );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name File operations
+ /// @{
+ ///
+ /// These functions allow you to open, close, and query files.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CheckFileFormat() tries to determine the format of a file.
+ ///
+ /// Tries to determine the format of a file, returning an \c #XMP_FileFormat value. Uses the
+ /// same logic as \c OpenFile() to select a smart handler.
+ ///
+ /// @param filePath The path for the file, appropriate for the local operating system. Passed as
+ /// a nul-terminated UTF-8 string. The path is the same as would be passed to \c OpenFile.
+ ///
+ /// @return The file's format if a smart handler would be selected by \c OpenFile(), otherwise
+ /// \c #kXMP_UnknownFile.
+
+ static XMP_FileFormat CheckFileFormat ( XMP_StringPtr filePath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CheckPackageFormat() tries to determine the format of a "package" folder.
+ ///
+ /// Tries to determine the format of a package, given the name of the top-level folder. Returns
+ /// an \c #XMP_FileFormat value. Examples of recognized packages include the video formats P2,
+ /// XDCAM, or Sony HDV. These packages contain collections of "clips", stored as multiple files
+ /// in specific subfolders.
+ ///
+ /// @param folderPath The path for the top-level folder, appropriate for the local operating
+ /// system. Passed as a nul-terminated UTF-8 string. This is not the same path you would pass to
+ /// \c OpenFile(). For example, the top-level path for a package might be ".../MyMovie", while
+ /// the path to a file you wish to open would be ".../MyMovie/SomeClip".
+ ///
+ /// @return The package's format if it can be determined, otherwise \c #kXMP_UnknownFile.
+
+ static XMP_FileFormat CheckPackageFormat ( XMP_StringPtr folderPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetFileModDate() returns the last modification date of all files that are returned
+ /// by \c GetAssociatedResources()
+ ///
+ /// Returns the most recent O/S file modification date of all associated files. In the typical case
+ /// of a single file containing embedded XMP, returned date value is the modification date of the
+ /// same file. For sidecar and folder based video packages, returned date value is the modification
+ /// date of that associated file which was updated last.
+ ///
+ /// @param filePath A path exactly as would be passed to \c OpenFile.
+ ///
+ /// @param modDate A required pointer to return the last modification date.
+ ///
+ /// @param format A format hint as would be passed to \c OpenFile.
+ ///
+ /// @param options An optional set of option flags. The only defined one is \c kXMPFiles_ForceGivenHandler,
+ /// used to shortcut the handler selection logic if the caller is certain of the format.
+ ///
+ /// @return Returns true if the file path is valid to select a smart handler, false for an
+ /// invalid path or if fallback packet scanning would be selected.
+
+ static bool GetFileModDate ( XMP_StringPtr filePath,
+ XMP_DateTime * modDate,
+ XMP_FileFormat * format = 0,
+ XMP_OptionBits options = 0 );
+
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetAssociatedResources() returns a list of files and folders associated to filePath.
+ ///
+ /// \c GetAssociatedResources is provided to locate all files that are associated to the given
+ /// filePath such as sidecar-based XMP or folder-based video packages.If a smart
+ /// handler can be selected (not fallback packet scanning) then a list of file/folder paths is
+ /// returned for the related files that can be safely copied/imported to a different location,
+ /// keeping intact metadata(XMP and non-XMP),content and the necessary folder structure of the
+ /// format. The necessary folder structure here is the structure that is needed to uniquely
+ /// identify a folder-based format.The filePath and format parameters are exactly as would be
+ /// used for OpenFile. In the simple embedded XMP case just one path is returned. In the simple
+ /// sidecar case one or two paths will be returned, one if there is no sidecar XMP and two if
+ /// sidecar XMP exists. For folder-based handlers paths to all associated files is returned,
+ /// including the files and folders necessary to identify the format.In general, all the returned
+ /// paths are existent.In case of folder based video formats the first associated resource in the
+ /// resourceList is the root folder.
+ ///
+ /// @param filePath A path exactly as would be passed to \c OpenFile.
+ ///
+ /// @param resourceList Address of a vector of strings to receive all associated resource paths.
+ ///
+ /// @param format A format hint as would be passed to \c OpenFile.
+ ///
+ /// @param options An optional set of option flags. The only defined one is \c kXMPFiles_ForceGivenHandler,
+ /// used to shortcut the handler selection logic if the caller is certain of the format.
+ ///
+ /// @return Returns true if the file path is valid to select a smart handler, false for an
+ /// invalid path or if fallback packet scanning would be selected. Can also return false for
+ /// unexpected errors that prevent knowledge of the file usage.
+
+ static bool GetAssociatedResources ( XMP_StringPtr filePath,
+ std::vector<tStringObj>* resourceList,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits options = 0);
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c IsMetadataWritable() returns true if metadata can be updated for the given media path.
+ ///
+ /// \c IsMetadataWritable is provided to check if metadata can be updated or written to the format.In
+ /// the case of folder-based video formats only if all the metadata files can be written to, true is
+ /// returned.In other words, false is returned for a partial-write state of metadata files in
+ /// folder-based media formats.
+ ///
+ /// @param filePath A path exactly as would be passed to \c OpenFile.
+ ///
+ /// @param writable A pointer to the result flag. Is true if the metadata can be updated in the format,
+ /// otherwise false.
+ ///
+ /// @param format A format hint as would be passed to \c OpenFile.
+ ///
+ /// @param options An optional set of option flags. The only defined one is \c kXMPFiles_ForceGivenHandler,
+ /// used to shortcut the handler selection logic if the caller is certain of the format.
+ ///
+ /// @return Returns true if the file path is valid to select a smart handler, false for an
+ /// invalid path or if fallback packet scanning would be selected.
+
+ static bool IsMetadataWritable (XMP_StringPtr filePath,
+ bool * writable,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c OpenFile() opens a file for metadata access.
+ ///
+ /// Opens a file for the requested forms of metadata access. Opening the file at a minimum
+ /// causes the raw XMP packet to be read from the file. If the file handler supports legacy
+ /// metadata reconciliation then legacy metadata is also read, unless \c #kXMPFiles_OpenOnlyXMP
+ /// is passed.
+ ///
+ /// If the file is opened for read-only access (passing \c #kXMPFiles_OpenForRead), the disk
+ /// file is closed immediately after reading the data from it; the \c XMPFiles object, however,
+ /// remains in the open state. You must call \c CloseFile() when finished using it. Other
+ /// methods, such as \c GetXMP(), can only be used between the \c OpenFile() and \c CloseFile()
+ /// calls. The \c XMPFiles destructor does not call \c CloseFile(); if you call it without
+ /// closing, any pending updates are lost.
+ ///
+ /// If the file is opened for update (passing \c #kXMPFiles_OpenForUpdate), the disk file
+ /// remains open until \c CloseFile() is called. The disk file is only updated once, when
+ /// \c CloseFile() is called, regardless of how many calls are made to \c PutXMP().
+ ///
+ /// Typically, the XMP is not parsed and legacy reconciliation is not performed until \c GetXMP()
+ /// is called, but this is not guaranteed. Specific file handlers might do earlier parsing of
+ /// the XMP. Delayed parsing and early disk file close for read-only access are optimizations
+ /// to help clients implementing file browsers, so that they can access the file briefly
+ /// and possibly display a thumbnail, then postpone more expensive XMP processing until later.
+ ///
+ /// @param filePath The path for the file, appropriate for the local operating system. Passed as
+ /// a nul-terminated UTF-8 string.
+ ///
+ /// @param format The format of the file. If the format is unknown (\c #kXMP_UnknownFile) the
+ /// format is determined from the file content. The first handler to check is guessed from the
+ /// file's extension. Passing a specific format value is generally just a hint about what file
+ /// handler to try first (instead of the one based on the extension). If
+ /// \c #kXMPFiles_OpenStrictly is set, then any format other than \c #kXMP_UnknownFile requires
+ /// that the file actually be that format; otherwise an exception is thrown.
+ ///
+ /// @param openFlags A set of option flags that describe the desired access. By default (zero)
+ /// the file is opened for read-only access and the format handler decides on the level of
+ /// reconciliation that will be performed. A logical OR of these bit-flag constants:
+ ///
+ /// \li \c #kXMPFiles_OpenForRead - Open for read-only access.
+ /// \li \c #kXMPFiles_OpenForUpdate - Open for reading and writing.
+ /// \li \c #kXMPFiles_OpenOnlyXMP - Only the XMP is wanted, no reconciliation.
+ /// \li \c #kXMPFiles_OpenStrictly - Be strict about locating XMP and reconciling with other
+ /// forms. By default, a best effort is made to locate the correct XMP and to reconcile XMP
+ /// with other forms (if reconciliation is done). This option forces stricter rules, resulting
+ /// in exceptions for errors. The definition of strictness is specific to each handler, there
+ /// might be no difference.
+ /// \li \c #kXMPFiles_OpenUseSmartHandler - Require the use of a smart handler.
+ /// \li \c #kXMPFiles_OpenUsePacketScanning - Force packet scanning, do not use a smart handler.
+ /// \li \c #kXMPFiles_OptimizeFileLayout - When updating a file, spend the effort necessary
+ /// to optimize file layout.
+ ///
+ /// @return True if the file is succesfully opened and attached to a file handler. False for
+ /// anticipated problems, such as passing \c #kXMPFiles_OpenUseSmartHandler but not having an
+ /// appropriate smart handler. Throws an exception for serious problems.
+
+ bool OpenFile ( XMP_StringPtr filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c OpenFile() opens a file for metadata access, using a string object
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object for the file
+ /// path. It is otherwise identical; see details in the canonical form.
+
+ bool OpenFile ( const tStringObj & filePath,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+
+ #if XMP_StaticBuild // ! Client XMP_IO objects can only be used in static builds.
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c OpenFile() opens a client-provided XMP_IO object for metadata access.
+ ///
+ /// Alternative to the basic form of the function, allowing you to pass an XMP_IO object for
+ /// client-managed I/O.
+ ///
+
+ bool OpenFile ( XMP_IO * clientIO,
+ XMP_FileFormat format = kXMP_UnknownFile,
+ XMP_OptionBits openFlags = 0 );
+ #endif
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief CloseFile() explicitly closes an opened file.
+ ///
+ /// Performs any necessary output to the file and closes it. Files that are opened for update
+ /// are written to only when closing.
+ ///
+ /// If the file is opened for read-only access (passing \c #kXMPFiles_OpenForRead), the disk
+ /// file is closed immediately after reading the data from it; the \c XMPFiles object, however,
+ /// remains in the open state. You must call \c CloseFile() when finished using it. Other
+ /// methods, such as \c GetXMP(), can only be used between the \c OpenFile() and \c CloseFile()
+ /// calls. The \c XMPFiles destructor does not call \c CloseFile(); if you call it without closing,
+ /// any pending updates are lost.
+ ///
+ /// If the file is opened for update (passing \c #kXMPFiles_OpenForUpdate), the disk file remains
+ /// open until \c CloseFile() is called. The disk file is only updated once, when \c CloseFile()
+ /// is called, regardless of how many calls are made to \c PutXMP().
+ ///
+ /// @param closeFlags Option flags for optional closing actions. This bit-flag constant is
+ /// defined:
+ ///
+ /// \li \c #kXMPFiles_UpdateSafely - Write into a temporary file then swap for crash safety.
+
+ void CloseFile ( XMP_OptionBits closeFlags = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetFileInfo() retrieves basic information about an opened file.
+ ///
+ /// @param filePath [out] A buffer in which to return the path passed to \c OpenFile(). Can be
+ /// null if value is not wanted.
+ ///
+ /// @param openFlags [out] A buffer in which to return the option flags passed to
+ /// \c OpenFile(). Can be null if value is not wanted.
+ ///
+ /// @param format [out] A buffer in which to return the file format. Can be null if value is not
+ /// wanted.
+ /// @param handlerFlags [out] A buffer in which to return the handler's capability flags. Can
+ /// be null if value is not wanted.
+ ///
+ /// @return True if the file object is in the open state; that is, \c OpenFile() has been called
+ /// but \c CloseFile() has not. False otherwise. Even if the file object is open, the actual
+ /// disk file might be closed in the host file-system sense; see \c OpenFile().
+
+ bool GetFileInfo ( tStringObj * filePath = 0,
+ XMP_OptionBits * openFlags = 0,
+ XMP_FileFormat * format = 0,
+ XMP_OptionBits * handlerFlags = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetAbortProc() registers a callback function used to check for a user-signaled abort.
+ ///
+ /// The specified procedure is called periodically to allow a user to cancel time-consuming
+ /// operations. The callback function should return true to signal an abort, which results in an
+ /// exception being thrown.
+ ///
+ /// @param abortProc The callback function.
+ ///
+ /// @param abortArg A pointer to caller-defined data to pass to the callback function.
+
+ void SetAbortProc ( XMP_AbortProc abortProc,
+ void * abortArg );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Accessing metadata
+ /// @{
+ ///
+ /// These functions allow you to retrieve XMP metadata from open files, so that you can use the
+ /// \c TXMPMeta API to manipulate it. The \c PutXMP() functions update the XMP packet in memory.
+ /// Changed XMP is not actually written out to the file until the file is closed.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetXMP() retrieves the XMP metadata from an open file.
+ ///
+ /// The function reports whether XMP is present in the file; you can choose to retrieve any or
+ /// all of the parsed XMP, the raw XMP packet,or information about the raw XMP packet. The
+ /// options provided when the file was opened determine if reconciliation is done with other
+ /// forms of metadata.
+ ///
+ /// @param xmpObj [out] An XMP object in which to return the parsed XMP metadata. Can be null.
+ ///
+ /// @param xmpPacket [out] An string object in which to return the raw XMP packet as stored in
+ /// the file. Can be null. The encoding of the packet is given in the \c packetInfo. Returns an
+ /// empty string if the low level file handler does not provide the raw packet.
+ ///
+ /// @param packetInfo [out] An string object in which to return the location and form of the raw
+ /// XMP in the file. \c #XMP_PacketInfo::charForm and \c #XMP_PacketInfo::writeable reflect the
+ /// raw XMP in the file. The parsed XMP property values are always UTF-8. The writeable flag is
+ /// taken from the packet trailer; it applies only to "format ignorant" writing. The
+ /// \c #XMP_PacketInfo structure always reflects the state of the XMP in the file. The offset,
+ /// length, and character form do not change as a result of calling \c PutXMP() unless the file
+ /// is also written. Some file handlers might not return location or contents of the raw packet
+ /// string. To determine whether one does, check the \c #kXMPFiles_ReturnsRawPacket bit returned
+ /// by \c GetFormatInfo(). If the low-level file handler does not provide the raw packet
+ /// location, \c #XMP_PacketInfo::offset and \c #XMP_PacketInfo::length are both 0,
+ /// \c #XMP_PacketInfo::charForm is UTF-8, and \c #XMP_PacketInfo::writeable is false.
+ ///
+ /// @return True if the file has XMP, false otherwise.
+
+ bool GetXMP ( SXMPMeta * xmpObj = 0,
+ tStringObj * xmpPacket = 0,
+ XMP_PacketInfo * packetInfo = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c PutXMP() updates the XMP metadata in this object without writing out the file.
+ ///
+ /// This function supplies new XMP for the file. However, the disk file is not written until the
+ /// object is closed with \c CloseFile(). The options provided when the file was opened
+ /// determine if reconciliation is done with other forms of metadata.
+ ///
+ /// @param xmpObj The new metadata as an XMP object.
+
+ void PutXMP ( const SXMPMeta & xmpObj );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c PutXMP() updates the XMP metadata in this object without writing out the file,
+ /// using a string object for input.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
+ /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
+ ///
+ /// @param xmpPacket The new metadata as a string object containing a complete XMP packet.
+
+ void PutXMP ( const tStringObj & xmpPacket );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c PutXMP() updates the XMP metadata in this object without writing out the file,
+ /// using a string object and optional length.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
+ /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
+ ///
+ /// @param xmpPacket The new metadata as a <tt>const char *</tt> string containing an XMP packet.
+ ///
+ /// @param xmpLength Optional. The number of bytes in the string. If not supplied, the string is
+ /// assumed to be nul-terminated.
+
+ void PutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength = kXMP_UseNullTermination );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CanPutXMP() reports whether this file can be updated with a specific XMP packet.
+ ///
+ /// Use to determine if the file can probably be updated with a given set of XMP metadata. This
+ /// depends on the size of the packet, the options with which the file was opened, and the
+ /// capabilities of the handler for the file format. The function obtains the length of the
+ /// serialized packet for the provided XMP, but does not keep it or modify it, and does not
+ /// cause the file to be written when closed. This is implemented roughly as follows:
+ ///
+ /// <pre>
+ /// bool CanPutXMP ( XMP_StringPtr xmpPacket )
+ /// {
+ /// XMP_FileFormat format;
+ /// this->GetFileInfo ( 0, &format, 0 );
+ ///
+ /// XMP_OptionBits formatFlags;
+ /// GetFormatInfo ( format, &formatFlags );
+ ///
+ /// if ( (formatFlags & kXMPFiles_CanInjectXMP) && (formatFlags & kXMPFiles_CanExpand) ) return true;
+ ///
+ /// XMP_PacketInfo packetInfo;
+ /// bool hasXMP = this->GetXMP ( 0, 0, &packetInfo );
+ ///
+ /// if ( ! hasXMP ) {
+ /// if ( formatFlags & kXMPFiles_CanInjectXMP ) return true;
+ /// } else {
+ /// if ( (formatFlags & kXMPFiles_CanExpand) ||
+ /// (packetInfo.length >= strlen(xmpPacket)) ) return true;
+ /// }
+ /// return false;
+ /// }
+ /// </pre>
+ ///
+ /// @param xmpObj The proposed new metadata as an XMP object.
+
+ bool CanPutXMP ( const SXMPMeta & xmpObj );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CanPutXMP() reports whether this file can be updated with a specific XMP packet,
+ /// passed in a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
+ /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
+ ///
+ /// @param xmpPacket The proposed new metadata as a string object containing an XMP packet.
+
+ bool CanPutXMP ( const tStringObj & xmpPacket );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CanPutXMP() reports whether this file can be updated with a specific XMP packet,
+ /// passed in a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass the metadata as a string object
+ /// instead of an XMP object. It is otherwise identical; see details in the canonical form.
+ ///
+ /// @param xmpPacket The proposed new metadata as a <tt>const char *</tt> string containing an XMP packet.
+ ///
+ /// @param xmpLength Optional. The number of bytes in the string. If not supplied, the string
+ /// is assumed to be nul-terminated.
+
+ bool CanPutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength = kXMP_UseNullTermination );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Progress notifications
+ /// @{
+ ///
+ /// These functions allow track the progress of file operations. Initially only file updates are
+ /// tracked, these all occur within calls to SXMPFiles::CloseFile. There are no plans to track
+ /// other operations at this time. Tracking support must be added to specific file handlers,
+ /// there are no guarantees about which handlers will have support. To simplify the logic only
+ /// file writes will be estimated and measured.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetDefaultProgressCallback() sets a global default for progress tracking. This is
+ /// used as a default for XMPFiles (library) objects created after the default is set. This does
+ /// not affect the callback for new SXMPFiles (client) objects with an existing XMPFiles object.
+ ///
+ /// @param proc The client's callback function. Can be zero to disable notifications.
+ ///
+ /// @param context A pointer used to carry client-private context.
+ ///
+ /// @param interval The desired number of seconds between notifications. Ideally the first
+ /// notification is sent after this interval, then at each following multiple of this interval.
+ ///
+ /// @param sendStartStop A Boolean value indicating if initial and final notifications are
+ /// wanted in addition to those at the reporting intervals.
+
+ static void SetDefaultProgressCallback ( XMP_ProgressReportProc proc, void * context = 0,
+ float interval = 1.0, bool sendStartStop = false );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProgressCallback() sets the progress notification callback for the associated
+ /// XMPFiles (library) object.
+ ///
+ /// @param proc The client's callback function. Can be zero to disable notifications.
+ ///
+ /// @param context A pointer used to carry client-private context.
+ ///
+ /// @param interval The desired number of seconds between notifications. Ideally the first
+ /// notification is sent after this interval, then at each following multiple of this interval.
+ ///
+ /// @param sendStartStop A Boolean value indicating if initial and final notifications are
+ /// wanted in addition to those at the reporting intervals.
+
+ void SetProgressCallback ( XMP_ProgressReportProc proc, void * context = 0,
+ float interval = 1.0, bool sendStartStop = false );
+
+ /// @}
+
+ // =============================================================================================
+ // Error notifications
+ // ===================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Error notifications
+ /// @{
+ ///
+ /// From the beginning through version 5.5, XMP Toolkit errors result in throwing an \c XMP_Error
+ /// exception. For the most part exceptions were thrown early and thus API calls aborted as soon
+ /// as an error was detected. Starting in version 5.5, support has been added for notifications
+ /// of errors arising in calls to \c TXMPFiles functions.
+ ///
+ /// A client can register an error notification callback function for a \c TXMPFile object. This
+ /// can be done as a global default or individually to each object. The global default applies
+ /// to all objects created after it is registered. Within the object there is no difference
+ /// between the global default or explicitly registered callback. The callback function returns
+ /// a \c bool value indicating if recovery should be attempted (true) or an exception thrown
+ /// (false). If no callback is registered, a best effort at recovery and continuation will be
+ /// made with an exception thrown if recovery is not possible.
+ ///
+ /// The number of notifications delivered for a given TXMPFiles object can be limited. This is
+ /// intended to reduce chatter from multiple or cascading errors. The limit is set when the
+ /// callback function is registered. This limits the number of notifications of the highest
+ /// severity delivered or less. If a higher severity error occurs, the counting starts again.
+ /// The limit and counting can be reset at any time, see \c ResetErrorCallbackLimit.
+
+ // --------------------------------------------------------------------------------------------
+ /// @brief SetDefaultErrorCallback() registers a global default error notification callback.
+ ///
+ /// @param proc The client's callback function.
+ ///
+ /// @param context Client-provided context for the callback.
+ ///
+ /// @param limit A limit on the number of notifications to be delivered.
+
+ static void SetDefaultErrorCallback ( XMPFiles_ErrorCallbackProc proc, void* context = 0, XMP_Uns32 limit = 1 );
+
+ // --------------------------------------------------------------------------------------------
+ /// @brief SetErrorCallback() registers an error notification callback.
+ ///
+ /// @param proc The client's callback function.
+ ///
+ /// @param context Client-provided context for the callback.
+ ///
+ /// @param limit A limit on the number of notifications to be delivered.
+
+ void SetErrorCallback ( XMPFiles_ErrorCallbackProc proc, void* context = 0, XMP_Uns32 limit = 1 );
+
+ // --------------------------------------------------------------------------------------------
+ /// @brief ResetErrorCallbackLimit() resets the error notification limit and counting. It has no
+ /// effect if an error notification callback function is not registered.
+ ///
+ /// @param limit A limit on the number of notifications to be delivered.
+
+ void ResetErrorCallbackLimit ( XMP_Uns32 limit = 1 );
+
+ /// @}
+
+ // =============================================================================================
+
+private:
+
+ XMPFilesRef xmpFilesRef;
+
+ // These are used as callbacks from the library code to the client when returning values that
+ // involve heap allocations. This ensures the allocations occur within the client.
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
+ static void SetClientStringVector ( void * clientPtr, XMP_StringPtr* arrayPtr, XMP_Uns32 stringCount );
+
+}; // class TXMPFiles
+
+// =================================================================================================
+
+#endif // __TXMPFiles_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/TXMPIterator.hpp b/gpr/source/lib/xmp_core/public/include/TXMPIterator.hpp
new file mode 100644
index 0000000..603db68
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/TXMPIterator.hpp
@@ -0,0 +1,235 @@
+#ifndef __TXMPIterator_hpp__
+#define __TXMPIterator_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// =================================================================================================
+/// \file TXMPIterator.hpp
+/// \brief API for access to the XMP Toolkit iteration services.
+///
+/// \c TXMPIterator is the template class providing iteration services for the XMP Toolkit. It must
+/// be instantiated with a string class such as \c std::string. See the instructions in XMP.hpp, and
+/// the Overview for a discussion of the overall architecture of the XMP API.
+// =================================================================================================
+
+// =================================================================================================
+/// \class TXMPIterator TXMPIterator.hpp
+/// @brief API for access to the XMP Toolkit iteration services.
+///
+/// \c TXMPIterator provides a uniform means to iterate over the schema and properties within an XMP
+/// object. \c TXMPIterator is a template class which must be instantiated with a string class such
+/// as \c std::string. See the instructions in XMP.hpp, and the Overview for a discussion of the
+/// overall architecture of the XMP API. Access these functions through the concrete class,
+/// \c SXMPIterator.
+///
+/// @note Only XMP object iteration is currently available. Future development may include iteration
+/// over global tables, such as registered namespaces.
+///
+/// To understand how iteration works, you should have a thorough understanding of the XMP data
+/// tree, as described in the XMP Specification Part 1. You might also find it helpful to create
+/// some complex XMP and examine the output of \c TXMPMeta::DumpObject().
+///
+/// \li The top of the XMP data tree is a single root node. This does not explicitly appear in the
+/// dump and is never visited by an iterator; that is, it is never returned from
+/// \c TXMPIterator::Next().
+///
+/// \li Beneath the root are schema nodes; these collect the top-level properties in the same
+/// namespace. They are created and destroyed implicitly.
+///
+/// \li Beneath the schema nodes are the property nodes. The nodes below a property node depend on
+/// its type (simple, struct, or array) and whether it has qualifiers.
+///
+/// A \c TXMPIterator constructor defines a starting point for the iteration, and options that
+/// control how it proceeds. By default, iteration starts at the root and visits all nodes beneath
+/// it in a depth-first manner. The root node iteself is not visited; the first visited node is a
+/// schema node. You can provide a schema name or property path to select a different starting node.
+/// By default, this visits the named root node first then all nodes beneath it in a depth-first
+/// manner.
+///
+/// The function \c TXMPIterator::Next() delivers the schema URI, path, and option flags for the
+/// node being visited. If the node is simple, it also delivers the value. Qualifiers for this node
+/// are visited next. The fields of a struct or items of an array are visited after the qualifiers
+/// of the parent.
+///
+/// You can specify options when contructing the iteration object to control how the iteration is
+/// performed.
+///
+/// \li \c #kXMP_IterJustChildren - Visit just the immediate children of the root. Skip the root
+/// itself and all nodes below the immediate children. This omits the qualifiers of the immediate
+/// children, the qualifier nodes being below what they qualify.
+/// \li \c #kXMP_IterJustLeafNodes - Visit just the leaf property nodes and their qualifiers.
+/// \li \c #kXMP_IterJustLeafName - Return just the leaf component of the node names. The default
+/// is to return the full path name.
+/// \li \c #kXMP_IterOmitQualifiers - Do not visit the qualifiers of a node.
+// =================================================================================================
+
+#include "client-glue/WXMPIterator.hpp"
+
+template <class tStringObj> class TXMPIterator {
+
+public:
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Assignment operator, assigns the internal ref and increments the ref count.
+ ///
+ /// Assigns the internal reference from an existing object and increments the reference count on
+ /// the underlying internal XMP iterator.
+ ///
+ /// @param rhs An existing iteration object.
+
+ void operator= ( const TXMPIterator<tStringObj> & rhs );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Copy constructor, creates a client object refering to the same internal object.
+ ///
+ /// Creates a new client iterator that refers to the same underlying iterator as an existing object.
+ ///
+ /// @param original An existing iteration object to copy.
+
+ TXMPIterator ( const TXMPIterator<tStringObj> & original );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Constructs an iterator for properties within a schema in an XMP object.
+ ///
+ /// See the class description for the general operation of an XMP object iterator.
+ /// Overloaded forms are provided to iterate the entire data tree,
+ /// a subtree rooted at a specific node, or properties within a specific schema.
+ ///
+ /// @param xmpObj The XMP object over which to iterate.
+ ///
+ /// @param schemaNS Optional schema namespace URI to restrict the iteration. To visit all of the
+ /// schema, pass 0 or the empty string "".
+ ///
+ /// @param propName Optional property name to restrict the iteration. May be an arbitrary path
+ /// expression. If provided, a schema URI must also be provided. To visit all properties, pass 0
+ /// or the empty string "".
+ ///
+ /// @param options Option flags to control the iteration. A logical OR of these bit flag constants:
+ /// \li \c #kXMP_IterJustChildren - Visit only the immediate children of the root; default visits subtrees.
+ /// \li \c #kXMP_IterJustLeafNodes - Visit only the leaf nodes; default visits all nodes.
+ /// \li \c #kXMP_IterJustLeafName - Return just the leaf part of the path; default returns the full path.
+ /// \li \c #kXMP_IterOmitQualifiers - Omit all qualifiers.
+ ///
+ /// @return The new TXMPIterator object.
+
+ TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Constructs an iterator for a subtree of properties within an XMP object.
+ ///
+ /// See the class description for the general operation of an XMP object iterator. Overloaded
+ /// forms are provided to iterate the entire data tree, a subtree rooted at a specific node, or
+ /// properties within a specific schema.
+ ///
+ /// @param xmpObj The XMP object over which to iterate.
+ ///
+ /// @param schemaNS Optional schema namespace URI to restrict the iteration. To visit all of the
+ /// schema, pass 0 or the empty string "".
+ ///
+ /// @param options Option flags to control the iteration. A logical OR of these bit flag constants:
+ /// \li \c #kXMP_IterJustChildren - Visit only the immediate children of the root; default visits subtrees.
+ /// \li \c #kXMP_IterJustLeafNodes - Visit only the leaf nodes; default visits all nodes.
+ /// \li \c #kXMP_IterJustLeafName - Return just the leaf part of the path; default returns the full path.
+ /// \li \c #kXMP_IterOmitQualifiers - Omit all qualifiers.
+ ///
+ /// @return The new TXMPIterator object.
+
+ TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Constructs an iterator for the entire data tree within an XMP object.
+ ///
+ /// See the class description for the general operation of an XMP object iterator. Overloaded
+ /// forms are provided to iterate the entire data tree, a subtree rooted at a specific node, or
+ /// properties within a specific schema.
+ ///
+ /// @param xmpObj The XMP object over which to iterate.
+ ///
+ /// @param options Option flags to control the iteration. A logical OR of these bit flag constants:
+ /// \li \c #kXMP_IterJustChildren - Visit only the immediate children of the root; default visits subtrees.
+ /// \li \c #kXMP_IterJustLeafNodes - Visit only the leaf nodes; default visits all nodes.
+ /// \li \c #kXMP_IterJustLeafName - Return just the leaf part of the path; default returns the full path.
+ /// \li \c #kXMP_IterOmitQualifiers - Omit all qualifiers.
+ ///
+ /// @return The new \c TXMPIterator object.
+
+ TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Constructs an iterator for the global tables of the XMP toolkit. Not implemented.
+
+ TXMPIterator ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Destructor, typical virtual destructor.
+
+ virtual ~TXMPIterator() throw();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Next() visits the next node in the iteration.
+ ///
+ /// Proceeds to the next node according to the options specified on creation of this object, and
+ /// delivers the schema URI, path, and option flags for the node being visited. If the node is
+ /// simple, it also delivers the value.
+ ///
+ /// @param schemaNS [out] A string object in which to return the assigned the schema namespace
+ /// URI of the current property. Can be null if the value is not wanted.
+ ///
+ /// @param propPath [out] A string object in which to return the XPath name of the current
+ /// property. Can be null if the value is not wanted.
+ ///
+ /// @param propValue [out] A string object in which to return the value of the current
+ /// property. Can be null if the value is not wanted.
+ ///
+ /// @param options [out] A buffer in which to return the flags describing the current property,
+ /// which are a logical OR of \c #XMP_OptionBits bit-flag constants.
+ ///
+ /// @return True if there was another node to visit, false if the iteration is complete.
+
+ bool Next ( tStringObj * schemaNS = 0,
+ tStringObj * propPath = 0,
+ tStringObj * propValue = 0,
+ XMP_OptionBits * options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Skip() skips some portion of the remaining iterations.
+ ///
+ /// @param options Option flags to control the iteration, a logical OR of these bit-flag
+ /// constants:
+ /// \li \c #kXMP_IterSkipSubtree - Skip the subtree below the current node.
+ /// \li \c #kXMP_IterSkipSiblings - Skip the subtree below and remaining siblings of the current node.
+
+ void Skip ( XMP_OptionBits options );
+
+private:
+
+ XMPIteratorRef iterRef;
+
+ TXMPIterator(); // ! Hidden, must choose property or table iteration.
+
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
+
+}; // class TXMPIterator
+
+// =================================================================================================
+
+#endif // __TXMPIterator_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/TXMPMeta.hpp b/gpr/source/lib/xmp_core/public/include/TXMPMeta.hpp
new file mode 100644
index 0000000..57aa62a
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/TXMPMeta.hpp
@@ -0,0 +1,1751 @@
+#ifndef __TXMPMeta_hpp__
+#define __TXMPMeta_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// =================================================================================================
+/// \file TXMPMeta.hpp
+/// \brief API for access to the XMP Toolkit core services.
+///
+/// \c TXMPMeta is the template class providing the core services of the XMP Toolkit. It must be
+/// instantiated with a string class such as \c std::string. Read the Toolkit Overview for
+/// information about the overall architecture of the XMP API, and the documentation for \c XMP.hpp
+/// for specific instantiation instructions. Please that you MUST NOT derive a class from this class,
+/// consider this class FINAL, use it directly. [1279031]
+///
+/// Access these functions through the concrete class, \c SXMPMeta.
+// =================================================================================================
+
+// =================================================================================================
+/// \class TXMPMeta TXMPMeta.hpp
+/// \brief API for access to the XMP Toolkit core services.
+///
+/// \c TXMPMeta is the template class providing the core services of the XMP Toolkit. It should be
+/// instantiated with a string class such as \c std::string. Read the Toolkit Overview for
+/// information about the overall architecture of the XMP API, and the documentation for \c XMP.hpp
+/// for specific instantiation instructions.
+///
+/// Access these functions through the concrete class, \c SXMPMeta.
+///
+/// You can create \c TXMPMeta objects (also called XMP objects) from metadata that you construct,
+/// or that you obtain from files using the XMP Toolkit's XMPFiles component; see \c TXMPFiles.hpp.
+// =================================================================================================
+
+template <class tStringObj> class TXMPIterator;
+template <class tStringObj> class TXMPUtils;
+
+// -------------------------------------------------------------------------------------------------
+
+template <class tStringObj> class TXMPMeta {
+
+public:
+
+ // =============================================================================================
+ // Initialization and termination
+ // ==============================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Initialization and termination
+ ///
+ /// @{
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetVersionInfo() retrieves runtime version information.
+ ///
+ /// The header \c XMPVersion.hpp defines a static version number for the XMP Toolkit, which
+ /// describes the version of the API used at client compile time. It is not necessarily the same
+ /// as the runtime version. Do not base runtime decisions on the static version alone; you can,
+ /// however, compare the runtime and static versions.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta). The
+ /// function can be called before calling \c TXMPMeta::Initialize().
+ ///
+ /// @param info [out] A buffer in which to return the version information.
+
+ static void GetVersionInfo ( XMP_VersionInfo * info );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Initialize() explicitly initializes the XMP Toolkit before use. */
+
+ /// Initializes the XMP Toolkit.
+ ///
+ /// Call this function before making any other calls to the \c TXMPMeta functions, except
+ /// \c TXMPMeta::GetVersionInfo().
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+ ///
+ /// @return True on success. */
+ static bool Initialize();
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Terminate() explicitly terminates usage of the XMP Toolkit.
+ ///
+ /// Frees structures created on initialization.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+
+ static void Terminate();
+
+ /// @}
+
+ // =============================================================================================
+ // Constuctors and destructor
+ // ==========================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Constructors and destructor
+ /// @{
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Default constructor, creates an empty object.
+ ///
+ /// The default constructor creates a new empty \c TXMPMeta object.
+ ///
+ /// @return The new object. */
+ TXMPMeta();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Copy constructor, creates a client object refering to the same internal object.
+ ///
+ /// The copy constructor creates a new \c TXMPMeta object that refers to the same internal XMP
+ /// object. as an existing \c TXMPMeta object.
+ ///
+ /// @param original The object to copy.
+ ///
+ /// @return The new object. */
+
+ TXMPMeta ( const TXMPMeta<tStringObj> & original );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Assignment operator, assigns the internal reference and increments the reference count.
+ ///
+ /// The assignment operator assigns the internal ref from the rhs object and increments the
+ /// reference count on the underlying internal XMP object.
+
+ void operator= ( const TXMPMeta<tStringObj> & rhs );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Reconstructs an XMP object from an internal reference.
+ ///
+ /// This constructor creates a new \c TXMPMeta object that refers to the underlying reference object
+ /// of an existing \c TXMPMeta object. Use to safely pass XMP objects across DLL boundaries.
+ ///
+ /// @param xmpRef The underlying reference object, obtained from some other XMP object with
+ /// \c TXMPMeta::GetInternalRef().
+ ///
+ /// @return The new object.
+
+ TXMPMeta ( XMPMetaRef xmpRef );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Constructs an object and parse one buffer of RDF into it.
+ ///
+ /// This constructor creates a new \c TXMPMeta object and populates it with metadata from a
+ /// buffer containing serialized RDF. This buffer must be a complete RDF parse stream.
+ ///
+ /// The result of passing serialized data to this function is identical to creating an empty
+ /// object then calling \c TXMPMeta::ParseFromBuffer(). To use the constructor, however, the RDF
+ /// must be complete. If you need to parse data from multiple buffers, create an empty object
+ /// and use \c TXMPMeta::ParseFromBuffer().
+ ///
+ /// @param buffer A pointer to the buffer of RDF to be parsed. Can be null if the length is 0;
+ /// in this case, the function creates an empty object.
+ ///
+ /// @param xmpSize The length in bytes of the buffer.
+ ///
+ /// @return The new object.
+
+ TXMPMeta ( XMP_StringPtr buffer,
+ XMP_StringLen xmpSize );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Destructor, typical virtual destructor. */
+ virtual ~TXMPMeta() throw();
+
+ /// @}
+
+ // =============================================================================================
+ // Global state functions
+ // ======================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Global option flags
+ /// @{
+ /// Global option flags affect the overall behavior of the XMP Toolkit. The available options
+ /// will be declared in \c XMP_Const.h. There are none in this version of the Toolkit.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetGlobalOptions() retrieves the set of global option flags. There are none in
+ /// this version of the Toolkit.
+ ///
+ /// This function is static; you can make the call from the class without instantiating it.
+ ///
+ /// @return A logical OR of global option bit-flag constants.
+
+ static XMP_OptionBits GetGlobalOptions();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetGlobalOptions() updates the set of global option flags. There are none in this
+ /// version of the Toolkit.
+ ///
+ /// The entire set is replaced with the new values. If only one flag is to be modified, use
+ /// \c TXMPMeta::GetGlobalOptions() to obtain the current set, modify the desired flag, then use
+ /// this function to reset the value.
+ ///
+ /// This function is static; you can make the call from the class without instantiating it.
+ ///
+ /// @param options A logical OR of global option bit-flag constants.
+
+ static void SetGlobalOptions ( XMP_OptionBits options );
+
+ /// @}
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Internal data structure dump utilities
+ /// @{
+ ///
+ /// These are debugging utilities that dump internal data structures, to be handled by
+ /// client-defined callback described in \c XMP_Const.h.
+ ///
+ /// @see Member function \c TXMPMeta::DumpObject()
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DumpNamespaces() sends the list of registered namespace URIs and prefixes to a handler.
+ ///
+ /// For debugging. Invokes a client-defined callback for each line of output.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+ ///
+ /// @param outProc The client-defined procedure to handle each line of output.
+ ///
+ /// @param clientData A pointer to client-defined data to pass to the handler.
+ ///
+ /// @return A success-fail status value, returned from the handler. Zero is success, failure
+ /// values are client-defined.
+
+ static XMP_Status DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * clientData );
+
+ /// @}
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Namespace Functions
+ /// @{
+ ///
+ /// Namespaces must be registered before use in namespace URI parameters or path expressions.
+ /// Within the XMP Toolkit the registered namespace URIs and prefixes must be unique. Additional
+ /// namespaces encountered when parsing RDF are automatically registered.
+ ///
+ /// The namespace URI should always end in an XML name separator such as '/' or '#'. This is
+ /// because some forms of RDF shorthand catenate a namespace URI with an element name to form a
+ /// new URI.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c RegisterNamespace() registers a namespace URI with a suggested prefix.
+ ///
+ /// If the URI is not registered but the suggested prefix is in use, a unique prefix is created
+ /// from the suggested one. The actual registered prefix is returned. The function result tells
+ /// if the registered prefix is the suggested one. It is not an error if the URI is already
+ /// registered, regardless of the prefix.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+ ///
+ /// @param namespaceURI The URI for the namespace. Must be a valid XML URI.
+ ///
+ /// @param suggestedPrefix The suggested prefix to be used if the URI is not yet registered.
+ /// Must be a valid XML name.
+ ///
+ /// @param registeredPrefix [out] A string object in which to return the prefix actually
+ /// registered for this URI.
+ ///
+ /// @return True if the registered prefix matches the suggested prefix.
+ ///
+ /// @note No checking is done on either the URI or the prefix. */
+
+ static bool RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ tStringObj * registeredPrefix );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetNamespacePrefix() obtains the prefix for a registered namespace URI, and
+ /// reports whether the URI is registered.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+ ///
+ /// @param namespaceURI The URI for the namespace. Must not be null or the empty string. It is
+ /// not an error if the namespace URI is not registered.
+ ///
+ /// @param namespacePrefix [out] A string object in which to return the prefix registered for
+ /// this URI, with a terminating colon character, ':'. If the namespace is not registered, this
+ /// string is not modified.
+ ///
+ /// @return True if the namespace URI is registered.
+
+ static bool GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ tStringObj * namespacePrefix );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetNamespaceURI() obtains the URI for a registered namespace prefix, and reports
+ /// whether the prefix is registered.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+ ///
+ /// @param namespacePrefix The prefix for the namespace. Must not be null or the empty string.
+ /// It is not an error if the namespace prefix is not registered.
+ ///
+ /// @param namespaceURI [out] A string object in which to return the URI registered for this
+ /// prefix. If the prefix is not registered, this string is not modified.
+ ///
+ /// @return True if the namespace prefix is registered.
+
+ static bool GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ tStringObj * namespaceURI );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Not implemented.
+ ///
+ /// Deletes a namespace from the registry. Does nothing if the URI is not registered, or if the
+ /// parameter is null or the empty string.
+ ///
+ /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
+ ///
+ /// @param namespaceURI The URI for the namespace.
+
+ static void DeleteNamespace ( XMP_StringPtr namespaceURI );
+
+ /// @}
+
+ // =============================================================================================
+ // Basic property manipulation functions
+ // =====================================
+
+ // *** Should add discussion of schemaNS and propName prefix usage.
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Accessing property values
+ /// @{
+ ///
+ /// The property value accessors all take a property specification; the top level namespace URI
+ /// (the "schema" namespace) and the basic name of the property being referenced. See the
+ /// introductory discussion of path expression usage for more information.
+ ///
+ /// The accessor functions return true if the specified property exists. If it does, output
+ /// parameters return the value (if any) and option flags describing the property. The option
+ /// bit-flag constants that describe properties are \c kXMP_PropXx and
+ /// \c kXMP_ArrayIsXx. See \c #kXMP_PropValueIsURI and following, and macros \c #XMP_PropIsSimple
+ /// and following in \c XMP_Const.h. If the property exists and has a value, it is returned as a
+ /// Unicode string in UTF-8 encoding. Arrays and the non-leaf levels of structs do not have
+ /// values.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetProperty() reports whether a property exists, and retrieves its value.
+ ///
+ /// This is the simplest property accessor. Use this to retrieve the values of top-level simple
+ /// properties, or after using the path composition functions in \c TXMPUtils.
+ ///
+ /// When specifying a namespace and path (in this and all other accessors):
+ /// \li If a namespace URI is specified, it must be for a registered namespace.
+ /// \li If the namespace is specified only by a prefix in the property name path,
+ /// it must be a registered prefix.
+ /// \li If both a URI and path prefix are present, they must be corresponding
+ /// parts of a registered namespace.
+ ///
+ /// @param schemaNS The namespace URI for the property. The URI must be for a registered
+ /// namespace. Must not be null or the empty string.
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string. The first component can be a namespace prefix; if present without a
+ /// \c schemaNS value, the prefix specifies the namespace. The prefix must be for a registered
+ /// namespace, and if a namespace URI is specified, must match the registered prefix for that
+ /// namespace.
+ ///
+ /// @param propValue [out] A string object in which to return the value of the property, if the
+ /// property exists and has a value. Arrays and non-leaf levels of structs do not have values.
+ /// Can be null if the value is not wanted.
+ ///
+ /// @param options A buffer in which to return option flags describing the property. Can be null
+ /// if the flags are not wanted.
+ ///
+ /// @return True if the property exists.
+
+ bool GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ tStringObj * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetArrayItem() provides access to items within an array.
+ ///
+ /// Reports whether the item exists; if it does, and if it has a value, the function retrieves
+ /// the value. Items are accessed by an integer index, where the first item has index 1.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem
+ /// to specify the last existing array item.
+ ///
+ /// @param itemValue [out] A string object in which to return the value of the array item, if it
+ /// has a value. Arrays and non-leaf levels of structs do not have values. Can be null if the
+ /// value is not wanted.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the array item.
+ /// Can be null if the flags are not wanted.
+ ///
+ /// @return True if the array item exists.
+
+ bool GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetStructField() provides access to fields within a nested structure.
+ ///
+ /// Reports whether the field exists; if it does, and if it has a value, the function retrieves
+ /// the value.
+ ///
+ /// @param schemaNS The namespace URI for the struct; see \c GetProperty().
+ ///
+ /// @param structName The name of the struct. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field. Same URI and prefix usage as the \c schemaNS
+ /// and \c structName parameters.
+ ///
+ /// @param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Same URI and prefix usage as the \c schemaNS and \c structName parameters.
+ ///
+ /// @param fieldValue [out] A string object in which to return the value of the field, if the
+ /// field has a value. Arrays and non-leaf levels of structs do not have values. Can be null if
+ /// the value is not wanted.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the field. Can
+ /// be null if the flags are not wanted.
+ ///
+ /// @return True if the field exists.
+
+ bool GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fieldValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetQualifier() provides access to a qualifier attached to a property.
+ ///
+ /// @note In this version of the Toolkit, qualifiers are supported only for simple leaf properties.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property to which the qualifier is attached. Can be a
+ /// general path expression, must not be null or the empty string; see \c GetProperty() for
+ /// namespace prefix usage.
+ ///
+ /// @param qualNS The namespace URI for the qualifier. Same URI and prefix usage as the
+ /// \c schemaNS and \c propName parameters.
+ ///
+ /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or
+ /// the empty string. Same URI and prefix usage as the \c schemaNS and \c propName parameters.
+ ///
+ /// @param qualValue [out] A string object in which to return the value of the qualifier, if the
+ /// qualifier has a value. Arrays and non-leaf levels of structs do not have values. Can be null
+ /// if the value is not wanted.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the qualifier.
+ /// Can be null if the flags are not wanted.
+ ///
+ /// @return True if the qualifier exists.
+
+ bool GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * qualValue,
+ XMP_OptionBits * options ) const;
+
+ /// @}
+
+ // =============================================================================================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Creating properties and setting their values
+ /// @{
+ ///
+ /// These functions all take a property specification; the top level namespace URI (the "schema"
+ /// namespace) and the basic name of the property being referenced. See the introductory
+ /// discussion of path expression usage for more information.
+ ///
+ /// All of the functions take a UTF-8 encoded Unicode string for the property value. Arrays and
+ /// non-leaf levels of structs do not have values. The value can be passed as an
+ /// \c #XMP_StringPtr (a pointer to a null-terminated string), or as a string object
+ /// (\c tStringObj).
+
+ /// Each function takes an options flag that describes the property. You can use these functions
+ /// to create empty arrays and structs by setting appropriate option flags. When you assign a
+ /// value, all levels of a struct that are implicit in the assignment are created if necessary.
+ /// \c TXMPMeta::AppendArrayItem() implicitly creates the named array if necessary.
+ ///
+ /// The allowed option bit-flags include:
+ /// \li \c #kXMP_PropValueIsStruct - Can be used to create an empty struct.
+ /// A struct is implicitly created when the first field is set.
+ /// \li \c #kXMP_PropValueIsArray - By default, a general unordered array (bag).
+ /// \li \c #kXMP_PropArrayIsOrdered - An ordered array.
+ /// \li \c #kXMP_PropArrayIsAlternate - An alternative array.
+ /// \li \c #kXMP_PropArrayIsAltText - An alt-text array. Each array element must
+ /// be a simple property with an \c xml:lang attribute.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty() creates or sets a property value.
+ ///
+ /// This is the simplest property setter. Use it for top-level simple properties, or after using
+ /// the path composition functions in \c TXMPUtils.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue The new value, a pointer to a null terminated UTF-8 string. Must be null
+ /// for arrays and non-leaf levels of structs that do not have values.
+ ///
+ /// @param options Option flags describing the property; a logical OR of allowed bit-flag
+ /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property
+ /// that already exists.
+
+ void SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty() creates or sets a property value using a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object
+ /// for the item value. It is otherwise identical; see details in the canonical form.
+
+ void SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const tStringObj & propValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetArrayItem() creates or sets the value of an item within an array.
+ ///
+ /// Items are accessed by an integer index, where the first item has index 1. This function
+ /// creates the item if necessary, but the array itself must already exist Use
+ /// \c AppendArrayItem() to create arrays. A new item is automatically appended if the index is the
+ /// array size plus 1. To insert a new item before or after an existing item, use option flags.
+ ///
+ /// Use \c TXMPUtils::ComposeArrayItemPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem
+ /// to specify the last existing array item.
+ ///
+ /// @param itemValue The new item value, a null-terminated UTF-8 string, if the array item has a
+ /// value.
+ ///
+ /// @param options Option flags describing the array type and insertion location for a new item;
+ /// a logical OR of allowed bit-flag constants. The type, if specified, must match the existing
+ /// array type, \c #kXMP_PropArrayIsOrdered, \c #kXMP_PropArrayIsAlternate, or
+ /// \c #kXMP_PropArrayIsAltText. Default (0 or \c #kXMP_NoOptions) matches the existing array type.
+ ///
+ /// To insert a new item before or after the specified index, set flag \c #kXMP_InsertBeforeItem
+ /// or \c #kXMP_InsertAfterItem.
+
+ void SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetArrayItem() creates or sets the value of an item within an array using a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object in which to
+ /// return the item value. It is otherwise identical; see details in the canonical form.
+
+ void SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ const tStringObj & itemValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c AppendArrayItem() adds an item to an array, creating the array if necessary.
+ ///
+ /// This function simplifies construction of an array by not requiring that you pre-create an
+ /// empty array. The array that is assigned is created automatically if it does not yet exist.
+ /// If the array exists, it must have the form specified by the options. Each call appends a new
+ /// item to the array.
+ ///
+ /// Use \c TXMPUtils::ComposeArrayItemPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param arrayOptions Option flags describing the array type to create; a logical OR of
+ /// allowed bit-flag constants, \c #kXMP_PropArrayIsOrdered, \c #kXMP_PropArrayIsAlternate, or
+ /// \c #kXMP_PropArrayIsAltText. If the array exists, must match the existing array type or be
+ /// null (0 or \c #kXMP_NoOptions).
+ ///
+ /// @param itemValue The new item value, a null-terminated UTF-8 string, if the array item has a
+ /// value.
+ ///
+ /// @param itemOptions Option flags describing the item type to create; one of the bit-flag
+ /// constants \c #kXMP_PropValueIsArray or \c #kXMP_PropValueIsStruct to create a complex array
+ /// item.
+
+ void AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits itemOptions = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c AppendArrayItem() adds an item to an array using a string object value, creating
+ /// the array if necessary.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object in which to
+ /// return the item value. It is otherwise identical; see details in the canonical form.
+
+ void AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ const tStringObj & itemValue,
+ XMP_OptionBits itemOptions = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetStructField() creates or sets the value of a field within a nested structure.
+ ///
+ /// Use this to set a value within an existing structure, create a new field within an existing
+ /// structure, or create an empty structure of any depth. If you set a field in a structure that
+ /// does not exist, the structure is automatically created.
+ ///
+ /// Use \c TXMPUtils::ComposeStructFieldPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param structName The name of the struct. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field. Same namespace and prefix usage as
+ /// \c GetProperty().
+ ///
+ /// @param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Same namespace and prefix usage as \c GetProperty().
+ ///
+ /// @param fieldValue The new value, a null-terminated UTF-8 string, if the field has a value.
+ /// Null to create a new, empty struct or empty field in an existing struct.
+ ///
+ /// @param options Option flags describing the property, in which the bit-flag
+ /// \c #kXMP_PropValueIsStruct must be set to create a struct.
+
+ void SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetStructField() creates or sets the value of a field within a nested structure,
+ /// using a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object in which to
+ /// return the field value. It is otherwise identical; see details in the canonical form.
+
+ void SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetQualifier() creates or sets a qualifier attached to a property.
+ ///
+ /// Use this to set a value for an existing qualifier, or create a new qualifier. <<how do
+ /// options work? macro vs bit-flag? interaction w/XMP_PropHasQualifier?>> Use
+ /// \c TXMPUtils::ComposeQualifierPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property to which the qualifier is attached. Can be a
+ /// general path expression, must not be null or the empty string; see \c GetProperty() for
+ /// namespace prefix usage.
+ ///
+ /// @param qualNS The namespace URI for the qualifier. Same namespace and prefix usage as
+ /// \c GetProperty().
+ ///
+ /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or
+ /// the empty string. Same namespace and prefix usage as \c GetProperty().
+ ///
+ /// @param qualValue The new value, a null-terminated UTF-8 string, if the qualifier has a
+ /// value. Null to create a new, empty qualifier.
+ ///
+ /// @param options Option flags describing the <<qualified property? qualifier?>>, a logical OR
+ /// of property-type bit-flag constants. Use the macro \c #XMP_PropIsQualifier to create a
+ /// qualifier. <<??>>
+
+ void SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetQualifier() creates or sets a qualifier attached to a property using a string object.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object
+ /// for the qualifier value. It is otherwise identical; see details in the canonical form.
+
+ void SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ const tStringObj & qualValue,
+ XMP_OptionBits options = 0 );
+
+ /// @}
+
+ // =============================================================================================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Detecting and deleting properties.
+ /// @{
+ ///
+ /// The namespace URI and prefix usage for property specifiers in these functions is the same as
+ /// for \c TXMPMeta::GetProperty().
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DeleteProperty() deletes an XMP subtree rooted at a given property.
+ ///
+ /// It is not an error if the property does not exist.
+ ///
+ /// @param schemaNS The namespace URI for the property; see \c GetProperty().
+ ///
+ /// @param propName The name of the property; see \c GetProperty().
+
+ void DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DeleteArrayItem() deletes an XMP subtree rooted at a given array item.
+ ///
+ /// It is not an error if the array item does not exist. Use
+ /// \c TXMPUtils::ComposeArrayItemPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem
+ /// to specify the last existing array item.
+
+ void DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DeleteStructField() deletes an XMP subtree rooted at a given struct field.
+ ///
+ /// It is not an error if the field does not exist.
+ ///
+ /// @param schemaNS The namespace URI for the struct; see \c GetProperty().
+ ///
+ /// @param structName The name of the struct. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field. Same namespace and prefix usage as
+ /// \c GetProperty().
+ ///
+ /// @param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Same namespace and prefix usage as \c GetProperty().
+
+ void DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DeleteQualifier() deletes an XMP subtree rooted at a given qualifier.
+ ///
+ /// It is not an error if the qualifier does not exist.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property to which the qualifier is attached. Can be a
+ /// general path expression, must not be null or the empty string; see \c GetProperty() for
+ /// namespace prefix usage.
+ ///
+ /// @param qualNS The namespace URI for the qualifier. Same namespace and prefix usage as
+ /// \c GetProperty().
+ ///
+ /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or
+ /// the empty string. Same namespace and prefix usage as \c GetProperty().
+
+ void DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DoesPropertyExist() reports whether a property currently exists.
+ ///
+ /// @param schemaNS The namespace URI for the property; see \c GetProperty().
+ ///
+ /// @param propName The name of the property; see \c GetProperty().
+ ///
+ /// @return True if the property exists.
+
+ bool DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DoesArrayItemExist() reports whether an array item currently exists.
+ ///
+ /// Use \c TXMPUtils::ComposeArrayItemPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param itemIndex The 1-based index of the desired item. Use the macro \c #kXMP_ArrayLastItem
+ /// to specify the last existing array item.
+ ///
+ /// @return True if the array item exists.
+
+ bool DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DoesStructFieldExist() reports whether a struct field currently exists.
+ ///
+ /// Use \c TXMPUtils::ComposeStructFieldPath() to create a complex path.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param structName The name of the struct. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field. Same namespace and prefix usage as
+ /// \c GetProperty().
+ ///
+ /// @param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Same namespace and prefix usage as \c GetProperty().
+ ///
+ /// @return True if the field exists.
+
+ bool DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DoesQualifierExist() reports whether a qualifier currently exists.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property to which the qualifier is attached. Can be a
+ /// general path expression, must not be null or the empty string; see \c GetProperty() for
+ /// namespace prefix usage.
+ ///
+ /// @param qualNS The namespace URI for the qualifier. Same namespace and prefix usage as
+ /// \c GetProperty().
+ ///
+ /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or
+ /// the empty string. Same namespace and prefix usage as \c GetProperty().
+ ///
+ /// @return True if the qualifier exists.
+
+ bool DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const;
+
+ /// @}
+
+ // =============================================================================================
+ // Specialized Get and Set functions
+ // =============================================================================================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Accessing properties as binary values.
+ /// @{
+ ///
+ /// These are very similar to \c TXMPMeta::GetProperty() and \c TXMPMeta::SetProperty(), except
+ /// that the value is returned or provided in binary form instead of as a UTF-8 string.
+ /// \c TXMPUtils provides functions for converting between binary and string values.
+ /// Use the path composition functions in \c TXMPUtils to compose complex path expressions
+ /// for fields or items in nested structures or arrays, or for qualifiers.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetProperty_Bool() retrieves the value of a Boolean property as a C++ bool.
+ ///
+ /// Reports whether a property exists, and retrieves its binary value and property type information.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue [out] A buffer in which to return the binary value. Can be null if the
+ /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have
+ /// values.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the property, a
+ /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can
+ /// be null if flags are not wanted.
+ ///
+ /// @return True if the property exists.
+
+ bool GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetProperty_Int() retrieves the value of an integer property as a C long integer.
+ ///
+ /// Reports whether a property exists, and retrieves its binary value and property type information.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue [out] A buffer in which to return the binary value. Can be null if the
+ /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have
+ /// values.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the property, a
+ /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can
+ /// be null if flags are not wanted.
+ ///
+ /// @return True if the property exists.
+
+ bool GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetProperty_Int64() retrieves the value of an integer property as a C long long integer.
+ ///
+ /// Reports whether a property exists, and retrieves its binary value and property type information.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue [out] A buffer in which to return the binary value. Can be null if the
+ /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have
+ /// values.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the property, a
+ /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can
+ /// be null if flags are not wanted.
+ ///
+ /// @return True if the property exists.
+
+ bool GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetProperty_Float() retrieves the value of a floating-point property as a C double float.
+ ///
+ /// Reports whether a property exists, and retrieves its binary value and property type information.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue [out] A buffer in which to return the binary value. Can be null if the
+ /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have
+ /// values.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the property, a
+ /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can
+ /// be null if flags are not wanted.
+ ///
+ /// @return True if the property exists.
+
+ bool GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetProperty_Date() retrieves the value of a date-time property as an \c #XMP_DateTime structure.
+ ///
+ /// Reports whether a property exists, and retrieves its binary value and property type information.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue [out] A buffer in which to return the binary value. Can be null if the
+ /// value is not wanted. Must be null for arrays and non-leaf levels of structs that do not have
+ /// values.
+ ///
+ /// @param options [out] A buffer in which to return the option flags describing the property, a
+ /// logical OR of allowed bit-flag constants; see \c #kXMP_PropValueIsStruct and following. Can
+ /// be null if flags are not wanted.
+ ///
+ /// @return True if the property exists.
+
+ bool GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty_Bool() sets the value of a Boolean property using a C++ bool.
+ ///
+ /// Sets a property with a binary value, creating it if necessary.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue The new binary value. Can be null if creating the property. Must be null
+ /// for arrays and non-leaf levels of structs that do not have values.
+ ///
+ /// @param options Option flags describing the property; a logical OR of allowed bit-flag
+ /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property
+ /// that already exists.
+
+ void SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty_Int() sets the value of an integer property using a C long integer.
+ ///
+ /// Sets a property with a binary value, creating it if necessary.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue The new binary value. Can be null if creating the property. Must be null
+ /// for arrays and non-leaf levels of structs that do not have values.
+ ///
+ /// @param options Option flags describing the property; a logical OR of allowed bit-flag
+ /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property
+ /// that already exists.
+
+ void SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty_Int64() sets the value of an integer property using a C long long integer.
+ ///
+ /// Sets a property with a binary value, creating it if necessary.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue The new binary value. Can be null if creating the property. Must be null
+ /// for arrays and non-leaf levels of structs that do not have values.
+ ///
+ /// @param options Option flags describing the property; a logical OR of allowed bit-flag
+ /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property
+ /// that already exists.
+
+ void SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty_Float() sets the value of a floating-point property using a C double float.
+ ///
+ /// Sets a property with a binary value, creating it if necessary.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue The new binary value. Can be null if creating the property. Must be null
+ /// for arrays and non-leaf levels of structs that do not have values.
+ ///
+ /// @param options Option flags describing the property; a logical OR of allowed bit-flag
+ /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property
+ /// that already exists.
+
+ void SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetProperty_Date() sets the value of a date/time property using an \c #XMP_DateTime structure.
+ ///
+ /// Sets a property with a binary value, creating it if necessary.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param propValue The new binary value. Can be null if creating the property. Must be null
+ /// for arrays and non-leaf levels of structs that do not have values.
+ ///
+ /// @param options Option flags describing the property; a logical OR of allowed bit-flag
+ /// constants; see \c #kXMP_PropValueIsStruct and following. Must match the type of a property
+ /// that already exists.
+
+ void SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options = 0 );
+
+ /// @}
+ // =============================================================================================
+ /// \name Accessing localized text (alt-text) properties.
+ /// @{
+ ///
+ /// Localized text properties are stored in alt-text arrays. They allow multiple concurrent
+ /// localizations of a property value, for example a document title or copyright in several
+ /// languages.
+ ///
+ /// These functions provide convenient support for localized text properties, including a
+ /// number of special and obscure aspects. The most important aspect of these functions is that
+ /// they select an appropriate array item based on one or two RFC 3066 language tags. One of
+ /// these languages, the "specific" language, is preferred and selected if there is an exact
+ /// match. For many languages it is also possible to define a "generic" language that can be
+ /// used if there is no specific language match. The generic language must be a valid RFC 3066
+ /// primary subtag, or the empty string.
+ ///
+ /// For example, a specific language of "en-US" should be used in the US, and a specific
+ /// language of "en-UK" should be used in England. It is also appropriate to use "en" as the
+ /// generic language in each case. If a US document goes to England, the "en-US" title is
+ /// selected by using the "en" generic language and the "en-UK" specific language.
+ ///
+ /// It is considered poor practice, but allowed, to pass a specific language that is just an
+ /// RFC 3066 primary tag. For example "en" is not a good specific language, it should only be
+ /// used as a generic language. Passing "i" or "x" as the generic language is also considered
+ /// poor practice but allowed.
+ ///
+ /// Advice from the W3C about the use of RFC 3066 language tags can be found at:
+ /// \li http://www.w3.org/International/articles/language-tags/
+ ///
+ /// \note RFC 3066 language tags must be treated in a case insensitive manner. The XMP toolkit
+ /// does this by normalizing their capitalization:
+ /// \li The primary subtag is lower case, the suggested practice of ISO 639.
+ /// \li All 2 letter secondary subtags are upper case, the suggested practice of ISO 3166.
+ /// \li All other subtags are lower case.
+ ///
+ /// The XMP specification defines an artificial language, "x-default", that is used to
+ /// explicitly denote a default item in an alt-text array. The XMP toolkit normalizes alt-text
+ /// arrays such that the x-default item is the first item. The \c SetLocalizedText() function
+ /// has several special features related to the x-default item, see its description for details.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetLocalizedText() retrieves information about a selected item in an alt-text array.
+ ///
+ /// The array item is selected according to these rules:
+ /// \li Look for an exact match with the specific language.
+ /// \li If a generic language is given, look for a partial match.
+ /// \li Look for an x-default item.
+ /// \li Choose the first item.
+ ///
+ /// A partial match with the generic language is where the start of the item's language matches
+ /// the generic string and the next character is '-'. An exact match is also recognized as a
+ /// degenerate case.
+ ///
+ /// You can pass "x-default" as the specific language. In this case, selection of an
+ /// \c x-default item is an exact match by the first rule, not a selection by the 3rd rule. The
+ /// last 2 rules are fallbacks used when the specific and generic languages fail to produce a
+ /// match.
+ ///
+ /// The return value reports whether a match was successfully made.
+ ///
+ /// @param schemaNS The namespace URI for the alt-text array; see \c GetProperty().
+ ///
+ /// @param altTextName The name of the alt-text array. Can be a general path expression, must
+ /// not be null or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be
+ /// null or the empty string if no generic language is wanted.
+ ///
+ /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default".
+ /// Must not be null or the empty string.
+ ///
+ /// @param actualLang [out] A string object in which to return the language of the selected
+ /// array item, if an appropriate array item is found. Can be null if the language is not wanted.
+ ///
+ /// @param itemValue [out] A string object in which to return the value of the array item, if an
+ /// appropriate array item is found. Can be null if the value is not wanted.
+ ///
+ /// @param options A buffer in which to return the option flags that describe the array item, if
+ /// an appropriate array item is found. Can be null if the flags are not wanted.
+ ///
+ /// @return True if an appropriate array item exists.
+
+ bool GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ tStringObj * actualLang,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetLocalizedText() modifies the value of a selected item in an alt-text array.
+ ///
+ /// Creates an appropriate array item if necessary, and handles special cases for the x-default
+ /// item.
+ ///
+ /// The array item is selected according to these rules:
+ /// \li Look for an exact match with the specific language.
+ /// \li If a generic language is given, look for a partial match.
+ /// \li Look for an x-default item.
+ /// \li Choose the first item.
+ ///
+ /// A partial match with the generic language is where the start of the item's language matches
+ /// the generic string and the next character is '-'. An exact match is also recognized as a
+ /// degenerate case.
+ ///
+ /// You can pass "x-default" as the specific language. In this case, selection of an
+ /// \c x-default item is an exact match by the first rule, not a selection by the 3rd rule. The
+ /// last 2 rules are fallbacks used when the specific and generic languages fail to produce a
+ /// match.
+ ///
+ /// Item values are modified according to these rules:
+ ///
+ /// \li If the selected item is from a match with the specific language, the value of that
+ /// item is modified. If the existing value of that item matches the existing value of the
+ /// x-default item, the x-default item is also modified. If the array only has 1 existing item
+ /// (which is not x-default), an x-default item is added with the given value.
+ ///
+ /// \li If the selected item is from a match with the generic language and there are no other
+ /// generic matches, the value of that item is modified. If the existing value of that item
+ /// matches the existing value of the x-default item, the x-default item is also modified. If
+ /// the array only has 1 existing item (which is not x-default), an x-default item is added
+ /// with the given value.
+ ///
+ /// \li If the selected item is from a partial match with the generic language and there are
+ /// other partial matches, a new item is created for the specific language. The x-default item
+ /// is not modified.
+ ///
+ /// \li If the selected item is from the last 2 rules then a new item is created for the
+ /// specific language. If the array only had an x-default item, the x-default item is also
+ /// modified. If the array was empty, items are created for the specific language and
+ /// x-default.
+ ///
+ /// @param schemaNS The namespace URI for the alt-text array; see \c GetProperty().
+ ///
+ /// @param altTextName The name of the alt-text array. Can be a general path expression, must
+ /// not be null or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be
+ /// null or the empty string if no generic language is wanted.
+ ///
+ /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default".
+ /// Must not be null or the empty string.
+ ///
+ /// @param itemValue The new value for the matching array item, specified as a null-terminated
+ /// UTF-8 string.
+ ///
+ /// @param options Option flags, none currently defined.
+
+ void SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetLocalizedText() modifies the value of a selected item in an alt-text array using
+ /// a string object.
+ ///
+ /// Creates an appropriate array item if necessary, and handles special cases for the x-default
+ /// item.
+ ///
+ /// The array item is selected according to these rules:
+ /// \li Look for an exact match with the specific language.
+ /// \li If a generic language is given, look for a partial match.
+ /// \li Look for an x-default item.
+ /// \li Choose the first item.
+ ///
+ /// A partial match with the generic language is where the start of the item's language matches
+ /// the generic string and the next character is '-'. An exact match is also recognized as a
+ /// degenerate case.
+ ///
+ /// You can pass "x-default" as the specific language. In this case, selection of an \c x-default
+ /// item is an exact match by the first rule, not a selection by the 3rd rule. The last 2 rules
+ /// are fallbacks used when the specific and generic languages fail to produce a match.
+ ///
+ /// Item values are modified according to these rules:
+ ///
+ /// \li If the selected item is from a match with the specific language, the value of that
+ /// item is modified. If the existing value of that item matches the existing value of the
+ /// x-default item, the x-default item is also modified. If the array only has 1 existing item
+ /// (which is not x-default), an x-default item is added with the given value.
+ ///
+ /// \li If the selected item is from a match with the generic language and there are no other
+ /// generic matches, the value of that item is modified. If the existing value of that item
+ /// matches the existing value of the x-default item, the x-default item is also modified. If
+ /// the array only has 1 existing item (which is not x-default), an x-default item is added
+ /// with the given value.
+ ///
+ /// \li If the selected item is from a partial match with the generic language and there are
+ /// other partial matches, a new item is created for the specific language. The x-default item
+ /// is not modified.
+ ///
+ /// \li If the selected item is from the last 2 rules then a new item is created for the
+ /// specific language. If the array only had an x-default item, the x-default item is also
+ /// modified. If the array was empty, items are created for the specific language and
+ /// x-default.
+ ///
+ /// @param schemaNS The namespace URI for the alt-text array; see \c GetProperty().
+ ///
+ /// @param altTextName The name of the alt-text array. Can be a general path expression, must
+ /// not be null or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be
+ /// null or the empty string if no generic language is wanted.
+ ///
+ /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default".
+ /// Must not be null or the empty string.
+ ///
+ /// @param itemValue The new value for the matching array item, specified as a string object.
+ ///
+ /// @param options Option flags, none currently defined.
+
+ void SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ const tStringObj & itemValue,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DeleteLocalizedText() deletes specific language alternatives from an alt-text array.
+ ///
+ /// The rules for finding the language value to delete are similar to those for \c #SetLocalizedText().
+ ///
+ /// @param schemaNS The namespace URI for the alt-text array; see \c #GetProperty().
+ ///
+ /// @param altTextName The name of the alt-text array. Can be a general path expression, must
+ /// not be null or the empty string; see \c #GetProperty() for namespace prefix usage.
+ ///
+ /// @param genericLang The name of the generic language as an RFC 3066 primary subtag. Can be
+ /// null or the empty string if no generic language is wanted.
+ ///
+ /// @param specificLang The name of the specific language as an RFC 3066 tag, or "x-default".
+ /// Must not be null or the empty string.
+ ///
+ void
+ DeleteLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Creating and reading serialized RDF.
+ /// @{
+ ///
+ /// The metadata contained in an XMP object must be serialized as RDF for storage in an XMP
+ /// packet and output to a file. Similarly, metadata in the form of serialized RDF (such as
+ /// metadata read from a file using \c TXMPFiles) must be parsed into an XMP object for
+ /// manipulation with the XMP Toolkit.
+ ///
+ /// These functions support parsing serialized RDF into an XMP object, and serializing an XMP
+ /// object into RDF. The input for parsing can be any valid Unicode encoding. ISO Latin-1 is
+ /// also recognized, but its use is strongly discouraged. Serialization is always as UTF-8.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ParseFromBuffer() parses RDF from a series of input buffers into this XMP object.
+ ///
+ /// Use this to convert metadata from serialized RDF form (as, for example, read from an XMP
+ /// packet embedded in a file) into an XMP object that you can manipulate with the XMP Toolkit.
+ /// If this XMP object is empty and the input buffer contains a complete XMP packet, this is the
+ /// same as creating a new XMP object from that buffer with the constructor.
+ ///
+ /// You can use this function to combine multiple buffers into a single metadata tree. To
+ /// terminate an input loop conveniently, pass the option \c #kXMP_ParseMoreBuffers for all
+ /// real input, then make a final call with a zero length and \c #kXMP_NoOptions. The buffers
+ /// can be any length. The buffer boundaries need not respect XML tokens or even Unicode
+ /// characters.
+ ///
+ /// @param buffer A pointer to a buffer of input. Can be null if \c bufferSize is 0.
+ ///
+ /// @param bufferSize The length of the input buffer in bytes. Zero is a valid value.
+ ///
+ /// @param options An options flag that controls how the parse operation is performed. A logical
+ /// OR of these bit-flag constants:
+ /// \li \c #kXMP_ParseMoreBuffers - This is not the last buffer of input, more calls follow.
+ /// \li \c #kXMP_RequireXMPMeta - The \c x:xmpmeta XML element is required around \c rdf:RDF.
+ ///
+ /// @see \c TXMPFiles::GetXMP()
+
+ void ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SerializeToBuffer() serializes metadata in this XMP object into a string as RDF.
+ ///
+ /// Use this to prepare metadata for storage as an XMP packet embedded in a file. See \c TXMPFiles::PutXMP().
+ ///
+ /// @param rdfString [out] A string object in which to return the serialized RDF. Must not be null.
+ ///
+ /// @param options An options flag that controls how the serialization operation is performed.
+ /// The specified options must be logically consistent; an exception is thrown if they are not.
+ /// A logical OR of these bit-flag constants:
+ /// \li \c kXMP_OmitPacketWrapper - Do not include an XML packet wrapper. This cannot be
+ /// specified together with \c #kXMP_ReadOnlyPacket, \c #kXMP_IncludeThumbnailPad, or
+ /// \c #kXMP_ExactPacketLength.
+ /// \li \c kXMP_ReadOnlyPacket - Create a read-only XML packet wapper. Cannot be specified
+ /// together with \c kXMP_OmitPacketWrapper.
+ /// \li \c kXMP_UseCompactFormat - Use a highly compact RDF syntax and layout.
+ /// \li \c kXMP_IncludeThumbnailPad - Include typical space for a JPEG thumbnail in the
+ /// padding if no \c xmp:Thumbnails property is present. Cannot be specified together with
+ /// \c kXMP_OmitPacketWrapper.
+ /// \li \c kXMP_ExactPacketLength - The padding parameter provides the overall packet length.
+ /// The actual amount of padding is computed. An exception is thrown if the packet exceeds
+ /// this length with no padding. Cannot be specified together with
+ /// \c kXMP_OmitPacketWrapper.
+ ///
+ /// In addition to the above options, you can include one of the following encoding options:
+ /// \li \c #kXMP_EncodeUTF8 - Encode as UTF-8, the default.
+ /// \li \c #kXMP_EncodeUTF16Big - Encode as big-endian UTF-16.
+ /// \li \c #kXMP_EncodeUTF16Little - Encode as little-endian UTF-16.
+ /// \li \c #kXMP_EncodeUTF32Big - Encode as big-endian UTF-32.
+ /// \li \c #kXMP_EncodeUTF32Little - Encode as little-endian UTF-32.
+ ///
+ /// @param padding The amount of padding to be added if a writeable XML packet is created. If
+ /// zero (the default) an appropriate amount of padding is computed.
+ ///
+ /// @param newline The string to be used as a line terminator. If empty, defaults to linefeed,
+ /// U+000A, the standard XML newline.
+ ///
+ /// @param indent The string to be used for each level of indentation in the serialized RDF. If
+ /// empty, defaults to two ASCII spaces, U+0020.
+ ///
+ /// @param baseIndent The number of levels of indentation to be used for the outermost XML
+ /// element in the serialized RDF. This is convenient when embedding the RDF in other text.
+
+ void SerializeToBuffer ( tStringObj * rdfString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent = "",
+ XMP_Index baseIndent = 0 ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SerializeToBuffer() serializes metadata in this XMP object into a string as RDF.
+ ///
+ /// This simpler form of the function uses default values for the \c newline, \c indent, and
+ /// \c baseIndent parameters.
+ ///
+ /// @param rdfString [out] A string object in which to return the serialized RDF. Must not be null.
+ ///
+ /// @param options An options flag that controls how the serialization operation is performed.
+ /// The specified options must be logically consistent; an exception is thrown if they are not.
+ /// A logical OR of these bit-flag constants:
+ /// \li \c kXMP_OmitPacketWrapper - Do not include an XML packet wrapper. This cannot be
+ /// specified together with \c #kXMP_ReadOnlyPacket, \c #kXMP_IncludeThumbnailPad, or
+ /// \c #kXMP_ExactPacketLength.
+ /// \li \c kXMP_ReadOnlyPacket - Create a read-only XML packet wapper. Cannot be specified
+ /// together with \c kXMP_OmitPacketWrapper.
+ /// \li \c kXMP_UseCompactFormat - Use a highly compact RDF syntax and layout.
+ /// \li \c kXMP_IncludeThumbnailPad - Include typical space for a JPEG thumbnail in the
+ /// padding if no \c xmp:Thumbnails property is present. Cannot be specified together with
+ /// \c kXMP_OmitPacketWrapper.
+ /// \li \c kXMP_ExactPacketLength - The padding parameter provides the overall packet length.
+ /// The actual amount of padding is computed. An exception is thrown if the packet exceeds
+ /// this length with no padding. Cannot be specified together with
+ /// \c kXMP_OmitPacketWrapper.
+ ///
+ /// In addition to the above options, you can include one of the following encoding options:
+ /// \li \c #kXMP_EncodeUTF8 - Encode as UTF-8, the default.
+ /// \li \c #kXMP_EncodeUTF16Big - Encode as big-endian UTF-16.
+ /// \li \c #kXMP_EncodeUTF16Little - Encode as little-endian UTF-16.
+ /// \li \c #kXMP_EncodeUTF32Big - Encode as big-endian UTF-32.
+ /// \li \c #kXMP_EncodeUTF32Little - Encode as little-endian UTF-32.
+ ///
+ /// @param padding The amount of padding to be added if a writeable XML packet is created.
+ /// If zero (the default) an appropriate amount of padding is computed.
+
+ void SerializeToBuffer ( tStringObj * rdfString,
+ XMP_OptionBits options = 0,
+ XMP_StringLen padding = 0 ) const;
+
+ /// @}
+ // =============================================================================================
+ // Miscellaneous Member Functions
+ // ==============================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Helper functions.
+ /// @{
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Retrieves an internal reference that can be safely passed across DLL boundaries and
+ /// reconstructed.
+ ///
+ /// The \c TXMPMeta class is a normal C++ template, it is instantiated and local to each client
+ /// executable, as are the other \c TXMP* classes. Different clients might not use the same
+ /// string type to instantiate \c TXMPMeta.
+ ///
+ /// Because of this you should not pass \c SXMPMeta objects, or pointers to \c SXMPMeta objects,
+ /// across DLL boundaries. Use this function to obtain a safe internal reference that you can
+ /// pass, then construct a local object on the callee side. This construction does not create a
+ /// cloned XMP tree, it is the same underlying XMP object safely wrapped in each client's
+ /// \c SXMPMeta object.
+ ///
+ /// Use this function and the associated constructor like this:
+ /// \li The callee's header contains:
+ /// <pre>
+ /// CalleeMethod ( XMPMetaRef xmpRef );
+ /// </pre>
+ ///
+ /// \li The caller's code contains:
+ /// <pre>
+ /// SXMPMeta callerXMP;
+ /// CalleeMethod ( callerXMP.GetInternalRef() );
+ /// </pre>
+ ///
+ /// \li The callee's code contains:
+ /// <pre>
+ /// SXMPMeta calleeXMP ( xmpRef );
+ /// </pre>
+ ///
+ /// @return The reference object.
+
+ XMPMetaRef GetInternalRef() const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c GetObjectName() retrieves the client-assigned name of this XMP object.
+ ///
+ /// Assign this name with \c SetObjectName().
+ ///
+ /// @param name [out] A string object in which to return the name.
+
+ void GetObjectName ( tStringObj * name ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetObjectName() assigns a name to this XMP object.
+ ///
+ /// Retrieve this client-assigned name with \c GetObjectName().
+ ///
+ /// @param name The name as a null-terminated UTF-8 string.
+
+ void SetObjectName ( XMP_StringPtr name );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetObjectName() assigns a name to this XMP object.
+ ///
+ /// Retrieve this client-assigned name with \c GetObjectName().
+ ///
+ /// @param name The name as a string object.
+
+ void SetObjectName ( tStringObj name );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Sort() sorts the data model tree of an XMP object.
+ ///
+ /// Use this function to sort the data model of an XMP object into a canonical order. This can
+ /// be convenient when comparing data models, (e.g. by text comparison of DumpObject output).
+ ///
+ /// At the top level the namespaces are sorted by their prefixes. Within a namespace, the top
+ /// level properties are sorted by name. Within a struct, the fields are sorted by their
+ /// qualified name, i.e. their XML prefix:local form. Unordered arrays of simple items are
+ /// sorted by value. Language Alternative arrays are sorted by the xml:lang qualifiers, with
+ /// the "x-default" item placed first.
+
+ void Sort();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Erase() restores the object to a "just constructed" state.
+
+ void Erase();
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c Clone() creates a deep copy of an XMP object.
+ ///
+ /// Use this function to copy an entire XMP metadata tree. Assignment and copy constructors only
+ /// increment a reference count, they do not do a deep copy. This function returns an object,
+ /// not a pointer. The following shows correct usage:
+ ///
+ /// <pre>
+ /// SXMPMeta * clone1 = new SXMPMeta ( sourceXMP.Clone() ); // This works.
+ /// SXMPMeta clone2 ( sourceXMP.Clone ); // This works also. (Not a pointer.)
+ /// </pre>
+ /// The \c clone2 example does not use an explicit pointer.
+ /// This is good for local usage, protecting against memory leaks.
+ ///
+ /// This is an example of incorrect usage:
+ /// <pre>
+ /// SXMPMeta * clone3 = &sourceXMP.Clone(); // ! This does not work!
+ /// </pre>
+ /// The assignment to \c clone3 creates a temporary object, initializes it with the clone,
+ /// assigns the address of the temporary to \c clone3, then deletes the temporary.
+ ///
+ /// @param options Option flags, not currently defined..
+ ///
+ /// @return An XMP object cloned from the original.
+
+ TXMPMeta Clone ( XMP_OptionBits options = 0 ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CountArrayItems() reports the number of items currently defined in an array.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @return The number of items.
+
+ XMP_Index CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DumpObject() outputs the content of an XMP object to a callback handler for debugging.
+ ///
+ /// Invokes a client-defined callback for each line of output.
+ ///
+ /// @param outProc The client-defined procedure to handle each line of output.
+ ///
+ /// @param clientData A pointer to client-defined data to pass to the handler.
+ ///
+ /// @return A success-fail status value, returned from the handler. Zero is success, failure
+ /// values are client-defined.
+ ///
+ /// @see Static function \c DumpNamespaces()
+
+ XMP_Status DumpObject ( XMP_TextOutputProc outProc,
+ void * clientData ) const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Not implemented
+ XMP_OptionBits GetObjectOptions() const;
+
+ // ---------------------------------------------------------------------------------------------
+ /// \brief Not implemented
+ void SetObjectOptions ( XMP_OptionBits options );
+
+ /// @}
+
+ // =============================================================================================
+ // Error notifications
+ // ===================
+
+ // ---------------------------------------------------------------------------------------------
+ /// \name Error notifications
+ /// @{
+ ///
+ /// From the beginning through version 5.5, XMP Tookit errors result in throwing an \c XMP_Error
+ /// exception. For the most part exceptions were thrown early and thus API calls aborted as soon
+ /// as an error was detected. Starting in version 5.5, support has been added for notifications
+ /// of errors arising in calls to \c TXMPMeta functions.
+ ///
+ /// A client can register an error notification callback function for a \c TXMPMeta object. This
+ /// can be done as a global default or individually to each object. The global default applies
+ /// to all objects created after it is registered. Within the object there is no difference
+ /// between the global default or explicitly registered callback. The callback function returns
+ /// a \c bool value indicating if recovery should be attempted (true) or an exception thrown
+ /// (false). If no callback is registered, a best effort at recovery and continuation will be
+ /// made with an exception thrown if recovery is not possible.
+ ///
+ /// The number of notifications delivered for a given TXMPMeta object can be limited. This is
+ /// intended to reduce chatter from multiple or cascading errors. The limit is set when the
+ /// callback function is registered. This limits the number of notifications of the highest
+ /// severity delivered or less. If a higher severity error occurs, the counting starts again.
+ /// The limit and counting can be reset at any time, see \c ResetErrorCallbackLimit.
+
+ // --------------------------------------------------------------------------------------------
+ /// @brief SetDefaultErrorCallback() registers a global default error notification callback.
+ ///
+ /// @param proc The client's callback function.
+ ///
+ /// @param context Client-provided context for the callback.
+ ///
+ /// @param limit A limit on the number of notifications to be delivered.
+
+ static void SetDefaultErrorCallback ( XMPMeta_ErrorCallbackProc proc, void* context = 0, XMP_Uns32 limit = 1 );
+
+ // --------------------------------------------------------------------------------------------
+ /// @brief SetErrorCallback() registers an error notification callback.
+ ///
+ /// @param proc The client's callback function.
+ ///
+ /// @param context Client-provided context for the callback.
+ ///
+ /// @param limit A limit on the number of notifications to be delivered.
+
+ void SetErrorCallback ( XMPMeta_ErrorCallbackProc proc, void* context = 0, XMP_Uns32 limit = 1 );
+
+ // --------------------------------------------------------------------------------------------
+ /// @brief ResetErrorCallbackLimit() resets the error notification limit and counting. It has no
+ /// effect if an error notification callback function is not registered.
+ ///
+ /// @param limit A limit on the number of notifications to be delivered.
+
+ void ResetErrorCallbackLimit ( XMP_Uns32 limit = 1 );
+
+ /// @}
+
+ // =============================================================================================
+
+ XMPMetaRef xmpRef; // *** Should be private, see below.
+
+private:
+
+#if 0 // *** VS.Net and gcc seem to not handle the friend declarations properly.
+ friend class TXMPIterator <class tStringObj>;
+ friend class TXMPUtils <class tStringObj>;
+#endif
+
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
+
+}; // class TXMPMeta
+
+#endif // __TXMPMeta_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/TXMPUtils.hpp b/gpr/source/lib/xmp_core/public/include/TXMPUtils.hpp
new file mode 100644
index 0000000..79ade07
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/TXMPUtils.hpp
@@ -0,0 +1,967 @@
+#ifndef __TXMPUtils_hpp__
+#define __TXMPUtils_hpp__ 1
+
+#if ( ! __XMP_hpp__ )
+ #error "Do not directly include, use XMP.hpp"
+#endif
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// =================================================================================================
+/// \file TXMPUtils.hpp
+/// \brief API for access to the XMP Toolkit utility services.
+///
+/// \c TXMPUtils is the template class providing utility services for the XMP Toolkit. It must be
+/// instantiated with a string class such as \c std::string. See the instructions in XMP.hpp, and
+/// the Overview for a discussion of the overall architecture of the XMP API.
+// =================================================================================================
+
+// =================================================================================================
+/// \class TXMPUtils TXMPUtils.hpp
+/// @brief API for access to the XMP Toolkit utility services.
+///
+/// \c TXMPUtils is a template class which must be instantiated with a string class such as
+/// \c std::string. See the instructions in XMP.hpp, and the Overview for a discussion of the overall
+/// architecture of the XMP API.
+///
+/// This class defines helper functions that support the basic metadata manipulation provided by
+/// \c TXMPMeta. All of the functions are static; that is, you call them directly from the concrete
+/// class (\c SXMPUtils), which is never itself instantiated.
+///
+/// General categories of utilities include:
+///
+/// \li Composing complex path expressions, which you can then pass to the property access
+/// functions in \c TXMPMeta
+/// \li Converting between binary and string forms of property values
+/// \li Manipulating date/time values
+/// \li Encoding and decoding base-64 strings
+/// \li JPEG file handling
+/// \li Editing aids for creating a user interface for the XMP Toolkit
+// =================================================================================================
+
+template <class tStringObj> class TXMPUtils {
+
+public:
+
+ // =============================================================================================
+ // No constructors or destructor declared or needed
+ // ================================================
+
+ // ============================================================================================
+ /// \name Path composition
+ /// @{
+ ///
+ /// These functions provide support for composing path expressions to deeply nested properties.
+ /// The functions in \c TXMPMeta such as \c TXMPMeta::GetProperty(),
+ /// \c TXMPMeta::GetArrayItem(), and \c TXMPMeta::GetStructField() provide easy access to top level
+ /// simple properties, items in top level arrays, and fields of top level structs. They are
+ /// not as convenient for more complex things, such as fields several levels deep in a complex
+ /// struct, or fields within an array of structs, or items of an array that is a field of a
+ /// struct. You can use these utility functions to compose these paths, which you can then pass
+ /// to the property access functions. You can also compose paths to top-level array items or
+ /// struct fields so that you can use the binary accessors such as
+ /// \c TXMPMeta::GetProperty_Int().
+ ///
+ /// You can use these functions is to compose a complete path expression, or all but the last
+ /// component. For example, suppose you have a property that is an array of integers within a
+ /// struct. You can access one of the array items like this:
+ ///
+ /// <pre>
+ /// SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
+ /// SXMPUtils::ComposeArrayItemPath ( schemaNS, path, index, &path );
+ /// exists = xmpObj.GetProperty_Int ( schemaNS, path, &value, &options );
+ /// </pre>
+ ///
+ /// You could also use this code if you want the string form of the integer:
+ ///
+ /// <pre>
+ /// SXMPUtils::ComposeStructFieldPath ( schemaNS, "Struct", fieldNS, "Array", &path );
+ /// xmpObj.GetArrayItem ( schemaNS, path, index, &value, &options );
+ /// </pre>
+ ///
+ /// \note It might look confusing that the \c schemaNS is passed in all of the calls above. This
+ /// is because the XMP Toolkit keeps the top-level "schema" namespace separate from the rest of
+ /// the path expression.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeArrayItemPath() composes the path expression for an item in an array.
+ ///
+ /// The returned string is in the form <tt>ns:arrayName[i]</tt>, where "ns" is the prefix for
+ /// the specified namespace, and "i" is the decimal representation of specified item index.
+ /// If the last item was specified, the path is <tt>ns:arrayName[last()]</tt>.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param itemIndex The 1-based index of the desired item. Use the macro
+ /// \c #kXMP_ArrayLastItem to specify the last existing array item.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeStructFieldPath() composes the path expression for a field in a struct.
+ ///
+ /// The returned string is in the form <tt>ns:structName/fNS:fieldName</tt>, where "ns" is the
+ /// prefix for the schema namespace, and "fNS" is the prefix for field namespace.
+ ///
+ /// @param schemaNS The namespace URI for the struct; see \c GetProperty().
+ ///
+ /// @param structName The name of the struct. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field. Same URI and prefix usage as the
+ /// \c schemaNS and \c structName parameters.
+ ///
+ /// @param fieldName The name of the field. Must be a single XML name, must not be null or the
+ /// empty string. Same URI and prefix usage as the \c schemaNS and \c structName parameters.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeQualifierPath() composes the path expression for a qualifier.
+ ///
+ /// The returned string is in the form <tt>ns:propName/?qNS:qualName</tt>, where "ns" is the
+ /// prefix for the schema namespace, and "qNS" is the prefix for the qualifier namespace.
+ ///
+ /// @param schemaNS The namespace URI; see \c GetProperty().
+ ///
+ /// @param propName The name of the property to which the qualifier is attached. Can be a
+ /// general path expression, must not be null or the empty string; see \c GetProperty() for
+ /// namespace prefix usage.
+ ///
+ /// @param qualNS The namespace URI for the qualifier. Same URI and prefix usage as the
+ /// \c schemaNS and \c propName parameters.
+ ///
+ /// @param qualName The name of the qualifier. Must be a single XML name, must not be null or the
+ /// empty string. Same URI and prefix usage as the \c schemaNS and \c propName parameters.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeLangSelector() composes the path expression to select an alternate item by language.
+ ///
+ /// Path syntax allows two forms of "content addressing" to select an item in an array of
+ /// alternatives. The form used in this function lets you select an item in an alt-text array
+ /// based on the value of its \c xml:lang qualifier. The other form of content addressing is
+ /// shown in \c ComposeFieldSelector().
+ ///
+ /// The returned string is in the form <tt>ns:arrayName[\@xml:lang='langName']</tt>, where
+ /// "ns" is the prefix for the schema namespace
+ ///
+ /// This function provides a path expression that is explicitly and only for a specific
+ /// language. In most cases, \c TXMPMeta::SetLocalizedText() and \c TXMPMeta::GetLocalizedText()
+ /// are preferred, because they provide extra logic to choose the appropriate language and
+ /// maintain consistency with the 'x-default' value.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param langName The RFC 3066 code for the desired language, as a null-terminated UTF-8 string.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ tStringObj * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeLangSelector() composes a path expression to select an alternate item by language.
+ ///
+ /// Path syntax allows two forms of "content addressing" to select an item in an array of
+ /// alternatives. The form used in this function lets you select an item in an alt-text array
+ /// based on the value of its \c xml:lang qualifier. The other form of content addressing is
+ /// shown in \c ComposeFieldSelector().
+ ///
+ /// The returned string is in the form <tt>ns:arrayName[\@xml:lang='langName']</tt>, where
+ /// "ns" is the prefix for the schema namespace
+ ///
+ /// This function provides a path expression that is explicitly and only for a specific
+ /// language. In most cases, \c TXMPMeta::SetLocalizedText() and \c TXMPMeta::GetLocalizedText()
+ /// are preferred, because they provide extra logic to choose the appropriate language and
+ /// maintain consistency with the 'x-default' value.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param langName The RFC 3066 code for the desired language, as a string object.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ const tStringObj & langName,
+ tStringObj * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeFieldSelector() composes a path expression to select an alternate item by a field's value.
+ ///
+ /// Path syntax allows two forms of "content addressing" to select an item in an array of
+ /// alternatives. The form used in this function lets you select an item in an array of structs
+ /// based on the value of one of the fields in the structs. The other form of content addressing
+ /// is shown in \c ComposeLangSelector().
+ ///
+ /// For example, consider a simple struct that has two fields, the name of a city and the URI of
+ /// an FTP site in that city. Use this to create an array of download alternatives. You can show
+ /// the user a popup built from the values of the city fields, then get the corresponding URI as
+ /// follows:
+ /// <pre>
+ /// ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
+ /// exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
+ /// </pre>
+ ///
+ /// The returned string is in the form <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where
+ /// "ns" is the prefix for the schema namespace and "fNS" is the prefix for the field namespace.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field used as the selector. Same URI and prefix
+ /// usage as the \c schemaNS and \c arrayName parameters.
+ ///
+ /// @param fieldName The name of the field used as the selector. Must be a single XML name, must
+ /// not be null or the empty string. It must be the name of a field that is itself simple.
+ ///
+ /// @param fieldValue The desired value of the field, specified as a null-terminated UTF-8 string.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ tStringObj * fullPath );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ComposeFieldSelector() composes a path expression to select an alternate item by a field's value.
+ ///
+ /// Path syntax allows two forms of "content addressing" to select an item in an array of
+ /// alternatives. The form used in this function lets you select an item in an array of structs
+ /// based on the value of one of the fields in the structs. The other form of content addressing
+ /// is shown in \c ComposeLangSelector().
+ ///
+ /// For example, consider a simple struct that has two fields, the name of a city and the URI of
+ /// an FTP site in that city. Use this to create an array of download alternatives. You can show
+ /// the user a popup built from the values of the city fields, then get the corresponding URI as
+ /// follows:
+ /// <pre>
+ /// ComposeFieldSelector ( schemaNS, "Downloads", fieldNS, "City", chosenCity, &path );
+ /// exists = GetStructField ( schemaNS, path, fieldNS, "URI", &uri );
+ /// </pre>
+ ///
+ /// The returned string is in the form <tt>ns:arrayName[fNS:fieldName='fieldValue']</tt>, where
+ /// "ns" is the prefix for the schema namespace and "fNS" is the prefix for the field namespace.
+ ///
+ /// @param schemaNS The namespace URI for the array; see \c GetProperty().
+ ///
+ /// @param arrayName The name of the array. Can be a general path expression, must not be null
+ /// or the empty string; see \c GetProperty() for namespace prefix usage.
+ ///
+ /// @param fieldNS The namespace URI for the field used as the selector. Same URI and prefix
+ /// usage as the \c schemaNS and \c arrayName parameters.
+ ///
+ /// @param fieldName The name of the field used as the selector. Must be a single XML name, must
+ /// not be null or the empty string. It must be the name of a field that is itself simple.
+ ///
+ /// @param fieldValue The desired value of the field, specified as a string object.
+ ///
+ /// @param fullPath [out] A string in which to return the composed path.
+
+ static void ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ tStringObj * fullPath );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Conversion between binary types and strings
+ /// @{
+ ///
+ /// The main accessors in \c TXMPMeta set and retrieve property values as strings. additional
+ /// functions, such as \c TXMPMeta::SetPropertyInt(), set and retrieve property values as
+ /// explicit binary data types. Use these functions to convert between binary and string
+ /// values.
+ ///
+ /// Strings can be specified as null-terminated UTF-8 (\c #XMP_StringPtr), or as string
+ /// objects (\c tStringObj) of the type declared when instantiating the XMP classes; see
+ /// \c XMP.hpp. Alternate forms of each conversion function allow either type of string.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertFromBool() converts a Boolean value to a string.
+ ///
+ /// The string values of Booleans are returned by the macros \c #kXMP_TrueStr and
+ /// \c #kXMP_FalseStr in \c XMP_Const.h.
+ ///
+ /// @param binValue The Boolean value to be converted.
+ ///
+ /// @param strValue [out] A buffer in which to return the string representation of the value.
+
+ static void ConvertFromBool ( bool binValue,
+ tStringObj * strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertFromInt() converts a 32-bit integer value to a string.
+ ///
+ /// @param binValue The integer value to be converted.
+ ///
+ /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d".
+ ///
+ /// @param strValue [out] A buffer in which to return the string representation of the value.
+
+ static void ConvertFromInt ( long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue );
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertFromInt64() converts a 64-bit integer value to a string.
+ ///
+ /// @param binValue The integer value to be converted.
+ ///
+ /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d".
+ ///
+ /// @param strValue [out] A buffer in which to return the string representation of the value.
+
+ static void ConvertFromInt64 ( long long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertFromFloat() converts a floating-point value to a string.
+ ///
+ /// @param binValue The floating-point value to be converted.
+ ///
+ /// @param format Optional. A C \c sprintf format for the conversion. Default is "%d".
+ ///
+ /// @param strValue [out] A buffer in which to return the string representation of the value.
+
+ static void ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertFromDate() converts a date/time value to a string.
+ ///
+ /// Formats a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime:
+ /// <pre>
+ /// YYYY
+ /// YYYY-MM
+ /// YYYY-MM-DD
+ /// YYYY-MM-DDThh:mmTZD
+ /// YYYY-MM-DDThh:mm:ssTZD
+ /// YYYY-MM-DDThh:mm:ss.sTZD
+ /// </pre>
+ ///
+ /// \c YYYY = four-digit year, formatted as "%.4d" <br>
+ /// \c MM = two-digit month (01=January) <br>
+ /// \c DD = two-digit day of month (01 through 31) <br>
+ /// \c hh = two digits of hour (00 through 23) <br>
+ /// \c mm = two digits of minute (00 through 59) <br>
+ /// \c ss = two digits of second (00 through 59) <br>
+ /// \c s = one or more digits representing a decimal fraction of a second <br>
+ /// \c TZD = time zone designator (Z or +hh:mm or -hh:mm)
+ ///
+ /// Time-only input is allowed where the year, month, and day are all zero. This is output as
+ /// "0000-00-00...".
+ ///
+ /// @note ISO 8601 does not allow years less than 1000 or greater than 9999. This API allows
+ /// any year, even negative ones. The W3C profile also requires a time zone designator if a time
+ /// is present, this API treats the time zone designator as optional. The XMP_DateTime type has
+ /// an explicit notion of zone-less time.
+ ///
+ /// @param binValue The date/time value to be converted.
+ ///
+ /// @param strValue [out] A buffer in which to return the ISO 8601 string representation of the date/time.
+
+ static void ConvertFromDate ( const XMP_DateTime & binValue,
+ tStringObj * strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToBool() converts a string to a Boolean value.
+ ///
+ /// The preferred strings are those returned by the macros \c #kXMP_TrueStr and \c #kXMP_FalseStr.
+ /// If these do not match, the function does a case insensitive comparison, then simply 't' or 'f',
+ /// and finally non-zero and zero integer representations.
+ ///
+ /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
+ ///
+ /// @return The appropriate C++ bool value for the string.
+
+ static bool ConvertToBool ( XMP_StringPtr strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToBool() converts a string to a Boolean value.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object,
+ /// rather than a <tt>const * char</tt>. It is otherwise identical; see details in the canonical form.
+ ///
+ /// @param strValue The string representation of the value, specified as a string object.
+ ///
+ /// @return The appropriate C++ bool value for the string.
+
+ static bool ConvertToBool ( const tStringObj & strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToInt() converts a string to a 32-bit integer value.
+ ///
+ /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
+ ///
+ /// @return The 32-bit integer value.
+
+ static long ConvertToInt ( XMP_StringPtr strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToInt() converts a string to a 32-bit integer value.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object,
+ /// rather than a <tt>const * char</tt>. It is otherwise identical.
+ ///
+ /// @param strValue The string representation of the value, specified as a string object.
+ ///
+ /// @return The 32-bit integer value.
+
+ static long ConvertToInt ( const tStringObj & strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToInt64() converts a string to a 64-bit integer value.
+ ///
+ /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
+ ///
+ /// @return The 64-bit integer value.
+
+ static long long ConvertToInt64 ( XMP_StringPtr strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToInt64() converts a string to a 64-bit integer value.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object,
+ /// rather than a <tt>const * char</tt>. It is otherwise identical.
+ ///
+ /// @param strValue The string representation of the value, specified as a string object.
+ ///
+ /// @return The 64-bit integer value.
+
+ static long long ConvertToInt64 ( const tStringObj & strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToFloat() converts a string to a floating-point value.
+ ///
+ /// @param strValue The string representation of the value, specified as a null-terminated UTF-8 string.
+ ///
+ /// @return The floating-point value.
+
+ static double ConvertToFloat ( XMP_StringPtr strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToFloat() converts a string to a floating-point value.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object,
+ /// rather than a <tt>const * char</tt>. It is otherwise identical.
+ ///
+ /// @param strValue The string representation of the value, specified as a string object.
+ ///
+ /// @return The floating-point value.
+
+ static double ConvertToFloat ( const tStringObj & strValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToDate() converts a string to a date/time value.
+ ///
+ /// Parses a date according to the ISO 8601 profile in http://www.w3.org/TR/NOTE-datetime:
+ /// <pre>
+ /// YYYY
+ /// YYYY-MM
+ /// YYYY-MM-DD
+ /// YYYY-MM-DDThh:mmTZD
+ /// YYYY-MM-DDThh:mm:ssTZD
+ /// YYYY-MM-DDThh:mm:ss.sTZD
+ /// </pre>
+ ///
+ /// \c YYYY = four-digit year, formatted as "%.4d" <br>
+ /// \c MM = two-digit month (01=January) <br>
+ /// \c DD = two-digit day of month (01 through 31) <br>
+ /// \c hh = two digits of hour (00 through 23) <br>
+ /// \c mm = two digits of minute (00 through 59) <br>
+ /// \c ss = two digits of second (00 through 59) <br>
+ /// \c s = one or more digits representing a decimal fraction of a second <br>
+ /// \c TZD = time zone designator (Z or +hh:mm or -hh:mm)
+ ///
+ /// A missing date portion or missing TZD are tolerated. A missing date value can begin with
+ /// "Thh:" or "hh:"; the year, month, and day are all set to zero in the \c #XMP_DateTime value.
+ /// A missing TZD is assumed to be UTC.
+ ///
+ /// @note ISO 8601 does not allow years less than 1000 or greater than 9999. This API allows
+ /// any year, even negative ones. The W3C profile also requires a time zone designator if a time
+ /// is present, this API treats the time zone designator as optional. The XMP_DateTime type has
+ /// an explicit notion of zone-less time.
+ ///
+ /// @param strValue The ISO 8601 string representation of the date/time, specified as a
+ /// null-terminated UTF-8 string.
+ ///
+ /// @param binValue [out] A buffer in which to return the binary date/time value.
+
+ static void ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToDate() converts a string to a date/time value.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object,
+ /// rather than a <tt>const * char</tt>. It is otherwise identical.
+ /// See details for the canonical form.
+ ///
+ ///
+ /// @param strValue The ISO 8601 string representation of the date/time, specified as a string
+ /// object.
+ ///
+ /// @param binValue [out] A buffer in which to return the binary date/time value.
+
+ static void ConvertToDate ( const tStringObj & strValue,
+ XMP_DateTime * binValue );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Date-time manipulation
+ /// @{
+ ///
+ /// In addition to the type-conversion functions that convert between strings and binary
+ /// date-time values, these functions create, manipulate, and compare date-time values.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CurrentDateTime() obtains the current date and time.
+ ///
+ /// Creates and returns a binary \c #XMP_DateTime value. The returned time is UTC, properly
+ /// adjusted for the local time zone. The resolution of the time is not guaranteed to be finer
+ /// than seconds.
+ ///
+ /// @param time [out] A buffer in which to return the date/time value.
+
+ static void CurrentDateTime ( XMP_DateTime * time );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SetTimeZone() sets the time zone in a date/time value to the local time zone.
+ ///
+ /// Any existing time zone value is replaced. The other date/time fields are not adjusted in any way.
+ ///
+ /// @param time A pointer to the date-time value, which is modified in place.
+
+ static void SetTimeZone ( XMP_DateTime * time );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToUTCTime() ensures that a time is UTC.
+ ///
+ /// If the time zone is not UTC, the time is adjusted and the time zone set to be UTC. The value
+ /// is not modified if the time zone is already UTC or if the value has no time zone.
+ ///
+ /// @param time A pointer to the date-time value, which is modified in place.
+
+ static void ConvertToUTCTime ( XMP_DateTime * time );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c ConvertToLocalTime() ensures that a time is local.
+ ///
+ /// If the time zone is not the local zone, the time is adjusted and the time zone set to be local.
+ /// The value is not modified if the time zone is already the local zone or if the value has no
+ /// time zone.
+ ///
+ /// @param time A pointer to the date-time value, which is modified in place.
+
+ static void ConvertToLocalTime ( XMP_DateTime * time );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CompareDateTime() compares the order of two date/time values.
+ ///
+ /// Both values are treated as in the same time zone if either has no time zone.
+ ///
+ /// @param left The left-side date/time value.
+ ///
+ /// @param right The right-side date/time value.
+ ///
+ /// @return An integer indicating the order:
+ /// \li -1 if left is earlier than right
+ /// \li 0 if left matches right
+ /// \li +1 if left is later than right
+
+ static int CompareDateTime ( const XMP_DateTime & left,
+ const XMP_DateTime & right );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Base64 encoding and decoding
+ /// @{
+ ///
+ /// These functions convert between raw data values and Base64-encoded strings.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c EncodeToBase64() converts a raw data value to a Base64-encoded string.
+ ///
+ /// @param rawStr An \c #XMP_StringPtr (char *) string containing the raw data to be converted.
+ ///
+ /// @param rawLen The number of characters of raw data to be converted.
+ ///
+ /// @param encodedStr [out] A string object in which to return the encoded string.
+
+ static void EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ tStringObj * encodedStr );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c EncodeToBase64() converts a raw data value passed in a string object to a Base64-encoded string.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object as input.
+ /// It is otherwise identical.
+ ///
+ /// @param rawStr A string object containing the raw data to be converted.
+ ///
+ /// @param encodedStr [out] A string object in which to return the encoded string.
+
+ static void EncodeToBase64 ( const tStringObj & rawStr,
+ tStringObj * encodedStr );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DecodeFromBase64() Decodes a Base64-encoded string to raw data.
+ ///
+ /// @param encodedStr An \c #XMP_StringPtr (char *) string containing the encoded data to be converted.
+ ///
+ /// @param encodedLen The number of characters of raw data to be converted.
+ ///
+ /// @param rawStr [out] A string object in which to return the decoded data.
+
+ static void DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ tStringObj * rawStr );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DecodeFromBase64() Decodes a Base64-encoded string, passed as a string object, to raw data.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object as input.
+ /// It is otherwise identical.
+ ///
+ /// @param encodedStr An string object containing the encoded data to be converted.
+ ///
+ /// @param rawStr [out] A string object in which to return the decoded data.
+
+ static void DecodeFromBase64 ( const tStringObj & encodedStr,
+ tStringObj * rawStr );
+
+ /// @}
+
+ // =============================================================================================
+ // =============================================================================================
+ /// \name JPEG file handling
+ /// @{
+ ///
+ /// These functions support the partitioning of XMP in JPEG files into standard and extended
+ /// portions in order to work around the 64KB size limit of JPEG marker segments.
+ ///
+ /// @note (Doc note) Add detail about how to write out and read back extended data
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c PackageForJPEG() creates XMP serializations appropriate for a JPEG file.
+ ///
+ /// The standard XMP in a JPEG file is limited to 64K bytes. This function serializes the XMP
+ /// metadata in an XMP object into a string of RDF (see \c TXMPMeta::SerializeToBuffer()). If
+ /// the data does not fit into the 64K byte limit, it creates a second packet string with the
+ /// extended data.
+ ///
+ /// @param xmpObj The XMP object containing the metadata.
+ ///
+ /// @param standardXMP [out] A string object in which to return the full standard XMP packet.
+ ///
+ /// @param extendedXMP [out] A string object in which to return the serialized extended XMP,
+ /// empty if not needed.
+ ///
+ /// @param extendedDigest [out] A string object in which to return an MD5 digest of the serialized
+ /// extended XMP, empty if not needed.
+ ///
+ /// @see \c MergeFromJPEG()
+
+ static void PackageForJPEG ( const TXMPMeta<tStringObj> & xmpObj,
+ tStringObj * standardXMP,
+ tStringObj * extendedXMP,
+ tStringObj * extendedDigest );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c MergeFromJPEG() merges standard and extended XMP retrieved from a JPEG file.
+ ///
+ /// When an extended partition stores properties that do not fit into the JPEG file limitation
+ /// of 64K bytes, this function integrates those properties back into the same XMP object with
+ /// those from the standard XMP packet.
+ ///
+ /// @param fullXMP [in, out] An XMP object which the caller has initialized from the standard
+ /// XMP packet in a JPEG file. The extended XMP is added to this object.
+ ///
+ /// @param extendedXMP An XMP object which the caller has initialized from the extended XMP
+ /// packet in a JPEG file.
+ ///
+ /// @see \c PackageForJPEG()
+
+ static void MergeFromJPEG ( TXMPMeta<tStringObj> * fullXMP,
+ const TXMPMeta<tStringObj> & extendedXMP );
+
+ /// @}
+
+ // =============================================================================================
+ /// \name Editing utilities
+ /// @{
+ ///
+ /// These functions are useful in implementing a user interface for editing XMP. They
+ /// convert sets of property values to and from displayable and manipulable strings, and perform
+ /// operations on sets of metadata, such as those available from the File Info dialog box.
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c CatenateArrayItems() creates a single edit string from a set of array item values.
+ ///
+ /// Collects the values of all items in an array into a single string, using a specified
+ /// separation string. Each item in the specified array must be a simple string value.
+ ///
+ /// @param xmpObj The XMP object containing the array to be catenated.
+ ///
+ /// @param schemaNS The schema namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// @param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string.
+ ///
+ /// @param separator The string with which to separate the items in the catenated string.
+ /// Defaults to "; ", ASCII semicolon and space (U+003B, U+0020).
+ ///
+ /// @param quotes The character or characters to use as quotes around array items that contain a
+ /// separator. Defaults to the double-quote character ("), ASCII quote (U+0022).
+ ///
+ /// @param options Option flags to control the catenation. <<what options?>>
+ ///
+ /// @param catedStr [out] A string object in which to return the catenated array items.
+ ///
+ /// @see \c SeparateArrayItems()
+
+ static void CatenateArrayItems ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ tStringObj * catedStr );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SeparateArrayItems() updates an array from a concatenated edit string of values.
+ ///
+ /// This reverses the action of \c CatenateArrayItems(), separating out individual array items
+ /// from the edit string and updating the array with the new values. Each item in the array must
+ /// be a simple string value.
+ ///
+ /// @param xmpObj The XMP object containing the array to be updated.
+ ///
+ /// @param schemaNS The schema namespace URI for the array. Must not be null or the empty string.
+ ///
+ /// @param arrayName The name of the array. May be a general path expression, must not be null
+ /// or the empty string.
+ ///
+ /// @param options Option flags to control the separation. <<what options?>>
+ ///
+ /// @param catedStr The concatenated array items, as created by \c CatenateArrayItems(),
+ /// specified as a null-terminated UTF-8 string.
+
+ static void SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c SeparateArrayItems() updates an array from a concatenated edit string of values.
+ ///
+ /// Overloads the basic form of the function, allowing you to pass a string object in which
+ /// to return the concatenated string. It is otherwise identical; see details for the canonical form.
+ ///
+
+ static void SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ const tStringObj & catedStr );
+
+ /// @brief \c ApplyTemplate() modifies a working XMP object according to a template object.
+ ///
+ /// The XMP template can be used to add, replace or delete properties from the working XMP object.
+ /// This function replaces the previous \c AppendProperties() function, which is no longer available.
+ /// The actions that you specify determine how the template is applied. Each action can be applied
+ /// individually or combined; if you do not specify any actions, the properties and values in the working
+ /// XMP object do not change.
+ ///
+ /// These actions are available:
+ /// \li Clear (\c #kXMPTemplate_ClearUnnamedProperties): Deletes top-level properties.
+ /// Any top-level property that is present in the template (even with empty value)
+ /// is retained. All other top-level properties in the working object are deleted.
+ ///
+ /// \li Add (\c #kXMPTemplate_AddNewProperties): Adds new properties to the working object if the
+ /// template properties have values. See additional detail below.
+ ///
+ /// \li Replace (\c #kXMPTemplate_ReplaceExistingProperties): Replaces the values of existing top-level
+ /// properties in the working XMP if the value forms match those in the template. Properties
+ /// with empty values in the template are ignored. If combined with Clear or Add actions,
+ /// those take precedence; values are cleared or added, rather than replaced.
+ ///
+ /// \li Replace/Delete empty (\c #kXMPTemplate_ReplaceWithDeleteEmpty): Replaces values in the same way
+ /// as the simple Replace action, and also deletes properties if the value in the template is empty.
+ /// If combined with Clear or Add actions, those take precedence; values are cleared or added,
+ /// rather than replaced.
+ ///
+ /// \li Include internal (\c #kXMPTemplate_IncludeInternalProperties): Performs specified action
+ /// on internal properties as well as external properties. By default, internal properties
+ /// are ignored for all actions.
+ ///
+ /// The Add behavior depends on the type of property:
+ /// <ul>
+ /// <li> If a top-level property is not in the working XMP, and has a value in the template,
+ /// the property and value are added. Empty properties are not added. </li>
+ /// <li> If a property is in both the working XMP and template, the value forms must match, otherwise
+ /// the template is ignored for that property.</li>
+ /// <li> If a struct is present in both the working XMP and template, the individual fields of the
+ /// template struct are added as appropriate; that is, the logic is recursively applied to the fields.
+ /// Struct values are equivalent if they have the same fields with equivalent values. </li>
+ /// <li> If an array is present in both the working XMP and template, items from the template are
+ /// added if the value forms match. Array values match if they have sets of equivalent items,
+ /// regardless of order.</li>
+ /// <li> Alt-text arrays use the \c xml:lang qualifier as a key, adding languages that are missing. </li>
+ /// </ul>
+ /// Array item checking is n-squared; this can be time-intensive if the Replace option is
+ /// not specified. Each source item is checked to see if it already exists in the destination,
+ /// without regard to order or duplicates. Simple items are compared by value and \c xml:lang
+ /// qualifier; other qualifiers are ignored. Structs are recursively compared by field names,
+ /// without regard to field order. Arrays are compared by recursively comparing all items.
+
+ /// @param workingXMP The destination XMP object.
+ ///
+ /// @param templateXMP The template to apply to the destination XMP object.
+ ///
+ /// @param actions Option flags to control the copying. If none are specified, the properties and values
+ /// in the working XMP do not change. A logical OR of these bit-flag constants:
+ /// \li \c #kXMPTemplate_ClearUnnamedProperties -- Delete anything that is not in the template
+ /// \li \c #kXMPTemplate_AddNewProperties -- Add properties; see detailed description.
+ /// \li \c #kXMPTemplate_ReplaceExistingProperties -- Replace the values of existing properties.
+ /// \li \c #kXMPTemplate_ReplaceWithDeleteEmpty -- Replace the values of existing properties
+ /// and delete properties if the new value is empty.
+ /// \li \c #kXMPTemplate_IncludeInternalProperties -- Operate on internal properties as well as
+ /// external properties.
+ ///
+
+ static void ApplyTemplate ( TXMPMeta<tStringObj> * workingXMP,
+ const TXMPMeta<tStringObj> & templateXMP,
+ XMP_OptionBits actions );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c RemoveProperties() removes multiple properties from an XMP object.
+ ///
+ /// The operation depends on how the namespace and property are specified:
+ ///
+ /// \li Non-empty \c schemaNS and \c propName - The named property is removed if it is an
+ /// external property, or if the \c #kXMPUtil_DoAllProperties option flag is set. It does not
+ /// matter whether the named property is an actual property or an alias.
+ ///
+ /// \li Non-empty \c schemaNS and empty \c propName - All external properties in the named
+ /// schema are removed. Internal properties are also removed if the
+ /// \c #kXMPUtil_DoAllProperties option flag is set. In addition, aliases from the named schema
+ /// are removed if the \c #kXMPUtil_IncludeAliases option flag is set.
+ ///
+ /// \li Empty \c schemaNS and empty \c propName - All external properties in all schemas are
+ /// removed. Internal properties are also removed if the \c #kXMPUtil_DoAllProperties option
+ /// flag is set. Aliases are handled implicitly, because the associated actuals are removed or
+ /// not.
+ ///
+ /// \li It is an error to pass an empty \c schemaNS and non-empty \c propName.
+ ///
+ /// @param xmpObj The XMP object containing the properties to be removed.
+ ///
+ /// @param schemaNS Optional schema namespace URI for the properties to be removed.
+ ///
+ /// @param propName Optional path expression for the property to be removed.
+ ///
+ /// @param options Option flags to control the deletion operation. A logical OR of these
+ /// bit-flag constants:
+ /// \li \c #kXMPUtil_DoAllProperties - Delete internal properties in addition to external properties.
+ /// \li \c #kXMPUtil_IncludeAliases - Include aliases if the schema is explicitly specified.
+
+ static void RemoveProperties ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS = 0,
+ XMP_StringPtr propName = 0,
+ XMP_OptionBits options = 0 );
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief \c DuplicateSubtree() replicates a subtree from one XMP object into another.
+ ///
+ /// The destination can be a different namespace and root location in the same object, or the
+ /// same or a different location in another XMP object.
+ ///
+ /// @param source The source XMP object.
+ ///
+ /// @param dest The destination XMP object.
+ ///
+ /// @param sourceNS The schema namespace URI for the source subtree.
+ ///
+ /// @param sourceRoot The root location for the source subtree. Can be a general path expression,
+ /// must not be null or the empty string.
+ ///
+ /// @param destNS The schema namespace URI for the destination. Defaults to the source namespace.
+ ///
+ /// @param destRoot The root location for the destination. Can be a general path expression.
+ /// Defaults to the source location.
+ ///
+ /// @param options Option flags to control the operation. <<options?>>
+
+ static void DuplicateSubtree ( const TXMPMeta<tStringObj> & source,
+ TXMPMeta<tStringObj> * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS = 0,
+ XMP_StringPtr destRoot = 0,
+ XMP_OptionBits options = 0 );
+
+ /// @}
+
+ // =============================================================================================
+
+private:
+
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
+
+}; // class TXMPUtils
+
+// =================================================================================================
+
+#endif // __TXMPUtils_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/XMP.hpp b/gpr/source/lib/xmp_core/public/include/XMP.hpp
new file mode 100644
index 0000000..8ec39eb
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/XMP.hpp
@@ -0,0 +1,98 @@
+#ifndef __XMP_hpp__
+#define __XMP_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file XMP.hpp
+/// \brief Overall header file for the XMP Toolkit
+///
+/// This is an overall header file, the only one that C++ clients should include.
+///
+/// The full client API is in the \c TXMPMeta.hpp, \c TXMPIterator.hpp, \c TXMPUtils.hpp headers.
+/// Read these for information, but do not include them directly. The \c TXMP... classes are C++
+/// template classes that must be instantiated with a string class such as \c std::string. The
+/// string class is used to return text strings for property values, serialized XMP, and so on.
+/// Clients must also compile \c XMP.incl_cpp to ensure that all client-side glue code is generated.
+/// This should be done by including it in exactly one client source file.
+///
+/// There are two C preprocessor macros that simplify use of the templates:
+///
+/// \li \c TXMP_STRING_TYPE - Define this as the string class to use with the template. You will get
+/// the template headers included and typedefs (\c SXMPMeta, and so on) to use in your code.
+///
+/// \li \c TXMP_EXPAND_INLINE - Define this as 1 if you want to have the template functions expanded
+/// inline in your code. Leave it undefined, or defined as 0, to use out-of-line instantiations of
+/// the template functions. Compiling \c XMP.incl_cpp generates explicit out-of-line
+/// instantiations if \c TXMP_EXPAND_INLINE is off.
+///
+/// The template parameter, class \c tStringObj, must have the following member functions (which
+/// match those for \c std::string):
+///
+/// <pre>
+/// tStringObj& assign ( const char * str, size_t len )
+/// size_t size() const
+/// const char * c_str() const
+/// </pre>
+///
+/// The string class must be suitable for at least UTF-8. This is the encoding used for all general
+/// values, and is the default encoding for serialized XMP. The string type must also be suitable
+/// for UTF-16 or UTF-32 if those serialization encodings are used. This mainly means tolerating
+/// embedded 0 bytes, which \c std::string does.
+// ================================================================================================
+
+/// /c XMP_Environment.h must be the first included header.
+#include "XMP_Environment.h"
+
+#include "XMP_Version.h"
+#include "XMP_Const.h"
+
+#if XMP_WinBuild
+ #if XMP_DebugBuild
+ #pragma warning ( push, 4 )
+ #else
+ #pragma warning ( push, 3 )
+ #endif
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+#if defined ( TXMP_STRING_TYPE )
+
+ #include "TXMPMeta.hpp"
+ #include "TXMPIterator.hpp"
+ #include "TXMPUtils.hpp"
+ typedef class TXMPMeta <TXMP_STRING_TYPE> SXMPMeta; // For client convenience.
+ typedef class TXMPIterator <TXMP_STRING_TYPE> SXMPIterator;
+ typedef class TXMPUtils <TXMP_STRING_TYPE> SXMPUtils;
+ #if TXMP_EXPAND_INLINE
+ #error "TXMP_EXPAND_INLINE is not working at present. Please don't use it."
+ #include "client-glue/TXMPMeta.incl_cpp"
+ #include "client-glue/TXMPIterator.incl_cpp"
+ #include "client-glue/TXMPUtils.incl_cpp"
+ #include "client-glue/TXMPFiles.incl_cpp"
+ #endif
+
+ #if XMP_INCLUDE_XMPFILES
+ #include "TXMPFiles.hpp" // ! Needs typedef for SXMPMeta.
+ typedef class TXMPFiles <TXMP_STRING_TYPE> SXMPFiles;
+ #if TXMP_EXPAND_INLINE
+ #include "client-glue/TXMPFiles.incl_cpp"
+ #endif
+ #endif
+
+#endif // TXMP_STRING_TYPE
+
+#if XMP_WinBuild
+ #pragma warning ( pop )
+#endif
+
+// =================================================================================================
+
+#endif // __XMP_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/XMP.incl_cpp b/gpr/source/lib/xmp_core/public/include/XMP.incl_cpp
new file mode 100644
index 0000000..fe2a6fa
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/XMP.incl_cpp
@@ -0,0 +1,69 @@
+#ifndef __XMP_incl_cpp__
+#define __XMP_incl_cpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file XMP.incl_cpp
+/// \brief Overall client glue file for the XMP toolkit.
+///
+/// This is an overall client source file of XMP toolkit glue, the only XMP-specific one that
+/// clients should build in projects. This ensures that all of the client-side glue code for the
+/// XMP toolkit gets compiled.
+///
+/// You cannot compile this file directly, because the template's string type must be declared and
+/// only the client can do that. Instead, include this in some other source file. For example,
+/// to use <tt>std::string</tt> you only need these two lines:
+///
+/// \code
+/// #include <string>
+/// #include "XMP.incl_cpp"
+/// \endcode
+
+
+#include "XMP.hpp" // ! This must be the first include!
+
+#define XMP_ClientBuild 1
+
+#if XMP_WinBuild
+ #if XMP_DebugBuild
+ #pragma warning ( push, 4 )
+ #else
+ #pragma warning ( push, 3 )
+ #endif
+
+ #pragma warning ( disable : 4127 ) // conditional expression is constant
+ #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced
+ #pragma warning ( disable : 4702 ) // unreachable code
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+#if defined ( TXMP_STRING_TYPE ) && (! TXMP_EXPAND_INLINE)
+
+ // We're using a single out of line instantiation. Do it here.
+
+ #include "client-glue/TXMPMeta.incl_cpp"
+ #include "client-glue/TXMPIterator.incl_cpp"
+ #include "client-glue/TXMPUtils.incl_cpp"
+ template class TXMPMeta <TXMP_STRING_TYPE>;
+ template class TXMPIterator <TXMP_STRING_TYPE>;
+ template class TXMPUtils <TXMP_STRING_TYPE>;
+ #if XMP_INCLUDE_XMPFILES
+ #include "client-glue/TXMPFiles.incl_cpp"
+ template class TXMPFiles <TXMP_STRING_TYPE>;
+ #endif
+
+#endif
+
+#if XMP_WinBuild
+ #pragma warning ( pop )
+#endif
+
+#endif // __XMP_incl_cpp__
diff --git a/gpr/source/lib/xmp_core/public/include/XMP_Const.h b/gpr/source/lib/xmp_core/public/include/XMP_Const.h
new file mode 100644
index 0000000..eadc267
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/XMP_Const.h
@@ -0,0 +1,1560 @@
+#ifndef __XMP_Const_h__
+#define __XMP_Const_h__ 1
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h"
+
+ #include <stddef.h>
+
+#if XMP_MacBuild | XMP_iOSBuild // ! No stdint.h on Windows and some UNIXes.
+ #include <stdint.h>
+#endif
+#if XMP_UNIXBuild // hopefully an inttypes.h on all UNIXes...
+ #include <inttypes.h>
+#endif
+
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+/// \file XMP_Const.h
+/// \brief Common C/C++ types and constants for the XMP toolkit.
+// =================================================================================================
+
+// =================================================================================================
+// Basic types and constants
+// =========================
+
+// The XMP_... types are used on the off chance that the ..._t types present a problem. In that
+// case only the declarations of the XMP_... types needs to change, not all of the uses. These
+// types are used where fixed sizes are required in order to have a known ABI for a DLL build.
+
+#if XMP_MacBuild | XMP_iOSBuild
+
+ typedef int8_t XMP_Int8;
+ typedef int16_t XMP_Int16;
+ typedef int32_t XMP_Int32;
+ typedef int64_t XMP_Int64;
+
+ typedef uint8_t XMP_Uns8;
+ typedef uint16_t XMP_Uns16;
+ typedef uint32_t XMP_Uns32;
+ typedef uint64_t XMP_Uns64;
+
+#elif XMP_WinBuild
+
+ typedef signed char XMP_Int8;
+ typedef signed short XMP_Int16;
+ typedef signed long XMP_Int32;
+ typedef signed long long XMP_Int64;
+
+ typedef unsigned char XMP_Uns8;
+ typedef unsigned short XMP_Uns16;
+ typedef unsigned long XMP_Uns32;
+ typedef unsigned long long XMP_Uns64;
+
+#elif XMP_UNIXBuild
+
+ #if ! XMP_64
+
+ typedef signed char XMP_Int8;
+ typedef signed short XMP_Int16;
+ typedef signed long XMP_Int32;
+ typedef signed long long XMP_Int64;
+
+ typedef unsigned char XMP_Uns8;
+ typedef unsigned short XMP_Uns16;
+ typedef unsigned long XMP_Uns32;
+ typedef unsigned long long XMP_Uns64;
+
+ #else
+
+ typedef signed char XMP_Int8;
+ typedef signed short XMP_Int16;
+ typedef signed int XMP_Int32;
+ typedef signed long long XMP_Int64;
+
+ typedef unsigned char XMP_Uns8;
+ typedef unsigned short XMP_Uns16;
+ typedef unsigned int XMP_Uns32;
+ typedef unsigned long long XMP_Uns64;
+
+ #endif
+
+#else
+
+ #error "XMP environment error - must define one of XMP_MacBuild, XMP_WinBuild, XMP_UNIXBuild or XMP_iOSBuild"
+
+#endif
+
+typedef XMP_Uns8 XMP_Bool;
+
+const XMP_Uns8 kXMP_Bool_False = 0;
+
+#define ConvertXMP_BoolToBool(a) (a) != kXMP_Bool_False
+#define ConvertBoolToXMP_Bool(a) (a) ? !kXMP_Bool_False : kXMP_Bool_False
+
+static const XMP_Uns8 Min_XMP_Uns8 = ( (XMP_Uns8) 0x00 );
+static const XMP_Uns8 Max_XMP_Uns8 = ( (XMP_Uns8) 0xFF );
+static const XMP_Uns16 Min_XMP_Uns16 = ( (XMP_Uns16) 0x00 );
+static const XMP_Uns16 Max_XMP_Uns16 = ( (XMP_Uns16) 0xFFFF );
+static const XMP_Uns32 Min_XMP_Uns32 = ( (XMP_Uns32) 0x00 );
+static const XMP_Uns32 Max_XMP_Uns32 = ( (XMP_Uns32) 0xFFFFFFFF );
+static const XMP_Uns64 Min_XMP_Uns64 = ( (XMP_Uns64) 0x00 );
+static const XMP_Uns64 Max_XMP_Uns64 = ( (XMP_Uns64) 0xFFFFFFFFFFFFFFFFLL );
+
+static const XMP_Int8 Min_XMP_Int8 = ( (XMP_Int8) 0x80 );
+static const XMP_Int8 Max_XMP_Int8 = ( (XMP_Int8) 0x7F );
+static const XMP_Int16 Min_XMP_Int16 = ( (XMP_Int16) 0x8000 );
+static const XMP_Int16 Max_XMP_Int16 = ( (XMP_Int16) 0x7FFF );
+static const XMP_Int32 Min_XMP_Int32 = ( (XMP_Int32) 0x80000000 );
+static const XMP_Int32 Max_XMP_Int32 = ( (XMP_Int32) 0x7FFFFFFF );
+static const XMP_Int64 Min_XMP_Int64 = ( (XMP_Int64) 0x8000000000000000LL );
+static const XMP_Int64 Max_XMP_Int64 = ( (XMP_Int64) 0x7FFFFFFFFFFFFFFFLL );
+
+
+/// An "ABI safe" pointer to the internal part of an XMP object. Use to pass an XMP object across
+/// client DLL boundaries. See \c TXMPMeta::GetInternalRef().
+typedef struct __XMPMeta__ * XMPMetaRef;
+
+/// An "ABI safe" pointer to the internal part of an XMP iteration object. Use to pass an XMP
+/// iteration object across client DLL boundaries. See \c TXMPIterator.
+typedef struct __XMPIterator__ * XMPIteratorRef;
+
+/// An "ABI safe" pointer to the internal part of an XMP document operations object. Use to pass an
+/// XMP document operations object across client DLL boundaries. See \c TXMPDocOps.
+typedef struct __XMPDocOps__ * XMPDocOpsRef;
+
+/// An "ABI safe" pointer to the internal part of an XMP file-handling object. Use to pass an XMP
+/// file-handling object across client DLL boundaries. See \c TXMPFiles.
+typedef struct __XMPFiles__ * XMPFilesRef;
+
+// =================================================================================================
+
+/// \name General scalar types and constants
+/// @{
+
+/// \typedef XMP_StringPtr
+/// \brief The type for input string parameters. A <tt>const char *</tt>, a null-terminated UTF-8
+/// string.
+
+/// \typedef XMP_StringLen
+/// \brief The type for string length parameters. A 32-bit unsigned integer, as big as will be
+/// practically needed.
+
+/// \typedef XMP_Index
+/// \brief The type for offsets and indices. A 32-bit signed integer. It is signed to allow -1 for
+/// loop termination.
+
+/// \typedef XMP_OptionBits
+/// \brief The type for a collection of 32 flag bits. Individual flags are defined as enum value bit
+/// masks; see \c #kXMP_PropValueIsURI and following. A number of macros provide common set or set
+/// operations, such as \c XMP_PropIsSimple. For other tests use an expression like <code>options &
+/// kXMP_<theOption></code>. When passing multiple option flags use the bitwise-OR operator. '|',
+/// not the arithmatic plus, '+'.
+
+typedef const char * XMP_StringPtr; // Points to a null terminated UTF-8 string.
+typedef XMP_Uns32 XMP_StringLen;
+typedef XMP_Int32 XMP_Index; // Signed, sometimes -1 is handy.
+typedef XMP_Uns32 XMP_OptionBits; // Used as 32 individual bits.
+
+/// \def kXMP_TrueStr
+/// \brief The canonical true string value for Booleans in serialized XMP.
+///
+/// Code that converts from string to bool should be case insensitive, and also allow "1".
+
+/// \def kXMP_FalseStr
+/// \brief The canonical false string value for Booleans in serialized XMP.
+///
+/// Code that converts from string to bool should be case insensitive, and also allow "0".
+
+#define kXMP_TrueStr "True" // Serialized XMP spellings, not for the type bool.
+#define kXMP_FalseStr "False"
+
+/// Type for yes/no/maybe answers. The values are picked to allow Boolean-like usage. The yes and
+/// values are true (non-zero), the no value is false (zero).
+enum {
+ /// The part or parts have definitely changed.
+ kXMPTS_Yes = 1,
+ /// The part or parts have definitely not changed.
+ kXMPTS_No = 0,
+ /// The part or parts might, or might not, have changed.
+ kXMPTS_Maybe = -1
+};
+typedef XMP_Int8 XMP_TriState;
+
+/// @}
+
+// =================================================================================================
+
+/// \struct XMP_DateTime
+/// \brief The expanded type for a date and time.
+///
+/// Dates and time in the serialized XMP are ISO 8601 strings. The \c XMP_DateTime struct allows
+/// easy conversion with other formats.
+///
+/// All of the fields are 32 bit, even though most could be 8 bit. This avoids overflow when doing
+/// carries for arithmetic or normalization. All fields have signed values for the same reasons.
+///
+/// Date-time values are occasionally used with only a date or only a time component. A date without
+/// a time has zeros in the \c XMP_DateTime struct for all time fields. A time without a date has
+/// zeros for all date fields (year, month, and day).
+///
+/// \c TXMPUtils provides utility functions for manipulating date-time values.
+///
+/// @see \c TXMPUtils::ConvertToDate(), \c TXMPUtils::ConvertFromDate(),
+/// \c TXMPUtils::CompareDateTime(), \c TXMPUtils::ConvertToLocalTime(),
+/// \c TXMPUtils::ConvertToUTCTime(), \c TXMPUtils::CurrentDateTime(),
+/// \c TXMPUtils::SetTimeZone()
+
+struct XMP_DateTime {
+
+ /// The year, can be negative.
+ XMP_Int32 year;
+
+ /// The month in the range 1..12.
+ XMP_Int32 month;
+
+ /// The day of the month in the range 1..31.
+ XMP_Int32 day;
+
+ /// The hour in the range 0..23.
+ XMP_Int32 hour;
+
+ /// The minute in the range 0..59.
+ XMP_Int32 minute;
+
+ /// The second in the range 0..59.
+ XMP_Int32 second;
+
+ /// Is the date portion meaningful?
+ XMP_Bool hasDate;
+
+ /// Is the time portion meaningful?
+ XMP_Bool hasTime;
+
+ /// Is the time zone meaningful?
+ XMP_Bool hasTimeZone;
+
+ /// The "sign" of the time zone, \c #kXMP_TimeIsUTC (0) means UTC, \c #kXMP_TimeWestOfUTC (-1)
+ /// is west, \c #kXMP_TimeEastOfUTC (+1) is east.
+ XMP_Int8 tzSign;
+
+ /// The time zone hour in the range 0..23.
+ XMP_Int32 tzHour;
+
+ /// The time zone minute in the range 0..59.
+ XMP_Int32 tzMinute;
+
+ /// Nanoseconds within a second, often left as zero.
+ XMP_Int32 nanoSecond;
+
+ #if __cplusplus
+ XMP_DateTime() : year(0), month(0), day(0), hour(0), minute(0), second(0),
+ hasDate(false),hasTime(false), hasTimeZone(false), tzSign(0), tzHour(0), tzMinute(0), nanoSecond(0){};
+ #endif
+
+};
+
+/// Constant values for \c XMP_DateTime::tzSign field.
+enum {
+ /// Time zone is west of UTC.
+ kXMP_TimeWestOfUTC = -1,
+ /// UTC time.
+ kXMP_TimeIsUTC = 0,
+ /// Time zone is east of UTC.
+ kXMP_TimeEastOfUTC = +1
+};
+
+#define XMPDateTime_IsDateOnly(dt) ((dt).hasDate & (! (dt).hasTime))
+#define XMPDateTime_IsTimeOnly(dt) ((dt).hasTime & (! (dt).hasDate))
+
+#define XMPDateTime_ClearTimeZone(dt) { (dt).hasTimeZone = (dt).tzSign = (dt).tzHour = (dt).tzMinute = 0; }
+
+// =================================================================================================
+// Standard namespace URI constants
+// ================================
+
+/// \name XML namespace constants for standard XMP schema.
+/// @{
+///
+/// \def kXMP_NS_XMP
+/// \brief The XML namespace for the XMP "basic" schema.
+///
+/// \def kXMP_NS_XMP_Rights
+/// \brief The XML namespace for the XMP copyright schema.
+///
+/// \def kXMP_NS_XMP_MM
+/// \brief The XML namespace for the XMP digital asset management schema.
+///
+/// \def kXMP_NS_XMP_BJ
+/// \brief The XML namespace for the job management schema.
+///
+/// \def kXMP_NS_XMP_T
+/// \brief The XML namespace for the XMP text document schema.
+///
+/// \def kXMP_NS_XMP_T_PG
+/// \brief The XML namespace for the XMP paged document schema.
+///
+/// \def kXMP_NS_PDF
+/// \brief The XML namespace for the PDF schema.
+///
+/// \def kXMP_NS_Photoshop
+/// \brief The XML namespace for the Photoshop custom schema.
+///
+/// \def kXMP_NS_EXIF
+/// \brief The XML namespace for Adobe's EXIF schema.
+///
+/// \def kXMP_NS_TIFF
+/// \brief The XML namespace for Adobe's TIFF schema.
+///
+/// @}
+
+#define kXMP_NS_XMP "http://ns.adobe.com/xap/1.0/"
+
+#define kXMP_NS_XMP_Rights "http://ns.adobe.com/xap/1.0/rights/"
+#define kXMP_NS_XMP_MM "http://ns.adobe.com/xap/1.0/mm/"
+#define kXMP_NS_XMP_BJ "http://ns.adobe.com/xap/1.0/bj/"
+
+#define kXMP_NS_PDF "http://ns.adobe.com/pdf/1.3/"
+#define kXMP_NS_Photoshop "http://ns.adobe.com/photoshop/1.0/"
+#define kXMP_NS_PSAlbum "http://ns.adobe.com/album/1.0/"
+#define kXMP_NS_EXIF "http://ns.adobe.com/exif/1.0/"
+#define kXMP_NS_EXIF_Aux "http://ns.adobe.com/exif/1.0/aux/"
+#define kXMP_NS_TIFF "http://ns.adobe.com/tiff/1.0/"
+#define kXMP_NS_PNG "http://ns.adobe.com/png/1.0/"
+#define kXMP_NS_SWF "http://ns.adobe.com/swf/1.0/"
+#define kXMP_NS_JPEG "http://ns.adobe.com/jpeg/1.0/"
+#define kXMP_NS_JP2K "http://ns.adobe.com/jp2k/1.0/"
+#define kXMP_NS_CameraRaw "http://ns.adobe.com/camera-raw-settings/1.0/"
+#define kXMP_NS_DM "http://ns.adobe.com/xmp/1.0/DynamicMedia/"
+#define kXMP_NS_Script "http://ns.adobe.com/xmp/1.0/Script/"
+#define kXMP_NS_ASF "http://ns.adobe.com/asf/1.0/"
+#define kXMP_NS_WAV "http://ns.adobe.com/xmp/wav/1.0/"
+#define kXMP_NS_BWF "http://ns.adobe.com/bwf/bext/1.0/"
+#define kXMP_NS_AEScart "http://ns.adobe.com/aes/cart/"
+#define kXMP_NS_RIFFINFO "http://ns.adobe.com/riff/info/"
+
+#define kXMP_NS_XMP_Note "http://ns.adobe.com/xmp/note/"
+
+#define kXMP_NS_AdobeStockPhoto "http://ns.adobe.com/StockPhoto/1.0/"
+#define kXMP_NS_CreatorAtom "http://ns.adobe.com/creatorAtom/1.0/"
+
+#define kXMP_NS_ExifEX "http://cipa.jp/exif/1.0/"
+
+/// \name XML namespace constants for qualifiers and structured property fields.
+/// @{
+///
+/// \def kXMP_NS_XMP_IdentifierQual
+/// \brief The XML namespace for qualifiers of the xmp:Identifier property.
+///
+/// \def kXMP_NS_XMP_Dimensions
+/// \brief The XML namespace for fields of the Dimensions type.
+///
+/// \def kXMP_NS_XMP_Image
+/// \brief The XML namespace for fields of a graphical image. Used for the Thumbnail type.
+///
+/// \def kXMP_NS_XMP_ResourceEvent
+/// \brief The XML namespace for fields of the ResourceEvent type.
+///
+/// \def kXMP_NS_XMP_ResourceRef
+/// \brief The XML namespace for fields of the ResourceRef type.
+///
+/// \def kXMP_NS_XMP_ST_Version
+/// \brief The XML namespace for fields of the Version type.
+///
+/// \def kXMP_NS_XMP_ST_Job
+/// \brief The XML namespace for fields of the JobRef type.
+///
+/// @}
+
+#define kXMP_NS_XMP_IdentifierQual "http://ns.adobe.com/xmp/Identifier/qual/1.0/"
+#define kXMP_NS_XMP_Dimensions "http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+#define kXMP_NS_XMP_Text "http://ns.adobe.com/xap/1.0/t/"
+#define kXMP_NS_XMP_PagedFile "http://ns.adobe.com/xap/1.0/t/pg/"
+#define kXMP_NS_XMP_Graphics "http://ns.adobe.com/xap/1.0/g/"
+#define kXMP_NS_XMP_Image "http://ns.adobe.com/xap/1.0/g/img/"
+#define kXMP_NS_XMP_Font "http://ns.adobe.com/xap/1.0/sType/Font#"
+#define kXMP_NS_XMP_ResourceEvent "http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
+#define kXMP_NS_XMP_ResourceRef "http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
+#define kXMP_NS_XMP_ST_Version "http://ns.adobe.com/xap/1.0/sType/Version#"
+#define kXMP_NS_XMP_ST_Job "http://ns.adobe.com/xap/1.0/sType/Job#"
+#define kXMP_NS_XMP_ManifestItem "http://ns.adobe.com/xap/1.0/sType/ManifestItem#"
+
+// Deprecated XML namespace constants
+#define kXMP_NS_XMP_T "http://ns.adobe.com/xap/1.0/t/"
+#define kXMP_NS_XMP_T_PG "http://ns.adobe.com/xap/1.0/t/pg/"
+#define kXMP_NS_XMP_G_IMG "http://ns.adobe.com/xap/1.0/g/img/"
+
+/// \name XML namespace constants from outside Adobe.
+/// @{
+///
+/// \def kXMP_NS_DC
+/// \brief The XML namespace for the Dublin Core schema.
+///
+/// \def kXMP_NS_IPTCCore
+/// \brief The XML namespace for the IPTC Core schema.
+///
+/// \def kXMP_NS_IPTCExt
+/// \brief The XML namespace for the IPTC Extension schema.
+///
+/// \def kXMP_NS_RDF
+/// \brief The XML namespace for RDF.
+///
+/// \def kXMP_NS_XML
+/// \brief The XML namespace for XML.
+///
+/// @}
+
+#define kXMP_NS_DC "http://purl.org/dc/elements/1.1/"
+
+#define kXMP_NS_IPTCCore "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"
+#define kXMP_NS_IPTCExt "http://iptc.org/std/Iptc4xmpExt/2008-02-29/"
+
+#define kXMP_NS_DICOM "http://ns.adobe.com/DICOM/"
+
+#define kXMP_NS_PLUS "http://ns.useplus.org/ldf/xmp/1.0/"
+
+#define kXMP_NS_PDFA_Schema "http://www.aiim.org/pdfa/ns/schema#"
+#define kXMP_NS_PDFA_Property "http://www.aiim.org/pdfa/ns/property#"
+#define kXMP_NS_PDFA_Type "http://www.aiim.org/pdfa/ns/type#"
+#define kXMP_NS_PDFA_Field "http://www.aiim.org/pdfa/ns/field#"
+#define kXMP_NS_PDFA_ID "http://www.aiim.org/pdfa/ns/id/"
+#define kXMP_NS_PDFA_Extension "http://www.aiim.org/pdfa/ns/extension/"
+
+#define kXMP_NS_PDFX "http://ns.adobe.com/pdfx/1.3/"
+#define kXMP_NS_PDFX_ID "http://www.npes.org/pdfx/ns/id/"
+
+#define kXMP_NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+#define kXMP_NS_XML "http://www.w3.org/XML/1998/namespace"
+
+// =================================================================================================
+// Enums and macros used for option bits
+// =====================================
+
+/// \name Macros for standard option selections.
+/// @{
+///
+/// \def kXMP_ArrayLastItem
+/// \brief Options macro accesses last array item.
+///
+/// \def kXMP_UseNullTermination
+/// \brief Options macro sets string style.
+///
+/// \def kXMP_NoOptions
+/// \brief Options macro clears all property-type bits.
+///
+/// @}
+
+#define kXMP_ArrayLastItem ((XMP_Index)(-1L))
+#define kXMP_UseNullTermination ((XMP_StringLen)(~0UL))
+#define kXMP_NoOptions ((XMP_OptionBits)0UL)
+
+/// \name Macros for setting and testing general option bits.
+/// @{
+///
+/// \def XMP_SetOption
+/// \brief Macro sets an option flag bit.
+/// \param var A variable storing an options flag.
+/// \param opt The bit-flag constant to set.
+///
+/// \def XMP_ClearOption
+/// \brief Macro clears an option flag bit.
+/// \param var A variable storing an options flag.
+/// \param opt The bit-flag constant to clear.
+///
+/// \def XMP_TestOption
+/// \brief Macro reports whether an option flag bit is set.
+/// \param var A variable storing an options flag.
+/// \param opt The bit-flag constant to test.
+/// \return True if the bit is set.
+///
+/// \def XMP_OptionIsSet
+/// \brief Macro reports whether an option flag bit is set.
+/// \param var A variable storing an options flag.
+/// \param opt The bit-flag constant to test.
+/// \return True if the bit is set.
+///
+/// \def XMP_OptionIsClear
+/// \brief Macro reports whether an option flag bit is clear.
+/// \param var A variable storing an options flag.
+/// \param opt The bit-flag constant to test.
+/// \return True if the bit is clear.
+///
+/// @}
+
+#define XMP_SetOption(var,opt) var |= (opt)
+#define XMP_ClearOption(var,opt) var &= ~(opt)
+#define XMP_TestOption(var,opt) (((var) & (opt)) != 0)
+#define XMP_OptionIsSet(var,opt) (((var) & (opt)) != 0)
+#define XMP_OptionIsClear(var,opt) (((var) & (opt)) == 0)
+
+/// \name Macros for setting and testing specific option bits.
+/// @{
+///
+/// \def XMP_PropIsSimple
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_PropIsStruct
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_PropIsArray
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_ArrayIsUnordered
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_ArrayIsOrdered
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_ArrayIsAlternate
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_ArrayIsAltText
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_PropHasQualifiers
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_PropIsQualifier
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_PropHasLang
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_NodeIsSchema
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// \def XMP_PropIsAlias
+/// \brief Macro reports the property type specified by an options flag.
+/// \param opt The options flag to check.
+///
+/// @}
+
+#define XMP_PropIsSimple(opt) (((opt) & kXMP_PropCompositeMask) == 0)
+#define XMP_PropIsStruct(opt) (((opt) & kXMP_PropValueIsStruct) != 0)
+#define XMP_PropIsArray(opt) (((opt) & kXMP_PropValueIsArray) != 0)
+
+#define XMP_ArrayIsUnordered(opt) (((opt) & kXMP_PropArrayIsOrdered) == 0)
+#define XMP_ArrayIsOrdered(opt) (((opt) & kXMP_PropArrayIsOrdered) != 0)
+#define XMP_ArrayIsAlternate(opt) (((opt) & kXMP_PropArrayIsAlternate) != 0)
+#define XMP_ArrayIsAltText(opt) (((opt) & kXMP_PropArrayIsAltText) != 0)
+
+#define XMP_PropHasQualifiers(opt) (((opt) & kXMP_PropHasQualifiers) != 0)
+#define XMP_PropIsQualifier(opt) (((opt) & kXMP_PropIsQualifier) != 0)
+#define XMP_PropHasLang(opt) (((opt) & kXMP_PropHasLang) != 0)
+
+#define XMP_NodeIsSchema(opt) (((opt) & kXMP_SchemaNode) != 0)
+#define XMP_PropIsAlias(opt) (((opt) & kXMP_PropIsAlias) != 0)
+
+// -------------------------------------------------------------------------------------------------
+
+/// Option bit flags for the \c TXMPMeta property accessor functions.
+enum {
+
+ /// The XML string form of the property value is a URI, use rdf:resource attribute. DISCOURAGED
+ kXMP_PropValueIsURI = 0x00000002UL,
+
+ // ------------------------------------------------------
+ // Options relating to qualifiers attached to a property.
+
+ /// The property has qualifiers, includes \c rdf:type and \c xml:lang.
+ kXMP_PropHasQualifiers = 0x00000010UL,
+
+ /// This is a qualifier for some other property, includes \c rdf:type and \c xml:lang.
+ /// Qualifiers can have arbitrary structure, and can themselves have qualifiers. If the
+ /// qualifier itself has a structured value, this flag is only set for the top node of the
+ /// qualifier's subtree.
+ kXMP_PropIsQualifier = 0x00000020UL,
+
+ /// Implies \c #kXMP_PropHasQualifiers, property has \c xml:lang.
+ kXMP_PropHasLang = 0x00000040UL,
+
+ /// Implies \c #kXMP_PropHasQualifiers, property has \c rdf:type.
+ kXMP_PropHasType = 0x00000080UL,
+
+ // --------------------------------------------
+ // Options relating to the data structure form.
+
+ /// The value is a structure with nested fields.
+ kXMP_PropValueIsStruct = 0x00000100UL,
+
+ /// The value is an array (RDF alt/bag/seq). The "ArrayIs..." flags identify specific types
+ /// of array; default is a general unordered array, serialized using an \c rdf:Bag container.
+ kXMP_PropValueIsArray = 0x00000200UL,
+
+ /// The item order does not matter.
+ kXMP_PropArrayIsUnordered = kXMP_PropValueIsArray,
+
+ /// Implies \c #kXMP_PropValueIsArray, item order matters. It is serialized using an \c rdf:Seq container.
+ kXMP_PropArrayIsOrdered = 0x00000400UL,
+
+ /// Implies \c #kXMP_PropArrayIsOrdered, items are alternates. It is serialized using an \c rdf:Alt container.
+ kXMP_PropArrayIsAlternate = 0x00000800UL,
+
+ // ------------------------------------
+ // Additional struct and array options.
+
+ /// Implies \c #kXMP_PropArrayIsAlternate, items are localized text. Each array element is a
+ /// simple property with an \c xml:lang attribute.
+ kXMP_PropArrayIsAltText = 0x00001000UL,
+
+ // kXMP_InsertBeforeItem = 0x00004000UL, ! Used by SetXyz functions.
+ // kXMP_InsertAfterItem = 0x00008000UL, ! Used by SetXyz functions.
+
+ // ----------------------------
+ // Other miscellaneous options.
+
+ /// This property is an alias name for another property. This is only returned by
+ /// \c TXMPMeta::GetProperty() and then only if the property name is simple, not an path expression.
+ kXMP_PropIsAlias = 0x00010000UL,
+
+ /// This property is the base value (actual) for a set of aliases.This is only returned by
+ /// \c TXMPMeta::GetProperty() and then only if the property name is simple, not an path expression.
+ kXMP_PropHasAliases = 0x00020000UL,
+
+ /// The value of this property is "owned" by the application, and should not generally be editable in a UI.
+ kXMP_PropIsInternal = 0x00040000UL,
+
+ /// The value of this property is not derived from the document content.
+ kXMP_PropIsStable = 0x00100000UL,
+
+ /// The value of this property is derived from the document content.
+ kXMP_PropIsDerived = 0x00200000UL,
+
+ // kXMPUtil_AllowCommas = 0x10000000UL, ! Used by TXMPUtils::CatenateArrayItems and ::SeparateArrayItems.
+ // kXMP_DeleteExisting = 0x20000000UL, ! Used by TXMPMeta::SetXyz functions to delete any pre-existing property.
+ // kXMP_SchemaNode = 0x80000000UL, ! Returned by iterators - #define to avoid warnings
+
+ // ------------------------------
+ // Masks that are multiple flags.
+
+ /// Property type bit-flag mask for all array types
+ kXMP_PropArrayFormMask = kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate | kXMP_PropArrayIsAltText,
+
+ /// Property type bit-flag mask for composite types (array and struct)
+ kXMP_PropCompositeMask = kXMP_PropValueIsStruct | kXMP_PropArrayFormMask,
+
+ /// Mask for bits that are reserved for transient use by the implementation.
+ kXMP_ImplReservedMask = 0x70000000L
+
+};
+
+#define kXMP_SchemaNode ((XMP_OptionBits)0x80000000UL)
+
+/// Option bit flags for the \c TXMPMeta property setting functions. These option bits are shared
+/// with the accessor functions:
+/// \li \c #kXMP_PropValueIsURI
+/// \li \c #kXMP_PropValueIsStruct
+/// \li \c #kXMP_PropValueIsArray
+/// \li \c #kXMP_PropArrayIsOrdered
+/// \li \c #kXMP_PropArrayIsAlternate
+/// \li \c #kXMP_PropArrayIsAltText
+enum {
+
+ /// Option for array item location: Insert a new item before the given index.
+ kXMP_InsertBeforeItem = 0x00004000UL,
+
+ /// Option for array item location: Insert a new item after the given index.
+ kXMP_InsertAfterItem = 0x00008000UL,
+
+ /// Delete any pre-existing property.
+ kXMP_DeleteExisting = 0x20000000UL,
+
+ /// Bit-flag mask for property-value option bits
+ kXMP_PropValueOptionsMask = kXMP_PropValueIsURI,
+
+ /// Bit-flag mask for array-item location bits
+ kXMP_PropArrayLocationMask = kXMP_InsertBeforeItem | kXMP_InsertAfterItem
+
+};
+
+// -------------------------------------------------------------------------------------------------
+
+/// Option bit flags for \c TXMPMeta::ParseFromBuffer().
+enum {
+
+ /// Require a surrounding \c x:xmpmeta element.
+ kXMP_RequireXMPMeta = 0x0001UL,
+
+ /// This is the not last input buffer for this parse stream.
+ kXMP_ParseMoreBuffers = 0x0002UL,
+
+ /// Do not reconcile alias differences, throw an exception.
+ kXMP_StrictAliasing = 0x0004UL
+
+};
+
+/// Option bit flags for \c TXMPMeta::SerializeToBuffer().
+enum {
+
+ // *** Option to remove empty struct/array, or leaf with empty value?
+
+ /// Omit the XML packet wrapper.
+ kXMP_OmitPacketWrapper = 0x0010UL,
+
+ /// Default is a writeable packet.
+ kXMP_ReadOnlyPacket = 0x0020UL,
+
+ /// Use a compact form of RDF.
+ kXMP_UseCompactFormat = 0x0040UL,
+
+ /// Use a canonical form of RDF.
+ kXMP_UseCanonicalFormat = 0x0080UL,
+
+ /// Include a padding allowance for a thumbnail image.
+ kXMP_IncludeThumbnailPad = 0x0100UL,
+
+ /// The padding parameter is the overall packet length.
+ kXMP_ExactPacketLength = 0x0200UL,
+
+ /// Omit all formatting whitespace.
+ kXMP_OmitAllFormatting = 0x0800UL,
+
+ /// Omit the x:xmpmeta element surrounding the rdf:RDF element.
+ kXMP_OmitXMPMetaElement = 0x1000UL,
+
+ /// Include a rdf Hash and Merged flag in x:xmpmeta element.
+ kXMP_IncludeRDFHash = 0x2000UL,
+
+ _XMP_LittleEndian_Bit = 0x0001UL, // ! Don't use directly, see the combined values below!
+ _XMP_UTF16_Bit = 0x0002UL,
+ _XMP_UTF32_Bit = 0x0004UL,
+
+ /// Bit-flag mask for encoding-type bits
+ kXMP_EncodingMask = 0x0007UL,
+
+ /// Use UTF8 encoding
+ kXMP_EncodeUTF8 = 0UL,
+
+ /// Use UTF16 big-endian encoding
+ kXMP_EncodeUTF16Big = _XMP_UTF16_Bit,
+
+ /// Use UTF16 little-endian encoding
+ kXMP_EncodeUTF16Little = _XMP_UTF16_Bit | _XMP_LittleEndian_Bit,
+
+ /// Use UTF32 big-endian encoding
+ kXMP_EncodeUTF32Big = _XMP_UTF32_Bit,
+
+ /// Use UTF13 little-endian encoding
+ kXMP_EncodeUTF32Little = _XMP_UTF32_Bit | _XMP_LittleEndian_Bit
+
+};
+
+// -------------------------------------------------------------------------------------------------
+
+/// Option bit flags for \c TXMPIterator construction.
+enum {
+
+ /// The low 8 bits are an enum of what data structure to iterate.
+ kXMP_IterClassMask = 0x00FFUL,
+
+ /// Iterate the property tree of a TXMPMeta object.
+ kXMP_IterProperties = 0x0000UL,
+
+ /// Iterate the global alias table.
+ kXMP_IterAliases = 0x0001UL,
+
+ /// Iterate the global namespace table.
+ kXMP_IterNamespaces = 0x0002UL,
+
+ /// Just do the immediate children of the root, default is subtree.
+ kXMP_IterJustChildren = 0x0100UL,
+
+ /// Just do the leaf nodes, default is all nodes in the subtree.
+ kXMP_IterJustLeafNodes = 0x0200UL,
+
+ /// Return just the leaf part of the path, default is the full path.
+ kXMP_IterJustLeafName = 0x0400UL,
+
+ /// Omit all qualifiers.
+ kXMP_IterOmitQualifiers = 0x1000UL
+
+};
+
+/// Option bit flags for \c TXMPIterator::Skip().
+enum {
+
+ /// Skip the subtree below the current node.
+ kXMP_IterSkipSubtree = 0x0001UL,
+
+ /// Skip the subtree below and remaining siblings of the current node.
+ kXMP_IterSkipSiblings = 0x0002UL
+
+};
+
+// -------------------------------------------------------------------------------------------------
+
+/// Option bit flags for \c TXMPUtils::CatenateArrayItems() and \c TXMPUtils::SeparateArrayItems().
+/// These option bits are shared with the accessor functions:
+/// \li \c #kXMP_PropValueIsArray,
+/// \li \c #kXMP_PropArrayIsOrdered,
+/// \li \c #kXMP_PropArrayIsAlternate,
+/// \li \c #kXMP_PropArrayIsAltText
+enum {
+
+ /// Allow commas in item values, default is separator.
+ kXMPUtil_AllowCommas = 0x10000000UL
+
+};
+
+/// Option bit flags for \c TXMPUtils::ApplyTemplate().
+enum {
+
+ /// Do all properties, default is just external properties.
+ kXMPTemplate_IncludeInternalProperties = 0x0001UL,
+
+ /// Perform a Replace operation, add new properties and modify existing ones.
+ kXMPTemplate_ReplaceExistingProperties = 0x0002UL,
+
+ /// Similar to Replace, also delete if the template has an empty value.
+ kXMPTemplate_ReplaceWithDeleteEmpty = 0x0004UL,
+
+ /// Perform an Add operation, add properties if they don't already exist.
+ kXMPTemplate_AddNewProperties = 0x0008UL,
+
+ /// Perform a Clear operation, keep named properties and delete everything else.
+ kXMPTemplate_ClearUnnamedProperties = 0x0010UL
+
+};
+
+/// Option bit flags for \c TXMPUtils::RemoveProperties() and \c TXMPUtils::AppendProperties().
+enum {
+
+ /// Do all properties, default is just external properties.
+ kXMPUtil_DoAllProperties = 0x0001UL,
+
+ /// Replace existing values, default is to leave them.
+ kXMPUtil_ReplaceOldValues = 0x0002UL,
+
+ /// Delete properties if the new value is empty.
+ kXMPUtil_DeleteEmptyValues = 0x0004UL,
+
+ /// Include aliases, default is just actual properties.
+ kXMPUtil_IncludeAliases = 0x0800UL
+
+};
+
+// =================================================================================================
+// Types and Constants for XMPFiles
+// ================================
+
+/// Seek mode constants for use with XMP_IO and inside XMPFiles library code.
+enum SeekMode { kXMP_SeekFromStart, kXMP_SeekFromCurrent, kXMP_SeekFromEnd };
+
+/// File format constants for use with XMPFiles.
+enum {
+
+ // ! Hex used to avoid gcc warnings. Leave the constants so the text reads big endian. There
+ // ! seems to be no decent way on UNIX to determine the target endianness at compile time.
+ // ! Forcing it on the client isn't acceptable.
+
+ // --------------------
+ // Public file formats.
+
+ /// Public file format constant: 'PDF '
+ kXMP_PDFFile = 0x50444620UL,
+ /// Public file format constant: 'PS ', general PostScript following DSC conventions
+ kXMP_PostScriptFile = 0x50532020UL,
+ /// Public file format constant: 'EPS ', encapsulated PostScript
+ kXMP_EPSFile = 0x45505320UL,
+
+ /// Public file format constant: 'JPEG'
+ kXMP_JPEGFile = 0x4A504547UL,
+ /// Public file format constant: 'JPX ', JPEG 2000, ISO 15444-1
+ kXMP_JPEG2KFile = 0x4A505820UL,
+ /// Public file format constant: 'TIFF'
+ kXMP_TIFFFile = 0x54494646UL,
+ /// Public file format constant: 'GIF '
+ kXMP_GIFFile = 0x47494620UL,
+ /// Public file format constant: 'PNG '
+ kXMP_PNGFile = 0x504E4720UL,
+
+ /// Public file format constant: 'SWF '
+ kXMP_SWFFile = 0x53574620UL,
+ /// Public file format constant: 'FLA '
+ kXMP_FLAFile = 0x464C4120UL,
+ /// Public file format constant: 'FLV '
+ kXMP_FLVFile = 0x464C5620UL,
+
+ /// Public file format constant: 'MOV ', Quicktime
+ kXMP_MOVFile = 0x4D4F5620UL,
+ /// Public file format constant: 'AVI '
+ kXMP_AVIFile = 0x41564920UL,
+ /// Public file format constant: 'CIN ', Cineon
+ kXMP_CINFile = 0x43494E20UL,
+ /// Public file format constant: 'WAV '
+ kXMP_WAVFile = 0x57415620UL,
+ /// Public file format constant: 'MP3 '
+ kXMP_MP3File = 0x4D503320UL,
+ /// Public file format constant: 'SES ', Audition session
+ kXMP_SESFile = 0x53455320UL,
+ /// Public file format constant: 'CEL ', Audition loop
+ kXMP_CELFile = 0x43454C20UL,
+ /// Public file format constant: 'MPEG'
+ kXMP_MPEGFile = 0x4D504547UL,
+ /// Public file format constant: 'MP2 '
+ kXMP_MPEG2File = 0x4D503220UL,
+ /// Public file format constant: 'MP4 ', ISO 14494-12 and -14
+ kXMP_MPEG4File = 0x4D503420UL,
+ /// Public file format constant: 'MXF '
+ kXMP_MXFFile = 0x4D584620UL,
+ /// Public file format constant: 'WMAV', Windows Media Audio and Video
+ kXMP_WMAVFile = 0x574D4156UL,
+ /// Public file format constant: 'AIFF'
+ kXMP_AIFFFile = 0x41494646UL,
+ /// Public file format constant: 'RED ', RED file format
+ kXMP_REDFile = 0x52454420UL,
+ /// Public file format constant: 'P2 ', a collection not really a single file
+ kXMP_P2File = 0x50322020UL,
+ /// Public file format constant: 'XDCF', a collection not really a single file
+ kXMP_XDCAM_FAMFile = 0x58444346UL,
+ /// Public file format constant: 'XDCS', a collection not really a single file
+ kXMP_XDCAM_SAMFile = 0x58444353UL,
+ /// Public file format constant: 'XDCX', a collection not really a single file
+ kXMP_XDCAM_EXFile = 0x58444358UL,
+ /// Public file format constant: 'AVHD', a collection not really a single file
+ kXMP_AVCHDFile = 0x41564844UL,
+ /// Public file format constant: 'SHDV', a collection not really a single file
+ kXMP_SonyHDVFile = 0x53484456UL,
+ /// Public file format constant: 'CNXF', a collection not really a single file
+ kXMP_CanonXFFile = 0x434E5846UL,
+
+ /// Public file format constant: 'HTML'
+ kXMP_HTMLFile = 0x48544D4CUL,
+ /// Public file format constant: 'XML '
+ kXMP_XMLFile = 0x584D4C20UL,
+ /// Public file format constant: 'text'
+ kXMP_TextFile = 0x74657874UL,
+
+ // -------------------------------
+ // Adobe application file formats.
+
+ /// Adobe application file format constant: 'PSD '
+ kXMP_PhotoshopFile = 0x50534420UL,
+ /// Adobe application file format constant: 'AI '
+ kXMP_IllustratorFile = 0x41492020UL,
+ /// Adobe application file format constant: 'INDD'
+ kXMP_InDesignFile = 0x494E4444UL,
+ /// Adobe application file format constant: 'AEP '
+ kXMP_AEProjectFile = 0x41455020UL,
+ /// Adobe application file format constant: 'AET ', After Effects Project Template
+ kXMP_AEProjTemplateFile = 0x41455420UL,
+ /// Adobe application file format constant: 'FFX '
+ kXMP_AEFilterPresetFile = 0x46465820UL,
+ /// Adobe application file format constant: 'NCOR'
+ kXMP_EncoreProjectFile = 0x4E434F52UL,
+ /// Adobe application file format constant: 'PRPJ'
+ kXMP_PremiereProjectFile = 0x5052504AUL,
+ /// Adobe application file format constant: 'PRTL'
+ kXMP_PremiereTitleFile = 0x5052544CUL,
+ /// Adobe application file format constant: 'UCF ', Universal Container Format
+ kXMP_UCFFile = 0x55434620UL,
+
+ // -------
+ // Others.
+
+ /// Unknown file format constant: ' '
+ kXMP_UnknownFile = 0x20202020UL
+
+};
+
+/// Type for file format identification constants. See \c #kXMP_PDFFile and following.
+typedef XMP_Uns32 XMP_FileFormat;
+
+// -------------------------------------------------------------------------------------------------
+
+/// Byte-order masks, do not use directly
+enum {
+ kXMP_CharLittleEndianMask = 1,
+ kXMP_Char16BitMask = 2,
+ kXMP_Char32BitMask = 4
+};
+
+/// Constants to allow easy testing for 16/32 bit and big/little endian.
+enum {
+ /// 8-bit
+ kXMP_Char8Bit = 0,
+ /// 16-bit big-endian
+ kXMP_Char16BitBig = kXMP_Char16BitMask,
+ /// 16-bit little-endian
+ kXMP_Char16BitLittle = kXMP_Char16BitMask | kXMP_CharLittleEndianMask,
+ /// 32-bit big-endian
+ kXMP_Char32BitBig = kXMP_Char32BitMask,
+ /// 32-bit little-endian
+ kXMP_Char32BitLittle = kXMP_Char32BitMask | kXMP_CharLittleEndianMask,
+ /// Variable or not-yet-known cases
+ kXMP_CharUnknown = 1
+};
+
+/// \name Macros to test components of the character form mask
+/// @{
+///
+/// \def XMP_CharFormIs16Bit
+/// \brief Macro reports the encoding of a character.
+/// \param f The character to check.
+///
+/// \def XMP_CharFormIs32Bit
+/// \brief Macro reports the encoding of a character.
+/// \param f The character to check.
+///
+/// \def XMP_CharFormIsBigEndian
+/// \brief Macro reports the byte-order of a character.
+/// \param f The character to check.
+///
+/// \def XMP_CharFormIsLittleEndian
+/// \brief Macro reports the byte-order of a character.
+/// \param f The character to check.
+///
+/// \def XMP_GetCharSize
+/// \brief Macro reports the byte-size of a character.
+/// \param f The character to check.
+///
+/// \def XMP_CharToSerializeForm
+/// \brief Macro converts \c XMP_Uns8 to \c XMP_OptionBits.
+/// \param cf The character to convert.
+///
+/// \def XMP_CharFromSerializeForm
+/// \brief Macro converts \c XMP_OptionBits to \c XMP_Uns8.
+/// \param sf The character to convert.
+///
+/// @}
+
+#define XMP_CharFormIs16Bit(f) ( ((int)(f) & kXMP_Char16BitMask) != 0 )
+#define XMP_CharFormIs32Bit(f) ( ((int)(f) & kXMP_Char32BitMask) != 0 )
+#define XMP_CharFormIsBigEndian(f) ( ((int)(f) & kXMP_CharLittleEndianMask) == 0 )
+#define XMP_CharFormIsLittleEndian(f) ( ((int)(f) & kXMP_CharLittleEndianMask) != 0 )
+#define XMP_GetCharSize(f) ( ((int)(f)&6) == 0 ? 1 : (int)(f)&6 )
+#define XMP_CharToSerializeForm(cf) ( (XMP_OptionBits)(cf) )
+#define XMP_CharFromSerializeForm(sf) ( (XMP_Uns8)(sf) )
+
+/// \def kXMPFiles_UnknownOffset
+/// \brief Constant for an unknown packet offset within a file.
+#define kXMPFiles_UnknownOffset ((XMP_Int64)-1)
+
+/// \def kXMPFiles_UnknownLength
+/// \brief Constant for an unknown packet length within a file.
+#define kXMPFiles_UnknownLength ((XMP_Int32)-1)
+
+/// XMP packet description
+struct XMP_PacketInfo {
+
+ /// Packet offset in the file in bytes, -1 if unknown.
+ XMP_Int64 offset;
+ /// Packet length in the file in bytes, -1 if unknown.
+ XMP_Int32 length;
+ /// Packet padding size in bytes, zero if unknown.
+ XMP_Int32 padSize; // Zero if unknown.
+
+ /// Character format using the values \c kXMP_Char8Bit, \c kXMP_Char16BitBig, etc.
+ XMP_Uns8 charForm;
+ /// True if there is a packet wrapper and the trailer says writeable by dumb packet scanners.
+ XMP_Bool writeable;
+ /// True if there is a packet wrapper, the "<?xpacket...>" XML processing instructions.
+ XMP_Bool hasWrapper;
+
+ /// Padding to make the struct's size be a multiple 4.
+ XMP_Uns8 pad;
+
+ /// Default constructor.
+ XMP_PacketInfo() : offset(kXMPFiles_UnknownOffset), length(kXMPFiles_UnknownLength),
+ padSize(0), charForm(0), writeable(0), hasWrapper(0), pad(0) {};
+
+};
+
+/// Version of the XMP_PacketInfo type
+enum {
+ /// Version of the XMP_PacketInfo type
+ kXMP_PacketInfoVersion = 3
+};
+
+// -------------------------------------------------------------------------------------------------
+
+/// Option bit flags for \c TXMPFiles::Initialize().
+enum {
+ /// Ignore non-XMP text that uses an undefined "local" encoding.
+ kXMPFiles_IgnoreLocalText = 0x0002,
+ /// Combination of flags necessary for server products using XMPFiles.
+ kXMPFiles_ServerMode = kXMPFiles_IgnoreLocalText
+};
+
+/// Option bit flags for \c TXMPFiles::GetFormatInfo().
+enum {
+
+ /// Can inject first-time XMP into an existing file.
+ kXMPFiles_CanInjectXMP = 0x00000001,
+
+ /// Can expand XMP or other metadata in an existing file.
+ kXMPFiles_CanExpand = 0x00000002,
+
+ /// Can copy one file to another, writing new metadata.
+ kXMPFiles_CanRewrite = 0x00000004,
+
+ /// Can expand, but prefers in-place update.
+ kXMPFiles_PrefersInPlace = 0x00000008,
+
+ /// Supports reconciliation between XMP and other forms.
+ kXMPFiles_CanReconcile = 0x00000010,
+
+ /// Allows access to just the XMP, ignoring other forms.
+ kXMPFiles_AllowsOnlyXMP = 0x00000020,
+
+ /// File handler returns raw XMP packet information.
+ kXMPFiles_ReturnsRawPacket = 0x00000040,
+
+ /// The file handler does the file open and close.
+ kXMPFiles_HandlerOwnsFile = 0x00000100,
+
+ /// The file handler allows crash-safe file updates.
+ kXMPFiles_AllowsSafeUpdate = 0x00000200,
+
+ /// The file format needs the XMP packet to be read-only.
+ kXMPFiles_NeedsReadOnlyPacket = 0x00000400,
+
+ /// The file handler uses a "sidecar" file for the XMP.
+ kXMPFiles_UsesSidecarXMP = 0x00000800,
+
+ /// The format is folder oriented, for example the P2 video format.
+ kXMPFiles_FolderBasedFormat = 0x00001000,
+
+ /// The file Handler is capable of notifying progress notifications
+ kXMPFiles_CanNotifyProgress = 0x00002000,
+
+ /// The plugin handler is not capable for delay loading
+ kXMPFiles_NeedsPreloading = 0x00004000
+
+};
+
+/// Option bit flags for \c TXMPFiles::OpenFile().
+enum {
+
+ /// Open for read-only access.
+ kXMPFiles_OpenForRead = 0x00000001,
+
+ /// Open for reading and writing.
+ kXMPFiles_OpenForUpdate = 0x00000002,
+
+ /// Only the XMP is wanted, allows space/time optimizations.
+ kXMPFiles_OpenOnlyXMP = 0x00000004,
+
+ /// Force use of the given handler (format), do not even verify the format.
+ kXMPFiles_ForceGivenHandler = 0x00000008,
+
+ /// Be strict about only attempting to use the designated file handler, no fallback to other handlers.
+ kXMPFiles_OpenStrictly = 0x00000010,
+
+ /// Require the use of a smart handler.
+ kXMPFiles_OpenUseSmartHandler = 0x00000020,
+
+ /// Force packet scanning, do not use a smart handler.
+ kXMPFiles_OpenUsePacketScanning = 0x00000040,
+
+ /// Only packet scan files "known" to need scanning.
+ kXMPFiles_OpenLimitedScanning = 0x00000080,
+
+ /// Attempt to repair a file opened for update, default is to not open (throw an exception).
+ kXMPFiles_OpenRepairFile = 0x00000100,
+
+ /// When updating a file, spend the effort necessary to optimize file layout.
+ kXMPFiles_OptimizeFileLayout = 0x00000200
+
+};
+
+/// Option bit flags for \c TXMPFiles::CloseFile().
+enum {
+ /// Write into a temporary file and swap for crash safety.
+ kXMPFiles_UpdateSafely = 0x0001
+};
+
+// =================================================================================================
+// Error notification and Exceptions
+// =================================
+
+/// \name Error notification and Exceptions
+/// @{
+///
+/// From the beginning through version 5.5, XMP Tookit errors result in throwing an \c XMP_Error
+/// exception. For the most part exceptions were thrown early and thus API calls aborted as soon as
+/// an error was detected. Starting in version 5.5, support has been added for notifications of
+/// errors arising in calls to \c TXMPMeta and \c TXMPFiles functions.
+///
+/// A client can register an error notification callback function for a \c TXMPMeta or \c TXMPFiles
+/// object. This can be done as a global default or individually to each object. The global default
+/// applies to all objects created after it is registered. Within the object there is no difference
+/// between the global default or explicitly registered callback. The callback function returns a
+/// \c bool value indicating if recovery should be attempted (true) or an exception thrown (false).
+/// If no callback is registered, a best effort at recovery and continuation will be made with an
+/// exception thrown if recovery is not possible. More details can be found in the \c TXMPMeta and
+/// \c TXMPFiles documentation.
+///
+/// The \c XMP_Error class contains a numeric code and an English explanation. New numeric codes may
+/// be added at any time. There are typically many possible explanations for each numeric code. The
+/// explanations try to be precise about the specific circumstances causing the error.
+///
+/// \note The explanation string is for debugging use only. It must not be shown to users in a
+/// final product. It is written for developers not users, and never localized.
+
+typedef XMP_Uns8 XMP_ErrorSeverity;
+
+/// Severity codes for error notifications
+enum {
+ /// Partial recovery and continuation is possible.
+ kXMPErrSev_Recoverable = 0,
+ /// Recovery is not possible, an exception will be thrown aborting the API call.
+ kXMPErrSev_OperationFatal = 1,
+ /// Recovery is not possible, an exception will be thrown, the file is corrupt and possibly unusable.
+ kXMPErrSev_FileFatal = 2,
+ /// Recovery is not possible, an exception will be thrown, the entire process should be aborted.
+ kXMPErrSev_ProcessFatal = 3
+};
+
+// -------------------------------------------------------------------------------------------------
+/// The signature of a client-defined callback for TXMPMeta error notifications.
+///
+/// @param context A pointer used to carry client-private context.
+///
+/// @param severity The severity of the error, see the \c XMP_ErrorSeverity values.
+///
+/// @param cause A numeric code for the cause of the error, from the XMP_Error exception codes.
+/// Codes used with TXMPMeta error notifications:
+/// \li \c kXMPErr_BadXML - An XML syntax error found during parsing.
+/// \li \c kXMPErr_BadRDF - A syntax or semantic parsing error in the XMP subset of RDF.
+/// \li \c kXMPErr_BadXMP - A semantic XMP data model error.
+/// \li \c kXMPErr_BadValue - An XMP value error, wrong type, out of range, etc.
+/// \li \c kXMPErr_NoMemory - A heap allocation failure.
+///
+/// @param message An explanation of the error, for debugging use only. This should not be displayed
+/// to users in a final product.
+///
+/// @return True if the operation should continue with a best effort attempt at recovery, false if
+/// it should be aborted with an exception thrown from the library back to the original caller.
+/// Recovery is possible only if the severity is kXMPErrSev_Recoverable, an exception will be
+/// thrown on return from the callback in all other cases.
+///
+/// @see \c TXMPMeta::SetDefaultErrorCallback() and \c TXMPMeta::SetErrorCallback()
+
+typedef bool (* XMPMeta_ErrorCallbackProc) ( void* context, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr message );
+
+// -------------------------------------------------------------------------------------------------
+/// The signature of a client-defined callback for TXMPFiles error notifications.
+///
+/// @param context A pointer used to carry client-private context.
+///
+/// @param filePath The path for the file involved in the error.
+///
+/// @param severity The severity of the error, see the \c XMP_ErrorSeverity values.
+///
+/// @param cause A numeric code for the cause of the error, from the XMP_Error exception codes.
+/// Codes used with TXMPFiles error notifications:
+/// \li \c kXMPErr_NoFile - A file does not exist
+/// \li \c kXMPErr_FilePermission - A file exists but cannot be opened
+/// \li \c kXMPErr_FilePathNotAFile - A path exists which is not a file
+/// \li \c dXMPErr_RejectedFileExtension - Any Operation called on rejected file extension
+/// \li \c KXMPErr_NoFileHandler - No suitable handler is found for the file
+/// \li \c kXMPErr_DiskSpace - A file write fails due to lack of disk space
+/// \li \c kXMPErr_ReadError - A file read fails
+/// \li \c kXMPErr_WriteError - A file write fails for some other reason than space
+/// \li \c kXMPErr_BadFileFormat - A file is corrupt or ill-formed
+/// \li \c kXMPErr_BadBlockFormat - A portion of a file is corrupt or ill-formed
+/// \li \c kXMPErr_BadValue - An XMP or non-XMP metadata item has an invalid value
+/// \li \c kXMPErr_NoMemory - A heap allocation failure
+///
+/// @param message An explanation of the error, for debugging use only. This should not be displayed
+/// to users in a final product.
+///
+/// @return True if the operation should continue with a best effort attempt at recovery, false if
+/// it should be aborted with an exception thrown from the library back to the original caller.
+/// Recovery is possible only if the severity is kXMPErrSev_Recoverable, an exception will be
+/// thrown on return from the callback in all other cases.
+///
+/// @see \c TXMPFiles::SetDefaultErrorCallback() and \c TXMPFiles::SetErrorCallback()
+
+typedef bool (* XMPFiles_ErrorCallbackProc) ( void* context, XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr message );
+
+// -------------------------------------------------------------------------------------------------
+/// Internal: The signatures of client-side wrappers for the error notification callbacks.
+
+typedef XMP_Bool (* XMPMeta_ErrorCallbackWrapper) ( XMPMeta_ErrorCallbackProc clientProc, void* context,
+ XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr message );
+
+typedef XMP_Bool (* XMPFiles_ErrorCallbackWrapper) ( XMPFiles_ErrorCallbackProc clientProc, void* context,
+ XMP_StringPtr filePath, XMP_ErrorSeverity severity,
+ XMP_Int32 cause, XMP_StringPtr message );
+
+/// XMP Toolkit error, associates an error code with a descriptive error string.
+class XMP_Error {
+public:
+
+ /// @brief Constructor for an XMP_Error.
+ ///
+ /// @param _id The numeric code.
+ ///
+ /// @param _errMsg The descriptive string, for debugging use only. It must not be shown to users
+ /// in a final product. It is written for developers, not users, and never localized.
+ XMP_Error ( XMP_Int32 _id, XMP_StringPtr _errMsg ) : id(_id), errMsg(_errMsg), notified(false) {};
+
+ /// Retrieves the numeric code from an XMP_Error.
+ inline XMP_Int32 GetID() const { return id; };
+
+ /// Retrieves the descriptive string from an XMP_Error.
+ inline XMP_StringPtr GetErrMsg() const { return errMsg; };
+
+ /// Retrieves the information whether particular error is notified or not
+ inline XMP_Bool IsNotified() const { return notified; }
+
+ /// Sets the notification status for an error
+ inline void SetNotified() { notified = true; };
+
+private:
+ /// Exception code. See constants \c #kXMPErr_Unknown and following.
+ XMP_Int32 id;
+ /// Descriptive string, for debugging use only. It must not be shown to users in a final
+ /// product. It is written for developers, not users, and never localized.
+ XMP_StringPtr errMsg;
+ /// Variable to store whether this particular error is notified to user or not
+ XMP_Bool notified;
+};
+
+/// XMP_Error exception code constants
+enum {
+
+ // --------------------
+ /// Generic error codes.
+
+ /// No error
+ kXMPErr_NoError = -1,
+
+ /// Generic unknown error
+ kXMPErr_Unknown = 0,
+ /// Generic undefined error
+ kXMPErr_TBD = 1,
+ /// Generic unavailable error
+ kXMPErr_Unavailable = 2,
+ /// Generic bad object error
+ kXMPErr_BadObject = 3,
+ /// Generic bad parameter error
+ kXMPErr_BadParam = 4,
+ /// Generic bad value error
+ kXMPErr_BadValue = 5,
+ /// Generic assertion failure
+ kXMPErr_AssertFailure = 6,
+ /// Generic enforcement failure
+ kXMPErr_EnforceFailure = 7,
+ /// Generic unimplemented error
+ kXMPErr_Unimplemented = 8,
+ /// Generic internal failure
+ kXMPErr_InternalFailure = 9,
+ /// Generic deprecated error
+ kXMPErr_Deprecated = 10,
+ /// Generic external failure
+ kXMPErr_ExternalFailure = 11,
+ /// Generic user abort error
+ kXMPErr_UserAbort = 12,
+ /// Generic standard exception
+ kXMPErr_StdException = 13,
+ /// Generic unknown exception
+ kXMPErr_UnknownException = 14,
+ /// Generic out-of-memory error
+ kXMPErr_NoMemory = 15,
+ /// Progress reporting callback requested abort
+ kXMPErr_ProgressAbort = 16,
+
+ // ------------------------------------
+ // More specific parameter error codes.
+
+ /// Bad schema parameter
+ kXMPErr_BadSchema = 101,
+ /// Bad XPath parameter
+ kXMPErr_BadXPath = 102,
+ /// Bad options parameter
+ kXMPErr_BadOptions = 103,
+ /// Bad index parameter
+ kXMPErr_BadIndex = 104,
+ /// Bad iteration position
+ kXMPErr_BadIterPosition = 105,
+ /// XML parsing error (deprecated)
+ kXMPErr_BadParse = 106,
+ /// Serialization error
+ kXMPErr_BadSerialize = 107,
+ /// File format error
+ kXMPErr_BadFileFormat = 108,
+ /// No file handler found for format
+ kXMPErr_NoFileHandler = 109,
+ /// Data too large for JPEG file format
+ kXMPErr_TooLargeForJPEG = 110,
+ /// A file does not exist
+ kXMPErr_NoFile = 111,
+ /// A file exists but cannot be opened
+ kXMPErr_FilePermission = 112,
+ /// A file write failed due to lack of disk space
+ kXMPErr_DiskSpace = 113,
+ /// A file read failed
+ kXMPErr_ReadError = 114,
+ /// A file write failed for a reason other than lack of disk space
+ kXMPErr_WriteError = 115,
+ /// A block of a file is ill-formed, e.g. invalid IPTC-IIM in a photo
+ kXMPErr_BadBlockFormat = 116,
+ /// File Path is not a file
+ kXMPErr_FilePathNotAFile = 117,
+ /// Rejected File extension
+ kXMPErr_RejectedFileExtension = 118,
+
+ // -----------------------------------------------
+ // File format and internal structure error codes.
+
+ /// XML format error
+ kXMPErr_BadXML = 201,
+ /// RDF format error
+ kXMPErr_BadRDF = 202,
+ /// XMP format error
+ kXMPErr_BadXMP = 203,
+ /// Empty iterator
+ kXMPErr_EmptyIterator = 204,
+ /// Unicode error
+ kXMPErr_BadUnicode = 205,
+ /// TIFF format error
+ kXMPErr_BadTIFF = 206,
+ /// JPEG format error
+ kXMPErr_BadJPEG = 207,
+ /// PSD format error
+ kXMPErr_BadPSD = 208,
+ /// PSIR format error
+ kXMPErr_BadPSIR = 209,
+ /// IPTC format error
+ kXMPErr_BadIPTC = 210,
+ /// MPEG format error
+ kXMPErr_BadMPEG = 211
+
+};
+
+/// @}
+
+// =================================================================================================
+// Client callbacks
+// ================
+
+// -------------------------------------------------------------------------------------------------
+/// \name Special purpose callback functions
+/// @{
+
+/// A signed 32-bit integer used as a status result for the output callback routine,
+/// \c XMP_TextOutputProc. Zero means no error, all other values except -1 are private to the callback.
+/// The callback is wrapped to prevent exceptions being thrown across DLL boundaries. Any exceptions
+/// thrown out of the callback cause a return status of -1.
+
+typedef XMP_Int32 XMP_Status;
+
+// -------------------------------------------------------------------------------------------------
+/// The signature of a client-defined callback for text output from XMP Toolkit debugging
+/// operations. The callback is invoked one or more times for each line of output. The end of a line
+/// is signaled by a '\\n' character at the end of the buffer. Formatting newlines are never present
+/// in the middle of a buffer, but values of properties might contain any UTF-8 characters.
+///
+/// @param refCon A pointer to client-defined data passed to the TextOutputProc.
+///
+/// @param buffer A string containing one line of output.
+///
+/// @param bufferSize The number of characters in the output buffer.
+///
+/// @return A success/fail status value. Any failure result aborts the output.
+///
+/// @see \c TXMPMeta::DumpObject()
+
+typedef XMP_Status (* XMP_TextOutputProc) ( void * refCon,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize );
+
+// -------------------------------------------------------------------------------------------------
+/// The signature of a client-defined callback to check for a user request to abort a time-consuming
+/// operation within XMPFiles.
+///
+/// @param arg A pointer to caller-defined data passed from the registration call.
+///
+/// @return True to abort the current operation, which results in an exception being thrown.
+///
+/// @see \c TXMPFiles::SetAbortProc()
+
+typedef bool (* XMP_AbortProc) ( void * arg );
+
+// -------------------------------------------------------------------------------------------------
+/// The signature of a client-defined callback for progress report notifications.
+///
+/// @param context A pointer used to carry client-private context.
+///
+/// @param elapsedTime The time in seconds since the progress reporting started.
+///
+/// @param fractionDone A float value estimating the amount of work already done, in the range of
+/// 0.0 to 1.0. A value of 0.0 is given if the amount is not known, this happens if there is no
+/// estimate total for the total work. The units of work are not defined, but should usually be
+/// related to the number of bytes of I/O. This will go backwards if total work estimate changes.
+///
+/// @param secondsToGo A float value estimating the number of seconds left to complete the file
+/// operation. A value of 0.0 is given if the amount is not known, this happens if the amount of
+/// total work is unknown. This can go backwards according to throughput or if work estimate changes.
+///
+/// @return True if the file operation should continue, false if it should be aborted with an
+/// exception being thrown from the XMPFiles library back to the original caller.
+///
+/// @see \c TXMPFiles::SetDefaultProgressCallback() and \c TXMPFiles::SetProgressCallback()
+
+typedef bool (* XMP_ProgressReportProc) ( void * context, float elapsedTime, float fractionDone, float secondsToGo );
+
+// -------------------------------------------------------------------------------------------------
+/// Internal: The signature of a client-side wrapper for the progress report callback.
+
+typedef XMP_Bool (* XMP_ProgressReportWrapper) ( XMP_ProgressReportProc proc, void * context,
+ float elapsedTime, float fractionDone, float secondsToGo );
+
+/// @}
+
+// =================================================================================================
+// Stuff with no better place to be
+// ================================
+
+/// XMP Toolkit version information
+typedef struct XMP_VersionInfo {
+ /// The primary release number, the "1" in version "1.2.3".
+ XMP_Uns8 major;
+ /// The secondary release number, the "2" in version "1.2.3".
+ XMP_Uns8 minor;
+ /// The tertiary release number, the "3" in version "1.2.3".
+ XMP_Uns8 micro;
+ /// A 0/1 boolean value, true if this is a debug build.
+ XMP_Bool isDebug;
+ /// A rolling build number, monotonically increasing in a release.
+ XMP_Uns32 build;
+ /// Individual feature implementation flags.
+ XMP_Uns32 flags;
+ /// A comprehensive version information string.
+ XMP_StringPtr message;
+} XMP_VersionInfo;
+
+// =================================================================================================
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#include <vector>
+
+#endif // __XMP_Const_h__
diff --git a/gpr/source/lib/xmp_core/public/include/XMP_Environment.h b/gpr/source/lib/xmp_core/public/include/XMP_Environment.h
new file mode 100644
index 0000000..fd459ad
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/XMP_Environment.h
@@ -0,0 +1,165 @@
+#ifndef __XMP_Environment_h__
+#define __XMP_Environment_h__ 1
+
+// =================================================================================================
+// XMP_Environment.h - Build environment flags for the XMP toolkit.
+// ================================================================
+//
+// This header is just C preprocessor macro definitions to set up the XMP toolkit build environment.
+// It must be the first #include in any chain since it might affect things in other #includes.
+//
+// =================================================================================================
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// =================================================================================================
+// Determine the Platform
+// =================================================================================================
+
+#ifdef _WIN32
+
+ #define XMP_MacBuild 0
+ #define XMP_iOSBuild 0
+ #define XMP_WinBuild 1
+ #define XMP_UNIXBuild 0
+
+#elif __APPLE__
+
+ #include "TargetConditionals.h"
+
+ #if TARGET_OS_IPHONE
+
+ #define XMP_MacBuild 0
+ #define XMP_iOSBuild 1
+ #define XMP_WinBuild 0
+ #define XMP_UNIXBuild 0
+
+ #else
+
+ #define XMP_MacBuild 1
+ #define XMP_iOSBuild 0
+ #define XMP_WinBuild 0
+ #define XMP_UNIXBuild 0
+
+ #endif
+
+#elif __ANDROID__
+
+#elif __linux__ || __unix__
+
+ #define XMP_MacBuild 0
+ #define XMP_WinBuild 0
+ #define XMP_UNIXBuild 1
+ #define XMP_iOSBuild 0
+
+#else
+ #error "XMP environment error - Unknown compiler"
+#endif
+
+// =================================================================================================
+// Common Macros
+// =============
+
+#if defined ( DEBUG )
+ #if defined ( NDEBUG )
+ #error "XMP environment error - both DEBUG and NDEBUG are defined"
+ #endif
+ #define XMP_DebugBuild 1
+#endif
+
+#if defined ( NDEBUG )
+ #define XMP_DebugBuild 0
+#endif
+
+#ifndef XMP_DebugBuild
+ #define XMP_DebugBuild 0
+#endif
+
+#if XMP_DebugBuild
+ #include <stdio.h> // The assert macro needs printf.
+#endif
+
+#ifndef DISABLE_SERIALIZED_IMPORT_EXPORT
+ #define DISABLE_SERIALIZED_IMPORT_EXPORT 0
+#endif
+
+#ifndef XMP_64
+ #if _WIN64 || defined(_LP64)
+ #define XMP_64 1
+ #else
+ #define XMP_64 0
+ #endif
+#endif
+
+// =================================================================================================
+// Macintosh Specific Settings
+// ===========================
+#if (XMP_MacBuild)
+ #define XMP_HELPER_DLL_IMPORT __attribute__((visibility("default")))
+ #define XMP_HELPER_DLL_EXPORT __attribute__((visibility("default")))
+ #define XMP_HELPER_DLL_PRIVATE __attribute__((visibility("hidden")))
+#endif
+
+// =================================================================================================
+// Windows Specific Settings
+// =========================
+#if (XMP_WinBuild)
+ #define XMP_HELPER_DLL_IMPORT
+ #define XMP_HELPER_DLL_EXPORT
+ #define XMP_HELPER_DLL_PRIVATE
+#endif
+
+// =================================================================================================
+// UNIX Specific Settings
+// ======================
+#if (XMP_UNIXBuild)
+ #define XMP_HELPER_DLL_IMPORT
+ #define XMP_HELPER_DLL_EXPORT
+ #define XMP_HELPER_DLL_PRIVATE
+#endif
+
+// =================================================================================================
+// IOS Specific Settings
+// ===========================
+#if (XMP_iOSBuild)
+ #include <TargetConditionals.h>
+ #if (TARGET_CPU_ARM)
+ #define XMP_IOS_ARM 1
+ #else
+ #define XMP_IOS_ARM 0
+ #endif
+ #define XMP_HELPER_DLL_IMPORT __attribute__((visibility("default")))
+ #define XMP_HELPER_DLL_EXPORT __attribute__((visibility("default")))
+ #define XMP_HELPER_DLL_PRIVATE __attribute__((visibility("hidden")))
+#endif
+
+// =================================================================================================
+// Banzai Specific Settings
+// ======================
+#if (XMP_Banzai)
+ #define XMP_HELPER_DLL_IMPORT
+ #define XMP_HELPER_DLL_EXPORT
+ #define XMP_HELPER_DLL_PRIVATE
+#endif
+
+
+// =================================================================================================
+
+#if (XMP_DynamicBuild)
+ #define XMP_PUBLIC XMP_HELPER_DLL_EXPORT
+ #define XMP_PRIVATE XMP_HELPER_DLL_PRIVATE
+#elif (XMP_StaticBuild)
+ #define XMP_PUBLIC
+ #define XMP_PRIVATE
+#else
+ #define XMP_PUBLIC XMP_HELPER_DLL_IMPORT
+ #define XMP_PRIVATE XMP_HELPER_DLL_PRIVATE
+#endif
+
+#endif // __XMP_Environment_h__
diff --git a/gpr/source/lib/xmp_core/public/include/XMP_IO.hpp b/gpr/source/lib/xmp_core/public/include/XMP_IO.hpp
new file mode 100644
index 0000000..d485392
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/XMP_IO.hpp
@@ -0,0 +1,171 @@
+#ifndef __XMP_IO_hpp__
+#define __XMP_IO_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2010 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "XMP_Const.h"
+
+// =================================================================================================
+/// \class XMP_IO XMP_IO.hpp
+/// \brief Abstract base class for client-managed I/O with \c TXMPFiles.
+///
+/// \c XMP_IO is an abstract base class for client-managed I/O with \c TXMPFiles. This allows a
+/// client to use the embedded metadata processing logic of \c TXMPFiles in cases where a string
+/// file path cannot be provided, or where it is impractical to allow \c TXMPFiles to separately
+/// open the file and do its own I/O. Although described in terms of files, any form of storage may
+/// be used as long as the functions operate as defined.
+///
+/// This is not a general purpose I/O class. It contains only the necessary functions needed by the
+/// internals of \c TXMPFiles. It is intended to be used as an adaptor for an existing I/O mechanism
+/// that the client wants \c TXMPFiles to use.
+///
+/// To use \c XMP_IO, a client creates a derived class then uses the form of \c TCMPFiles::OpenFile
+/// that takes an \c XMP_IO parameter instead of a string file path. The derived \c XMP_IO object
+/// must be ready for use when \c TCMPFiles::OpenFile is called.
+///
+/// There are no Open or Close functions in \c XMP_IO, they are specific to each implementation. The
+/// derived \c XMP_IO object must be open and ready for use before being passed to \c
+/// TXMP_Files::OpenFile, and remain open and ready for use until \c TXMP_Files::CloseFile returns,
+/// or some other fatal error occurs. The client has final responsibility for closing and
+/// terminating the derived \c XMP_IO object.
+// =================================================================================================
+
+class XMP_IO {
+public:
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Read into a buffer, returning the number of bytes read.
+ ///
+ /// Read into a buffer, returning the number of bytes read. Returns the actual number of bytes
+ /// read. Throws an exception if requireSuccess is true and not enough data is available.
+ /// Throwing \c XMPError is recommended. The buffer content and I/O position after a throw are
+ /// undefined.
+ ///
+ /// @param buffer A pointer to the buffer.
+ /// @param count The length of the buffer in bytes.
+ /// @param readAll True if reading less than the requested amount is a failure.
+ ///
+ /// @return Returns the number of bytes read.
+
+ enum { kReadAll = true };
+
+ virtual XMP_Uns32 Read ( void* buffer, XMP_Uns32 count, bool readAll = false ) = 0;
+
+ inline XMP_Uns32 ReadAll ( void* buffer, XMP_Uns32 bytes )
+ { return this->Read ( buffer, bytes, kReadAll ); };
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Write from a buffer.
+ ///
+ /// Write from a buffer, overwriting existing data and extending the file as necesary. All data
+ /// must be written or an exception thrown. Throwing \c XMPError is recommended.
+ ///
+ /// @param buffer A pointer to the buffer.
+ /// @param count The length of the buffer in bytes.
+
+ virtual void Write ( const void* buffer, XMP_Uns32 count ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Set the I/O position, returning the new absolute offset in bytes.
+ ///
+ /// Set the I/O position, returning the new absolute offset in bytes. The offset parameter may
+ /// be positive or negative. A seek beyond EOF is allowed when writing and extends the file, it
+ /// is equivalent to seeking to EOF then writing the needed amount of undefined data. A
+ /// read-only seek beyond EOF throws an exception. Throwing \c XMPError is recommended.
+ ///
+ /// @param offset The offset relative to the mode.
+ /// @param mode The mode, or origin, of the seek.
+ ///
+ /// @return The new absolute offset in bytes.
+
+ virtual XMP_Int64 Seek ( XMP_Int64 offset, SeekMode mode ) = 0;
+
+ inline XMP_Int64 Offset() { return this->Seek ( 0, kXMP_SeekFromCurrent ); };
+ inline XMP_Int64 Rewind() { return this->Seek ( 0, kXMP_SeekFromStart ); }; // Always returns 0.
+ inline XMP_Int64 ToEOF() { return this->Seek ( 0, kXMP_SeekFromEnd ); };
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Return the length of the file in bytes.
+ ///
+ /// Return the length of the file in bytes. The I/O position is unchanged.
+ ///
+ /// @return The length of the file in bytes.
+
+ virtual XMP_Int64 Length() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Truncate the file to the given length.
+ ///
+ /// Truncate the file to the given length. The I/O position after truncation is unchanged if
+ /// still valid, otherwise it is set to the new EOF. Throws an exception if the new length is
+ /// longer than the file's current length. Throwing \c XMPError is recommended.
+ ///
+ /// @param length The new length for the file, must be less than or equal to the current length.
+
+ virtual void Truncate ( XMP_Int64 length ) = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Create an associated temp file for use in a safe-save style operation.
+ ///
+ /// Create an associated temp file, for example in the same directory and with a related name.
+ /// Returns an already existing temp with no other action. The temp must be opened for
+ /// read-write access. It will be used in a safe-save style operation, using some of the
+ /// original file plus new portions to write the temp, then replacing the original from the temp
+ /// when done. Throws an exception if the owning object is opened for read-only access, or if
+ /// the temp file cannot be created. Throwing \c XMPError is recommended.
+ ///
+ /// The temp file is normally closed and deleted, and the temporary \c XMP_IO object deleted, by
+ /// a call to \c AbsorbTemp or \c DeleteTemp. It must be closed and deleted by the derived \c
+ /// XMP_IO object's destructor if necessary.
+ ///
+ /// \c DeriveTemp may be called on a temporary \c XMP_IO object.
+ ///
+ /// @return A pointer to the associated temporary \c XMP_IO object.
+
+ virtual XMP_IO* DeriveTemp() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Replace the owning file's content with that of the temp.
+ ///
+ /// Used at the end of a safe-save style operation to replace the original content with that
+ /// from the associated temp file. The temp file must be closed and deleted after the content
+ /// swap. The temporary \c XMP_IO object is deleted. Throws an exception if the temp file cannot
+ /// be absorbed. Throwing \c XMPError is recommended.
+
+ virtual void AbsorbTemp() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+ /// @brief Delete a temp file, leaving the original alone.
+ ///
+ /// Used for a failed safe-save style operation. The temp file is closed and deleted without
+ /// being absorbed, and the temporary \c XMP_IO object is deleted. Does nothing if no temp
+ /// exists.
+
+ virtual void DeleteTemp() = 0;
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMP_IO() {};
+ virtual ~XMP_IO() {};
+
+private:
+
+ // ---------------------------------------------------------------------------------------------
+ /// Copy construction and assignment are not public. That would require the implementation to
+ /// share state across multiple XMP_IO objects.
+
+ XMP_IO ( const XMP_IO & original );
+ void operator= ( const XMP_IO& in ) { *this = in; /* Avoid Win compile warnings. */ };
+
+};
+
+#endif // __XMP_IO_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/XMP_Version.h b/gpr/source/lib/xmp_core/public/include/XMP_Version.h
new file mode 100644
index 0000000..53707b1
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/XMP_Version.h
@@ -0,0 +1,52 @@
+#ifndef __XMP_Version_h__
+#define __XMP_Version_h__ 1
+
+/* --------------------------------------------------------------------------------------------- */
+/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */
+/* --------------------------------------------------------------------------------------------- */
+
+/*
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+*/
+
+/* ============================================================================================= */
+/**
+XMP Toolkit Version Information
+
+Version information for the XMP toolkit is stored in the executable and available through a runtime
+call, <tt>SXMPMeta::GetVersionInfo</tt>. In addition a static version number is defined in this
+header. The information in the executable or returned by <tt>SXMPMeta::GetVersionInfo</tt> is about
+the implementation internals, it is runtime version information. The values defined in this header
+describe the version of the API used at client compile time. They do not necessarily relate to the
+runtime version.
+
+Important: Do not display the static values defined here to users as the version of XMP in use. Do
+not base runtime decisions on just this static version. It is OK to compare the static and runtime
+versions.
+
+*/
+/* ============================================================================================= */
+
+#define XMPCORE_API_VERSION_MAJOR 5
+#define XMPCORE_API_VERSION_MINOR 5
+#define XMPCORE_API_VERSION_MICRO 0
+
+#define XMPCORE_API_VERSION 5.5.0
+#define XMPCORE_API_VERSION_STRING "5.5.0"
+
+#define XMPFILES_API_VERSION_MAJOR 5
+#define XMPFILES_API_VERSION_MINOR 6
+#define XMPFILES_API_VERSION_MICRO 0
+
+#define XMPFILES_API_VERSION 5.6.0
+#define XMPFILES_API_VERSION_STRING "5.6.0"
+
+/* ============================================================================================= */
+
+#endif /* __XMP_Version_h__ */
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/TXMPFiles.incl_cpp b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPFiles.incl_cpp
new file mode 100644
index 0000000..eb19887
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPFiles.incl_cpp
@@ -0,0 +1,484 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPFiles.incl_cpp
+/// \brief The implementation of the TXMPFiles template class.
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4003 ) // not enough actual parameters for macro
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+#include "client-glue/WXMP_Common.hpp"
+
+#include "client-glue/WXMPFiles.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. The jobs done in this code are:
+//
+// 1. ...
+//
+// =================================================================================================
+
+#ifndef XMPFiles_TraceCTorDTor
+ #define XMPFiles_TraceCTorDTor 0
+#endif
+
+#if XMPFiles_TraceCTorDTor
+ class XFPeek { // Hack to peek at the client ref count in the internal object.
+ public:
+ XFPeek();
+ virtual ~XFPeek();
+ XMP_Int32 clientRefs;
+ };
+#endif
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen )
+{
+ tStringObj * clientStr = (tStringObj*) clientPtr;
+ clientStr->assign ( valuePtr, valueLen );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetClientStringVector ( void * clientPtr, XMP_StringPtr * arrayPtr, XMP_Uns32 stringCount )
+{
+ std::vector<tStringObj>* clientVec = (std::vector<tStringObj>*) clientPtr;
+ clientVec->clear();
+ for ( XMP_Uns32 i = 0; i < stringCount; ++i ) {
+ tStringObj nextValue ( arrayPtr[i] );
+ clientVec->push_back ( nextValue );
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+GetVersionInfo ( XMP_VersionInfo * versionInfo )
+{
+ WrapNoCheckVoid ( zXMPFiles_GetVersionInfo_1 ( versionInfo ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+Initialize()
+{
+ WrapCheckBool ( ok, zXMPFiles_Initialize_1 ( 0 ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+Initialize( const char* pluginFolder, const char* plugins )
+{
+ WrapCheckBool ( ok, zXMPFiles_Initialize_2 ( 0, pluginFolder, plugins ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+Initialize ( XMP_OptionBits options )
+{
+ WrapCheckBool ( ok, zXMPFiles_Initialize_1 ( options ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+Initialize ( XMP_OptionBits options, const char* pluginFolder, const char* plugins )
+{
+ WrapCheckBool ( ok, zXMPFiles_Initialize_2 ( options, pluginFolder, plugins ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+Terminate()
+{
+ WrapNoCheckVoid ( zXMPFiles_Terminate_1() );
+}
+
+// =================================================================================================
+
+static XMPFilesRef Default_CTor()
+{
+ WrapCheckXMPFilesRef ( newRef, zXMPFiles_CTor_1() );
+ return newRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles() : xmpFilesRef(Default_CTor())
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Default construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( const TXMPFiles<tStringObj> & original ) : xmpFilesRef(original.xmpFilesRef)
+{
+ WXMPFiles_IncrementRefCount_1 ( this->xmpFilesRef );
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Copy construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+operator= ( const TXMPFiles<tStringObj> & rhs )
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfLHS = (XFPeek*)this->xmpFilesRef;
+ XFPeek* xfRHS = (XFPeek*)rhs.xmpFilesRef;
+ printf ( "Assign TXMPFiles, lhs @ %.8X, rhs @ %.8X\n", this, &rhs );
+ printf ( " original lhs ref = %.8X, count = %d\n", xfLHS, xfLHS->clientRefs );
+ printf ( " original rhs ref = %.8X, count = %d\n", xfRHS, xfRHS->clientRefs );
+ #endif
+ XMPFilesRef oldRef = this->xmpFilesRef; // ! Decrement last so errors leave client object OK.
+ this->xmpFilesRef = rhs.xmpFilesRef;
+ WXMPFiles_IncrementRefCount_1 ( this->xmpFilesRef ); // Increment the count on the new ref.
+ WXMPFiles_DecrementRefCount_1 ( oldRef ); // Decrement the count on the old ref.
+ #if XMPFiles_TraceCTorDTor
+ printf ( " result lhs ref = %.8X, count = %d\n", xfLHS, xfLHS->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( XMPFilesRef _xmpFilesRef ) : xmpFilesRef(_xmpFilesRef)
+{
+ WXMPFiles_IncrementRefCount_1 ( this->xmpFilesRef );
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Ref construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( XMP_StringPtr filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ ) : xmpFilesRef(Default_CTor())
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "File construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+ bool ok = this->OpenFile ( filePath, format, openFlags );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_NoFileHandler, "OpenFile returned false" );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+TXMPFiles ( const tStringObj & filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ ) : xmpFilesRef(Default_CTor())
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "File construct TXMPFiles @ %.8X, ref = %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+ bool ok = this->OpenFile ( filePath.c_str(), format, openFlags );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_NoFileHandler, "OpenFile returned false" );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPFiles)::
+~TXMPFiles () throw()
+{
+ #if XMPFiles_TraceCTorDTor
+ XFPeek* xfPtr = (XFPeek*)this->xmpFilesRef;
+ printf ( "Destruct TXMPFiles @ %.8X, ref= %.8X, count = %d\n", this, xfPtr, xfPtr->clientRefs );
+ #endif
+ WXMPFiles_DecrementRefCount_1 ( this->xmpFilesRef );
+ this->xmpFilesRef = 0;
+}
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetFormatInfo ( XMP_FileFormat format,
+ XMP_OptionBits * flags )
+{
+ WrapCheckBool ( found, zXMPFiles_GetFormatInfo_1 ( format, flags ) );
+ return found;
+}
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,XMPFilesRef)::
+GetInternalRef()
+{
+ return this->xmpFilesRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,XMP_FileFormat)::
+CheckFileFormat ( XMP_StringPtr filePath )
+{
+ WrapCheckFormat ( format, zXMPFiles_CheckFileFormat_1 ( filePath ) );
+ return format;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,XMP_FileFormat)::
+CheckPackageFormat ( XMP_StringPtr folderPath )
+{
+ WrapCheckFormat ( format, zXMPFiles_CheckPackageFormat_1 ( folderPath ) );
+ return format;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetFileModDate ( XMP_StringPtr filePath, XMP_DateTime * modDate, XMP_FileFormat * format, XMP_OptionBits options )
+{
+ WrapCheckBool ( ok, zXMPFiles_GetFileModDate_1 ( filePath, modDate, format, options ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetAssociatedResources ( XMP_StringPtr filePath,
+ std::vector<tStringObj>* resourceList,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits options /* = 0 */)
+{
+ WrapCheckBool ( ok, zXMPFiles_GetAssociatedResources_1 ( filePath, resourceList, format, options, SetClientStringVector ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+IsMetadataWritable ( XMP_StringPtr filePath,
+ bool * writable,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits options /* = 0 */)
+{
+ if ( writable)
+ {
+ XMP_Bool internalWritable = ConvertBoolToXMP_Bool( *writable );
+ WrapCheckBool ( ok, zXMPFiles_IsMetadataWritable_1 ( filePath, &internalWritable, format, options ) );
+ *writable = ConvertXMP_BoolToBool( internalWritable );
+ return ok;
+ }
+ else
+ {
+ WrapCheckBool ( ok, zXMPFiles_IsMetadataWritable_1 ( filePath, NULL, format, options ) );
+ return ok;
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+OpenFile ( XMP_StringPtr filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ )
+{
+ WrapCheckBool ( ok, zXMPFiles_OpenFile_1 ( filePath, format, openFlags ) );
+ return ok;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+OpenFile ( const tStringObj & filePath,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ )
+{
+ return this->OpenFile ( filePath.c_str(), format, openFlags );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+#if XMP_StaticBuild // ! Client XMP_IO objects can only be used in static builds.
+XMP_MethodIntro(TXMPFiles,bool)::
+OpenFile ( XMP_IO * clientIO,
+ XMP_FileFormat format /* = kXMP_UnknownFile */,
+ XMP_OptionBits openFlags /* = 0 */ )
+{
+ WrapCheckBool ( ok, zXMPFiles_OpenFile_2 ( clientIO, format, openFlags ) );
+ return ok;
+}
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPFiles_CloseFile_1 ( closeFlags ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetFileInfo ( tStringObj * filePath /* = 0 */,
+ XMP_OptionBits * openFlags /* = 0 */,
+ XMP_FileFormat * format /* = 0 */,
+ XMP_OptionBits * handlerFlags /* = 0 */ )
+{
+ WrapCheckBool ( isOpen, zXMPFiles_GetFileInfo_1 ( filePath, openFlags, format, handlerFlags, SetClientString ) );
+ return isOpen;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetAbortProc ( XMP_AbortProc abortProc,
+ void * abortArg )
+{
+ WrapCheckVoid ( zXMPFiles_SetAbortProc_1 ( abortProc, abortArg ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+GetXMP ( SXMPMeta * xmpObj /* = 0 */,
+ tStringObj * xmpPacket /* = 0 */,
+ XMP_PacketInfo * packetInfo /* = 0 */ )
+{
+ XMPMetaRef xmpRef = 0;
+ if ( xmpObj != 0 ) {
+ SXMPUtils::RemoveProperties ( xmpObj, 0, 0, kXMPUtil_DoAllProperties ); // *** Need an SXMPMeta::Clear method:
+ xmpRef = xmpObj->GetInternalRef();
+ }
+
+ WrapCheckBool ( hasXMP, zXMPFiles_GetXMP_1 ( xmpRef, xmpPacket, packetInfo, SetClientString ) );
+ return hasXMP;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+PutXMP ( const SXMPMeta & xmpObj )
+{
+ WrapCheckVoid ( zXMPFiles_PutXMP_1 ( xmpObj.GetInternalRef(), 0, 0 ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+PutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength /* = kXMP_UseNullTermination */ )
+{
+ WrapCheckVoid ( zXMPFiles_PutXMP_1 ( 0, xmpPacket, xmpLength ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+PutXMP ( const tStringObj & xmpPacket )
+{
+ this->PutXMP ( xmpPacket.c_str(), (XMP_StringLen)xmpPacket.size() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+CanPutXMP ( const SXMPMeta & xmpObj )
+{
+ WrapCheckBool ( canPut, zXMPFiles_CanPutXMP_1 ( xmpObj.GetInternalRef(), 0, 0 ) );
+ return canPut;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+CanPutXMP ( XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpLength /* = kXMP_UseNullTermination */ )
+{
+ WrapCheckBool ( canPut, zXMPFiles_CanPutXMP_1 ( 0, xmpPacket, xmpLength ) );
+ return canPut;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,bool)::
+CanPutXMP ( const tStringObj & xmpPacket )
+{
+ return this->CanPutXMP ( xmpPacket.c_str(), (XMP_StringLen)xmpPacket.size() );
+}
+
+// =================================================================================================
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetDefaultProgressCallback ( XMP_ProgressReportProc proc, void * context /* = 0 */,
+ float interval /* = 1.0 */, bool sendStartStop /* = false */ )
+{
+ XMP_Bool internalsendStartStop = ConvertBoolToXMP_Bool( sendStartStop );
+ WrapCheckVoid ( zXMPFiles_SetDefaultProgressCallback_1 ( proc, context, interval, internalsendStartStop ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetProgressCallback ( XMP_ProgressReportProc proc, void * context /* = 0 */,
+ float interval /* = 1.0 */, bool sendStartStop /* = false */ )
+{
+ XMP_Bool internalsendStartStop = ConvertBoolToXMP_Bool( sendStartStop );
+ WrapCheckVoid ( zXMPFiles_SetProgressCallback_1 ( proc, context, interval, internalsendStartStop ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetDefaultErrorCallback ( XMPFiles_ErrorCallbackProc proc,
+ void * context /* = 0 */, XMP_Uns32 limit /*= 1 */ )
+{
+ WrapCheckVoid ( zXMPFiles_SetDefaultErrorCallback_1 ( proc, context, limit ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+SetErrorCallback ( XMPFiles_ErrorCallbackProc proc,
+ void * context /* = 0 */, XMP_Uns32 limit /*= 1 */ )
+{
+ WrapCheckVoid ( zXMPFiles_SetErrorCallback_1 ( proc, context, limit ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPFiles,void)::
+ResetErrorCallbackLimit ( XMP_Uns32 limit /* = 1 */ )
+{
+ WrapCheckVoid ( zXMPFiles_ResetErrorCallbackLimit_1 ( limit ) );
+}
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/TXMPIterator.incl_cpp b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPIterator.incl_cpp
new file mode 100644
index 0000000..0b39d01
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPIterator.incl_cpp
@@ -0,0 +1,223 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPIterator.incl_cpp
+/// \brief The implementation of the TXMPIterator template class.
+
+#include "XMP.hpp"
+#include "client-glue/WXMP_Common.hpp"
+#include "client-glue/WXMPIterator.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. The jobs done in this code are:
+//
+// 1. Set up the xmpIter template data member in the constructors.
+// 2. Call through to the appropriate WXMPIterator function.
+// 3. Copy returned strings and release the threading lock.
+//
+// The various kinds of functions follow similar patterns, first assuming no returned string:
+//
+// Constructors - Use an initializer for the xmpIter data member to call the WXMPIterator constructor.
+// Destructor - Let the WXMPIterator destructor be implicitly called for the xmpIter data member.
+// Static function - Simply call the corresponding WXMPIterator static function.
+// Non-static function - Simply call the corresponding WXMPIterator function using xmpIter.
+//
+// If a member function has returned strings the code looks roughly like this:
+//
+// <<<callthrough>>>
+// <<<checkfailure>>>
+// if ( <<<appropriate>>> ) {
+// if ( outStr != 0 ) outStr->assign ( outPtr, outLen );
+// <<<unlock>>>
+// }
+// return result;
+//
+// The <<<callthrough>>> is the call to the wrapper, and <<<checkfailure>>> is the check and throw
+// if the wrapper reports failure. The <<<appropriate>>> check is used to determine if the string
+// should actually be assigned. For example, GetProperty can't assign the value if the property
+// does not exist. There is no <<<appropriate>>> check if it isn't, well, appropriate. Outputs are
+// always passed as explicit pointers, and null can be passed if the string is not wanted. The
+// inner implementation holds the threading lock if an output string is returned, regardless of
+// whether the client wants it or not (which the implementation does not know).
+//
+// =================================================================================================
+
+#ifndef XMP_TraceCTorDTor
+ #define XMP_TraceCTorDTor 0
+#endif
+
+#if XMP_TraceCTorDTor
+ class XIPeek { // Hack to peek at the client ref count in the internal object.
+ public:
+ XIPeek();
+ virtual ~XIPeek();
+ XMP_Int32 clientRefs;
+ };
+#endif
+
+// -------------------------------------------------------------------------------------------------
+
+#define PropIterCTor(xmpRef,schemaNS,propName,options) \
+ WrapCheckIterRef ( newRef, zXMPIterator_PropCTor_1 ( xmpRef, schemaNS, propName, options ) ); \
+ this->iterRef = newRef
+
+// -------------------------------------------------------------------------------------------------
+
+#define TableIterCTor(schemaNS,propName,options) \
+ WrapCheckIterRef ( newRef, zXMPIterator_TableCTor_1 ( schemaNS, propName, options ) ); \
+ this->iterRef = newRef
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,void)::
+SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen )
+{
+ tStringObj * clientStr = (tStringObj*) clientPtr;
+ clientStr->assign ( valuePtr, valueLen );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPIterator<tStringObj> & original ) : iterRef(original.iterRef)
+{
+ WXMPIterator_IncrementRefCount_1 ( this->iterRef );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Copy construct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,void)::
+operator= ( const TXMPIterator<tStringObj> & rhs )
+{
+ #if XMP_TraceCTorDTor
+ XIPeek* xiLHS = (XIPeek*)this->iterRef;
+ XIPeek* xiRHS = (XIPeek*)rhs.iterRef;
+ printf ( "Assign TXMPIterator, lhs @ %.8X, rhs @ %.8X\n", this, &rhs );
+ printf ( " original lhs ref = %.8X, count = %d\n", xiLHS, xiLHS->clientRefs );
+ printf ( " original rhs ref = %.8X, count = %d\n", xiRHS, xiRHS->clientRefs );
+ #endif
+ XMPIteratorRef oldRef = this->iterRef; // ! Decrement last so errors leave client object OK.
+ this->iterRef = rhs.iterRef;
+ WXMPIterator_IncrementRefCount_1 ( this->iterRef );
+ WXMPIterator_DecrementRefCount_1 ( oldRef );
+ #if XMP_TraceCTorDTor
+ printf ( " result lhs ref = %.8X, count = %d\n", xiLHS, xiLHS->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator() : iterRef(0)
+{
+ throw XMP_Error ( kXMPErr_Unavailable, "No default construction for XMP iterators" );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Default construct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options /* = 0 */ ) : iterRef(0)
+{
+ PropIterCTor ( xmpObj.GetInternalRef(), schemaNS, propName, options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct property TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_OptionBits options /* = 0 */ ) : iterRef(0)
+{
+ PropIterCTor ( xmpObj.GetInternalRef(), schemaNS, "", options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct schema TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_OptionBits options /* = 0 */ ) : iterRef(0)
+{
+ PropIterCTor ( xmpObj.GetInternalRef(), "", "", options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct tree TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+TXMPIterator ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options ) : iterRef(0)
+{
+ TableIterCTor ( schemaNS, propName, options );
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Construct table TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPIterator)::
+~TXMPIterator () throw()
+{
+ #if XMP_TraceCTorDTor
+ XIPeek* xiPtr = (XIPeek*)this->iterRef;
+ printf ( "Destruct TXMPIterator @ %.8X, ref = %.8X, count = %d\n", this, xiPtr, xiPtr->clientRefs );
+ #endif
+ WXMPIterator_DecrementRefCount_1 ( this->iterRef );
+ this->iterRef = 0;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,bool)::
+Next ( tStringObj * schemaNS /* = 0 */,
+ tStringObj * propPath /* = 0 */,
+ tStringObj * propValue /* = 0 */,
+ XMP_OptionBits * options /* = 0 */ )
+{
+ WrapCheckBool ( found, zXMPIterator_Next_1 ( schemaNS, propPath, propValue, options, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPIterator,void)::
+Skip ( XMP_OptionBits options )
+{
+ WrapCheckVoid ( zXMPIterator_Skip_1 ( options ) );
+}
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/TXMPMeta.incl_cpp b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPMeta.incl_cpp
new file mode 100644
index 0000000..aa5f4b8
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPMeta.incl_cpp
@@ -0,0 +1,914 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPMeta.incl_cpp
+/// \brief The implementation of the TXMPMeta template class.
+
+#include "XMP.hpp"
+
+#include "client-glue/WXMP_Common.hpp"
+
+#include "client-glue/WXMPMeta.hpp"
+
+#if INCLUDE_XMP_NEW_DOM_MODEL
+ #include "XMPCore/XMPCore_Defines.h"
+
+ #if ENABLE_NEW_DOM_MODEL
+ #include "XMPCore/XMPCore_Defines.h"
+ #include "XMPCore/Interfaces/IXMPDOMFactory.h"
+ #endif
+#endif
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. ...
+//
+// =================================================================================================
+
+#ifndef XMP_TraceCTorDTor
+ #define XMP_TraceCTorDTor 0
+#endif
+
+#if XMP_TraceCTorDTor
+ class XMPeek { // Hack to peek at the client ref count in the internal object.
+ public:
+ XMPeek();
+ virtual ~XMPeek();
+ XMP_Int32 clientRefs;
+ };
+#endif
+
+// =================================================================================================
+// Local utilities
+// ===============
+
+class TOPW_Info {
+public:
+ XMP_TextOutputProc clientProc;
+ void * clientRefCon;
+ TOPW_Info ( XMP_TextOutputProc proc, void * refCon ) : clientProc(proc), clientRefCon(refCon) {};
+private:
+ TOPW_Info() {}; // ! Hide default constructor.
+};
+
+static XMP_Status TextOutputProcWrapper ( void * refCon,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize )
+{
+ try { // Don't let client callback exceptions propagate across DLL boundaries.
+ TOPW_Info * info = (TOPW_Info*)refCon;
+ return info->clientProc ( info->clientRefCon, buffer, bufferSize );
+ } catch ( ... ) {
+ return -1;
+ }
+}
+
+// =================================================================================================
+// Initialization and termination
+// ==============================
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen )
+{
+ tStringObj * clientStr = (tStringObj*) clientPtr;
+ clientStr->assign ( valuePtr, valueLen );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+GetVersionInfo ( XMP_VersionInfo * info )
+{
+ WrapNoCheckVoid ( zXMPMeta_GetVersionInfo_1 ( info ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+#if XMP_TraceClientCalls
+ FILE * xmpClientLog = stderr;
+#endif
+
+#ifndef XMP_TypeCheck
+ #if ! XMP_DebugBuild
+ #define XMP_TypeCheck(e,msg) /* nothing */
+ #else
+ #define XMP_TypeCheck(e,msg) if ( ! (e) ) throw XMP_Error ( kXMPErr_AssertFailure, msg );
+ #endif
+#endif
+
+XMP_MethodIntro(TXMPMeta,bool)::
+Initialize()
+{
+ // Verify critical type sizes.
+ XMP_TypeCheck ( (sizeof(XMP_Int8) == 1), "Size wrong for critical type XMP_Int8" );
+ XMP_TypeCheck ( (sizeof(XMP_Int16) == 2), "Size wrong for critical type XMP_Int16" );
+ XMP_TypeCheck ( (sizeof(XMP_Int32) == 4), "Size wrong for critical type XMP_Int32" );
+ XMP_TypeCheck ( (sizeof(XMP_Int64) == 8), "Size wrong for critical type XMP_Int64" );
+ XMP_TypeCheck ( (sizeof(XMP_Uns8) == 1), "Size wrong for critical type XMP_Uns8" );
+ XMP_TypeCheck ( (sizeof(XMP_Uns16) == 2), "Size wrong for critical type XMP_Uns16" );
+ XMP_TypeCheck ( (sizeof(XMP_Uns32) == 4), "Size wrong for critical type XMP_Uns32" );
+ XMP_TypeCheck ( (sizeof(XMP_Uns64) == 8), "Size wrong for critical type XMP_Uns64" );
+ XMP_TypeCheck ( (sizeof(XMP_Bool) == 1), "Size wrong for critical type XMP_Bool" );
+
+ #if XMP_TraceClientCallsToFile
+ xmpClientLog = fopen ( "XMPClientLog.txt", "w" );
+ if ( xmpClientLog == 0 ) xmpClientLog = stderr;
+ #endif
+
+ WrapCheckBool ( ok, zXMPMeta_Initialize_1() );
+
+ #if ENABLE_NEW_DOM_MODEL
+ NS_XMPCOMMON::IXMPDOMFactory_latest::CreateInstance();
+ #endif
+
+ return ok;
+
+}
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+Terminate()
+{
+ WrapNoCheckVoid ( zXMPMeta_Terminate_1() );
+
+ #if XMP_TraceClientCallsToFile
+ if ( xmpClientLog != stderr ) fclose ( xmpClientLog );
+ xmpClientLog = stderr;
+ #endif
+}
+
+// =================================================================================================
+// Constuctors, destructor, operators
+// ==================================
+
+static XMPMetaRef DefaultCTor()
+{
+ WrapCheckMetaRef ( newRef, zXMPMeta_CTor_1() );
+ return newRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta() : xmpRef(DefaultCTor())
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Default construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta ( const TXMPMeta<tStringObj> & original ) : xmpRef(original.xmpRef)
+{
+ WXMPMeta_IncrementRefCount_1 ( this->xmpRef );
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Copy construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+operator= ( const TXMPMeta<tStringObj> & rhs )
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmLHS = (XMPeek*)this->xmpRef;
+ XMPeek* xmRHS = (XMPeek*)rhs.xmpRef;
+ printf ( "Assign TXMPMeta, lhs @ %.8X, rhs @ %.8X\n", this, &rhs );
+ printf ( " original lhs ref = %.8X, count = %d\n", xmLHS, xmLHS->clientRefs );
+ printf ( " original rhs ref = %.8X, count = %d\n", xmRHS, xmRHS->clientRefs );
+ #endif
+ XMPMetaRef oldRef = this->xmpRef; // ! Decrement last so errors leave client object OK.
+ this->xmpRef = rhs.xmpRef;
+ WXMPMeta_IncrementRefCount_1 ( this->xmpRef ); // Increment the count on the new ref.
+ WXMPMeta_DecrementRefCount_1 ( oldRef ); // Decrement the count on the old ref.
+ #if XMP_TraceCTorDTor
+ printf ( " result lhs ref = %.8X, count = %d\n", xmLHS, xmLHS->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta ( XMPMetaRef _xmpRef ) : xmpRef(_xmpRef)
+{
+ WXMPMeta_IncrementRefCount_1 ( this->xmpRef );
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Ref construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+TXMPMeta ( XMP_StringPtr buffer,
+ XMP_StringLen xmpSize ) : xmpRef(DefaultCTor())
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Parse construct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+ try {
+ this->ParseFromBuffer ( buffer, xmpSize );
+ } catch ( ... ) {
+ WXMPMeta_DecrementRefCount_1 ( this->xmpRef );
+ this->xmpRef = 0;
+ throw;
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_CTorDTorIntro(TXMPMeta)::
+~TXMPMeta() throw()
+{
+ #if XMP_TraceCTorDTor
+ XMPeek* xmPtr = (XMPeek*)this->xmpRef;
+ printf ( "Destruct TXMPMeta @ %.8X, ref = %.8X, count = %d\n", this, xmPtr, xmPtr->clientRefs );
+ #endif
+ WXMPMeta_DecrementRefCount_1 ( this->xmpRef );
+ this->xmpRef = 0;
+
+} // ~TXMPMeta ()
+
+// =================================================================================================
+// Global state functions
+// ======================
+
+XMP_MethodIntro(TXMPMeta,XMP_OptionBits)::
+GetGlobalOptions()
+{
+ WrapCheckOptions ( options, zXMPMeta_GetGlobalOptions_1() );
+ return options;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetGlobalOptions ( XMP_OptionBits options )
+{
+ WrapCheckVoid ( zXMPMeta_SetGlobalOptions_1 ( options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Status)::
+DumpNamespaces ( XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ TOPW_Info info ( outProc, refCon );
+ WrapCheckStatus ( status, zXMPMeta_DumpNamespaces_1 ( TextOutputProcWrapper, &info ) );
+ return status;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ tStringObj * registeredPrefix )
+{
+ WrapCheckBool ( prefixMatch, zXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, registeredPrefix, SetClientString ) );
+ return prefixMatch;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetNamespacePrefix ( XMP_StringPtr namespaceURI,
+ tStringObj * namespacePrefix )
+{
+ WrapCheckBool ( found, zXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetNamespaceURI ( XMP_StringPtr namespacePrefix,
+ tStringObj * namespaceURI )
+{
+ WrapCheckBool ( found, zXMPMeta_GetNamespaceURI_1 ( namespacePrefix, namespaceURI, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteNamespace ( XMP_StringPtr namespaceURI )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteNamespace_1 ( namespaceURI ) );
+}
+
+// =================================================================================================
+// Basic property manipulation functions
+// =====================================
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ tStringObj * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_1 ( schemaNS, propName, propValue, options, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetArrayItem_1 ( schemaNS, arrayName, itemIndex, itemValue, options, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fieldValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetStructField_1 ( schemaNS, structName, fieldNS, fieldName, fieldValue, options, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * qualValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetQualifier_1 ( schemaNS, propName, qualNS, qualName, qualValue, options, SetClientString ) );
+ return found;
+} //GetQualifier ()
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const tStringObj & propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetProperty ( schemaNS, propName, propValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetArrayItem_1 ( schemaNS, arrayName, itemIndex, itemValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ const tStringObj & itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_AppendArrayItem_1 ( schemaNS, arrayName, arrayOptions, itemValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ const tStringObj & itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetStructField_1 ( schemaNS, structName, fieldNS, fieldName, fieldValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetQualifier_1 ( schemaNS, propName, qualNS, qualName, qualValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ const tStringObj & qualValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteProperty_1 ( schemaNS, propName ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteArrayItem_1 ( schemaNS, arrayName, itemIndex ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteStructField_1 ( schemaNS, structName, fieldNS, fieldName ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteQualifier_1 ( schemaNS, propName, qualNS, qualName ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesPropertyExist_1 ( schemaNS, propName ) );
+ return exists;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesArrayItemExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesArrayItemExist_1 ( schemaNS, arrayName, itemIndex ) );
+ return exists;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesStructFieldExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesStructFieldExist_1 ( schemaNS, structName, fieldNS, fieldName ) );
+ return exists;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+DoesQualifierExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName ) const
+{
+ WrapCheckBool ( exists, zXMPMeta_DoesQualifierExist_1 ( schemaNS, propName, qualNS, qualName ) );
+ return exists;
+}
+
+// =================================================================================================
+// Specialized Get and Set functions
+// =================================
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ tStringObj * actualLang,
+ tStringObj * itemValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang,
+ actualLang, itemValue, options, SetClientString ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang, itemValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ const tStringObj & itemValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ this->SetLocalizedText ( schemaNS, altTextName, genericLang, specificLang, itemValue.c_str(), options );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+DeleteLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang )
+{
+ WrapCheckVoid ( zXMPMeta_DeleteLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool * propValue,
+ XMP_OptionBits * options ) const
+{
+ XMP_Bool binValue;
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Bool_1 ( schemaNS, propName, &binValue, options ) );
+ if ( found && (propValue != 0) ) *propValue = binValue;
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Int_1 ( schemaNS, propName, propValue, options ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Int64_1 ( schemaNS, propName, propValue, options ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Float_1 ( schemaNS, propName, propValue, options ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,bool)::
+GetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options ) const
+{
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Date_1 ( schemaNS, propName, propValue, options ) );
+ return found;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Bool ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ bool propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Bool_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Int ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Int_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Int64 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Int64_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Float ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Float_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetProperty_Date ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetProperty_Date_1 ( schemaNS, propName, propValue, options ) );
+}
+
+// =================================================================================================
+// Miscellaneous Member Functions
+// ==============================
+
+XMP_MethodIntro(TXMPMeta,XMPMetaRef)::
+GetInternalRef() const
+{
+ return this->xmpRef;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+GetObjectName ( tStringObj * nameStr ) const
+{
+ WrapCheckVoid ( zXMPMeta_GetObjectName_1 ( nameStr, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetObjectName ( XMP_StringPtr name )
+{
+ WrapCheckVoid ( zXMPMeta_SetObjectName_1 ( name ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetObjectName ( tStringObj name )
+{
+ this->SetObjectName ( name.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_OptionBits)::
+GetObjectOptions() const
+{
+ WrapCheckOptions ( options, zXMPMeta_GetObjectOptions_1() );
+ return options;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetObjectOptions ( XMP_OptionBits options )
+{
+ WrapCheckVoid ( zXMPMeta_SetObjectOptions_1 ( options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+Sort()
+{
+ WrapCheckVoid ( zXMPMeta_Sort_1() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+Erase()
+{
+ WrapCheckVoid ( zXMPMeta_Erase_1() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,TXMPMeta<tStringObj>)::
+Clone ( XMP_OptionBits options ) const
+{
+ WrapCheckMetaRef ( cloneRef, zXMPMeta_Clone_1 ( options ) );
+ return TXMPMeta<tStringObj> ( cloneRef ); // Ref construct will increment the clientRefs.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Index)::
+CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const
+{
+ WrapCheckIndex ( count, zXMPMeta_CountArrayItems_1 ( schemaNS, arrayName ) );
+ return count;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,XMP_Status)::
+DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const
+{
+ TOPW_Info info ( outProc, refCon );
+ WrapCheckStatus ( status, zXMPMeta_DumpObject_1 ( TextOutputProcWrapper, &info ) );
+ return status;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options /* = 0 */ )
+{
+ WrapCheckVoid ( zXMPMeta_ParseFromBuffer_1 ( buffer, bufferSize, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SerializeToBuffer ( tStringObj * pktString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent /* = 0 */ ) const
+{
+ WrapCheckVoid ( zXMPMeta_SerializeToBuffer_1 ( pktString, options, padding, newline, indent, baseIndent, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SerializeToBuffer ( tStringObj * pktString,
+ XMP_OptionBits options /* = 0 */,
+ XMP_StringLen padding /* = 0 */ ) const
+{
+ this->SerializeToBuffer ( pktString, options, padding, "", "", 0 );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetDefaultErrorCallback ( XMPMeta_ErrorCallbackProc proc,
+ void * context /* = 0 */,
+ XMP_Uns32 limit /* = 1 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetDefaultErrorCallback_1 ( proc, context, limit ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+SetErrorCallback ( XMPMeta_ErrorCallbackProc proc,
+ void * context /* = 0 */,
+ XMP_Uns32 limit /* = 1 */ )
+{
+ WrapCheckVoid ( zXMPMeta_SetErrorCallback_1 ( proc, context, limit ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPMeta,void)::
+ResetErrorCallbackLimit ( XMP_Uns32 limit /* = 1 */ )
+{
+ WrapCheckVoid ( zXMPMeta_ResetErrorCallbackLimit_1 ( limit ) );
+}
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/TXMPUtils.incl_cpp b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPUtils.incl_cpp
new file mode 100644
index 0000000..2cd5bae
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/TXMPUtils.incl_cpp
@@ -0,0 +1,445 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+// ================================================================================================
+/// \file TXMPUtils.incl_cpp
+/// \brief The implementation of the TXMPUtils template class.
+
+#include "XMP.hpp"
+#include "client-glue/WXMP_Common.hpp"
+#include "client-glue/WXMPUtils.hpp"
+
+// =================================================================================================
+// Implementation Guidelines
+// =========================
+//
+// The implementations of the template functions are very stylized. ...
+//
+// =================================================================================================
+
+XMP_MethodIntro(TXMPUtils,void)::
+SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen )
+{
+ tStringObj * clientStr = (tStringObj*) clientPtr;
+ clientStr->assign ( valuePtr, valueLen );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeArrayItemPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ tStringObj * fullPath )
+{
+ WrapCheckVoid ( zXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, fullPath, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeStructFieldPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ tStringObj * fullPath )
+{
+ WrapCheckVoid ( zXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, fullPath, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeQualifierPath ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ tStringObj * fullPath )
+{
+ WrapCheckVoid ( zXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, fullPath, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ tStringObj * fullPath )
+{
+ WrapCheckVoid ( zXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, fullPath, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeLangSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ const tStringObj & langName,
+ tStringObj * fullPath )
+{
+ TXMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName.c_str(), fullPath );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ tStringObj * fullPath )
+{
+ WrapCheckVoid ( zXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ComposeFieldSelector ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ const tStringObj & fieldValue,
+ tStringObj * fullPath )
+{
+ TXMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue.c_str(), fullPath );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromBool ( bool binValue,
+ tStringObj * strValue )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertFromBool_1 ( binValue, strValue, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromInt ( long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue )
+{
+ #if XMP_MacBuild & XMP_64 // This is checked because on Mac 64 bit environment, long is of 64 bit and hence gives a warning during implicit
+ // typecasting to XMP_Int32. Now doing it explicitly in that case.
+ WrapCheckVoid ( zXMPUtils_ConvertFromInt_1 ( (XMP_Int32)binValue, format, strValue, SetClientString ) );
+ #else
+ WrapCheckVoid ( zXMPUtils_ConvertFromInt_1 ( binValue, format, strValue, SetClientString ) );
+ #endif
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromInt64 ( long long binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromFloat ( double binValue,
+ XMP_StringPtr format,
+ tStringObj * strValue )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertFromDate ( const XMP_DateTime & binValue,
+ tStringObj * strValue )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertFromDate_1 ( binValue, strValue, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,bool)::
+ConvertToBool ( XMP_StringPtr strValue )
+{
+ WrapCheckBool ( value, zXMPUtils_ConvertToBool_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,bool)::
+ConvertToBool ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToBool ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long)::
+ConvertToInt ( XMP_StringPtr strValue )
+{
+ WrapCheckInt32 ( value, zXMPUtils_ConvertToInt_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long)::
+ConvertToInt ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToInt ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long long)::
+ConvertToInt64 ( XMP_StringPtr strValue )
+{
+ WrapCheckInt64 ( value, zXMPUtils_ConvertToInt64_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,long long)::
+ConvertToInt64 ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToInt64 ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,double)::
+ConvertToFloat ( XMP_StringPtr strValue )
+{
+ WrapCheckFloat ( value, zXMPUtils_ConvertToFloat_1 ( strValue ) );
+ return value;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,double)::
+ConvertToFloat ( const tStringObj & strValue )
+{
+ return TXMPUtils::ConvertToFloat ( strValue.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToDate ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertToDate_1 ( strValue, binValue ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToDate ( const tStringObj & strValue,
+ XMP_DateTime * binValue )
+{
+ TXMPUtils::ConvertToDate ( strValue.c_str(), binValue );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+CurrentDateTime ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_CurrentDateTime_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+SetTimeZone ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_SetTimeZone_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToUTCTime ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertToUTCTime_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ConvertToLocalTime ( XMP_DateTime * time )
+{
+ WrapCheckVoid ( zXMPUtils_ConvertToLocalTime_1 ( time ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,int)::
+CompareDateTime ( const XMP_DateTime & left,
+ const XMP_DateTime & right )
+{
+ WrapCheckInt32 ( result, zXMPUtils_CompareDateTime_1 ( left, right ) );
+ return result;
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+EncodeToBase64 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ tStringObj * encodedStr )
+{
+ WrapCheckVoid ( zXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, encodedStr, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+EncodeToBase64 ( const tStringObj & rawStr,
+ tStringObj * encodedStr )
+{
+ TXMPUtils::EncodeToBase64 ( rawStr.c_str(), (XMP_StringLen)rawStr.size(), encodedStr );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+DecodeFromBase64 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ tStringObj * rawStr )
+{
+ WrapCheckVoid ( zXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, rawStr, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+DecodeFromBase64 ( const tStringObj & encodedStr,
+ tStringObj * rawStr )
+{
+ TXMPUtils::DecodeFromBase64 ( encodedStr.c_str(), (XMP_StringLen)encodedStr.size(), rawStr );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+PackageForJPEG ( const TXMPMeta<tStringObj> & xmpObj,
+ tStringObj * standardXMP,
+ tStringObj * extendedXMP,
+ tStringObj * extendedDigest )
+{
+ WrapCheckVoid ( zXMPUtils_PackageForJPEG_1 ( xmpObj.GetInternalRef(), standardXMP, extendedXMP, extendedDigest, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+MergeFromJPEG ( TXMPMeta<tStringObj> * fullXMP,
+ const TXMPMeta<tStringObj> & extendedXMP )
+{
+ WrapCheckVoid ( zXMPUtils_MergeFromJPEG_1 ( fullXMP->GetInternalRef(), extendedXMP.GetInternalRef() ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+CatenateArrayItems ( const TXMPMeta<tStringObj> & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ tStringObj * catedStr )
+{
+ WrapCheckVoid ( zXMPUtils_CatenateArrayItems_1 ( xmpObj.GetInternalRef(), schemaNS, arrayName,
+ separator, quotes, options, catedStr, SetClientString ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr )
+{
+ if ( xmpObj == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_SeparateArrayItems_1 ( xmpObj->GetInternalRef(), schemaNS, arrayName, options, catedStr ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+SeparateArrayItems ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ const tStringObj & catedStr )
+{
+ TXMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr.c_str() );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+ApplyTemplate ( TXMPMeta<tStringObj> * workingXMP,
+ const TXMPMeta<tStringObj> & templateXMP,
+ XMP_OptionBits actions )
+{
+ if ( workingXMP == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null working SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_ApplyTemplate_1 ( workingXMP->GetInternalRef(), templateXMP.GetInternalRef(), actions ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+RemoveProperties ( TXMPMeta<tStringObj> * xmpObj,
+ XMP_StringPtr schemaNS /* = 0 */,
+ XMP_StringPtr propName /* = 0 */,
+ XMP_OptionBits options /* = 0 */ )
+{
+ if ( xmpObj == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_RemoveProperties_1 ( xmpObj->GetInternalRef(), schemaNS, propName, options ) );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------------
+
+XMP_MethodIntro(TXMPUtils,void)::
+DuplicateSubtree ( const TXMPMeta<tStringObj> & source,
+ TXMPMeta<tStringObj> * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS /*= 0 */,
+ XMP_StringPtr destRoot /* = 0 */,
+ XMP_OptionBits options /* = 0 */ )
+{
+ if ( dest == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
+ WrapCheckVoid ( zXMPUtils_DuplicateSubtree_1 ( source.GetInternalRef(), dest->GetInternalRef(),
+ sourceNS, sourceRoot, destNS, destRoot, options ) );
+}
+
+// =================================================================================================
+
+// =================================================================================================
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/WXMPFiles.hpp b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPFiles.hpp
new file mode 100644
index 0000000..648a842
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPFiles.hpp
@@ -0,0 +1,281 @@
+#ifndef __WXMPFiles_hpp__
+#define __WXMPFiles_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if XMP_StaticBuild // ! Client XMP_IO objects can only be used in static builds.
+ #include "XMP_IO.hpp"
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+/// \file WXMPFiles.h
+/// \brief High level support to access metadata in files of interest to Adobe applications.
+///
+/// This header ...
+///
+// =================================================================================================
+
+// =================================================================================================
+
+#define WrapCheckXMPFilesRef(result,WCallProto) \
+ WXMP_Result wResult; \
+ WCallProto; \
+ PropagateException ( wResult ); \
+ XMPFilesRef result = XMPFilesRef(wResult.ptrResult)
+
+static XMP_Bool WrapProgressReport ( XMP_ProgressReportProc proc, void * context,
+ float elapsedTime, float fractionDone, float secondsToGo )
+{
+ bool ok;
+ try {
+ ok = (*proc) ( context, elapsedTime, fractionDone, secondsToGo );
+ } catch ( ... ) {
+ ok = false;
+ }
+ return ConvertBoolToXMP_Bool( ok );
+}
+
+// =================================================================================================
+
+static XMP_Bool WrapFilesErrorNotify ( XMPFiles_ErrorCallbackProc proc, void * context,
+ XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr message )
+{
+ bool ok;
+ try {
+ ok = (*proc) ( context, filePath, severity, cause, message );
+ } catch ( ... ) {
+ ok = false;
+ }
+ return ConvertBoolToXMP_Bool( ok );
+}
+
+// =================================================================================================
+
+#define zXMPFiles_GetVersionInfo_1(versionInfo) \
+ WXMPFiles_GetVersionInfo_1 ( versionInfo /* no wResult */ )
+
+#define zXMPFiles_Initialize_1(options) \
+ WXMPFiles_Initialize_1 ( options, &wResult )
+
+#define zXMPFiles_Initialize_2(options,pluginFolder,plugins) \
+ WXMPFiles_Initialize_2 ( options, pluginFolder, plugins, &wResult )
+
+#define zXMPFiles_Terminate_1() \
+ WXMPFiles_Terminate_1 ( /* no wResult */ )
+
+#define zXMPFiles_CTor_1() \
+ WXMPFiles_CTor_1 ( &wResult )
+
+#define zXMPFiles_GetFormatInfo_1(format,flags) \
+ WXMPFiles_GetFormatInfo_1 ( format, flags, &wResult )
+
+#define zXMPFiles_CheckFileFormat_1(filePath) \
+ WXMPFiles_CheckFileFormat_1 ( filePath, &wResult )
+
+#define zXMPFiles_CheckPackageFormat_1(folderPath) \
+ WXMPFiles_CheckPackageFormat_1 ( folderPath, &wResult )
+
+#define zXMPFiles_GetFileModDate_1(filePath,modDate,format,options) \
+ WXMPFiles_GetFileModDate_1 ( filePath, modDate, format, options, &wResult )
+
+#define zXMPFiles_GetAssociatedResources_1( filePath, resourceList, format, options, SetClientStringVector ) \
+ WXMPFiles_GetAssociatedResources_1 ( filePath, resourceList, format, options, SetClientStringVector, &wResult )
+
+#define zXMPFiles_IsMetadataWritable_1( filePath, writable, format, options ) \
+ WXMPFiles_IsMetadataWritable_1 ( filePath, writable, format, options, &wResult )
+
+#define zXMPFiles_OpenFile_1(filePath,format,openFlags) \
+ WXMPFiles_OpenFile_1 ( this->xmpFilesRef, filePath, format, openFlags, &wResult )
+
+#if XMP_StaticBuild // ! Client XMP_IO objects can only be used in static builds.
+#define zXMPFiles_OpenFile_2(clientIO,format,openFlags) \
+ WXMPFiles_OpenFile_2 ( this->xmpFilesRef, clientIO, format, openFlags, &wResult )
+#endif
+
+#define zXMPFiles_CloseFile_1(closeFlags) \
+ WXMPFiles_CloseFile_1 ( this->xmpFilesRef, closeFlags, &wResult )
+
+#define zXMPFiles_GetFileInfo_1(clientPath,openFlags,format,handlerFlags,SetClientString) \
+ WXMPFiles_GetFileInfo_1 ( this->xmpFilesRef, clientPath, openFlags, format, handlerFlags, SetClientString, &wResult )
+
+#define zXMPFiles_SetAbortProc_1(abortProc,abortArg) \
+ WXMPFiles_SetAbortProc_1 ( this->xmpFilesRef, abortProc, abortArg, &wResult )
+
+#define zXMPFiles_GetXMP_1(xmpRef,clientPacket,packetInfo,SetClientString) \
+ WXMPFiles_GetXMP_1 ( this->xmpFilesRef, xmpRef, clientPacket, packetInfo, SetClientString, &wResult )
+
+#define zXMPFiles_PutXMP_1(xmpRef,xmpPacket,xmpPacketLen) \
+ WXMPFiles_PutXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, &wResult )
+
+#define zXMPFiles_CanPutXMP_1(xmpRef,xmpPacket,xmpPacketLen) \
+ WXMPFiles_CanPutXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, &wResult )
+
+#define zXMPFiles_SetDefaultProgressCallback_1(proc,context,interval,sendStartStop) \
+ WXMPFiles_SetDefaultProgressCallback_1 ( WrapProgressReport, proc, context, interval, sendStartStop, &wResult )
+
+#define zXMPFiles_SetProgressCallback_1(proc,context,interval,sendStartStop) \
+ WXMPFiles_SetProgressCallback_1 ( this->xmpFilesRef, WrapProgressReport, proc, context, interval, sendStartStop, &wResult )
+
+#define zXMPFiles_SetDefaultErrorCallback_1(proc,context,limit) \
+ WXMPFiles_SetDefaultErrorCallback_1 ( WrapFilesErrorNotify, proc, context, limit, &wResult )
+
+#define zXMPFiles_SetErrorCallback_1(proc,context,limit) \
+ WXMPFiles_SetErrorCallback_1 ( this->xmpFilesRef, WrapFilesErrorNotify, proc, context, limit, &wResult )
+
+#define zXMPFiles_ResetErrorCallbackLimit_1(limit) \
+ WXMPFiles_ResetErrorCallbackLimit_1 ( this->xmpFilesRef, limit, &wResult )
+
+// =================================================================================================
+
+extern void WXMPFiles_GetVersionInfo_1 ( XMP_VersionInfo * versionInfo );
+
+extern void WXMPFiles_Initialize_1 ( XMP_OptionBits options,
+ WXMP_Result * result );
+
+extern void WXMPFiles_Initialize_2 ( XMP_OptionBits options,
+ const char* pluginFolder,
+ const char* plugins,
+ WXMP_Result * result );
+
+extern void WXMPFiles_Terminate_1();
+
+extern void WXMPFiles_CTor_1 ( WXMP_Result * result );
+
+extern void WXMPFiles_IncrementRefCount_1 ( XMPFilesRef xmpFilesRef );
+
+extern void WXMPFiles_DecrementRefCount_1 ( XMPFilesRef xmpFilesRef );
+
+extern void WXMPFiles_GetFormatInfo_1 ( XMP_FileFormat format,
+ XMP_OptionBits * flags, // ! Can be null.
+ WXMP_Result * result );
+
+extern void WXMPFiles_CheckFileFormat_1 ( XMP_StringPtr filePath,
+ WXMP_Result * result );
+
+extern void WXMPFiles_CheckPackageFormat_1 ( XMP_StringPtr folderPath,
+ WXMP_Result * result );
+
+extern void WXMPFiles_GetFileModDate_1 ( XMP_StringPtr filePath,
+ XMP_DateTime * modDate,
+ XMP_FileFormat * format, // ! Can be null.
+ XMP_OptionBits options,
+ WXMP_Result * result );
+
+
+extern void WXMPFiles_GetAssociatedResources_1 ( XMP_StringPtr filePath,
+ void * resourceList,
+ XMP_FileFormat format,
+ XMP_OptionBits options,
+ SetClientStringVectorProc SetClientStringVector,
+ WXMP_Result * result );
+
+extern void WXMPFiles_IsMetadataWritable_1 ( XMP_StringPtr filePath,
+ XMP_Bool * writable,
+ XMP_FileFormat format,
+ XMP_OptionBits options,
+ WXMP_Result * result );
+
+extern void WXMPFiles_OpenFile_1 ( XMPFilesRef xmpFilesRef,
+ XMP_StringPtr filePath,
+ XMP_FileFormat format,
+ XMP_OptionBits openFlags,
+ WXMP_Result * result );
+
+#if XMP_StaticBuild // ! Client XMP_IO objects can only be used in static builds.
+extern void WXMPFiles_OpenFile_2 ( XMPFilesRef xmpFilesRef,
+ XMP_IO * clientIO,
+ XMP_FileFormat format,
+ XMP_OptionBits openFlags,
+ WXMP_Result * result );
+#endif
+
+extern void WXMPFiles_CloseFile_1 ( XMPFilesRef xmpFilesRef,
+ XMP_OptionBits closeFlags,
+ WXMP_Result * result );
+
+extern void WXMPFiles_GetFileInfo_1 ( XMPFilesRef xmpFilesRef,
+ void * clientPath,
+ XMP_OptionBits * openFlags, // ! Can be null.
+ XMP_FileFormat * format, // ! Can be null.
+ XMP_OptionBits * handlerFlags, // ! Can be null.
+ SetClientStringProc SetClientString,
+ WXMP_Result * result );
+
+extern void WXMPFiles_SetAbortProc_1 ( XMPFilesRef xmpFilesRef,
+ XMP_AbortProc abortProc,
+ void * abortArg,
+ WXMP_Result * result );
+
+extern void WXMPFiles_GetXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Can be null.
+ void * clientPacket,
+ XMP_PacketInfo * packetInfo, // ! Can be null.
+ SetClientStringProc SetClientString,
+ WXMP_Result * result );
+
+extern void WXMPFiles_PutXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
+ XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen,
+ WXMP_Result * result );
+
+extern void WXMPFiles_CanPutXMP_1 ( XMPFilesRef xmpFilesRef,
+ XMPMetaRef xmpRef, // ! Only one of the XMP object or packet are passed.
+ XMP_StringPtr xmpPacket,
+ XMP_StringLen xmpPacketLen,
+ WXMP_Result * result );
+
+extern void WXMPFiles_SetDefaultProgressCallback_1 ( XMP_ProgressReportWrapper wrapperproc,
+ XMP_ProgressReportProc clientProc,
+ void * context,
+ float interval,
+ XMP_Bool sendStartStop,
+ WXMP_Result * result );
+
+extern void WXMPFiles_SetProgressCallback_1 ( XMPFilesRef xmpFilesRef,
+ XMP_ProgressReportWrapper wrapperproc,
+ XMP_ProgressReportProc clientProc,
+ void * context,
+ float interval,
+ XMP_Bool sendStartStop,
+ WXMP_Result * result );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void WXMPFiles_SetDefaultErrorCallback_1 ( XMPFiles_ErrorCallbackWrapper wrapperProc,
+ XMPFiles_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult );
+
+extern void WXMPFiles_SetErrorCallback_1 ( XMPFilesRef xmpRef,
+ XMPFiles_ErrorCallbackWrapper wrapperProc,
+ XMPFiles_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult );
+
+extern void WXMPFiles_ResetErrorCallbackLimit_1 ( XMPFilesRef xmpRef,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult );
+
+// =================================================================================================
+
+#if __cplusplus
+}
+#endif
+
+#endif // __WXMPFiles_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/WXMPIterator.hpp b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPIterator.hpp
new file mode 100644
index 0000000..e40a1d4
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPIterator.hpp
@@ -0,0 +1,74 @@
+#if ! __WXMPIterator_hpp__
+#define __WXMPIterator_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+
+#define zXMPIterator_PropCTor_1(xmpRef,schemaNS,propName,options) \
+ WXMPIterator_PropCTor_1 ( xmpRef, schemaNS, propName, options, &wResult );
+
+#define zXMPIterator_TableCTor_1(schemaNS,propName,options) \
+ WXMPIterator_TableCTor_1 ( schemaNS, propName, options, &wResult );
+
+
+#define zXMPIterator_Next_1(schemaNS,propPath,propValue,options,SetClientString) \
+ WXMPIterator_Next_1 ( this->iterRef, schemaNS, propPath, propValue, options, SetClientString, &wResult );
+
+#define zXMPIterator_Skip_1(options) \
+ WXMPIterator_Skip_1 ( this->iterRef, options, &wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef );
+
+extern void
+XMP_PUBLIC WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef );
+
+extern void
+XMP_PUBLIC WXMPIterator_Next_1 ( XMPIteratorRef iterRef,
+ void * schemaNS,
+ void * propPath,
+ void * propValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPIterator_Skip_1 ( XMPIteratorRef iterRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMPIterator_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/WXMPMeta.hpp b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPMeta.hpp
new file mode 100644
index 0000000..361ad9d
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPMeta.hpp
@@ -0,0 +1,621 @@
+#if ! __WXMPMeta_hpp__
+#define __WXMPMeta_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+
+static XMP_Bool WrapErrorNotify ( XMPMeta_ErrorCallbackProc proc, void * context,
+ XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr message )
+{
+ bool ok;
+ try {
+ ok = (*proc) ( context, severity, cause, message );
+ } catch ( ... ) {
+ ok = false;
+ }
+ return ConvertBoolToXMP_Bool( ok );
+}
+
+// =================================================================================================
+
+#define zXMPMeta_GetVersionInfo_1(info) \
+ WXMPMeta_GetVersionInfo_1 ( info /* no wResult */ )
+
+#define zXMPMeta_Initialize_1() \
+ WXMPMeta_Initialize_1 ( &wResult )
+#define zXMPMeta_Terminate_1() \
+ WXMPMeta_Terminate_1 ( /* no wResult */ )
+
+#define zXMPMeta_CTor_1() \
+ WXMPMeta_CTor_1 ( &wResult )
+
+#define zXMPMeta_GetGlobalOptions_1() \
+ WXMPMeta_GetGlobalOptions_1 ( &wResult )
+
+#define zXMPMeta_SetGlobalOptions_1(options) \
+ WXMPMeta_SetGlobalOptions_1 ( options, &wResult )
+
+#define zXMPMeta_DumpNamespaces_1(outProc,refCon) \
+ WXMPMeta_DumpNamespaces_1 ( outProc, refCon, &wResult )
+
+#define zXMPMeta_RegisterNamespace_1(namespaceURI,suggestedPrefix,actualPrefix,SetClientString) \
+ WXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, actualPrefix, SetClientString, &wResult )
+
+#define zXMPMeta_GetNamespacePrefix_1(namespaceURI,namespacePrefix,SetClientString) \
+ WXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, SetClientString, &wResult )
+
+#define zXMPMeta_GetNamespaceURI_1(namespacePrefix,namespaceURI,SetClientString) \
+ WXMPMeta_GetNamespaceURI_1 ( namespacePrefix, namespaceURI, SetClientString, &wResult )
+
+#define zXMPMeta_DeleteNamespace_1(namespaceURI) \
+ WXMPMeta_DeleteNamespace_1 ( namespaceURI, &wResult )
+
+#define zXMPMeta_GetProperty_1(schemaNS,propName,propValue,options,SetClientString) \
+ WXMPMeta_GetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, options, SetClientString, &wResult )
+
+#define zXMPMeta_GetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,options,SetClientString) \
+ WXMPMeta_GetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, options, SetClientString, &wResult )
+
+#define zXMPMeta_GetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,options,SetClientString) \
+ WXMPMeta_GetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, options, SetClientString, &wResult )
+
+#define zXMPMeta_GetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,options,SetClientString) \
+ WXMPMeta_GetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, options, SetClientString, &wResult )
+
+#define zXMPMeta_SetProperty_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,options) \
+ WXMPMeta_SetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, options, &wResult )
+
+#define zXMPMeta_AppendArrayItem_1(schemaNS,arrayName,arrayOptions,itemValue,options) \
+ WXMPMeta_AppendArrayItem_1 ( this->xmpRef, schemaNS, arrayName, arrayOptions, itemValue, options, &wResult )
+
+#define zXMPMeta_SetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,options) \
+ WXMPMeta_SetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, options, &wResult )
+
+#define zXMPMeta_SetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,options) \
+ WXMPMeta_SetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, options, &wResult )
+
+#define zXMPMeta_DeleteProperty_1(schemaNS,propName) \
+ WXMPMeta_DeleteProperty_1 ( this->xmpRef, schemaNS, propName, &wResult )
+
+#define zXMPMeta_DeleteArrayItem_1(schemaNS,arrayName,itemIndex) \
+ WXMPMeta_DeleteArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, &wResult )
+
+#define zXMPMeta_DeleteStructField_1(schemaNS,structName,fieldNS,fieldName) \
+ WXMPMeta_DeleteStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, &wResult )
+
+#define zXMPMeta_DeleteQualifier_1(schemaNS,propName,qualNS,qualName) \
+ WXMPMeta_DeleteQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, &wResult )
+
+#define zXMPMeta_DoesPropertyExist_1(schemaNS,propName) \
+ WXMPMeta_DoesPropertyExist_1 ( this->xmpRef, schemaNS, propName, &wResult )
+
+#define zXMPMeta_DoesArrayItemExist_1(schemaNS,arrayName,itemIndex) \
+ WXMPMeta_DoesArrayItemExist_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, &wResult )
+
+#define zXMPMeta_DoesStructFieldExist_1(schemaNS,structName,fieldNS,fieldName) \
+ WXMPMeta_DoesStructFieldExist_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, &wResult )
+
+#define zXMPMeta_DoesQualifierExist_1(schemaNS,propName,qualNS,qualName) \
+ WXMPMeta_DoesQualifierExist_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, &wResult )
+
+#define zXMPMeta_GetLocalizedText_1(schemaNS,altTextName,genericLang,specificLang,clientLang,clientValue,options,SetClientString) \
+ WXMPMeta_GetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, clientLang, clientValue, options, SetClientString, &wResult )
+
+#define zXMPMeta_SetLocalizedText_1(schemaNS,altTextName,genericLang,specificLang,itemValue,options) \
+ WXMPMeta_SetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, itemValue, options, &wResult )
+
+#define zXMPMeta_DeleteLocalizedText_1(schemaNS,altTextName,genericLang,specificLang) \
+ WXMPMeta_DeleteLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, &wResult )
+#define zXMPMeta_GetProperty_Bool_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Bool_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Int_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Int_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Int64_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Int64_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Float_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Float_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetProperty_Date_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_GetProperty_Date_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Bool_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Bool_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Int_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Int_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Int64_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Int64_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Float_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Float_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_SetProperty_Date_1(schemaNS,propName,propValue,options) \
+ WXMPMeta_SetProperty_Date_1 ( this->xmpRef, schemaNS, propName, propValue, options, &wResult )
+
+#define zXMPMeta_GetObjectName_1(objName,SetClientString) \
+ WXMPMeta_GetObjectName_1 ( this->xmpRef, objName, SetClientString, &wResult )
+
+#define zXMPMeta_SetObjectName_1(name) \
+ WXMPMeta_SetObjectName_1 ( this->xmpRef, name, &wResult )
+
+#define zXMPMeta_GetObjectOptions_1() \
+ WXMPMeta_GetObjectOptions_1 ( this->xmpRef, &wResult )
+
+#define zXMPMeta_SetObjectOptions_1(options) \
+ WXMPMeta_SetObjectOptions_1 ( this->xmpRef, options, &wResult )
+
+#define zXMPMeta_Sort_1() \
+ WXMPMeta_Sort_1 ( this->xmpRef, &wResult )
+
+#define zXMPMeta_Erase_1() \
+ WXMPMeta_Erase_1 ( this->xmpRef, &wResult )
+
+#define zXMPMeta_Clone_1(options) \
+ WXMPMeta_Clone_1 ( this->xmpRef, options, &wResult )
+
+#define zXMPMeta_CountArrayItems_1(schemaNS,arrayName) \
+ WXMPMeta_CountArrayItems_1 ( this->xmpRef, schemaNS, arrayName, &wResult )
+
+#define zXMPMeta_DumpObject_1(outProc,refCon) \
+ WXMPMeta_DumpObject_1 ( this->xmpRef, outProc, refCon, &wResult )
+
+#define zXMPMeta_ParseFromBuffer_1(buffer,bufferSize,options) \
+ WXMPMeta_ParseFromBuffer_1 ( this->xmpRef, buffer, bufferSize, options, &wResult )
+
+#define zXMPMeta_SerializeToBuffer_1(pktString,options,padding,newline,indent,baseIndent,SetClientString) \
+ WXMPMeta_SerializeToBuffer_1 ( this->xmpRef, pktString, options, padding, newline, indent, baseIndent, SetClientString, &wResult )
+
+#define zXMPMeta_SetDefaultErrorCallback_1(proc,context,limit) \
+ WXMPMeta_SetDefaultErrorCallback_1 ( WrapErrorNotify, proc, context, limit, &wResult )
+
+#define zXMPMeta_SetErrorCallback_1(proc,context,limit) \
+ WXMPMeta_SetErrorCallback_1 ( this->xmpRef, WrapErrorNotify, proc, context, limit, &wResult )
+
+#define zXMPMeta_ResetErrorCallbackLimit_1(limit) \
+ WXMPMeta_ResetErrorCallbackLimit_1 ( this->xmpRef, limit, &wResult )
+
+// =================================================================================================
+
+extern void
+XMP_PUBLIC WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info );
+
+extern void
+XMP_PUBLIC WXMPMeta_Initialize_1 ( WXMP_Result * wResult );
+extern void
+XMP_PUBLIC WXMPMeta_Terminate_1();
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_CTor_1 ( WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef );
+
+extern void
+XMP_PUBLIC WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ void * actualPrefix,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
+ void * namespacePrefix,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
+ void * namespaceURI,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ void * propValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ void * itemValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ void * fieldValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ void * qualValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ void * clientLang,
+ void * clientValue,
+ XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_DeleteLocalizedText_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_DateTime * propValue,
+ XMP_OptionBits * options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Bool propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int32 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_Int64 propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ double propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ const XMP_DateTime & propValue,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef,
+ void * objName,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr name,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_Sort_1 ( XMPMetaRef xmpRef,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_Erase_1 ( XMPMetaRef xmpRef,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_Clone_1 ( XMPMetaRef xmpRef,
+ XMP_OptionBits options,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ WXMP_Result * wResult ) /* const */ ;
+
+extern void
+XMP_PUBLIC WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef,
+ XMP_TextOutputProc outProc,
+ void * refCon,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef,
+ XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef,
+ void * pktString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPMeta_SetDefaultErrorCallback_1 ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_SetErrorCallback_1 ( XMPMetaRef xmpRef,
+ XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPMeta_ResetErrorCallbackLimit_1 ( XMPMetaRef xmpRef,
+ XMP_Uns32 limit,
+ WXMP_Result * wResult );
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMPMeta_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/WXMPUtils.hpp b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPUtils.hpp
new file mode 100644
index 0000000..3c96b83
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/WXMPUtils.hpp
@@ -0,0 +1,315 @@
+#if ! __WXMPUtils_hpp__
+#define __WXMPUtils_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "client-glue/WXMP_Common.hpp"
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// =================================================================================================
+
+#define zXMPUtils_ComposeArrayItemPath_1(schemaNS,arrayName,itemIndex,itemPath,SetClientString) \
+ WXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, itemPath, SetClientString, &wResult );
+
+#define zXMPUtils_ComposeStructFieldPath_1(schemaNS,structName,fieldNS,fieldName,fieldPath,SetClientString) \
+ WXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, fieldPath, SetClientString, &wResult );
+
+#define zXMPUtils_ComposeQualifierPath_1(schemaNS,propName,qualNS,qualName,qualPath,SetClientString) \
+ WXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, qualPath, SetClientString, &wResult );
+
+#define zXMPUtils_ComposeLangSelector_1(schemaNS,arrayName,langName,selPath,SetClientString) \
+ WXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, selPath, SetClientString, &wResult );
+
+#define zXMPUtils_ComposeFieldSelector_1(schemaNS,arrayName,fieldNS,fieldName,fieldValue,selPath,SetClientString) \
+ WXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, selPath, SetClientString, &wResult );
+
+#define zXMPUtils_ConvertFromBool_1(binValue,strValue,SetClientString) \
+ WXMPUtils_ConvertFromBool_1 ( binValue, strValue, SetClientString, &wResult );
+
+#define zXMPUtils_ConvertFromInt_1(binValue,format,strValue,SetClientString) \
+ WXMPUtils_ConvertFromInt_1 ( binValue, format, strValue, SetClientString, &wResult );
+
+#define zXMPUtils_ConvertFromInt64_1(binValue,format,strValue,SetClientString) \
+ WXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, SetClientString, &wResult );
+
+#define zXMPUtils_ConvertFromFloat_1(binValue,format,strValue,SetClientString) \
+ WXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, SetClientString, &wResult );
+
+#define zXMPUtils_ConvertFromDate_1(binValue,strValue,SetClientString) \
+ WXMPUtils_ConvertFromDate_1 ( binValue, strValue, SetClientString, &wResult );
+
+#define zXMPUtils_ConvertToBool_1(strValue) \
+ WXMPUtils_ConvertToBool_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToInt_1(strValue) \
+ WXMPUtils_ConvertToInt_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToInt64_1(strValue) \
+ WXMPUtils_ConvertToInt64_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToFloat_1(strValue) \
+ WXMPUtils_ConvertToFloat_1 ( strValue, &wResult );
+
+#define zXMPUtils_ConvertToDate_1(strValue,binValue) \
+ WXMPUtils_ConvertToDate_1 ( strValue, binValue, &wResult );
+
+#define zXMPUtils_CurrentDateTime_1(time) \
+ WXMPUtils_CurrentDateTime_1 ( time, &wResult );
+
+#define zXMPUtils_SetTimeZone_1(time) \
+ WXMPUtils_SetTimeZone_1 ( time, &wResult );
+
+#define zXMPUtils_ConvertToUTCTime_1(time) \
+ WXMPUtils_ConvertToUTCTime_1 ( time, &wResult );
+
+#define zXMPUtils_ConvertToLocalTime_1(time) \
+ WXMPUtils_ConvertToLocalTime_1 ( time, &wResult );
+
+#define zXMPUtils_CompareDateTime_1(left,right) \
+ WXMPUtils_CompareDateTime_1 ( left, right, &wResult );
+
+#define zXMPUtils_EncodeToBase64_1(rawStr,rawLen,encodedStr,SetClientString) \
+ WXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, encodedStr, SetClientString, &wResult );
+
+#define zXMPUtils_DecodeFromBase64_1(encodedStr,encodedLen,rawStr,SetClientString) \
+ WXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, rawStr, SetClientString, &wResult );
+
+#define zXMPUtils_PackageForJPEG_1(xmpObj,stdStr,extStr,digestStr,SetClientString) \
+ WXMPUtils_PackageForJPEG_1 ( xmpObj, stdStr, extStr, digestStr, SetClientString, &wResult );
+
+#define zXMPUtils_MergeFromJPEG_1(fullXMP,extendedXMP) \
+ WXMPUtils_MergeFromJPEG_1 ( fullXMP, extendedXMP, &wResult );
+
+#define zXMPUtils_CatenateArrayItems_1(xmpObj,schemaNS,arrayName,separator,quotes,options,catedStr,SetClientString) \
+ WXMPUtils_CatenateArrayItems_1 ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedStr, SetClientString, &wResult );
+
+#define zXMPUtils_SeparateArrayItems_1(xmpObj,schemaNS,arrayName,options,catedStr) \
+ WXMPUtils_SeparateArrayItems_1 ( xmpObj, schemaNS, arrayName, options, catedStr, &wResult );
+
+#define zXMPUtils_ApplyTemplate_1(workingXMP,templateXMP,actions) \
+ WXMPUtils_ApplyTemplate_1 ( workingXMP, templateXMP, actions, &wResult );
+
+#define zXMPUtils_RemoveProperties_1(xmpObj,schemaNS,propName,options) \
+ WXMPUtils_RemoveProperties_1 ( xmpObj, schemaNS, propName, options, &wResult );
+
+#define zXMPUtils_DuplicateSubtree_1(source,dest,sourceNS,sourceRoot,destNS,destRoot,options) \
+ WXMPUtils_DuplicateSubtree_1 ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options, &wResult );
+
+// =================================================================================================
+
+extern void
+XMP_PUBLIC WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ void * itemPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ void * fieldPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ void * qualPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr langName,
+ void * selPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ void * selPath,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertFromFloat_1 ( double binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
+ XMP_DateTime * binValue,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
+ const XMP_DateTime & right,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ void * encodedStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ void * rawStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPUtils_PackageForJPEG_1 ( XMPMetaRef xmpObj,
+ void * stdStr,
+ void * extStr,
+ void * digestStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef fullXMP,
+ XMPMetaRef extendedXMP,
+ WXMP_Result * wResult );
+
+// -------------------------------------------------------------------------------------------------
+
+extern void
+XMP_PUBLIC WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ void * catedStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_ApplyTemplate_1 ( XMPMetaRef workingXMP,
+ XMPMetaRef templateXMP,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_RemoveProperties_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+extern void
+XMP_PUBLIC WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef source,
+ XMPMetaRef dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
+
+// =================================================================================================
+
+#if __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // __WXMPUtils_hpp__
diff --git a/gpr/source/lib/xmp_core/public/include/client-glue/WXMP_Common.hpp b/gpr/source/lib/xmp_core/public/include/client-glue/WXMP_Common.hpp
new file mode 100644
index 0000000..97fb9fc
--- /dev/null
+++ b/gpr/source/lib/xmp_core/public/include/client-glue/WXMP_Common.hpp
@@ -0,0 +1,128 @@
+#if ! __WXMP_Common_hpp__
+#define __WXMP_Common_hpp__ 1
+
+// =================================================================================================
+// Copyright 2002 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#ifndef XMP_Inline
+ #if TXMP_EXPAND_INLINE
+ #define XMP_Inline inline
+ #else
+ #define XMP_Inline /* not inline */
+ #endif
+#endif
+
+#define XMP_CTorDTorIntro(Class) template <class tStringObj> XMP_Inline Class<tStringObj>
+#define XMP_MethodIntro(Class,ResultType) template <class tStringObj> XMP_Inline ResultType Class<tStringObj>
+
+typedef void (* SetClientStringProc) ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
+typedef void (* SetClientStringVectorProc) ( void * clientPtr, XMP_StringPtr * arrayPtr, XMP_Uns32 stringCount );
+
+struct WXMP_Result {
+ XMP_StringPtr errMessage;
+ void * ptrResult;
+ double floatResult;
+ XMP_Uns64 int64Result;
+ XMP_Uns32 int32Result;
+ WXMP_Result() : errMessage(0),ptrResult(NULL),floatResult(0),int64Result(0),int32Result(0){};
+};
+
+#if __cplusplus
+extern "C" {
+#endif
+
+#define PropagateException(res) \
+ if ( res.errMessage != 0 ) throw XMP_Error ( res.int32Result, res.errMessage );
+
+#ifndef XMP_TraceClientCalls
+ #define XMP_TraceClientCalls 0
+ #define XMP_TraceClientCallsToFile 0
+#endif
+
+#if ! XMP_TraceClientCalls
+ #define InvokeCheck(WCallProto) \
+ WXMP_Result wResult; \
+ WCallProto; \
+ PropagateException ( wResult )
+#else
+ extern FILE * xmpClientLog;
+ #define InvokeCheck(WCallProto) \
+ WXMP_Result wResult; \
+ fprintf ( xmpClientLog, "WXMP calling: %s\n", #WCallProto ); fflush ( xmpClientLog ); \
+ WCallProto; \
+ if ( wResult.errMessage == 0 ) { \
+ fprintf ( xmpClientLog, "WXMP back, no error\n" ); fflush ( xmpClientLog ); \
+ } else { \
+ fprintf ( xmpClientLog, "WXMP back, error: %s\n", wResult.errMessage ); fflush ( xmpClientLog ); \
+ } \
+ PropagateException ( wResult )
+#endif
+
+// =================================================================================================
+
+#define WrapNoCheckVoid(WCallProto) \
+ WCallProto;
+
+#define WrapCheckVoid(WCallProto) \
+ InvokeCheck(WCallProto);
+
+#define WrapCheckMetaRef(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMPMetaRef result = XMPMetaRef(wResult.ptrResult)
+
+#define WrapCheckIterRef(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMPIteratorRef result = XMPIteratorRef(wResult.ptrResult)
+
+#define WrapCheckDocOpsRef(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMPDocOpsRef result = XMPDocOpsRef(wResult.ptrResult)
+
+#define WrapCheckBool(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ bool result = bool(wResult.int32Result)
+
+#define WrapCheckTriState(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_TriState result = XMP_TriState(wResult.int32Result)
+
+#define WrapCheckOptions(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_OptionBits result = XMP_OptionBits(wResult.int32Result)
+
+#define WrapCheckStatus(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Status result = XMP_Status(wResult.int32Result)
+
+#define WrapCheckIndex(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Index result = XMP_Index(wResult.int32Result)
+
+#define WrapCheckInt32(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Int32 result = wResult.int32Result
+
+#define WrapCheckInt64(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_Int64 result = wResult.int64Result
+
+#define WrapCheckFloat(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ double result = wResult.floatResult
+
+#define WrapCheckFormat(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ XMP_FileFormat result = wResult.int32Result
+
+// =================================================================================================
+
+#if __cplusplus
+} // extern "C"
+#endif
+
+#endif // __WXMP_Common_hpp__