No OneTemporary

File Metadata

Created
Sat, May 11, 1:11 PM
This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/core/libs/dngwriter/CMakeLists.txt b/core/libs/dngwriter/CMakeLists.txt
index 536e2b5bd0..af46581b27 100644
--- a/core/libs/dngwriter/CMakeLists.txt
+++ b/core/libs/dngwriter/CMakeLists.txt
@@ -1,160 +1,186 @@
#
-# Copyright (c) 2010-2019, Gilles Caulier, <caulier dot gilles at gmail dot com>
+# Copyright (c) 2010-2020, Gilles Caulier, <caulier dot gilles at gmail dot com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# DNG SDK and XMP SDK use C++ exceptions
kde_enable_exceptions()
include_directories(
$<TARGET_PROPERTY:Qt5::Widgets,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:KF5::I18n,INTERFACE_INCLUDE_DIRECTORIES>
${EXPAT_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/extra/md5
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk
${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/common
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/include
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/include/client-glue
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/build
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/client-glue
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCore
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCore/Interfaces
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCore/sources
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCommon
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCommon/Interfaces
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCommon/Utilities
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/public/include/XMPCommon/sources
${CMAKE_CURRENT_SOURCE_DIR}/
)
#------------------------------------------------------------------------------------
set(libmd5_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/extra/md5/XMP_MD5.cpp)
# Adjust flag for static lib and 64 bits computers using -fPIC for GCC compiler (bug: #269903)
foreach(_currentfile ${libmd5_SRCS})
if(NOT MSVC)
set_source_files_properties(${_currentfile} PROPERTIES COMPILE_FLAGS "-fPIC")
endif()
endforeach()
add_library(libmd5_src OBJECT ${libmd5_SRCS})
#------------------------------------------------------------------------------------
set(libxmp_SRCS
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/common/XML_Node.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/common/UnicodeConversions.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPCore_Impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/WXMPIterator.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/WXMPMeta.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/WXMPUtils.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPIterator.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPMeta-GetSet.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPMeta-Parse.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPMeta-Serialize.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPMeta.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPUtils-FileInfo.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/XMPUtils.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/ExpatAdapter.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/ParseRDF.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/Host_IO-POSIX.cpp
+# ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/Host_IO-Win.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/IOUtils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/PerfUtils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/SafeStringAPIs.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/UnicodeConversions.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/XIO.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/XML_Node.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/XMP_LibUtils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/XMP_ProgressTracker.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/source/XMPFiles_IO.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/ExpatAdapter.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/ParseRDF.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/WXMPIterator.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/WXMPMeta.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/WXMPUtils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPIterator.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPMeta-GetSet.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPMeta-Parse.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPMeta-Serialize.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPMeta.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPUtils-FileInfo.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/xmp_sdk/XMPCore/source/XMPUtils.cpp
)
# Disable warnings: we will never touch this code.
# Adjust flag for static lib and 64 bits computers using -fPIC for GCC compiler (bug: #269903)
foreach(_currentfile ${libxmp_SRCS})
if(MSVC)
set_source_files_properties(${_currentfile} PROPERTIES COMPILE_FLAGS "-w")
else()
set_source_files_properties(${_currentfile} PROPERTIES COMPILE_FLAGS "-w -fPIC")
endif()
endforeach()
add_library(libxmp_src OBJECT ${libxmp_SRCS})
#------------------------------------------------------------------------------------
set(libdng_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_1d_function.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_date_time.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_ifd.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_memory.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_point.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_simple_image.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_1d_table.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_exceptions.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_image.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_memory_stream.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_rational.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_spline.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_xmp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_abort_sniffer.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_exif.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_image_writer.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_preview.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_misc_opcodes.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_mosaic_info.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_read_image.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_stream.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_xmp_sdk.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_area_task.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_file_stream.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_info.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_mutex.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_rect.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_string.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_xy_coord.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_bottlenecks.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_bad_pixels.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_filter_task.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_iptc.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_negative.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_reference.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_string_list.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_big_table.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_bottlenecks.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_camera_profile.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_color_space.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_color_spec.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_date_time.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_exceptions.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_exif.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_file_stream.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_filter_task.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_fingerprint.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_gain_map.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_globals.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_host.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_hue_sat_map.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_ifd.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_image.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_image_writer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_info.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_iptc.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_jpeg_image.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_lens_correction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_linearization_info.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_local_string.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_lossless_jpeg.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_matrix.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_memory.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_memory_stream.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_misc_opcodes.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_mosaic_info.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_mutex.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_negative.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_opcode_list.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_opcodes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_orientation.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_render.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_tag_types.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_color_space.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_globals.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_gain_map.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_lossless_jpeg.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_parse_utils.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_resample.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_temperature.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_color_spec.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_host.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_matrix.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_pixel_buffer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_point.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_preview.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_pthread.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_rational.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_read_image.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_rect.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_ref_counted_block.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_reference.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_render.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_resample.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_safe_arithmetic.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_shared.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_simple_image.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_spline.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_stream.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_string.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_string_list.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_tag_types.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_temperature.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_tile_iterator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_tone_curve.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_hue_sat_map.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_pthread.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_utils.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_validate.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_xmp.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_xmp_sdk.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/extra/dng_sdk/dng_xy_coord.cpp
)
# Disable warnings: we will never touch this code.
# Adjust flag for static lib and 64 bits computers using -fPIC for GCC compiler (bug: #269903)
foreach(_currentfile ${libdng_SRCS})
if(MSVC)
set_source_files_properties(${_currentfile} PROPERTIES COMPILE_FLAGS "-w")
else()
set_source_files_properties(${_currentfile} PROPERTIES COMPILE_FLAGS "-w -fPIC")
endif()
endforeach()
add_library(libdng_src OBJECT ${libdng_SRCS})
#------------------------------------------------------------------------------------
set(libdngwriter_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/dngwriter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dngwriter_p.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dngwriter_convert.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dngwriterhost.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dngsettings.cpp
)
add_library(dngwriter_src OBJECT ${libdngwriter_SRCS})
diff --git a/core/libs/dngwriter/dngwriter_convert.cpp b/core/libs/dngwriter/dngwriter_convert.cpp
index 1d50efcca2..9854f836e7 100644
--- a/core/libs/dngwriter/dngwriter_convert.cpp
+++ b/core/libs/dngwriter/dngwriter_convert.cpp
@@ -1,1243 +1,1265 @@
/* ============================================================
*
* This file is a part of digiKam project
* https://www.digikam.org
*
* Date : 2008-09-25
* Description : a tool to convert RAW file to DNG
*
* Copyright (C) 2008-2020 by Gilles Caulier <caulier dot gilles at gmail dot com>
* Copyright (C) 2010-2011 by Jens Mueller <tschenser at gmx dot de>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
#include "dngwriter_p.h"
namespace Digikam
{
int DNGWriter::convert()
{
d->cancel = false;
try
{
if (inputFile().isEmpty())
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: No input file to convert. Aborted..." ;
return PROCESSFAILED;
}
QFileInfo inputInfo(inputFile());
QString dngFilePath = outputFile();
if (dngFilePath.isEmpty())
{
dngFilePath = QString(inputInfo.completeBaseName() + QLatin1String(".dng"));
}
QFileInfo outputInfo(dngFilePath);
QByteArray rawData;
DRawInfo identify;
DRawInfo identifyMake;
// -----------------------------------------------------------------------------------------
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Loading RAW data from " << inputInfo.fileName() ;
DRawDecoder rawProcessor;
if (!rawProcessor.rawFileIdentify(identifyMake, inputFile()))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Reading RAW file failed. Aborted..." ;
return PROCESSFAILED;
}
dng_rect activeArea;
// TODO: need to get correct default crop size to avoid artifacts at the borders
int activeWidth = 0;
int activeHeight = 0;
int outputHeight = 0;
int outputWidth = 0;
if ((identifyMake.orientation == 5) || (identifyMake.orientation == 6))
{
outputHeight = identifyMake.outputSize.width();
outputWidth = identifyMake.outputSize.height();
}
else
{
outputHeight = identifyMake.outputSize.height();
outputWidth = identifyMake.outputSize.width();
}
if (!rawProcessor.extractRAWData(inputFile(), rawData, identify, 0))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Loading RAW data failed. Aborted..." ;
return FILENOTSUPPORTED;
}
if (d->cancel)
{
return PROCESSCANCELED;
}
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Raw data loaded:" ;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Data Size: " << rawData.size() << " bytes";
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Date: " << identify.dateTime.toString(Qt::ISODate);
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Make: " << identify.make;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Model: " << identify.model;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- ImageSize: " << identify.imageSize.width() << "x" << identify.imageSize.height();
qCDebug(DIGIKAM_GENERAL_LOG) << "--- FullSize: " << identify.fullSize.width() << "x" << identify.fullSize.height();
qCDebug(DIGIKAM_GENERAL_LOG) << "--- OutputSize: " << identify.outputSize.width() << "x" << identify.outputSize.height();
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Orientation: " << identify.orientation;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Top margin: " << identify.topMargin;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Left margin: " << identify.leftMargin;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Filter: " << identify.filterPattern;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Colors: " << identify.rawColors;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- Black: " << identify.blackPoint;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- White: " << identify.whitePoint;
qCDebug(DIGIKAM_GENERAL_LOG) << "--- CAM->XYZ:" ;
QString matrixVal;
for (int i = 0 ; i < 4 ; ++i)
{
qCDebug(DIGIKAM_GENERAL_LOG) << " "
<< QString().sprintf("%03.4f %03.4f %03.4f", identify.cameraXYZMatrix[i][0],
identify.cameraXYZMatrix[i][1],
identify.cameraXYZMatrix[i][2]);
}
// Check if CFA layout is supported by DNG SDK.
Private::DNGBayerPattern bayerPattern = Private::Unknown;
uint32 filter = 0;
bool fujiRotate90 = false;
// Standard bayer layouts
if (identify.filterPattern == QLatin1String("GRBGGRBGGRBGGRBG"))
{
bayerPattern = Private::Standard;
filter = 0;
}
else if (identify.filterPattern == QLatin1String("RGGBRGGBRGGBRGGB"))
{
bayerPattern = Private::Standard;
filter = 1;
}
else if (identify.filterPattern == QLatin1String("BGGRBGGRBGGRBGGR"))
{
bayerPattern = Private::Standard;
filter = 2;
}
else if (identify.filterPattern == QLatin1String("GBRGGBRGGBRGGBRG"))
{
bayerPattern = Private::Standard;
filter = 3;
}
else if ((identify.filterPattern == QLatin1String("RGBGRGBGRGBGRGBG")) && (identifyMake.make == QLatin1String("FUJIFILM")))
{
// Fuji layouts
bayerPattern = Private::Fuji;
fujiRotate90 = false;
filter = 0;
}
else if ((identify.filterPattern == QLatin1String("RBGGBRGGRBGGBRGG")) && (identifyMake.make == QLatin1String("FUJIFILM")))
{
// Fuji layouts
bayerPattern = Private::Fuji;
fujiRotate90 = true;
filter = 0;
}
else if ((identify.rawColors == 3) &&
(identify.filterPattern.isEmpty()) &&
/*
(identify.filterPattern == QString("")) &&
*/
((uint32)rawData.size() == identify.outputSize.width() * identify.outputSize.height() * 3 * sizeof(uint16)))
{
bayerPattern = Private::LinearRaw;
}
else if (identify.rawColors == 4) // Four color sensors
{
bayerPattern = Private::FourColor;
if (identify.filterPattern.length() != 16)
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Bayer mosaic not supported. Aborted..." ;
return FILENOTSUPPORTED;
}
for (int i = 0 ; i < 16 ; ++i)
{
filter = filter >> 2;
if (identify.filterPattern[i] == QLatin1Char('G'))
{
filter |= 0x00000000;
}
else if (identify.filterPattern[i] == QLatin1Char('M'))
{
filter |= 0x40000000;
}
else if (identify.filterPattern[i] == QLatin1Char('C'))
{
filter |= 0x80000000;
}
else if (identify.filterPattern[i] == QLatin1Char('Y'))
{
filter |= 0xC0000000;
}
else
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Bayer mosaic not supported. Aborted..." ;
return FILENOTSUPPORTED;
}
}
}
else
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Bayer mosaic not supported. Aborted..." ;
return FILENOTSUPPORTED;
}
if (fujiRotate90)
{
if (!d->fujiRotate(rawData, identify))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "Can not rotate fuji image. Aborted...";
return PROCESSFAILED;
}
int tmp = outputWidth;
outputWidth = outputHeight;
outputHeight = tmp;
}
activeArea = dng_rect(identify.outputSize.height(), identify.outputSize.width());
activeWidth = identify.outputSize.width();
activeHeight = identify.outputSize.height();
// Check if number of Raw Color components is supported.
if ((identify.rawColors != 3) && (identify.rawColors != 4))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Number of Raw color components not supported. Aborted..." ;
return PROCESSFAILED;
}
int width = identify.outputSize.width();
int height = identify.outputSize.height();
/*
// NOTE: code to hack RAW data extraction
QString rawdataFilePath(inputInfo.completeBaseName() + QString(".dat"));
QFileInfo rawdataInfo(rawdataFilePath);
QFile rawdataFile(rawdataFilePath);
if (!rawdataFile.open(QIODevice::WriteOnly))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Cannot open file to write RAW data. Aborted..." ;
return PROCESSFAILED;
}
QDataStream rawdataStream(&rawdataFile);
rawdataStream.writeRawData(rawData.data(), rawData.size());
rawdataFile.close();
*/
// -----------------------------------------------------------------------------------------
if (d->cancel)
{
return PROCESSCANCELED;
}
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG memory allocation and initialization" ;
dng_memory_allocator memalloc(gDefaultDNGMemoryAllocator);
dng_rect rect(height, width);
DNGWriterHost host(d, &memalloc);
host.SetSaveDNGVersion(dngVersion_SaveDefault);
host.SetSaveLinearDNG(false);
host.SetKeepOriginalFile(true);
AutoPtr<dng_image> image(new dng_simple_image(rect, (bayerPattern == Private::LinearRaw) ? 3 : 1, ttShort, memalloc));
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
dng_pixel_buffer buffer;
buffer.fArea = rect;
buffer.fPlane = 0;
buffer.fPlanes = bayerPattern == Private::LinearRaw ? 3 : 1;
buffer.fRowStep = buffer.fPlanes * width;
buffer.fColStep = buffer.fPlanes;
buffer.fPlaneStep = 1;
buffer.fPixelType = ttShort;
buffer.fPixelSize = TagTypeSize(ttShort);
buffer.fData = rawData.data();
image->Put(buffer);
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG Negative structure creation" ;
AutoPtr<dng_negative> negative(host.Make_dng_negative());
negative->SetDefaultScale(dng_urational(outputWidth, activeWidth), dng_urational(outputHeight, activeHeight));
if (bayerPattern != Private::LinearRaw)
{
negative->SetDefaultCropOrigin(8, 8);
negative->SetDefaultCropSize(activeWidth - 16, activeHeight - 16);
}
else
{
negative->SetDefaultCropOrigin(0, 0);
negative->SetDefaultCropSize(activeWidth, activeHeight);
}
negative->SetActiveArea(activeArea);
negative->SetModelName(identify.model.toLatin1().constData());
negative->SetLocalName(QString::fromUtf8("%1 %2").arg(identify.make, identify.model).toLatin1().constData());
negative->SetOriginalRawFileName(inputInfo.fileName().toLatin1().constData());
negative->SetColorChannels(identify.rawColors);
ColorKeyCode colorCodes[4] = { colorKeyMaxEnum, colorKeyMaxEnum, colorKeyMaxEnum, colorKeyMaxEnum };
for (int i = 0 ; i < qMax(4, identify.colorKeys.length()) ; ++i)
{
if (identify.colorKeys[i] == QLatin1Char('R'))
{
colorCodes[i] = colorKeyRed;
}
else if (identify.colorKeys[i] == QLatin1Char('G'))
{
colorCodes[i] = colorKeyGreen;
}
else if (identify.colorKeys[i] == QLatin1Char('B'))
{
colorCodes[i] = colorKeyBlue;
}
else if (identify.colorKeys[i] == QLatin1Char('C'))
{
colorCodes[i] = colorKeyCyan;
}
else if (identify.colorKeys[i] == QLatin1Char('M'))
{
colorCodes[i] = colorKeyMagenta;
}
else if (identify.colorKeys[i] == QLatin1Char('Y'))
{
colorCodes[i] = colorKeyYellow;
}
}
negative->SetColorKeys(colorCodes[0], colorCodes[1], colorCodes[2], colorCodes[3]);
switch (bayerPattern)
{
case Private::Standard:
// Standard bayer mosaicing. All work fine there.
// Bayer CCD mask: https://en.wikipedia.org/wiki/Bayer_filter
negative->SetBayerMosaic(filter);
break;
case Private::Fuji:
// TODO: Fuji is special case. Need to setup different bayer rules here.
// It do not work in all settings. Need indeep investiguations.
// Fuji superCCD: https://en.wikipedia.org/wiki/Super_CCD
negative->SetFujiMosaic(filter);
break;
case Private::FourColor:
negative->SetQuadMosaic(filter);
break;
default:
break;
}
negative->SetWhiteLevel(identify.whitePoint, 0);
negative->SetWhiteLevel(identify.whitePoint, 1);
negative->SetWhiteLevel(identify.whitePoint, 2);
negative->SetWhiteLevel(identify.whitePoint, 3);
const dng_mosaic_info* const mosaicinfo = negative->GetMosaicInfo();
if ((mosaicinfo != nullptr) && (mosaicinfo->fCFAPatternSize == dng_point(2, 2)))
{
negative->SetQuadBlacks(identify.blackPoint + identify.blackPointCh[0],
identify.blackPoint + identify.blackPointCh[1],
identify.blackPoint + identify.blackPointCh[2],
identify.blackPoint + identify.blackPointCh[3]);
}
else
{
negative->SetBlackLevel(identify.blackPoint, 0);
}
negative->SetBaselineExposure(0.0);
negative->SetBaselineNoise(1.0);
negative->SetBaselineSharpness(1.0);
dng_orientation orientation;
switch (identify.orientation)
{
case DRawInfo::ORIENTATION_180:
orientation = dng_orientation::Rotate180();
break;
case DRawInfo::ORIENTATION_Mirror90CCW:
orientation = dng_orientation::Mirror90CCW();
break;
case DRawInfo::ORIENTATION_90CCW:
orientation = dng_orientation::Rotate90CCW();
break;
case DRawInfo::ORIENTATION_90CW:
orientation = dng_orientation::Rotate90CW();
break;
default: // ORIENTATION_NONE
orientation = dng_orientation::Normal();
break;
}
negative->SetBaseOrientation(orientation);
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(QString::fromUtf8("%1 %2").arg(identify.make, identify.model).toLatin1().constData());
// Set Camera->XYZ Color matrix as profile.
dng_matrix matrix;
switch (identify.rawColors)
{
case 3:
{
dng_matrix_3by3 camXYZ;
camXYZ[0][0] = identify.cameraXYZMatrix[0][0];
camXYZ[0][1] = identify.cameraXYZMatrix[0][1];
camXYZ[0][2] = identify.cameraXYZMatrix[0][2];
camXYZ[1][0] = identify.cameraXYZMatrix[1][0];
camXYZ[1][1] = identify.cameraXYZMatrix[1][1];
camXYZ[1][2] = identify.cameraXYZMatrix[1][2];
camXYZ[2][0] = identify.cameraXYZMatrix[2][0];
camXYZ[2][1] = identify.cameraXYZMatrix[2][1];
camXYZ[2][2] = identify.cameraXYZMatrix[2][2];
if (camXYZ.MaxEntry() == 0.0)
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: camera XYZ Matrix is null : camera not supported" ;
return FILENOTSUPPORTED;
}
matrix = camXYZ;
break;
}
case 4:
{
dng_matrix_4by3 camXYZ;
camXYZ[0][0] = identify.cameraXYZMatrix[0][0];
camXYZ[0][1] = identify.cameraXYZMatrix[0][1];
camXYZ[0][2] = identify.cameraXYZMatrix[0][2];
camXYZ[1][0] = identify.cameraXYZMatrix[1][0];
camXYZ[1][1] = identify.cameraXYZMatrix[1][1];
camXYZ[1][2] = identify.cameraXYZMatrix[1][2];
camXYZ[2][0] = identify.cameraXYZMatrix[2][0];
camXYZ[2][1] = identify.cameraXYZMatrix[2][1];
camXYZ[2][2] = identify.cameraXYZMatrix[2][2];
camXYZ[3][0] = identify.cameraXYZMatrix[3][0];
camXYZ[3][1] = identify.cameraXYZMatrix[3][1];
camXYZ[3][2] = identify.cameraXYZMatrix[3][2];
if (camXYZ.MaxEntry() == 0.0)
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: camera XYZ Matrix is null : camera not supported" ;
return FILENOTSUPPORTED;
}
matrix = camXYZ;
break;
}
}
prof->SetColorMatrix1((dng_matrix) matrix);
prof->SetCalibrationIlluminant1(lsD65);
negative->AddProfile(prof);
dng_vector camNeutral(identify.rawColors);
for (int i = 0 ; i < identify.rawColors ; ++i)
{
camNeutral[i] = 1.0/identify.cameraMult[i];
}
negative->SetCameraNeutral(camNeutral);
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Updating metadata to DNG Negative" ;
dng_exif* const exif = negative->GetExif();
exif->fModel.Set_ASCII(identify.model.toLatin1().constData());
exif->fMake.Set_ASCII(identify.make.toLatin1().constData());
QString str;
DMetadata meta;
if (meta.load(inputFile()))
{
long int num, den;
long val;
// Time from original shot
dng_date_time_info dti;
dti.SetDateTime(d->dngDateTime(meta.getItemDateTime()));
exif->fDateTimeOriginal = dti;
dti.SetDateTime(d->dngDateTime(meta.getDigitizationDateTime(true)));
exif->fDateTimeDigitized = dti;
negative->UpdateDateTime(dti);
// String Tags
str = meta.getExifTagString("Exif.Image.Make");
if (!str.isEmpty()) exif->fMake.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Image.Model");
if (!str.isEmpty()) exif->fModel.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Image.Software");
if (!str.isEmpty()) exif->fSoftware.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Image.ImageDescription");
if (!str.isEmpty()) exif->fImageDescription.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Image.Artist");
if (!str.isEmpty()) exif->fArtist.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Image.Copyright");
if (!str.isEmpty()) exif->fCopyright.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Photo.UserComment");
if (!str.isEmpty()) exif->fUserComment.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Image.CameraSerialNumber");
if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSLatitudeRef");
if (!str.isEmpty()) exif->fGPSLatitudeRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSLongitudeRef");
if (!str.isEmpty()) exif->fGPSLongitudeRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSSatellites");
if (!str.isEmpty()) exif->fGPSSatellites.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSStatus");
if (!str.isEmpty()) exif->fGPSStatus.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSMeasureMode");
if (!str.isEmpty()) exif->fGPSMeasureMode.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSSpeedRef");
if (!str.isEmpty()) exif->fGPSSpeedRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSTrackRef");
if (!str.isEmpty()) exif->fGPSTrackRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSSpeedRef");
if (!str.isEmpty()) exif->fGPSSpeedRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSImgDirectionRef");
if (!str.isEmpty()) exif->fGPSSpeedRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSMapDatum");
if (!str.isEmpty()) exif->fGPSMapDatum.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSDestLatitudeRef");
if (!str.isEmpty()) exif->fGPSDestLatitudeRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSDestLongitudeRef");
if (!str.isEmpty()) exif->fGPSDestLongitudeRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSDestBearingRef");
if (!str.isEmpty()) exif->fGPSDestBearingRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSDestDistanceRef");
if (!str.isEmpty()) exif->fGPSDestDistanceRef.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSProcessingMethod");
if (!str.isEmpty()) exif->fGPSProcessingMethod.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSAreaInformation");
if (!str.isEmpty()) exif->fGPSAreaInformation.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.GPSInfo.GPSDateStamp");
if (!str.isEmpty()) exif->fGPSDateStamp.Set_ASCII(str.trimmed().toLatin1().constData());
// Rational Tags
if (meta.getExifTagRational("Exif.Photo.ExposureTime", num, den)) exif->fExposureTime = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.FNumber", num, den)) exif->fFNumber = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.ShutterSpeedValue", num, den)) exif->fShutterSpeedValue = dng_srational(num, den);
if (meta.getExifTagRational("Exif.Photo.ApertureValue", num, den)) exif->fApertureValue = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.BrightnessValue", num, den)) exif->fBrightnessValue = dng_srational(num, den);
if (meta.getExifTagRational("Exif.Photo.ExposureBiasValue", num, den)) exif->fExposureBiasValue = dng_srational(num, den);
if (meta.getExifTagRational("Exif.Photo.MaxApertureValue", num, den)) exif->fMaxApertureValue = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.FocalLength", num, den)) exif->fFocalLength = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.DigitalZoomRatio", num, den)) exif->fDigitalZoomRatio = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.SubjectDistance", num, den)) exif->fSubjectDistance = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Image.BatteryLevel", num, den)) exif->fBatteryLevelR = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.FocalPlaneXResolution", num, den)) exif->fFocalPlaneXResolution = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Photo.FocalPlaneYResolution", num, den)) exif->fFocalPlaneYResolution = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSAltitude", num, den)) exif->fGPSAltitude = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDOP", num, den)) exif->fGPSDOP = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSSpeed", num, den)) exif->fGPSSpeed = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSTrack", num, den)) exif->fGPSTrack = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSImgDirection", num, den)) exif->fGPSImgDirection = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestBearing", num, den)) exif->fGPSDestBearing = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestDistance", num, den)) exif->fGPSDestDistance = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSLatitude", num, den, 0)) exif->fGPSLatitude[0] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSLatitude", num, den, 1)) exif->fGPSLatitude[1] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSLatitude", num, den, 2)) exif->fGPSLatitude[2] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSLongitude", num, den, 0)) exif->fGPSLongitude[0] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSLongitude", num, den, 1)) exif->fGPSLongitude[1] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSLongitude", num, den, 2)) exif->fGPSLongitude[2] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSTimeStamp", num, den, 0)) exif->fGPSTimeStamp[0] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSTimeStamp", num, den, 1)) exif->fGPSTimeStamp[1] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSTimeStamp", num, den, 2)) exif->fGPSTimeStamp[2] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestLatitude", num, den, 0)) exif->fGPSDestLatitude[0] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestLatitude", num, den, 1)) exif->fGPSDestLatitude[1] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestLatitude", num, den, 2)) exif->fGPSDestLatitude[2] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestLongitude", num, den, 0)) exif->fGPSDestLongitude[0] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestLongitude", num, den, 1)) exif->fGPSDestLongitude[1] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.GPSInfo.GPSDestLongitude", num, den, 2)) exif->fGPSDestLongitude[2] = dng_urational(num, den);
// Integer Tags
if (meta.getExifTagLong("Exif.Photo.ExposureProgram", val)) exif->fExposureProgram = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.ISOSpeedRatings", val)) exif->fISOSpeedRatings[0] = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.MeteringMode", val)) exif->fMeteringMode = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.LightSource", val)) exif->fLightSource = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.Flash", val)) exif->fFlash = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.SensingMethod", val)) exif->fSensingMethod = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.FileSource", val)) exif->fFileSource = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.SceneType", val)) exif->fSceneType = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.CustomRendered", val)) exif->fCustomRendered = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.ExposureMode", val)) exif->fExposureMode = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.WhiteBalance", val)) exif->fWhiteBalance = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.SceneCaptureType", val)) exif->fSceneCaptureType = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.GainControl", val)) exif->fGainControl = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.Contrast", val)) exif->fContrast = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.Saturation", val)) exif->fSaturation = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.Sharpness", val)) exif->fSharpness = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.SubjectDistanceRange", val)) exif->fSubjectDistanceRange = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.FocalLengthIn35mmFilm", val)) exif->fFocalLengthIn35mmFilm = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.ComponentsConfiguration", val)) exif->fComponentsConfiguration = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.PixelXDimension", val)) exif->fPixelXDimension = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.PixelYDimension", val)) exif->fPixelYDimension = (uint32)val;
if (meta.getExifTagLong("Exif.Photo.FocalPlaneResolutionUnit", val)) exif->fFocalPlaneResolutionUnit = (uint32)val;
if (meta.getExifTagLong("Exif.GPSInfo.GPSAltitudeRef", val)) exif->fGPSAltitudeRef = (uint32)val;
if (meta.getExifTagLong("Exif.GPSInfo.GPSDifferential", val)) exif->fGPSDifferential = (uint32)val;
long gpsVer1 = 0;
long gpsVer2 = 0;
long gpsVer3 = 0;
long gpsVer4 = 0;
meta.getExifTagLong("Exif.GPSInfo.GPSVersionID", gpsVer1, 0);
meta.getExifTagLong("Exif.GPSInfo.GPSVersionID", gpsVer2, 1);
meta.getExifTagLong("Exif.GPSInfo.GPSVersionID", gpsVer3, 2);
meta.getExifTagLong("Exif.GPSInfo.GPSVersionID", gpsVer4, 3);
long gpsVer = 0;
gpsVer += gpsVer1 << 24;
gpsVer += gpsVer2 << 16;
gpsVer += gpsVer3 << 8;
gpsVer += gpsVer4;
exif->fGPSVersionID = (uint32)gpsVer;
// Nikon Markernotes
if (meta.getExifTagRational("Exif.Nikon3.Lens", num, den, 0)) exif->fLensInfo[0] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Nikon3.Lens", num, den, 1)) exif->fLensInfo[1] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Nikon3.Lens", num, den, 2)) exif->fLensInfo[2] = dng_urational(num, den);
if (meta.getExifTagRational("Exif.Nikon3.Lens", num, den, 3)) exif->fLensInfo[3] = dng_urational(num, den);
if (meta.getExifTagLong("Exif.Nikon3.ISOSpeed", val, 1)) exif->fISOSpeedRatings[1] = (uint32)val;
str = meta.getExifTagString("Exif.Nikon3.SerialNO");
if (!str.isEmpty()) str = str.replace(QLatin1String("NO="), QLatin1String(""));
if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Nikon3.SerialNumber");
if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.toLatin1().constData());
if (meta.getExifTagLong("Exif.Nikon3.ShutterCount", val)) exif->fImageNumber = (uint32)val;
if (meta.getExifTagLong("Exif.NikonLd1.LensIDNumber", val)) exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
if (meta.getExifTagLong("Exif.NikonLd2.LensIDNumber", val)) exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
if (meta.getExifTagLong("Exif.NikonLd3.LensIDNumber", val)) exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
if (meta.getExifTagLong("Exif.NikonLd2.FocusDistance", val)) exif->fSubjectDistance = dng_urational((uint32)pow(10.0, val/40.0), 100);
if (meta.getExifTagLong("Exif.NikonLd3.FocusDistance", val)) exif->fSubjectDistance = dng_urational((uint32)pow(10.0, val/40.0), 100);
str = meta.getExifTagString("Exif.NikonLd1.LensIDNumber");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.NikonLd2.LensIDNumber");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.NikonLd3.LensIDNumber");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
// Canon Markernotes
if (meta.getExifTagLong("Exif.Canon.SerialNumber", val)) exif->fCameraSerialNumber.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
/*
if (meta.getExifTagLong("Exif.CanonCs.LensType", val)) exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
if (meta.getExifTagLong("Exif.CanonCs.FlashActivity", val)) exif->fFlash = (uint32)val;
if (meta.getExifTagLong("Exif.CanonFi.FileNumber", val)) exif->fImageNumber = (uint32)val;
if (meta.getExifTagLong("Exif.CanonCs.MaxAperture", val)) exif->fMaxApertureValue = dng_urational(val, 100000);
*/
if (meta.getExifTagLong("Exif.CanonCs.ExposureProgram", val))
{
switch (val)
{
case 1:
exif->fExposureProgram = 2;
break;
case 2:
exif->fExposureProgram = 4;
break;
case 3:
exif->fExposureProgram = 3;
break;
case 4:
exif->fExposureProgram = 1;
break;
default:
break;
}
}
if (meta.getExifTagLong("Exif.CanonCs.MeteringMode", val))
{
switch (val)
{
case 1:
exif->fMeteringMode = 3;
break;
case 2:
exif->fMeteringMode = 1;
break;
case 3:
exif->fMeteringMode = 5;
break;
case 4:
exif->fMeteringMode = 6;
break;
case 5:
exif->fMeteringMode = 2;
break;
default:
break;
}
}
long canonLensUnits = 1;
if (meta.getExifTagRational("Exif.CanonCs.Lens", num, den, 2)) canonLensUnits = num;
if (meta.getExifTagRational("Exif.CanonCs.Lens", num, den, 0)) exif->fLensInfo[1] = dng_urational(num, canonLensUnits);
if (meta.getExifTagRational("Exif.CanonCs.Lens", num, den, 1)) exif->fLensInfo[0] = dng_urational(num, canonLensUnits);
if (meta.getExifTagRational("Exif.Canon.FocalLength", num, den, 1)) exif->fFocalLength = dng_urational(num, canonLensUnits);
long canonLensType = 65535;
if (meta.getExifTagLong("Exif.CanonCs.LensType", canonLensType)) exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(canonLensType)).toLatin1().constData());
str = meta.getExifTagString("Exif.Canon.LensModel");
if (!str.isEmpty())
{
exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
}
else if (canonLensType != 65535)
{
str = meta.getExifTagString("Exif.CanonCs.LensType");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
}
str = meta.getExifTagString("Exif.Canon.OwnerName");
if (!str.isEmpty()) exif->fOwnerName.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Canon.FirmwareVersion");
if (!str.isEmpty()) str = str.replace(QLatin1String("Firmware"), QLatin1String(""));
if (!str.isEmpty()) str = str.replace(QLatin1String("Version"), QLatin1String(""));
if (!str.isEmpty()) exif->fFirmware.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.CanonSi.ISOSpeed");
if (!str.isEmpty()) exif->fISOSpeedRatings[1] = str.toInt();
// Pentax Markernotes
str = meta.getExifTagString("Exif.Pentax.LensType");
if (!str.isEmpty())
{
exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
exif->fLensName.TrimLeadingBlanks();
exif->fLensName.TrimTrailingBlanks();
}
long pentaxLensId1 = 0;
long pentaxLensId2 = 0;
if ((meta.getExifTagLong("Exif.Pentax.LensType", pentaxLensId1, 0)) &&
(meta.getExifTagLong("Exif.Pentax.LensType", pentaxLensId2, 1)))
{
exif->fLensID.Set_ASCII(QString::fromUtf8("%1").arg(pentaxLensId1, pentaxLensId2).toLatin1().constData());
}
// Olympus Makernotes
str = meta.getExifTagString("Exif.OlympusEq.SerialNumber");
if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.OlympusEq.LensSerialNumber");
if (!str.isEmpty()) exif->fLensSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.OlympusEq.LensModel");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
if (meta.getExifTagLong("Exif.OlympusEq.MinFocalLength", val)) exif->fLensInfo[0] = dng_urational(val, 1);
if (meta.getExifTagLong("Exif.OlympusEq.MaxFocalLength", val)) exif->fLensInfo[1] = dng_urational(val, 1);
// Panasonic Makernotes
str = meta.getExifTagString("Exif.Panasonic.LensType");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
str = meta.getExifTagString("Exif.Panasonic.LensSerialNumber");
if (!str.isEmpty()) exif->fLensSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
// Sony Makernotes
if (meta.getExifTagLong("Exif.Sony2.LensID", val))
{
exif->fLensID.Set_ASCII(QString::fromUtf8("%1").arg(val).toLatin1().constData());
}
str = meta.getExifTagString("Exif.Sony2.LensID");
if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
// -------------------------------------------
if ((exif->fLensName.IsEmpty()) && (exif->fLensInfo[0].As_real64() > 0) && (exif->fLensInfo[1].As_real64() > 0))
{
QString lensName;
QTextStream stream(&lensName);
double dval = (double)exif->fLensInfo[0].n / (double)exif->fLensInfo[0].d;
stream << QString::fromUtf8("%1").arg(dval, 0, 'f', 1);
if (exif->fLensInfo[0].As_real64() != exif->fLensInfo[1].As_real64())
{
dval = (double)exif->fLensInfo[1].n / (double)exif->fLensInfo[1].d;
stream << QString::fromUtf8("-%1").arg(dval, 0, 'f', 1);
}
stream << " mm";
if (exif->fLensInfo[2].As_real64() > 0)
{
dval = (double)exif->fLensInfo[2].n / (double)exif->fLensInfo[2].d;
stream << QString::fromUtf8(" 1/%1").arg(dval, 0, 'f', 1);
}
if ((exif->fLensInfo[3].As_real64() > 0) &&
(exif->fLensInfo[2].As_real64() != exif->fLensInfo[3].As_real64()))
{
dval = (double)exif->fLensInfo[3].n / (double)exif->fLensInfo[3].d;
stream << QString::fromUtf8("-%1").arg(dval, 0, 'f', 1);
}
exif->fLensName.Set_ASCII(lensName.toLatin1().constData());
}
// Markernote backup.
QByteArray mkrnts = meta.getExifTagData("Exif.Photo.MakerNote");
if (!mkrnts.isEmpty())
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Backup Makernote (" << mkrnts.size() << " bytes)" ;
dng_memory_allocator memalloc(gDefaultDNGMemoryAllocator);
dng_memory_stream stream(memalloc);
stream.Put(mkrnts.data(), mkrnts.size());
AutoPtr<dng_memory_block> block(host.Allocate(mkrnts.size()));
stream.SetReadPosition(0);
stream.Get(block->Buffer(), mkrnts.size());
if (identifyMake.make != QLatin1String("Canon") &&
identifyMake.make != QLatin1String("Panasonic"))
{
negative->SetMakerNote(block);
negative->SetMakerNoteSafety(true);
}
long mknOffset = 0;
QString mknByteOrder = meta.getExifTagString("Exif.MakerNote.ByteOrder");
if ((meta.getExifTagLong("Exif.MakerNote.Offset", mknOffset)) && !mknByteOrder.isEmpty())
{
dng_memory_stream streamPriv(memalloc);
streamPriv.SetBigEndian();
streamPriv.Put("Adobe", 5);
streamPriv.Put_uint8(0x00);
streamPriv.Put("MakN", 4);
streamPriv.Put_uint32(mkrnts.size() + mknByteOrder.size() + 4);
streamPriv.Put(mknByteOrder.toLatin1().constData(), mknByteOrder.size());
streamPriv.Put_uint32(mknOffset);
streamPriv.Put(mkrnts.data(), mkrnts.size());
AutoPtr<dng_memory_block> blockPriv(host.Allocate(streamPriv.Length()));
streamPriv.SetReadPosition(0);
streamPriv.Get(blockPriv->Buffer(), streamPriv.Length());
negative->SetPrivateData(blockPriv);
}
}
}
if (d->backupOriginalRawFile)
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Backup Original RAW file (" << inputInfo.size() << " bytes)";
QFileInfo originalFileInfo(inputFile());
QFile originalFile(originalFileInfo.absoluteFilePath());
if (!originalFile.open(QIODevice::ReadOnly))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Cannot open original RAW file to backup in DNG. Aborted...";
return PROCESSFAILED;
}
QDataStream originalDataStream(&originalFile);
quint32 forkLength = originalFileInfo.size();
quint32 forkBlocks = (quint32)floor((forkLength + 65535.0) / 65536.0);
QVector<quint32> offsets;
quint32 offset = (2 + forkBlocks) * sizeof(quint32);
offsets.push_back(offset);
QByteArray originalDataBlock;
originalDataBlock.resize(CHUNK);
QTemporaryFile compressedFile;
if (!compressedFile.open())
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Cannot open temporary file to write Zipped Raw data. Aborted...";
return PROCESSFAILED;
}
QDataStream compressedDataStream(&compressedFile);
for (quint32 block = 0 ; block < forkBlocks ; ++block)
{
int originalBlockLength = originalDataStream.readRawData(originalDataBlock.data(), CHUNK);
QByteArray compressedDataBlock = qCompress((const uchar*)originalDataBlock.data(), originalBlockLength, -1);
compressedDataBlock.remove(0, 4); // removes qCompress own header
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: compressed data block " << originalBlockLength << " -> " << compressedDataBlock.size();
offset += compressedDataBlock.size();
offsets.push_back(offset);
compressedDataStream.writeRawData(compressedDataBlock.data(), compressedDataBlock.size());
}
dng_memory_allocator memalloc(gDefaultDNGMemoryAllocator);
dng_memory_stream tempDataStream(memalloc);
tempDataStream.SetBigEndian(true);
tempDataStream.Put_uint32(forkLength);
for (qint32 idx = 0; idx < offsets.size(); ++idx)
{
tempDataStream.Put_uint32(offsets[idx]);
}
QByteArray compressedData;
compressedData.resize(compressedFile.size());
compressedFile.seek(0);
compressedDataStream.readRawData(compressedData.data(), compressedData.size());
tempDataStream.Put(compressedData.data(), compressedData.size());
compressedFile.remove();
originalFile.close();
tempDataStream.Put_uint32(0);
tempDataStream.Put_uint32(0);
tempDataStream.Put_uint32(0);
tempDataStream.Put_uint32(0);
tempDataStream.Put_uint32(0);
tempDataStream.Put_uint32(0);
tempDataStream.Put_uint32(0);
AutoPtr<dng_memory_block> block(host.Allocate(tempDataStream.Length()));
tempDataStream.SetReadPosition(0);
tempDataStream.Get(block->Buffer(), tempDataStream.Length());
dng_md5_printer md5;
md5.Process(block->Buffer(), block->LogicalSize());
negative->SetOriginalRawFileData(block);
negative->SetOriginalRawFileDigest(md5.Result());
negative->ValidateOriginalRawFileDigest();
}
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Build DNG Negative" ;
// Assign Raw image data.
negative->SetStage1Image(image);
// Compute linearized and range mapped image
negative->BuildStage2Image(host);
// Compute demosaiced image (used by preview and thumbnail)
negative->BuildStage3Image(host);
negative->SynchronizeMetadata();
- negative->RebuildIPTC(true, false);
+ negative->RebuildIPTC(true);
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
dng_preview_list previewList;
if (d->previewMode != DNGWriter::NONE)
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG preview image creation" ;
// Construct a preview image as TIFF format.
AutoPtr<dng_image> tiffImage;
dng_render tiff_render(host, *negative);
tiff_render.SetFinalSpace(dng_space_sRGB::Get());
tiff_render.SetFinalPixelType(ttByte);
tiff_render.SetMaximumSize(d->previewMode == MEDIUM ? 1280 : width);
tiffImage.Reset(tiff_render.Render());
dng_image_writer tiff_writer;
AutoPtr<dng_memory_stream> dms(new dng_memory_stream(gDefaultDNGMemoryAllocator));
tiff_writer.WriteTIFF(host, *dms, *tiffImage.Get(), piRGB,
ccUncompressed, negative.Get(), &tiff_render.FinalSpace());
// Write TIFF preview image data to a temp JPEG file
std::vector<char> tiff_mem_buffer(dms->Length());
dms->SetReadPosition(0);
dms->Get(&tiff_mem_buffer.front(), tiff_mem_buffer.size());
dms.Reset();
QImage pre_image;
if (!pre_image.loadFromData((uchar*)&tiff_mem_buffer.front(), tiff_mem_buffer.size(), "TIFF"))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Cannot load TIFF preview data in memory. Aborted..." ;
return PROCESSFAILED;
}
QTemporaryFile previewFile;
if (!previewFile.open())
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Cannot open temporary file to write JPEG preview. Aborted..." ;
return PROCESSFAILED;
}
if (!pre_image.save(previewFile.fileName(), "JPEG", 90))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Cannot save file to write JPEG preview. Aborted..." ;
return PROCESSFAILED;
}
// Load JPEG preview file data in DNG preview container.
AutoPtr<dng_jpeg_preview> jpeg_preview;
jpeg_preview.Reset(new dng_jpeg_preview);
jpeg_preview->fPhotometricInterpretation = piYCbCr;
jpeg_preview->fPreviewSize.v = pre_image.height();
jpeg_preview->fPreviewSize.h = pre_image.width();
jpeg_preview->fCompressedData.Reset(host.Allocate(previewFile.size()));
QDataStream previewStream( &previewFile );
previewStream.readRawData(jpeg_preview->fCompressedData->Buffer_char(), previewFile.size());
AutoPtr<dng_preview> pp( dynamic_cast<dng_preview*>(jpeg_preview.Release()) );
previewList.Append(pp);
previewFile.remove();
}
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG thumbnail creation" ;
dng_image_preview thumbnail;
dng_render thumbnail_render(host, *negative);
thumbnail_render.SetFinalSpace(dng_space_sRGB::Get());
thumbnail_render.SetFinalPixelType(ttByte);
thumbnail_render.SetMaximumSize(256);
thumbnail.fImage.Reset(thumbnail_render.Render());
if (d->cancel)
{
return PROCESSCANCELED;
}
// -----------------------------------------------------------------------------------------
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Creating DNG file " << outputInfo.fileName() ;
dng_image_writer writer;
dng_file_stream filestream(QFile::encodeName(dngFilePath).constData(), true);
- writer.WriteDNG(host, filestream, *negative.Get(), thumbnail,
- d->jpegLossLessCompression ? ccJPEG : ccUncompressed,
- &previewList);
+ /// 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);
+
+
+
+ writer.WriteDNG(host,
+ filestream,
+ *negative.Get(),
+ &previewList,
+ dngVersion_SaveDefault,
+// thumbnail,
+ d->jpegLossLessCompression
+ );
// -----------------------------------------------------------------------------------------
// Metadata makernote cleanup using Exiv2 for some RAW file types
// See bug #204437 and #210371, and write XMP Sidecar if necessary
// We disable writing to RAW files, see bug #381432
/*
if (meta.load(dngFilePath))
{
if (inputInfo.suffix().toUpper() == QLatin1String("ORF"))
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: cleanup makernotes using Exiv2" ;
meta.setWriteRawFiles(true);
meta.removeExifTag("Exif.OlympusIp.BlackLevel", false);
}
else
{
// Don't touch DNG file and create XMP sidecar depending of host application settings.
meta.setWriteRawFiles(false);
}
meta.applyChanges();
}
*/
// -----------------------------------------------------------------------------------------
// update modification time if desired
if (d->updateFileDate)
{
QDateTime date = meta.getItemDateTime();
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Setting modification date from meta data: " << date.toString();
// don't touch access time
QT_STATBUF st;
if (QT_STAT(QFile::encodeName(dngFilePath).constData(), &st) == 0)
{
struct utimbuf ut;
ut.actime = st.st_atime;
ut.modtime = date.toTime_t();
utime(QFile::encodeName(dngFilePath).constData(), &ut);
}
}
}
catch (const dng_exception& exception)
{
int ret = exception.ErrorCode();
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG SDK exception code (" << ret << ")" ;
return DNGSDKINTERNALERROR;
}
catch (...)
{
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG SDK exception code unknow" ;
return DNGSDKINTERNALERROR;
}
qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG conversion complete..." ;
return PROCESSCOMPLETE;
}
} // namespace Digikam
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.cpp
index 1952e76018..07f49dafbb 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.cpp
@@ -1,195 +1,188 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_1d_function.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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++)
+
+ for (uint32 iteration = 0; iteration < kMaxIterations; iteration++)
{
-
+
if (Abs_real64 (y1 - y0) < kNearZero)
{
break;
}
-
- real64 x2 = Pin_real64 (0.0,
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.h b/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.h
index bb76f20458..600db0307f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_1d_function.h
@@ -1,159 +1,154 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_1d_function.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.cpp
index 1f28e9985d..d9cb8189f9 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.cpp
@@ -1,195 +1,196 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_1d_table.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_1d_table.h"
#include "dng_1d_function.h"
+#include "dng_assertions.h"
#include "dng_memory.h"
#include "dng_utils.h"
/*****************************************************************************/
-dng_1d_table::dng_1d_table ()
-
- : fBuffer ()
- , fTable (NULL)
+dng_1d_table::dng_1d_table (uint32 count)
+ : fBuffer ()
+ , fTable (NULL)
+ , fTableCount (count)
+
{
+ DNG_REQUIRE (count >= kMinTableSize,
+ "count must be at least kMinTableSize");
+
+ DNG_REQUIRE ((count & (count - 1)) == 0,
+ "count must be power of 2");
+
}
/*****************************************************************************/
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));
-
+
+ bool subDivide = (range > (fTableCount >> 8));
+
if (!subDivide)
{
-
- real32 delta = Abs_real32 (fTable [upper] -
+
+ 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));
-
+
+ fTable [middle] = (real32) function.Evaluate (middle * (1.0 / (real64) fTableCount));
+
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)));
-
+
+ fBuffer.Reset (allocator.Allocate ((fTableCount + 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) *
+
+ fTable [0 ] = (real32) function.Evaluate (0.0);
+ fTable [fTableCount] = (real32) function.Evaluate (1.0);
+
+ real32 maxDelta = Max_real32 (Abs_real32 (fTable [fTableCount] -
+ fTable [0 ]), 1.0f) *
(1.0f / 256.0f);
-
+
SubDivide (function,
0,
- kTableSize,
+ fTableCount,
maxDelta);
-
+
}
-
+
else
{
-
- for (uint32 j = 0; j <= kTableSize; j++)
+
+ for (uint32 j = 0; j <= fTableCount; j++)
{
-
- real64 x = j * (1.0 / (real64) kTableSize);
-
+
+ real64 x = j * (1.0 / (real64) fTableCount);
+
real64 y = function.Evaluate (x);
-
+
fTable [j] = (real32) y;
-
+
}
-
+
}
-
- fTable [kTableSize + 1] = fTable [kTableSize];
-
+
+ fTable [fTableCount + 1] = fTable [fTableCount];
+
}
/*****************************************************************************/
void dng_1d_table::Expand16 (uint16 *table16) const
{
-
- real64 step = (real64) kTableSize / 65535.0;
-
+
+ real64 step = (real64) fTableCount / 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/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.h b/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.h
index da869f7c16..e698fd131d 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_1d_table.h
@@ -1,122 +1,126 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_1d_table.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include "dng_uncopyable.h"
/*****************************************************************************/
/// \brief A 1D floating-point lookup table using linear interpolation.
-class dng_1d_table
+class dng_1d_table: private dng_uncopyable
{
public:
- /// Constants denoting size of table.
+ /// Constant denoting minimum 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.
- };
+ static const uint32 kMinTableSize = 512;
+
+ private:
+
+ /// Constant denoting default size of table.
+ static const uint32 kDefaultTableSize = 4096;
+
protected:
-
+
AutoPtr<dng_memory_block> fBuffer;
-
+
real32 *fTable;
+ const uint32 fTableCount;
+
public:
- dng_1d_table ();
-
+ /// Table constructor. count must be a power of two
+ /// and at least kMinTableSize.
+
+ explicit dng_1d_table (uint32 count = kDefaultTableSize);
+
virtual ~dng_1d_table ();
- /// Set up table, initialize entries using function.
+ /// Number of table entries.
+
+ uint32 Count () const
+ {
+ return fTableCount;
+ }
+
+ /// 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 function.Evaluate(0.0) to function.Evaluate(1.0).
+ /// \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;
-
+
+ real32 y = x * (real32) fTableCount;
+
int32 index = (int32) y;
- DNG_ASSERT (index >= 0 && index <= kTableSize,
- "dng_1d_table::Interpolate parameter out of range");
-
+ // Enable vectorization by using DNG_ASSERT instead of DNG_REQUIRE
+ DNG_ASSERT(!(index < 0 || index >(int32) fTableCount), "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);
-
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.cpp
index fe26ee3286..ebd47a62cf 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.cpp
@@ -1,242 +1,316 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_abort_sniffer.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_abort_sniffer.h"
+#include "dng_assertions.h"
#include "dng_mutex.h"
/*****************************************************************************/
#if qDNGThreadSafe
/*****************************************************************************/
+// TO DO: This priority-based wait mechanism is not compatible with thread
+// pools. Putting worker threads to sleep may result in deadlock because
+// higher priority work may not make progress (the pool may not be able to
+// spin up any new threads).
+
class dng_priority_manager
{
-
+
private:
+ // Use lower-level mutex and condition_variable for priority manager
+ // since we don't want to include these in our priority tracking.
+
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);
+
+ void Increment (dng_priority priority,
+ const char *name);
+
+ void Decrement (dng_priority priority,
+ const char *name);
+
+ void Wait (dng_abort_sniffer *sniffer);
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")
+ : 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)
+void dng_priority_manager::Increment (dng_priority priority,
+ const char *name)
{
-
+
dng_lock_mutex lock (&fMutex);
fCounter [priority] += 1;
+ #if 0
+
+ printf ("increment priority %d (%s) (%d, %d, %d)\n",
+ (int) priority,
+ name,
+ fCounter [dng_priority_low],
+ fCounter [dng_priority_medium],
+ fCounter [dng_priority_high]);
+
+ #else
+
+ (void) name;
+
+ #endif
+
}
/*****************************************************************************/
-void dng_priority_manager::Decrement (dng_priority priority)
+void dng_priority_manager::Decrement (dng_priority priority,
+ const char *name)
{
- dng_lock_mutex lock (&fMutex);
+ dng_priority oldMin = dng_priority_minimum;
+ dng_priority newMin = dng_priority_minimum;
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ oldMin = MinPriority ();
+
+ fCounter [priority] -= 1;
- dng_priority oldMin = MinPriority ();
+ newMin = MinPriority ();
- fCounter [priority] -= 1;
+ #if 0
- dng_priority newMin = MinPriority ();
+ printf ("decrement priority %d (%s) (%d, %d, %d)\n",
+ (int) priority,
+ name,
+ fCounter [dng_priority_low],
+ fCounter [dng_priority_medium],
+ fCounter [dng_priority_high]);
+ #else
+
+ (void) name;
+
+ #endif
+
+ }
+
if (newMin < oldMin)
{
fCondition.Broadcast ();
-
+
}
-
+
}
-
+
/*****************************************************************************/
-void dng_priority_manager::Wait (dng_priority priority)
+void dng_priority_manager::Wait (dng_abort_sniffer *sniffer)
{
- if (priority < dng_priority_maximum)
+ if (!sniffer)
{
+ return;
+ }
+
+ const dng_priority priority = sniffer->Priority ();
+ if (priority < dng_priority_maximum)
+ {
+
dng_lock_mutex lock (&fMutex);
while (priority < MinPriority ())
{
-
+
fCondition.Wait (fMutex);
}
-
+
}
}
-
+
/*****************************************************************************/
static dng_priority_manager gPriorityManager;
/*****************************************************************************/
-#endif
+#endif // qDNGThreadSafe
/*****************************************************************************/
-dng_set_minimum_priority::dng_set_minimum_priority (dng_priority priority)
+dng_set_minimum_priority::dng_set_minimum_priority (dng_priority priority,
+ const char *name)
: fPriority (priority)
{
-
+
#if qDNGThreadSafe
- gPriorityManager.Increment (fPriority);
-
+ gPriorityManager.Increment (fPriority, name);
+
#endif
+ fName.Set (name);
+
}
/*****************************************************************************/
dng_set_minimum_priority::~dng_set_minimum_priority ()
{
#if qDNGThreadSafe
- gPriorityManager.Decrement (fPriority);
-
+ gPriorityManager.Decrement (fPriority, fName.Get ());
+
#endif
-
+
}
/*****************************************************************************/
-dng_abort_sniffer::dng_abort_sniffer ()
+dng_abort_sniffer::dng_abort_sniffer ()
: fPriority (dng_priority_maximum)
{
-
+
}
/*****************************************************************************/
dng_abort_sniffer::~dng_abort_sniffer ()
{
+
+ }
+
+/*****************************************************************************/
+
+void dng_abort_sniffer::SetPriority (dng_priority priority)
+ {
+
+ fPriority = priority;
}
/*****************************************************************************/
+bool dng_abort_sniffer::SupportsPriorityWait () const
+ {
+ return false;
+ }
+
+/*****************************************************************************/
+
void dng_abort_sniffer::SniffForAbort (dng_abort_sniffer *sniffer)
{
if (sniffer)
{
#if qDNGThreadSafe
- gPriorityManager.Wait (sniffer->Priority ());
+ if (sniffer->SupportsPriorityWait ())
+ {
+
+ gPriorityManager.Wait (sniffer);
+ }
+
#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/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.h b/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.h
index ce515dc75b..840277248f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_abort_sniffer.h
@@ -1,233 +1,241 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_abort_sniffer.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* Classes supporting user cancellation and progress tracking.
*/
/*****************************************************************************/
#ifndef __dng_abort_sniffer__
#define __dng_abort_sniffer__
/*****************************************************************************/
+#include "dng_classes.h"
#include "dng_flags.h"
+#include "dng_string.h"
#include "dng_types.h"
+#include "dng_uncopyable.h"
/*****************************************************************************/
-// Thread priority level.
+/// \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,
-
+ 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;
+ dng_string fName;
+
public:
-
- dng_set_minimum_priority (dng_priority priority);
-
+
+ dng_set_minimum_priority (dng_priority priority,
+ const char *name);
+
~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);
- void SetPriority (dng_priority priority)
- {
- fPriority = priority;
- }
-
- /// Check for pending user cancellation or other abort. ThrowUserCanceled
+ /// 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:
+ // Specifies whether or not this sniffer may participate in
+ // priority-based waiting (sleep the current thread on which
+ // SniffForAbort is called, if another thread has higher priority).
+ // Default result is false. Subclass must override to return true.
+
+ virtual bool SupportsPriorityWait () const;
+ 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
+class dng_sniffer_task: private dng_uncopyable
{
-
+
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 .
+ /// 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/core/libs/dngwriter/extra/dng_sdk/dng_area_task.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_area_task.cpp
index fcc290aea4..95f36b9d80 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_area_task.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_area_task.cpp
@@ -1,241 +1,324 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_area_task.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_area_task.h"
#include "dng_abort_sniffer.h"
+#include "dng_auto_ptr.h"
+#include "dng_flags.h"
+#include "dng_globals.h"
#include "dng_sdk_limits.h"
#include "dng_tile_iterator.h"
#include "dng_utils.h"
/*****************************************************************************/
-dng_area_task::dng_area_task ()
+dng_area_task::dng_area_task (const char *name)
: fMaxThreads (kMaxMPThreads)
-
+
, fMinTaskArea (256 * 256)
-
+
, fUnitCell (1, 1)
-
+
, fMaxTileSize (256, 256)
+ , fName ()
+
{
+ if (!name)
+ {
+ name = "dng_area_task";
+ }
+
+ fName.Set (name);
+
}
/*****************************************************************************/
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_rect & /* dstArea */,
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 (maxTileSize);
-
- tileSize.v = Min_int32 (tileSize.v, repeatV);
- tileSize.h = Min_int32 (tileSize.h, repeatH);
+
+ dng_point maxTileSize = MaxTileSize ();
+
+ dng_point tileSize;
+
+ tileSize.v = Min_int32 (repeatV, maxTileSize.v);
+ tileSize.h = Min_int32 (repeatH, maxTileSize.h);
+
+ // Make Xcode happy (div by zero).
+
+ tileSize.v = Max_int32 (tileSize.v, 1);
+ tileSize.h = Max_int32 (tileSize.h, 1);
+
+ // 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;
+ // Make Xcode happy (div by zero).
+
+ countV = Max_uint32 (countV, 1);
+ countH = Max_uint32 (countH, 1);
+
tileSize.v = (repeatV + countV - 1) / countV;
tileSize.h = (repeatH + countH - 1) / countH;
-
+
+ // Round up to unit cell size.
+
dng_point unitCell = UnitCell ();
-
- tileSize.v = ((tileSize.v + unitCell.v - 1) / unitCell.v) * unitCell.v;
- tileSize.h = ((tileSize.h + unitCell.h - 1) / unitCell.h) * unitCell.h;
-
+
+ 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 (gPrintTimings)
+ {
+ fprintf (stdout,
+ "\nRender tile for below: %d x %d\n",
+ (int32) tileSize.h,
+ (int32) tileSize.v);
+ }
return tileSize;
-
+
}
-
+
/*****************************************************************************/
void dng_area_task::ProcessOnThread (uint32 threadIndex,
const dng_rect &area,
const dng_point &tileSize,
- dng_abort_sniffer *sniffer)
+ dng_abort_sniffer *sniffer,
+ dng_area_task_progress *progress)
{
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))
+ // TODO_EP: Review & document case where these dynamic allocations appeared to have significant overhead
+ AutoPtr<dng_base_tile_iterator> iter1
+ (MakeTileIterator (threadIndex,
+ repeatingTile3,
+ area));
+
+ while (iter1->GetOneTile (tile1))
{
-
+
dng_rect tile2;
-
- dng_tile_iterator iter2 (repeatingTile2, tile1);
-
- while (iter2.GetOneTile (tile2))
+
+ AutoPtr<dng_base_tile_iterator> iter2
+ (MakeTileIterator (threadIndex,
+ repeatingTile2,
+ tile1));
+
+ while (iter2->GetOneTile (tile2))
{
-
+
dng_rect tile3;
-
- dng_tile_iterator iter3 (repeatingTile1, tile2);
-
- while (iter3.GetOneTile (tile3))
+
+ AutoPtr<dng_base_tile_iterator> iter3
+ (MakeTileIterator (threadIndex,
+ repeatingTile1,
+ tile2));
+
+ while (iter3->GetOneTile (tile3))
{
-
+
dng_rect tile4;
-
- dng_tile_iterator iter4 (tileSize, tile3);
-
- while (iter4.GetOneTile (tile4))
+
+ AutoPtr<dng_base_tile_iterator> iter4
+ (MakeTileIterator (threadIndex,
+ tileSize,
+ tile3));
+
+ while (iter4->GetOneTile (tile4))
{
-
+
dng_abort_sniffer::SniffForAbort (sniffer);
-
+
Process (threadIndex, tile4, sniffer);
+ if (progress)
+ {
+ progress->FinishedTile (tile4);
+ }
+
}
-
+
}
-
+
}
-
+
}
}
/*****************************************************************************/
+dng_base_tile_iterator * dng_area_task::MakeTileIterator (uint32 /* threadIndex */,
+ const dng_rect &tile,
+ const dng_rect &area) const
+ {
+
+ return new dng_tile_forward_iterator (tile, area);
+
+ }
+
+/*****************************************************************************/
+
+dng_base_tile_iterator * dng_area_task::MakeTileIterator (uint32 /* threadIndex */,
+ const dng_point &tileSize,
+ const dng_rect &area) const
+ {
+
+ return new dng_tile_forward_iterator (tileSize, area);
+
+ }
+
+/*****************************************************************************/
+
void dng_area_task::Perform (dng_area_task &task,
const dng_rect &area,
dng_memory_allocator *allocator,
- dng_abort_sniffer *sniffer)
+ dng_abort_sniffer *sniffer,
+ dng_area_task_progress *progress)
{
-
+
dng_point tileSize (task.FindTileSize (area));
-
- task.Start (1, tileSize, allocator, sniffer);
-
- task.ProcessOnThread (0, area, tileSize, sniffer);
-
+
+ task.Start (1, area, tileSize, allocator, sniffer);
+
+ task.ProcessOnThread (0, area, tileSize, sniffer, progress);
+
task.Finish (1);
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_area_task.h b/core/libs/dngwriter/extra/dng_sdk/dng_area_task.h
index 0be7026fa9..693f46196d 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_area_task.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_area_task.h
@@ -1,198 +1,286 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_area_task.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
- * Class to handle partitioning a rectangular image processing operation taking into account multiple processing resources and memory constraints.
+ * 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_string.h"
#include "dng_types.h"
+#include "dng_uncopyable.h"
/*****************************************************************************/
-/// \brief Abstract class for rectangular processing operations with support for partitioning across multiple processing resources and observing memory constraints.
+class dng_area_task_progress: private dng_uncopyable
+ {
+
+ public:
+
+ virtual ~dng_area_task_progress ()
+ {
+ }
+
+ virtual void FinishedTile (const dng_rect & /* tile */) = 0;
+
+ };
+
+/*****************************************************************************/
+
+/// \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;
+ dng_string fName;
+
public:
-
- dng_area_task ();
-
+
+ explicit dng_area_task (const char *name = "unnamed dng_area_task");
+
virtual ~dng_area_task ();
- /// Getter for the maximum number of threads (resources) that can be used for processing
+ const char * Name () const
+ {
+ return fName.Get ();
+ }
+
+ /// 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 overridden for a specific task to indicate the smallest
- /// area for partitioning. Default is 256x256 pixels.
+ /// 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 partitioned tile in order to give performant operation. (Partitions can be smaller due to small inputs and edge cases.)
+ /// \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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
-
+ /// 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.
+ /// 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 threadCount Total number of threads that will be used for processing.
+ /// Less than or equal to MaxThreads.
+ /// \param dstArea Area to be processed in the current run of the 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_rect &dstArea,
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.
+ /// 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 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.
+ /// \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.
+
+ /// 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.
+ /// 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 tileSize size of tiles to use for processing.
/// \param sniffer dng_abort_sniffer to use to check for user cancellation and progress updates.
+ /// \param progress optional pointer to progress reporting object.
void ProcessOnThread (uint32 threadIndex,
const dng_rect &area,
const dng_point &tileSize,
- dng_abort_sniffer *sniffer);
+ dng_abort_sniffer *sniffer,
+ dng_area_task_progress *progress);
+
+ /// Factory method to make a tile iterator. This iterator will be used
+ /// by a thread to process tiles in an area in a specific order. The
+ /// default implementation uses a forward iterator that visits tiles
+ /// from left to right (inner), top down (outer). Subclasses can
+ /// override this method to produce tile iterators that visit tiles in
+ /// different orders.
+ ///
+ /// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
+ /// \param tile The tile to be traversed within the tile area.
+ /// \param area Tile area partitioned to this resource.
- /// 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 .
+ virtual dng_base_tile_iterator * MakeTileIterator (uint32 threadIndex,
+ const dng_rect &tile,
+ const dng_rect &area) const;
+
+ /// Factory method to make a tile iterator. This iterator will be used
+ /// by a thread to process tiles in an area in a specific order. The
+ /// default implementation uses a forward iterator that visits tiles
+ /// from left to right (inner), top down (outer). Subclasses can
+ /// override this method to produce tile iterators that visit tiles in
+ /// different orders.
+ ///
+ /// \param threadIndex 0 to threadCount - 1 index indicating which thread this is.
+ /// \param tileSize The tile size to be traversed within the tile area.
+ /// \param area Tile area partitioned to this resource.
+
+ virtual dng_base_tile_iterator * MakeTileIterator (uint32 threadIndex,
+ const dng_point &tileSize,
+ const dng_rect &area) const;
+
+ /// 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.
+ /// \param progress optional pointer to progress reporting object.
static void Perform (dng_area_task &task,
const dng_rect &area,
dng_memory_allocator *allocator,
- dng_abort_sniffer *sniffer);
+ dng_abort_sniffer *sniffer,
+ dng_area_task_progress *progress);
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_assertions.h b/core/libs/dngwriter/extra/dng_sdk/dng_assertions.h
index 4a2dae1099..4a34612813 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_assertions.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_assertions.h
@@ -1,131 +1,128 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_assertions.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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.
+/// Platform-specific function to display an assert.
+
void dng_show_message (const char *s);
-// Show a formatted error message.
+/// 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_show_message (msg); \
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_auto_ptr.h b/core/libs/dngwriter/extra/dng_sdk/dng_auto_ptr.h
index 1d40611bcd..651fa3b1cd 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_auto_ptr.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_auto_ptr.h
@@ -1,157 +1,239 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_auto_ptr.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
- * Class to implement std::auto_ptr like functionality even on platforms which do not have a full Standard C++ library.
+ * 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>
+
+#include "dng_uncopyable.h"
+
/*****************************************************************************/
-// The following template has similar functionality to the STL auto_ptr,
-// without requiring all the weight of STL.
+// 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.
+/// \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
+class AutoPtr: private dng_uncopyable
{
-
+
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.
+ /// \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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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_; }
-
- 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);
-
+
+ /// 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;
+ }
+
};
/*****************************************************************************/
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: private dng_uncopyable
+ {
+
+ 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 an array pointer is owned, it is deleted. Ownership is
+ /// taken of the passed in pointer p_.
+ /// \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:
+
+ // Owned pointer or NULL.
+
+ T *p;
+
+ };
+
+/*****************************************************************************/
+
#endif
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.cpp
index a5b9fe54d5..810c36e092 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.cpp
@@ -1,1836 +1,1853 @@
/*****************************************************************************/
-// Copyright 2008 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_bad_pixels.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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
+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", 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", 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;
+ count = Max_uint32 (count, 1); // Suppress div-by-zero warning.
+ 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];
-
- est0 = g13 + g75;
-
+
+ // 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;
-
+
+ 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;
-
+
+ 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 (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;
+
+ 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 (g46 - g53) +
Abs_int32 (r38 - r52) +
Abs_int32 (r36 - r50);
-
- est5 = g35 + g53;
-
+
+ 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;
-
+
+ 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;
+ count = Max_uint32 (count, 1); // Suppress div-by-zero warning.
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.h b/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.h
index fd3ca042e4..69554ad338 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_bad_pixels.h
@@ -1,227 +1,303 @@
/*****************************************************************************/
-// Copyright 2008 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_bad_pixels.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_memory.h"
#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 ((row + col + fBayerPhase + (fBayerPhase >> 1)) & 1) == 0;
+ 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;
-
+
+ dng_std_vector<dng_point> fBadPoints;
+
// List of bad rectangles (usually single rows or columns).
-
- std::vector<dng_rect> fBadRects;
-
+
+ dng_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 r 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/core/libs/dngwriter/extra/dng_sdk/dng_big_table.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_big_table.cpp
new file mode 100644
index 0000000000..b2bfdcff04
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_big_table.cpp
@@ -0,0 +1,1950 @@
+/*****************************************************************************/
+// Copyright 2015-2019 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 "dng_big_table.h"
+
+#include "dng_memory_stream.h"
+#include "dng_mutex.h"
+#include "dng_stream.h"
+#include "dng_xmp.h"
+
+#include "zlib.h"
+
+#include <map>
+
+/*****************************************************************************/
+
+class dng_big_table_cache
+ {
+
+ private:
+
+ dng_std_mutex fMutex;
+
+ typedef std::pair <dng_fingerprint,
+ int32> RefCountsPair;
+
+ typedef std::map <dng_fingerprint,
+ int32,
+ dng_fingerprint_less_than> RefCountsMap;
+
+ RefCountsMap fRefCounts;
+
+ std::vector<dng_fingerprint> fRecentlyUsed;
+
+ protected:
+
+ enum
+ {
+ kDefaultRecentlyUsedLimit = 5
+ };
+
+ uint32 fRecentlyUsedLimit;
+
+ protected:
+
+ dng_big_table_cache ();
+
+ void UseTable (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint);
+
+ virtual void CacheIncrement (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint);
+
+ virtual void CacheDecrement (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint);
+
+ virtual void CacheAdd (dng_lock_std_mutex &lock,
+ const dng_big_table &table);
+
+ virtual bool CacheExtract (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table);
+
+ virtual void InsertTableData (dng_lock_std_mutex &lock,
+ const dng_big_table &table) = 0;
+
+ virtual void EraseTableData (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint) = 0;
+
+ virtual void ExtractTableData (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table) = 0;
+
+ public:
+
+ virtual ~dng_big_table_cache ();
+
+ void FlushRecentlyUsed ();
+
+ static void Increment (dng_big_table_cache *cache,
+ const dng_fingerprint &fingerprint);
+
+ static void Decrement (dng_big_table_cache *cache,
+ const dng_fingerprint &fingerprint);
+
+ static void Add (dng_big_table_cache *cache,
+ const dng_big_table &table);
+
+ static bool Extract (dng_big_table_cache *cache,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table);
+
+ };
+
+/*****************************************************************************/
+
+dng_big_table_cache::dng_big_table_cache ()
+
+ : fMutex ()
+
+ , fRefCounts ()
+
+ , fRecentlyUsed ()
+ , fRecentlyUsedLimit (kDefaultRecentlyUsedLimit)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table_cache::~dng_big_table_cache ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::UseTable (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint)
+ {
+
+ // See if fingerprint is in recently used list.
+
+ int32 lastIndex = (int32) fRecentlyUsed.size () - 1;
+
+ for (int32 index = lastIndex; index >= 0; index--)
+ {
+
+ if (fingerprint == fRecentlyUsed [index])
+ {
+
+ // Move to end of list if not already there.
+
+ if (index != lastIndex)
+ {
+
+ fRecentlyUsed.erase (fRecentlyUsed.begin () + index);
+
+ fRecentlyUsed.push_back (fingerprint);
+
+ }
+
+ // Item is in recently used list, so we are done.
+
+ return;
+
+ }
+
+ }
+
+ // Is the recently used list full?
+
+ if (fRecentlyUsed.size () == fRecentlyUsedLimit)
+ {
+
+ CacheDecrement (lock, fRecentlyUsed.front ());
+
+ fRecentlyUsed.erase (fRecentlyUsed.begin ());
+
+ }
+
+ // Add to end of list.
+
+ fRecentlyUsed.push_back (fingerprint);
+
+ CacheIncrement (lock, fingerprint);
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::FlushRecentlyUsed ()
+ {
+
+ dng_lock_std_mutex lock (fMutex);
+
+ while (!fRecentlyUsed.empty ())
+ {
+
+ CacheDecrement (lock, fRecentlyUsed.back ());
+
+ fRecentlyUsed.pop_back ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::CacheIncrement (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint)
+ {
+
+ if (fingerprint.IsValid ())
+ {
+
+ RefCountsMap::iterator it = fRefCounts.find (fingerprint);
+
+ if (it == fRefCounts.end ())
+ {
+
+ DNG_REPORT ("dng_big_table_cache::CacheIncrement"
+ "fingerprint not in cache");
+
+ }
+
+ else
+ {
+
+ it->second++;
+
+ UseTable (lock, fingerprint);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::CacheDecrement (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint)
+ {
+
+ if (fingerprint.IsValid ())
+ {
+
+ RefCountsMap::iterator it = fRefCounts.find (fingerprint);
+
+ if (it == fRefCounts.end ())
+ {
+
+ DNG_REPORT ("dng_big_table_cache::CacheDecrement"
+ "fingerprint not in cache");
+
+ }
+
+ else if (--(it->second) == 0)
+ {
+
+ fRefCounts.erase (it);
+
+ EraseTableData (lock, fingerprint);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::CacheAdd (dng_lock_std_mutex &lock,
+ const dng_big_table &table)
+ {
+
+ if (table.Fingerprint ().IsValid ())
+ {
+
+ RefCountsMap::iterator it = fRefCounts.find (table.Fingerprint ());
+
+ if (it == fRefCounts.end ())
+ {
+
+ fRefCounts.insert (RefCountsPair (table.Fingerprint (), 1));
+
+ InsertTableData (lock, table);
+
+ }
+
+ else
+ {
+
+ it->second++;
+
+ }
+
+ UseTable (lock, table.Fingerprint ());
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table_cache::CacheExtract (dng_lock_std_mutex &lock,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table)
+ {
+
+ if (fingerprint.IsValid ())
+ {
+
+ RefCountsMap::iterator it = fRefCounts.find (fingerprint);
+
+ if (it != fRefCounts.end ())
+ {
+
+ it->second++;
+
+ ExtractTableData (lock, fingerprint, table);
+
+ UseTable (lock, fingerprint);
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::Increment (dng_big_table_cache *cache,
+ const dng_fingerprint &fingerprint)
+ {
+
+ if (cache)
+ {
+
+ dng_lock_std_mutex lock (cache->fMutex);
+
+ cache->CacheIncrement (lock, fingerprint);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::Decrement (dng_big_table_cache *cache,
+ const dng_fingerprint &fingerprint)
+ {
+
+ if (cache)
+ {
+
+ dng_lock_std_mutex lock (cache->fMutex);
+
+ cache->CacheDecrement (lock, fingerprint);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_cache::Add (dng_big_table_cache *cache,
+ const dng_big_table &table)
+ {
+
+ if (cache)
+ {
+
+ dng_lock_std_mutex lock (cache->fMutex);
+
+ cache->CacheAdd (lock, table);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table_cache::Extract (dng_big_table_cache *cache,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table)
+ {
+
+ if (cache)
+ {
+
+ dng_lock_std_mutex lock (cache->fMutex);
+
+ return cache->CacheExtract (lock, fingerprint, table);
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+class dng_look_table_cache : public dng_big_table_cache
+ {
+
+ private:
+
+ typedef std::pair <dng_fingerprint,
+ dng_look_table::table_data> TableDataPair;
+
+ typedef std::map <dng_fingerprint,
+ dng_look_table::table_data,
+ dng_fingerprint_less_than> TableDataMap;
+
+ TableDataMap fTableData;
+
+ public:
+
+ dng_look_table_cache ()
+
+ : fTableData ()
+
+ {
+ }
+
+ virtual void InsertTableData (dng_lock_std_mutex & /* lock */,
+ const dng_big_table &table)
+ {
+
+ const dng_look_table *lookTable = static_cast
+ <const dng_look_table *>
+ (&table);
+
+ fTableData.insert (TableDataPair (lookTable->Fingerprint (),
+ lookTable->fData));
+
+ }
+
+ virtual void EraseTableData (dng_lock_std_mutex & /* lock */,
+ const dng_fingerprint &fingerprint)
+ {
+
+ TableDataMap::iterator it = fTableData.find (fingerprint);
+
+ if (it != fTableData.end ())
+ {
+
+ fTableData.erase (it);
+
+ }
+
+ else
+ {
+
+ DNG_REPORT ("dng_look_table_cache::EraseTableData"
+ "fingerprint not in cache");
+
+ }
+
+ }
+
+ virtual void ExtractTableData (dng_lock_std_mutex & /* lock */,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table)
+ {
+
+ TableDataMap::iterator it = fTableData.find (fingerprint);
+
+ if (it != fTableData.end ())
+ {
+
+ dng_look_table *lookTable = static_cast
+ <dng_look_table *>
+ (&table);
+
+ lookTable->fData = it->second;
+
+ }
+
+ else
+ {
+
+ DNG_REPORT ("dng_look_table_cache::ExtractTableData"
+ "fingerprint not in cache");
+
+ }
+
+ }
+
+ };
+
+static dng_look_table_cache gLookTableCache;
+
+/*****************************************************************************/
+
+class dng_rgb_table_cache : public dng_big_table_cache
+ {
+
+ private:
+
+ typedef std::pair <dng_fingerprint,
+ dng_rgb_table::table_data> TableDataPair;
+
+ typedef std::map <dng_fingerprint,
+ dng_rgb_table::table_data,
+ dng_fingerprint_less_than> TableDataMap;
+
+ TableDataMap fTableData;
+
+ public:
+
+ dng_rgb_table_cache ()
+
+ : fTableData ()
+
+ {
+ }
+
+ virtual void InsertTableData (dng_lock_std_mutex & /* lock */,
+ const dng_big_table &table)
+ {
+
+ const dng_rgb_table *rgbTable = static_cast
+ <const dng_rgb_table *>
+ (&table);
+
+ fTableData.insert (TableDataPair (rgbTable->Fingerprint (),
+ rgbTable->fData));
+
+ }
+
+ virtual void EraseTableData (dng_lock_std_mutex & /* lock */,
+ const dng_fingerprint &fingerprint)
+ {
+
+ TableDataMap::iterator it = fTableData.find (fingerprint);
+
+ if (it != fTableData.end ())
+ {
+
+ fTableData.erase (it);
+
+ }
+
+ else
+ {
+
+ DNG_REPORT ("dng_rgb_table_cache::EraseTableData"
+ "fingerprint not in cache");
+
+ }
+
+ }
+
+ virtual void ExtractTableData (dng_lock_std_mutex & /* lock */,
+ const dng_fingerprint &fingerprint,
+ dng_big_table &table)
+ {
+
+ TableDataMap::iterator it = fTableData.find (fingerprint);
+
+ if (it != fTableData.end ())
+ {
+
+ dng_rgb_table *rgbTable = static_cast
+ <dng_rgb_table *>
+ (&table);
+
+ rgbTable->fData = it->second;
+
+ }
+
+ else
+ {
+
+ DNG_REPORT ("dng_rgb_table_cache::ExtractTableData"
+ "fingerprint not in cache");
+
+ }
+
+ }
+
+ };
+
+static dng_rgb_table_cache gRGBTableCache;
+
+/*****************************************************************************/
+
+void dng_big_table_cache_flush ()
+ {
+
+ gLookTableCache.FlushRecentlyUsed ();
+
+ gRGBTableCache.FlushRecentlyUsed ();
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table::dng_big_table (dng_big_table_cache *cache)
+
+ : fFingerprint ()
+ , fCache (cache)
+ , fIsMissing (false)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table::dng_big_table (const dng_big_table &table)
+
+ : fFingerprint (table.fFingerprint)
+ , fCache (table.fCache )
+ , fIsMissing (false )
+
+ {
+
+ dng_big_table_cache::Increment (fCache, fFingerprint);
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table & dng_big_table::operator= (const dng_big_table &table)
+ {
+
+ if (fFingerprint != table.fFingerprint ||
+ fCache != table.fCache )
+ {
+
+ dng_big_table_cache::Decrement (fCache, fFingerprint);
+
+ fFingerprint = table.fFingerprint;
+ fCache = table.fCache;
+
+ dng_big_table_cache::Increment (fCache, fFingerprint);
+
+ }
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table::~dng_big_table ()
+ {
+
+ dng_big_table_cache::Decrement (fCache, fFingerprint);
+
+ }
+
+/*****************************************************************************/
+
+const dng_fingerprint & dng_big_table::Fingerprint () const
+ {
+
+ return fFingerprint;
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table::RecomputeFingerprint ()
+ {
+
+ dng_big_table_cache::Decrement (fCache, fFingerprint);
+
+ fFingerprint.Clear ();
+
+ if (IsValid ())
+ {
+
+ {
+
+ dng_md5_printer_stream stream;
+
+ stream.SetLittleEndian ();
+
+ PutStream (stream, true);
+
+ fFingerprint = stream.Result ();
+
+ }
+
+ // Try extract first to force sharing of table data memory if
+ // table data is already in cache.
+
+ if (!dng_big_table_cache::Extract (fCache, fFingerprint, *this))
+ {
+
+ // Otherwise add to cache.
+
+ dng_big_table_cache::Add (fCache, *this);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table::DecodeFromBinary (const uint8 *compressedData,
+ uint32 compressedSize,
+ dng_memory_allocator &allocator)
+ {
+
+ // Decompress the data.
+
+ AutoPtr<dng_memory_block> block3;
+
+ {
+
+ if (compressedSize < 5)
+ {
+ return false;
+ }
+
+ // Uncompressed size is stored in first four bytes of decoded data,
+ // little endian order.
+
+ uint32 uncompressedSize = (((uint32) compressedData [0]) ) +
+ (((uint32) compressedData [1]) << 8) +
+ (((uint32) compressedData [2]) << 16) +
+ (((uint32) compressedData [3]) << 24);
+
+ block3.Reset (allocator.Allocate (uncompressedSize));
+
+ uLongf destLen = uncompressedSize;
+
+ int zResult = ::uncompress (block3->Buffer_uint8 (),
+ &destLen,
+ compressedData + 4,
+ compressedSize - 4);
+
+ if (zResult != Z_OK)
+ {
+ return false;
+ }
+
+ }
+
+ // Now read in the table data from the uncompressed stream.
+
+ {
+
+ dng_stream stream (block3->Buffer (),
+ block3->LogicalSize ());
+
+ stream.SetLittleEndian ();
+
+ GetStream (stream);
+
+ block3.Reset ();
+
+ }
+
+ // Force recomputation of fingerprint.
+
+ RecomputeFingerprint ();
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table::DecodeFromString (const dng_string &block1,
+ dng_memory_allocator &allocator)
+ {
+
+ // Decode the text to binary.
+
+ AutoPtr<dng_memory_block> block2;
+
+ uint32 compressedSize = 0;
+
+ {
+
+ // This binary to text encoding is very similar to the Z85
+ // encoding, but the exact charactor set has been adjusted to
+ // encode more cleanly into XMP.
+
+ static uint8 kDecodeTable [96] =
+ {
+
+ 0xFF, // space
+ 0x44, // !
+ 0xFF, // "
+ 0x54, // #
+ 0x53, // $
+ 0x52, // %
+ 0xFF, // &
+ 0x49, // '
+ 0x4B, // (
+ 0x4C, // )
+ 0x46, // *
+ 0x41, // +
+ 0xFF, // ,
+ 0x3F, // -
+ 0x3E, // .
+ 0x45, // /
+
+ 0x00, 0x01, 0x02, 0x03, 0x04, // 01234
+ 0x05, 0x06, 0x07, 0x08, 0x09, // 56789
+
+ 0x40, // :
+ 0xFF, // ;
+ 0xFF, // <
+ 0x42, // =
+ 0xFF, // >
+ 0x47, // ?
+ 0x51, // @
+
+ 0x24, 0x25, 0x26, 0x27, 0x28, // ABCDE
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, // FGHIJ
+ 0x2E, 0x2F, 0x30, 0x31, 0x32, // KLMNO
+ 0x33, 0x34, 0x35, 0x36, 0x37, // PQRST
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, // UVWXY
+ 0x3D, // Z
+
+ 0x4D, // [
+ 0xFF, // backslash
+ 0x4E, // ]
+ 0x43, // ^
+ 0xFF, // _
+ 0x48, // `
+
+ 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // abcde
+ 0x0F, 0x10, 0x11, 0x12, 0x13, // fghij
+ 0x14, 0x15, 0x16, 0x17, 0x18, // klmno
+ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, // pqrst
+ 0x1E, 0x1F, 0x20, 0x21, 0x22, // uvwxy
+ 0x23, // z
+
+ 0x4F, // {
+ 0x4A, // |
+ 0x50, // }
+ 0xFF, // ~
+ 0xFF // del
+
+ };
+
+ uint32 encodedSize = block1.Length ();
+
+ uint32 maxCompressedSize = (encodedSize + 4) / 5 * 4;
+
+ block2.Reset (allocator.Allocate (maxCompressedSize));
+
+ uint32 phase = 0;
+ uint32 value;
+
+ uint8 *dPtr = block2->Buffer_uint8 ();
+
+ for (const char *sPtr = block1.Get (); *sPtr; sPtr++)
+ {
+
+ uint8 e = (uint8) *sPtr;
+
+ if (e < 32 || e > 127)
+ {
+ continue;
+ }
+
+ uint32 d = kDecodeTable [e - 32];
+
+ if (d > 85)
+ {
+ continue;
+ }
+
+ phase++;
+
+ if (phase == 1)
+ {
+ value = d;
+ }
+
+ else if (phase == 2)
+ {
+ value += d * 85;
+ }
+
+ else if (phase == 3)
+ {
+ value += d * (85 * 85);
+ }
+
+ else if (phase == 4)
+ {
+ value += d * (85 * 85 * 85);
+ }
+
+ else
+ {
+
+ value += d * (85 * 85 * 85 * 85);
+
+ dPtr [0] = (uint8) (value );
+ dPtr [1] = (uint8) (value >> 8);
+ dPtr [2] = (uint8) (value >> 16);
+ dPtr [3] = (uint8) (value >> 24);
+
+ dPtr += 4;
+
+ compressedSize += 4;
+
+ phase = 0;
+
+ }
+
+ }
+
+ if (phase > 3)
+ {
+
+ dPtr [2] = (uint8) (value >> 16);
+
+ compressedSize++;
+
+ }
+
+ if (phase > 2)
+ {
+
+ dPtr [1] = (uint8) (value >> 8);
+
+ compressedSize++;
+
+ }
+
+ if (phase > 1)
+ {
+
+ dPtr [0] = (uint8) (value);
+
+ compressedSize++;
+
+ }
+
+ }
+
+ return DecodeFromBinary (block2->Buffer_uint8 (),
+ compressedSize,
+ allocator);
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block* dng_big_table::EncodeAsBinary (dng_memory_allocator &allocator,
+ uint32 &compressedSize) const
+ {
+
+ // Stream to a binary block..
+
+ AutoPtr<dng_memory_block> block1;
+
+ {
+
+ dng_memory_stream stream (allocator);
+
+ stream.SetLittleEndian ();
+
+ PutStream (stream, false);
+
+ block1.Reset (stream.AsMemoryBlock (allocator));
+
+ }
+
+ // Compress the block.
+
+ AutoPtr<dng_memory_block> block2;
+
+ {
+
+ uint32 uncompressedSize = block1->LogicalSize ();
+
+ uint32 safeCompressedSize = uncompressedSize + (uncompressedSize >> 8) + 64;
+
+ block2.Reset (allocator.Allocate (safeCompressedSize + 4));
+
+ // Store uncompressed size in first four bytes of compressed block.
+
+ uint8 *dPtr = block2->Buffer_uint8 ();
+
+ dPtr [0] = (uint8) (uncompressedSize );
+ dPtr [1] = (uint8) (uncompressedSize >> 8);
+ dPtr [2] = (uint8) (uncompressedSize >> 16);
+ dPtr [3] = (uint8) (uncompressedSize >> 24);
+
+ uLongf dCount = safeCompressedSize;
+
+ int zResult = ::compress2 (dPtr + 4,
+ &dCount,
+ block1->Buffer_uint8 (),
+ uncompressedSize,
+ Z_DEFAULT_COMPRESSION);
+
+ if (zResult != Z_OK)
+ {
+ ThrowMemoryFull ();
+ }
+
+ compressedSize = (uint32) dCount + 4;
+
+ block1.Reset ();
+
+ }
+
+ return block2.Release ();
+
+ }
+
+/*****************************************************************************/
+
+dng_memory_block* dng_big_table::EncodeAsString (dng_memory_allocator &allocator) const
+ {
+
+ // Get compressed binary data.
+
+ uint32 compressedSize;
+
+ AutoPtr<dng_memory_block> block2 (EncodeAsBinary (allocator, compressedSize));
+
+ // Encode binary to text.
+
+ AutoPtr<dng_memory_block> block3;
+
+ {
+
+ // This binary to text encoding is very similar to the Z85
+ // encoding, but the exact charactor set has been adjusted to
+ // encode more cleanly into XMP.
+
+ static const char *kEncodeTable =
+ "0123456789"
+ "abcdefghij"
+ "klmnopqrst"
+ "uvwxyzABCD"
+ "EFGHIJKLMN"
+ "OPQRSTUVWX"
+ "YZ.-:+=^!/"
+ "*?`'|()[]{"
+ "}@%$#";
+
+ uint32 safeEncodedSize = compressedSize +
+ (compressedSize >> 2) +
+ (compressedSize >> 6) +
+ 16;
+
+ block3.Reset (allocator.Allocate (safeEncodedSize));
+
+ uint8 *sPtr = block2->Buffer_uint8 ();
+
+ sPtr [compressedSize ] = 0;
+ sPtr [compressedSize + 1] = 0;
+ sPtr [compressedSize + 2] = 0;
+
+ uint8 *dPtr = block3->Buffer_uint8 ();
+
+ while (compressedSize)
+ {
+
+ uint32 x0 = (((uint32) sPtr [0]) ) +
+ (((uint32) sPtr [1]) << 8) +
+ (((uint32) sPtr [2]) << 16) +
+ (((uint32) sPtr [3]) << 24);
+
+ sPtr += 4;
+
+ uint32 x1 = x0 / 85;
+
+ *dPtr++ = kEncodeTable [x0 - x1 * 85];
+
+ uint32 x2 = x1 / 85;
+
+ *dPtr++ = kEncodeTable [x1 - x2 * 85];
+
+ if (!--compressedSize)
+ break;
+
+ uint32 x3 = x2 / 85;
+
+ *dPtr++ = kEncodeTable [x2 - x3 * 85];
+
+ if (!--compressedSize)
+ break;
+
+ uint32 x4 = x3 / 85;
+
+ *dPtr++ = kEncodeTable [x3 - x4 * 85];
+
+ if (!--compressedSize)
+ break;
+
+ *dPtr++ = kEncodeTable [x4];
+
+ compressedSize--;
+
+ }
+
+ *dPtr = 0;
+
+ block2.Reset ();
+
+ }
+
+ return block3.Release ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table::ExtractFromCache (const dng_fingerprint &fingerprint)
+ {
+
+ if (dng_big_table_cache::Extract (fCache, fingerprint, *this))
+ {
+
+ fFingerprint = fingerprint;
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table::ReadTableFromXMP (const dng_xmp &xmp,
+ const char *ns,
+ const dng_fingerprint &fingerprint)
+ {
+
+ // Read in the table data.
+
+ dng_string tablePath;
+
+ tablePath.Set ("Table_");
+
+ tablePath.Append (dng_xmp::EncodeFingerprint (fingerprint).Get ());
+
+ dng_string block1;
+
+ if (!xmp.GetString (ns,
+ tablePath.Get (),
+ block1))
+ {
+
+ DNG_REPORT ("Missing big table data");
+
+ return false;
+
+ }
+
+ bool ok = DecodeFromString (block1,
+ xmp.Allocator ());
+
+ block1.Clear ();
+
+ // Validate fingerprint match.
+
+ DNG_ASSERT (Fingerprint () == fingerprint,
+ "dng_big_table fingerprint mismatch");
+
+ // It worked!
+
+ return ok;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table::ReadFromXMP (const dng_xmp &xmp,
+ const char *ns,
+ const char *path,
+ dng_big_table_storage &storage)
+ {
+
+ dng_fingerprint fingerprint;
+
+ if (!xmp.GetFingerprint (ns, path, fingerprint))
+ {
+
+ return false;
+
+ }
+
+ // See if we can skip reading the table data, and just grab from cache.
+
+ if (ExtractFromCache (fingerprint))
+ {
+
+ return true;
+
+ }
+
+ // Next see if we can get the table from the storage object.
+
+ if (storage.ReadTable (*this, fingerprint, xmp.Allocator ()))
+ {
+
+ return true;
+
+ }
+
+ // Read in the table data.
+
+ if (ReadTableFromXMP (xmp, ns, fingerprint))
+ {
+
+ return true;
+
+ }
+
+ // Unable to find table data anywhere. Notify storage object.
+
+ storage.MissingTable (fingerprint);
+
+ // Also make a note that this table is missing.
+
+ SetMissing ();
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table::WriteToXMP (dng_xmp &xmp,
+ const char *ns,
+ const char *path,
+ dng_big_table_storage &storage) const
+ {
+
+ const dng_fingerprint &fingerprint = Fingerprint ();
+
+ if (!fingerprint.IsValid () || IsMissing ())
+ {
+
+ xmp.Remove (ns, path);
+
+ return;
+
+ }
+
+ xmp.SetFingerprint (ns, path, fingerprint);
+
+ // See if we can just use the storage object to store the table.
+
+ if (storage.WriteTable (*this, fingerprint, xmp.Allocator ()))
+ {
+
+ return;
+
+ }
+
+ dng_string tablePath;
+
+ tablePath.Set ("Table_");
+
+ tablePath.Append (dng_xmp::EncodeFingerprint (fingerprint).Get ());
+
+ if (xmp.Exists (ns, tablePath.Get ()))
+ {
+
+ return;
+
+ }
+
+ AutoPtr<dng_memory_block> block;
+
+ block.Reset (EncodeAsString (xmp.Allocator ()));
+
+ xmp.Set (ns,
+ tablePath.Get (),
+ block->Buffer_char ());
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table_storage::dng_big_table_storage ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_big_table_storage::~dng_big_table_storage ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table_storage::ReadTable (dng_big_table & /* table */,
+ const dng_fingerprint & /* fingerprint */,
+ dng_memory_allocator & /* allocator */)
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_big_table_storage::WriteTable (const dng_big_table & /* table */,
+ const dng_fingerprint & /* fingerprint */,
+ dng_memory_allocator & /* allocator */)
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_big_table_storage::MissingTable (const dng_fingerprint & /* fingerprint */)
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_look_table::dng_look_table ()
+
+ : dng_big_table (&gLookTableCache)
+
+ , fData ()
+ , fAmount (1.0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_look_table::dng_look_table (const dng_look_table &table)
+
+ : dng_big_table (table)
+
+ , fData (table.fData)
+ , fAmount (table.fAmount)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_look_table & dng_look_table::operator= (const dng_look_table &table)
+ {
+
+ dng_big_table::operator= (table);
+
+ fData = table.fData;
+ fAmount = table.fAmount;
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+dng_look_table::~dng_look_table ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_look_table::Set (const dng_hue_sat_map &map,
+ uint32 encoding)
+ {
+
+ fData.fMap = map;
+ fData.fEncoding = encoding;
+
+ fData.ComputeMonochrome ();
+
+ RecomputeFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_look_table::IsValid () const
+ {
+
+ if (IsMissing ())
+ {
+ return false;
+ }
+
+ return fData.fMap.IsValid ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_look_table::SetInvalid ()
+ {
+
+ *this = dng_look_table ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_look_table::GetStream (dng_stream &stream)
+ {
+
+ table_data data;
+
+ if (stream.Get_uint32 () != btt_LookTable)
+ {
+ ThrowBadFormat ("Not a look table");
+ }
+
+ uint32 version = stream.Get_uint32 ();
+
+ if (version != kLookTableVersion1 &&
+ version != kLookTableVersion2)
+ {
+ ThrowBadFormat ("Unknown look table version");
+ }
+
+ uint32 hueDivisions = stream.Get_uint32 ();
+ uint32 satDivisions = stream.Get_uint32 ();
+ uint32 valDivisions = stream.Get_uint32 ();
+
+ if (hueDivisions < 1 || hueDivisions > kMaxHueSamples ||
+ satDivisions < 1 || satDivisions > kMaxSatSamples ||
+ valDivisions < 1 || valDivisions > kMaxValSamples ||
+ (dng_safe_uint32 (hueDivisions) *
+ dng_safe_uint32 (satDivisions) *
+ dng_safe_uint32 (valDivisions)).Get () > kMaxTotalSamples)
+ {
+ ThrowBadFormat ();
+ }
+
+ data.fMap.SetDivisions (hueDivisions,
+ satDivisions,
+ valDivisions);
+
+ uint32 count = data.fMap.DeltasCount ();
+
+ dng_hue_sat_map::HSBModify * deltas = data.fMap.GetDeltas ();
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ deltas->fHueShift = stream.Get_real32 ();
+ deltas->fSatScale = stream.Get_real32 ();
+ deltas->fValScale = stream.Get_real32 ();
+
+ deltas++;
+
+ }
+
+ data.fMap.AssignNewUniqueRuntimeFingerprint ();
+
+ data.fEncoding = stream.Get_uint32 ();
+
+ if (data.fEncoding != encoding_Linear &&
+ data.fEncoding != encoding_sRGB)
+ {
+ ThrowBadFormat ("Unknown look table encoding");
+ }
+
+ if (version != kLookTableVersion1)
+ {
+
+ data.fMinAmount = stream.Get_real64 ();
+ data.fMaxAmount = stream.Get_real64 ();
+
+ if (data.fMinAmount < 0.0 || data.fMinAmount > 1.0 || data.fMaxAmount < 1.0)
+ {
+ ThrowBadFormat ("Invalid min/max amount for look table");
+ }
+
+ }
+
+ else
+ {
+
+ data.fMinAmount = 1.0;
+ data.fMaxAmount = 1.0;
+
+ }
+
+ data.ComputeMonochrome ();
+
+ fData = data;
+
+ }
+
+/*****************************************************************************/
+
+void dng_look_table::PutStream (dng_stream &stream,
+ bool /* forFingerprint */) const
+ {
+
+ DNG_REQUIRE (IsValid (), "Invalid Look Table");
+
+ stream.Put_uint32 (btt_LookTable);
+
+ uint32 version = kLookTableVersion1;
+
+ if (fData.fMinAmount != 1.0 ||
+ fData.fMaxAmount != 1.0)
+ {
+ version = kLookTableVersion2;
+ }
+
+ stream.Put_uint32 (version);
+
+ uint32 hueDivisions;
+ uint32 satDivisions;
+ uint32 valDivisions;
+
+ fData.fMap.GetDivisions (hueDivisions,
+ satDivisions,
+ valDivisions);
+
+ stream.Put_uint32 (hueDivisions);
+ stream.Put_uint32 (satDivisions);
+ stream.Put_uint32 (valDivisions);
+
+ uint32 count = fData.fMap.DeltasCount ();
+
+ const dng_hue_sat_map::HSBModify * deltas = fData.fMap.GetConstDeltas ();
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ stream.Put_real32 (deltas->fHueShift);
+ stream.Put_real32 (deltas->fSatScale);
+ stream.Put_real32 (deltas->fValScale);
+
+ deltas++;
+
+ }
+
+ stream.Put_uint32 (fData.fEncoding);
+
+ if (version != kLookTableVersion1)
+ {
+
+ stream.Put_real64 (fData.fMinAmount);
+ stream.Put_real64 (fData.fMaxAmount);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_rgb_table::dng_rgb_table ()
+
+ : dng_big_table (&gRGBTableCache)
+
+ , fData ()
+ , fAmount (1.0)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_rgb_table::dng_rgb_table (const dng_rgb_table &table)
+
+ : dng_big_table (table)
+
+ , fData (table.fData)
+ , fAmount (table.fAmount)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_rgb_table & dng_rgb_table::operator= (const dng_rgb_table &table)
+ {
+
+ dng_big_table::operator= (table);
+
+ fData = table.fData;
+ fAmount = table.fAmount;
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+dng_rgb_table::~dng_rgb_table ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_rgb_table::IsValid () const
+ {
+
+ if (IsMissing ())
+ {
+ return false;
+ }
+
+ // If table itself is invalid, then invalid.
+
+ if (fData.fDimensions == 0)
+ return false;
+
+ // If table has some effect, then valid.
+
+ if (fAmount > 0.0)
+ return true;
+
+ // Does the matrix itself do any clipping?
+
+ if (fData.fPrimaries == primaries_ProPhoto ||
+ fData.fGamut == gamut_extend )
+ return false;
+
+ // Table is a NOP but there is some gamut clipping.
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_rgb_table::SetInvalid ()
+ {
+
+ *this = dng_rgb_table ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_rgb_table::Set (uint32 dimensions,
+ uint32 divisions,
+ dng_ref_counted_block samples)
+ {
+
+ if (dimensions == 1)
+ {
+
+ if (divisions < kMinDivisions1D ||
+ divisions > kMaxDivisions1D)
+ {
+
+ ThrowProgramError ("Bad 1D divisions");
+
+ }
+
+ if (samples.LogicalSize () != divisions * 4 * sizeof (uint16))
+ {
+
+ ThrowProgramError ("Bad 1D sample count");
+
+ }
+
+ }
+
+ else if (dimensions == 3)
+ {
+
+ if (divisions < kMinDivisions3D ||
+ divisions > kMaxDivisions3D_InMemory)
+ {
+
+ ThrowProgramError ("Bad 3D divisions");
+
+ }
+
+ if (samples.LogicalSize () != divisions *
+ divisions *
+ divisions * 4 * sizeof (uint16))
+ {
+
+ ThrowProgramError ("Bad 3D sample count");
+
+ }
+
+ }
+
+ else
+ {
+
+ ThrowProgramError ("Bad dimensions");
+
+ }
+
+ fData.fDimensions = dimensions;
+
+ fData.fDivisions = divisions;
+
+ fData.fSamples = samples;
+
+ fData.ComputeMonochrome ();
+
+ RecomputeFingerprint ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_rgb_table::GetStream (dng_stream &stream)
+ {
+
+ table_data data;
+
+ if (stream.Get_uint32 () != btt_RGBTable)
+ {
+ ThrowBadFormat ("Not a RGB table");
+ }
+
+ if (stream.Get_uint32 () != kRGBTableVersion)
+ {
+ ThrowBadFormat ("Unknown RGB table version");
+ }
+
+ data.fDimensions = stream.Get_uint32 ();
+
+ data.fDivisions = stream.Get_uint32 ();
+
+ if (data.fDimensions == 1)
+ {
+
+ if (data.fDivisions < kMinDivisions1D ||
+ data.fDivisions > kMaxDivisions1D)
+ {
+ ThrowBadFormat ("Invalid 1D divisions");
+ }
+
+ }
+
+ else if (data.fDimensions == 3)
+ {
+
+ if (data.fDivisions < kMinDivisions3D ||
+ data.fDivisions > kMaxDivisions3D)
+ {
+ ThrowBadFormat ("Invalid 3D divisions");
+ }
+
+ }
+
+ else
+ {
+ ThrowBadFormat ("Invalid dimensions");
+ }
+
+ uint16 nopValue [kMaxDivisions1D > kMaxDivisions3D ? kMaxDivisions1D
+ : kMaxDivisions3D];
+
+ for (uint32 index = 0; index < data.fDivisions; index++)
+ {
+
+ nopValue [index] = (uint16)
+ ((index * 0x0FFFF + (data.fDivisions >> 1)) /
+ (data.fDivisions - 1));
+
+ }
+
+ if (data.fDimensions == 1)
+ {
+
+ data.fSamples.Allocate (data.fDivisions * 4 * sizeof (uint16));
+
+ uint16 *samples = data.fSamples.Buffer_uint16 ();
+
+ for (uint32 index = 0; index < data.fDivisions; index++)
+ {
+
+ samples [0] = stream.Get_uint16 () + nopValue [index];
+ samples [1] = stream.Get_uint16 () + nopValue [index];
+ samples [2] = stream.Get_uint16 () + nopValue [index];
+ samples [3] = 0;
+
+ samples += 4;
+
+ }
+
+ }
+
+ else
+ {
+
+ data.fSamples.Allocate (data.fDivisions *
+ data.fDivisions *
+ data.fDivisions * 4 * sizeof (uint16));
+
+ uint16 *samples = data.fSamples.Buffer_uint16 ();
+
+ for (uint32 rIndex = 0; rIndex < data.fDivisions; rIndex++)
+ {
+
+ for (uint32 gIndex = 0; gIndex < data.fDivisions; gIndex++)
+ {
+
+ for (uint32 bIndex = 0; bIndex < data.fDivisions; bIndex++)
+ {
+
+ samples [0] = stream.Get_uint16 () + nopValue [rIndex];
+ samples [1] = stream.Get_uint16 () + nopValue [gIndex];
+ samples [2] = stream.Get_uint16 () + nopValue [bIndex];
+ samples [3] = 0;
+
+ samples += 4;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ uint32 primaries = stream.Get_uint32 ();
+
+ if (primaries >= primaries_count)
+ {
+ ThrowBadFormat ("Unknown RGB table primaries");
+ }
+
+ data.fPrimaries = (primaries_enum) primaries;
+
+ uint32 gamma = stream.Get_uint32 ();
+
+ if (gamma >= gamma_count)
+ {
+ ThrowBadFormat ("Unknown RGB table gamma");
+ }
+
+ data.fGamma = (gamma_enum) gamma;
+
+ uint32 gamut = stream.Get_uint32 ();
+
+ if (gamut >= gamut_count)
+ {
+ ThrowBadFormat ("Unknown RGB table gamut processing option");
+ }
+
+ data.fGamut = (gamut_enum) gamut;
+
+ data.fMinAmount = stream.Get_real64 ();
+ data.fMaxAmount = stream.Get_real64 ();
+
+ if (data.fMinAmount < 0.0 || data.fMinAmount > 1.0 || data.fMaxAmount < 1.0)
+ {
+ ThrowBadFormat ("Invalid min/max amount for RGB table");
+ }
+
+ data.ComputeMonochrome ();
+
+ fData = data;
+
+ }
+
+/*****************************************************************************/
+
+void dng_rgb_table::PutStream (dng_stream &stream,
+ bool /* forFingerprint */) const
+ {
+
+ DNG_REQUIRE (IsValid (), "Invalid RGB Table");
+
+ stream.Put_uint32 (btt_RGBTable);
+
+ stream.Put_uint32 (kRGBTableVersion);
+
+ stream.Put_uint32 (fData.fDimensions);
+
+ stream.Put_uint32 (fData.fDivisions);
+
+ uint16 nopValue [kMaxDivisions1D > kMaxDivisions3D_InMemory ? kMaxDivisions1D
+ : kMaxDivisions3D_InMemory];
+
+ for (uint32 index = 0; index < fData.fDivisions; index++)
+ {
+
+ nopValue [index] = (uint16)
+ ((index * 0x0FFFF + (fData.fDivisions >> 1)) /
+ (fData.fDivisions - 1));
+
+ }
+
+ const uint16 *samples = fData.fSamples.Buffer_uint16 ();
+
+ if (fData.fDimensions == 1)
+ {
+
+ for (uint32 index = 0; index < fData.fDivisions; index++)
+ {
+
+ stream.Put_uint16 (samples [0] - nopValue [index]);
+ stream.Put_uint16 (samples [1] - nopValue [index]);
+ stream.Put_uint16 (samples [2] - nopValue [index]);
+
+ samples += 4;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 rIndex = 0; rIndex < fData.fDivisions; rIndex++)
+ {
+
+ for (uint32 gIndex = 0; gIndex < fData.fDivisions; gIndex++)
+ {
+
+ for (uint32 bIndex = 0; bIndex < fData.fDivisions; bIndex++)
+ {
+
+ stream.Put_uint16 (samples [0] - nopValue [rIndex]);
+ stream.Put_uint16 (samples [1] - nopValue [gIndex]);
+ stream.Put_uint16 (samples [2] - nopValue [bIndex]);
+
+ samples += 4;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ stream.Put_uint32 ((uint32) fData.fPrimaries);
+
+ stream.Put_uint32 ((uint32) fData.fGamma);
+
+ stream.Put_uint32 ((uint32) fData.fGamut);
+
+ stream.Put_real64 (fData.fMinAmount);
+ stream.Put_real64 (fData.fMaxAmount);
+
+ }
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_big_table.h b/core/libs/dngwriter/extra/dng_sdk/dng_big_table.h
new file mode 100644
index 0000000000..a1ae678a1c
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_big_table.h
@@ -0,0 +1,670 @@
+/*****************************************************************************/
+// Copyright 2015-2019 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 __dng_big_table__
+#define __dng_big_table__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_camera_profile.h"
+
+/*****************************************************************************/
+
+class dng_big_table_cache;
+class dng_big_table_storage;
+
+/*****************************************************************************/
+
+void dng_big_table_cache_flush ();
+
+/*****************************************************************************/
+
+class dng_big_table
+ {
+
+ protected:
+
+ enum BigTableTypeEnum
+ {
+ btt_LookTable = 0,
+ btt_RGBTable = 1
+ };
+
+ private:
+
+ dng_fingerprint fFingerprint;
+
+ dng_big_table_cache * fCache;
+
+ bool fIsMissing;
+
+ protected:
+
+ dng_big_table (dng_big_table_cache *cache);
+
+ dng_big_table (const dng_big_table &table);
+
+ dng_big_table & operator= (const dng_big_table &table);
+
+ public:
+
+ virtual ~dng_big_table ();
+
+ bool IsMissing () const
+ {
+ return fIsMissing;
+ }
+
+ void SetMissing ()
+ {
+ fIsMissing = true;
+ }
+
+ virtual bool IsValid () const = 0;
+
+ const dng_fingerprint & Fingerprint () const;
+
+ bool DecodeFromBinary (const uint8 * compressedData,
+ uint32 compressedSize,
+ dng_memory_allocator &allocator);
+
+ bool DecodeFromString (const dng_string &block1,
+ dng_memory_allocator &allocator);
+
+ dng_memory_block * EncodeAsBinary (dng_memory_allocator &allocator,
+ uint32 &compressedSize) const;
+
+ dng_memory_block * EncodeAsString (dng_memory_allocator &allocator) const;
+
+ bool ExtractFromCache (const dng_fingerprint &fingerprint);
+
+ bool ReadTableFromXMP (const dng_xmp &xmp,
+ const char *ns,
+ const dng_fingerprint &fingerprint);
+
+ bool ReadFromXMP (const dng_xmp &xmp,
+ const char *ns,
+ const char *path,
+ dng_big_table_storage &storage);
+
+ void WriteToXMP (dng_xmp &xmp,
+ const char *ns,
+ const char *path,
+ dng_big_table_storage &storage) const;
+
+ protected:
+
+ void RecomputeFingerprint ();
+
+ virtual void GetStream (dng_stream &stream) = 0;
+
+ virtual void PutStream (dng_stream &stream,
+ bool forFingerprint) const = 0;
+
+ };
+
+/*****************************************************************************/
+
+class dng_big_table_storage
+ {
+
+ public:
+
+ dng_big_table_storage ();
+
+ virtual ~dng_big_table_storage ();
+
+ virtual bool ReadTable (dng_big_table &table,
+ const dng_fingerprint &fingerprint,
+ dng_memory_allocator &allocator);
+
+ virtual bool WriteTable (const dng_big_table &table,
+ const dng_fingerprint &fingerprint,
+ dng_memory_allocator &allocator);
+
+ virtual void MissingTable (const dng_fingerprint &fingerprint);
+
+ };
+
+/*****************************************************************************/
+
+class dng_look_table : public dng_big_table
+ {
+
+ friend class dng_look_table_cache;
+
+ public:
+
+ enum
+ {
+
+ // Tables are are allowed to trade off resolution
+ // between dimensions, but need to keep total
+ // samples below this limit. This results in
+ // 216K memory footprint (12 byte per sample)
+ // which is similar in size to the RGB table
+ // size limit.
+
+ kMaxTotalSamples = 36 * 32 * 16,
+
+ // Also each must be within their own limits.
+
+ kMaxHueSamples = 360,
+ kMaxSatSamples = 256,
+ kMaxValSamples = 256
+
+ };
+
+ private:
+
+ enum
+ {
+ kLookTableVersion1 = 1,
+ kLookTableVersion2 = 2
+ };
+
+ // Table data affecting fingerprint and caching.
+
+ struct table_data
+ {
+
+ // 3-D hue/sat table to apply a "look".
+
+ dng_hue_sat_map fMap;
+
+ // Value (V of HSV) encoding for look table.
+
+ uint32 fEncoding;
+
+ // Minimum and maximum scale amounts supported by table.
+
+ real64 fMinAmount;
+ real64 fMaxAmount;
+
+ // Does this table have only monochrome output (when amount is 1.0)?
+
+ bool fMonochrome;
+
+ // Constructor to set defaults.
+
+ table_data ()
+
+ : fMap ()
+ , fEncoding (encoding_Linear)
+ , fMinAmount (1.0)
+ , fMaxAmount (1.0)
+ , fMonochrome (false)
+
+ {
+ }
+
+ // Compute monchrome flag.
+
+ void ComputeMonochrome ()
+ {
+
+ fMonochrome = true;
+
+ uint32 count = fMap.DeltasCount ();
+
+ dng_hue_sat_map::HSBModify * deltas = fMap.GetDeltas ();
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ if (deltas [index] . fSatScale != 0.0f)
+ {
+
+ fMonochrome = false;
+
+ return;
+
+ }
+
+ }
+
+ }
+
+ };
+
+ table_data fData;
+
+ // Amount to apply at runtime (does not affect fingerprint).
+
+ real64 fAmount;
+
+ public:
+
+ dng_look_table ();
+
+ dng_look_table (const dng_look_table &table);
+
+ dng_look_table & operator= (const dng_look_table &table);
+
+ virtual ~dng_look_table ();
+
+ bool operator== (const dng_look_table &table) const
+ {
+ return Fingerprint () == table.Fingerprint () &&
+ Amount () == table.Amount () &&
+ IsMissing () == table.IsMissing ();
+ }
+
+ bool operator!= (const dng_look_table &table) const
+ {
+ return !(*this == table);
+ }
+
+ void Set (const dng_hue_sat_map &map,
+ uint32 encoding);
+
+ virtual bool IsValid () const;
+
+ void SetInvalid ();
+
+ real64 MinAmount () const
+ {
+ return fData.fMinAmount;
+ }
+
+ real64 MaxAmount () const
+ {
+ return fData.fMaxAmount;
+ }
+
+ void SetAmountRange (real64 minAmount,
+ real64 maxAmount)
+ {
+
+ fData.fMinAmount = Pin_real64 (0.0,
+ Round_int32 (minAmount * 100.0) * 0.01,
+ 1.0);
+
+ fData.fMaxAmount = Pin_real64 (1.0,
+ Round_int32 (maxAmount * 100.0) * 0.01,
+ 2.0);
+
+ fAmount = Pin_real64 (fData.fMinAmount, fAmount, fData.fMaxAmount);
+
+ RecomputeFingerprint ();
+
+ }
+
+ real64 Amount () const
+ {
+ return fAmount;
+ }
+
+ void SetAmount (real64 amount)
+ {
+
+ fAmount = Pin_real64 (fData.fMinAmount,
+ Round_int32 (amount * 100.0) * 0.01,
+ fData.fMaxAmount);
+
+ // Not part of fingerprint.
+
+ }
+
+ const dng_hue_sat_map & Map () const
+ {
+ return fData.fMap;
+ }
+
+ uint32 Encoding () const
+ {
+ return fData.fEncoding;
+ }
+
+ bool Monochrome () const
+ {
+ return IsValid () && fAmount == 1.0 && fData.fMonochrome;
+ }
+
+ protected:
+
+ virtual void GetStream (dng_stream &stream);
+
+ virtual void PutStream (dng_stream &stream,
+ bool forFingerprint) const;
+
+ };
+
+/*****************************************************************************/
+
+class dng_rgb_table : public dng_big_table
+ {
+
+ friend class dng_rgb_table_cache;
+
+ public:
+
+ enum
+ {
+
+ kMinDivisions1D = 2,
+ kMaxDivisions1D = 4096,
+
+ kMinDivisions3D = 2,
+ kMaxDivisions3D = 32,
+
+ kMaxDivisions3D_InMemory = 128
+
+ };
+
+ enum primaries_enum
+ {
+
+ primaries_sRGB = 0,
+ primaries_Adobe,
+ primaries_ProPhoto,
+ primaries_P3,
+ primaries_Rec2020,
+
+ primaries_count
+
+ };
+
+ enum gamma_enum
+ {
+
+ gamma_Linear = 0,
+ gamma_sRGB,
+ gamma_1_8,
+ gamma_2_2,
+ gamma_Rec2020,
+
+ gamma_count
+
+ };
+
+ enum gamut_enum
+ {
+
+ gamut_clip = 0,
+ gamut_extend,
+
+ gamut_count
+
+ };
+
+ private:
+
+ enum
+ {
+ kRGBTableVersion = 1
+ };
+
+ // Table data affecting fingerprint and caching.
+
+ struct table_data
+ {
+
+ // Number of dimensions of the table (1 or 3).
+
+ uint32 fDimensions;
+
+ // Number of samples per side of table.
+
+ uint32 fDivisions;
+
+ // Sample data. 16-bit unsigned encoding.
+ // Right zero padded to 64 bits per sample (i.e. RGB0).
+
+ dng_ref_counted_block fSamples;
+
+ // Color primaries for table.
+
+ primaries_enum fPrimaries;
+
+ // Gamma encoding for table.
+
+ gamma_enum fGamma;
+
+ // Gamut processing option for table.
+
+ gamut_enum fGamut;
+
+ // Minimum and maximum scale amounts supported by table.
+
+ real64 fMinAmount;
+ real64 fMaxAmount;
+
+ // Does this table have only monochrome output (when amount is 1.0)?
+
+ bool fMonochrome;
+
+ // Constructor to set defaults.
+
+ table_data ()
+
+ : fDimensions (0)
+ , fDivisions (0)
+ , fSamples ()
+ , fPrimaries (primaries_sRGB)
+ , fGamma (gamma_sRGB)
+ , fGamut (gamut_clip)
+ , fMinAmount (0.0)
+ , fMaxAmount (2.0)
+ , fMonochrome (false)
+
+ {
+ }
+
+ // Compute monchrome flag.
+
+ void ComputeMonochrome ()
+ {
+
+ if (fPrimaries != primaries_ProPhoto &&
+ fGamut != gamut_clip)
+ {
+
+ fMonochrome = false;
+
+ return;
+
+ }
+
+ if (fDimensions != 3)
+ {
+
+ fMonochrome = false;
+
+ return;
+
+ }
+
+ fMonochrome = true;
+
+ uint32 count = fDivisions * fDivisions * fDivisions;
+
+ const uint16 * sample = fSamples.Buffer_uint16 ();
+
+ for (uint32 index = 0; index < count; index++)
+ {
+
+ if (sample [0] != sample [1] ||
+ sample [0] != sample [2])
+ {
+
+ fMonochrome = false;
+
+ return;
+
+ }
+
+ sample += 4;
+
+ }
+
+ }
+
+ };
+
+ table_data fData;
+
+ // Amount to apply at runtime (does not affect fingerprint).
+
+ real64 fAmount;
+
+ public:
+
+ dng_rgb_table ();
+
+ dng_rgb_table (const dng_rgb_table &table);
+
+ dng_rgb_table & operator= (const dng_rgb_table &table);
+
+ virtual ~dng_rgb_table ();
+
+ bool operator== (const dng_rgb_table &table) const
+ {
+ return Fingerprint () == table.Fingerprint () &&
+ Amount () == table.Amount () &&
+ IsMissing () == table.IsMissing ();
+ }
+
+ bool operator!= (const dng_rgb_table &table) const
+ {
+ return !(*this == table);
+ }
+
+ virtual bool IsValid () const;
+
+ void SetInvalid ();
+
+ primaries_enum Primaries () const
+ {
+ return fData.fPrimaries;
+ }
+
+ void SetPrimaries (primaries_enum primaries)
+ {
+
+ fData.fPrimaries = primaries;
+
+ fData.ComputeMonochrome ();
+
+ RecomputeFingerprint ();
+
+ }
+
+ gamma_enum Gamma () const
+ {
+ return fData.fGamma;
+ }
+
+ void SetGamma (gamma_enum gamma)
+ {
+
+ fData.fGamma = gamma;
+
+ RecomputeFingerprint ();
+
+ }
+
+ gamut_enum Gamut () const
+ {
+ return fData.fGamut;
+ }
+
+ void SetGamut (gamut_enum gamut)
+ {
+
+ fData.fGamut = gamut;
+
+ fData.ComputeMonochrome ();
+
+ RecomputeFingerprint ();
+
+ }
+
+ real64 MinAmount () const
+ {
+ return fData.fMinAmount;
+ }
+
+ real64 MaxAmount () const
+ {
+ return fData.fMaxAmount;
+ }
+
+ void SetAmountRange (real64 minAmount,
+ real64 maxAmount)
+ {
+
+ fData.fMinAmount = Pin_real64 (0.0,
+ Round_int32 (minAmount * 100.0) * 0.01,
+ 1.0);
+
+ fData.fMaxAmount = Pin_real64 (1.0,
+ Round_int32 (maxAmount * 100.0) * 0.01,
+ 2.0);
+
+ fAmount = Pin_real64 (fData.fMinAmount, fAmount, fData.fMaxAmount);
+
+ RecomputeFingerprint ();
+
+ }
+
+ real64 Amount () const
+ {
+ return fAmount;
+ }
+
+ void SetAmount (real64 amount)
+ {
+
+ fAmount = Pin_real64 (fData.fMinAmount,
+ Round_int32 (amount * 100.0) * 0.01,
+ fData.fMaxAmount);
+
+ // Not part of fingerprint.
+
+ }
+
+ uint32 Dimensions () const
+ {
+ return fData.fDimensions;
+ }
+
+ uint32 Divisions () const
+ {
+ return fData.fDivisions;
+ }
+
+ const uint16 * Samples () const
+ {
+ return fData.fSamples.Buffer_uint16 ();
+ }
+
+ bool Monochrome () const
+ {
+ return IsValid () && fAmount == 1.0 && fData.fMonochrome;
+ }
+
+ void Set (uint32 dimensions,
+ uint32 divisions,
+ dng_ref_counted_block samples);
+
+ protected:
+
+ virtual void GetStream (dng_stream &stream);
+
+ virtual void PutStream (dng_stream &stream,
+ bool forFingerprint) const;
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.cpp
index 04fbee2f31..4c857eff09 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.cpp
@@ -1,71 +1,66 @@
/*****************************************************************************/
-// Copyright 2006-2009 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_bottlenecks.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_bottlenecks.h"
#include "dng_reference.h"
/*****************************************************************************/
dng_suite gDNGSuite =
{
RefZeroBytes,
RefCopyBytes,
RefSwapBytes16,
RefSwapBytes32,
RefSetArea8,
- RefSetArea16,
- RefSetArea32,
+ RefSetArea<Scalar, uint16>,
+ RefSetArea<Scalar, uint32>,
RefCopyArea8,
RefCopyArea16,
RefCopyArea32,
RefCopyArea8_16,
RefCopyArea8_S16,
RefCopyArea8_32,
- RefCopyArea16_S16,
+ RefCopyArea16_S16<Scalar>,
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,
- RefMapArea16
+ RefVignette32,
+ RefMapArea16,
+ RefBaselineMapPoly32
};
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.h b/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.h
index fbba1c3ee6..6405c9255d 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_bottlenecks.h
@@ -1,1670 +1,1752 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_bottlenecks.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_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,
+ uint16 blackLevel);
+
+/*****************************************************************************/
+
typedef void (MapArea16Proc)
(uint16 *dPtr,
uint32 count0,
uint32 count1,
uint32 count2,
int32 step0,
int32 step1,
int32 step2,
const uint16 *map);
/*****************************************************************************/
-struct dng_suite
+typedef void (BaselineMapPoly32Proc)
+ (real32 *dPtr,
+ const int32 rowStep,
+ const uint32 rows,
+ const uint32 cols,
+ const uint32 rowPitch,
+ const uint32 colPitch,
+ const real32 *coefficients,
+ const uint32 degree,
+ uint16 blackLevel);
+
+/*****************************************************************************/
+
+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_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;
+ BaselineMapPoly32Proc *BaselineMapPoly32;
};
/*****************************************************************************/
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_hue_sat_map &lut,
+ const dng_1d_table *encodeTable,
+ const dng_1d_table *decodeTable)
{
-
+
(gDNGSuite.BaselineHueSatMap) (sPtrR,
sPtrG,
sPtrB,
dPtrR,
dPtrG,
dPtrB,
count,
- lut);
-
+ 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,
+ uint16 blackLevel)
+ {
+
+ (gDNGSuite.Vignette32) (sPtr,
+ mPtr,
+ rows,
+ cols,
+ planes,
+ sRowStep,
+ sPlaneStep,
+ mRowStep,
+ mBits,
+ blackLevel);
+
+ }
+
+/*****************************************************************************/
+
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
+inline void DoBaselineMapPoly32 (real32 *dPtr,
+ const int32 rowStep,
+ const uint32 rows,
+ const uint32 cols,
+ const uint32 rowPitch,
+ const uint32 colPitch,
+ const real32 *coefficients,
+ const uint32 degree,
+ uint16 blackLevel)
+ {
+
+ (gDNGSuite.BaselineMapPoly32) (dPtr,
+ rowStep,
+ rows,
+ cols,
+ rowPitch,
+ colPitch,
+ coefficients,
+ degree,
+ blackLevel);
+
+ }
/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.cpp
index 87f0b1a514..81e470f8bc 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.cpp
@@ -1,1261 +1,1434 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_camera_profile.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 + 5400.0) * 0.5;
+ return (4600.0 + 5500.0) * 0.5;
}
-
+
case lsCoolWhiteFluorescent:
case lsFluorescent:
{
- return (3900.0 + 4500.0) * 0.5;
+ return (3800.0 + 4500.0) * 0.5;
}
-
+
case lsWhiteFluorescent:
{
- return (3200.0 + 3700.0) * 0.5;
+ 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 (fLookTable.IsValid ())
+ if (haveHueSat1 || haveHueSat2)
{
+ if (fHueSatMapEncoding != 0)
+ {
+
+ printer.Put_uint32 (fHueSatMapEncoding);
+
+ }
+
+ }
+
+ if (fLookTable.IsValid ())
+ {
+
FingerprintHueSatMap (printer, fLookTable);
+ if (fLookTableEncoding != 0)
+ {
+
+ printer.Put_uint32 (fLookTableEncoding);
+
+ }
+
}
- if (fToneCurve.IsValid ())
+ 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)
+dng_fingerprint dng_camera_profile::UniqueID () const
{
- const real64 kThreshold = 0.01;
+ dng_md5_printer_stream printer;
+
+ // MD5 hash is always calculated on little endian data.
+ printer.SetLittleEndian ();
+
+ // Start with the existing fingerprint.
+
+ if (!fFingerprint.IsValid ())
+ CalculateFingerprint ();
+
+ printer.Put (fFingerprint.data,
+ (uint32) sizeof (fFingerprint.data));
+
+ // Also include the UniqueCameraModelRestriction tag.
+
+ printer.Put (fUniqueCameraModelRestriction.Get (),
+ fUniqueCameraModelRestriction.Length ());
+
+ // Add any other needed fields here.
+
+ // ...
+
+ return 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 invertible.
-
+
+ // Make sure ColorMatrix1 is invertable.
+
try
{
-
+
if (fReductionMatrix1.NotEmpty ())
{
-
+
(void) Invert (fColorMatrix1,
fReductionMatrix1);
-
+
}
-
+
else
{
-
+
(void) Invert (fColorMatrix1);
-
+
}
-
+
}
-
+
catch (...)
{
-
+
#if qDNGValidate
-
- ReportError ("ColorMatrix1 is not invertible");
-
+
+ ReportError ("ColorMatrix1 is not invertable");
+
#endif
-
+
return false;
-
+
}
-
- // Make sure ColorMatrix2 is invertible.
-
+
+ // 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 invertible");
-
+
+ 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 &&
- fLookTable == profile.fLookTable &&
- fToneCurve == profile.fToneCurve &&
- fProfileCalibrationSignature == profile.fProfileCalibrationSignature;
+ 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);
-
+
}
-
+
}
-
+
}
+ hueSatMap.AssignNewUniqueRuntimeFingerprint ();
+
}
/*****************************************************************************/
+DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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;
+ if (points > kMaxToneCurvePoints)
+ {
+ ThrowProgramError ("Too many tone curve points");
+ }
+
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 == 7 && baseName.StartsWith ("ACR ", true))
+ {
+
+ if (name.Get () [len - 3] >= '0' &&
+ name.Get () [len - 3] <= '9' &&
+ name.Get () [len - 2] == '.' &&
+ name.Get () [len - 1] >= '0' &&
+ name.Get () [len - 1] <= '9')
+
+ baseName.Truncate (3);
+
+ version = ((int32) (name.Get () [len - 3] - '0')) * 10 +
+ ((int32) (name.Get () [len - 1] - '0'));
+
+ return;
+
+ }
+
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/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.h b/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.h
index 4157e05379..fc2a00a0b2 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_camera_profile.h
@@ -1,656 +1,879 @@
/******************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_camera_profile.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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
+ * 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
+ * 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);
}
- dng_camera_profile_id (const dng_string &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 id 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 id 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.
+
+ // 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.
- // 3-D hue/sat table to apply a "look".
+ uint32 fHueSatMapEncoding;
+ // 3-D hue/sat table to apply a "look".
+
dng_hue_sat_map fLookTable;
- // The "as shot" tone curve for this profile. Check IsValid method
+ // 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.
+
+ /// 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.
+
+ /// 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.
+
+ /// 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.
+
+ /// 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 required to support four-color cameras.
+ /// 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 required to support four-color cameras.
+ /// 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 unique ID. Use this ID for uniquely
+ /// identifying profiles (e.g., for syncing purposes).
+
+ dng_fingerprint UniqueID () const;
+
/// 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.
+ /// \retval 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);
+ ClearFingerprint ();
}
+ /// 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/core/libs/dngwriter/extra/dng_sdk/dng_classes.h b/core/libs/dngwriter/extra/dng_sdk/dng_classes.h
index 970365cb1f..c20434275b 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_classes.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_classes.h
@@ -1,97 +1,108 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_classes.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_area_task_progress;
+class dng_base_tile_iterator;
class dng_basic_tag_set;
+class dng_big_table;
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_local_string;
+class dng_look_table;
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_ref_counted_block;
class dng_render;
+class dng_resample_function;
class dng_resolution;
+class dng_rgb_table;
+class dng_set_minimum_priority;
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
+struct dng_xmp_namespace;
/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_color_space.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_color_space.cpp
index ff33fa878b..40df39840f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_color_space.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_color_space.cpp
@@ -1,1072 +1,1067 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_color_space.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_color_space.h b/core/libs/dngwriter/extra/dng_sdk/dng_color_space.h
index e6f737a6c6..86539a91bf 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_color_space.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_color_space.h
@@ -1,347 +1,346 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_color_space.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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.
+
+ /// 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.
+
+ /// 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)
+ /// 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).
+ /// 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
+
+ /// Returns dng_function_GammaEncode_2_2
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/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.cpp
index fbdef0e8e0..f63d972955 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.cpp
@@ -1,546 +1,554 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_color_spec.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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],
+ 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
{
- dng_matrix pcsToCamera = colorMatrix * MapWhiteMatrix (PCStoXY (), fWhiteXY);
-
- // Scale matrix so PCS white can just be reached when the first camera
- // channel saturates.
-
- real64 scale = MaxEntry (pcsToCamera * PCStoXYZ ());
-
- pcsToCamera = (1.0 / scale) * pcsToCamera;
-
- // Invert this matrix. Note that if there are more than three
+ // Invert this PCS to camera matrix. Note that if there are more than three
// camera channels, this inversion is non-unique.
-
- fCameraToPCS = Invert (pcsToCamera, reductionMatrix);
-
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.h b/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.h
index 2a1aca5ca8..5eb3a81c47 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_color_spec.h
@@ -1,138 +1,141 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_color_spec.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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
+/// 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
+ /// 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.
+ /// \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.
+
+ /// 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
+ /// \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.
+ /// 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/core/libs/dngwriter/extra/dng_sdk/dng_date_time.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_date_time.cpp
index 0482cbb34a..961723ec25 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_date_time.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_date_time.cpp
@@ -1,1136 +1,1050 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_date_time.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_date_time.h"
#include "dng_exceptions.h"
+#include "dng_globals.h"
#include "dng_mutex.h"
#include "dng_stream.h"
#include "dng_string.h"
#include "dng_utils.h"
#include <time.h>
#if qMacOS
#include <CoreServices/CoreServices.h>
#endif
#if qWinOS
#include <windows.h>
-#if defined(__GNUC__)
-#include <winbase.h>
-
-/*
- * Win32 kernel time functions from Wine API.
- *
- * Copyright 1995 Martin von Loewis and Cameron Heide
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#define FILETIME2LL( pft, ll) ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime;
-#define LL2FILETIME( ll, pft ) (pft)->dwLowDateTime = (UINT)(ll); (pft)->dwHighDateTime = (UINT)((ll) >> 32);
-
-const int MonthLengths[2][12] =
-{
- { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
-};
-inline int IsLeapYear(int Year)
-{
- return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
-};
-BOOL TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION *pTZinfo,
- FILETIME *lpFileTime, BOOL islocal, LONG *pBias);
-BOOL TIME_CompTimeZoneID(const TIME_ZONE_INFORMATION *pTZinfo,
- FILETIME *lpFileTime, BOOL islocal);
-int TIME_DayLightCompareDate(const SYSTEMTIME *date,
- const SYSTEMTIME *compareDate);
-BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
- LPSYSTEMTIME lpLocalTime,
- LPSYSTEMTIME lpUniversalTime);
-#endif /* defined(__GNUC__) */
#endif
/******************************************************************************/
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 >= 0 && fHour <= 23 &&
- fMinute >= 0 && fMinute <= 59 &&
- fSecond >= 0 && fSecond <= 59;
-
+ 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::SetOffsetTime (const dng_string &s)
+ {
+
+ // Initialize zone to invalid.
+
+ dng_time_zone zone;
+
+ SetZone (zone);
+
+ // Parse EXIF OffsetTime format.
+
+ if (s.Length () == 6 &&
+ (s.Get () [0] == '+' || s.Get () [0] == '-') &&
+ (s.Get () [1] >= '0' && s.Get () [1] <= '1') &&
+ (s.Get () [2] >= '0' && s.Get () [2] <= '9') &&
+ (s.Get () [3] == ':') &&
+ (s.Get () [4] >= '0' && s.Get () [4] <= '5') &&
+ (s.Get () [5] >= '0' && s.Get () [5] <= '9'))
+ {
+
+ int32 hours = (s.Get () [1] - '0') * 10 +
+ (s.Get () [2] - '0');
+
+ int32 minutes = (s.Get () [4] - '0') * 10 +
+ (s.Get () [5] - '0');
+
+ int32 offset = hours * 60 + minutes;
+
+ if (s.Get () [0] == '-')
+ {
+ offset = -offset;
+ }
+
+ zone.SetOffsetMinutes (offset);
+
+ if (zone.IsValid ())
+ {
+
+ SetZone (zone);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_string dng_date_time_info::OffsetTime () const
+ {
+
+ dng_string result;
+
+ if (TimeZone ().IsValid ())
+ {
+
+ int32 offset = TimeZone ().OffsetMinutes ();
+
+ char s [7];
+
+ s [0] = (offset >= 0) ? '+' : '-';
+
+ offset = Abs_int32 (offset);
+
+ uint32 hours = offset / 60;
+ uint32 minutes = offset % 60;
+
+ s [1] = (hours / 10) + '0';
+ s [2] = (hours % 10) + '0';
+
+ s [3] = ':';
+
+ s [4] = (minutes / 10) + '0';
+ s [5] = (minutes % 10) + '0';
+
+ result.Set (s);
+
+ }
+
+ else
+ {
+
+ result.Set (" : ");
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
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;
-
- if (sscanf (s + j + 1,
- "%u:%u:%u",
- &hour,
- &minute,
- &second) == 3)
+
+ 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;
}
-
- for (uint32 k = j + 1; k < len; k++)
+
+ if (items == 3)
{
-
- if (s [k] == '.')
+
+ for (uint32 k = j + 1; k < len; k++)
{
-
- while (++k < len && s [k] >= '0' && s [k] <= '9')
+
+ if (s [k] == '.')
{
-
- char ss [2];
-
- ss [0] = s [k];
- ss [1] = 0;
-
- fSubseconds.Append (ss);
-
+
+ while (++k < len && s [k] >= '0' && s [k] <= '9')
+ {
+
+ char ss [2];
+
+ ss [0] = s [k];
+ ss [1] = 0;
+
+ fSubseconds.Append (ss);
+
+ }
+
+ break;
+
}
-
- 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 ());
}
-
+
}
-
- // 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 ())
+
+ if (gDNGUseFakeTimeZonesInXMP)
{
- tempZone = LocalTimeZone (fDateTime);
+
+ // 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 ());
+
}
-
- 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",
- fDateTime.fYear,
- fDateTime.fMonth,
- fDateTime.fDay);
-
+ (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 && fTimeZone.IsValid ())
+
+ if (IsValid () && !fDateOnly)
{
-
+
char s [64];
-
- sprintf (s,
- "%02u%02u%02u%c%02u%02u",
- fDateTime.fHour,
- fDateTime.fMinute,
- fDateTime.fSecond,
- fTimeZone.OffsetMinutes () >= 0 ? '+' : '-',
- Abs_int32 (fTimeZone.OffsetMinutes ()) / 60,
- Abs_int32 (fTimeZone.OffsetMinutes ()) % 60);
-
+
+ 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");
+static dng_std_mutex gDateTimeMutex;
/*****************************************************************************/
void CurrentDateTimeAndZone (dng_date_time_info &info)
{
-
+
time_t sec;
-
+
time (&sec);
-
+
tm t;
tm zt;
-
+
{
-
- dng_lock_mutex lock (&gDateTimeMutex);
-
+
+ dng_lock_std_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);
-
+
+ dng_lock_std_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
-
+
CFTimeZoneRef zoneRef = CFTimeZoneCopyDefault ();
+ CFReleaseHelper<CFTimeZoneRef> zoneRefDeleter (zoneRef);
+
if (zoneRef)
{
- CFGregorianDate gregDate;
-
- gregDate.year = dt.fYear;
- gregDate.month = dt.fMonth;
- gregDate.day = dt.fDay;
- gregDate.hour = dt.fHour;
- gregDate.minute = dt.fMinute;
- gregDate.second = dt.fSecond;
-
- CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime (gregDate, zoneRef);
-
- CFTimeInterval secondsDelta = CFTimeZoneGetSecondsFromGMT (zoneRef, absTime);
+ // New path that doesn't use deprecated CFGregorian-based APIs.
+
+ CFCalendarRef calendar =
+ CFCalendarCreateWithIdentifier (kCFAllocatorDefault,
+ kCFGregorianCalendar);
+
+ CFReleaseHelper<CFCalendarRef> calendarDeleter (calendar);
+
+ CFAbsoluteTime absTime;
+
+ if (CFCalendarComposeAbsoluteTime (calendar,
+ &absTime,
+ "yMdHms",
+ dt.fYear,
+ dt.fMonth,
+ dt.fDay,
+ dt.fHour,
+ dt.fMinute,
+ dt.fSecond))
+ {
+
+ CFTimeInterval secondsDelta = CFTimeZoneGetSecondsFromGMT (zoneRef, absTime);
- CFRelease (zoneRef);
+ result.SetOffsetSeconds (Round_int32 (secondsDelta));
- result.SetOffsetSeconds (secondsDelta);
+ if (result.IsValid ())
+ {
+ return result;
+ }
- 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;
-
+
}
-/*****************************************************************************
- * Win32 kernel time functions from Wine API used to implement
- * TzSpecificLocalTimeToSystemTime() from win32 which is unavailable with MinGW.
- */
-
-#if qWinOS && defined(__GNUC__)
-
-/***********************************************************************
- * TIME_GetTimezoneBias
- *
- * Calculates the local time bias for a given time zone.
- *
- * PARAMS
- * pTZinfo [in] The time zone data.
- * lpFileTime [in] The system or local time.
- * islocal [in] It is local time.
- * pBias [out] The calculated bias in minutes.
- *
- * RETURNS
- * TRUE when the time zone bias was calculated.
- */
-BOOL TIME_GetTimezoneBias(const TIME_ZONE_INFORMATION *pTZinfo,
- FILETIME *lpFileTime, BOOL islocal, LONG *pBias)
- {
- LONG bias = pTZinfo->Bias;
- DWORD tzid = TIME_CompTimeZoneID( pTZinfo, lpFileTime, islocal);
-
- if( tzid == TIME_ZONE_ID_INVALID)
- return FALSE;
- if (tzid == TIME_ZONE_ID_DAYLIGHT)
- bias += pTZinfo->DaylightBias;
- else if (tzid == TIME_ZONE_ID_STANDARD)
- bias += pTZinfo->StandardBias;
- *pBias = bias;
- return TRUE;
-}
-
-/***********************************************************************
- * TIME_CompTimeZoneID
- *
- * Computes the local time bias for a given time and time zone.
- *
- * PARAMS
- * pTZinfo [in] The time zone data.
- * lpFileTime [in] The system or local time.
- * islocal [in] it is local time.
- *
- * RETURNS
- * TIME_ZONE_ID_INVALID An error occurred
- * TIME_ZONE_ID_UNKNOWN There are no transition time known
- * TIME_ZONE_ID_STANDARD Current time is standard time
- * TIME_ZONE_ID_DAYLIGHT Current time is dayligh saving time
- */
-BOOL TIME_CompTimeZoneID(const TIME_ZONE_INFORMATION *pTZinfo,
- FILETIME *lpFileTime, BOOL islocal)
-{
- int ret;
- BOOL beforeStandardDate, afterDaylightDate;
- DWORD retval = TIME_ZONE_ID_INVALID;
- LONGLONG llTime = 0; /* initialized to prevent gcc complaining */
- SYSTEMTIME SysTime;
- FILETIME ftTemp;
-
- if (pTZinfo->DaylightDate.wMonth != 0)
- {
- if (pTZinfo->StandardDate.wMonth == 0 ||
- pTZinfo->StandardDate.wDay<1 ||
- pTZinfo->StandardDate.wDay>5 ||
- pTZinfo->DaylightDate.wDay<1 ||
- pTZinfo->DaylightDate.wDay>5)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return TIME_ZONE_ID_INVALID;
- }
-
- if (!islocal) {
- FILETIME2LL( lpFileTime, llTime );
- llTime -= ( pTZinfo->Bias + pTZinfo->DaylightBias )
- * (LONGLONG)600000000;
- LL2FILETIME( llTime, &ftTemp)
- lpFileTime = &ftTemp;
- }
-
- FileTimeToSystemTime(lpFileTime, &SysTime);
-
- /* check for daylight saving */
- ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate);
- if (ret == -2)
- return TIME_ZONE_ID_INVALID;
-
- beforeStandardDate = ret < 0;
-
- if (!islocal) {
- llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias )
- * (LONGLONG)600000000;
- LL2FILETIME( llTime, &ftTemp)
- FileTimeToSystemTime(lpFileTime, &SysTime);
- }
-
- ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate);
- if (ret == -2)
- return TIME_ZONE_ID_INVALID;
-
- afterDaylightDate = ret >= 0;
-
- retval = TIME_ZONE_ID_STANDARD;
- if( pTZinfo->DaylightDate.wMonth < pTZinfo->StandardDate.wMonth ) {
- /* Northern hemisphere */
- if( beforeStandardDate && afterDaylightDate )
- retval = TIME_ZONE_ID_DAYLIGHT;
- } else /* Down south */
- if( beforeStandardDate || afterDaylightDate )
- retval = TIME_ZONE_ID_DAYLIGHT;
- } else
- /* No transition date */
- retval = TIME_ZONE_ID_UNKNOWN;
-
- return retval;
-}
-
-/***********************************************************************
- * TIME_DayLightCompareDate
- *
- * Compares two dates without looking at the year.
- *
- * PARAMS
- * date [in] The local time to compare.
- * compareDate [in] The daylight saving begin or end date.
- *
- * RETURNS
- *
- * -1 if date < compareDate
- * 0 if date == compareDate
- * 1 if date > compareDate
- * -2 if an error occurs
- */
-int TIME_DayLightCompareDate(const SYSTEMTIME *date,
- const SYSTEMTIME *compareDate)
-{
- int limit_day, dayinsecs;
-
- if (date->wMonth < compareDate->wMonth)
- return -1; /* We are in a month before the date limit. */
-
- if (date->wMonth > compareDate->wMonth)
- return 1; /* We are in a month after the date limit. */
-
- if (compareDate->wDayOfWeek <= 6)
- {
- WORD First;
- /* compareDate->wDay is interpreted as number of the week in the month
- * 5 means: the last week in the month */
- int weekofmonth = compareDate->wDay;
- /* calculate the day of the first DayOfWeek in the month */
- First = ( 6 + compareDate->wDayOfWeek - date->wDayOfWeek + date->wDay
- ) % 7 + 1;
- limit_day = First + 7 * (weekofmonth - 1);
- /* check needed for the 5th weekday of the month */
- if(limit_day > MonthLengths[date->wMonth==2 && IsLeapYear(date->wYear)]
- [date->wMonth - 1])
- limit_day -= 7;
- }
- else
- {
- limit_day = compareDate->wDay;
- }
-
- /* convert to seconds */
- limit_day = ((limit_day * 24 + compareDate->wHour) * 60 +
- compareDate->wMinute ) * 60;
- dayinsecs = ((date->wDay * 24 + date->wHour) * 60 +
- date->wMinute ) * 60 + date->wSecond;
- /* and compare */
- return dayinsecs < limit_day ? -1 :
- dayinsecs > limit_day ? 1 :
- 0; /* date is equal to the date limit. */
-}
-
-/***********************************************************************
- * TzSpecificLocalTimeToSystemTime
- *
- * Converts a local time to a time in utc.
- *
- * PARAMS
- * lpTimeZoneInformation [in] The desired time zone.
- * lpLocalTime [in] The local time.
- * lpUniversalTime [out] The calculated utc time.
- *
- * RETURNS
- * Success: TRUE. lpUniversalTime contains the converted time.
- * Failure: FALSE.
- */
-BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformation,
- LPSYSTEMTIME lpLocalTime,
- LPSYSTEMTIME lpUniversalTime)
-{
- FILETIME ft;
- LONG lBias;
- LONGLONG t;
- TIME_ZONE_INFORMATION tzinfo;
-
- if (lpTimeZoneInformation != NULL)
- {
- memcpy(&tzinfo, lpTimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
- }
- else
- {
- if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
- return FALSE;
- }
-
- if (!SystemTimeToFileTime(lpLocalTime, &ft))
- return FALSE;
- FILETIME2LL( &ft, t)
- if (!TIME_GetTimezoneBias(&tzinfo, &ft, TRUE, &lBias))
- return FALSE;
- /* convert minutes to 100-nanoseconds-ticks */
- t += (LONGLONG)lBias * 600000000;
- LL2FILETIME( t, &ft)
- return FileTimeToSystemTime(&ft, lpUniversalTime);
-}
-
-#endif /* qWinOS && defined(__GNUC__) */
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_date_time.h b/core/libs/dngwriter/extra/dng_sdk/dng_date_time.h
index 6ffe27ee04..feaa6411f9 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_date_time.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_date_time.h
@@ -1,379 +1,388 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_date_time.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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?
-
+
+ // 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 ();
}
-
+
+ bool IsDateOnly () const
+ {
+ return fDateOnly;
+ }
+
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 ClearZone ()
+ {
+ fTimeZone.Clear ();
+ }
+
+ void SetOffsetTime (const dng_string &s);
+
+ dng_string OffsetTime () const;
+
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
+/// \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 representation format
+/// 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
+
+ /// 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;
-
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_errors.h b/core/libs/dngwriter/extra/dng_sdk/dng_errors.h
index ca3b101e56..c8fbd978f7 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_errors.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_errors.h
@@ -1,57 +1,54 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_errors.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_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.
+ dng_error_overflow //!< Arithmetic overflow.
};
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.cpp
index 4e08744cd9..7c61301e60 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.cpp
@@ -1,215 +1,219 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_exceptions.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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
-
- fprintf (stderr, "*** Warning: %s", message);
-
- if (sub_message)
- {
-
- fprintf (stderr, " (%s)", sub_message);
-
- }
-
- fprintf (stderr, " ***\n");
-
+
+ #ifdef cr_logw
+
+ cr_logs("report", 2, NULL, 0, cr_logfunc(), "%s %s\n", message, sub_message ? sub_message : "");
+
+ #else
+
+ if (sub_message)
+ fprintf (stderr, "*** Warning: %s (%s) ***\n", message, sub_message);
+ else
+ fprintf (stderr, "*** Warning: %s ***\n", message);
+
+ #endif
+
#else
(void) message;
(void) sub_message;
-
+
#endif
-
+
}
/*****************************************************************************/
void ReportError (const char *message,
const char *sub_message)
{
- #if qDNGReportErrors
-
- fprintf (stderr, "*** Error: %s", message);
-
- if (sub_message)
- {
-
- fprintf (stderr, " (%s)", sub_message);
-
- }
-
- fprintf (stderr, " ***\n");
-
- // When Xcode won't let us set a break point, comment out the line below to
- // force the app to crash at this point (assuming the message is in protected
- // memory).
-
- // * const_cast< char *> (message) = 'X';
-
+ #if qDNGReportErrors
+
+ #ifdef cr_loge
+
+ cr_logs("report", 3, NULL, 0, cr_logfunc(), "%s %s\n", message, sub_message ? sub_message : "");
+
+ #else
+
+ if (sub_message)
+ fprintf (stderr, "*** Error: %s (%s) ***\n", message, sub_message);
+ else
+ fprintf (stderr, "*** Error: %s ***\n", message);
+
+ #endif
+
#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;
+ }
+
+ case dng_error_overflow:
+ {
+ message = "Arithmetic overflow/underflow";
+ break;
+ }
+
default:
{
message = "Unknown error";
break;
}
-
+
}
-
+
}
-
+
if (message && !silent)
{
ReportError (message, sub_message);
}
-
+
}
-
+
#else
-
- message;
- sub_message;
- silent;
-
+
+ (void) message;
+ (void) sub_message;
+ (void) silent;
+
#endif
-
+
throw dng_exception (err);
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.h b/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.h
index 9925a9f001..e3afa7daee 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_exceptions.h
@@ -1,289 +1,319 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_exceptions.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* C++ exception support for DNG SDK.
*/
/*****************************************************************************/
#ifndef __dng_exceptions__
#define __dng_exceptions__
/*****************************************************************************/
#include "dng_errors.h"
#include "dng_flags.h"
/*****************************************************************************/
+#ifndef DNG_NO_RETURN
+#ifdef __GNUC__
+#define DNG_NO_RETURN __attribute__((noreturn))
+#else
+#define DNG_NO_RETURN
+#endif
+#endif
+
+/*****************************************************************************/
+
/// 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);
+ bool silent = false) DNG_NO_RETURN;
/******************************************************************************/
/// \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_overflow.
+
+inline void ThrowOverflow (const char * sub_message = NULL)
+ {
+
+ Throw_dng_error (dng_error_overflow, 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)
+inline void ThrowHostInsufficient (const char * sub_message = NULL,
+ bool silent = false)
{
-
- Throw_dng_error (dng_error_host_insufficient, NULL, sub_message);
-
+
+ Throw_dng_error (dng_error_host_insufficient, NULL, sub_message, silent);
+
}
/*****************************************************************************/
/// \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/core/libs/dngwriter/extra/dng_sdk/dng_exif.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_exif.cpp
index bbf2c7f9b8..517d9e4d8a 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_exif.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_exif.cpp
@@ -1,3827 +1,4754 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_exif.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 ()
+
+ , fDateTimeOriginal ()
, fDateTimeOriginalStorageInfo ()
-
- , fDateTimeDigitized ()
+
+ , 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)
- , fSubjectAreaCount (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)
-
+
+ , 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 ()
- , fLensName ()
+
+ , fLensID ()
+ , fLensMake ()
+ , fLensName ()
, fLensSerialNumber ()
+
+ , fLensNameWasReadFromExif (false)
- , fFlashCompensation ()
+ , fApproxFocusDistance ()
+ , fFlashCompensation ()
+
, fOwnerName ()
, fFirmware ()
- {
+ , fTemperature ()
+ , fHumidity ()
+ , fPressure ()
+ , fWaterDepth ()
+ , fAcceleration ()
+ , fCameraElevationAngle ()
+ , fTitle ()
+
+ {
+
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;
}
+ memset (fLensDistortInfo, 0, sizeof (fLensDistortInfo));
+
}
-
+
/*****************************************************************************/
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 >= 1.0 / 1073741824.0 && et <= 1073741824.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);
+
+ 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 ();
- if (fs >= 1.0 && fs <= 32768.0)
+ // 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 = 2.0 * log (fFNumber.As_real64 ()) / log (2.0);
+
+ 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);
-
+
+ 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 fs = pow (2.0, av * 0.5);
+/*****************************************************************************/
- SetFNumber (fs);
+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 ());
+
}
/*****************************************************************************/
-void dng_exif::UpdateDateTime (const dng_date_time_info &dt)
+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
+ {
+
+ return fExifVersion >= DNG_CHAR4 ('0','2','3','0');
+
+ }
+
+/*****************************************************************************/
+
+bool dng_exif::AtLeastVersion0231 () const
+ {
+
+ return fExifVersion >= DNG_CHAR4 ('0','2','3','1');
+
+ }
+
+/*****************************************************************************/
+
+void dng_exif::SetVersion0231 ()
+ {
+
+ fExifVersion = DNG_CHAR4 ('0','2','3','1');
+
+ }
+/*****************************************************************************/
+
+bool dng_exif::HasLensDistortInfo () const
+ {
+
+ return (fLensDistortInfo [0] . IsValid () &&
+ fLensDistortInfo [1] . IsValid () &&
+ fLensDistortInfo [2] . IsValid () &&
+ fLensDistortInfo [3] . IsValid ());
+
}
/*****************************************************************************/
+
+void dng_exif::SetLensDistortInfo (const dng_vector &params)
+ {
+
+ if (params.Count () != 4)
+ {
+ return;
+ }
+
+ fLensDistortInfo [0] . Set_real64 (params [0]);
+ fLensDistortInfo [1] . Set_real64 (params [1]);
+ fLensDistortInfo [2] . Set_real64 (params [2]);
+ fLensDistortInfo [3] . Set_real64 (params [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) 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 (), true);
-
+
#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.1f\n",
+
+ 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 tcTimeZoneOffset:
+
+ case tcSensitivityType:
{
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
- CheckTagType (parentCode, tagCode, tagType, ttSShort);
-
- CheckTagCount (parentCode, tagCode, tagCount, 1, 2);
-
- dng_time_zone zoneOriginal;
+ fSensitivityType = (uint32) stream.Get_uint16 ();
+
+ #if qDNGValidate
- zoneOriginal.SetOffsetHours (stream.TagValue_int32 (tagType));
+ if (gVerbose)
+ {
+
+ printf ("SensitivityType: %s\n",
+ LookupSensitivityType (fSensitivityType));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcStandardOutputSensitivity:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
- fDateTimeOriginal.SetZone (zoneOriginal);
+ fStandardOutputSensitivity = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
- // Note that there is no "TimeZoneOffsetDigitized" field, so
- // we assume the same tone zone as the original.
+ 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);
+
+ #if 0 // MWG: Not filling in time zones unless we are sure.
+
+ // Note that there is no "TimeZoneOffsetDigitized" field, so
+ // we assume the same tone zone as the original.
+
fDateTimeDigitized.SetZone (zoneOriginal);
+
+ #endif
dng_time_zone zoneCurrent;
if (tagCount >= 2)
{
-
+
zoneCurrent.SetOffsetHours (stream.TagValue_int32 (tagType));
-
+
fDateTime.SetZone (zoneCurrent);
-
+
}
-
+
#if qDNGValidate
if (gVerbose)
{
-
- printf ("TimeZoneOffset: DateTimeOriginal = %d",
+
+ 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 tcOffsetTime:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ dng_string offsetTime;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ offsetTime);
+
+ fDateTime.SetOffsetTime (offsetTime);
+
+ // The offset time tags were added to EXIF spec 2.3.1.
+ // We need EXIF spec version to figure out legacy fake time
+ // zones in XMP, so force a correct exif spec version if
+ // these EXIF tags are used.
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OffsetTime: ");
+
+ DumpString (offsetTime);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOffsetTimeOriginal:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ dng_string offsetTime;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ offsetTime);
+
+ fDateTimeOriginal.SetOffsetTime (offsetTime);
+
+ // The offset time tags were added to EXIF spec 2.3.1.
+ // We need EXIF spec version to figure out legacy fake time
+ // zones in XMP, so force a correct exif spec version if
+ // these EXIF tags are used.
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OffsetTimeOriginal: ");
+
+ DumpString (offsetTime);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcOffsetTimeDigitized:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii);
+
+ dng_string offsetTime;
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ offsetTime);
+
+ fDateTimeDigitized.SetOffsetTime (offsetTime);
+
+ // The offset time tags were added to EXIF spec 2.3.1.
+ // We need EXIF spec version to figure out legacy fake time
+ // zones in XMP, so force a correct exif spec version if
+ // these EXIF tags are used.
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("OffsetTimeDigitized: ");
+
+ DumpString (offsetTime);
+
+ 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.1f\n", x);
-
+
+ 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 = 2.0 * log (fs) / log (2.0);
-
+
+ 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 tcTemperature:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fTemperature = stream.TagValue_srational (tagType);
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Temperature: %0.1f\n",
+ fTemperature.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcHumidity:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fHumidity = stream.TagValue_urational (tagType);
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Humidity: %0.1f\n",
+ fHumidity.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcPressure:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fPressure = stream.TagValue_urational (tagType);
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Pressure: %0.1f\n",
+ fPressure.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcWaterDepth:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fWaterDepth = stream.TagValue_srational (tagType);
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("WaterDepth: %0.1f\n",
+ fWaterDepth.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcAcceleration:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fAcceleration = stream.TagValue_urational (tagType);
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("Acceleration: %0.1f\n",
+ fAcceleration.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcCameraElevationAngle:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttSRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fCameraElevationAngle = stream.TagValue_srational (tagType);
+
+ if (!AtLeastVersion0231 ())
+ {
+ SetVersion0231 ();
+ }
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("CameraElevationAngle: %0.1f\n",
+ fCameraElevationAngle.As_real64 ());
+
+ }
+
+ #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;
+
+ }
- fImageUniqueID = f;
+ 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;
+
+ }
- printf ("ImageUniqueID: ");
+ 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
- DumpFingerprint (fImageUniqueID);
+ }
+
+ }
+
+ #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))
+
+ // Should really be ttRational per EXIF spec, but allow
+ // ttSRational too because some JPEGs from Nexus 5
+ // apparently use ttSRational type.
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttRational) &&
+ !CheckTagType (parentCode, tagCode, tagType, ttSRational))
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 = 2.0 * log (fs) / log (2.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 = 2.0 * log (fs1) / log (2.0);
- real64 av2 = 2.0 * log (fs2) / log (2.0);
-
+
+ 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 (fISOSpeedRatings [0] == 0 && fExposureIndex.IsValid ())
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_exif.h b/core/libs/dngwriter/extra/dng_sdk/dng_exif.h
index 65cc992d33..644998bec5 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_exif.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_exif.h
@@ -1,268 +1,377 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_exif.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
- * EXIF read access support. See the \ref spec_exif "EXIF specification" for full description of tags.
+ * 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];
-
+
+ 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 fRelatedImageWidth;
uint32 fRelatedImageLength;
- dng_string fCameraSerialNumber;
-
- dng_urational fLensInfo [4];
-
+ dng_string fCameraSerialNumber; // EXIF 2.3: BodySerialNumber.
+
+ dng_urational fLensInfo [4]; // EXIF 2.3: LensSpecification.
+
dng_string fLensID;
- dng_string fLensName;
+ 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;
+
+ dng_string fOwnerName; // EXIF 2.3: CameraOwnerName.
dng_string fFirmware;
-
+
+ // EXIF 2.3.1:
+
+ dng_srational fTemperature;
+ dng_urational fHumidity;
+ dng_urational fPressure;
+ dng_srational fWaterDepth;
+ dng_urational fAcceleration;
+ dng_srational fCameraElevationAngle;
+
+ // Not really part of EXIF, but some formats may use.
+
+ dng_string fTitle;
+
+ // Image-specific radial distortion correction metadata that can be
+ // used later during (UI-driven) lens profile corrections. Same model
+ // as DNG opcode model.
+
+ dng_srational fLensDistortInfo [4];
+
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 ss 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;
+
+ /// Returns true iff the EXIF version is at least 2.3.1.
+
+ bool AtLeastVersion0231 () const;
+
+ /// Sets the EXIF version to 2.3.1.
+
+ void SetVersion0231 ();
+
+ bool HasLensDistortInfo () const;
+
+ void SetLensDistortInfo (const dng_vector &params);
+
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/core/libs/dngwriter/extra/dng_sdk/dng_fast_module.h b/core/libs/dngwriter/extra/dng_sdk/dng_fast_module.h
index 21e58df51e..71e4f87c19 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_fast_module.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_fast_module.h
@@ -1,31 +1,26 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_fast_module.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* Include file to set optimization to highest level for performance-critical routines.
- * Normal files should have optimization set to normal level to save code size as there is less
+ * 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/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.cpp
index f2d26c8d22..c0df9c8ad3 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.cpp
@@ -1,135 +1,182 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_file_stream.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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
}
+
+ }
+
+/*****************************************************************************/
+
+#if qWinOS
+
+/*****************************************************************************/
+
+dng_file_stream::dng_file_stream (const wchar_t *filename,
+ bool output,
+ uint32 bufferSize)
+
+ : dng_stream ((dng_abort_sniffer *) NULL,
+ bufferSize,
+ 0)
+
+ , fFile (NULL)
+
+ {
+
+ fFile = _wfopen (filename, output ? L"wb" : L"rb");
+
+ if (!fFile)
+ {
+
+ #if qDNGValidate
+
+ char filenameCString[256];
+
+ size_t returnCount;
+ wcstombs_s (&returnCount,
+ filenameCString,
+ 256,
+ filename,
+ _TRUNCATE);
+
+ ReportError ("Unable to open file",
+ filenameCString);
+
+ ThrowSilentError ();
+
+ #else
+
+ ThrowOpenFile ();
+
+ #endif // qDNGValidate
+
+ }
+
}
/*****************************************************************************/
+#endif // qWinOS
+
+/*****************************************************************************/
+
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 ftell (fFile);
-
+
+ return (uint64) ftell (fFile);
+
}
-
+
/*****************************************************************************/
void dng_file_stream::DoRead (void *data,
uint32 count,
uint64 offset)
{
-
- if (fseek (fFile, (uint32) offset, SEEK_SET) != 0)
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.h b/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.h
index 516b21f7cc..2d4e819837 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_file_stream.h
@@ -1,77 +1,72 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_file_stream.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* Simple, portable, file read/write support.
*/
/*****************************************************************************/
#ifndef __dng_file_stream__
#define __dng_file_stream__
/*****************************************************************************/
#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 ();
+ #if qWinOS
- protected:
+ dng_file_stream (const wchar_t *filename,
+ bool output = false,
+ uint32 bufferSize = kDefaultBufferSize);
+ #endif // qWinOS
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.cpp
index 52852abdba..fd2858c8c9 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.cpp
@@ -1,167 +1,157 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_filter_task.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_tag_values.h"
#include "dng_utils.h"
/*****************************************************************************/
-dng_filter_task::dng_filter_task (const dng_image &srcImage,
+dng_filter_task::dng_filter_task (const char *name,
+ const dng_image &srcImage,
dng_image &dstImage)
- : fSrcImage (srcImage)
+ : dng_area_task (name)
+
+ , fSrcImage (srcImage)
, fDstImage (dstImage)
-
+
, fSrcPlane (0 )
, fSrcPlanes (srcImage.Planes ())
, fSrcPixelType (srcImage.PixelType ())
-
+
, fDstPlane (0 )
, fDstPlanes (dstImage.Planes ())
, fDstPixelType (dstImage.PixelType ())
-
+
, fSrcRepeat (1, 1)
-
+ , fSrcTileSize (0, 0)
+
{
}
-
+
/*****************************************************************************/
dng_filter_task::~dng_filter_task ()
{
-
+
}
-
+
/*****************************************************************************/
void dng_filter_task::Start (uint32 threadCount,
+ const dng_rect & /* dstArea */,
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;
-
+
+ fSrcTileSize = SrcTileSize (tileSize);
+
+ uint32 srcBufferSize = ComputeBufferSize (fSrcPixelType,
+ fSrcTileSize,
+ fSrcPlanes,
+ padSIMDBytes);
+
+ uint32 dstBufferSize = ComputeBufferSize (fDstPixelType,
+ tileSize,
+ fDstPlanes,
+ padSIMDBytes);
+
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);
+ // Safety check.
+
+ int32 src_area_w;
+ int32 src_area_h;
+
+ if (!ConvertUint32ToInt32 (srcArea.W (),
+ &src_area_w) ||
+ !ConvertUint32ToInt32 (srcArea.H (),
+ &src_area_h) ||
+ src_area_w > fSrcTileSize.h ||
+ src_area_h > fSrcTileSize.v)
+ {
+
+ ThrowMemoryFull ("Area exceeds tile size.");
+
+ }
+
// 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 ();
-
+
+ dng_pixel_buffer srcBuffer (srcArea,
+ fSrcPlane,
+ fSrcPlanes,
+ fSrcPixelType,
+ pcRowInterleavedAlignSIMD,
+ 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 ();
-
+
+ dng_pixel_buffer dstBuffer (area,
+ fDstPlane,
+ fDstPlanes,
+ fDstPixelType,
+ pcRowInterleavedAlignSIMD,
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.h b/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.h
index 8a4dd2e6ee..ca72dd2194 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_filter_task.h
@@ -1,129 +1,155 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_filter_task.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
- * Specialization of dng_area_task for processing an area from one dng_image to an area of another.
- */
+ * 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.
+/// \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;
-
+ dng_point fSrcTileSize;
+
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_filter_task (const char *name,
+ 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.
+ /// 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.
+ ///
+ /// \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.
+ /// 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.
+ ///
+ /// \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.
+ /// 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 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.
+ /// 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_rect &dstArea,
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.
+
+ /// 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 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.
+ /// \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/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.cpp
index 4f0812d1d6..cd6f652f6a 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.cpp
@@ -1,499 +1,618 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_fingerprint.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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++)
+
+ for (uint32 j = 0; j < kDNGFingerprintSize; j++)
{
-
+
data [j] = 0;
-
+
}
-
+
}
/*****************************************************************************/
+dng_fingerprint::dng_fingerprint (const char *hex)
+ {
+
+ if (!hex || strlen (hex) != kDNGFingerprintSize * 2 || !FromUtf8HexString (hex))
+ {
+
+ Clear ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
bool dng_fingerprint::IsNull () const
{
-
- for (uint32 j = 0; j < 16; j++)
+
+ for (uint32 j = 0; j < kDNGFingerprintSize; 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++)
+
+ for (uint32 j = 0; j < kDNGFingerprintSize; j++)
{
-
+
if (data [j] != print.data [j])
{
-
+
return false;
-
+
}
-
+
}
-
+
return true;
+
+ }
+
+/******************************************************************************/
+bool dng_fingerprint::operator< (const dng_fingerprint &print) const
+ {
+
+ for (uint32 j = 0; j < kDNGFingerprintSize; j++)
+ {
+
+ if (data [j] != print.data [j])
+ {
+
+ return data [j] < print.data [j];
+
+ }
+
+ }
+
+ return false;
+
}
/******************************************************************************/
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);
}
- return x;
+ 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.
+DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.h b/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.h
index 619a1dcb6a..809c3c3c61 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_fingerprint.h
@@ -1,319 +1,400 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_fingerprint.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
- * Fingerprint (cryptographic hashing) support for generating strong hashes of image data.
+ * 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 [16];
-
+ uint8 data [kDNGFingerprintSize];
+
public:
-
+
dng_fingerprint ();
-
+
+ dng_fingerprint (const char *hex);
+
/// 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);
}
+
+ /// Comparision test for fingerprints.
+
+ bool operator< (const dng_fingerprint &print) const;
+
+ /// 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]);
- /// Produce a 32-bit hash value from fingerprint used for faster hashing of fingerprints.
+ };
+
+/*****************************************************************************/
- uint32 Collapse32 () const;
+/// \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
+/// \brief Utility to hash fingerprints (e.g., for hashtables).
+
+struct dng_fingerprint_hash
+ {
+
+ /// Hash function.
+
+ size_t operator () (const dng_fingerprint &digest) const
+ {
+
+ return (size_t) digest.Collapse32 ();
+
+ }
+
+ };
+
+/******************************************************************************/
+
+// 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));
-
+
+ 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.
-
+
+ DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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;
}
+ DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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;
}
+ DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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;
}
+ DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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;
-
+
};
/*****************************************************************************/
-// A dng_stream based interface to the MD5 printing logic.
+/// \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:
- dng_md5_printer_stream ()
+ /// 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/core/libs/dngwriter/extra/dng_sdk/dng_flags.h b/core/libs/dngwriter/extra/dng_sdk/dng_flags.h
index 355756bb1f..cda8867036 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_flags.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_flags.h
@@ -1,189 +1,402 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_flags.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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__
/*****************************************************************************/
-/// \def qMcOS 1 if compiling for Mac OS X
-/// \def qWinOS 1 if compiling for Windows
+/// \def qMacOS
+/// 1 if compiling for Mac OS X.
+
+/// \def qWinOS
+/// 1 if compiling for Windows.
-// Make sure qMacOS and qWinOS are defined.
+// Make sure a platform is defined
-#if !defined(qMacOS) || !defined(qWinOS)
+#if !(defined(qMacOS) || defined(qWinOS) || defined(qAndroid) || defined(qiPhone) || defined(qLinux))
#include "RawEnvironment.h"
#endif
-#if !defined(qMacOS) || !defined(qWinOS)
+// This requires a force include or compiler define. These are the unique platforms.
+
+#if !(defined(qMacOS) || defined(qWinOS) || defined(qAndroid) || defined(qiPhone) || defined(qLinux))
#error Unable to figure out platform
#endif
/*****************************************************************************/
-/// \def qDNGDebug 1 if debug code is compiled in, 0 otherwise. Enables assertions and other
-/// debug checks in exchange for slower processing.
+// Platforms.
+// Zeros out any undefined platforms, so that #if can be used in place of #ifdef.
+
+#ifndef qMacOS
+#define qMacOS 0
+#endif
+
+#ifndef qiPhone
+#define qiPhone 0
+#endif
+
+#ifndef qiPhoneSimulator
+#define qiPhoneSimulator 0
+#endif
+
+#ifndef qAndroid
+#define qAndroid 0
+#endif
+
+#ifndef qWinOS
+#define qWinOS 0
+#endif
+
+#ifndef qWinRT
+#define qWinRT 0
+#endif
+
+#ifndef qLinux
+#define qLinux 0
+#endif
+
+#ifndef qWeb
+#define qWeb 0
+#endif
+
+/*****************************************************************************/
+
+#if qiPhoneSimulator
+#if !qiPhone
+#error "qiPhoneSimulator set and not qiPhone"
+#endif
+#endif
+
+#if qWinRT
+#if !qWinOS
+#error "qWinRT set but not qWinOS"
+#endif
+#endif
+
+/*****************************************************************************/
+
+// arm and neon support
+
+// arm detect (apple vs. win)
+#if defined(__arm__) || defined(__arm64__) || defined(_M_ARM)
+#define qARM 1
+#endif
+
+// arm_neon detect
+#if defined(__ARM_NEON__) || defined(_M_ARM)
+#define qARMNeon 1
+#endif
+
+#ifndef qARM
+#define qARM 0
+#endif
+
+#ifndef qARMNeon
+#define qARMNeon 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
+/*****************************************************************************/
+// Support Intel Thread Building Blocks (TBB)?
+//
+// This flag needs to be configured via the project, because there are sources
+// outside the cr_sdk (such as the CTJPEG and ACE libs) that need to use the
+// same flag to determine whether to use TBB or not.
+//
+// By default, configure to 0 (disabled).
+
+#ifndef qCRSupportTBB
+#define qCRSupportTBB 0
+#endif
+
+#if qCRSupportTBB
+#ifndef TBB_DEPRECATED
+#define TBB_DEPRECATED 0
+#endif
+#endif
+
+// This is not really a switch, but rather a shorthand for determining whether
+// or not we're building a particular translation unit (source file) using the
+// Intel Compiler.
+
+#ifndef qDNGIntelCompiler
+#if defined(__INTEL_COMPILER)
+#define qDNGIntelCompiler (__INTEL_COMPILER >= 1700)
+#else
+#define qDNGIntelCompiler 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
+/// \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(__s390__)
-#define qDNGBigEndian 1
-
-#elif defined(__sparc__)
-#define qDNGBigEndian 1
-
#elif defined(__INTEL__)
#define qDNGBigEndian 0
#elif defined(_M_IX86)
#define qDNGBigEndian 0
-#elif defined(_M_X64)
+#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(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
- __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#define qDNGBigEndian 1
-
-#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
- __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#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
+/// \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
+#elif qLinux
+
+#ifdef __LP64__
+#if __LP64__
+#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
+/// \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
+/// \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.
+/// \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.
+/// \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
/*****************************************************************************/
+// Experimental features -- work in progress for Lightroom and Camera Raw
+// major releases. Turn this off for Lightroom & Camera Raw dot releases.
+
+#ifndef qDNGExperimental
+#define qDNGExperimental 1
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGXMPFiles
+/// 1 to use XMPFiles.
+
+#ifndef qDNGXMPFiles
+#define qDNGXMPFiles 1
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGXMPDocOps
+/// 1 to use XMPDocOps.
+
+#ifndef qDNGXMPDocOps
+#define qDNGXMPDocOps (!qDNGValidateTarget)
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGUseLibJPEG
+/// 1 to use open-source libjpeg for lossy jpeg processing.
+
+#ifndef qDNGUseLibJPEG
+#define qDNGUseLibJPEG qDNGValidateTarget
+#endif
+
+/*****************************************************************************/
+
+#ifndef qDNGAVXSupport
+#define qDNGAVXSupport ((qMacOS || qWinOS) && qDNG64Bit && !qARM && 1)
#endif
+#if qDNGAVXSupport && !(qDNG64Bit && !qARM)
+#error AVX support is enabled when 64-bit support is not or ARM is
+#endif
+
+/*****************************************************************************/
+
+#ifndef qDNGSupportVC5
+#define qDNGSupportVC5 (1)
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGUsingSanitizer
+/// Set to 1 when using a Sanitizer tool.
+
+#ifndef qDNGUsingSanitizer
+#define qDNGUsingSanitizer (0)
+#endif
+
+/*****************************************************************************/
+
+#ifndef DNG_ATTRIB_NO_SANITIZE
+#if qDNGUsingSanitizer && defined(__clang__)
+#define DNG_ATTRIB_NO_SANITIZE(type) __attribute__((no_sanitize(type)))
+#else
+#define DNG_ATTRIB_NO_SANITIZE(type)
+#endif
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGDepthSupport
+/// 1 to add support for depth maps in DNG format.
+/// Deprecated 2018-09-19.
+
+#ifdef __cplusplus
+#define qDNGDepthSupport #error
+#endif
+
+/*****************************************************************************/
+
+/// \def qDNGPreserveBlackPoint
+/// 1 to add support for non-zero black point in early raw pipeline.
+/// Deprecated 2018-09-19.
+
+#ifdef __cplusplus
+#define qDNGPreserveBlackPoint #error
+#endif
+
+/*****************************************************************************/
+
+#endif
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.cpp
index a86e4822ce..2e2dd9933c 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.cpp
@@ -1,583 +1,644 @@
/*****************************************************************************/
-// Copyright 2008-2009 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_gain_map.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_gain_map.h"
#include "dng_exceptions.h"
#include "dng_globals.h"
#include "dng_host.h"
+#include "dng_negative.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)
+
+ if (fMap.Points ().v < 1)
{
+ ThrowProgramError ("Empty gain map");
+ }
- fRowIndex1 = fMap.Points ().v - 1;
+ uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1);
+
+ if (rowIndexF >= static_cast<real64> (lastRow))
+ {
+
+ fRowIndex1 = lastRow;
fRowIndex2 = fRowIndex1;
-
+
fRowFract = 0.0f;
-
+
}
-
+
else
{
+
+ // If we got here, we know that rowIndexF can safely be converted to
+ // a uint32 and that static_cast<uint32> (rowIndexF) < lastRow. This
+ // implies fRowIndex2 <= lastRow below.
+ fRowIndex1 = static_cast<uint32> (rowIndexF);
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)) -
+
+ 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)
+
+ if (fMap.Points ().h < 1)
{
+ ThrowProgramError ("Empty gain map");
+ }
- fValueBase = InterpolateEntry (fMap.Points ().h - 1);
-
+ uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1);
+
+ if (colIndexF >= static_cast<real64> (lastCol))
+ {
+
+ fValueBase = InterpolateEntry (lastCol);
+
fValueStep = 0.0f;
-
+
fResetColumn = 0x7FFFFFFF;
-
+
}
-
+
else
{
+
+ // If we got here, we know that colIndexF can safely be converted
+ // to a uint32 and that static_cast<uint32> (colIndexF) < lastCol.
+ // This implies colIndex + 1 <= lastCol, i.e. the argument to
+ // InterpolateEntry() below is valid.
+
+ uint32 colIndex = static_cast<uint32> (colIndexF);
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_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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 * sizeof (real32)));
-
+
+ fBuffer.Reset (allocator.Allocate (ComputeBufferSize (ttFloat,
+ fPoints,
+ fPlanes,
+ padSIMDBytes)));
+
}
-
+
/*****************************************************************************/
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_host &host,
dng_stream &stream)
{
-
+
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",
+
+ printf ("Points: v=%d, h=%d\n",
(int) mapPoints.v,
(int) mapPoints.h);
-
- printf ("Spacing: v=%.6f, h=%.6f\n",
+
+ printf ("Spacing: v=%.6f, h=%.6f\n",
mapSpacing.v,
mapSpacing.h);
-
- printf ("Origin: v=%.6f, h=%.6f\n",
+
+ printf ("Origin: v=%.6f, h=%.6f\n",
mapOrigin.v,
mapOrigin.h);
-
- printf ("Planes: %u\n",
+
+ 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 (host.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", 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 (host, stream));
-
+
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 */,
+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 ())
{
-
+
+ uint16 blackLevel = (Stage () >= 2) ? negative.Stage3BlackLevel () : 0;
+
+ real32 blackScale1 = 1.0f;
+ real32 blackScale2 = 1.0f;
+ real32 blackOffset1 = 0.0f;
+ real32 blackOffset2 = 0.0f;
+
+ if (blackLevel != 0)
+ {
+
+ blackOffset2 = ((real32) blackLevel) / 65535.0f;
+ blackScale2 = 1.0f - blackOffset2;
+ blackScale1 = 1.0f / blackScale2;
+ blackOffset1 = 1.0f - blackScale1;
+
+ }
+
uint32 cols = overlap.W ();
-
+
uint32 colPitch = fAreaSpec.ColPitch ();
-
+
+ colPitch = Min_uint32 (colPitch, cols);
+
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);
-
+
+ if (blackLevel != 0)
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = dPtr [col] * blackScale1 + blackOffset1;
+
+ }
+
+ }
+
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 ();
}
-
+
}
-
+
+ if (blackLevel != 0)
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = dPtr [col] * blackScale2 + blackOffset2;
+
+ }
+
+ }
+
}
-
+
}
-
+
}
}
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.h b/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.h
index 7bab8ec2b4..3595a65390 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_gain_map.h
@@ -1,169 +1,200 @@
/*****************************************************************************/
-// Copyright 2008-2009 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_gain_map.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include "dng_uncopyable.h"
/*****************************************************************************/
-class dng_gain_map
- {
+/// \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_uncopyable
+ {
+
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_host &host,
dng_stream &stream);
- private:
-
- // Hidden copy constructor and assignment operator.
-
- dng_gain_map (const dng_gain_map &map);
-
- dng_gain_map & operator= (const dng_gain_map &map);
-
};
/*****************************************************************************/
-class dng_opcode_GainMap: public dng_inplace_opcode
- {
+/// \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_uncopyable
+ {
+
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/core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp
index 031b5076df..9e2b38fc72 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp
@@ -1,28 +1,52 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_globals.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_globals.h"
+#include "dng_simd_type.h"
/*****************************************************************************/
#if qDNGValidate
bool gVerbose = false;
uint32 gDumpLineLimit = 100;
#endif
+/******************************************************************************/
+
+bool gDNGUseFakeTimeZonesInXMP = false;
+
+/*****************************************************************************/
+
+bool gDNGShowTimers = true;
+
+/*****************************************************************************/
+
+uint32 gDNGStreamBlockSize = 4096;
+
+uint32 gDNGMaxStreamBufferSize = 1024 * 1024;
+
+/*****************************************************************************/
+
+bool gImagecore = false;
+
+bool gPrintTimings = false;
+
+bool gPrintAsserts = true;
+
+bool gBreakOnAsserts = true;
+
+/*****************************************************************************/
+
+// This is declared in dng_simd_type.h
+
+SIMDType gDNGMaxSIMD = Scalar;
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_globals.h b/core/libs/dngwriter/extra/dng_sdk/dng_globals.h
index 60869b572f..0f11ed0065 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_globals.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_globals.h
@@ -1,46 +1,85 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_globals.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
- * Definitions of global variables controling DNG SDK behavior. Currenntly only used for validation control.
+ * Definitions of global variables controling DNG SDK behavior.
*/
/*****************************************************************************/
#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.
+/// When validation (qValidate) is turned on, this global 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.
+/// 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
+// Print out results from dng_timers?
+
+extern bool gDNGShowTimers;
+
+/******************************************************************************/
+// MWG says don't use fake time zones in XMP, but there is some
+// old software that requires them to work correctly.
+
+extern bool gDNGUseFakeTimeZonesInXMP;
+
+/*****************************************************************************/
+
+// Stream block size. Choose a size that the OS likes for file system
+// efficent read/write alignment.
+
+extern uint32 gDNGStreamBlockSize;
+
+// Maximum stream buffer size to use on large reads and writes.
+
+extern uint32 gDNGMaxStreamBufferSize;
+
+/*****************************************************************************/
+
+// Are we running as part of the imagecore library?
+
+extern bool gImagecore;
+
+// Print out timing info for area tasks?
+
+extern bool gPrintTimings;
+
+// Print assert messages?
+
+extern bool gPrintAsserts;
+
+// Break into debugger on asserts?
+
+extern bool gBreakOnAsserts;
+
+/*****************************************************************************/
+
+#endif
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_host.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_host.cpp
index 26a8254497..017f1c7fd3 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_host.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_host.cpp
@@ -1,493 +1,587 @@
/*****************************************************************************/
-// Copyright 2006-2009 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_host.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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)
-
+ , fForFastSaveToDNG (false)
+ , fFastSaveToDNGSize (0)
+ , fPreserveStage2 (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 if (PreferredSize () >= 2400 && PreferredSize () <= 2560)
+ {
+ SetMinimumSize (2400);
+ }
+
+ // The following resolutions are typically on HiDPI displays where a
+ // greater degree of upsampling remains visually ok for previews. The
+ // following ratios are all based on 20% upsampling in a linear
+ // dimension.
+ else if (PreferredSize () >= 2448 && PreferredSize () <= 2880)
+ {
+ SetMinimumSize (2448);
+ }
+
+ // 1st-generation Surface Book.
+
+ else if (PreferredSize () >= 2560 && PreferredSize () <= 3000)
+ {
+ SetMinimumSize (2560);
+ }
+
+ // 4K (actually 3840).
+
+ else if (PreferredSize () >= 3480 && PreferredSize () <= 4096)
+ {
+ SetMinimumSize (3480);
+ }
+
+ // Surface Studio.
+
+ else if (PreferredSize () >= 3824 && PreferredSize () <= 4500)
+ {
+ SetMinimumSize (3824);
+ }
+
+ // 5K.
+
+ else if (PreferredSize () >= 4352 && PreferredSize () <= 5120)
+ {
+ SetMinimumSize (4352);
+ }
+
+ // 8K.
+
+ else if (PreferredSize () >= 6528 && PreferredSize () <= 7680)
+ {
+ SetMinimumSize (6528);
+ }
+
+ // 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)
+ const dng_rect &area,
+ dng_area_task_progress *progress)
{
-
+
dng_area_task::Perform (task,
area,
&Allocator (),
- Sniffer ());
+ Sniffer (),
+ progress);
+
+ }
+
+/*****************************************************************************/
+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 (Allocator ());
-
+
+ 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);
- break;
+
}
+
}
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/core/libs/dngwriter/extra/dng_sdk/dng_host.h b/core/libs/dngwriter/extra/dng_sdk/dng_host.h
index f638f71914..5fcac431c3 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_host.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_host.h
@@ -1,390 +1,444 @@
/*****************************************************************************/
-// Copyright 2006-2009 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_host.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include "dng_uncopyable.h"
/*****************************************************************************/
-/// \brief The main class for communication between the application and the
+/// \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
+/// 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
+/// establishing mutual exclusion for read/write access to a single dng_host
/// object if it is used in multiple threads.)
-class dng_host
+class dng_host: private dng_uncopyable
{
-
+
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 performed.
-
+ // 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;
- public:
+ // Is this host being used to perform a negative read for fast
+ // conversion to DNG?
- /// Allocate a dng_host object, possibly with custom allocator and sniffer.
+ bool fForFastSaveToDNG;
+
+ uint32 fFastSaveToDNGSize;
+
+ bool fPreserveStage2;
+
+ public:
+
+ /// 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
+ /// \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
+
+ /// 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.
+ /// 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.
+
+ /// 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.
+ /// 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
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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 perform fast save to DNG.
+ /// \param flag True if the host is being used to perform a negative
+ /// read for fast conversion to DNG, false otherwise.
+
+ void SetForFastSaveToDNG (bool flag,
+ uint32 size)
+ {
+ fForFastSaveToDNG = flag;
+ fFastSaveToDNGSize = size;
+ }
+
+ /// Getter for the Boolean value that indicates whether this host is
+ /// being used to perform a negative read for fast conversion to DNG.
+
+ bool ForFastSaveToDNG () const
+ {
+ return fForFastSaveToDNG;
+ }
+
+ uint32 FastSaveToDNGSize () const
+ {
+ return fFastSaveToDNGSize;
+ }
+
/// 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.
+
+ /// 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.
+
+ /// 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.
+ /// 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.
+
+ /// 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, original RAW data will be kept.
+
+ /// 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.
+ /// 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
- /// occurrence such as user cancellation or memory exhaustion. This method is
+ /// 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
+ /// 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 bottleneck for image processing tasks.
- /// Default implementation calls dng_area_task::PerformAreaTask method on
- /// task. Can be overridden in derived classes to support multiprocessing,
+ /// 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);
-
- /// Factory method for dng_exif class. Can be used to customize allocation or
+ const dng_rect &area,
+ dng_area_task_progress *progress = NULL);
+
+ /// 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_shared class. Can be used to customize allocation
+ /// 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 class. Can be used to
+
+ /// 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.
+ /// Getter for flag determining whether we should preserve the stage 2
+ /// image after building the stage 3 image.
- dng_host (const dng_host &host);
+ bool WantsPreserveStage2 () const
+ {
+ return fPreserveStage2;
+ }
- dng_host & operator= (const dng_host &host);
+ /// Setter for flag determining whether we should preserve the stage 2
+ /// image after building the stage 3 image.
+ void SetWantsPreserveStage2 (bool flag)
+ {
+ fPreserveStage2 = flag;
+ }
+
};
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.cpp
index a7ca28c79d..c0db058f97 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.cpp
@@ -1,365 +1,405 @@
/*****************************************************************************/
-// Copyright 2007 Adobe Systems Incorporated
+// Copyright 2007-2019 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_3/dng_sdk/source/dng_hue_sat_map.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
/*****************************************************************************/
+std::atomic<uint64> dng_hue_sat_map::sRuntimeFingerprintCounter (0);
+
+/*****************************************************************************/
+
dng_hue_sat_map::dng_hue_sat_map ()
- : fHueDivisions (0)
- , fSatDivisions (0)
- , fValDivisions (0)
- , fHueStep (0)
- , fValStep (0)
- , fDeltas ()
+ : fHueDivisions (0)
+ , fSatDivisions (0)
+ , fValDivisions (0)
+ , fHueStep (0)
+ , fValStep (0)
+ , fRuntimeFingerprint ()
+ , 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 ()
+ : fHueDivisions (0)
+ , fSatDivisions (0)
+ , fValDivisions (0)
+ , fHueStep (0)
+ , fValStep (0)
+ , fRuntimeFingerprint ()
+ , 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
{
- this->SetDivisions (rhs.fHueDivisions,
- rhs.fSatDivisions,
- rhs.fValDivisions);
+ fHueDivisions = rhs.fHueDivisions;
+ fSatDivisions = rhs.fSatDivisions;
+ fValDivisions = rhs.fValDivisions;
- memcpy (this->GetDeltas (),
- rhs.GetDeltas (),
- DeltasCount () * sizeof (HSBModify));
+ fHueStep = rhs.fHueStep;
+ fValStep = rhs.fValStep;
+
+ fRuntimeFingerprint = rhs.fRuntimeFingerprint;
+
+ 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 () * sizeof (HSBModify);
+ dng_safe_uint32 size (DeltasCount ());
- fDeltas.Allocate (size);
+ size *= (uint32) sizeof (HSBModify);
+
+ fDeltas.Allocate (size.Get ());
+
+ DoZeroBytes (fDeltas.Buffer (), size.Get ());
- DoZeroBytes (fDeltas.Buffer (), size);
+ fRuntimeFingerprint.Clear ();
}
/*****************************************************************************/
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 = GetDeltas ();
+ const HSBModify *deltas = GetConstDeltas ();
modify.fHueShift = deltas [offset].fHueShift;
modify.fSatScale = deltas [offset].fSatScale;
modify.fValScale = deltas [offset].fValScale;
}
/*****************************************************************************/
-void dng_hue_sat_map::SetDelta (uint32 hueDiv,
- uint32 satDiv,
- uint32 valDiv,
- const HSBModify &modify)
+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;
- GetDeltas () [offset] = modify;
-
+ 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
-
- GetDeltas () [offset] . fValScale = 1.0f;
-
+
+ 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
+void dng_hue_sat_map::AssignNewUniqueRuntimeFingerprint ()
{
+ const uint64 uid = ++sRuntimeFingerprintCounter;
+
+ dng_md5_printer printer;
+ printer.Process (&uid, sizeof (uid));
+ fRuntimeFingerprint = printer.Result ();
+
+ }
+
+/*****************************************************************************/
+
+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 (GetDeltas (),
- rhs.GetDeltas (),
+ 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.GetDeltas ();
- const HSBModify *data2 = map2.GetDeltas ();
-
- HSBModify *data3 = result->GetDeltas ();
-
+
+ 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++;
+
+ }
+
+ // Compute a fingerprint based on the inputs for the new dng_hue_sat_map
+ // so that repeated interpolations of the same objects with the same
+ // parameters produce the same fingerprint each time.
+
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process ("Interpolate", 11);
+
+ printer.Process (&weight1, sizeof(weight1));
+
+ printer.Process (map1.RuntimeFingerprint ().data,
+ dng_fingerprint::kDNGFingerprintSize);
+
+ printer.Process (map2.RuntimeFingerprint ().data,
+ dng_fingerprint::kDNGFingerprintSize);
+
+ result->SetRuntimeFingerprint (printer.Result ());
}
// Return interpolated tables.
-
+
return result.Release ();
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.h b/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.h
index 382049a202..2531e6ebf2 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_hue_sat_map.h
@@ -1,141 +1,258 @@
/*****************************************************************************/
-// Copyright 2007 Adobe Systems Incorporated
+// Copyright 2007-2019 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_3/dng_sdk/source/dng_hue_sat_map.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_memory.h"
+#include "dng_fingerprint.h"
+#include "dng_ref_counted_block.h"
+#include "dng_safe_arithmetic.h"
#include "dng_types.h"
+#include <atomic>
+
/*****************************************************************************/
+/// \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. 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. fSatScale and 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_memory_data fDeltas;
+ // This fingerprint is intended to be used for certain rendering
+ // optimizations. Also, it can vary from session to session.
+ // In general, dng_hue_sat_map objects loaded from raw data
+ // will be given unique values for the session while dng_hue_sat_map
+ // objects derived from other dng_hue_sat_map objects will be
+ // given fingerprint values based on their inputs so that if they
+ // are recomputed, they get the same value (again, in that sesssion).
+
+ dng_fingerprint fRuntimeFingerprint;
+
+ static std::atomic<uint64> sRuntimeFingerprintCounter;
+
+ 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;
+ fRuntimeFingerprint.Clear ();
+
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);
+ 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);
+ 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;
+ return (dng_safe_uint32 (fValDivisions) *
+ dng_safe_uint32 (fHueDivisions) *
+ dng_safe_uint32 (fSatDivisions)).Get ();
}
+
+ /// 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 ();
}
- const HSBModify *GetDeltas () const
+ void AssignNewUniqueRuntimeFingerprint ();
+
+ /// Set Fingerprint. Rare use cases want to set the fingerprint.
+
+ void SetRuntimeFingerprint (const dng_fingerprint fingerprint)
{
- return (HSBModify *) fDeltas.Buffer_real32 ();
+ fRuntimeFingerprint = fingerprint;
}
- bool operator== (const dng_hue_sat_map &rhs) const;
+ /// Get the runtime fingerprint of this hue sat map.
+
+ const dng_fingerprint & RuntimeFingerprint () const
+ {
+ return fRuntimeFingerprint;
+ }
+
+ /// 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/core/libs/dngwriter/extra/dng_sdk/dng_ifd.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_ifd.cpp
index 3ef91b8c62..4926aae413 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_ifd.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_ifd.cpp
@@ -1,3837 +1,4542 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_ifd.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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)
+ , fNoiseProfile ()
- , fSampleBitShift (0)
+ , fEnhanceParams ()
+
+ , fBaselineSharpness (0, 0)
+
+ , fNoiseReductionApplied (0, 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 ()
{
+
+ }
+
+/*****************************************************************************/
+dng_ifd * dng_ifd::Clone () const
+ {
+
+ return new dng_ifd (*this);
+
}
/*****************************************************************************/
// 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);
-
+
+ const uint32 maxBitsPerSample = 32;
+
if (j < kMaxSamplesPerPixel)
{
+
+ if (x > maxBitsPerSample)
+ {
+ //ThrowBadFormat ("BitsPerSample out of bounds");
+ DNG_REPORT ("BitsPerSample > 32");
+ x = maxBitsPerSample;
+ }
+
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: %u\n", (unsigned) fPredictor);
-
+
+ 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 (" %u", (unsigned) x);
+ 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,
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,
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,
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,
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:
{
-
- CheckMainIFD (parentCode, tagCode, fNewSubFileType);
-
+
+ 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:
{
-
- CheckMainIFD (parentCode, tagCode, fNewSubFileType);
-
+
+ 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 tcOpcodeList3:
+ case tcNoiseProfile:
{
- CheckMainIFD (parentCode, tagCode, fNewSubFileType);
+ if (!CheckTagType (parentCode, tagCode, tagType, ttDouble))
+ return false;
- CheckTagType (parentCode, tagCode, tagType, ttUndefined);
+ // This tag will be parsed even in non-raw IFDs (such as
+ // thumbnails, previews, etc.) to support legacy DNGs that have
+ // the tag in the wrong IFD, but we'll now issue a warning.
+ // (Turn off the warning for IFD0 since we are writing it
+ // there for backward compatiblity).
+
+ if (parentCode != 0)
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ }
+
+ // Must be an even, positive number of doubles in a noise profile.
+
+ if (!tagCount || (tagCount & 1))
+ return false;
- fOpcodeList3Count = tagCount;
- fOpcodeList3Offset = tagOffset;
+ // 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.
+
+ dng_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 ("OpcodeList3: count = %u, offset = %u\n",
- (unsigned) fOpcodeList3Count,
- (unsigned) fOpcodeList3Offset);
+ printf (" Noise function for plane %u: scale = %.20lf, offset = %.20lf\n",
+ (unsigned) plane,
+ noiseFunctions [plane].Scale (),
+ noiseFunctions [plane].Offset ());
+ }
+
}
#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;
+
+ }
+
+ case tcEnhanceParams:
+ {
+
+ #if qDNGValidate
+
+ if (fNewSubFileType != sfEnhancedImage)
+ {
+
+ char message [256];
+
+ sprintf (message,
+ "%s %s is not allowed IFDs with NewSubFileType != EnhancedImage",
+ LookupParentCode (parentCode),
+ LookupTagCode (parentCode, tagCode));
+
+ ReportWarning (message);
+
+ }
+
+ #endif
+
+ CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
+
+ ParseStringTag (stream,
+ parentCode,
+ tagCode,
+ tagCount,
+ fEnhanceParams,
+ false);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("EnhanceParams: ");
+
+ DumpString (fEnhanceParams);
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcBaselineSharpness:
+ {
+
+ if (fNewSubFileType != sfEnhancedImage)
+ {
+ return false;
+ }
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fBaselineSharpness = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("BaselineSharpness (EnhancedImage): %0.2f\n",
+ fBaselineSharpness.As_real64 ());
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcNoiseReductionApplied:
+ {
+
+ if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
+ return false;
+
+ if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
+ return false;
+
+ // This tag will be parsed even in non-raw IFDs (such as
+ // thumbnails, previews, etc.) to support legacy DNGs that have
+ // the tag in the wrong IFD, but we'll now issue a warning.
+ // (Turn off the warning for IFD0 since we are writing it
+ // there for backward compatiblity).
+
+ if (parentCode != 0)
+ {
+
+ CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
+
+ }
+
+ fNoiseReductionApplied = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("NoiseReductionApplied: %u/%u\n",
+ (unsigned) fNoiseReductionApplied.n,
+ (unsigned) fNoiseReductionApplied.d);
+
+ }
+
+ #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 = (1 << fBitsPerSample [0]) - 1;
-
+
+ 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;
-
+
}
}
-
+
}
- }
+ // Check NoiseProfile.
+ if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Invalid NoiseProfile");
+
+ #endif
+
+ fNoiseProfile = dng_noise_profile ();
+
+ }
+
+ }
+
/*****************************************************************************/
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 = (1 << fBitsPerSample [0]) - 1;
-
+
+ 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 &&
+
+ if (fNewSubFileType != sfMainImage &&
+ fNewSubFileType != sfPreviewImage &&
+ fNewSubFileType != sfTransparencyMask &&
+ fNewSubFileType != sfPreviewMask &&
+ fNewSubFileType != sfDepthMap &&
+ fNewSubFileType != sfPreviewDepthMap &&
+ fNewSubFileType != sfEnhancedImage &&
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.
-
- switch (fPhotometricInterpretation)
+
+ if (fNewSubFileType == sfTransparencyMask ||
+ fNewSubFileType == sfPreviewMask)
{
-
- case piBlackIsZero:
- case piRGB:
- case piYCbCr:
+
+ if (fPhotometricInterpretation != piTransparencyMask)
{
-
- if (isMainIFD)
- {
-
- #if qDNGValidate
-
- ReportError ("PhotometricInterpretation requires NewSubFileType = 1",
- LookupParentCode (parentCode));
-
- #endif
-
- return false;
-
- }
-
- break;
-
+
+ #if qDNGValidate
+
+ ReportError ("NewSubFileType requires PhotometricInterpretation = TransparencyMask",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
}
-
- case piCFA:
+
+ }
+
+ else if (fNewSubFileType == sfDepthMap ||
+ fNewSubFileType == sfPreviewDepthMap)
+ {
+
+ if (fPhotometricInterpretation != piDepth)
+ {
+
+ #if qDNGValidate
+
+ ReportError ("NewSubFileType requires PhotometricInterpretation = Depth",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ return false;
+
+ }
+
+ }
+
+ else
+ {
+
+ switch (fPhotometricInterpretation)
{
-
- if (!isMainIFD)
+
+ 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 ("PhotometricInterpretation requires NewSubFileType = 0",
+
+ ReportError ("Missing or invalid PhotometricInterpretation",
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 processing software may be adding color effects.
-
+ // 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;
+ }
+
+ case piDepth:
+ {
+ 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 require 8 or 16 bits per sample",
+
+ 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 qDNGSupportVC5
+
+ case ccVc5:
+ break;
+
+ #endif // qDNGSupportVC5
+
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 &&
+ fPhotometricInterpretation != piDepth)
+ {
+
+ #if qDNGValidate
+ ReportError ("ZIP compression is limited to floating point, 32-bit integer,"
+ " transparency masks, and depth maps",
+ LookupParentCode (parentCode));
+
+ #endif
+
+ }
+
+ break;
+
+ }
+
default:
{
-
+
#if qDNGValidate
ReportError ("Unsupported Compression",
LookupParentCode (parentCode));
-
+
#endif
-
+
return false;
-
+
}
-
+
}
-
+
// Check Predictor.
-
- if (fPredictor != cpNullPredictor)
+
+ 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] != sfUnsignedInteger)
+
+ 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)
+
+ if (fWhiteLevel [j] < 1.0 || (fWhiteLevel [j] > maxWhite && !isFloatingPoint))
{
-
+
#if qDNGValidate
ReportError ("Invalid WhiteLevel",
LookupParentCode (parentCode));
-
+
#endif
-
+
return false;
-
+
}
-
+
}
- // Check DefaultScale.
+ // 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
- // Warning if too little padding on CFA image.
+ ReportError ("non-default DefaultCropOrigin on non-main image");
+
+ #endif
+
+ return false;
- #if qDNGValidate
+ }
+
+ 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;
+ uint64 width64 = (uint64) fTileWidth;
+ return (uint32) (((fImageWidth + width64) - 1) / width64);
+
}
-
+
return 0;
}
-
+
/*****************************************************************************/
uint32 dng_ifd::TilesDown () const
{
-
+
if (fTileLength)
{
- return (fImageLength + fTileLength - 1) / fTileLength;
+ // Use 64-bit math to prevent overflow. RowsPerStrip (assigned to
+ // fImageLength during parsing) may be 2^32 - 1, indicating a single
+ // strip.
- }
+ uint64 length64 = (uint64) fTileLength;
+ return (uint32) (((fImageLength + length64) - 1) / length64);
+
+ }
+
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 ();
+ DNG_REQUIRE (across > 0, "Bad number of tiles across in dng_ifd::FindTileSize");
+
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 (fCompression != ccJPEG)
+
+ if (fBitsPerSample [0] != 8)
{
return false;
}
-
- if (fBitsPerSample [0] != 8)
+
+ if (fSampleFormat [0] != sfUnsignedInteger)
{
return false;
}
- if (fSampleFormat [0] != sfUnsignedInteger)
+ 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) const
+ dng_image &image,
+ dng_jpeg_image *jpegImage,
+ dng_fingerprint *jpegDigest) const
{
-
+
dng_read_image reader;
-
+
reader.Read (host,
*this,
stream,
- image);
-
+ image,
+ jpegImage,
+ jpegDigest);
+
}
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_ifd.h b/core/libs/dngwriter/extra/dng_sdk/dng_ifd.h
index dbc9b91100..22538072e3 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_ifd.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_ifd.h
@@ -1,290 +1,311 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_ifd.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* DNG image file directory support.
*/
/*****************************************************************************/
#ifndef __dng_ifd__
#define __dng_ifd__
/*****************************************************************************/
#include "dng_fingerprint.h"
+#include "dng_negative.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;
+ dng_noise_profile fNoiseProfile;
+
+ dng_string fEnhanceParams;
+
+ dng_urational fBaselineSharpness;
+
+ dng_urational fNoiseReductionApplied;
+
bool fLosslessJPEGBug16;
-
+
uint32 fSampleBitShift;
-
+
uint64 fThisIFD;
uint64 fNextIFD;
+
+ int32 fCompressionQuality;
+
+ bool fPatchFirstJPEGByte;
public:
-
+
dng_ifd ();
-
+
virtual ~dng_ifd ();
+ virtual dng_ifd * Clone () const;
+
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) const;
-
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_image.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_image.cpp
index b7df8b11b2..811a783a01 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_image.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_image.cpp
@@ -1,835 +1,854 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_image.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 ();
+
+ }
+
+ // Allow up to 2 * kMaxImageSide to deal with intermediate image objects
+ // (e.g., rotated and padded).
+
+ static const uint32 kLimit = 2 * kMaxImageSide;
+ if (bounds.W () > kLimit ||
+ bounds.H () > kLimit)
+ {
+
+ ThrowBadFormat ("dng_image bounds too large");
+
+ }
+
}
/*****************************************************************************/
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
/*****************************************************************************/
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)
+void dng_image::DoCopyArea (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/core/libs/dngwriter/extra/dng_sdk/dng_image.h b/core/libs/dngwriter/extra/dng_sdk/dng_image.h
index 72f7460237..28633b58d1 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_image.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_image.h
@@ -1,433 +1,433 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_image.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include "dng_uncopyable.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
+class dng_tile_buffer: public dng_pixel_buffer,
+ private dng_uncopyable
{
-
+
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 access.
+ /// \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.
+
+ /// 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
+ /// \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);
+ uint32 planes)
+ {
+
+ DoCopyArea (src, area, srcPlane, dstPlane, 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);
+ DoCopyArea (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;
-
+ virtual 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);
+ virtual void DoCopyArea (const dng_image &src,
+ const dng_rect &area,
+ uint32 srcPlane,
+ uint32 dstPlane,
+ uint32 planes);
+
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/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.cpp
index 5485858710..39327fb9ba 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.cpp
@@ -1,4022 +1,7499 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_image_writer.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_image_writer.h"
+#include "dng_abort_sniffer.h"
+#include "dng_area_task.h"
#include "dng_bottlenecks.h"
#include "dng_camera_profile.h"
#include "dng_color_space.h"
+#include "dng_exceptions.h"
#include "dng_exif.h"
#include "dng_flags.h"
-#include "dng_exceptions.h"
+#include "dng_globals.h"
#include "dng_host.h"
#include "dng_ifd.h"
#include "dng_image.h"
+#include "dng_jpeg_image.h"
#include "dng_lossless_jpeg.h"
+#include "dng_memory.h"
#include "dng_memory_stream.h"
#include "dng_negative.h"
#include "dng_pixel_buffer.h"
#include "dng_preview.h"
#include "dng_read_image.h"
+#include "dng_safe_arithmetic.h"
#include "dng_stream.h"
+#include "dng_string_list.h"
#include "dng_tag_codes.h"
#include "dng_tag_values.h"
#include "dng_utils.h"
#include "dng_xmp.h"
+#include "zlib.h"
+
+#if qDNGUseLibJPEG
+#include "jpeglib.h"
+#include "jerror.h"
+#endif
+
+#include <atomic>
+
/*****************************************************************************/
// Defines for testing DNG 1.2 features.
//#define qTestRowInterleave 2
//#define qTestSubTileBlockRows 2
//#define qTestSubTileBlockCols 2
/*****************************************************************************/
dng_resolution::dng_resolution ()
: fXResolution ()
, fYResolution ()
-
+
, fResolutionUnit (0)
-
+
{
-
+
}
/******************************************************************************/
static void SpoolAdobeData (dng_stream &stream,
- const dng_negative *negative,
+ const dng_metadata *metadata,
const dng_jpeg_preview *preview,
const dng_memory_block *imageResources)
{
-
+
TempBigEndian tempEndian (stream);
-
- if (negative && negative->GetXMP ())
+
+ if (metadata && metadata->GetXMP ())
{
-
+
bool marked = false;
-
- if (negative->GetXMP ()->GetBoolean ("http://ns.adobe.com/xap/1.0/rights/",
+
+ if (metadata->GetXMP ()->GetBoolean (XMP_NS_XAP_RIGHTS,
"Marked",
marked))
{
-
+
stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
stream.Put_uint16 (1034);
stream.Put_uint16 (0);
-
+
stream.Put_uint32 (1);
-
+
stream.Put_uint8 (marked ? 1 : 0);
-
+
stream.Put_uint8 (0);
-
+
}
-
+
dng_string webStatement;
-
- if (negative->GetXMP ()->GetString ("http://ns.adobe.com/xap/1.0/rights/",
+
+ if (metadata->GetXMP ()->GetString (XMP_NS_XAP_RIGHTS,
"WebStatement",
webStatement))
{
-
+
dng_memory_data buffer;
-
+
uint32 size = webStatement.Get_SystemEncoding (buffer);
-
+
if (size > 0)
{
-
+
stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
stream.Put_uint16 (1035);
stream.Put_uint16 (0);
-
+
stream.Put_uint32 (size);
-
+
stream.Put (buffer.Buffer (), size);
-
+
if (size & 1)
stream.Put_uint8 (0);
-
+
}
-
+
}
-
+
}
-
+
if (preview)
{
-
+
preview->SpoolAdobeThumbnail (stream);
-
+
}
-
- if (negative)
+
+ if (metadata && metadata->IPTCLength ())
{
-
- dng_fingerprint iptcDigest = negative->IPTCDigest ();
+
+ dng_fingerprint iptcDigest = metadata->IPTCDigest ();
if (iptcDigest.IsValid ())
{
-
+
stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
stream.Put_uint16 (1061);
stream.Put_uint16 (0);
-
+
stream.Put_uint32 (16);
-
+
stream.Put (iptcDigest.data, 16);
-
+
}
-
+
}
-
+
if (imageResources)
{
-
+
uint32 size = imageResources->LogicalSize ();
-
+
stream.Put (imageResources->Buffer (), size);
-
+
if (size & 1)
stream.Put_uint8 (0);
-
+
}
-
+
}
/******************************************************************************/
static dng_memory_block * BuildAdobeData (dng_host &host,
- const dng_negative *negative,
+ const dng_metadata *metadata,
const dng_jpeg_preview *preview,
const dng_memory_block *imageResources)
{
-
+
dng_memory_stream stream (host.Allocator ());
-
+
SpoolAdobeData (stream,
- negative,
+ metadata,
preview,
imageResources);
-
+
return stream.AsMemoryBlock (host.Allocator ());
-
+
}
/*****************************************************************************/
tag_string::tag_string (uint16 code,
const dng_string &s,
bool forceASCII)
-
+
: tiff_tag (code, ttAscii, 0)
-
+
, fString (s)
-
+
{
-
+
if (forceASCII)
{
-
- fString.ForceASCII ();
-
- }
-
+
+ // Metadata working group recommendation - go ahead
+ // write UTF-8 into ASCII tag strings, rather than
+ // actually force the strings to ASCII. There is a matching
+ // change on the reading side to assume UTF-8 if the string
+ // contains a valid UTF-8 string.
+ //
+ // fString.ForceASCII ();
+
+ }
+
else if (!fString.IsASCII ())
{
-
+
fType = ttByte;
-
+
}
-
+
fCount = fString.Length () + 1;
-
+
}
/*****************************************************************************/
void tag_string::Put (dng_stream &stream) const
{
-
+
stream.Put (fString.Get (), Size ());
-
+
}
/*****************************************************************************/
tag_encoded_text::tag_encoded_text (uint16 code,
const dng_string &text)
-
+
: tiff_tag (code, ttUndefined, 0)
-
+
, fText (text)
-
+
, fUTF16 ()
-
+
{
-
+
if (fText.IsASCII ())
{
-
+
fCount = 8 + fText.Length ();
-
+
}
-
+
else
{
-
+
fCount = 8 + fText.Get_UTF16 (fUTF16) * 2;
-
+
}
-
+
}
/*****************************************************************************/
void tag_encoded_text::Put (dng_stream &stream) const
{
-
+
if (fUTF16.Buffer ())
{
-
+
stream.Put ("UNICODE\000", 8);
-
+
uint32 chars = (fCount - 8) >> 1;
-
+
const uint16 *buf = fUTF16.Buffer_uint16 ();
-
+
for (uint32 j = 0; j < chars; j++)
{
-
+
stream.Put_uint16 (buf [j]);
-
+
}
-
+
}
-
+
else
{
-
+
stream.Put ("ASCII\000\000\000", 8);
-
+
stream.Put (fText.Get (), fCount - 8);
-
+
}
-
+
}
-
+
/*****************************************************************************/
void tag_data_ptr::Put (dng_stream &stream) const
{
-
+
// If we are swapping bytes, we need to swap with the right size
// entries.
-
+
if (stream.SwapBytes ())
{
-
+
switch (Type ())
{
-
+
// Two byte entries.
-
+
case ttShort:
case ttSShort:
case ttUnicode:
{
-
+
const uint16 *p = (const uint16 *) fData;
-
+
uint32 entries = (Size () >> 1);
-
+
for (uint32 j = 0; j < entries; j++)
{
-
+
stream.Put_uint16 (p [j]);
-
+
}
-
+
return;
-
+
}
-
+
// Four byte entries.
-
+
case ttLong:
case ttSLong:
case ttRational:
case ttSRational:
case ttIFD:
case ttFloat:
case ttComplex:
{
-
+
const uint32 *p = (const uint32 *) fData;
-
+
uint32 entries = (Size () >> 2);
-
+
for (uint32 j = 0; j < entries; j++)
{
-
+
stream.Put_uint32 (p [j]);
-
+
}
-
+
return;
-
+
}
-
+
// Eight byte entries.
-
+
case ttDouble:
{
-
+
const real64 *p = (const real64 *) fData;
-
+
uint32 entries = (Size () >> 3);
-
+
for (uint32 j = 0; j < entries; j++)
{
-
+
stream.Put_real64 (p [j]);
-
+
}
-
+
return;
-
+
}
-
+
// Entries don't need to be byte swapped. Fall through
// to non-byte swapped case.
-
+
default:
{
-
+
break;
-
+
}
}
-
+
}
-
+
// Non-byte swapped case.
-
+
stream.Put (fData, Size ());
-
+
}
/******************************************************************************/
tag_matrix::tag_matrix (uint16 code,
const dng_matrix &m)
-
+
: tag_srational_ptr (code, fEntry, m.Rows () * m.Cols ())
-
+
{
-
+
uint32 index = 0;
-
+
for (uint32 r = 0; r < m.Rows (); r++)
for (uint32 c = 0; c < m.Cols (); c++)
{
-
+
fEntry [index].Set_real64 (m [r] [c], 10000);
-
+
index++;
-
+
}
-
+
}
/******************************************************************************/
tag_icc_profile::tag_icc_profile (const void *profileData,
uint32 profileSize)
-
- : tag_data_ptr (tcICCProfile,
+
+ : tag_data_ptr (tcICCProfile,
ttUndefined,
0,
NULL)
-
+
{
-
+
if (profileData && profileSize)
{
-
+
SetCount (profileSize);
SetData (profileData);
-
+
}
-
+
}
-
+
/******************************************************************************/
void tag_cfa_pattern::Put (dng_stream &stream) const
{
-
+
stream.Put_uint16 ((uint16) fCols);
stream.Put_uint16 ((uint16) fRows);
-
+
for (uint32 col = 0; col < fCols; col++)
for (uint32 row = 0; row < fRows; row++)
{
-
+
stream.Put_uint8 (fPattern [row * kMaxCFAPattern + col]);
-
+
}
}
/******************************************************************************/
tag_exif_date_time::tag_exif_date_time (uint16 code,
const dng_date_time &dt)
-
+
: tag_data_ptr (code, ttAscii, 20, fData)
-
+
{
-
+
if (dt.IsValid ())
{
-
+
sprintf (fData,
"%04d:%02d:%02d %02d:%02d:%02d",
(int) dt.fYear,
(int) dt.fMonth,
(int) dt.fDay,
(int) dt.fHour,
(int) dt.fMinute,
(int) dt.fSecond);
-
+
}
-
+
}
/******************************************************************************/
tag_iptc::tag_iptc (const void *data,
uint32 length)
-
+
: tiff_tag (tcIPTC_NAA, ttLong, (length + 3) >> 2)
-
+
, fData (data )
, fLength (length)
-
+
{
-
+
}
/******************************************************************************/
void tag_iptc::Put (dng_stream &stream) const
{
-
- // Note: For historical compatibility reasons, the standard TIFF data
+
+ // Note: For historical compatiblity reasons, the standard TIFF data
// type for IPTC data is ttLong, but without byte swapping. This really
// should be ttUndefined, but doing the right thing would break some
// existing readers.
-
+
stream.Put (fData, fLength);
-
+
// Pad with zeros to get to long word boundary.
-
+
uint32 extra = fCount * 4 - fLength;
-
+
while (extra--)
{
stream.Put_uint8 (0);
}
}
/******************************************************************************/
tag_xmp::tag_xmp (const dng_xmp *xmp)
-
+
: tag_uint8_ptr (tcXMP, NULL, 0)
-
+
, fBuffer ()
-
+
{
-
+
if (xmp)
{
-
+
fBuffer.Reset (xmp->Serialize (true));
-
+
if (fBuffer.Get ())
{
-
+
SetData (fBuffer->Buffer_uint8 ());
-
+
SetCount (fBuffer->LogicalSize ());
-
+
}
-
+
}
-
+
}
/******************************************************************************/
void dng_tiff_directory::Add (const tiff_tag *tag)
{
-
+
if (fEntries >= kMaxEntries)
{
ThrowProgramError ();
}
-
+
// Tags must be sorted in increasing order of tag code.
-
+
uint32 index = fEntries;
-
+
for (uint32 j = 0; j < fEntries; j++)
{
-
+
if (tag->Code () < fTag [j]->Code ())
{
index = j;
break;
}
-
+
}
-
+
for (uint32 k = fEntries; k > index; k--)
{
-
+
fTag [k] = fTag [k - 1];
-
+
}
-
+
fTag [index] = tag;
-
+
fEntries++;
-
+
}
-
+
/******************************************************************************/
uint32 dng_tiff_directory::Size () const
{
-
+
if (!fEntries) return 0;
-
+
uint32 size = fEntries * 12 + 6;
-
+
for (uint32 index = 0; index < fEntries; index++)
{
-
+
uint32 tagSize = fTag [index]->Size ();
-
+
if (tagSize > 4)
{
-
+
size += (tagSize + 1) & ~1;
-
+
}
-
+
}
-
+
return size;
-
+
}
-
+
/******************************************************************************/
void dng_tiff_directory::Put (dng_stream &stream,
OffsetsBase offsetsBase,
uint32 explicitBase) const
{
-
+
if (!fEntries) return;
-
+
uint32 index;
-
+
uint32 bigData = fEntries * 12 + 6;
-
+
if (offsetsBase == offsetsRelativeToStream)
bigData += (uint32) stream.Position ();
else if (offsetsBase == offsetsRelativeToExplicitBase)
bigData += explicitBase;
stream.Put_uint16 ((uint16) fEntries);
-
+
for (index = 0; index < fEntries; index++)
{
-
+
const tiff_tag &tag = *fTag [index];
-
+
stream.Put_uint16 (tag.Code ());
stream.Put_uint16 (tag.Type ());
stream.Put_uint32 (tag.Count ());
-
+
uint32 size = tag.Size ();
-
+
if (size <= 4)
{
-
+
tag.Put (stream);
-
+
while (size < 4)
{
stream.Put_uint8 (0);
size++;
}
-
+
}
-
+
else
{
-
+
stream.Put_uint32 (bigData);
-
+
bigData += (size + 1) & ~1;
-
+
}
-
+
}
-
+
stream.Put_uint32 (fChained); // Next IFD offset
-
+
for (index = 0; index < fEntries; index++)
{
-
+
const tiff_tag &tag = *fTag [index];
-
+
uint32 size = tag.Size ();
-
+
if (size > 4)
{
-
+
tag.Put (stream);
-
+
if (size & 1)
stream.Put_uint8 (0);
-
+
}
-
+
}
-
+
}
/******************************************************************************/
dng_basic_tag_set::dng_basic_tag_set (dng_tiff_directory &directory,
const dng_ifd &info)
-
+
: fNewSubFileType (tcNewSubFileType, info.fNewSubFileType)
-
+
, fImageWidth (tcImageWidth , info.fImageWidth )
, fImageLength (tcImageLength, info.fImageLength)
-
+
, fPhotoInterpretation (tcPhotometricInterpretation,
(uint16) info.fPhotometricInterpretation)
-
+
, fFillOrder (tcFillOrder, 1)
-
+
, fSamplesPerPixel (tcSamplesPerPixel, (uint16) info.fSamplesPerPixel)
-
+
, fBitsPerSample (tcBitsPerSample,
fBitsPerSampleData,
info.fSamplesPerPixel)
-
+
, fStrips (info.fUsesStrips)
-
+
, fTileWidth (tcTileWidth, info.fTileWidth)
-
- , fTileLength (fStrips ? tcRowsPerStrip : tcTileLength,
+
+ , fTileLength (fStrips ? tcRowsPerStrip : tcTileLength,
info.fTileLength)
-
- , fTileInfoBuffer (info.TilesPerImage () * 8)
-
+
+ , fTileInfoBuffer (info.TilesPerImage (), 8)
+
, fTileOffsetData (fTileInfoBuffer.Buffer_uint32 ())
-
+
, fTileOffsets (fStrips ? tcStripOffsets : tcTileOffsets,
fTileOffsetData,
info.TilesPerImage ())
-
+
, fTileByteCountData (fTileOffsetData + info.TilesPerImage ())
-
+
, fTileByteCounts (fStrips ? tcStripByteCounts : tcTileByteCounts,
fTileByteCountData,
info.TilesPerImage ())
-
+
, fPlanarConfiguration (tcPlanarConfiguration, pcInterleaved)
-
+
, fCompression (tcCompression, (uint16) info.fCompression)
, fPredictor (tcPredictor , (uint16) info.fPredictor )
-
+
, fExtraSamples (tcExtraSamples,
fExtraSamplesData,
info.fExtraSamplesCount)
-
+
, fSampleFormat (tcSampleFormat,
fSampleFormatData,
info.fSamplesPerPixel)
-
+
, fRowInterleaveFactor (tcRowInterleaveFactor,
(uint16) info.fRowInterleaveFactor)
-
+
, fSubTileBlockSize (tcSubTileBlockSize,
fSubTileBlockSizeData,
2)
-
+
{
-
+
uint32 j;
-
+
for (j = 0; j < info.fSamplesPerPixel; j++)
{
-
+
fBitsPerSampleData [j] = (uint16) info.fBitsPerSample [0];
-
+
}
-
+
directory.Add (&fNewSubFileType);
-
+
directory.Add (&fImageWidth);
directory.Add (&fImageLength);
-
+
directory.Add (&fPhotoInterpretation);
-
+
directory.Add (&fSamplesPerPixel);
-
+
directory.Add (&fBitsPerSample);
-
+
if (info.fBitsPerSample [0] != 8 &&
info.fBitsPerSample [0] != 16 &&
info.fBitsPerSample [0] != 32)
{
-
+
directory.Add (&fFillOrder);
-
+
}
-
+
if (!fStrips)
{
-
+
directory.Add (&fTileWidth);
-
+
}
directory.Add (&fTileLength);
-
+
directory.Add (&fTileOffsets);
directory.Add (&fTileByteCounts);
-
+
directory.Add (&fPlanarConfiguration);
-
+
directory.Add (&fCompression);
-
+
if (info.fPredictor != cpNullPredictor)
{
-
+
directory.Add (&fPredictor);
-
+
}
-
+
if (info.fExtraSamplesCount != 0)
{
-
+
for (j = 0; j < info.fExtraSamplesCount; j++)
{
fExtraSamplesData [j] = (uint16) info.fExtraSamples [j];
}
-
+
directory.Add (&fExtraSamples);
-
+
}
-
+
if (info.fSampleFormat [0] != sfUnsignedInteger)
{
-
+
for (j = 0; j < info.fSamplesPerPixel; j++)
{
fSampleFormatData [j] = (uint16) info.fSampleFormat [j];
}
-
+
directory.Add (&fSampleFormat);
-
+
}
-
+
if (info.fRowInterleaveFactor != 1)
{
-
+
directory.Add (&fRowInterleaveFactor);
-
+
}
-
+
if (info.fSubTileBlockRows != 1 ||
info.fSubTileBlockCols != 1)
{
-
+
fSubTileBlockSizeData [0] = (uint16) info.fSubTileBlockRows;
fSubTileBlockSizeData [1] = (uint16) info.fSubTileBlockCols;
-
+
directory.Add (&fSubTileBlockSize);
-
+
}
-
+
}
/******************************************************************************/
exif_tag_set::exif_tag_set (dng_tiff_directory &directory,
const dng_exif &exif,
bool makerNoteSafe,
const void *makerNoteData,
uint32 makerNoteLength,
bool insideDNG)
: fExifIFD ()
, fGPSIFD ()
-
+
, fExifLink (tcExifIFD, 0)
, fGPSLink (tcGPSInfo, 0)
-
+
, fAddedExifLink (false)
, fAddedGPSLink (false)
-
+
, fExifVersion (tcExifVersion, ttUndefined, 4, fExifVersionData)
-
+
, fExposureTime (tcExposureTime , exif.fExposureTime )
, fShutterSpeedValue (tcShutterSpeedValue, exif.fShutterSpeedValue)
-
+
, fFNumber (tcFNumber , exif.fFNumber )
, fApertureValue (tcApertureValue, exif.fApertureValue)
-
+
, fBrightnessValue (tcBrightnessValue, exif.fBrightnessValue)
-
+
, fExposureBiasValue (tcExposureBiasValue, exif.fExposureBiasValue)
-
+
, fMaxApertureValue (tcMaxApertureValue , exif.fMaxApertureValue)
-
+
, fSubjectDistance (tcSubjectDistance, exif.fSubjectDistance)
-
+
, fFocalLength (tcFocalLength, exif.fFocalLength)
+
+ // Special case: the EXIF 2.2 standard represents ISO speed ratings with 2 bytes,
+ // which cannot hold ISO speed ratings above 65535 (e.g., 102400). In these
+ // cases, we write the maximum representable ISO speed rating value in the EXIF
+ // tag, i.e., 65535.
- , fISOSpeedRatings (tcISOSpeedRatings, (uint16) exif.fISOSpeedRatings [0])
+ , fISOSpeedRatings (tcISOSpeedRatings,
+ (uint16) Min_uint32 (65535,
+ exif.fISOSpeedRatings [0]))
- , fFlash (tcFlash, (uint16) exif.fFlash)
+ , fSensitivityType (tcSensitivityType, (uint16) exif.fSensitivityType)
- , fExposureProgram (tcExposureProgram, (uint16) exif.fExposureProgram)
+ , fStandardOutputSensitivity (tcStandardOutputSensitivity, exif.fStandardOutputSensitivity)
+
+ , fRecommendedExposureIndex (tcRecommendedExposureIndex, exif.fRecommendedExposureIndex)
- , fMeteringMode (tcMeteringMode, (uint16) exif.fMeteringMode)
+ , fISOSpeed (tcISOSpeed, exif.fISOSpeed)
- , fLightSource (tcLightSource, (uint16) exif.fLightSource)
+ , fISOSpeedLatitudeyyy (tcISOSpeedLatitudeyyy, exif.fISOSpeedLatitudeyyy)
- , fSensingMethod (tcSensingMethodExif, (uint16) exif.fSensingMethod)
+ , fISOSpeedLatitudezzz (tcISOSpeedLatitudezzz, exif.fISOSpeedLatitudezzz)
+ , fFlash (tcFlash, (uint16) exif.fFlash)
+
+ , fExposureProgram (tcExposureProgram, (uint16) exif.fExposureProgram)
+
+ , fMeteringMode (tcMeteringMode, (uint16) exif.fMeteringMode)
+
+ , fLightSource (tcLightSource, (uint16) exif.fLightSource)
+
+ , fSensingMethod (tcSensingMethodExif, (uint16) exif.fSensingMethod)
+
, fFocalLength35mm (tcFocalLengthIn35mmFilm, (uint16) exif.fFocalLengthIn35mmFilm)
-
+
, fFileSourceData ((uint8) exif.fFileSource)
, fFileSource (tcFileSource, ttUndefined, 1, &fFileSourceData)
, fSceneTypeData ((uint8) exif.fSceneType)
, fSceneType (tcSceneType, ttUndefined, 1, &fSceneTypeData)
-
+
, fCFAPattern (tcCFAPatternExif,
exif.fCFARepeatPatternRows,
exif.fCFARepeatPatternCols,
&exif.fCFAPattern [0] [0])
-
+
, fCustomRendered (tcCustomRendered , (uint16) exif.fCustomRendered )
, fExposureMode (tcExposureMode , (uint16) exif.fExposureMode )
, fWhiteBalance (tcWhiteBalance , (uint16) exif.fWhiteBalance )
, fSceneCaptureType (tcSceneCaptureType , (uint16) exif.fSceneCaptureType )
, fGainControl (tcGainControl , (uint16) exif.fGainControl )
, fContrast (tcContrast , (uint16) exif.fContrast )
, fSaturation (tcSaturation , (uint16) exif.fSaturation )
, fSharpness (tcSharpness , (uint16) exif.fSharpness )
, fSubjectDistanceRange (tcSubjectDistanceRange, (uint16) exif.fSubjectDistanceRange)
-
+
, fDigitalZoomRatio (tcDigitalZoomRatio, exif.fDigitalZoomRatio)
-
+
, fExposureIndex (tcExposureIndexExif, exif.fExposureIndex)
-
+
, fImageNumber (tcImageNumber, exif.fImageNumber)
-
+
, fSelfTimerMode (tcSelfTimerMode, (uint16) exif.fSelfTimerMode)
-
+
, fBatteryLevelA (tcBatteryLevel, exif.fBatteryLevelA)
, fBatteryLevelR (tcBatteryLevel, exif.fBatteryLevelR)
+ , fColorSpace (tcColorSpace, (uint16) exif.fColorSpace)
+
, fFocalPlaneXResolution (tcFocalPlaneXResolutionExif, exif.fFocalPlaneXResolution)
, fFocalPlaneYResolution (tcFocalPlaneYResolutionExif, exif.fFocalPlaneYResolution)
-
+
, fFocalPlaneResolutionUnit (tcFocalPlaneResolutionUnitExif, (uint16) exif.fFocalPlaneResolutionUnit)
-
+
, fSubjectArea (tcSubjectArea, fSubjectAreaData, exif.fSubjectAreaCount)
, fLensInfo (tcLensInfo, fLensInfoData, 4)
-
+
, fDateTime (tcDateTime , exif.fDateTime .DateTime ())
, fDateTimeOriginal (tcDateTimeOriginal , exif.fDateTimeOriginal .DateTime ())
, fDateTimeDigitized (tcDateTimeDigitized, exif.fDateTimeDigitized.DateTime ())
-
+
, fSubsecTime (tcSubsecTime, exif.fDateTime .Subseconds ())
, fSubsecTimeOriginal (tcSubsecTimeOriginal, exif.fDateTimeOriginal .Subseconds ())
, fSubsecTimeDigitized (tcSubsecTimeDigitized, exif.fDateTimeDigitized.Subseconds ())
- , fTimeZoneOffset (tcTimeZoneOffset, fTimeZoneOffsetData, 2)
+ , fOffsetTime (tcOffsetTime, exif.fDateTime .OffsetTime ())
+ , fOffsetTimeOriginal (tcOffsetTimeOriginal, exif.fDateTimeOriginal .OffsetTime ())
+ , fOffsetTimeDigitized (tcOffsetTimeDigitized, exif.fDateTimeDigitized.OffsetTime ())
, fMake (tcMake, exif.fMake)
, fModel (tcModel, exif.fModel)
-
+
, fArtist (tcArtist, exif.fArtist)
-
+
, fSoftware (tcSoftware, exif.fSoftware)
-
+
, fCopyright (tcCopyright, exif.fCopyright)
+
+ , fImageDescription (tcImageDescription, exif.fImageDescription)
+
+ , fSerialNumber (tcCameraSerialNumber, exif.fCameraSerialNumber)
- , fMakerNoteSafety (tcMakerNoteSafety, makerNoteSafe ? 1 : 0)
+ , fMakerNoteSafety (tcMakerNoteSafety, makerNoteSafe ? 1 : 0)
- , fMakerNote (tcMakerNote, ttUndefined, makerNoteLength, makerNoteData)
+ , fMakerNote (tcMakerNote, ttUndefined, makerNoteLength, makerNoteData)
- , fImageDescription (tcImageDescription, exif.fImageDescription)
+ , fUserComment (tcUserComment, exif.fUserComment)
+
+ , fImageUniqueID (tcImageUniqueID, ttAscii, 33, fImageUniqueIDData)
- , fSerialNumber (tcCameraSerialNumber, exif.fCameraSerialNumber)
+ // EXIF 2.3 tags.
- , fUserComment (tcUserComment, exif.fUserComment)
+ , fCameraOwnerName (tcCameraOwnerNameExif, exif.fOwnerName )
+ , fBodySerialNumber (tcCameraSerialNumberExif, exif.fCameraSerialNumber)
+ , fLensSpecification (tcLensSpecificationExif, fLensInfoData, 4 )
+ , fLensMake (tcLensMakeExif, exif.fLensMake )
+ , fLensModel (tcLensModelExif, exif.fLensName )
+ , fLensSerialNumber (tcLensSerialNumberExif, exif.fLensSerialNumber )
- , fImageUniqueID (tcImageUniqueID, ttAscii, 33, fImageUniqueIDData)
+ // EXIF 2.3.1 tags.
- , fGPSVersionID (tcGPSVersionID, fGPSVersionData, 4)
+ , fTemperature (tcTemperature, exif.fTemperature )
+ , fHumidity (tcHumidity, exif.fHumidity )
+ , fPressure (tcPressure, exif.fPressure )
+ , fWaterDepth (tcWaterDepth, exif.fWaterDepth )
+ , fAcceleration (tcAcceleration, exif.fAcceleration )
+ , fCameraElevationAngle (tcCameraElevationAngle, exif.fCameraElevationAngle)
+ , fGPSVersionID (tcGPSVersionID, fGPSVersionData, 4)
+
, fGPSLatitudeRef (tcGPSLatitudeRef, exif.fGPSLatitudeRef)
, fGPSLatitude (tcGPSLatitude, exif.fGPSLatitude, 3)
-
+
, fGPSLongitudeRef (tcGPSLongitudeRef, exif.fGPSLongitudeRef)
, fGPSLongitude (tcGPSLongitude, exif.fGPSLongitude, 3)
-
+
, fGPSAltitudeRef (tcGPSAltitudeRef, (uint8) exif.fGPSAltitudeRef)
, fGPSAltitude (tcGPSAltitude, exif.fGPSAltitude )
-
+
, fGPSTimeStamp (tcGPSTimeStamp, exif.fGPSTimeStamp, 3)
-
+
, fGPSSatellites (tcGPSSatellites , exif.fGPSSatellites )
, fGPSStatus (tcGPSStatus , exif.fGPSStatus )
, fGPSMeasureMode (tcGPSMeasureMode, exif.fGPSMeasureMode)
-
+
, fGPSDOP (tcGPSDOP, exif.fGPSDOP)
-
+
, fGPSSpeedRef (tcGPSSpeedRef, exif.fGPSSpeedRef)
, fGPSSpeed (tcGPSSpeed , exif.fGPSSpeed )
-
+
, fGPSTrackRef (tcGPSTrackRef, exif.fGPSTrackRef)
, fGPSTrack (tcGPSTrack , exif.fGPSTrack )
-
+
, fGPSImgDirectionRef (tcGPSImgDirectionRef, exif.fGPSImgDirectionRef)
, fGPSImgDirection (tcGPSImgDirection , exif.fGPSImgDirection )
-
+
, fGPSMapDatum (tcGPSMapDatum, exif.fGPSMapDatum)
-
+
, fGPSDestLatitudeRef (tcGPSDestLatitudeRef, exif.fGPSDestLatitudeRef)
, fGPSDestLatitude (tcGPSDestLatitude, exif.fGPSDestLatitude, 3)
-
+
, fGPSDestLongitudeRef (tcGPSDestLongitudeRef, exif.fGPSDestLongitudeRef)
, fGPSDestLongitude (tcGPSDestLongitude, exif.fGPSDestLongitude, 3)
-
+
, fGPSDestBearingRef (tcGPSDestBearingRef, exif.fGPSDestBearingRef)
, fGPSDestBearing (tcGPSDestBearing , exif.fGPSDestBearing )
-
+
, fGPSDestDistanceRef (tcGPSDestDistanceRef, exif.fGPSDestDistanceRef)
, fGPSDestDistance (tcGPSDestDistance , exif.fGPSDestDistance )
-
+
, fGPSProcessingMethod (tcGPSProcessingMethod, exif.fGPSProcessingMethod)
, fGPSAreaInformation (tcGPSAreaInformation , exif.fGPSAreaInformation )
-
+
, fGPSDateStamp (tcGPSDateStamp, exif.fGPSDateStamp)
-
+
, fGPSDifferential (tcGPSDifferential, (uint16) exif.fGPSDifferential)
-
+
+ , fGPSHPositioningError (tcGPSHPositioningError, exif.fGPSHPositioningError)
+
{
-
+
if (exif.fExifVersion)
{
-
+
fExifVersionData [0] = (uint8) (exif.fExifVersion >> 24);
fExifVersionData [1] = (uint8) (exif.fExifVersion >> 16);
fExifVersionData [2] = (uint8) (exif.fExifVersion >> 8);
fExifVersionData [3] = (uint8) (exif.fExifVersion );
-
+
fExifIFD.Add (&fExifVersion);
}
-
+
if (exif.fExposureTime.IsValid ())
{
fExifIFD.Add (&fExposureTime);
}
-
+
if (exif.fShutterSpeedValue.IsValid ())
{
fExifIFD.Add (&fShutterSpeedValue);
}
-
+
if (exif.fFNumber.IsValid ())
{
fExifIFD.Add (&fFNumber);
}
-
+
if (exif.fApertureValue.IsValid ())
{
fExifIFD.Add (&fApertureValue);
}
-
+
if (exif.fBrightnessValue.IsValid ())
{
fExifIFD.Add (&fBrightnessValue);
}
-
+
if (exif.fExposureBiasValue.IsValid ())
{
fExifIFD.Add (&fExposureBiasValue);
}
-
+
if (exif.fMaxApertureValue.IsValid ())
{
fExifIFD.Add (&fMaxApertureValue);
}
-
+
if (exif.fSubjectDistance.IsValid ())
{
fExifIFD.Add (&fSubjectDistance);
}
-
+
if (exif.fFocalLength.IsValid ())
{
fExifIFD.Add (&fFocalLength);
}
-
+
if (exif.fISOSpeedRatings [0] != 0)
{
fExifIFD.Add (&fISOSpeedRatings);
}
-
+
if (exif.fFlash <= 0x0FFFF)
{
fExifIFD.Add (&fFlash);
}
-
+
if (exif.fExposureProgram <= 0x0FFFF)
{
fExifIFD.Add (&fExposureProgram);
}
-
+
if (exif.fMeteringMode <= 0x0FFFF)
{
fExifIFD.Add (&fMeteringMode);
}
-
+
if (exif.fLightSource <= 0x0FFFF)
{
fExifIFD.Add (&fLightSource);
}
-
+
if (exif.fSensingMethod <= 0x0FFFF)
{
fExifIFD.Add (&fSensingMethod);
}
-
+
if (exif.fFocalLengthIn35mmFilm != 0)
{
fExifIFD.Add (&fFocalLength35mm);
}
-
+
if (exif.fFileSource <= 0x0FF)
{
fExifIFD.Add (&fFileSource);
}
-
+
if (exif.fSceneType <= 0x0FF)
{
fExifIFD.Add (&fSceneType);
}
-
+
if (exif.fCFARepeatPatternRows &&
exif.fCFARepeatPatternCols)
{
fExifIFD.Add (&fCFAPattern);
}
-
+
if (exif.fCustomRendered <= 0x0FFFF)
{
fExifIFD.Add (&fCustomRendered);
}
-
+
if (exif.fExposureMode <= 0x0FFFF)
{
fExifIFD.Add (&fExposureMode);
}
-
+
if (exif.fWhiteBalance <= 0x0FFFF)
{
fExifIFD.Add (&fWhiteBalance);
}
-
+
if (exif.fSceneCaptureType <= 0x0FFFF)
{
fExifIFD.Add (&fSceneCaptureType);
}
-
+
if (exif.fGainControl <= 0x0FFFF)
{
fExifIFD.Add (&fGainControl);
}
-
+
if (exif.fContrast <= 0x0FFFF)
{
fExifIFD.Add (&fContrast);
}
-
+
if (exif.fSaturation <= 0x0FFFF)
{
fExifIFD.Add (&fSaturation);
}
-
+
if (exif.fSharpness <= 0x0FFFF)
{
fExifIFD.Add (&fSharpness);
}
-
+
if (exif.fSubjectDistanceRange <= 0x0FFFF)
{
fExifIFD.Add (&fSubjectDistanceRange);
}
-
+
if (exif.fDigitalZoomRatio.IsValid ())
{
fExifIFD.Add (&fDigitalZoomRatio);
}
-
+
if (exif.fExposureIndex.IsValid ())
{
fExifIFD.Add (&fExposureIndex);
}
-
+
if (insideDNG) // TIFF-EP only tags
{
-
+
if (exif.fImageNumber != 0xFFFFFFFF)
{
directory.Add (&fImageNumber);
}
-
+
if (exif.fSelfTimerMode <= 0x0FFFF)
{
directory.Add (&fSelfTimerMode);
}
-
+
if (exif.fBatteryLevelA.NotEmpty ())
{
directory.Add (&fBatteryLevelA);
}
-
+
else if (exif.fBatteryLevelR.IsValid ())
{
directory.Add (&fBatteryLevelR);
}
-
+
}
-
+
+ if (exif.fColorSpace == 1 ||
+ exif.fColorSpace == 0xFFFF)
+ {
+ fExifIFD.Add (&fColorSpace);
+ }
+
if (exif.fFocalPlaneXResolution.IsValid ())
{
fExifIFD.Add (&fFocalPlaneXResolution);
}
-
+
if (exif.fFocalPlaneYResolution.IsValid ())
{
fExifIFD.Add (&fFocalPlaneYResolution);
}
-
+
if (exif.fFocalPlaneResolutionUnit <= 0x0FFFF)
{
fExifIFD.Add (&fFocalPlaneResolutionUnit);
}
-
+
if (exif.fSubjectAreaCount)
{
-
+
fSubjectAreaData [0] = (uint16) exif.fSubjectArea [0];
fSubjectAreaData [1] = (uint16) exif.fSubjectArea [1];
fSubjectAreaData [2] = (uint16) exif.fSubjectArea [2];
fSubjectAreaData [3] = (uint16) exif.fSubjectArea [3];
-
+
fExifIFD.Add (&fSubjectArea);
-
+
}
-
+
if (exif.fLensInfo [0].IsValid () &&
- exif.fLensInfo [1].IsValid () && insideDNG)
+ exif.fLensInfo [1].IsValid ())
{
-
+
fLensInfoData [0] = exif.fLensInfo [0];
fLensInfoData [1] = exif.fLensInfo [1];
fLensInfoData [2] = exif.fLensInfo [2];
fLensInfoData [3] = exif.fLensInfo [3];
- directory.Add (&fLensInfo);
-
+ if (insideDNG)
+ {
+ directory.Add (&fLensInfo);
+ }
+
}
-
+
if (exif.fDateTime.IsValid ())
{
-
+
directory.Add (&fDateTime);
-
+
if (exif.fDateTime.Subseconds ().NotEmpty ())
{
fExifIFD.Add (&fSubsecTime);
}
-
+
}
-
+
if (exif.fDateTimeOriginal.IsValid ())
{
-
+
fExifIFD.Add (&fDateTimeOriginal);
-
+
if (exif.fDateTimeOriginal.Subseconds ().NotEmpty ())
{
fExifIFD.Add (&fSubsecTimeOriginal);
}
-
+
}
-
+
if (exif.fDateTimeDigitized.IsValid ())
{
-
+
fExifIFD.Add (&fDateTimeDigitized);
-
+
if (exif.fDateTimeDigitized.Subseconds ().NotEmpty ())
{
fExifIFD.Add (&fSubsecTimeDigitized);
}
-
- }
-
- if (insideDNG) // TIFF-EP only tags
- {
-
- if (exif.fDateTimeOriginal.IsValid () &&
- exif.fDateTimeOriginal.TimeZone ().IsExactHourOffset ())
- {
-
- fTimeZoneOffsetData [0] = (int16) exif.fDateTimeOriginal.TimeZone ().ExactHourOffset ();
- fTimeZoneOffsetData [1] = (int16) exif.fDateTime .TimeZone ().ExactHourOffset ();
-
- if (!exif.fDateTime.IsValid () ||
- !exif.fDateTime.TimeZone ().IsExactHourOffset ())
- {
- fTimeZoneOffset.SetCount (1);
- }
-
- directory.Add (&fTimeZoneOffset);
-
- }
-
+
}
-
+
if (exif.fMake.NotEmpty ())
{
directory.Add (&fMake);
}
-
+
if (exif.fModel.NotEmpty ())
{
directory.Add (&fModel);
}
-
+
if (exif.fArtist.NotEmpty ())
{
directory.Add (&fArtist);
}
-
+
if (exif.fSoftware.NotEmpty ())
{
directory.Add (&fSoftware);
}
-
+
if (exif.fCopyright.NotEmpty ())
{
directory.Add (&fCopyright);
}
-
+
if (exif.fImageDescription.NotEmpty ())
{
directory.Add (&fImageDescription);
}
-
+
if (exif.fCameraSerialNumber.NotEmpty () && insideDNG)
{
directory.Add (&fSerialNumber);
}
-
+
if (makerNoteSafe && makerNoteData)
{
-
+
directory.Add (&fMakerNoteSafety);
-
+
fExifIFD.Add (&fMakerNote);
-
+
}
-
+
if (exif.fUserComment.NotEmpty ())
{
fExifIFD.Add (&fUserComment);
}
-
+
if (exif.fImageUniqueID.IsValid ())
{
-
+
for (uint32 j = 0; j < 16; j++)
{
-
+
sprintf (fImageUniqueIDData + j * 2,
"%02X",
(unsigned) exif.fImageUniqueID.data [j]);
+
+ }
+
+ fExifIFD.Add (&fImageUniqueID);
+
+ }
+
+ if (exif.AtLeastVersion0230 ())
+ {
+ if (exif.fSensitivityType != 0)
+ {
+
+ fExifIFD.Add (&fSensitivityType);
+
}
- fExifIFD.Add (&fImageUniqueID);
+ // Sensitivity tags. Do not write these extra tags unless the SensitivityType
+ // and PhotographicSensitivity (i.e., ISOSpeedRatings) values are valid.
- }
+ if (exif.fSensitivityType != 0 &&
+ exif.fISOSpeedRatings [0] != 0)
+ {
+
+ // Standard Output Sensitivity (SOS).
+
+ if (exif.fStandardOutputSensitivity != 0)
+ {
+ fExifIFD.Add (&fStandardOutputSensitivity);
+ }
+
+ // Recommended Exposure Index (REI).
+
+ if (exif.fRecommendedExposureIndex != 0)
+ {
+ fExifIFD.Add (&fRecommendedExposureIndex);
+ }
+
+ // ISO Speed.
+
+ if (exif.fISOSpeed != 0)
+ {
+
+ fExifIFD.Add (&fISOSpeed);
+
+ if (exif.fISOSpeedLatitudeyyy != 0 &&
+ exif.fISOSpeedLatitudezzz != 0)
+ {
+
+ fExifIFD.Add (&fISOSpeedLatitudeyyy);
+ fExifIFD.Add (&fISOSpeedLatitudezzz);
+
+ }
+
+ }
+
+ }
+
+ if (exif.fOwnerName.NotEmpty ())
+ {
+ fExifIFD.Add (&fCameraOwnerName);
+ }
+
+ if (exif.fCameraSerialNumber.NotEmpty ())
+ {
+ fExifIFD.Add (&fBodySerialNumber);
+ }
+ if (exif.fLensInfo [0].IsValid () &&
+ exif.fLensInfo [1].IsValid ())
+ {
+ fExifIFD.Add (&fLensSpecification);
+ }
+
+ if (exif.fLensMake.NotEmpty ())
+ {
+ fExifIFD.Add (&fLensMake);
+ }
+
+ if (exif.fLensName.NotEmpty ())
+ {
+ fExifIFD.Add (&fLensModel);
+ }
+
+ if (exif.fLensSerialNumber.NotEmpty ())
+ {
+ fExifIFD.Add (&fLensSerialNumber);
+ }
+
+ }
+
+ if (exif.AtLeastVersion0231 ())
+ {
+
+ if (exif.fDateTime.IsValid () &&
+ exif.fDateTime.TimeZone ().IsValid ())
+ {
+ fExifIFD.Add (&fOffsetTime);
+ }
+
+ if (exif.fDateTimeOriginal.IsValid () &&
+ exif.fDateTimeOriginal.TimeZone ().IsValid ())
+ {
+ fExifIFD.Add (&fOffsetTimeOriginal);
+ }
+
+ if (exif.fDateTimeDigitized.IsValid () &&
+ exif.fDateTimeDigitized.TimeZone ().IsValid ())
+ {
+ fExifIFD.Add (&fOffsetTimeDigitized);
+ }
+
+ if (exif.fTemperature.IsValid ())
+ {
+ fExifIFD.Add (&fTemperature);
+ }
+
+ if (exif.fHumidity.IsValid ())
+ {
+ fExifIFD.Add (&fHumidity);
+ }
+
+ if (exif.fPressure.IsValid ())
+ {
+ fExifIFD.Add (&fPressure);
+ }
+
+ if (exif.fWaterDepth.IsValid ())
+ {
+ fExifIFD.Add (&fWaterDepth);
+ }
+
+ if (exif.fAcceleration.IsValid ())
+ {
+ fExifIFD.Add (&fAcceleration);
+ }
+
+ if (exif.fCameraElevationAngle.IsValid ())
+ {
+ fExifIFD.Add (&fCameraElevationAngle);
+ }
+
+ }
+
if (exif.fGPSVersionID)
{
-
+
fGPSVersionData [0] = (uint8) (exif.fGPSVersionID >> 24);
fGPSVersionData [1] = (uint8) (exif.fGPSVersionID >> 16);
fGPSVersionData [2] = (uint8) (exif.fGPSVersionID >> 8);
fGPSVersionData [3] = (uint8) (exif.fGPSVersionID );
-
+
fGPSIFD.Add (&fGPSVersionID);
-
+
}
-
+
if (exif.fGPSLatitudeRef.NotEmpty () &&
exif.fGPSLatitude [0].IsValid ())
{
fGPSIFD.Add (&fGPSLatitudeRef);
fGPSIFD.Add (&fGPSLatitude );
}
-
+
if (exif.fGPSLongitudeRef.NotEmpty () &&
exif.fGPSLongitude [0].IsValid ())
{
fGPSIFD.Add (&fGPSLongitudeRef);
fGPSIFD.Add (&fGPSLongitude );
}
-
+
if (exif.fGPSAltitudeRef <= 0x0FF)
{
fGPSIFD.Add (&fGPSAltitudeRef);
}
-
+
if (exif.fGPSAltitude.IsValid ())
{
fGPSIFD.Add (&fGPSAltitude);
}
-
+
if (exif.fGPSTimeStamp [0].IsValid ())
{
fGPSIFD.Add (&fGPSTimeStamp);
}
-
+
if (exif.fGPSSatellites.NotEmpty ())
{
fGPSIFD.Add (&fGPSSatellites);
}
-
+
if (exif.fGPSStatus.NotEmpty ())
{
fGPSIFD.Add (&fGPSStatus);
}
-
+
if (exif.fGPSMeasureMode.NotEmpty ())
{
fGPSIFD.Add (&fGPSMeasureMode);
}
-
+
if (exif.fGPSDOP.IsValid ())
{
fGPSIFD.Add (&fGPSDOP);
}
-
+
if (exif.fGPSSpeedRef.NotEmpty ())
{
fGPSIFD.Add (&fGPSSpeedRef);
}
-
+
if (exif.fGPSSpeed.IsValid ())
{
fGPSIFD.Add (&fGPSSpeed);
}
-
+
if (exif.fGPSTrackRef.NotEmpty ())
{
fGPSIFD.Add (&fGPSTrackRef);
}
-
+
if (exif.fGPSTrack.IsValid ())
{
fGPSIFD.Add (&fGPSTrack);
}
-
+
if (exif.fGPSImgDirectionRef.NotEmpty ())
{
fGPSIFD.Add (&fGPSImgDirectionRef);
}
-
+
if (exif.fGPSImgDirection.IsValid ())
{
fGPSIFD.Add (&fGPSImgDirection);
}
if (exif.fGPSMapDatum.NotEmpty ())
{
fGPSIFD.Add (&fGPSMapDatum);
}
-
+
if (exif.fGPSDestLatitudeRef.NotEmpty () &&
exif.fGPSDestLatitude [0].IsValid ())
{
fGPSIFD.Add (&fGPSDestLatitudeRef);
fGPSIFD.Add (&fGPSDestLatitude );
}
-
+
if (exif.fGPSDestLongitudeRef.NotEmpty () &&
exif.fGPSDestLongitude [0].IsValid ())
{
fGPSIFD.Add (&fGPSDestLongitudeRef);
fGPSIFD.Add (&fGPSDestLongitude );
}
-
+
if (exif.fGPSDestBearingRef.NotEmpty ())
{
fGPSIFD.Add (&fGPSDestBearingRef);
}
-
+
if (exif.fGPSDestBearing.IsValid ())
{
fGPSIFD.Add (&fGPSDestBearing);
}
if (exif.fGPSDestDistanceRef.NotEmpty ())
{
fGPSIFD.Add (&fGPSDestDistanceRef);
}
-
+
if (exif.fGPSDestDistance.IsValid ())
{
fGPSIFD.Add (&fGPSDestDistance);
}
-
+
if (exif.fGPSProcessingMethod.NotEmpty ())
{
fGPSIFD.Add (&fGPSProcessingMethod);
}
if (exif.fGPSAreaInformation.NotEmpty ())
{
fGPSIFD.Add (&fGPSAreaInformation);
}
-
+
if (exif.fGPSDateStamp.NotEmpty ())
{
fGPSIFD.Add (&fGPSDateStamp);
}
-
+
if (exif.fGPSDifferential <= 0x0FFFF)
{
fGPSIFD.Add (&fGPSDifferential);
}
- AddLinks (directory);
+ if (exif.AtLeastVersion0230 ())
+ {
+
+ if (exif.fGPSHPositioningError.IsValid ())
+ {
+ fGPSIFD.Add (&fGPSHPositioningError);
+ }
+ }
+
+ AddLinks (directory);
+
}
/******************************************************************************/
void exif_tag_set::AddLinks (dng_tiff_directory &directory)
{
-
+
if (fExifIFD.Size () != 0 && !fAddedExifLink)
{
-
+
directory.Add (&fExifLink);
-
+
fAddedExifLink = true;
-
+
}
-
+
if (fGPSIFD.Size () != 0 && !fAddedGPSLink)
{
-
+
directory.Add (&fGPSLink);
-
+
fAddedGPSLink = true;
-
+
}
-
+
}
-
+
/******************************************************************************/
class range_tag_set
{
-
+
private:
-
+
uint32 fActiveAreaData [4];
-
+
tag_uint32_ptr fActiveArea;
-
+
uint32 fMaskedAreaData [kMaxMaskedAreas * 4];
-
+
tag_uint32_ptr fMaskedAreas;
-
+
tag_uint16_ptr fLinearizationTable;
-
+
uint16 fBlackLevelRepeatDimData [2];
-
+
tag_uint16_ptr fBlackLevelRepeatDim;
-
+
dng_urational fBlackLevelData [kMaxBlackPattern *
kMaxBlackPattern *
kMaxSamplesPerPixel];
-
+
tag_urational_ptr fBlackLevel;
-
+
dng_memory_data fBlackLevelDeltaHData;
dng_memory_data fBlackLevelDeltaVData;
-
+
tag_srational_ptr fBlackLevelDeltaH;
tag_srational_ptr fBlackLevelDeltaV;
-
+
uint16 fWhiteLevelData16 [kMaxSamplesPerPixel];
uint32 fWhiteLevelData32 [kMaxSamplesPerPixel];
-
+
tag_uint16_ptr fWhiteLevel16;
tag_uint32_ptr fWhiteLevel32;
-
+
public:
-
+
range_tag_set (dng_tiff_directory &directory,
const dng_negative &negative);
-
+
};
-
+
/******************************************************************************/
range_tag_set::range_tag_set (dng_tiff_directory &directory,
const dng_negative &negative)
-
+
: fActiveArea (tcActiveArea,
fActiveAreaData,
4)
-
+
, fMaskedAreas (tcMaskedAreas,
fMaskedAreaData,
0)
-
+
, fLinearizationTable (tcLinearizationTable,
NULL,
0)
-
+
, fBlackLevelRepeatDim (tcBlackLevelRepeatDim,
fBlackLevelRepeatDimData,
2)
-
+
, fBlackLevel (tcBlackLevel,
fBlackLevelData)
-
+
, fBlackLevelDeltaHData ()
, fBlackLevelDeltaVData ()
-
+
, fBlackLevelDeltaH (tcBlackLevelDeltaH)
, fBlackLevelDeltaV (tcBlackLevelDeltaV)
-
+
, fWhiteLevel16 (tcWhiteLevel,
fWhiteLevelData16)
-
+
, fWhiteLevel32 (tcWhiteLevel,
fWhiteLevelData32)
-
+
{
-
+
const dng_image &rawImage (negative.RawImage ());
-
+
const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo ();
-
+
if (rangeInfo)
{
-
+
// ActiveArea:
-
+
{
-
+
const dng_rect &r = rangeInfo->fActiveArea;
-
+
if (r.NotEmpty ())
{
-
+
fActiveAreaData [0] = r.t;
fActiveAreaData [1] = r.l;
fActiveAreaData [2] = r.b;
fActiveAreaData [3] = r.r;
-
+
directory.Add (&fActiveArea);
-
+
}
-
+
}
-
+
// MaskedAreas:
-
+
if (rangeInfo->fMaskedAreaCount)
{
-
+
fMaskedAreas.SetCount (rangeInfo->fMaskedAreaCount * 4);
-
+
for (uint32 index = 0; index < rangeInfo->fMaskedAreaCount; index++)
{
-
+
const dng_rect &r = rangeInfo->fMaskedArea [index];
-
+
fMaskedAreaData [index * 4 + 0] = r.t;
fMaskedAreaData [index * 4 + 1] = r.l;
fMaskedAreaData [index * 4 + 2] = r.b;
fMaskedAreaData [index * 4 + 3] = r.r;
-
+
}
-
+
directory.Add (&fMaskedAreas);
-
+
}
-
+
// LinearizationTable:
if (rangeInfo->fLinearizationTable.Get ())
{
-
+
fLinearizationTable.SetData (rangeInfo->fLinearizationTable->Buffer_uint16 () );
fLinearizationTable.SetCount (rangeInfo->fLinearizationTable->LogicalSize () >> 1);
-
+
directory.Add (&fLinearizationTable);
-
+
}
-
+
// BlackLevelRepeatDim:
-
+
{
-
+
fBlackLevelRepeatDimData [0] = (uint16) rangeInfo->fBlackLevelRepeatRows;
fBlackLevelRepeatDimData [1] = (uint16) rangeInfo->fBlackLevelRepeatCols;
-
+
directory.Add (&fBlackLevelRepeatDim);
-
+
}
-
+
// BlackLevel:
-
+
{
-
+
uint32 index = 0;
-
+
for (uint16 v = 0; v < rangeInfo->fBlackLevelRepeatRows; v++)
{
-
+
for (uint32 h = 0; h < rangeInfo->fBlackLevelRepeatCols; h++)
{
-
+
for (uint32 c = 0; c < rawImage.Planes (); c++)
{
-
+
fBlackLevelData [index++] = rangeInfo->BlackLevel (v, h, c);
-
+
}
-
+
}
-
+
}
-
+
fBlackLevel.SetCount (rangeInfo->fBlackLevelRepeatRows *
rangeInfo->fBlackLevelRepeatCols * rawImage.Planes ());
-
+
directory.Add (&fBlackLevel);
-
+
}
-
+
// BlackLevelDeltaH:
-
+
if (rangeInfo->ColumnBlackCount ())
{
-
+
uint32 count = rangeInfo->ColumnBlackCount ();
-
- fBlackLevelDeltaHData.Allocate (count * sizeof (dng_srational));
-
+
+ fBlackLevelDeltaHData.Allocate (count, sizeof (dng_srational));
+
dng_srational *blacks = (dng_srational *) fBlackLevelDeltaHData.Buffer ();
-
+
for (uint32 col = 0; col < count; col++)
{
-
+
blacks [col] = rangeInfo->ColumnBlack (col);
-
+
}
-
+
fBlackLevelDeltaH.SetData (blacks);
fBlackLevelDeltaH.SetCount (count );
-
+
directory.Add (&fBlackLevelDeltaH);
-
+
}
-
+
// BlackLevelDeltaV:
-
+
if (rangeInfo->RowBlackCount ())
{
-
+
uint32 count = rangeInfo->RowBlackCount ();
-
- fBlackLevelDeltaVData.Allocate (count * sizeof (dng_srational));
-
+
+ fBlackLevelDeltaVData.Allocate (count, sizeof (dng_srational));
+
dng_srational *blacks = (dng_srational *) fBlackLevelDeltaVData.Buffer ();
-
+
for (uint32 row = 0; row < count; row++)
{
-
+
blacks [row] = rangeInfo->RowBlack (row);
-
+
}
-
+
fBlackLevelDeltaV.SetData (blacks);
fBlackLevelDeltaV.SetCount (count );
-
+
directory.Add (&fBlackLevelDeltaV);
-
+
}
-
- }
-
+
+ }
+
+ else if (negative.RawImageBlackLevel ())
+ {
+
+ for (uint32 c = 0; c < rawImage.Planes (); c++)
+ {
+
+ fBlackLevelData [c] = dng_urational (negative.RawImageBlackLevel (), 1);
+
+ }
+
+ fBlackLevel.SetCount (rawImage.Planes ());
+
+ directory.Add (&fBlackLevel);
+
+ }
+
// WhiteLevel:
-
+
// Only use the 32-bit data type if we must use it since there
// are some lazy (non-Adobe) DNG readers out there.
-
+
bool needs32 = false;
-
+
fWhiteLevel16.SetCount (rawImage.Planes ());
fWhiteLevel32.SetCount (rawImage.Planes ());
-
+
for (uint32 c = 0; c < fWhiteLevel16.Count (); c++)
{
-
+
fWhiteLevelData32 [c] = negative.WhiteLevel (c);
-
+
if (fWhiteLevelData32 [c] > 0x0FFFF)
{
needs32 = true;
}
-
+
fWhiteLevelData16 [c] = (uint16) fWhiteLevelData32 [c];
-
+
}
-
+
if (needs32)
{
directory.Add (&fWhiteLevel32);
}
-
+
else
{
directory.Add (&fWhiteLevel16);
}
-
+
}
/******************************************************************************/
class mosaic_tag_set
{
-
+
private:
-
+
uint16 fCFARepeatPatternDimData [2];
-
+
tag_uint16_ptr fCFARepeatPatternDim;
-
+
uint8 fCFAPatternData [kMaxCFAPattern *
kMaxCFAPattern];
-
+
tag_uint8_ptr fCFAPattern;
-
+
uint8 fCFAPlaneColorData [kMaxColorPlanes];
-
+
tag_uint8_ptr fCFAPlaneColor;
-
+
tag_uint16 fCFALayout;
-
+
tag_uint32 fGreenSplit;
-
+
public:
-
+
mosaic_tag_set (dng_tiff_directory &directory,
const dng_mosaic_info &info);
-
+
};
-
+
/******************************************************************************/
mosaic_tag_set::mosaic_tag_set (dng_tiff_directory &directory,
const dng_mosaic_info &info)
: fCFARepeatPatternDim (tcCFARepeatPatternDim,
fCFARepeatPatternDimData,
2)
-
+
, fCFAPattern (tcCFAPattern,
fCFAPatternData)
-
+
, fCFAPlaneColor (tcCFAPlaneColor,
fCFAPlaneColorData)
-
+
, fCFALayout (tcCFALayout,
(uint16) info.fCFALayout)
-
+
, fGreenSplit (tcBayerGreenSplit,
info.fBayerGreenSplit)
-
+
{
-
+
if (info.IsColorFilterArray ())
{
-
+
// CFARepeatPatternDim:
-
+
fCFARepeatPatternDimData [0] = (uint16) info.fCFAPatternSize.v;
fCFARepeatPatternDimData [1] = (uint16) info.fCFAPatternSize.h;
-
+
directory.Add (&fCFARepeatPatternDim);
-
+
// CFAPattern:
-
+
fCFAPattern.SetCount (info.fCFAPatternSize.v *
info.fCFAPatternSize.h);
-
+
for (int32 r = 0; r < info.fCFAPatternSize.v; r++)
{
-
+
for (int32 c = 0; c < info.fCFAPatternSize.h; c++)
{
-
+
fCFAPatternData [r * info.fCFAPatternSize.h + c] = info.fCFAPattern [r] [c];
-
+
}
-
+
}
-
+
directory.Add (&fCFAPattern);
-
+
// CFAPlaneColor:
-
+
fCFAPlaneColor.SetCount (info.fColorPlanes);
-
+
for (uint32 j = 0; j < info.fColorPlanes; j++)
{
-
+
fCFAPlaneColorData [j] = info.fCFAPlaneColor [j];
-
+
}
-
+
directory.Add (&fCFAPlaneColor);
-
+
// CFALayout:
-
+
fCFALayout.Set ((uint16) info.fCFALayout);
-
+
directory.Add (&fCFALayout);
-
+
// BayerGreenSplit: (only include if the pattern is a Bayer pattern)
-
+
if (info.fCFAPatternSize == dng_point (2, 2) &&
info.fColorPlanes == 3)
{
-
+
directory.Add (&fGreenSplit);
-
+
}
-
+
}
}
-
+
/******************************************************************************/
class color_tag_set
{
-
+
private:
-
+
uint32 fColorChannels;
-
+
tag_matrix fCameraCalibration1;
tag_matrix fCameraCalibration2;
-
+
tag_string fCameraCalibrationSignature;
-
+
tag_string fAsShotProfileName;
dng_urational fAnalogBalanceData [4];
-
+
tag_urational_ptr fAnalogBalance;
-
+
dng_urational fAsShotNeutralData [4];
-
+
tag_urational_ptr fAsShotNeutral;
-
+
dng_urational fAsShotWhiteXYData [2];
-
+
tag_urational_ptr fAsShotWhiteXY;
-
+
tag_urational fLinearResponseLimit;
-
+
public:
-
+
color_tag_set (dng_tiff_directory &directory,
const dng_negative &negative);
-
+
};
-
+
/******************************************************************************/
color_tag_set::color_tag_set (dng_tiff_directory &directory,
const dng_negative &negative)
-
+
: fColorChannels (negative.ColorChannels ())
-
+
, fCameraCalibration1 (tcCameraCalibration1,
negative.CameraCalibration1 ())
-
+
, fCameraCalibration2 (tcCameraCalibration2,
negative.CameraCalibration2 ())
-
+
, fCameraCalibrationSignature (tcCameraCalibrationSignature,
negative.CameraCalibrationSignature ())
-
+
, fAsShotProfileName (tcAsShotProfileName,
negative.AsShotProfileName ())
, fAnalogBalance (tcAnalogBalance,
fAnalogBalanceData,
fColorChannels)
-
+
, fAsShotNeutral (tcAsShotNeutral,
fAsShotNeutralData,
fColorChannels)
-
+
, fAsShotWhiteXY (tcAsShotWhiteXY,
fAsShotWhiteXYData,
2)
-
+
, fLinearResponseLimit (tcLinearResponseLimit,
negative.LinearResponseLimitR ())
-
+
{
-
+
if (fColorChannels > 1)
{
-
+
uint32 channels2 = fColorChannels * fColorChannels;
-
+
if (fCameraCalibration1.Count () == channels2)
{
-
+
directory.Add (&fCameraCalibration1);
-
+
}
-
+
if (fCameraCalibration2.Count () == channels2)
{
-
+
directory.Add (&fCameraCalibration2);
-
+
}
-
+
if (fCameraCalibration1.Count () == channels2 ||
fCameraCalibration2.Count () == channels2)
{
-
+
if (negative.CameraCalibrationSignature ().NotEmpty ())
{
-
+
directory.Add (&fCameraCalibrationSignature);
-
+
}
-
+
}
-
+
if (negative.AsShotProfileName ().NotEmpty ())
{
-
+
directory.Add (&fAsShotProfileName);
-
+
}
-
+
for (uint32 j = 0; j < fColorChannels; j++)
{
-
+
fAnalogBalanceData [j] = negative.AnalogBalanceR (j);
-
+
}
-
+
directory.Add (&fAnalogBalance);
-
+
if (negative.HasCameraNeutral ())
{
-
+
for (uint32 k = 0; k < fColorChannels; k++)
{
-
+
fAsShotNeutralData [k] = negative.CameraNeutralR (k);
-
+
}
-
+
directory.Add (&fAsShotNeutral);
-
+
}
-
+
else if (negative.HasCameraWhiteXY ())
{
-
+
negative.GetCameraWhiteXY (fAsShotWhiteXYData [0],
fAsShotWhiteXYData [1]);
-
+
directory.Add (&fAsShotWhiteXY);
-
+
}
-
+
directory.Add (&fLinearResponseLimit);
-
+
}
-
+
}
/******************************************************************************/
class profile_tag_set
{
-
+
private:
-
+
tag_uint16 fCalibrationIlluminant1;
tag_uint16 fCalibrationIlluminant2;
-
+
tag_matrix fColorMatrix1;
tag_matrix fColorMatrix2;
-
+
tag_matrix fForwardMatrix1;
tag_matrix fForwardMatrix2;
tag_matrix fReductionMatrix1;
tag_matrix fReductionMatrix2;
-
+
tag_string fProfileName;
-
+
tag_string fProfileCalibrationSignature;
-
+
tag_uint32 fEmbedPolicyTag;
-
+
tag_string fCopyrightTag;
-
+
uint32 fHueSatMapDimData [3];
-
+
tag_uint32_ptr fHueSatMapDims;
tag_data_ptr fHueSatData1;
tag_data_ptr fHueSatData2;
-
+
+ tag_uint32 fHueSatMapEncodingTag;
+
uint32 fLookTableDimData [3];
-
+
tag_uint32_ptr fLookTableDims;
tag_data_ptr fLookTableData;
+
+ tag_uint32 fLookTableEncodingTag;
- dng_memory_data fToneCurveBuffer;
+ tag_srational fBaselineExposureOffsetTag;
+
+ tag_uint32 fDefaultBlackRenderTag;
+ dng_memory_data fToneCurveBuffer;
+
tag_data_ptr fToneCurveTag;
public:
-
+
profile_tag_set (dng_tiff_directory &directory,
const dng_camera_profile &profile);
-
+
};
-
+
/******************************************************************************/
profile_tag_set::profile_tag_set (dng_tiff_directory &directory,
const dng_camera_profile &profile)
-
+
: fCalibrationIlluminant1 (tcCalibrationIlluminant1,
(uint16) profile.CalibrationIlluminant1 ())
-
+
, fCalibrationIlluminant2 (tcCalibrationIlluminant2,
(uint16) profile.CalibrationIlluminant2 ())
-
+
, fColorMatrix1 (tcColorMatrix1,
profile.ColorMatrix1 ())
-
+
, fColorMatrix2 (tcColorMatrix2,
profile.ColorMatrix2 ())
, fForwardMatrix1 (tcForwardMatrix1,
profile.ForwardMatrix1 ())
-
+
, fForwardMatrix2 (tcForwardMatrix2,
profile.ForwardMatrix2 ())
-
+
, fReductionMatrix1 (tcReductionMatrix1,
profile.ReductionMatrix1 ())
-
+
, fReductionMatrix2 (tcReductionMatrix2,
profile.ReductionMatrix2 ())
-
+
, fProfileName (tcProfileName,
profile.Name (),
false)
-
+
, fProfileCalibrationSignature (tcProfileCalibrationSignature,
profile.ProfileCalibrationSignature (),
false)
-
+
, fEmbedPolicyTag (tcProfileEmbedPolicy,
profile.EmbedPolicy ())
-
+
, fCopyrightTag (tcProfileCopyright,
profile.Copyright (),
false)
-
- , fHueSatMapDims (tcProfileHueSatMapDims,
+
+ , fHueSatMapDims (tcProfileHueSatMapDims,
fHueSatMapDimData,
3)
-
+
, fHueSatData1 (tcProfileHueSatMapData1,
ttFloat,
profile.HueSatDeltas1 ().DeltasCount () * 3,
- profile.HueSatDeltas1 ().GetDeltas ())
-
+ profile.HueSatDeltas1 ().GetConstDeltas ())
+
, fHueSatData2 (tcProfileHueSatMapData2,
ttFloat,
profile.HueSatDeltas2 ().DeltasCount () * 3,
- profile.HueSatDeltas2 ().GetDeltas ())
-
+ profile.HueSatDeltas2 ().GetConstDeltas ())
+
+ , fHueSatMapEncodingTag (tcProfileHueSatMapEncoding,
+ profile.HueSatMapEncoding ())
+
, fLookTableDims (tcProfileLookTableDims,
fLookTableDimData,
3)
-
+
, fLookTableData (tcProfileLookTableData,
ttFloat,
profile.LookTable ().DeltasCount () * 3,
- profile.LookTable ().GetDeltas ())
-
+ profile.LookTable ().GetConstDeltas ())
+
+ , fLookTableEncodingTag (tcProfileLookTableEncoding,
+ profile.LookTableEncoding ())
+
+ , fBaselineExposureOffsetTag (tcBaselineExposureOffset,
+ profile.BaselineExposureOffset ())
+
+ , fDefaultBlackRenderTag (tcDefaultBlackRender,
+ profile.DefaultBlackRender ())
+
, fToneCurveBuffer ()
-
+
, fToneCurveTag (tcProfileToneCurve,
ttFloat,
0,
NULL)
{
-
+
if (profile.HasColorMatrix1 ())
{
-
+
uint32 colorChannels = profile.ColorMatrix1 ().Rows ();
-
+
directory.Add (&fCalibrationIlluminant1);
-
+
directory.Add (&fColorMatrix1);
-
+
if (fForwardMatrix1.Count () == colorChannels * 3)
{
-
+
directory.Add (&fForwardMatrix1);
}
-
+
if (colorChannels > 3 && fReductionMatrix1.Count () == colorChannels * 3)
{
-
+
directory.Add (&fReductionMatrix1);
-
+
}
-
+
if (profile.HasColorMatrix2 ())
{
-
+
directory.Add (&fCalibrationIlluminant2);
-
+
directory.Add (&fColorMatrix2);
-
+
if (fForwardMatrix2.Count () == colorChannels * 3)
{
-
+
directory.Add (&fForwardMatrix2);
}
-
+
if (colorChannels > 3 && fReductionMatrix2.Count () == colorChannels * 3)
{
-
+
directory.Add (&fReductionMatrix2);
-
+
}
-
+
}
-
+
if (profile.Name ().NotEmpty ())
{
-
+
directory.Add (&fProfileName);
}
-
+
if (profile.ProfileCalibrationSignature ().NotEmpty ())
{
-
+
directory.Add (&fProfileCalibrationSignature);
-
+
}
-
+
directory.Add (&fEmbedPolicyTag);
-
+
if (profile.Copyright ().NotEmpty ())
{
-
+
directory.Add (&fCopyrightTag);
-
+
}
-
+
bool haveHueSat1 = profile.HueSatDeltas1 ().IsValid ();
-
+
bool haveHueSat2 = profile.HueSatDeltas2 ().IsValid () &&
profile.HasColorMatrix2 ();
if (haveHueSat1 || haveHueSat2)
{
-
+
uint32 hueDivs = 0;
uint32 satDivs = 0;
uint32 valDivs = 0;
if (haveHueSat1)
{
profile.HueSatDeltas1 ().GetDivisions (hueDivs,
satDivs,
valDivs);
}
else
{
profile.HueSatDeltas2 ().GetDivisions (hueDivs,
satDivs,
valDivs);
}
-
+
fHueSatMapDimData [0] = hueDivs;
fHueSatMapDimData [1] = satDivs;
fHueSatMapDimData [2] = valDivs;
-
+
directory.Add (&fHueSatMapDims);
- }
+ // Don't bother including the ProfileHueSatMapEncoding tag unless it's
+ // non-linear.
+
+ if (profile.HueSatMapEncoding () != encoding_Linear)
+ {
+ directory.Add (&fHueSatMapEncodingTag);
+
+ }
+
+ }
+
if (haveHueSat1)
{
-
+
directory.Add (&fHueSatData1);
-
+
}
-
+
if (haveHueSat2)
{
-
+
directory.Add (&fHueSatData2);
-
+
}
-
+
if (profile.HasLookTable ())
{
-
+
uint32 hueDivs = 0;
uint32 satDivs = 0;
uint32 valDivs = 0;
profile.LookTable ().GetDivisions (hueDivs,
satDivs,
valDivs);
fLookTableDimData [0] = hueDivs;
fLookTableDimData [1] = satDivs;
fLookTableDimData [2] = valDivs;
-
+
directory.Add (&fLookTableDims);
-
+
directory.Add (&fLookTableData);
+
+ // Don't bother including the ProfileLookTableEncoding tag unless it's
+ // non-linear.
+ if (profile.LookTableEncoding () != encoding_Linear)
+ {
+
+ directory.Add (&fLookTableEncodingTag);
+
+ }
+
}
- if (profile.ToneCurve ().IsValid ())
+ // Don't bother including the BaselineExposureOffset tag unless it's both
+ // valid and non-zero.
+
+ if (profile.BaselineExposureOffset ().IsValid ())
+ {
+
+ if (profile.BaselineExposureOffset ().As_real64 () != 0.0)
+ {
+
+ directory.Add (&fBaselineExposureOffsetTag);
+
+ }
+
+ }
+
+ if (profile.DefaultBlackRender () != defaultBlackRender_Auto)
{
+ directory.Add (&fDefaultBlackRenderTag);
+
+ }
+
+ if (profile.ToneCurve ().IsValid ())
+ {
+
// Tone curve stored as pairs of 32-bit coordinates. Probably could do with
// 16-bits here, but should be small number of points so...
-
+
uint32 toneCurvePoints = (uint32) (profile.ToneCurve ().fCoord.size ());
- fToneCurveBuffer.Allocate (toneCurvePoints * 2 * sizeof (real32));
+ fToneCurveBuffer.Allocate (dng_safe_uint32 (toneCurvePoints) * 2u,
+ sizeof (real32));
real32 *points = fToneCurveBuffer.Buffer_real32 ();
-
+
fToneCurveTag.SetCount (toneCurvePoints * 2);
fToneCurveTag.SetData (points);
-
+
for (uint32 i = 0; i < toneCurvePoints; i++)
{
// Transpose coordinates so they are in a more expected
// order (domain -> range).
points [i * 2 ] = (real32) profile.ToneCurve ().fCoord [i].h;
points [i * 2 + 1] = (real32) profile.ToneCurve ().fCoord [i].v;
}
directory.Add (&fToneCurveTag);
}
}
-
+
}
/******************************************************************************/
-tiff_dng_extended_color_profile::tiff_dng_extended_color_profile
+tiff_dng_extended_color_profile::tiff_dng_extended_color_profile
(const dng_camera_profile &profile)
: fProfile (profile)
{
-
+
}
/******************************************************************************/
void tiff_dng_extended_color_profile::Put (dng_stream &stream,
bool includeModelRestriction)
{
-
+
// Profile header.
stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
stream.Put_uint16 (magicExtendedProfile);
stream.Put_uint32 (8);
-
+
// Profile tags.
-
+
profile_tag_set tagSet (*this, fProfile);
// Camera this profile is for.
- tag_string cameraModelTag (tcUniqueCameraModel,
+ tag_string cameraModelTag (tcUniqueCameraModel,
fProfile.UniqueCameraModelRestriction ());
-
+
if (includeModelRestriction)
{
-
+
if (fProfile.UniqueCameraModelRestriction ().NotEmpty ())
{
-
+
Add (&cameraModelTag);
-
+
}
-
+
}
// Write it all out.
dng_tiff_directory::Put (stream, offsetsRelativeToExplicitBase, 8);
}
/*****************************************************************************/
tag_dng_noise_profile::tag_dng_noise_profile (const dng_noise_profile &profile)
: tag_data_ptr (tcNoiseProfile,
ttDouble,
2 * profile.NumFunctions (),
fValues)
{
DNG_REQUIRE (profile.NumFunctions () <= kMaxColorPlanes,
"Too many noise functions in tag_dng_noise_profile.");
for (uint32 i = 0; i < profile.NumFunctions (); i++)
{
fValues [(2 * i) ] = profile.NoiseFunction (i).Scale ();
fValues [(2 * i) + 1] = profile.NoiseFunction (i).Offset ();
}
+
+ }
+
+/*****************************************************************************/
+dng_image_writer::dng_image_writer ()
+ {
+
}
/*****************************************************************************/
-dng_image_writer::dng_image_writer ()
+dng_image_writer::~dng_image_writer ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_image_writer::CompressedBufferSize (const dng_ifd &ifd,
+ uint32 uncompressedSize)
+ {
+
+ const dng_safe_uint32 safeUncompressedSize (uncompressedSize);
+
+ switch (ifd.fCompression)
+ {
+
+ case ccLZW:
+ {
+
+ // Add lots of slop for LZW to expand data.
+
+ return (safeUncompressedSize * 2u + 1024u).Get ();
+
+ }
+
+ case ccDeflate:
+ {
+
+ // ZLib says maximum is source size + 0.1% + 12 bytes.
- : fCompressedBuffer ()
- , fUncompressedBuffer ()
- , fSubTileBlockBuffer ()
+ const dng_safe_uint32 temp (uncompressedSize >> 8);
+
+ return (safeUncompressedSize + temp + 64u).Get ();
+
+ }
+
+ case ccJPEG:
+ {
+
+ // If we are saving lossless JPEG from an 8-bit image, reserve
+ // space to pad the data out to 16-bits.
+
+ if (ifd.fBitsPerSample [0] <= 8)
+ {
+
+ return (safeUncompressedSize * 2u).Get ();
+
+ }
+
+ break;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ return 0;
+
+ }
+
+/******************************************************************************/
+static void EncodeDelta8 (uint8 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 channels)
{
+
+ const uint32 dRowStep = cols * channels;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = cols - 1; col > 0; col--)
+ {
+
+ for (uint32 channel = 0; channel < channels; channel++)
+ {
+
+ dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
+
+ }
+
+ }
+
+ dPtr += dRowStep;
+
+ }
}
-/*****************************************************************************/
+/******************************************************************************/
-dng_image_writer::~dng_image_writer ()
+static void EncodeDelta16 (uint16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 channels)
{
+
+ const uint32 dRowStep = cols * channels;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = cols - 1; col > 0; col--)
+ {
+
+ for (uint32 channel = 0; channel < channels; channel++)
+ {
+
+ dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
+
+ }
+
+ }
+
+ dPtr += dRowStep;
+
+ }
}
+
+/******************************************************************************/
+
+static void EncodeDelta32 (uint32 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 channels)
+ {
+
+ const uint32 dRowStep = cols * channels;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = cols - 1; col > 0; col--)
+ {
+
+ for (uint32 channel = 0; channel < channels; channel++)
+ {
+
+ dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
+
+ }
+
+ }
+
+ dPtr += dRowStep;
+
+ }
+ }
+
/*****************************************************************************/
-uint32 dng_image_writer::CompressedBufferSize (const dng_ifd &ifd,
- uint32 uncompressedSize)
+inline void EncodeDeltaBytes (uint8 *bytePtr, int32 cols, int32 channels)
{
+
+ if (channels == 1)
+ {
+
+ bytePtr += (cols - 1);
+
+ uint8 this0 = bytePtr [0];
+
+ for (int32 col = 1; col < cols; col++)
+ {
+
+ uint8 prev0 = bytePtr [-1];
+
+ this0 -= prev0;
+
+ bytePtr [0] = this0;
+
+ this0 = prev0;
+
+ bytePtr -= 1;
- // If we are saving lossless JPEG from an 8-bit image, reserve
- // space to pad the data out to 16-bits.
+ }
+
+ }
+
+ else if (channels == 3)
+ {
+
+ bytePtr += (cols - 1) * 3;
+
+ uint8 this0 = bytePtr [0];
+ uint8 this1 = bytePtr [1];
+ uint8 this2 = bytePtr [2];
+
+ for (int32 col = 1; col < cols; col++)
+ {
+
+ uint8 prev0 = bytePtr [-3];
+ uint8 prev1 = bytePtr [-2];
+ uint8 prev2 = bytePtr [-1];
+
+ this0 -= prev0;
+ this1 -= prev1;
+ this2 -= prev2;
+
+ bytePtr [0] = this0;
+ bytePtr [1] = this1;
+ bytePtr [2] = this2;
+
+ this0 = prev0;
+ this1 = prev1;
+ this2 = prev2;
+
+ bytePtr -= 3;
- if (ifd.fCompression == ccJPEG && ifd.fBitsPerSample [0] <= 8)
+ }
+
+ }
+
+ else
{
+
+ uint32 rowBytes = cols * channels;
+
+ bytePtr += rowBytes - 1;
+
+ for (uint32 col = channels; col < rowBytes; col++)
+ {
+
+ bytePtr [0] -= bytePtr [-channels];
+
+ bytePtr--;
- return uncompressedSize * 2;
-
+ }
+
}
- return 0;
+ }
+
+/*****************************************************************************/
+static void EncodeFPDelta (uint8 *buffer,
+ uint8 *temp,
+ int32 cols,
+ int32 channels,
+ int32 bytesPerSample)
+ {
+
+ int32 rowIncrement = cols * channels;
+
+ if (bytesPerSample == 2)
+ {
+
+ const uint8 *src = buffer;
+
+ #if qDNGBigEndian
+ uint8 *dst0 = temp;
+ uint8 *dst1 = temp + rowIncrement;
+ #else
+ uint8 *dst1 = temp;
+ uint8 *dst0 = temp + rowIncrement;
+ #endif
+
+ for (int32 col = 0; col < rowIncrement; ++col)
+ {
+
+ dst0 [col] = src [0];
+ dst1 [col] = src [1];
+
+ src += 2;
+
+ }
+
+ }
+
+ else if (bytesPerSample == 3)
+ {
+
+ const uint8 *src = buffer;
+
+ uint8 *dst0 = temp;
+ uint8 *dst1 = temp + rowIncrement;
+ uint8 *dst2 = temp + rowIncrement * 2;
+
+ for (int32 col = 0; col < rowIncrement; ++col)
+ {
+
+ dst0 [col] = src [0];
+ dst1 [col] = src [1];
+ dst2 [col] = src [2];
+
+ src += 3;
+
+ }
+
+ }
+
+ else
+ {
+
+ const uint8 *src = buffer;
+
+ #if qDNGBigEndian
+ uint8 *dst0 = temp;
+ uint8 *dst1 = temp + rowIncrement;
+ uint8 *dst2 = temp + rowIncrement * 2;
+ uint8 *dst3 = temp + rowIncrement * 3;
+ #else
+ uint8 *dst3 = temp;
+ uint8 *dst2 = temp + rowIncrement;
+ uint8 *dst1 = temp + rowIncrement * 2;
+ uint8 *dst0 = temp + rowIncrement * 3;
+ #endif
+
+ for (int32 col = 0; col < rowIncrement; ++col)
+ {
+
+ dst0 [col] = src [0];
+ dst1 [col] = src [1];
+ dst2 [col] = src [2];
+ dst3 [col] = src [3];
+
+ src += 4;
+
+ }
+
+ }
+
+ EncodeDeltaBytes (temp, cols*bytesPerSample, channels);
+
+ memcpy (buffer, temp, cols*bytesPerSample*channels);
+
}
/*****************************************************************************/
-void dng_image_writer::EncodePredictor (dng_host & /* host */,
+void dng_image_writer::EncodePredictor (dng_host &host,
const dng_ifd &ifd,
- dng_pixel_buffer & /* buffer */)
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &tempBuffer)
{
+
+ switch (ifd.fPredictor)
+ {
+
+ 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:
+ {
+
+ EncodeDelta8 ((uint8 *) buffer.fData,
+ buffer.fArea.H (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor);
+
+ return;
+
+ }
+
+ case ttShort:
+ {
+
+ EncodeDelta16 ((uint16 *) buffer.fData,
+ buffer.fArea.H (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor);
+
+ return;
+
+ }
+
+ case ttLong:
+ {
+
+ EncodeDelta32 ((uint32 *) buffer.fData,
+ buffer.fArea.H (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor);
+
+ return;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ break;
+
+ }
+
+ case cpFloatingPoint:
+ case cpFloatingPointX2:
+ case cpFloatingPointX4:
+ {
+
+ int32 xFactor = 1;
+
+ if (ifd.fPredictor == cpFloatingPointX2)
+ {
+ xFactor = 2;
+ }
+
+ else if (ifd.fPredictor == cpFloatingPointX4)
+ {
+ xFactor = 4;
+ }
+
+ if (buffer.fRowStep < 0)
+ {
+ ThrowProgramError ("Row step may not be negative");
+ }
+
+ dng_safe_uint32 tempBufferSize =
+ dng_safe_uint32 (buffer.fPixelSize) *
+ static_cast<uint32> (buffer.fRowStep);
+ if (!tempBuffer.Get () ||
+ tempBuffer->LogicalSize () < tempBufferSize.Get ())
+ {
+
+ tempBuffer.Reset (host.Allocate (tempBufferSize.Get ()));
+
+ }
+
+ for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
+ {
+
+ EncodeFPDelta ((uint8 *) buffer.DirtyPixel (row, buffer.fArea.l, buffer.fPlane),
+ tempBuffer->Buffer_uint8 (),
+ buffer.fArea.W () / xFactor,
+ buffer.fPlanes * xFactor,
+ buffer.fPixelSize);
+
+ }
+
+ return;
+
+ }
+
+ default:
+ break;
+
+ }
+
if (ifd.fPredictor != cpNullPredictor)
{
-
+
ThrowProgramError ();
-
+
}
-
+
}
-
+
/*****************************************************************************/
void dng_image_writer::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_image_writer::ReorderSubTileBlocks (const dng_ifd &ifd,
- dng_pixel_buffer &buffer)
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
{
-
+
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 = fUncompressedBuffer->Buffer_uint8 ();
- uint8 *d0 = fSubTileBlockBuffer->Buffer_uint8 ();
-
+
+ const uint8 *s0 = uncompressedBuffer->Buffer_uint8 ();
+ uint8 *d0 = subTileBlockBuffer->Buffer_uint8 ();
+
for (uint32 rowBlock = 0; rowBlock < rowBlocks; rowBlock++)
{
-
+
const uint8 *s1 = s0;
-
+
for (uint32 colBlock = 0; colBlock < colBlocks; colBlock++)
{
-
+
const uint8 *s2 = s1;
-
+
for (uint32 blockRow = 0; blockRow < blockRows; blockRow++)
{
-
+
for (uint32 j = 0; j < blockColBytes; j++)
{
-
+
d0 [j] = s2 [j];
-
+
}
-
+
d0 += blockColBytes;
-
+
s2 += rowStep;
-
+
}
-
+
s1 += colBlockStep;
-
+
}
-
+
s0 += rowBlockStep;
-
+
}
-
+
// Copy back reordered pixels.
-
- DoCopyBytes (fSubTileBlockBuffer->Buffer (),
- fUncompressedBuffer->Buffer (),
- fUncompressedBuffer->LogicalSize ());
-
+
+ DoCopyBytes (subTileBlockBuffer->Buffer (),
+ uncompressedBuffer->Buffer (),
+ uncompressedBuffer->LogicalSize ());
+
}
+
+/******************************************************************************/
-/*****************************************************************************/
-
-void dng_image_writer::WriteData (dng_host &host,
- const dng_ifd &ifd,
- dng_stream &stream,
- dng_pixel_buffer &buffer)
+class dng_lzw_compressor: private dng_uncopyable
{
+
+ private:
+
+ enum
+ {
+ kResetCode = 256,
+ kEndCode = 257,
+ kTableSize = 4096
+ };
- switch (ifd.fCompression)
- {
+ // Compressor nodes have two son pointers. The low order bit of
+ // the next code determines which pointer is used. This cuts the
+ // number of nodes searched for the next code by two on average.
- case ccUncompressed:
+ struct LZWCompressorNode
+ {
+ int16 final;
+ int16 son0;
+ int16 son1;
+ int16 brother;
+ };
+
+ dng_memory_data fBuffer;
+
+ LZWCompressorNode *fTable;
+
+ uint8 *fDstPtr;
+
+ int32 fBitOffset;
+
+ int32 fNextCode;
+
+ int32 fCodeSize;
+
+ public:
+
+ dng_lzw_compressor ();
+
+ void Compress (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 sCount,
+ uint32 &dCount);
+
+ private:
+
+ void InitTable ();
+
+ int32 SearchTable (int32 w, int32 k) const
{
+
+ DNG_ASSERT ((w >= 0) && (w <= kTableSize),
+ "Bad w value in dng_lzw_compressor::SearchTable");
+
+ int32 son0 = fTable [w] . son0;
+ int32 son1 = fTable [w] . son1;
+
+ // Branchless version of:
+ // int32 code = (k & 1) ? son1 : son0;
+
+ int32 code = son0 + ((-((int32) (k & 1))) & (son1 - son0));
+
+ while (code > 0 && fTable [code].final != k)
+ {
+ code = fTable [code].brother;
+ }
- // Special case support for when we save to 8-bits from
- // 16-bit data.
+ return code;
- if (ifd.fBitsPerSample [0] == 8 && buffer.fPixelType == ttShort)
- {
+ }
- uint32 count = buffer.fRowStep *
- buffer.fArea.H ();
+ void AddTable (int32 w, int32 k);
+
+ void PutCodeWord (int32 code);
- const uint16 *sPtr = (const uint16 *) buffer.fData;
+ };
- for (uint32 j = 0; j < count; j++)
- {
+/******************************************************************************/
- stream.Put_uint8 ((uint8) sPtr [j]);
+dng_lzw_compressor::dng_lzw_compressor ()
- }
+ : fBuffer ()
+ , fTable (NULL)
+ , fDstPtr (NULL)
+ , fBitOffset (0)
+ , fNextCode (0)
+ , fCodeSize (0)
+
+ {
+
+ fBuffer.Allocate (kTableSize, sizeof (LZWCompressorNode));
+
+ fTable = (LZWCompressorNode *) fBuffer.Buffer ();
+
+ }
+
+/******************************************************************************/
+
+void dng_lzw_compressor::InitTable ()
+ {
+
+ fCodeSize = 9;
+
+ fNextCode = 258;
+
+ LZWCompressorNode *node = &fTable [0];
+
+ for (int32 code = 0; code < 256; ++code)
+ {
+
+ node->final = (int16) code;
+ node->son0 = -1;
+ node->son1 = -1;
+ node->brother = -1;
+
+ node++;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_lzw_compressor::AddTable (int32 w, int32 k)
+ {
+
+ DNG_ASSERT ((w >= 0) && (w <= kTableSize),
+ "Bad w value in dng_lzw_compressor::AddTable");
+
+ LZWCompressorNode *node = &fTable [w];
+
+ int32 nextCode = fNextCode;
+
+ DNG_ASSERT ((nextCode >= 0) && (nextCode <= kTableSize),
+ "Bad fNextCode value in dng_lzw_compressor::AddTable");
+
+ LZWCompressorNode *node2 = &fTable [nextCode];
+
+ fNextCode++;
+
+ int32 oldSon;
+
+ if( k&1 )
+ {
+ oldSon = node->son1;
+ node->son1 = (int16) nextCode;
+ }
+ else
+ {
+ oldSon = node->son0;
+ node->son0 = (int16) nextCode;
+ }
+
+ node2->final = (int16) k;
+ node2->son0 = -1;
+ node2->son1 = -1;
+ node2->brother = (int16) oldSon;
+
+ if (nextCode == (1 << fCodeSize) - 1)
+ {
+ if (fCodeSize != 12)
+ fCodeSize++;
+ }
+
+ }
+
+/******************************************************************************/
+
+void dng_lzw_compressor::PutCodeWord (int32 code)
+ {
+
+ int32 bit = (int32) (fBitOffset & 7);
+
+ int32 offset1 = fBitOffset >> 3;
+ int32 offset2 = (fBitOffset + fCodeSize - 1) >> 3;
+
+ int32 shift1 = (fCodeSize + bit) - 8;
+ int32 shift2 = (fCodeSize + bit) - 16;
+
+ uint8 byte1 = (uint8) (code >> shift1);
+
+ uint8 *dstPtr1 = fDstPtr + offset1;
+ uint8 *dstPtr3 = fDstPtr + offset2;
+
+ if (offset1 + 1 == offset2)
+ {
+
+ uint8 byte2 = (uint8) (code << (-shift2));
+
+ if (bit)
+ *dstPtr1 |= byte1;
+ else
+ *dstPtr1 = byte1;
+
+ *dstPtr3 = byte2;
+
+ }
+
+ else
+ {
+
+ int32 shift3 = (fCodeSize + bit) - 24;
+
+ uint8 byte2 = (uint8) (code >> shift2);
+ uint8 byte3 = (uint8) (code << (-shift3));
+
+ uint8 *dstPtr2 = fDstPtr + (offset1 + 1);
+
+ if (bit)
+ *dstPtr1 |= byte1;
+ else
+ *dstPtr1 = byte1;
+
+ *dstPtr2 = byte2;
+
+ *dstPtr3 = byte3;
+
+ }
+
+ fBitOffset += fCodeSize;
+
+ }
+
+/******************************************************************************/
+void dng_lzw_compressor::Compress (const uint8 *sPtr,
+ uint8 *dPtr,
+ uint32 sCount,
+ uint32 &dCount)
+ {
+
+ fDstPtr = dPtr;
+
+ fBitOffset = 0;
+
+ InitTable ();
+
+ PutCodeWord (kResetCode);
+
+ int32 code = -1;
+
+ int32 pixel;
+
+ if (sCount > 0)
+ {
+
+ pixel = *sPtr;
+ sPtr = sPtr + 1;
+ code = pixel;
+
+ sCount--;
+
+ while (sCount--)
+ {
+
+ pixel = *sPtr;
+ sPtr = sPtr + 1;
+
+ int32 newCode = SearchTable (code, pixel);
+
+ if (newCode == -1)
+ {
+
+ PutCodeWord (code);
+
+ if (fNextCode < 4093)
+ {
+ AddTable (code, pixel);
+ }
+ else
+ {
+ PutCodeWord (kResetCode);
+ InitTable ();
+ }
+
+ code = pixel;
+
}
+
+ else
+ code = newCode;
+
+ }
+
+ }
+
+ if (code != -1)
+ {
+ PutCodeWord (code);
+ AddTable (code, 0);
+ }
+
+ PutCodeWord (kEndCode);
+
+ dCount = (fBitOffset + 7) >> 3;
+
+ }
+/*****************************************************************************/
+
+#if qDNGUseLibJPEG
+
+/*****************************************************************************/
+
+static void dng_error_exit (j_common_ptr cinfo)
+ {
+
+ // Output message.
+
+ (*cinfo->err->output_message) (cinfo);
+
+ // Convert to a dng_exception.
+
+ switch (cinfo->err->msg_code)
+ {
+
+ case JERR_OUT_OF_MEMORY:
+ {
+ ThrowMemoryFull ();
+ break;
+ }
+
+ default:
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+static void dng_output_message (j_common_ptr cinfo)
+ {
+
+ // Format message to string.
+
+ char buffer [JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+ // Report the libjpeg message as a warning.
+
+ ReportWarning ("libjpeg", buffer);
+
+ }
+
+/*****************************************************************************/
+
+struct dng_jpeg_stream_dest
+ {
+
+ struct jpeg_destination_mgr pub;
+
+ dng_stream *fStream;
+
+ uint8 fBuffer [4096];
+
+ };
+
+/*****************************************************************************/
+
+static void dng_init_destination (j_compress_ptr cinfo)
+ {
+
+ dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
+
+ dest->pub.next_output_byte = dest->fBuffer;
+ dest->pub.free_in_buffer = sizeof (dest->fBuffer);
+
+ }
+
+/*****************************************************************************/
+
+static boolean dng_empty_output_buffer (j_compress_ptr cinfo)
+ {
+
+ dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
+
+ dest->fStream->Put (dest->fBuffer, sizeof (dest->fBuffer));
+
+ dest->pub.next_output_byte = dest->fBuffer;
+ dest->pub.free_in_buffer = sizeof (dest->fBuffer);
+
+ return TRUE;
+
+ }
+
+/*****************************************************************************/
+
+static void dng_term_destination (j_compress_ptr cinfo)
+ {
+
+ dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
+
+ uint32 datacount = sizeof (dest->fBuffer) -
+ (uint32) dest->pub.free_in_buffer;
+
+ if (datacount)
+ {
+ dest->fStream->Put (dest->fBuffer, datacount);
+ }
+
+ }
+
+/*****************************************************************************/
+
+static void jpeg_set_adobe_quality (struct jpeg_compress_struct *cinfo,
+ int32 quality)
+ {
+
+ // If out of range, map to default.
+
+ if (quality < 0 || quality > 12)
+ {
+ quality = 10;
+ }
+
+ // Adobe turns off chroma downsampling at high quality levels.
+
+ bool useChromaDownsampling = (quality <= 6);
+
+ // Approximate mapping from Adobe quality levels to LibJPEG levels.
+
+ const int kLibJPEGQuality [13] =
+ {
+ 5, 11, 23, 34, 46, 63, 76, 77, 86, 90, 94, 97, 99
+ };
+
+ quality = kLibJPEGQuality [quality];
+
+ jpeg_set_quality (cinfo, quality, TRUE);
+
+ // LibJPEG defaults to always using chroma downsampling. Turn if off
+ // if we need it off to match Adobe.
+
+ if (!useChromaDownsampling)
+ {
+
+ cinfo->comp_info [0].h_samp_factor = 1;
+ cinfo->comp_info [0].h_samp_factor = 1;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+void dng_image_writer::WriteData (dng_host &host,
+ const dng_ifd &ifd,
+ dng_stream &stream,
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ bool /* usingMultipleThreads */)
+ {
+
+ switch (ifd.fCompression)
+ {
+
+ case ccUncompressed:
+ {
+
+ // Special case support for when we save to 8-bits from
+ // 16-bit data.
+
+ if (ifd.fBitsPerSample [0] == 8 && buffer.fPixelType == ttShort)
+ {
+
+ uint32 count = buffer.fRowStep *
+ buffer.fArea.H ();
+
+ const uint16 *sPtr = (const uint16 *) buffer.fData;
+
+ for (uint32 j = 0; j < count; j++)
+ {
+
+ stream.Put_uint8 ((uint8) sPtr [j]);
+
+ }
+
+ }
+
else
{
-
+
// Swap bytes if required.
-
+
if (stream.SwapBytes ())
{
-
+
ByteSwapBuffer (host, buffer);
-
+
}
-
+
// Write the bytes.
-
+
stream.Put (buffer.fData, buffer.fRowStep *
buffer.fArea.H () *
buffer.fPixelSize);
-
+
}
-
+
break;
-
+
}
+
+ case ccLZW:
+ case ccDeflate:
+ {
+
+ // Both these compression algorithms are byte based. The floating
+ // point predictor already does byte ordering, so don't ever swap
+ // when using it.
+
+ if (stream.SwapBytes () && ifd.fPredictor != cpFloatingPoint)
+ {
+
+ ByteSwapBuffer (host,
+ buffer);
+
+ }
+
+ // Run the compression algorithm.
+
+ uint32 sBytes = buffer.fRowStep *
+ buffer.fArea.H () *
+ buffer.fPixelSize;
+
+ uint8 *sBuffer = (uint8 *) buffer.fData;
+
+ uint32 dBytes = 0;
+
+ uint8 *dBuffer = compressedBuffer->Buffer_uint8 ();
+
+ if (ifd.fCompression == ccLZW)
+ {
+
+ dng_lzw_compressor lzwCompressor;
+
+ lzwCompressor.Compress (sBuffer,
+ dBuffer,
+ sBytes,
+ dBytes);
+
+ }
+
+ else
+ {
+
+ uLongf dCount = compressedBuffer->LogicalSize ();
+
+ int32 level = Z_DEFAULT_COMPRESSION;
+
+ if (ifd.fCompressionQuality >= Z_BEST_SPEED &&
+ ifd.fCompressionQuality <= Z_BEST_COMPRESSION)
+ {
+
+ level = ifd.fCompressionQuality;
+
+ }
+
+ int zResult = ::compress2 (dBuffer,
+ &dCount,
+ sBuffer,
+ sBytes,
+ level);
+
+ if (zResult != Z_OK)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ dBytes = (uint32) dCount;
+
+ }
+
+ if (dBytes > compressedBuffer->LogicalSize ())
+ {
+
+ ThrowOverflow ("Compression output buffer overflow");
+
+ }
+
+ stream.Put (dBuffer, dBytes);
+
+ return;
+ }
+
case ccJPEG:
{
-
+
dng_pixel_buffer temp (buffer);
-
+
if (buffer.fPixelType == ttByte)
{
-
+
// The lossless JPEG encoder needs 16-bit data, so if we are
// are saving 8 bit data, we need to pad it out to 16-bits.
-
- temp.fData = fCompressedBuffer->Buffer ();
-
+
+ temp.fData = compressedBuffer->Buffer ();
+
temp.fPixelType = ttShort;
temp.fPixelSize = 2;
-
+
temp.CopyArea (buffer,
buffer.fArea,
buffer.fPlane,
buffer.fPlanes);
-
+
}
-
+
EncodeLosslessJPEG ((const uint16 *) temp.fData,
temp.fArea.H (),
temp.fArea.W (),
temp.fPlanes,
ifd.fBitsPerSample [0],
temp.fRowStep,
temp.fColStep,
stream);
-
+
break;
-
+
}
+
+ #if qDNGUseLibJPEG
+
+ case ccLossyJPEG:
+ {
+
+ struct jpeg_compress_struct cinfo;
+
+ // Setup the error manager.
+
+ struct jpeg_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error (&jerr);
+
+ jerr.error_exit = dng_error_exit;
+ jerr.output_message = dng_output_message;
+
+ try
+ {
+
+ // Create the compression context.
+
+ jpeg_create_compress (&cinfo);
+
+ // Setup the destination manager to write to stream.
+
+ dng_jpeg_stream_dest dest;
+
+ dest.fStream = &stream;
+
+ dest.pub.init_destination = dng_init_destination;
+ dest.pub.empty_output_buffer = dng_empty_output_buffer;
+ dest.pub.term_destination = dng_term_destination;
+
+ cinfo.dest = &dest.pub;
+
+ // Setup basic image info.
+
+ cinfo.image_width = buffer.fArea.W ();
+ cinfo.image_height = buffer.fArea.H ();
+ cinfo.input_components = buffer.fPlanes;
+
+ switch (buffer.fPlanes)
+ {
+
+ case 1:
+ cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+
+ case 3:
+ cinfo.in_color_space = JCS_RGB;
+ break;
+
+ case 4:
+ cinfo.in_color_space = JCS_CMYK;
+ break;
+
+ default:
+ ThrowProgramError ();
+
+ }
+
+ // Setup the compression parameters.
+
+ jpeg_set_defaults (&cinfo);
+
+ jpeg_set_adobe_quality (&cinfo, ifd.fCompressionQuality);
+
+ // Write the JPEG header.
+
+ jpeg_start_compress (&cinfo, TRUE);
+
+ // Write the scanlines.
+
+ for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
+ {
+
+ uint8 *sampArray [1];
+
+ sampArray [0] = buffer.DirtyPixel_uint8 (row,
+ buffer.fArea.l,
+ 0);
+
+ jpeg_write_scanlines (&cinfo, sampArray, 1);
+
+ }
+ // Cleanup.
+
+ jpeg_finish_compress (&cinfo);
+
+ jpeg_destroy_compress (&cinfo);
+
+ }
+
+ catch (...)
+ {
+
+ jpeg_destroy_compress (&cinfo);
+
+ throw;
+
+ }
+
+ return;
+
+ }
+
+ #endif
+
default:
{
-
+
ThrowProgramError ();
- break;
+
}
-
+
}
-
+
}
+
+/******************************************************************************/
+void dng_image_writer::EncodeJPEGPreview (dng_host &host,
+ const dng_image &image,
+ dng_jpeg_preview &preview,
+ int32 quality)
+ {
+
+ #if qDNGUseLibJPEG
+
+ dng_memory_stream stream (host.Allocator ());
+
+ struct jpeg_compress_struct cinfo;
+
+ // Setup the error manager.
+
+ struct jpeg_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error (&jerr);
+
+ jerr.error_exit = dng_error_exit;
+ jerr.output_message = dng_output_message;
+
+ try
+ {
+
+ // Create the compression context.
+
+ jpeg_create_compress (&cinfo);
+
+ // Setup the destination manager to write to stream.
+
+ dng_jpeg_stream_dest dest;
+
+ dest.fStream = &stream;
+
+ dest.pub.init_destination = dng_init_destination;
+ dest.pub.empty_output_buffer = dng_empty_output_buffer;
+ dest.pub.term_destination = dng_term_destination;
+
+ cinfo.dest = &dest.pub;
+
+ // Setup basic image info.
+
+ cinfo.image_width = image.Bounds ().W ();
+ cinfo.image_height = image.Bounds ().H ();
+ cinfo.input_components = image.Planes ();
+
+ switch (image.Planes ())
+ {
+
+ case 1:
+ cinfo.in_color_space = JCS_GRAYSCALE;
+ break;
+
+ case 3:
+ cinfo.in_color_space = JCS_RGB;
+ break;
+
+ default:
+ ThrowProgramError ();
+
+ }
+
+ // Setup the compression parameters.
+
+ jpeg_set_defaults (&cinfo);
+
+ jpeg_set_adobe_quality (&cinfo, quality);
+
+ // Find some preview information based on the compression settings.
+
+ preview.fPreviewSize = image.Size ();
+
+ if (image.Planes () == 1)
+ {
+
+ preview.fPhotometricInterpretation = piBlackIsZero;
+
+ }
+
+ else
+ {
+
+ preview.fPhotometricInterpretation = piYCbCr;
+
+ preview.fYCbCrSubSampling.h = cinfo.comp_info [0].h_samp_factor;
+ preview.fYCbCrSubSampling.v = cinfo.comp_info [0].v_samp_factor;
+
+ }
+
+ // Write the JPEG header.
+
+ jpeg_start_compress (&cinfo, TRUE);
+
+ // Write the scanlines.
+
+ dng_pixel_buffer buffer (image.Bounds (),
+ 0,
+ image.Planes (),
+ ttByte,
+ pcInterleaved,
+ NULL);
+
+ AutoPtr<dng_memory_block> bufferData (host.Allocate (buffer.fRowStep));
+
+ buffer.fData = bufferData->Buffer ();
+
+ for (uint32 row = 0; row < cinfo.image_height; row++)
+ {
+
+ buffer.fArea.t = row;
+ buffer.fArea.b = row + 1;
+
+ image.Get (buffer);
+
+ uint8 *sampArray [1];
+
+ sampArray [0] = buffer.DirtyPixel_uint8 (row,
+ buffer.fArea.l,
+ 0);
+
+ jpeg_write_scanlines (&cinfo, sampArray, 1);
+
+ }
+
+ // Cleanup.
+
+ jpeg_finish_compress (&cinfo);
+
+ jpeg_destroy_compress (&cinfo);
+
+ }
+
+ catch (...)
+ {
+
+ jpeg_destroy_compress (&cinfo);
+
+ throw;
+
+ }
+
+ preview.fCompressedData.Reset (stream.AsMemoryBlock (host.Allocator ()));
+
+ #else
+
+ (void) host;
+ (void) image;
+ (void) preview;
+ (void) quality;
+
+ ThrowProgramError ("No JPEG encoder");
+
+ #endif
+
+ }
+
/*****************************************************************************/
void dng_image_writer::WriteTile (dng_host &host,
const dng_ifd &ifd,
dng_stream &stream,
const dng_image &image,
const dng_rect &tileArea,
- uint32 fakeChannels)
+ uint32 fakeChannels,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer,
+ bool usingMultipleThreads)
{
-
+
// Create pixel buffer to hold uncompressed tile.
+
+ dng_pixel_buffer buffer (tileArea,
+ 0,
+ ifd.fSamplesPerPixel,
+ image.PixelType (),
+ pcInterleaved,
+ uncompressedBuffer->Buffer ());
+
+ // Get the uncompressed data.
+
+ image.Get (buffer, dng_image::edge_zero);
+
+ // Deal with sub-tile blocks.
+
+ if (ifd.fSubTileBlockRows > 1)
+ {
+
+ ReorderSubTileBlocks (ifd,
+ buffer,
+ uncompressedBuffer,
+ subTileBlockBuffer);
+
+ }
+
+ // Floating point depth conversion.
+
+ if (ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+
+ if (ifd.fBitsPerSample [0] == 16)
+ {
+
+ uint32 *srcPtr = (uint32 *) buffer.fData;
+ uint16 *dstPtr = (uint16 *) buffer.fData;
+
+ uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes;
+
+ for (uint32 j = 0; j < pixels; j++)
+ {
+
+ dstPtr [j] = DNG_FloatToHalf (srcPtr [j]);
+
+ }
+
+ buffer.fPixelSize = 2;
+
+ }
+
+ if (ifd.fBitsPerSample [0] == 24)
+ {
+
+ uint32 *srcPtr = (uint32 *) buffer.fData;
+ uint8 *dstPtr = (uint8 *) buffer.fData;
+
+ uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes;
+
+ if (stream.BigEndian () || ifd.fPredictor == cpFloatingPoint ||
+ ifd.fPredictor == cpFloatingPointX2 ||
+ ifd.fPredictor == cpFloatingPointX4)
+ {
+
+ for (uint32 j = 0; j < pixels; j++)
+ {
+
+ DNG_FloatToFP24 (srcPtr [j], dstPtr);
+
+ dstPtr += 3;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 j = 0; j < pixels; j++)
+ {
+
+ uint8 output [3];
+
+ DNG_FloatToFP24 (srcPtr [j], output);
+
+ dstPtr [0] = output [2];
+ dstPtr [1] = output [1];
+ dstPtr [2] = output [0];
+
+ dstPtr += 3;
+
+ }
+
+ }
+
+ buffer.fPixelSize = 3;
+
+ }
+
+ }
+
+ // Run predictor.
+
+ EncodePredictor (host,
+ ifd,
+ buffer,
+ tempBuffer);
+
+ // Adjust pixel buffer for fake channels.
+
+ if (fakeChannels > 1)
+ {
+
+ buffer.fPlanes *= fakeChannels;
+ buffer.fColStep *= fakeChannels;
+
+ buffer.fArea.r = buffer.fArea.l + (buffer.fArea.W () / fakeChannels);
+
+ }
+
+ // Compress (if required) and write out the data.
+
+ WriteData (host,
+ ifd,
+ stream,
+ buffer,
+ compressedBuffer,
+ usingMultipleThreads);
+
+ }
- dng_pixel_buffer buffer;
+/*****************************************************************************/
- buffer.fArea = tileArea;
+dng_write_tiles_task::dng_write_tiles_task
+ (dng_image_writer &imageWriter,
+ dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels,
+ uint32 tilesDown,
+ uint32 tilesAcross,
+ uint32 compressedSize,
+ uint32 uncompressedSize)
+
+ : dng_area_task ("dng_write_tiles_task")
+
+ , fImageWriter (imageWriter)
+ , fHost (host)
+ , fIFD (ifd)
+ , fBasic (basic)
+ , fStream (stream)
+ , fImage (image)
+ , fFakeChannels (fakeChannels)
+ , fTilesDown (tilesDown)
+ , fTilesAcross (tilesAcross)
+ , fCompressedSize (compressedSize)
+ , fUncompressedSize (uncompressedSize)
+ , fNextTileIndex (0)
+ , fMutex ("dng_write_tiles_task")
+ , fCondition ()
+ , fTaskFailed (false)
+ , fWriteTileIndex (0)
- buffer.fPlane = 0;
- buffer.fPlanes = ifd.fSamplesPerPixel;
+ {
- buffer.fRowStep = buffer.fPlanes * tileArea.W ();
- buffer.fColStep = buffer.fPlanes;
- buffer.fPlaneStep = 1;
+ fMinTaskArea = 16 * 16;
+ fUnitCell = dng_point (16, 16);
+ fMaxTileSize = dng_point (16, 16);
- buffer.fPixelType = image.PixelType ();
- buffer.fPixelSize = image.PixelSize ();
+ }
- buffer.fData = fUncompressedBuffer->Buffer ();
+/*****************************************************************************/
+
+void dng_write_tiles_task::Process (uint32 /* threadIndex */,
+ const dng_rect & /* tile */,
+ dng_abort_sniffer *sniffer)
+ {
- // Get the uncompressed data.
+ try
+ {
- image.Get (buffer, dng_image::edge_zero);
+ AutoPtr<dng_memory_block> compressedBuffer;
+ AutoPtr<dng_memory_block> uncompressedBuffer;
+ AutoPtr<dng_memory_block> subTileBlockBuffer;
+ AutoPtr<dng_memory_block> tempBuffer;
- // Deal with sub-tile blocks.
+ if (fCompressedSize)
+ {
+ compressedBuffer.Reset (fHost.Allocate (fCompressedSize));
+ }
- if (ifd.fSubTileBlockRows > 1)
+ if (fUncompressedSize)
+ {
+ uncompressedBuffer.Reset (fHost.Allocate (fUncompressedSize));
+ }
+
+ if (fIFD.fSubTileBlockRows > 1 && fUncompressedSize)
+ {
+ subTileBlockBuffer.Reset (fHost.Allocate (fUncompressedSize));
+ }
+
+ while (true)
+ {
+
+ // Find tile index to compress.
+
+ // Note: fNextTileIndex is atomic
+
+ uint32 tileIndex = fNextTileIndex++;
+
+ if (tileIndex >= fTilesDown * fTilesAcross)
+ {
+ return;
+ }
+
+ // Encode the tile. This may be done concurrently.
+
+ uint32 tileByteCount = 0;
+
+ dng_memory_stream tileStream (fHost.Allocator ());
+
+ ProcessTask (tileIndex,
+ compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer,
+ tempBuffer,
+ tileByteCount,
+ tileStream,
+ sniffer);
+
+ // Wait until it is our turn to write tile.
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ while (!fTaskFailed &&
+ fWriteTileIndex != tileIndex)
+ {
+
+ fCondition.Wait (fMutex);
+
+ }
+
+ // If the task failed in another thread, that thread already
+ // threw an exception.
+
+ if (fTaskFailed)
+ return;
+
+ }
+
+ // Write the encoded tile to the output stream. This must be done
+ // sequentially in ascending order of tileIndex (enforced by the
+ // above 'wait').
+
+ WriteTask (tileIndex,
+ tileByteCount,
+ tileStream,
+ sniffer);
+
+ // Let other threads know it is safe to write to stream.
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ // If the task failed in another thread, that thread already
+ // threw an exception.
+
+ if (fTaskFailed)
+ return;
+
+ fWriteTileIndex++;
+
+ fCondition.Broadcast ();
+
+ }
+
+ }
+
+ }
+
+ catch (...)
{
- ReorderSubTileBlocks (ifd, buffer);
+ // If first to fail, wake up any threads waiting on condition.
+
+ bool needBroadcast = false;
+
+ {
+
+ dng_lock_mutex lock (&fMutex);
+
+ needBroadcast = !fTaskFailed;
+ fTaskFailed = true;
+
+ }
+
+ if (needBroadcast)
+ fCondition.Broadcast ();
+
+ throw;
}
- // Run predictor.
+ }
- EncodePredictor (host,
- ifd,
- buffer);
+/*****************************************************************************/
- // Adjust pixel buffer for fake channels.
+void dng_write_tiles_task::ProcessTask
+ (uint32 tileIndex,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer,
+ uint32 &tileByteCount, // output
+ dng_memory_stream &tileStream, // output
+ dng_abort_sniffer *sniffer)
+ {
- if (fakeChannels > 1)
- {
+ // This routine may be executed concurrently.
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ // Compress tile.
+
+ uint32 rowIndex = tileIndex / fTilesAcross;
+
+ uint32 colIndex = tileIndex - rowIndex * fTilesAcross;
+
+ dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
+
+ tileStream.SetLittleEndian (fStream.LittleEndian ());
+
+ dng_host host (&fHost.Allocator (),
+ sniffer);
+
+ fImageWriter.WriteTile (host,
+ fIFD,
+ tileStream,
+ fImage,
+ tileArea,
+ fFakeChannels,
+ compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer,
+ tempBuffer,
+ true);
+
+ tileStream.Flush ();
+
+ tileByteCount = (uint32) tileStream.Length ();
+
+ tileStream.SetReadPosition (0);
+
+ }
- buffer.fPlanes *= fakeChannels;
- buffer.fColStep *= fakeChannels;
+/*****************************************************************************/
- buffer.fArea.r = buffer.fArea.l + (buffer.fArea.W () / fakeChannels);
+void dng_write_tiles_task::WriteTask (uint32 tileIndex,
+ uint32 tileByteCount,
+ dng_memory_stream &tileStream,
+ dng_abort_sniffer *sniffer)
+ {
+
+ // This task must be executed serially and in sequential (ascending) order
+ // of tileIndex.
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ // Remember this offset.
+
+ uint32 tileOffset = (uint32) fStream.Position ();
+
+ fBasic.SetTileOffset (tileIndex, tileOffset);
+
+ // Copy tile stream for tile into main stream.
+
+ tileStream.CopyToStream (fStream, tileByteCount);
+ // Update tile count.
+
+ fBasic.SetTileByteCount (tileIndex, tileByteCount);
+
+ // Keep the tiles on even byte offsets.
+
+ if (tileByteCount & 1)
+ {
+ fStream.Put_uint8 (0);
}
- // Compress (if required) and write out the data.
+ }
- WriteData (host,
- ifd,
- stream,
- buffer);
+/*****************************************************************************/
+void dng_image_writer::DoWriteTiles (dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels,
+ uint32 tilesDown,
+ uint32 tilesAcross,
+ uint32 compressedSize,
+ const dng_safe_uint32 &uncompressedSize)
+ {
+
+ uint32 threadCount = Min_uint32 (tilesDown * tilesAcross,
+ host.PerformAreaTaskThreads ());
+
+ dng_write_tiles_task task (*this,
+ host,
+ ifd,
+ basic,
+ stream,
+ image,
+ fakeChannels,
+ tilesDown,
+ tilesAcross,
+ compressedSize,
+ uncompressedSize.Get ());
+
+ host.PerformAreaTask (task,
+ dng_rect (0, 0, 16, 16 * threadCount));
+
}
/*****************************************************************************/
void dng_image_writer::WriteImage (dng_host &host,
const dng_ifd &ifd,
dng_basic_tag_set &basic,
dng_stream &stream,
const dng_image &image,
uint32 fakeChannels)
{
-
+
// 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 (*((dng_image *) &image),
ifd.fRowInterleaveFactor);
-
+
WriteImage (host,
tempIFD,
basic,
stream,
tempImage,
fakeChannels);
-
+
return;
-
+
}
-
+
// Compute basic information.
- uint32 bytesPerSample = TagTypeSize (image.PixelType ());
-
- uint32 bytesPerPixel = ifd.fSamplesPerPixel * bytesPerSample;
-
- uint32 tileRowBytes = ifd.fTileWidth * bytesPerPixel;
+ dng_safe_uint32 bytesPerSample (TagTypeSize (image.PixelType ()));
+
+ dng_safe_uint32 bytesPerPixel = bytesPerSample * ifd.fSamplesPerPixel;
+
+ dng_safe_uint32 tileRowBytes = bytesPerPixel * ifd.fTileWidth;
// If we can compute the number of bytes needed to store the
// data, we can split the write for each tile into sub-tiles.
-
+
uint32 subTileLength = ifd.fTileLength;
-
+
if (ifd.TileByteCount (ifd.TileArea (0, 0)) != 0)
{
-
+
subTileLength = Pin_uint32 (ifd.fSubTileBlockRows,
- kImageBufferSize / tileRowBytes,
+ kImageBufferSize / tileRowBytes.Get (),
ifd.fTileLength);
-
+
// Don't split sub-tiles across subTileBlocks.
-
+
subTileLength = subTileLength / ifd.fSubTileBlockRows
* ifd.fSubTileBlockRows;
+
+ }
+
+ // Find size of uncompressed buffer.
+
+ dng_safe_uint32 uncompressedSize = tileRowBytes * subTileLength;
+
+ // Find size of compressed buffer, if required.
+
+ uint32 compressedSize = CompressedBufferSize (ifd, uncompressedSize.Get ());
+
+ // See if we can do this write using multiple threads.
+
+ uint32 tilesAcross = ifd.TilesAcross ();
+ uint32 tilesDown = ifd.TilesDown ();
+
+ bool useMultipleThreads = (tilesDown * tilesAcross >= 2) &&
+ (host.PerformAreaTaskThreads () > 1) &&
+ (subTileLength == ifd.fTileLength) &&
+ (ifd.fCompression != ccUncompressed);
+
+ if (useMultipleThreads)
+ {
+
+ DoWriteTiles (host,
+ ifd,
+ basic,
+ stream,
+ image,
+ fakeChannels,
+ tilesDown,
+ tilesAcross,
+ compressedSize,
+ uncompressedSize.Get ());
+
+ }
+
+ else
+ {
+
+ AutoPtr<dng_memory_block> compressedBuffer;
+ AutoPtr<dng_memory_block> uncompressedBuffer;
+ AutoPtr<dng_memory_block> subTileBlockBuffer;
+ AutoPtr<dng_memory_block> tempBuffer;
+
+ if (compressedSize)
+ {
+ compressedBuffer.Reset (host.Allocate (compressedSize));
+ }
+
+ if (uncompressedSize.Get ())
+ {
+ uncompressedBuffer.Reset (host.Allocate (uncompressedSize.Get ()));
+ }
+
+ if (ifd.fSubTileBlockRows > 1 && uncompressedSize.Get ())
+ {
+ subTileBlockBuffer.Reset (host.Allocate (uncompressedSize.Get ()));
+ }
+
+ // Write out each tile.
+
+ uint32 tileIndex = 0;
+
+ for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
+ {
+
+ for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
+ {
+
+ // Remember this offset.
+
+ uint32 tileOffset = (uint32) stream.Position ();
+
+ basic.SetTileOffset (tileIndex, tileOffset);
+
+ // Split tile into sub-tiles if possible.
+
+ 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);
+
+ // Write the sub-tile.
+
+ WriteTile (host,
+ ifd,
+ stream,
+ image,
+ subArea,
+ fakeChannels,
+ compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer,
+ tempBuffer,
+ useMultipleThreads);
+
+ }
+
+ // Update tile count.
+
+ uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
+
+ basic.SetTileByteCount (tileIndex, tileByteCount);
+
+ tileIndex++;
+
+ // Keep the tiles on even byte offsets.
+
+ if (tileByteCount & 1)
+ {
+ stream.Put_uint8 (0);
+ }
+
+ }
+ }
+
}
+
+ }
- // Allocate buffer to hold one sub-tile of uncompressed data.
-
- uint32 uncompressedSize = subTileLength * tileRowBytes;
-
- fUncompressedBuffer.Reset (host.Allocate (uncompressedSize));
-
- // Buffer to repack tiles order.
+/*****************************************************************************/
- if (ifd.fSubTileBlockRows > 1)
+static void CopyString (const dng_xmp &oldXMP,
+ dng_xmp &newXMP,
+ const char *ns,
+ const char *path,
+ dng_string *exif = NULL)
+ {
+
+ dng_string s;
+
+ if (oldXMP.GetString (ns, path, s))
{
-
- fSubTileBlockBuffer.Reset (host.Allocate (uncompressedSize));
-
+
+ if (s.NotEmpty ())
+ {
+
+ newXMP.SetString (ns, path, s);
+
+ if (exif)
+ {
+
+ *exif = s;
+
+ }
+
+ }
+
}
+
+ }
+
+/*****************************************************************************/
- // Allocate compressed buffer, if required.
-
- uint32 compressedSize = CompressedBufferSize (ifd, uncompressedSize);
-
- if (compressedSize)
+static void CopyStringList (const dng_xmp &oldXMP,
+ dng_xmp &newXMP,
+ const char *ns,
+ const char *path,
+ bool isBag)
+ {
+
+ dng_string_list list;
+
+ if (oldXMP.GetStringList (ns, path, list))
{
-
- fCompressedBuffer.Reset (host.Allocate (compressedSize));
-
+
+ if (list.Count ())
+ {
+
+ newXMP.SetStringList (ns, path, list, isBag);
+
+ }
+
}
+
+ }
+
+/*****************************************************************************/
- // Write out each tile.
+static void CopyAltLangDefault (const dng_xmp &oldXMP,
+ dng_xmp &newXMP,
+ const char *ns,
+ const char *path,
+ dng_string *exif = NULL)
+ {
+
+ dng_string s;
+
+ if (oldXMP.GetAltLangDefault (ns, path, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ newXMP.SetAltLangDefault (ns, path, s);
+
+ if (exif)
+ {
+
+ *exif = s;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
- uint32 tileIndex = 0;
+static void CopyStructField (const dng_xmp &oldXMP,
+ dng_xmp &newXMP,
+ const char *ns,
+ const char *path,
+ const char *field)
+ {
+
+ dng_string s;
+
+ if (oldXMP.GetStructField (ns, path, ns, field, s))
+ {
+
+ if (s.NotEmpty ())
+ {
+
+ newXMP.SetStructField (ns, path, ns, field, s);
+
+ }
+
+ }
+
+ }
- uint32 tilesAcross = ifd.TilesAcross ();
- uint32 tilesDown = ifd.TilesDown ();
+/*****************************************************************************/
- for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
+static void CopyBoolean (const dng_xmp &oldXMP,
+ dng_xmp &newXMP,
+ const char *ns,
+ const char *path)
+ {
+
+ bool b;
+
+ if (oldXMP.GetBoolean (ns, path, b))
{
+
+ newXMP.SetBoolean (ns, path, b);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_image_writer::CleanUpMetadata (dng_host &host,
+ dng_metadata &metadata,
+ dng_metadata_subset metadataSubset,
+ const char *dstMIME,
+ const char *software)
+ {
+
+ if (metadata.GetXMP () && metadata.GetExif ())
+ {
+
+ dng_xmp &newXMP (*metadata.GetXMP ());
+ dng_exif &newEXIF (*metadata.GetExif ());
+
+ // Update software tag.
+
+ if (software)
+ {
+
+ newEXIF.fSoftware.Set (software);
+
+ newXMP.Set (XMP_NS_XAP,
+ "CreatorTool",
+ software);
+
+ }
+
+ #if qDNGXMPDocOps
+
+ newXMP.DocOpsPrepareForSave (metadata.SourceMIME ().Get (),
+ dstMIME);
+
+ #else
+
+ metadata.UpdateDateTimeToNow ();
+
+ #endif
+
+ // Update EXIF version to at least 2.3.1 so all the exif tags
+ // can be written.
+
+ if (!newEXIF.AtLeastVersion0231 ())
+ {
+
+ newEXIF.SetVersion0231 ();
+
+ newXMP.Set (XMP_NS_EXIF, "ExifVersion", "0231");
+
+ }
+
+ // Resync EXIF, remove EXIF tags from XMP.
+
+ newXMP.SyncExif (newEXIF,
+ metadata.GetOriginalExif (),
+ false,
+ true);
+
+ // Deal with ImageIngesterPro bug. This program is adding lots of
+ // empty metadata strings into the XMP, which is screwing up Adobe CS4.
+ // We are saving a new file, so this is a chance to clean up this mess.
+
+ newXMP.RemoveEmptyStringsAndArrays (XMP_NS_DC);
+ newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP);
+ newXMP.RemoveEmptyStringsAndArrays (XMP_NS_PHOTOSHOP);
+ newXMP.RemoveEmptyStringsAndArrays (XMP_NS_IPTC);
+ newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP_RIGHTS);
+ newXMP.RemoveEmptyStringsAndArrays ("http://ns.iview-multimedia.com/mediapro/1.0/");
+
+ // Process metadata subset.
+
+ if (metadataSubset == kMetadataSubset_CopyrightOnly ||
+ metadataSubset == kMetadataSubset_CopyrightAndContact)
+ {
+
+ dng_xmp oldXMP (newXMP );
+ dng_exif oldEXIF (newEXIF);
+
+ // For these options, we start from nothing, and only fill in the
+ // fields that we absolutely need.
+
+ newXMP.RemoveProperties (NULL);
+
+ newEXIF.SetEmpty ();
+
+ metadata.ClearMakerNote ();
+
+ // Exif version is always required.
+
+ newEXIF.fExifVersion = oldEXIF.fExifVersion;
+
+ // Move copyright related fields over.
+
+ CopyAltLangDefault (oldXMP,
+ newXMP,
+ XMP_NS_DC,
+ "rights",
+ &newEXIF.fCopyright);
+
+ CopyAltLangDefault (oldXMP,
+ newXMP,
+ XMP_NS_XAP_RIGHTS,
+ "UsageTerms");
+
+ CopyString (oldXMP,
+ newXMP,
+ XMP_NS_XAP_RIGHTS,
+ "WebStatement");
+
+ CopyBoolean (oldXMP,
+ newXMP,
+ XMP_NS_XAP_RIGHTS,
+ "Marked");
+
+ #if qDNGXMPDocOps
+
+ // Include basic DocOps fields, but not the full history.
+
+ CopyString (oldXMP,
+ newXMP,
+ XMP_NS_MM,
+ "OriginalDocumentID");
+
+ CopyString (oldXMP,
+ newXMP,
+ XMP_NS_MM,
+ "DocumentID");
+
+ CopyString (oldXMP,
+ newXMP,
+ XMP_NS_MM,
+ "InstanceID");
+
+ CopyString (oldXMP,
+ newXMP,
+ XMP_NS_XAP,
+ "MetadataDate");
+
+ #endif
+
+ // Copyright and Contact adds the contact info fields.
+
+ if (metadataSubset == kMetadataSubset_CopyrightAndContact)
+ {
+
+ // Note: Save for Web is not including the dc:creator list, but it
+ // is part of the IPTC contract info metadata panel, so I
+ // think it should be copied as part of the contact info.
+
+ CopyStringList (oldXMP,
+ newXMP,
+ XMP_NS_DC,
+ "creator",
+ false);
+
+ // The first string dc:creator list is mirrored to the
+ // the exif artist tag, so copy that also.
+
+ newEXIF.fArtist = oldEXIF.fArtist;
+
+ // Copy other contact fields.
+
+ CopyString (oldXMP,
+ newXMP,
+ XMP_NS_PHOTOSHOP,
+ "AuthorsPosition");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiEmailWork");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiAdrExtadr");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiAdrCity");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiAdrRegion");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiAdrPcode");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiAdrCtry");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiTelWork");
+
+ CopyStructField (oldXMP,
+ newXMP,
+ XMP_NS_IPTC,
+ "CreatorContactInfo",
+ "CiUrlWork");
+
+ CopyAltLangDefault (oldXMP,
+ newXMP,
+ XMP_NS_DC,
+ "title");
+
+ }
- for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
+ }
+
+ else if (metadataSubset == kMetadataSubset_AllExceptCameraInfo ||
+ metadataSubset == kMetadataSubset_AllExceptCameraAndLocation ||
+ metadataSubset == kMetadataSubset_AllExceptLocationInfo ||
+ metadataSubset == KMetadataSubset_AllExceptCameraRawInfo ||
+ metadataSubset == KMetadataSubset_AllExceptCameraRawInfoAndLocation)
{
+
+ dng_xmp oldXMP (newXMP );
+ dng_exif oldEXIF (newEXIF);
- // Remember this offset.
+ if (metadataSubset == kMetadataSubset_AllExceptCameraInfo ||
+ metadataSubset == kMetadataSubset_AllExceptCameraAndLocation ||
+ metadataSubset == KMetadataSubset_AllExceptCameraRawInfo ||
+ metadataSubset == KMetadataSubset_AllExceptCameraRawInfoAndLocation)
+ {
+
+ // Remove Camera Raw info.
- uint32 tileOffset = (uint32) stream.Position ();
+ newXMP.RemoveProperties(XMP_NS_CRS);
+ newXMP.RemoveProperties(XMP_NS_CRSS);
+ newXMP.RemoveProperties(XMP_NS_CRX);
- basic.SetTileOffset (tileIndex, tileOffset);
+ // Remove DocOps history, since it contains the original
+ // camera format and processing history.
- // Split tile into sub-tiles if possible.
+ newXMP.Remove(XMP_NS_MM, "History");
- dng_rect tileArea = ifd.TileArea (rowIndex, colIndex);
+ // Remove Panorama info.
- uint32 subTileCount = (tileArea.H () + subTileLength - 1) /
- subTileLength;
+ newXMP.RemoveProperties(XMP_NS_PANO);
- for (uint32 subIndex = 0; subIndex < subTileCount; subIndex++)
+ }
+
+ if (metadataSubset == kMetadataSubset_AllExceptCameraInfo ||
+ metadataSubset == kMetadataSubset_AllExceptCameraAndLocation)
{
+
+ // This removes most of the EXIF info, so just copy the fields
+ // we are not deleting.
+
+ newEXIF.SetEmpty ();
+
+ newEXIF.fImageDescription = oldEXIF.fImageDescription; // Note: Differs from SFW
+ newEXIF.fSoftware = oldEXIF.fSoftware;
+ newEXIF.fArtist = oldEXIF.fArtist;
+ newEXIF.fCopyright = oldEXIF.fCopyright;
+ newEXIF.fCopyright2 = oldEXIF.fCopyright2;
+ newEXIF.fDateTime = oldEXIF.fDateTime;
+ newEXIF.fDateTimeOriginal = oldEXIF.fDateTimeOriginal;
+ newEXIF.fDateTimeDigitized = oldEXIF.fDateTimeDigitized;
+ newEXIF.fExifVersion = oldEXIF.fExifVersion;
+ newEXIF.fImageUniqueID = oldEXIF.fImageUniqueID;
+
+ newEXIF.CopyGPSFrom (oldEXIF);
+
+ // Remove exif info from XMP.
+
+ newXMP.RemoveProperties (XMP_NS_EXIF);
+ newXMP.RemoveProperties (XMP_NS_EXIFEX);
+ newXMP.RemoveProperties (XMP_NS_AUX);
+
+ // MakerNote contains camera info.
+
+ metadata.ClearMakerNote ();
+
+ }
+
+ if (metadataSubset == kMetadataSubset_AllExceptLocationInfo ||
+ metadataSubset == kMetadataSubset_AllExceptCameraAndLocation ||
+ metadataSubset == KMetadataSubset_AllExceptCameraRawInfoAndLocation)
+ {
+
+ // Remove GPS fields.
+
+ dng_exif blankExif;
+
+ newEXIF.CopyGPSFrom (blankExif);
+
+ // Remove MakerNote just in case, because we don't know
+ // all of what is in it.
+
+ metadata.ClearMakerNote ();
+
+ // Remove XMP & IPTC location fields.
+
+ newXMP.Remove (XMP_NS_PHOTOSHOP, "City");
+ newXMP.Remove (XMP_NS_PHOTOSHOP, "State");
+ newXMP.Remove (XMP_NS_PHOTOSHOP, "Country");
+ newXMP.Remove (XMP_NS_IPTC, "Location");
+ newXMP.Remove (XMP_NS_IPTC, "CountryCode");
+ newXMP.Remove (XMP_NS_IPTC_EXT, "LocationCreated");
+ newXMP.Remove (XMP_NS_IPTC_EXT, "LocationShown");
+
+ }
+
+ }
+
+ // Rebuild the legacy IPTC block, if needed.
+
+ bool isTIFF = (strcmp (dstMIME, "image/tiff") == 0);
+ bool isDNG = (strcmp (dstMIME, "image/dng" ) == 0);
- host.SniffForAbort ();
-
- dng_rect subArea (tileArea);
+ if (!isDNG)
+ {
+
+ metadata.RebuildIPTC (host.Allocator (),
+ isTIFF);
+
+ }
+
+ else
+ {
+
+ metadata.ClearIPTC ();
+
+ }
+
+ // Clear format related XMP.
+
+ newXMP.ClearOrientation ();
+
+ newXMP.ClearImageInfo ();
+
+ newXMP.RemoveProperties (XMP_NS_DNG);
+
+ // Clear default camera raw settings if not writing to DNG.
+
+ if (!isDNG)
+ {
+
+ newXMP.RemoveProperties (XMP_NS_CRD);
+
+ }
+
+ // All the formats we care about already keep the IPTC digest
+ // elsewhere, do we don't need to write it to the XMP.
+
+ newXMP.ClearIPTCDigest ();
+
+ // Make sure that sidecar specific tags never get written to files.
+
+ newXMP.Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
+ newXMP.Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
+
+ }
+
+ }
- subArea.t = tileArea.t + subIndex * subTileLength;
+/*****************************************************************************/
- subArea.b = Min_int32 (subArea.t + subTileLength,
- tileArea.b);
+void dng_image_writer::UpdateExifColorSpaceTag (dng_metadata &metadata,
+ const void *profileData,
+ const uint32 profileSize)
+ {
+
+ if (!metadata.GetExif ())
+ {
+ return;
+ }
- // Write the sub-tile.
+ dng_exif &exif = *metadata.GetExif ();
- WriteTile (host,
- ifd,
- stream,
- image,
- subArea,
- fakeChannels);
+ uint32 tagValue = 0xFFFF;
- }
+ if (profileData && profileSize)
+ {
- // Update tile count.
+ // Is the color profile sRGB IEC61966-2.1?
- uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
+ uint32 sRGB_size = 0;
+ const uint8 *sRGB_data = 0;
- basic.SetTileByteCount (tileIndex, tileByteCount);
+ if (dng_space_sRGB::Get ().ICCProfile (sRGB_size,
+ sRGB_data))
+ {
- tileIndex++;
+ if ((sRGB_size == profileSize) &&
+ !memcmp (profileData,
+ (const void *) sRGB_data,
+ (size_t) sRGB_size))
+ {
- // Keep the tiles on even byte offsets.
+ // Yes.
+
+ tagValue = 1;
- if (tileByteCount & 1)
- {
- stream.Put_uint8 (0);
}
-
+
}
+#if qLinux
+ exif.fColorSpace = tagValue;
}
-
- // We are done with the compression buffers.
-
- fCompressedBuffer .Reset ();
- fUncompressedBuffer.Reset ();
-
+#else
+ }
+ exif.fColorSpace = tagValue;
+#endif
}
/*****************************************************************************/
void dng_image_writer::WriteTIFF (dng_host &host,
dng_stream &stream,
const dng_image &image,
uint32 photometricInterpretation,
uint32 compression,
dng_negative *negative,
const dng_color_space *space,
const dng_resolution *resolution,
const dng_jpeg_preview *thumbnail,
- const dng_memory_block *imageResources)
+ const dng_memory_block *imageResources,
+ dng_metadata_subset metadataSubset,
+ bool hasTransparency)
{
+
+ WriteTIFF (host,
+ stream,
+ image,
+ photometricInterpretation,
+ compression,
+ negative ? &(negative->Metadata ()) : NULL,
+ space,
+ resolution,
+ thumbnail,
+ imageResources,
+ metadataSubset,
+ hasTransparency);
+
+ }
+
+/*****************************************************************************/
+void dng_image_writer::WriteTIFF (dng_host &host,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 photometricInterpretation,
+ uint32 compression,
+ const dng_metadata *metadata,
+ const dng_color_space *space,
+ const dng_resolution *resolution,
+ const dng_jpeg_preview *thumbnail,
+ const dng_memory_block *imageResources,
+ dng_metadata_subset metadataSubset,
+ bool hasTransparency)
+ {
+
const void *profileData = NULL;
uint32 profileSize = 0;
-
+
const uint8 *data = NULL;
uint32 size = 0;
-
+
if (space && space->ICCProfile (size, data))
{
-
+
profileData = data;
profileSize = size;
-
+
}
+
+ WriteTIFFWithProfile (host,
+ stream,
+ image,
+ photometricInterpretation,
+ compression,
+ metadata,
+ profileData,
+ profileSize,
+ resolution,
+ thumbnail,
+ imageResources,
+ metadataSubset,
+ hasTransparency);
+
+ }
+/*****************************************************************************/
+
+void dng_image_writer::WriteTIFFWithProfile (dng_host &host,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 photometricInterpretation,
+ uint32 compression,
+ dng_negative *negative,
+ const void *profileData,
+ uint32 profileSize,
+ const dng_resolution *resolution,
+ const dng_jpeg_preview *thumbnail,
+ const dng_memory_block *imageResources,
+ dng_metadata_subset metadataSubset,
+ bool hasTransparency)
+ {
+
WriteTIFFWithProfile (host,
stream,
image,
photometricInterpretation,
compression,
- negative,
+ negative ? &(negative->Metadata ()) : NULL,
profileData,
profileSize,
resolution,
thumbnail,
- imageResources);
-
+ imageResources,
+ metadataSubset,
+ hasTransparency);
+
}
-
+
/*****************************************************************************/
void dng_image_writer::WriteTIFFWithProfile (dng_host &host,
dng_stream &stream,
const dng_image &image,
uint32 photometricInterpretation,
uint32 compression,
- dng_negative *negative,
+ const dng_metadata *constMetadata,
const void *profileData,
uint32 profileSize,
const dng_resolution *resolution,
const dng_jpeg_preview *thumbnail,
- const dng_memory_block *imageResources)
+ const dng_memory_block *imageResources,
+ dng_metadata_subset metadataSubset,
+ bool hasTransparency)
{
-
+
uint32 j;
-
+
+ AutoPtr<dng_metadata> metadata;
+
+ if (constMetadata)
+ {
+
+ metadata.Reset (constMetadata->Clone (host.Allocator ()));
+
+ CleanUpMetadata (host,
+ *metadata,
+ metadataSubset,
+ "image/tiff");
+
+ UpdateExifColorSpaceTag (*metadata,
+ profileData,
+ profileSize);
+
+ }
+
dng_ifd ifd;
-
+
ifd.fNewSubFileType = sfMainImage;
-
+
ifd.fImageWidth = image.Bounds ().W ();
ifd.fImageLength = image.Bounds ().H ();
-
+
ifd.fSamplesPerPixel = image.Planes ();
-
+
ifd.fBitsPerSample [0] = TagTypeSize (image.PixelType ()) * 8;
-
+
for (j = 1; j < ifd.fSamplesPerPixel; j++)
{
ifd.fBitsPerSample [j] = ifd.fBitsPerSample [0];
}
-
+
ifd.fPhotometricInterpretation = photometricInterpretation;
-
+
ifd.fCompression = compression;
-
+
if (ifd.fCompression == ccUncompressed)
{
-
+
ifd.SetSingleStrip ();
-
+
}
-
+
else
{
-
+
ifd.FindStripSize (128 * 1024);
-
+
ifd.fPredictor = cpHorizontalDifference;
-
+
}
uint32 extraSamples = 0;
-
+
switch (photometricInterpretation)
{
-
+
case piBlackIsZero:
{
extraSamples = image.Planes () - 1;
break;
}
-
+
case piRGB:
+ case piCIELab:
+ case piICCLab:
{
extraSamples = image.Planes () - 3;
break;
}
-
+
+ case piCMYK:
+ {
+ extraSamples = image.Planes () - 4;
+ break;
+ }
+
default:
break;
-
+
}
-
+
ifd.fExtraSamplesCount = extraSamples;
-
+
+ if (hasTransparency && extraSamples)
+ {
+ ifd.fExtraSamples [0] = esAssociatedAlpha;
+ }
+
if (image.PixelType () == ttFloat)
{
-
+
for (j = 0; j < ifd.fSamplesPerPixel; j++)
{
ifd.fSampleFormat [j] = sfFloatingPoint;
}
-
+
}
-
+
dng_tiff_directory mainIFD;
-
+
dng_basic_tag_set basic (mainIFD, ifd);
-
+
// Resolution.
-
+
dng_resolution res;
-
+
if (resolution)
{
res = *resolution;
}
-
+
tag_urational tagXResolution (tcXResolution, res.fXResolution);
tag_urational tagYResolution (tcYResolution, res.fYResolution);
-
+
tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
-
+
if (resolution)
{
mainIFD.Add (&tagXResolution );
mainIFD.Add (&tagYResolution );
mainIFD.Add (&tagResolutionUnit);
}
// ICC Profile.
-
+
tag_icc_profile iccProfileTag (profileData, profileSize);
-
+
if (iccProfileTag.Count ())
{
mainIFD.Add (&iccProfileTag);
}
-
- // Rebuild IPTC with TIFF padding bytes.
-
- if (negative && negative->GetXMP ())
- {
-
- negative->RebuildIPTC (true, false);
-
- }
-
+
// XMP metadata.
-
- AutoPtr<dng_xmp> xmp;
-
- if (negative && negative->GetXMP ())
- {
-
- xmp.Reset (new dng_xmp (*negative->GetXMP ()));
-
- xmp->ClearOrientation ();
-
- xmp->ClearItemInfo ();
-
- xmp->SetImageSize (image.Size ());
-
- xmp->SetSampleInfo (ifd.fSamplesPerPixel,
- ifd.fBitsPerSample [0]);
-
- xmp->SetPhotometricInterpretation (ifd.fPhotometricInterpretation);
-
- if (resolution)
- {
- xmp->SetResolution (*resolution);
- }
-
- }
-
- tag_xmp tagXMP (xmp.Get ());
-
+
+ tag_xmp tagXMP (metadata.Get () ? metadata->GetXMP () : NULL);
+
if (tagXMP.Count ())
{
mainIFD.Add (&tagXMP);
}
-
- xmp.Reset ();
-
+
// IPTC metadata.
-
- tag_iptc tagIPTC (negative ? negative->IPTCData () : NULL,
- negative ? negative->IPTCLength () : 0);
-
+
+ tag_iptc tagIPTC (metadata.Get () ? metadata->IPTCData () : NULL,
+ metadata.Get () ? metadata->IPTCLength () : 0);
+
if (tagIPTC.Count ())
{
mainIFD.Add (&tagIPTC);
}
-
+
// Adobe data (thumbnail and IPTC digest)
-
+
AutoPtr<dng_memory_block> adobeData (BuildAdobeData (host,
- negative,
+ metadata.Get (),
thumbnail,
imageResources));
-
+
tag_uint8_ptr tagAdobe (tcAdobeData,
adobeData->Buffer_uint8 (),
adobeData->LogicalSize ());
-
+
if (tagAdobe.Count ())
{
mainIFD.Add (&tagAdobe);
}
-
+
// Exif metadata.
-
+
exif_tag_set exifSet (mainIFD,
- negative && negative->GetExif () ? *negative->GetExif ()
- : dng_exif (),
- negative ? negative->IsMakerNoteSafe () : false,
- negative ? negative->MakerNoteData () : NULL,
- negative ? negative->MakerNoteLength () : 0,
+ metadata.Get () && metadata->GetExif () ? *metadata->GetExif ()
+ : dng_exif (),
+ metadata.Get () ? metadata->IsMakerNoteSafe () : false,
+ metadata.Get () ? metadata->MakerNoteData () : NULL,
+ metadata.Get () ? metadata->MakerNoteLength () : 0,
false);
// Find offset to main image data.
-
+
uint32 offsetMainIFD = 8;
-
+
uint32 offsetExifData = offsetMainIFD + mainIFD.Size ();
-
+
exifSet.Locate (offsetExifData);
-
+
uint32 offsetMainData = offsetExifData + exifSet.Size ();
-
+
stream.SetWritePosition (offsetMainData);
-
+
// Write the main image data.
-
+
WriteImage (host,
ifd,
basic,
stream,
image);
-
+
// Trim the file to this length.
-
+
stream.SetLength (stream.Position ());
-
+
// TIFF has a 4G size limit.
-
+
if (stream.Length () > 0x0FFFFFFFFL)
{
ThrowImageTooBigTIFF ();
}
-
+
// Write TIFF Header.
-
+
stream.SetWritePosition (0);
-
+
stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
-
+
stream.Put_uint16 (42);
-
+
stream.Put_uint32 (offsetMainIFD);
-
+
// Write the IFDs.
-
+
mainIFD.Put (stream);
-
+
exifSet.Put (stream);
-
+
stream.Flush ();
-
+
}
-
+
/*****************************************************************************/
void dng_image_writer::WriteDNG (dng_host &host,
dng_stream &stream,
- const dng_negative &negative,
- const dng_image_preview &thumbnail,
- uint32 compression,
- const dng_preview_list *previewList)
+ dng_negative &negative,
+ const dng_preview_list *previewList,
+ uint32 maxBackwardVersion,
+ bool uncompressed)
+ {
+
+ WriteDNGWithMetadata (host,
+ stream,
+ negative,
+ negative.Metadata (),
+ previewList,
+ maxBackwardVersion,
+ uncompressed);
+
+ }
+
+/*****************************************************************************/
+
+void dng_image_writer::WriteDNGWithMetadata (dng_host &host,
+ dng_stream &stream,
+ const dng_negative &negative,
+ const dng_metadata &constMetadata,
+ const dng_preview_list *previewList,
+ uint32 maxBackwardVersion,
+ bool uncompressed)
{
uint32 j;
+
+ // Clean up metadata per MWG recommendations.
+
+ AutoPtr<dng_metadata> metadata (constMetadata.Clone (host.Allocator ()));
+
+ CleanUpMetadata (host,
+ *metadata,
+ kMetadataSubset_All,
+ "image/dng");
+
+ // Figure out the compression to use. Most of the time this is lossless
+ // JPEG.
+
+ uint32 compression = uncompressed ? ccUncompressed : ccJPEG;
+
+ // Was the the original file lossy JPEG compressed?
+
+ const dng_jpeg_image *rawJPEGImage = negative.RawJPEGImage ();
+
+ // If so, can we save it using the requested compression and DNG version?
+
+ if (uncompressed || maxBackwardVersion < dngVersion_1_4_0_0)
+ {
+
+ if (rawJPEGImage || negative.RawJPEGImageDigest ().IsValid ())
+ {
+
+ rawJPEGImage = NULL;
+
+ negative.ClearRawJPEGImageDigest ();
+
+ negative.ClearRawImageDigest ();
+
+ }
+
+ }
+
+ else if (rawJPEGImage)
+ {
+
+ compression = ccLossyJPEG;
+
+ }
+
+ // Are we saving the original size tags?
+
+ bool saveOriginalDefaultFinalSize = false;
+ bool saveOriginalBestQualityFinalSize = false;
+ bool saveOriginalDefaultCropSize = false;
+
+ {
+
+ // See if we are saving a proxy image.
+
+ dng_point defaultFinalSize (negative.DefaultFinalHeight (),
+ negative.DefaultFinalWidth ());
+
+ saveOriginalDefaultFinalSize = (negative.OriginalDefaultFinalSize () !=
+ defaultFinalSize);
+
+ if (saveOriginalDefaultFinalSize)
+ {
+
+ // If the save OriginalDefaultFinalSize tag, this changes the defaults
+ // for the OriginalBestQualityFinalSize and OriginalDefaultCropSize tags.
+
+ saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () !=
+ negative.OriginalDefaultFinalSize ());
+
+ saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () !=
+ dng_urational (negative.OriginalDefaultFinalSize ().v, 1)) ||
+ (negative.OriginalDefaultCropSizeH () !=
+ dng_urational (negative.OriginalDefaultFinalSize ().h, 1));
+ }
+
+ else
+ {
+
+ // Else these two tags default to the normal non-proxy size image values.
+
+ dng_point bestQualityFinalSize (negative.BestQualityFinalHeight (),
+ negative.BestQualityFinalWidth ());
+
+ saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () !=
+ bestQualityFinalSize);
+
+ saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () !=
+ negative.DefaultCropSizeV ()) ||
+ (negative.OriginalDefaultCropSizeH () !=
+ negative.DefaultCropSizeH ());
+
+ }
+
+ }
+
+ // Is this a floating point image that we are saving?
+
+ bool isFloatingPoint = (negative.RawImage ().PixelType () == ttFloat);
+
+ // Does this image have a transparency mask?
+
+ bool hasTransparencyMask = (negative.RawTransparencyMask () != NULL);
+
+ // Does the image have depth mask?
+
+ bool hasDepthMap = (negative.RawDepthMap () != NULL);
+
+ // Should we save the enhanced stage 3 image?
+
+ bool hasEnhancedImage = (&negative.RawImage () != negative.Stage3Image ()) &&
+ negative.EnhanceParams ().NotEmpty ();
+
+ // Should we save a compressed 32-bit integer file?
+
+ bool isCompressed32BitInteger = (negative.RawImage ().PixelType () == ttLong) &&
+ (maxBackwardVersion >= dngVersion_1_4_0_0) &&
+ (!uncompressed);
+
// Figure out what main version to use.
-
+
uint32 dngVersion = dngVersion_Current;
-
+
+ if (!hasDepthMap && !hasEnhancedImage)
+ {
+
+ // Nothing in DNG 1.5 specification breaks backward compatiblity,
+ // so there is not really any reason to mark the file as being
+ // in DNG 1.5 format. So unless we are actually using an optional
+ // DNG 1.5 feature, leave the main version tag at 1.4.
+
+ dngVersion = dngVersion_1_4_0_0;
+
+ }
+
// Figure out what backward version to use.
-
+
uint32 dngBackwardVersion = dngVersion_1_1_0_0;
-
+
#if defined(qTestRowInterleave) || defined(qTestSubTileBlockRows) || defined(qTestSubTileBlockCols)
dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_2_0_0);
#endif
-
+
dngBackwardVersion = Max_uint32 (dngBackwardVersion,
negative.OpcodeList1 ().MinVersion (false));
dngBackwardVersion = Max_uint32 (dngBackwardVersion,
negative.OpcodeList2 ().MinVersion (false));
dngBackwardVersion = Max_uint32 (dngBackwardVersion,
negative.OpcodeList3 ().MinVersion (false));
-
+
if (negative.GetMosaicInfo () &&
negative.GetMosaicInfo ()->fCFALayout >= 6)
{
dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_3_0_0);
}
-
+
+ if (rawJPEGImage || isFloatingPoint || hasTransparencyMask || isCompressed32BitInteger)
+ {
+ dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_4_0_0);
+ }
+
if (dngBackwardVersion > dngVersion)
{
ThrowProgramError ();
}
+
+ // Find best thumbnail from preview list, if any.
+ const dng_preview *thumbnail = NULL;
+
+ if (previewList)
+ {
+
+ uint32 thumbArea = 0;
+
+ for (j = 0; j < previewList->Count (); j++)
+ {
+
+ const dng_image_preview *imagePreview = dynamic_cast<const dng_image_preview *>(&previewList->Preview (j));
+
+ if (imagePreview)
+ {
+
+ uint32 thisArea = imagePreview->fImage->Bounds ().W () *
+ imagePreview->fImage->Bounds ().H ();
+
+ if (!thumbnail || thisArea < thumbArea)
+ {
+
+ thumbnail = &previewList->Preview (j);
+
+ thumbArea = thisArea;
+
+ }
+
+ }
+
+ const dng_jpeg_preview *jpegPreview = dynamic_cast<const dng_jpeg_preview *>(&previewList->Preview (j));
+
+ if (jpegPreview)
+ {
+
+ uint32 thisArea = jpegPreview->fPreviewSize.h *
+ jpegPreview->fPreviewSize.v;
+
+ if (!thumbnail || thisArea < thumbArea)
+ {
+
+ thumbnail = &previewList->Preview (j);
+
+ thumbArea = thisArea;
+
+ }
+
+ }
+
+ }
+
+ }
+
// Create the main IFD
-
+
dng_tiff_directory mainIFD;
+
+ // Create the IFD for the raw data. If there is no thumnail, this is
+ // just a reference the main IFD. Otherwise allocate a new one.
+
+ AutoPtr<dng_tiff_directory> rawIFD_IfNotMain;
+
+ if (thumbnail)
+ {
+ rawIFD_IfNotMain.Reset (new dng_tiff_directory);
+ }
+ dng_tiff_directory &rawIFD (thumbnail ? *rawIFD_IfNotMain : mainIFD);
+
// Include DNG version tags.
-
+
uint8 dngVersionData [4];
-
+
dngVersionData [0] = (uint8) (dngVersion >> 24);
dngVersionData [1] = (uint8) (dngVersion >> 16);
dngVersionData [2] = (uint8) (dngVersion >> 8);
dngVersionData [3] = (uint8) (dngVersion );
-
+
tag_uint8_ptr tagDNGVersion (tcDNGVersion, dngVersionData, 4);
-
+
mainIFD.Add (&tagDNGVersion);
-
+
uint8 dngBackwardVersionData [4];
dngBackwardVersionData [0] = (uint8) (dngBackwardVersion >> 24);
dngBackwardVersionData [1] = (uint8) (dngBackwardVersion >> 16);
dngBackwardVersionData [2] = (uint8) (dngBackwardVersion >> 8);
dngBackwardVersionData [3] = (uint8) (dngBackwardVersion );
-
+
tag_uint8_ptr tagDNGBackwardVersion (tcDNGBackwardVersion, dngBackwardVersionData, 4);
-
+
mainIFD.Add (&tagDNGBackwardVersion);
-
- // The main IFD contains the thumbnail.
-
- AutoPtr<dng_basic_tag_set> thmBasic (thumbnail.AddTagSet (mainIFD));
-
+
+ // The main IFD contains the thumbnail, if there is a thumbnail.
+
+ AutoPtr<dng_basic_tag_set> thmBasic;
+
+ if (thumbnail)
+ {
+ thmBasic.Reset (thumbnail->AddTagSet (mainIFD));
+ }
+
// Get the raw image we are writing.
-
+
const dng_image &rawImage (negative.RawImage ());
-
- // We currently don't support compression for deeper
- // than 16-bit images.
-
+
+ // For floating point, we only support ZIP compression.
+
+ if (isFloatingPoint && !uncompressed)
+ {
+
+ compression = ccDeflate;
+
+ }
+
+ // For 32-bit integer images, we only support ZIP and uncompressed.
+
if (rawImage.PixelType () == ttLong)
{
- compression = ccUncompressed;
+
+ if (isCompressed32BitInteger)
+ {
+ compression = ccDeflate;
+ }
+
+ else
+ {
+ compression = ccUncompressed;
+ }
+
}
-
+
// Get a copy of the mosaic info.
-
+
dng_mosaic_info mosaicInfo;
-
+
if (negative.GetMosaicInfo ())
{
mosaicInfo = *(negative.GetMosaicInfo ());
}
-
- // Create the IFD for the raw data.
-
- dng_tiff_directory rawIFD;
-
+
// Create a dng_ifd record for the raw image.
-
+
dng_ifd info;
-
+
info.fImageWidth = rawImage.Width ();
info.fImageLength = rawImage.Height ();
-
+
info.fSamplesPerPixel = rawImage.Planes ();
-
+
info.fPhotometricInterpretation = mosaicInfo.IsColorFilterArray () ? piCFA
: piLinearRaw;
-
+
info.fCompression = compression;
-
+
+ if (isFloatingPoint && compression == ccDeflate)
+ {
+
+ info.fPredictor = cpFloatingPoint;
+
+ if (mosaicInfo.IsColorFilterArray ())
+ {
+
+ if (mosaicInfo.fCFAPatternSize.h == 2)
+ {
+ info.fPredictor = cpFloatingPointX2;
+ }
+
+ else if (mosaicInfo.fCFAPatternSize.h == 4)
+ {
+ info.fPredictor = cpFloatingPointX4;
+ }
+
+ }
+
+ }
+
+ if (isCompressed32BitInteger)
+ {
+
+ info.fPredictor = cpHorizontalDifference;
+
+ if (mosaicInfo.IsColorFilterArray ())
+ {
+
+ if (mosaicInfo.fCFAPatternSize.h == 2)
+ {
+ info.fPredictor = cpHorizontalDifferenceX2;
+ }
+
+ else if (mosaicInfo.fCFAPatternSize.h == 4)
+ {
+ info.fPredictor = cpHorizontalDifferenceX4;
+ }
+
+ }
+
+ }
+
uint32 rawPixelType = rawImage.PixelType ();
-
+
if (rawPixelType == ttShort)
{
-
+
// See if we are using a linearization table with <= 256 entries, in which
// case the useful data will all fit within 8-bits.
-
+
const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo ();
-
+
if (rangeInfo)
{
if (rangeInfo->fLinearizationTable.Get ())
{
-
+
uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
-
+
if (entries <= 256)
{
-
+
rawPixelType = ttByte;
-
+
}
-
+
}
-
+
}
}
-
+
switch (rawPixelType)
{
-
+
case ttByte:
{
info.fBitsPerSample [0] = 8;
break;
}
-
+
case ttShort:
{
info.fBitsPerSample [0] = 16;
break;
}
-
+
case ttLong:
{
info.fBitsPerSample [0] = 32;
break;
}
+
+ case ttFloat:
+ {
+
+ if (negative.RawFloatBitDepth () == 16)
+ {
+ info.fBitsPerSample [0] = 16;
+ }
+
+ else if (negative.RawFloatBitDepth () == 24)
+ {
+ info.fBitsPerSample [0] = 24;
+ }
+
+ else
+ {
+ info.fBitsPerSample [0] = 32;
+ }
+
+ for (j = 0; j < info.fSamplesPerPixel; j++)
+ {
+ info.fSampleFormat [j] = sfFloatingPoint;
+ }
+ break;
+
+ }
+
default:
{
ThrowProgramError ();
- break;
}
-
+
}
-
+
// For lossless JPEG compression, we often lie about the
// actual channel count to get the predictors to work across
// same color mosaic pixels.
-
+
uint32 fakeChannels = 1;
-
+
if (info.fCompression == ccJPEG)
{
-
+
if (mosaicInfo.IsColorFilterArray ())
{
-
+
if (mosaicInfo.fCFAPatternSize.h == 4)
{
fakeChannels = 4;
}
-
+
else if (mosaicInfo.fCFAPatternSize.h == 2)
{
fakeChannels = 2;
}
-
+
// However, lossless JEPG is limited to four channels,
// so compromise might be required.
-
+
while (fakeChannels * info.fSamplesPerPixel > 4 &&
fakeChannels > 1)
{
-
+
fakeChannels >>= 1;
-
+
}
-
+
}
-
+
}
-
+
// Figure out tile sizes.
-
- if (info.fCompression == ccJPEG)
- {
-
+
+ if (rawJPEGImage)
+ {
+
+ DNG_ASSERT (rawPixelType == ttByte,
+ "Unexpected jpeg pixel type");
+
+ DNG_ASSERT (info.fImageWidth == (uint32) rawJPEGImage->fImageSize.h &&
+ info.fImageLength == (uint32) rawJPEGImage->fImageSize.v,
+ "Unexpected jpeg image size");
+
+ info.fTileWidth = rawJPEGImage->fTileSize.h;
+ info.fTileLength = rawJPEGImage->fTileSize.v;
+
+ info.fUsesStrips = rawJPEGImage->fUsesStrips;
+
+ info.fUsesTiles = !info.fUsesStrips;
+
+ }
+
+ else if (info.fCompression == ccJPEG)
+ {
+
info.FindTileSize (128 * 1024);
-
+
}
-
+
+ else if (info.fCompression == ccDeflate)
+ {
+
+ info.FindTileSize (512 * 1024);
+
+ }
+
+ else if (info.fCompression == ccLossyJPEG)
+ {
+
+ ThrowProgramError ("No JPEG compressed image");
+
+ }
+
// Don't use tiles for uncompressed images.
-
+
else
{
-
+
info.SetSingleStrip ();
-
+
}
-
+
#ifdef qTestRowInterleave
-
+
info.fRowInterleaveFactor = qTestRowInterleave;
-
+
#endif
-
+
#if defined(qTestSubTileBlockRows) && defined(qTestSubTileBlockCols)
-
+
info.fSubTileBlockRows = qTestSubTileBlockRows;
info.fSubTileBlockCols = qTestSubTileBlockCols;
-
+
if (fakeChannels == 2)
fakeChannels = 4;
-
+
#endif
-
+
// Basic information.
-
+
dng_basic_tag_set rawBasic (rawIFD, info);
-
+
+ // JPEG tables, if any.
+
+ tag_data_ptr tagJPEGTables (tcJPEGTables,
+ ttUndefined,
+ 0,
+ NULL);
+
+ if (rawJPEGImage && rawJPEGImage->fJPEGTables.Get ())
+ {
+
+ tagJPEGTables.SetData (rawJPEGImage->fJPEGTables->Buffer ());
+
+ tagJPEGTables.SetCount (rawJPEGImage->fJPEGTables->LogicalSize ());
+
+ rawIFD.Add (&tagJPEGTables);
+
+ }
+
// DefaultScale tag.
dng_urational defaultScaleData [2];
-
+
defaultScaleData [0] = negative.DefaultScaleH ();
defaultScaleData [1] = negative.DefaultScaleV ();
-
+
tag_urational_ptr tagDefaultScale (tcDefaultScale,
defaultScaleData,
2);
rawIFD.Add (&tagDefaultScale);
-
+
// Best quality scale tag.
-
+
tag_urational tagBestQualityScale (tcBestQualityScale,
negative.BestQualityScale ());
-
+
rawIFD.Add (&tagBestQualityScale);
-
+
// DefaultCropOrigin tag.
dng_urational defaultCropOriginData [2];
-
+
defaultCropOriginData [0] = negative.DefaultCropOriginH ();
defaultCropOriginData [1] = negative.DefaultCropOriginV ();
-
+
tag_urational_ptr tagDefaultCropOrigin (tcDefaultCropOrigin,
defaultCropOriginData,
2);
rawIFD.Add (&tagDefaultCropOrigin);
-
+
// DefaultCropSize tag.
dng_urational defaultCropSizeData [2];
-
+
defaultCropSizeData [0] = negative.DefaultCropSizeH ();
defaultCropSizeData [1] = negative.DefaultCropSizeV ();
-
+
tag_urational_ptr tagDefaultCropSize (tcDefaultCropSize,
defaultCropSizeData,
2);
rawIFD.Add (&tagDefaultCropSize);
+
+ // DefaultUserCrop tag.
- // Range mapping tag set.
+ dng_urational defaultUserCropData [4];
- range_tag_set rangeSet (rawIFD, negative);
+ defaultUserCropData [0] = negative.DefaultUserCropT ();
+ defaultUserCropData [1] = negative.DefaultUserCropL ();
+ defaultUserCropData [2] = negative.DefaultUserCropB ();
+ defaultUserCropData [3] = negative.DefaultUserCropR ();
- // Mosaic pattern information.
+ tag_urational_ptr tagDefaultUserCrop (tcDefaultUserCrop,
+ defaultUserCropData,
+ 4);
- mosaic_tag_set mosaicSet (rawIFD, mosaicInfo);
+ if (negative.HasDefaultUserCrop ())
+ {
- // Chroma blur radius.
+ rawIFD.Add (&tagDefaultUserCrop);
+ }
+
+ // Range mapping tag set.
+
+ range_tag_set rangeSet (rawIFD, negative);
+
+ // Mosaic pattern information.
+
+ mosaic_tag_set mosaicSet (rawIFD, mosaicInfo);
+
+ // Chroma blur radius.
+
tag_urational tagChromaBlurRadius (tcChromaBlurRadius,
negative.ChromaBlurRadius ());
-
+
if (negative.ChromaBlurRadius ().IsValid ())
{
-
+
rawIFD.Add (&tagChromaBlurRadius);
-
+
}
-
+
// Anti-alias filter strength.
-
+
tag_urational tagAntiAliasStrength (tcAntiAliasStrength,
negative.AntiAliasStrength ());
-
+
if (negative.AntiAliasStrength ().IsValid ())
{
-
+
rawIFD.Add (&tagAntiAliasStrength);
-
+
}
-
+
// Profile and other color related tags.
-
+
AutoPtr<profile_tag_set> profileSet;
-
+
AutoPtr<color_tag_set> colorSet;
-
+
std::vector<uint32> extraProfileIndex;
-
+
if (!negative.IsMonochrome ())
{
-
- const dng_camera_profile &mainProfile (*negative.CameraProfileToEmbed ());
-
+
+ const dng_camera_profile &mainProfile (*negative.ComputeCameraProfileToEmbed (constMetadata));
+
profileSet.Reset (new profile_tag_set (mainIFD,
mainProfile));
-
+
colorSet.Reset (new color_tag_set (mainIFD,
negative));
-
+
// Build list of profile indices to include in extra profiles tag.
-
+
uint32 profileCount = negative.ProfileCount ();
-
+
for (uint32 index = 0; index < profileCount; index++)
{
-
+
const dng_camera_profile &profile (negative.ProfileByIndex (index));
-
+
if (&profile != &mainProfile)
{
-
+
if (profile.WasReadFromDNG ())
{
-
+
extraProfileIndex.push_back (index);
-
+
}
-
+
}
-
+
}
-
+
}
-
+
// Extra camera profiles tag.
-
+
uint32 extraProfileCount = (uint32) extraProfileIndex.size ();
-
- dng_memory_data extraProfileOffsets (extraProfileCount * sizeof (uint32));
-
+
+ dng_memory_data extraProfileOffsets (extraProfileCount, sizeof (uint32));
+
tag_uint32_ptr extraProfileTag (tcExtraCameraProfiles,
extraProfileOffsets.Buffer_uint32 (),
extraProfileCount);
-
+
if (extraProfileCount)
{
-
+
mainIFD.Add (&extraProfileTag);
}
-
+
// Other tags.
-
+
tag_uint16 tagOrientation (tcOrientation,
- (uint16) negative.Orientation ().GetTIFF ());
-
+ (uint16) negative.ComputeOrientation (constMetadata).GetTIFF ());
+
mainIFD.Add (&tagOrientation);
tag_srational tagBaselineExposure (tcBaselineExposure,
negative.BaselineExposureR ());
-
+
mainIFD.Add (&tagBaselineExposure);
tag_urational tagBaselineNoise (tcBaselineNoise,
negative.BaselineNoiseR ());
-
+
mainIFD.Add (&tagBaselineNoise);
+
+ dng_urational rawNoiseReductionApplied = hasEnhancedImage ? negative.RawNoiseReductionApplied ()
+ : negative.NoiseReductionApplied ();
+
+ tag_urational tagNoiseReductionAppliedMainIFD (tcNoiseReductionApplied,
+ rawNoiseReductionApplied);
+
+ tag_urational tagNoiseReductionAppliedRawIFD (tcNoiseReductionApplied,
+ rawNoiseReductionApplied);
+
+ if (rawNoiseReductionApplied.IsValid ())
+ {
+
+ rawIFD.Add (&tagNoiseReductionAppliedRawIFD);
+
+ // Kludge: DNG spec says that the NoiseReductionApplied tag should be
+ // in the Raw IFD, not main IFD. However, we also write a copy of this tag to
+ // main IFD to deal with legacy DNG readers that try to read the tag
+ // from the main IFD.
+
+ if ((&rawIFD) != (&mainIFD))
+ {
+
+ mainIFD.Add (&tagNoiseReductionAppliedMainIFD);
+
+ }
+
+ }
+
+ dng_noise_profile rawNoiseProfile = hasEnhancedImage ? negative.RawNoiseProfile ()
+ : negative.NoiseProfile ();
+
+ tag_dng_noise_profile tagNoiseProfileMainIFD (rawNoiseProfile);
+ tag_dng_noise_profile tagNoiseProfileRawIFD (rawNoiseProfile);
+
+ if (rawNoiseProfile.IsValidForNegative (negative))
+ {
+
+ rawIFD.Add (&tagNoiseProfileRawIFD);
+
+ // Kludge: DNG spec says that NoiseProfile tag should be in the Raw
+ // IFD, not main IFD. However, we also write a copy of this tag to
+ // main IFD to deal with legacy DNG readers that try to read the tag
+ // from the main IFD.
+
+ if ((&rawIFD) != (&mainIFD))
+ {
- tag_urational tagNoiseReductionApplied (tcNoiseReductionApplied,
- negative.NoiseReductionApplied ());
-
- if (negative.NoiseReductionApplied ().IsValid ())
- {
-
- mainIFD.Add (&tagNoiseReductionApplied);
-
- }
-
- tag_dng_noise_profile tagNoiseProfile (negative.NoiseProfile ());
-
- if (negative.NoiseProfile ().IsValidForNegative (negative))
- {
-
- mainIFD.Add (&tagNoiseProfile);
-
+ mainIFD.Add (&tagNoiseProfileMainIFD);
+
+ }
+
}
tag_urational tagBaselineSharpness (tcBaselineSharpness,
- negative.BaselineSharpnessR ());
-
+ negative.RawBaselineSharpness ());
+
mainIFD.Add (&tagBaselineSharpness);
tag_string tagUniqueName (tcUniqueCameraModel,
negative.ModelName (),
true);
-
+
mainIFD.Add (&tagUniqueName);
-
+
tag_string tagLocalName (tcLocalizedCameraModel,
negative.LocalName (),
false);
-
+
if (negative.LocalName ().NotEmpty ())
{
-
+
mainIFD.Add (&tagLocalName);
-
+
}
-
+
tag_urational tagShadowScale (tcShadowScale,
negative.ShadowScaleR ());
-
+
mainIFD.Add (&tagShadowScale);
-
+
tag_uint16 tagColorimetricReference (tcColorimetricReference,
(uint16) negative.ColorimetricReference ());
-
+
if (negative.ColorimetricReference () != crSceneReferred)
{
-
+
mainIFD.Add (&tagColorimetricReference);
-
+
}
-
- negative.FindRawImageDigest (host);
-
- tag_uint8_ptr tagRawImageDigest (tcRawImageDigest,
- negative.RawImageDigest ().data,
- 16);
-
- if (negative.RawImageDigest ().IsValid ())
+
+ bool useNewDigest = (maxBackwardVersion >= dngVersion_1_4_0_0);
+
+ if (compression == ccLossyJPEG)
{
-
- mainIFD.Add (&tagRawImageDigest);
-
+
+ negative.FindRawJPEGImageDigest (host);
+
}
-
+
+ else
+ {
+
+ if (useNewDigest)
+ {
+ negative.FindNewRawImageDigest (host);
+ }
+ else
+ {
+ negative.FindRawImageDigest (host);
+ }
+
+ }
+
+ tag_uint8_ptr tagRawImageDigest (useNewDigest ? tcNewRawImageDigest : tcRawImageDigest,
+ compression == ccLossyJPEG ?
+ negative.RawJPEGImageDigest ().data :
+ (useNewDigest ? negative.NewRawImageDigest ().data
+ : negative.RawImageDigest ().data),
+ 16);
+
+ mainIFD.Add (&tagRawImageDigest);
+
negative.FindRawDataUniqueID (host);
+ // Make a local copy of the raw data unique ID.
+
+ const auto rawDataUniqueID = negative.RawDataUniqueID ();
+
tag_uint8_ptr tagRawDataUniqueID (tcRawDataUniqueID,
- negative.RawDataUniqueID ().data,
+ rawDataUniqueID.data,
16);
-
- if (negative.RawDataUniqueID ().IsValid ())
+
+ if (rawDataUniqueID.IsValid ())
{
-
+
mainIFD.Add (&tagRawDataUniqueID);
-
+
}
-
+
tag_string tagOriginalRawFileName (tcOriginalRawFileName,
negative.OriginalRawFileName (),
false);
-
+
if (negative.HasOriginalRawFileName ())
{
-
+
mainIFD.Add (&tagOriginalRawFileName);
-
+
}
-
+
negative.FindOriginalRawFileDigest ();
-
+
tag_data_ptr tagOriginalRawFileData (tcOriginalRawFileData,
ttUndefined,
negative.OriginalRawFileDataLength (),
negative.OriginalRawFileData ());
-
+
tag_uint8_ptr tagOriginalRawFileDigest (tcOriginalRawFileDigest,
negative.OriginalRawFileDigest ().data,
16);
-
+
if (negative.OriginalRawFileData ())
{
-
+
mainIFD.Add (&tagOriginalRawFileData);
-
+
mainIFD.Add (&tagOriginalRawFileDigest);
-
+
}
// XMP metadata.
-
- AutoPtr<dng_xmp> xmp;
-
- if (negative.GetXMP ())
- {
-
- xmp.Reset (new dng_xmp (*negative.GetXMP ()));
-
- // Make sure the XMP orientation always matches the
- // tag orientation.
-
- xmp->SetOrientation (negative.Orientation ());
-
- }
-
- tag_xmp tagXMP (xmp.Get ());
-
+
+ tag_xmp tagXMP (metadata->GetXMP ());
+
if (tagXMP.Count ())
{
-
+
mainIFD.Add (&tagXMP);
-
+
}
-
- xmp.Reset ();
-
+
// Exif tags.
-
+
exif_tag_set exifSet (mainIFD,
- *negative.GetExif (),
- negative.IsMakerNoteSafe (),
- negative.MakerNoteData (),
- negative.MakerNoteLength (),
+ *metadata->GetExif (),
+ metadata->IsMakerNoteSafe (),
+ metadata->MakerNoteData (),
+ metadata->MakerNoteLength (),
true);
-
+
// Private data.
-
+
tag_uint8_ptr tagPrivateData (tcDNGPrivateData,
negative.PrivateData (),
negative.PrivateLength ());
-
+
if (negative.PrivateLength ())
{
-
+
mainIFD.Add (&tagPrivateData);
-
- }
-
+
+ }
+
+ // Proxy size tags.
+
+ uint32 originalDefaultFinalSizeData [2];
+
+ originalDefaultFinalSizeData [0] = negative.OriginalDefaultFinalSize ().h;
+ originalDefaultFinalSizeData [1] = negative.OriginalDefaultFinalSize ().v;
+
+ tag_uint32_ptr tagOriginalDefaultFinalSize (tcOriginalDefaultFinalSize,
+ originalDefaultFinalSizeData,
+ 2);
+
+ if (saveOriginalDefaultFinalSize)
+ {
+
+ mainIFD.Add (&tagOriginalDefaultFinalSize);
+
+ }
+
+ uint32 originalBestQualityFinalSizeData [2];
+
+ originalBestQualityFinalSizeData [0] = negative.OriginalBestQualityFinalSize ().h;
+ originalBestQualityFinalSizeData [1] = negative.OriginalBestQualityFinalSize ().v;
+
+ tag_uint32_ptr tagOriginalBestQualityFinalSize (tcOriginalBestQualityFinalSize,
+ originalBestQualityFinalSizeData,
+ 2);
+
+ if (saveOriginalBestQualityFinalSize)
+ {
+
+ mainIFD.Add (&tagOriginalBestQualityFinalSize);
+
+ }
+
+ dng_urational originalDefaultCropSizeData [2];
+
+ originalDefaultCropSizeData [0] = negative.OriginalDefaultCropSizeH ();
+ originalDefaultCropSizeData [1] = negative.OriginalDefaultCropSizeV ();
+
+ tag_urational_ptr tagOriginalDefaultCropSize (tcOriginalDefaultCropSize,
+ originalDefaultCropSizeData,
+ 2);
+
+ if (saveOriginalDefaultCropSize)
+ {
+
+ mainIFD.Add (&tagOriginalDefaultCropSize);
+
+ }
+
// Opcode list 1.
-
+
AutoPtr<dng_memory_block> opcodeList1Data (negative.OpcodeList1 ().Spool (host));
-
+
tag_data_ptr tagOpcodeList1 (tcOpcodeList1,
ttUndefined,
opcodeList1Data.Get () ? opcodeList1Data->LogicalSize () : 0,
opcodeList1Data.Get () ? opcodeList1Data->Buffer () : NULL);
-
+
if (opcodeList1Data.Get ())
{
-
+
rawIFD.Add (&tagOpcodeList1);
-
+
}
-
+
// Opcode list 2.
-
+
AutoPtr<dng_memory_block> opcodeList2Data (negative.OpcodeList2 ().Spool (host));
-
+
tag_data_ptr tagOpcodeList2 (tcOpcodeList2,
ttUndefined,
opcodeList2Data.Get () ? opcodeList2Data->LogicalSize () : 0,
opcodeList2Data.Get () ? opcodeList2Data->Buffer () : NULL);
-
+
if (opcodeList2Data.Get ())
{
-
+
rawIFD.Add (&tagOpcodeList2);
-
+
}
-
+
// Opcode list 3.
-
+
AutoPtr<dng_memory_block> opcodeList3Data (negative.OpcodeList3 ().Spool (host));
-
+
tag_data_ptr tagOpcodeList3 (tcOpcodeList3,
ttUndefined,
opcodeList3Data.Get () ? opcodeList3Data->LogicalSize () : 0,
opcodeList3Data.Get () ? opcodeList3Data->Buffer () : NULL);
-
+
if (opcodeList3Data.Get ())
{
-
+
rawIFD.Add (&tagOpcodeList3);
-
- }
-
+
+ }
+
+ // Transparency mask, if any.
+
+ AutoPtr<dng_ifd> maskInfo;
+
+ AutoPtr<dng_tiff_directory> maskIFD;
+
+ AutoPtr<dng_basic_tag_set> maskBasic;
+
+ if (hasTransparencyMask)
+ {
+
+ // Create mask IFD.
+
+ maskInfo.Reset (new dng_ifd);
+
+ maskInfo->fNewSubFileType = sfTransparencyMask;
+
+ maskInfo->fImageWidth = negative.RawTransparencyMask ()->Bounds ().W ();
+ maskInfo->fImageLength = negative.RawTransparencyMask ()->Bounds ().H ();
+
+ maskInfo->fSamplesPerPixel = 1;
+
+ maskInfo->fBitsPerSample [0] = negative.RawTransparencyMaskBitDepth ();
+
+ maskInfo->fPhotometricInterpretation = piTransparencyMask;
+
+ maskInfo->fCompression = uncompressed ? ccUncompressed : ccDeflate;
+ maskInfo->fPredictor = uncompressed ? cpNullPredictor : cpHorizontalDifference;
+
+ if (negative.RawTransparencyMask ()->PixelType () == ttFloat)
+ {
+
+ maskInfo->fSampleFormat [0] = sfFloatingPoint;
+
+ if (maskInfo->fCompression == ccDeflate)
+ {
+ maskInfo->fPredictor = cpFloatingPoint;
+ }
+
+ }
+
+ if (maskInfo->fCompression == ccDeflate)
+ {
+ maskInfo->FindTileSize (512 * 1024);
+ }
+ else
+ {
+ maskInfo->SetSingleStrip ();
+ }
+
+ // Create mask tiff directory.
+
+ maskIFD.Reset (new dng_tiff_directory);
+
+ // Add mask basic tag set.
+
+ maskBasic.Reset (new dng_basic_tag_set (*maskIFD, *maskInfo));
+
+ }
+
+ AutoPtr<dng_ifd> depthInfo;
+
+ AutoPtr<dng_tiff_directory> depthIFD;
+
+ AutoPtr<dng_basic_tag_set> depthBasic;
+
+ tag_uint16 tagDepthFormat (tcDepthFormat,
+ (uint16) negative.DepthFormat ());
+
+ tag_urational tagDepthNear (tcDepthNear,
+ negative.DepthNear ());
+
+ tag_urational tagDepthFar (tcDepthFar,
+ negative.DepthFar ());
+
+ tag_uint16 tagDepthUnits (tcDepthUnits,
+ (uint16) negative.DepthUnits ());
+
+ tag_uint16 tagDepthMeasureType (tcDepthMeasureType,
+ (uint16) negative.DepthMeasureType ());
+
+ if (hasDepthMap)
+ {
+
+ // Create depth IFD.
+
+ depthInfo.Reset (new dng_ifd);
+
+ depthInfo->fNewSubFileType = sfDepthMap;
+
+ depthInfo->fImageWidth = negative.RawDepthMap ()->Bounds ().W ();
+ depthInfo->fImageLength = negative.RawDepthMap ()->Bounds ().H ();
+
+ depthInfo->fSamplesPerPixel = 1;
+
+ depthInfo->fBitsPerSample [0] = negative.RawDepthMap ()->PixelSize () * 8;
+
+ depthInfo->fPhotometricInterpretation = piDepth;
+
+ depthInfo->fCompression = uncompressed ? ccUncompressed : ccDeflate;
+ depthInfo->fPredictor = uncompressed ? cpNullPredictor : cpHorizontalDifference;
+
+ if (depthInfo->fCompression == ccDeflate)
+ {
+ depthInfo->FindTileSize (512 * 1024);
+ }
+ else
+ {
+ depthInfo->SetSingleStrip ();
+ }
+
+ // Create mask tiff directory.
+
+ depthIFD.Reset (new dng_tiff_directory);
+
+ // Add mask basic tag set.
+
+ depthBasic.Reset (new dng_basic_tag_set (*depthIFD, *depthInfo));
+
+ // Depth metadata.
+
+ mainIFD.Add (&tagDepthFormat);
+ mainIFD.Add (&tagDepthNear);
+ mainIFD.Add (&tagDepthFar);
+ mainIFD.Add (&tagDepthUnits);
+ mainIFD.Add (&tagDepthMeasureType);
+
+ }
+
+ // Enhanced stage 3 image.
+
+ AutoPtr<dng_ifd> enhancedInfo;
+
+ AutoPtr<dng_tiff_directory> enhancedIFD;
+
+ AutoPtr<dng_basic_tag_set> enhancedBasic;
+
+ tag_string enhanceParams (tcEnhanceParams,
+ negative.EnhanceParams (),
+ false);
+
+ tag_urational enhanceBaselineSharpness (tcBaselineSharpness,
+ negative.BaselineSharpnessR ());
+
+ tag_urational enhanceNoiseReductionApplied (tcNoiseReductionApplied,
+ negative.NoiseReductionApplied ());
+
+ tag_dng_noise_profile enhanceNoiseProfile (negative.NoiseProfile ());
+
+ uint16 enhanceBlackLevelData [kMaxColorPlanes];
+
+ tag_uint16_ptr enhanceBlackLevel (tcBlackLevel,
+ enhanceBlackLevelData);
+
+ if (hasEnhancedImage)
+ {
+
+ // Create enhanced IFD.
+
+ enhancedInfo.Reset (new dng_ifd);
+
+ enhancedInfo->fNewSubFileType = sfEnhancedImage;
+
+ enhancedInfo->fImageWidth = negative.Stage3Image ()->Bounds ().W ();
+ enhancedInfo->fImageLength = negative.Stage3Image ()->Bounds ().H ();
+
+ enhancedInfo->fSamplesPerPixel = negative.Stage3Image ()->Planes ();
+
+ for (uint32 plane = 0; plane < enhancedInfo->fSamplesPerPixel; plane++)
+ {
+
+ enhancedInfo->fBitsPerSample [plane] = negative.Stage3Image ()->PixelSize () * 8;
+
+ if (negative.Stage3Image ()->PixelType () == ttFloat)
+ {
+
+ enhancedInfo->fSampleFormat [plane] = sfFloatingPoint;
+
+ }
+
+ }
+
+ enhancedInfo->fPhotometricInterpretation = piLinearRaw;
+
+ if (uncompressed)
+ {
+
+ enhancedInfo->fCompression = ccUncompressed;
+
+ enhancedInfo->SetSingleStrip ();
+
+ }
+
+ else if (negative.Stage3Image ()->PixelType () == ttShort)
+ {
+
+ enhancedInfo->fCompression = ccJPEG;
+
+ enhancedInfo->FindTileSize (128 * 1024);
+
+ }
+
+ else
+ {
+
+ enhancedInfo->fCompression = ccDeflate;
+ enhancedInfo->fPredictor = cpFloatingPoint;
+
+ enhancedInfo->FindTileSize (512 * 1024);
+
+ }
+
+ // Create enhanced tiff directory.
+
+ enhancedIFD.Reset (new dng_tiff_directory);
+
+ // Add enhanced basic tag set.
+
+ enhancedBasic.Reset (new dng_basic_tag_set (*enhancedIFD, *enhancedInfo));
+
+ // Add EnhanceParams tag.
+
+ enhancedIFD->Add (&enhanceParams);
+
+ // Record the enhanced baseline sharpness tag, if different.
+
+ if (negative.RawBaselineSharpness () != negative.BaselineSharpnessR ())
+ {
+
+ enhancedIFD->Add (&enhanceBaselineSharpness);
+
+ }
+
+ // Record the enhanced noise reduction applied, if different.
+
+ if (negative.RawNoiseReductionApplied () != negative.NoiseReductionApplied ())
+ {
+
+ enhancedIFD->Add (&enhanceNoiseReductionApplied);
+
+ }
+
+ // Record the enhanced noise profile, if different.
+
+ if (negative.RawNoiseProfile () != negative.NoiseProfile ())
+ {
+
+ enhancedIFD->Add (&enhanceNoiseProfile);
+
+ }
+
+ // Record stage3 black level.
+
+ if (negative.Stage3BlackLevel ())
+ {
+
+ for (uint32 plane = 0; plane < enhancedInfo->fSamplesPerPixel; plane++)
+ {
+
+ enhanceBlackLevelData [plane] = negative.Stage3BlackLevel ();
+
+ }
+
+ enhanceBlackLevel.SetCount (enhancedInfo->fSamplesPerPixel);
+
+ enhancedIFD->Add (&enhanceBlackLevel);
+
+ }
+
+ }
+
// Add other subfiles.
-
- uint32 subFileCount = 1;
-
+
+ uint32 subFileCount = thumbnail ? 1 : 0;
+
+ if (hasTransparencyMask)
+ {
+ subFileCount++;
+ }
+
+ if (hasDepthMap)
+ {
+ subFileCount++;
+ }
+
+ if (hasEnhancedImage)
+ {
+ subFileCount++;
+ }
+
// Add previews.
-
+
uint32 previewCount = previewList ? previewList->Count () : 0;
-
+
AutoPtr<dng_tiff_directory> previewIFD [kMaxDNGPreviews];
-
+
AutoPtr<dng_basic_tag_set> previewBasic [kMaxDNGPreviews];
-
+
for (j = 0; j < previewCount; j++)
{
-
- previewIFD [j] . Reset (new dng_tiff_directory);
-
- previewBasic [j] . Reset (previewList->Preview (j).AddTagSet (*previewIFD [j]));
-
- subFileCount++;
-
+
+ if (thumbnail != &previewList->Preview (j))
+ {
+
+ previewIFD [j] . Reset (new dng_tiff_directory);
+
+ previewBasic [j] . Reset (previewList->Preview (j).AddTagSet (*previewIFD [j]));
+
+ subFileCount++;
+
+ }
+
}
-
+
// And a link to the raw and JPEG image IFDs.
-
- uint32 subFileData [kMaxDNGPreviews + 1];
-
+
+ uint32 subFileData [kMaxDNGPreviews + 2];
+
tag_uint32_ptr tagSubFile (tcSubIFDs,
subFileData,
subFileCount);
-
- mainIFD.Add (&tagSubFile);
-
+
+ if (subFileCount)
+ {
+
+ mainIFD.Add (&tagSubFile);
+
+ }
+
// Skip past the header and IFDs for now.
-
+
uint32 currentOffset = 8;
-
+
currentOffset += mainIFD.Size ();
-
- subFileData [0] = currentOffset;
-
- currentOffset += rawIFD.Size ();
+
+ uint32 subFileIndex = 0;
+
+ if (thumbnail)
+ {
+
+ subFileData [subFileIndex++] = currentOffset;
+
+ currentOffset += rawIFD.Size ();
+
+ }
+
+ if (hasTransparencyMask)
+ {
+
+ subFileData [subFileIndex++] = currentOffset;
+
+ currentOffset += maskIFD->Size ();
+
+ }
+
+ if (hasDepthMap)
+ {
+
+ subFileData [subFileIndex++] = currentOffset;
+
+ currentOffset += depthIFD->Size ();
+
+ }
+
+ if (hasEnhancedImage)
+ {
+
+ subFileData [subFileIndex++] = currentOffset;
+
+ currentOffset += enhancedIFD->Size ();
+
+ }
for (j = 0; j < previewCount; j++)
{
+
+ if (thumbnail != &previewList->Preview (j))
+ {
+
+ subFileData [subFileIndex++] = currentOffset;
- subFileData [j + 1] = currentOffset;
-
- currentOffset += previewIFD [j]->Size ();
-
+ currentOffset += previewIFD [j]->Size ();
+
+ }
+
}
-
+
exifSet.Locate (currentOffset);
-
+
currentOffset += exifSet.Size ();
-
+
stream.SetWritePosition (currentOffset);
-
+
// Write the extra profiles.
-
+
if (extraProfileCount)
{
-
+
for (j = 0; j < extraProfileCount; j++)
{
-
+
extraProfileOffsets.Buffer_uint32 () [j] = (uint32) stream.Position ();
-
+
uint32 index = extraProfileIndex [j];
-
+
const dng_camera_profile &profile (negative.ProfileByIndex (index));
-
+
tiff_dng_extended_color_profile extraWriter (profile);
-
+
extraWriter.Put (stream, false);
-
+
}
-
+
}
-
+
// Write the thumbnail data.
-
- thumbnail.WriteData (host,
- *this,
- *thmBasic,
- stream);
-
+
+ if (thumbnail)
+ {
+
+ thumbnail->WriteData (host,
+ *this,
+ *thmBasic,
+ stream);
+
+ }
+
// Write the preview data.
-
+
for (j = 0; j < previewCount; j++)
{
-
- previewList->Preview (j).WriteData (host,
- *this,
- *previewBasic [j],
- stream);
-
+
+ if (thumbnail != &previewList->Preview (j))
+ {
+
+ previewList->Preview (j).WriteData (host,
+ *this,
+ *previewBasic [j],
+ stream);
+
+ }
+
}
-
+
// Write the raw data.
+
+ if (rawJPEGImage)
+ {
+
+ uint32 tileCount = info.TilesAcross () *
+ info.TilesDown ();
+
+ for (uint32 tileIndex = 0; tileIndex < tileCount; tileIndex++)
+ {
+
+ // Remember this offset.
+
+ uint32 tileOffset = (uint32) stream.Position ();
+
+ rawBasic.SetTileOffset (tileIndex, tileOffset);
+
+ // Write JPEG data.
+
+ stream.Put (rawJPEGImage->fJPEGData [tileIndex]->Buffer (),
+ rawJPEGImage->fJPEGData [tileIndex]->LogicalSize ());
+
+ // Update tile count.
+
+ uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
+
+ rawBasic.SetTileByteCount (tileIndex, tileByteCount);
+
+ // Keep the tiles on even byte offsets.
+
+ if (tileByteCount & 1)
+ {
+ stream.Put_uint8 (0);
+ }
- WriteImage (host,
- info,
- rawBasic,
- stream,
- rawImage,
- fakeChannels);
-
+ }
+
+ }
+
+ else
+ {
+
+ #if qDNGValidate
+ dng_timer timer ("Write raw image time");
+ #endif
+
+ WriteImage (host,
+ info,
+ rawBasic,
+ stream,
+ rawImage,
+ fakeChannels);
+
+ }
+
+ // Write transparency mask image.
+
+ if (hasTransparencyMask)
+ {
+
+ #if qDNGValidate
+ dng_timer timer ("Write transparency mask time");
+ #endif
+
+ WriteImage (host,
+ *maskInfo,
+ *maskBasic,
+ stream,
+ *negative.RawTransparencyMask ());
+
+ }
+
+ // Write depth map image.
+
+ if (hasDepthMap)
+ {
+
+ #if qDNGValidate
+ dng_timer timer ("Write depth map time");
+ #endif
+
+ WriteImage (host,
+ *depthInfo,
+ *depthBasic,
+ stream,
+ *negative.RawDepthMap ());
+
+ }
+
+ if (hasEnhancedImage)
+ {
+
+ #if qDNGValidate
+ dng_timer timer ("Write enhanced image time");
+ #endif
+
+ WriteImage (host,
+ *enhancedInfo,
+ *enhancedBasic,
+ stream,
+ *negative.Stage3Image ());
+
+ }
+
// Trim the file to this length.
-
+
stream.SetLength (stream.Position ());
-
+
// DNG has a 4G size limit.
-
+
if (stream.Length () > 0x0FFFFFFFFL)
{
ThrowImageTooBigDNG ();
}
-
+
// Write TIFF Header.
-
+
stream.SetWritePosition (0);
-
+
stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
-
+
stream.Put_uint16 (42);
-
+
stream.Put_uint32 (8);
-
+
// Write the IFDs.
-
+
mainIFD.Put (stream);
-
- rawIFD.Put (stream);
-
+
+ if (thumbnail)
+ {
+
+ rawIFD.Put (stream);
+
+ }
+
+ if (hasTransparencyMask)
+ {
+
+ maskIFD->Put (stream);
+
+ }
+
+ if (hasDepthMap)
+ {
+
+ depthIFD->Put (stream);
+
+ }
+
+ if (hasEnhancedImage)
+ {
+
+ enhancedIFD->Put (stream);
+
+ }
+
for (j = 0; j < previewCount; j++)
{
-
- previewIFD [j]->Put (stream);
-
+
+ if (thumbnail != &previewList->Preview (j))
+ {
+
+ previewIFD [j]->Put (stream);
+
+ }
+
}
-
+
exifSet.Put (stream);
-
+
stream.Flush ();
-
+
}
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.h b/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.h
index 50b7c519aa..9eeaa59252 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_image_writer.h
@@ -1,1117 +1,1296 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_image_writer.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* Support for writing DNG images to files.
*/
/*****************************************************************************/
#ifndef __dng_image_writer__
#define __dng_image_writer__
/*****************************************************************************/
+#include "dng_area_task.h"
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_fingerprint.h"
#include "dng_memory.h"
+#include "dng_mutex.h"
#include "dng_point.h"
#include "dng_rational.h"
+#include "dng_safe_arithmetic.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_uncopyable.h"
+
+#include <atomic>
/*****************************************************************************/
+/// \brief Image resolution.
+
class dng_resolution
{
-
+
public:
-
+
dng_urational fXResolution;
dng_urational fYResolution;
-
+
uint16 fResolutionUnit;
-
+
public:
-
+
dng_resolution ();
-
+
};
/*****************************************************************************/
-class tiff_tag
+class tiff_tag: private dng_uncopyable
{
-
+
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
+class dng_tiff_directory: private dng_uncopyable
{
-
+
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
+class dng_basic_tag_set: private dng_uncopyable
{
-
+
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
+class exif_tag_set: private dng_uncopyable
{
-
+
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_uint16 fColorSpace;
+
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;
-
- int16 fTimeZoneOffsetData [2];
-
- tag_int16_ptr fTimeZoneOffset;
+
+ tag_string fOffsetTime;
+ tag_string fOffsetTimeOriginal;
+ tag_string fOffsetTimeDigitized;
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;
+
+ // EXIF 2.3.1 tags.
+
+ tag_srational fTemperature;
+ tag_urational fHumidity;
+ tag_urational fPressure;
+ tag_srational fWaterDepth;
+ tag_urational fAcceleration;
+ tag_srational fCameraElevationAngle;
+
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_AllExceptCameraRawInfo,
+ KMetadataSubset_AllExceptCameraRawInfoAndLocation,
+
+ kMetadataSubset_Last = KMetadataSubset_AllExceptCameraRawInfoAndLocation
+
};
/*****************************************************************************/
/// \brief Support for writing dng_image or dng_negative instances to a
/// dng_stream in TIFF or DNG format.
class dng_image_writer
{
-
+
+ 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
-
+
};
-
- AutoPtr<dng_memory_block> fCompressedBuffer;
-
- AutoPtr<dng_memory_block> fUncompressedBuffer;
-
- AutoPtr<dng_memory_block> fSubTileBlockBuffer;
-
+
public:
-
+
dng_image_writer ();
-
+
virtual ~dng_image_writer ();
+
+ 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 If non-NULL, EXIF, IPTC, and XMP metadata from this negative is written to TIFF.
+ /// \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.
-
- virtual void WriteTIFF (dng_host &host,
- dng_stream &stream,
- const dng_image &image,
- uint32 photometricInterpretation = piBlackIsZero,
- uint32 compression = ccUncompressed,
- dng_negative *negative = NULL,
- const dng_color_space *space = NULL,
- const dng_resolution *resolution = NULL,
- const dng_jpeg_preview *thumbnail = NULL,
- const dng_memory_block *imageResources = NULL);
-
+ /// \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,
+ bool hasTransparency = false);
+
+ 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,
+ bool hasTransparency = false);
+
/// 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 If non-NULL, EXIF, IPTC, and XMP metadata from this negative is written to TIFF.
+ /// \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,
+ bool hasTransparency = false);
+
virtual void WriteTIFFWithProfile (dng_host &host,
dng_stream &stream,
const dng_image &image,
uint32 photometricInterpretation = piBlackIsZero,
uint32 compression = ccUncompressed,
- dng_negative *negative = NULL,
+ 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);
-
+ const dng_memory_block *imageResources = NULL,
+ dng_metadata_subset metadataSubset = kMetadataSubset_All,
+ bool hasTransparency = 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 and metadata (EXIF, IPTC, XMP) to be written.
- /// \param thumbnail Thumbanil image. Must be provided.
- /// \param compression Either ccUncompressed or ccJPEG for lossless JPEG.
/// \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_image_preview &thumbnail,
- uint32 compression = ccJPEG,
- const dng_preview_list *previewList = NULL);
-
+ virtual void WriteDNGWithMetadata (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 *dstMIME,
+ const char *software = NULL);
+
protected:
+ virtual void UpdateExifColorSpaceTag (dng_metadata &metadata,
+ const void *profileData,
+ const uint32 profileSize);
+
virtual uint32 CompressedBufferSize (const dng_ifd &ifd,
uint32 uncompressedSize);
-
+
virtual void EncodePredictor (dng_host &host,
const dng_ifd &ifd,
- dng_pixel_buffer &buffer);
-
+ 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);
-
+ 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);
-
+ dng_pixel_buffer &buffer,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ bool usingMultipleThreads);
+
virtual void WriteTile (dng_host &host,
const dng_ifd &ifd,
dng_stream &stream,
const dng_image &image,
const dng_rect &tileArea,
- uint32 fakeChannels);
-
+ uint32 fakeChannels,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer,
+ bool usingMultipleThreads);
+
+ virtual void DoWriteTiles (dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels,
+ uint32 tilesDown,
+ uint32 tilesAcross,
+ uint32 compressedSize,
+ const dng_safe_uint32 &uncompressedSize);
+
};
/*****************************************************************************/
-#endif
+class dng_write_tiles_task : public dng_area_task,
+ private dng_uncopyable
+ {
+
+ protected:
+
+ dng_image_writer &fImageWriter;
+
+ dng_host &fHost;
+
+ const dng_ifd &fIFD;
+
+ dng_basic_tag_set &fBasic;
+
+ dng_stream &fStream;
+
+ const dng_image &fImage;
+
+ uint32 fFakeChannels;
+
+ uint32 fTilesDown;
+
+ uint32 fTilesAcross;
+
+ uint32 fCompressedSize;
+
+ uint32 fUncompressedSize;
+
+ std::atomic_uint fNextTileIndex;
+
+ dng_mutex fMutex;
+
+ dng_condition fCondition;
+
+ bool fTaskFailed;
+
+ uint32 fWriteTileIndex;
+
+ public:
+
+ dng_write_tiles_task (dng_image_writer &imageWriter,
+ dng_host &host,
+ const dng_ifd &ifd,
+ dng_basic_tag_set &basic,
+ dng_stream &stream,
+ const dng_image &image,
+ uint32 fakeChannels,
+ uint32 tilesDown,
+ uint32 tilesAcross,
+ uint32 compressedSize,
+ uint32 uncompressedSize);
+
+ void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer *sniffer);
+ protected:
+
+ void ProcessTask (uint32 tileIndex,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ AutoPtr<dng_memory_block> &tempBuffer,
+ uint32 &tileByteCount, // output
+ dng_memory_stream &tileStream, // output
+ dng_abort_sniffer *sniffer);
+
+ void WriteTask (uint32 tileIndex,
+ uint32 tileByteCount,
+ dng_memory_stream &tileStream,
+ dng_abort_sniffer *sniffer);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_info.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_info.cpp
index c446c01e20..68e6cc91dc 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_info.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_info.cpp
@@ -1,2386 +1,2742 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_info.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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)
- , fIFDCount (0)
- , fChainedIFDCount (0)
+ , fMaskIndex (-1)
+ , fDepthIndex (-1)
+ , fEnhancedIndex (-1)
+ , fIFD ()
+ , fChainedIFD ()
+ , fChainedSubIFD ()
, fMakerNoteNextIFD (0)
-
+
{
-
+
}
-
+
/*****************************************************************************/
dng_info::~dng_info ()
{
+ for (size_t index = 0; index < fIFD.size (); index++)
+ {
+
+ if (fIFD [index])
+ {
+ delete fIFD [index];
+ fIFD [index] = NULL;
+ }
+
+ }
+
+ for (size_t index2 = 0; index2 < fChainedIFD.size (); index2++)
+ {
+
+ if (fChainedIFD [index2])
+ {
+ delete fChainedIFD [index2];
+ fChainedIFD [index2] = NULL;
+ }
+
+ }
+
+ for (size_t index3 = 0; index3 < fChainedSubIFD.size (); index3++)
+ {
+
+ for (size_t index4 = 0; index4 < fChainedSubIFD [index3].size (); index4++)
+ {
+
+ if (fChainedSubIFD [index3] [index4])
+ {
+ delete fChainedSubIFD [index3] [index4];
+ fChainedSubIFD [index3] [index4] = NULL;
+ }
+
+ }
+
+ }
+
}
/*****************************************************************************/
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 ();
- break;
+
}
-
+
}
-
+
}
/*****************************************************************************/
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;
-
+ break;
+
case 8240:
olympusMakerParent = tcOlympusMakerNote8240;
- break;
-
+ break;
+
case 8256:
olympusMakerParent = tcOlympusMakerNote8256;
- break;
-
+ break;
+
case 8272:
olympusMakerParent = tcOlympusMakerNote8272;
- break;
-
+ 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);
-
+
+ // TIFF IFDs often read from two very different places in the file,
+ // one for the IFD itself (and small tags), and elsewhere in the file
+ // for large tags. We can reduce the number of calls to the OS
+ // by double buffering reads for the two areas of the file.
+
+ dng_stream_double_buffered ifdStream (stream);
+
+ ifdStream.SetReadPosition (ifdOffset);
+
if (ifd)
{
ifd->fThisIFD = ifdOffset;
}
-
- uint32 ifdEntries = stream.Get_uint16 ();
-
+
+ uint32 ifdEntries = ifdStream.Get_uint16 ();
+
#if qDNGValidate
-
+
+ // IC hits these warnings on JPG
+ bool generateOddOffsetWarnings = true;
+ if (gImagecore)
+ generateOddOffsetWarnings = false;
+
if (gVerbose)
{
-
+
printf ("%s: Offset = %u, Entries = %u\n\n",
LookupParentCode (parentCode),
- (unsigned) ifdOffset,
+ (unsigned) ifdOffset,
(unsigned) ifdEntries);
-
+
}
-
- if ((ifdOffset & 1) && !isMakerNote)
+
+ if (generateOddOffsetWarnings && (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 ();
-
+
+ ifdStream.SetReadPosition (ifdOffset + 2 + tag_index * 12);
+
+ uint32 tagCode = ifdStream.Get_uint16 ();
+ uint32 tagType = ifdStream.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 ();
-
+
+ uint32 tagCount = ifdStream.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;
-
+
}
-
+
+ bool localTag = true;
+
uint64 tagOffset = ifdOffset + 2 + tag_index * 12 + 8;
-
+
if (tagCount * tag_type_size > 4)
{
-
- tagOffset = stream.Get_uint32 ();
-
+
+ tagOffset = ifdStream.Get_uint32 ();
+
#if qDNGValidate
-
+
{
-
- if (!(ifdOffset & 1) &&
+
+ if (generateOddOffsetWarnings &&
+ !(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);
-
+
+ localTag = ifdStream.DataInBuffer (tagCount * tag_type_size,
+ tagOffset);
+
+ if (localTag)
+ ifdStream.SetReadPosition (tagOffset);
+ else
+ stream.SetReadPosition (tagOffset);
+
}
-
+
ParseTag (host,
- stream,
+ localTag ? ifdStream : stream,
exif,
shared,
ifd,
parentCode,
tagCode,
tagType,
tagCount,
tagOffset,
offsetDelta);
-
+
}
-
- stream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
-
- uint32 nextIFD = stream.Get_uint32 ();
-
+
+ ifdStream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
+
+ uint32 nextIFD = ifdStream.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");
}
+
+ stream.SetReadPosition (ifdStream.Position ());
#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 ();
+
+ dng_stream_double_buffered ifdStream (stream);
+
+ ifdStream.SetReadPosition (ifdOffset);
+
+ uint32 ifdEntries = ifdStream.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 ();
-
+
+ ifdStream.SetReadPosition (ifdOffset + 2 + tagIndex * 12 + 2);
+
+ tagType = ifdStream.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) 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 ();
-
+
+ ifdStream.SetReadPosition (ifdOffset + 2 + tagIndex * 12);
+
+ tagCode = ifdStream.Get_uint16 ();
+ tagType = ifdStream.Get_uint16 ();
+ tagCount = ifdStream.Get_uint32 ();
+
if (tagType == 0)
{
continue;
}
-
+
uint32 tagSize = tagCount * TagTypeSize (tagType);
-
+
uint64 tagOffset = ifdOffset + 2 + tagIndex * 12 + 8;
-
+
+ bool localTag = true;
+
if (tagSize > 4)
{
-
- tagOffset = stream.Get_uint32 () + offsetDelta;
-
+
+ tagOffset = ifdStream.Get_uint32 () + offsetDelta;
+
if (tagOffset < minOffset ||
tagOffset + tagSize > maxOffset)
{
-
+
// Tag data is outside the valid offset range,
// so ignore this tag.
-
+
continue;
-
+
}
-
+
+ localTag = ifdStream.DataInBuffer (tagSize, tagOffset);
+
+ ifdStream.SetReadPosition (tagOffset);
+
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;
-
+ break;
+
case 8240:
olympusMakerParent = tcOlympusMakerNote8240;
- break;
-
+ break;
+
case 8256:
olympusMakerParent = tcOlympusMakerNote8256;
- break;
-
+ break;
+
case 8272:
olympusMakerParent = tcOlympusMakerNote8272;
- break;
-
+ 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,
+ localTag ? ifdStream : 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 ();
-
+
+ ifdStream.SetReadPosition (ifdOffset + 2 + ifdEntries * 12);
+
+ fMakerNoteNextIFD = ifdStream.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.
-
- if (memcmp (firstBytes, "LEICA\000\000\000", 8) == 0)
+
+ // 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\004\000", 8) == 0) ||
+ (memcmp (firstBytes, "LEICA\000\005\000", 8) == 0) ||
+ (memcmp (firstBytes, "LEICA\000\006\000", 8) == 0))
{
if (makerNoteCount > 8)
{
-
+
ParseMakerNoteIFD (host,
stream,
makerNoteCount - 8,
makerNoteOffset + 8,
makerNoteOffset,
minOffset,
maxOffset,
tcLeicaMakerNote);
-
+
}
-
+
return;
}
- // Nikon version 2 MakerNote with header.
+ // 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) ||
+ (memcmp (firstBytes, "LEICA\000\002\000", 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.
-
+
+ // Pentax MakerNote, absolute addresses.
+
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;
-
+
}
+ // Pentax MakerNote, relative addresses.
+
+ if (memcmp (firstBytes, "PENTAX", 6) == 0)
+ {
+
+ if (makerNoteCount > 8)
+ {
+
+ stream.SetReadPosition (makerNoteOffset + 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,
+ makerNoteCount - 10,
+ makerNoteOffset + 10,
+ makerNoteOffset, // Relative to start of MakerNote.
+ 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 */,
- uint32 /* count */,
+ 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
+
+ // 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);
-
+
}
-
+
// 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 ()
+
+ 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 ());
-
+
+ fIFD.push_back (host.Make_dng_ifd ());
+
ParseIFD (host,
stream,
fExif.Get (),
fShared.Get (),
- fIFD [0].Get (),
+ fIFD [0],
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 (ChainedIFDCount () == kMaxChainedIFDs)
{
-
+
#if qDNGValidate
-
+
{
-
+
ReportWarning ("Chained IFD count exceeds DNG SDK parsing limit");
}
-
+
#endif
-
+
break;
-
+
}
-
- fChainedIFD [fChainedIFDCount].Reset (host.Make_dng_ifd ());
-
+
+ fChainedIFD.push_back (host.Make_dng_ifd ());
+
+ fChainedSubIFD.push_back (std::vector <dng_ifd *> ());
+
ParseIFD (host,
stream,
NULL,
NULL,
- fChainedIFD [fChainedIFDCount].Get (),
+ fChainedIFD [ChainedIFDCount () - 1],
fTIFFBlockOffset + next_offset,
fTIFFBlockOffset,
- tcFirstChainedIFD + fChainedIFDCount);
-
- next_offset = fChainedIFD [fChainedIFDCount]->fNextIFD;
-
- fChainedIFDCount++;
-
+ tcFirstChainedIFD + ChainedIFDCount () - 1);
+
+ next_offset = fChainedIFD [ChainedIFDCount () - 1]->fNextIFD;
+
}
-
+
// Parse SubIFDs.
-
+
uint32 searchedIFDs = 0;
-
+
bool tooManySubIFDs = false;
-
- while (searchedIFDs < fIFDCount && !tooManySubIFDs)
+
+ while (searchedIFDs < IFDCount () && !tooManySubIFDs)
{
-
- uint32 searchLimit = fIFDCount;
-
+
+ uint32 searchLimit = IFDCount ();
+
for (uint32 searchIndex = searchedIFDs;
searchIndex < searchLimit && !tooManySubIFDs;
searchIndex++)
{
-
+
for (uint32 subIndex = 0;
subIndex < fIFD [searchIndex]->fSubIFDsCount;
subIndex++)
{
-
- if (fIFDCount == kMaxSubIFDs + 1)
+
+ if (IFDCount () == 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 ());
-
+
+ fIFD.push_back (host.Make_dng_ifd ());
+
ParseIFD (host,
stream,
fExif.Get (),
fShared.Get (),
- fIFD [fIFDCount].Get (),
+ fIFD [IFDCount () - 1],
fTIFFBlockOffset + sub_ifd_offset,
fTIFFBlockOffset,
- tcFirstSubIFD + fIFDCount - 1);
-
- fIFDCount++;
-
+ tcFirstSubIFD + IFDCount () - 2);
+
}
-
+
searchedIFDs = searchLimit;
-
+
}
-
+
}
-
+
#if qDNGValidate
{
-
+
if (tooManySubIFDs)
{
-
+
ReportWarning ("SubIFD count exceeds DNG SDK parsing limit");
}
-
+
}
-
+
#endif
+ // Parse SubIFDs in Chained IFDs. Don't currently need to make this a
+ // recursive search.
+
+ for (uint32 chainedIndex = 0;
+ chainedIndex < ChainedIFDCount ();
+ chainedIndex++)
+ {
+
+ for (uint32 subIndex = 0;
+ subIndex < fChainedIFD [chainedIndex]->fSubIFDsCount;
+ subIndex++)
+ {
+
+ if (subIndex == kMaxSubIFDs)
+ {
+
+ #if qDNGValidate
+
+ ReportWarning ("Chained SubIFD count exceeds DNG SDK parsing limit");
+
+ #endif
+
+ break;
+
+ }
+
+ stream.SetReadPosition (fChainedIFD [chainedIndex]->fSubIFDsOffset +
+ subIndex * 4);
+
+ uint32 sub_ifd_offset = stream.Get_uint32 ();
+
+ fChainedSubIFD [chainedIndex].push_back (host.Make_dng_ifd ());
+
+ ParseIFD (host,
+ stream,
+ fExif.Get (),
+ fShared.Get (),
+ fChainedSubIFD [chainedIndex] [subIndex],
+ fTIFFBlockOffset + sub_ifd_offset,
+ fTIFFBlockOffset,
+ tcFirstSubIFD + subIndex);
+
+ }
+
+ }
+
// 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++)
+
+ for (index = 0; index < IFDCount (); index++)
{
-
+
fIFD [index]->PostParse ();
-
+
}
-
- for (index = 0; index < fChainedIFDCount; index++)
+
+ for (index = 0; index < ChainedIFDCount (); index++)
{
-
+
fChainedIFD [index]->PostParse ();
-
+
}
+
+ for (size_t i = 0; i < fChainedSubIFD.size (); i++)
+ {
+
+ std::vector <dng_ifd *> &chain = fChainedSubIFD [i];
+ for (size_t j = 0; j < chain.size (); j++)
+ {
+
+ if (chain [j])
+ {
+ chain [j]->PostParse ();
+ }
+
+ }
+
+ }
+
if (fShared->fDNGVersion != 0)
{
-
+
// Find main IFD.
-
+
fMainIndex = -1;
-
- for (index = 0; index < fIFDCount; index++)
+
+ for (index = 0; index < IFDCount (); 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 < IFDCount (); index++)
+ {
+
+ if (fIFD [index]->fNewSubFileType == sfTransparencyMask)
+ {
+
+ if (fMaskIndex == -1)
+ {
+
+ fMaskIndex = index;
+
+ }
+
+ #if qDNGValidate
+
+ else
+ {
+ ReportError ("Multiple IFDs marked as transparency mask image");
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+ // Find depth index.
+
+ for (index = 0; index < IFDCount (); index++)
+ {
+
+ if (fIFD [index]->fNewSubFileType == sfDepthMap)
+ {
+
+ if (fDepthIndex == -1)
+ {
+
+ fDepthIndex = index;
+
+ }
+
+ #if qDNGValidate
+
+ else
+ {
+
+ ReportError ("Multiple IFDs marked as depth map image");
+
+ }
+
+ #endif
+
+ }
+
+ }
+
+ // Find enhanced ifd index.
+
+ for (index = 0; index < IFDCount (); index++)
+ {
+
+ if (fIFD [index]->fNewSubFileType == sfEnhancedImage)
+ {
+
+ if (fEnhancedIndex == -1)
+ {
+
+ fEnhancedIndex = index;
+
+ }
+
+ #if qDNGValidate
+
+ else
+ {
+
+ ReportError ("Multiple IFDs marked as enhanced image");
+
+ }
+
+ #endif
+
+ }
+
+ }
+
// Warn about Chained IFDs.
-
+
#if qDNGValidate
-
- if (fChainedIFDCount > 0)
+
+ if (ChainedIFDCount () > 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++)
+
+ for (uint32 index = 0; index < IFDCount (); index++)
{
-
+
uint32 parentCode = (index == 0 ? 0 : tcFirstSubIFD + index - 1);
-
+
if (!fIFD [index]->IsValidDNG (*fShared.Get (),
parentCode))
{
-
- // Only errors in the main IFD are fatal to parsing.
-
- if (index == (uint32) fMainIndex)
+
+ // Only errors in the main and transparency mask IFDs are fatal to parsing.
+
+ if (index == (uint32) fMainIndex ||
+ index == (uint32) fMaskIndex)
{
-
+
return false;
-
+
}
-
+
+ // Also errors to depth map...
+
+ if (index == (uint32) fDepthIndex)
+ {
+
+ return false;
+
+ }
+
}
-
+
}
-
+
return true;
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_info.h b/core/libs/dngwriter/extra/dng_sdk/dng_info.h
index 214c46ecd3..f2f596eb6e 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_info.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_info.h
@@ -1,161 +1,179 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_info.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* Class for holding top-level information about a DNG image.
*/
/*****************************************************************************/
#ifndef __dng_info__
#define __dng_info__
/*****************************************************************************/
+#include "dng_auto_ptr.h"
#include "dng_classes.h"
-#include "dng_ifd.h"
-#include "dng_exif.h"
-#include "dng_shared.h"
#include "dng_errors.h"
+#include "dng_exif.h"
+#include "dng_ifd.h"
#include "dng_sdk_limits.h"
-#include "dng_auto_ptr.h"
+#include "dng_shared.h"
+#include "dng_uncopyable.h"
+
+#include <vector>
/*****************************************************************************/
/// \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
+class dng_info: private dng_uncopyable
{
-
+
public:
-
+
uint64 fTIFFBlockOffset;
-
+
uint64 fTIFFBlockOriginalOffset;
-
+
bool fBigEndian;
-
+
uint32 fMagic;
-
+
AutoPtr<dng_exif> fExif;
-
+
AutoPtr<dng_shared> fShared;
-
+
int32 fMainIndex;
+
+ int32 fMaskIndex;
+
+ int32 fDepthIndex;
+
+ int32 fEnhancedIndex;
+
+ std::vector <dng_ifd *> fIFD;
- uint32 fIFDCount;
+ std::vector <dng_ifd *> fChainedIFD;
- AutoPtr<dng_ifd> fIFD [kMaxSubIFDs + 1];
+ std::vector <std::vector <dng_ifd *> > fChainedSubIFD;
- uint32 fChainedIFDCount;
+ protected:
+
+ uint32 fMakerNoteNextIFD;
+
+ public:
+
+ dng_info ();
+
+ virtual ~dng_info ();
- AutoPtr<dng_ifd> fChainedIFD [kMaxChainedIFDs];
+ /// Returns the number of parsed SubIFDs (including the main IFD).
- protected:
+ uint32 IFDCount () const
+ {
+ return (uint32) fIFD.size ();
+ }
- uint32 fMakerNoteNextIFD;
+ /// Returns the number of chained IFDs.
- public:
+ uint32 ChainedIFDCount () const
+ {
+ return (uint32) fChainedIFD.size ();
+ }
- dng_info ();
+ /// Returns number SubIFDs for a chained IFD.
- virtual ~dng_info ();
+ uint32 ChainedSubIFDCount (uint32 chainIndex) const
+ {
+ if (chainIndex >= fChainedSubIFD.size ())
+ return 0;
+ else
+ return (uint32) fChainedSubIFD [chainIndex].size ();
+ }
/// 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,
- uint32 count,
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_iptc.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_iptc.cpp
index 4da851e8e3..7f982fb115 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_iptc.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_iptc.cpp
@@ -1,986 +1,978 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_iptc.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
/*****************************************************************************/
dng_iptc::dng_iptc ()
- : fForceUTF8 (false)
-
- , fTitle ()
+ : fTitle ()
, fUrgency (-1)
, fCategory ()
-
+
, fSupplementalCategories ()
-
+
, fKeywords ()
-
+
, fInstructions ()
-
+
, fDateTimeCreated ()
-
- , fAuthor ()
+
+ , 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 (fAuthor .NotEmpty () ||
+
+ 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);
- break;
- }
-
+ {
+ 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;
-
- uint64 nextOffset = stream.Position ();
-
+
+ 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;
-
- fForceUTF8 = true;
-
+
}
-
+
}
-
+
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 == 11)
+
+ if (length >= 4 && length <= 11)
{
-
+
char time [12];
-
- stream.Get (time, 11);
-
- time [11] = 0;
-
+
+ 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:
{
- ParseString (stream, fAuthor, charSet);
+
+ 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);
-
- }
-
- }
-
-/*****************************************************************************/
-
-bool dng_iptc::SafeForSystemEncoding (const dng_string &s)
- {
-
- return s.ValidSystemEncoding ();
-
- }
-
-/*****************************************************************************/
-
-bool dng_iptc::SafeForSystemEncoding (const dng_string_list &list)
- {
-
- for (uint32 j = 0; j < list.Count (); j++)
- {
-
- if (!SafeForSystemEncoding (list [j]))
- {
-
- return false;
-
- }
-
- }
-
- return true;
-
- }
-
-/*****************************************************************************/
-
-bool dng_iptc::SafeForSystemEncoding () const
- {
-
- if (!SafeForSystemEncoding (fTitle))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fCategory))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fSupplementalCategories))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fKeywords))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fInstructions))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fAuthor))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fAuthorsPosition))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fCity))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fState))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fCountry))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fCountryCode))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fLocation))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fTransmissionReference))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fHeadline))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fCredit))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fSource))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fCopyrightNotice))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fDescription))
- {
- return false;
- }
-
- if (!SafeForSystemEncoding (fDescriptionWriter))
- {
- return false;
+
}
-
- return true;
-
+
}
-
/*****************************************************************************/
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 ();
-
- // Figure out character set to use. Due to bugs in Photoshop CS2 and
- // before, we only write UTF-8 in cases where it is required to preserve
- // all the characters. It is not ideal since it makes the files not
- // portable across systems with different encodings. Perhaps we can
- // switch to using UTF-8 in all cases in the CS4 timeframe.
-
- CharSet charSet = SafeForSystemEncoding () ? kCharSetUnknown
- : kCharSetUTF8;
-
- // Override to force UTF8
-
- if (fForceUTF8)
- {
- charSet = kCharSetUTF8;
- }
+
+ // 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 (2);
-
+ stream.Put_uint16 (4);
+
SpoolString (stream,
fTitle,
kObjectNameSet,
64,
charSet);
-
+
if (fUrgency >= 0)
{
-
- sprintf (s, "%1u", fUrgency);
-
+
+ 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 ())
{
-
- DNG_ASSERT (timeString.Length () == 11, "Wrong length IPTC time");
-
+
stream.Put_uint16 (0x1C02);
stream.Put_uint8 (kTimeCreatedSet);
-
- stream.Put_uint16 (11);
-
- stream.Put (timeString.Get (), 11);
-
+
+ stream.Put_uint16 ((uint16)timeString.Length ());
+
+ stream.Put (timeString.Get (), timeString.Length ());
+
}
-
+
}
- SpoolString (stream,
- fAuthor,
- kBylineSet,
- 32,
- charSet);
+ 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);
-
- if (fCountryCode.Length () == 3)
- {
-
- SpoolString (stream,
- fCountryCode,
- kCountryCodeSet,
- 3,
- 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/core/libs/dngwriter/extra/dng_sdk/dng_iptc.h b/core/libs/dngwriter/extra/dng_sdk/dng_iptc.h
index 674b0b9405..70d5e4eec7 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_iptc.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_iptc.h
@@ -1,175 +1,167 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_iptc.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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:
-
- bool fForceUTF8;
-
+
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_string fAuthor;
+
+ 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
+ /// \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);
-
- static bool SafeForSystemEncoding (const dng_string &s);
-
- static bool SafeForSystemEncoding (const dng_string_list &list);
-
- bool SafeForSystemEncoding () const;
-
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_jpeg_image.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_jpeg_image.cpp
new file mode 100644
index 0000000000..94284974cf
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_jpeg_image.cpp
@@ -0,0 +1,354 @@
+/*****************************************************************************/
+// Copyright 2011-2019 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 "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_safe_arithmetic.h"
+#include "dng_uncopyable.h"
+
+#include <atomic>
+
+/*****************************************************************************/
+
+dng_jpeg_image::dng_jpeg_image ()
+
+ : fImageSize ()
+ , fTileSize ()
+ , fUsesStrips (false)
+ , fJPEGTables ()
+ , fJPEGData ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+class dng_jpeg_image_encode_task : public dng_area_task,
+ private dng_uncopyable
+ {
+
+ private:
+
+ dng_host &fHost;
+
+ dng_image_writer &fWriter;
+
+ const dng_image &fImage;
+
+ dng_jpeg_image &fJPEGImage;
+
+ uint32 fTileCount;
+
+ const dng_ifd &fIFD;
+
+ std::atomic_uint 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)
+
+ : dng_area_task ("dng_jpeg_image_encode_task")
+
+ , fHost (host)
+ , fWriter (writer)
+ , fImage (image)
+ , fJPEGImage (jpegImage)
+ , fTileCount (tileCount)
+ , fIFD (ifd)
+ , 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 = SafeUint32Mult (fIFD.fTileLength,
+ fIFD.fTileWidth,
+ fIFD.fSamplesPerPixel);
+
+ uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize));
+
+ uint32 tilesAcross = fIFD.TilesAcross ();
+
+ while (true)
+ {
+
+ // Note: fNextTileIndex is atomic
+
+ uint32 tileIndex = fNextTileIndex++;
+
+ if (tileIndex >= fTileCount)
+ {
+ return;
+ }
+
+ 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,
+ true);
+
+ fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ()));
+
+ }
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+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, if we are targeting a
+ // "large" size proxy (larger than 5 MP), 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 dng_uncopyable
+ {
+
+ private:
+
+ const dng_jpeg_image &fJPEGImage;
+
+ uint32 fTileCount;
+
+ dng_fingerprint *fDigests;
+
+ std::atomic_uint fNextTileIndex;
+
+ public:
+
+ dng_jpeg_image_find_digest_task (const dng_jpeg_image &jpegImage,
+ uint32 tileCount,
+ dng_fingerprint *digests)
+
+ : dng_area_task ("dng_jpeg_image_find_digest_task")
+
+ , fJPEGImage (jpegImage)
+ , fTileCount (tileCount)
+ , fDigests (digests)
+ , 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)
+ {
+
+ // Note: fNextTileIndex is atomic
+
+ uint32 tileIndex = fNextTileIndex++;
+
+ if (tileIndex >= fTileCount)
+ {
+ return;
+ }
+
+ dng_abort_sniffer::SniffForAbort (sniffer);
+
+ dng_md5_printer printer;
+
+ printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer (),
+ fJPEGImage.fJPEGData [tileIndex]->LogicalSize ());
+
+ fDigests [tileIndex] = printer.Result ();
+
+ }
+
+ }
+
+ };
+
+/*****************************************************************************/
+
+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/core/libs/dngwriter/extra/dng_sdk/dng_jpeg_image.h b/core/libs/dngwriter/extra/dng_sdk/dng_jpeg_image.h
new file mode 100644
index 0000000000..c9c2ca3d8d
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_jpeg_image.h
@@ -0,0 +1,85 @@
+/*****************************************************************************/
+// Copyright 2011-2019 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 __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/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.cpp
index 900cb86e4f..79ca79ee44 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.cpp
@@ -1,2368 +1,2509 @@
/*****************************************************************************/
-// Copyright 2008 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_lens_correction.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_safe_arithmetic.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,
+ 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,
+ 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 () &&
+ 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 ||
+ 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++)
+
+ for (uint32 iteration = 0; iteration < kMaxIterations; iteration++)
{
-
+
if (Abs_real64 (y1 - y0) < kNearZero)
{
break;
}
-
- const real64 x2 = Pin_real64 (0.0,
+
+ 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,
+ : 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];
}
+ fPlanes = totalPlanes;
+
}
/*****************************************************************************/
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.
+
+ // 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
+ 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],
+
+ 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;
+
+ }
+
+/*****************************************************************************/
+real64 dng_warp_params_rectilinear::SafeMinRatio () const
+ {
+
+ return 0.5;
+
}
/*****************************************************************************/
-void dng_warp_params_rectilinear::Dump () const
+real64 dng_warp_params_rectilinear::SafeMaxRatio () const
{
+
+ return 2.0;
+
+ }
+
+/*****************************************************************************/
+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];
}
+ fPlanes = totalPlanes;
+
}
/*****************************************************************************/
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);
}
+
+/*****************************************************************************/
+
+real64 dng_warp_params_fisheye::SafeMinRatio () const
+ {
+
+ return 0.2;
+
+ }
/*****************************************************************************/
-void dng_warp_params_fisheye::Dump () const
+real64 dng_warp_params_fisheye::SafeMaxRatio () const
{
+
+ return 5.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,
+ : dng_filter_task ("dng_filter_warp",
+ 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 +
+ 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 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);
+ dng_rect srcArea (yMin,
+ xMin,
+ yMax,
+ xMax);
- return srcArea;
+ // Limit to src image area.
+
+ srcArea = srcArea & fSrcImage.Bounds ();
+ 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);
+ DNG_REQUIRE (srcTileSize.v > 0, "Bad srcTileSize.v in dng_filter_warp::SrcTileSize");
+ DNG_REQUIRE (srcTileSize.h > 0, "Bad srcTileSize.h in dng_filter_warp::SrcTileSize");
+
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 hMax = SafeInt32Sub (SafeInt32Sub (srcArea.r, wCount), 1);
const int32 vMin = srcArea.t;
- const int32 vMax = srcArea.b - wCount - 1;
+ const int32 vMax = SafeInt32Sub (SafeInt32Sub (srcArea.b, wCount), 1);
+
+ if (hMax < hMin ||
+ vMax < vMin)
+ {
+
+ ThrowBadFormat ("Empty source area in dng_filter_warp.");
+
+ }
// Warp each plane.
+ const dng_rect_real64 srcImageArea (fSrcImage.Bounds ());
+
for (uint32 plane = 0; plane < dstBuffer.fPlanes; plane++)
{
-
- uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstArea.t,
- dstArea.l,
+
+ 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);
+ dng_point_real64 sPos = GetSrcPixelPosition (dPos,
+ plane);
+
+ // Limit to source image area.
+
+ sPos.h = Max_real64 (sPos.h, srcImageArea.l);
+ sPos.h = Min_real64 (sPos.h, srcImageArea.r - 1.0);
+ sPos.v = Max_real64 (sPos.v, srcImageArea.t);
+ sPos.v = Min_real64 (sPos.v, srcImageArea.b - 1.0);
// 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 int16 *w = fWeights.Weights16 (sFct);
+ const real32 *w = fWeights.Weights32 (sFct);
- const uint16 *s = srcBuffer.ConstPixel_uint16 (sInt.v,
+ const real32 *s = srcBuffer.ConstPixel_real32 (sInt.v,
sInt.h,
plane);
- int32 total = 8192;
+ real32 total = 0.0f;
for (int32 i = 0; i < wCount; i++)
{
-
+
for (int32 j = 0; j < wCount; j++)
{
-
- total += w [j] * (int32) s [j];
-
+
+ total += w [j] * s [j];
+
}
w += wCount;
s += srcRowStep;
-
+
}
// Store final pixel value.
- dPtr [dstIndex] = Pin_uint16 (total >> 14);
-
+ 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 ());
+
+ }
+/*****************************************************************************/
+
+bool dng_opcode_WarpRectilinear::HasDistort () const
+ {
+
+ for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
+ {
+
+ if (fWarpParams.IsNOP (plane))
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
}
/*****************************************************************************/
-uint32 dng_opcode_WarpRectilinear::ParamBytes (uint32 planes)
+bool dng_opcode_WarpRectilinear::HasLateralCA () const
{
+
+ if (fWarpParams.fPlanes <= 1)
+ {
+ return false;
+ }
+
+ for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
+ {
+
+ if (!fWarpParams.IsNOP (plane))
+ {
+ return true;
+ }
+
+ }
- return (1 * sizeof (uint32) ) + // Number of planes.
- (6 * sizeof (real64) * planes) + // Warp coefficients.
- (2 * sizeof (real64) ); // Optical center.
+ return false;
+
+ }
+/*****************************************************************************/
+
+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 * sizeof (uint32) ) + // Number of planes.
- (4 * sizeof (real64) * planes) + // Warp coefficients.
- (2 * sizeof (real64) ); // Optical center.
-
+
+ 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,
+dng_vignette_radial_params::dng_vignette_radial_params (const dng_std_vector<real64> &params,
const dng_point_real64 &center)
: fParams (params)
, fCenter (center)
{
+
+ }
+/*****************************************************************************/
+
+dng_vignette_radial_params::dng_vignette_radial_params
+ (const dng_vignette_radial_params &params)
+ {
+
+ fParams = params.fParams;
+
+ fCenter = params.fCenter;
+
}
/*****************************************************************************/
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 ||
+ 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;
+ const dng_std_vector<real64> &v = fParams.fParams;
- for (std::vector<real64>::const_reverse_iterator i = v.rbegin (); i != v.rend (); i++)
+ for (dng_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);
+ fParams.fParams = dng_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 signed 16-bit images.
-
- if (bufferPixelType != ttSShort)
+ // This opcode is restricted to 32-bit images.
+
+ if (bufferPixelType != ttFloat)
{
ThrowBadFormat ();
}
// Sanity check number of planes.
- DNG_ASSERT (imagePlanes >= 1 && imagePlanes <= kMaxColorPlanes,
+ DNG_ASSERT (imagePlanes >= 1 && imagePlanes <= kMaxColorPlanes,
"Bad number of planes.");
if (imagePlanes < 1 || imagePlanes > kMaxColorPlanes)
{
ThrowProgramError ();
}
-
+
fImagePlanes = imagePlanes;
- // Set the vignette correction curve.
+ // Get the vignette radial params.
- const dng_vignette_radial_function curve (fParams);
+ dng_vignette_radial_params params = MakeParamsForRender (negative);
// 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),
+ params.fCenter.v),
Lerp_real64 (bounds.l,
bounds.r,
- fParams.fCenter.h));
+ params.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 * 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++)
+
+ if (!fGainTable.Get ())
{
- real32 x = index * scale0;
-
- real32 y = table32.Interpolate (x) * scale1;
-
- table16 [index] = (uint16) Round_uint32 (y);
+ // Set the vignette correction curve.
+
+ const dng_vignette_radial_function curve (params);
+
+ // 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;
+ const uint32 bufferSize = ComputeBufferSize (pixelType,
+ tileSize,
+ imagePlanes,
+ padSIMDBytes);
- for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ // Support repeated Prepare() calls by ensuring all buffers are reset.
+
+ for (uint32 threadIndex = 0; threadIndex < kMaxMPThreads; threadIndex++)
{
+
+ fMaskBuffers [threadIndex] . Reset ();
+
+ }
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
fMaskBuffers [threadIndex] . Reset (allocator.Allocate (bufferSize));
-
+
}
}
-
+
}
/*****************************************************************************/
-void dng_opcode_FixVignetteRadial::ProcessArea (dng_negative & /* negative */,
+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 ();
+
+ dng_pixel_buffer maskPixelBuffer (dstArea,
+ 0,
+ fImagePlanes,
+ ttShort,
+ pcRowInterleavedAlignSIMD,
+ 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.
+
+ uint16 blackLevel = (Stage () >= 2) ? negative.Stage3BlackLevel () : 0;
- DoVignette16 (buffer.DirtyPixel_int16 (dstArea.t, dstArea.l),
+ 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);
+ fTableOutputBits,
+ blackLevel);
}
/*****************************************************************************/
uint32 dng_opcode_FixVignetteRadial::ParamBytes ()
{
const uint32 N = dng_vignette_radial_params::kNumTerms;
-
+
return ((N * sizeof (real64)) + // Vignette coefficients.
(2 * sizeof (real64))); // Optical center.
+
+ }
+
+/*****************************************************************************/
+
+dng_vignette_radial_params dng_opcode_FixVignetteRadial::MakeParamsForRender
+ (const dng_negative &negative)
+ {
+
+ (void) negative;
+ return fParams;
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.h b/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.h
index cd6b5411e7..31ef98ba90 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_lens_correction.h
@@ -1,601 +1,670 @@
/*****************************************************************************/
-// Copyright 2008 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_lens_correction.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+/** \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_memory.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.
+/// \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).
+ // 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].
+ // 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 ();
- // planes is 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.
+ /// 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?
+ /// Is the entire correction a NOP for all planes?
virtual bool IsNOPAll () const;
- // Is the entire correction a NOP for the specified plane?
+ /// 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?
+ /// Is the radial correction a NOP for all planes?
virtual bool IsRadNOPAll () const;
- // Is the radial correction a NOP for the specified plane?
+ /// 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?
+ /// Is the tangential correction a NOP for all planes?
virtual bool IsTanNOPAll () const;
- // Is the tangential correction a NOP for the specified plane?
+ /// Is the tangential correction a NOP for the specified plane?
virtual bool IsTanNOP (uint32 plane) const;
- // Do these warp params appear valid?
+ /// Do these warp params appear valid?
virtual bool IsValid () const;
- // Are these warp params valid for the specified negative?
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+
+ /// 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.
+
+ /// 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).
+ /// 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.
+ /// 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.
+ /// Compute and return the minimum src/dst ratio that should be used
+ /// for this warp.
+
+ virtual real64 SafeMinRatio () const = 0;
+
+ /// Compute and return the maximum src/dst ratio that should be used
+ /// for this warp.
+
+ virtual real64 SafeMaxRatio () 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.
+/// \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:
+ // 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.
+ // 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:
+ // 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, 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:
+ // 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 real64 SafeMinRatio () const;
+
+ virtual real64 SafeMaxRatio () const;
+
virtual void Dump () const;
};
/*****************************************************************************/
-/// \brief Warp parameters for fisheye camera model (radial component only). Note the
-/// restrictions described below.
+/// \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:
+ // 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.
+ // 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:
+ // 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:
+ // 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 real64 SafeMinRatio () const;
+
+ virtual real64 SafeMaxRatio () 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);
+ // Other methods.
+
+ bool HasDistort () const;
+
+ bool HasLateralCA () const;
+
+ const dng_warp_params_rectilinear & Params () const
+ {
+ return fWarpParams;
+ }
+
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.
+/// \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_std_vector<real64> fParams;
dng_point_real64 fCenter;
public:
dng_vignette_radial_params ();
- dng_vignette_radial_params (const std::vector<real64> &params,
+ dng_vignette_radial_params (const dng_std_vector<real64> &params,
const dng_point_real64 &center);
+ dng_vignette_radial_params (const dng_vignette_radial_params &params);
+
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);
+
+ const dng_vignette_radial_params & Params () const
+ {
+ return fParams;
+ }
virtual bool IsNOP () const;
-
+
virtual bool IsValidForNegative (const dng_negative &) const;
-
+
virtual void PutData (dng_stream &stream) const;
virtual uint32 BufferPixelType (uint32 /* imagePixelType */)
{
- return ttSShort;
+ 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 ();
+ virtual dng_vignette_radial_params MakeParamsForRender (const dng_negative &negative);
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.cpp
index 91c81d8c96..c534e94988 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.cpp
@@ -1,1410 +1,1600 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_linearization_info.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_safe_arithmetic.h"
+#include "dng_sdk_limits.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,
+ uint16 dstBlackLevel,
+ bool forceClipBlackLevel,
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,
+ uint16 dstBlackLevel,
+ bool forceClipBlackLevel,
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 != 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));
-
+
+ fBlack_2D_buffer.Reset (host.Allocate (SafeUint32Mult (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;
+
+ x *= (0x0FFFF - dstBlackLevel) * 256;
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))
+ (info.fBlackLevelRepeatRows > 1 || (fSrcPixelType != ttShort &&
+ fSrcPixelType != ttByte)))
{
-
+
fBlack_1D_rows = info.fBlackLevelRepeatRows;
-
+
}
-
+
if (fBlack_1D_rows)
{
-
- fBlack_1D_buffer.Reset (host.Allocate (fBlack_1D_rows * 4));
-
+
+ fBlack_1D_buffer.Reset
+ (host.Allocate (SafeUint32Mult (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]
+
+ 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;
+
+ x *= (0x0FFFF - dstBlackLevel) * 256;
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)
+
+ 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 *
+
+ uint32 scaleLUTEntries = (fSrcPixelType == ttByte ? 0x100 : 0x10000);
+
+ fScale_buffer.Reset (host.Allocate (scaleLUTEntries *
TagTypeSize (fDstPixelType)));
-
- for (j = 0; j < 0x10000; j++)
+
+ for (j = 0; j < scaleLUTEntries; 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;
+
+ // Burn in the clipping if requested.
- // We can burn in the clipping also.
-
- y = Pin_real64 (0.0, y, 1.0);
-
- // Store output value in table.
-
- if (fDstPixelType == ttShort)
+ if (forceClipBlackLevel)
{
-
- uint16 z = (uint16) Round_uint32 (y * 0x0FFFF);
-
- fScale_buffer->Buffer_uint16 () [j] = z;
-
+ y = Pin_real64 (0.0, y, 1.0);
}
-
- else
- {
-
- fScale_buffer->Buffer_real32 () [j] = (real32) y;
-
- }
-
+
+ // Store output value in table.
+
+ if (fDstPixelType == ttShort)
+ {
+
+ uint16 z = Pin_uint16 (Round_int32 (y * (0x0FFFF - dstBlackLevel) + dstBlackLevel));
+
+ 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);
+
+ int32 z = Round_int32 ((y * (0x0FFFF - dstBlackLevel) + dstBlackLevel) * 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.
-
- if (fBlack_1D_rows == 0 &&
- fBlack_2D_rows == 0 && fSrcPixelType != ttLong)
+
+ 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)
{
-
+
+ DNG_REQUIRE (fBlack_2D_rows > 0,
+ "Bad fBlack_2D_rows in dng_linearize_plane::Process");
+
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)
{
-
+
+ DNG_REQUIRE (fBlack_2D_rows > 0,
+ "Bad fBlack_2D_rows in dng_linearize_plane::Process");
+
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,
+ uint16 dstBlackLevel,
+ bool forceClipBlackLevel,
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,
+ uint16 dstBlackLevel,
+ bool forceClipBlackLevel,
const dng_image &srcImage,
dng_image &dstImage)
- : fSrcImage (srcImage)
+ : dng_area_task ("dng_linearization_image")
+
+ , 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,
+ dstBlackLevel,
+ forceClipBlackLevel,
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 ();
-
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex];
+
// 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 * sizeof (uint16);
-
+
+ uint32 size = SafeUint32Mult (rawIFD.fLinearizationTableCount,
+ static_cast<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 * sizeof (real64);
-
+
+ uint32 size = SafeUint32Mult (rawIFD.fBlackLevelDeltaHCount,
+ static_cast<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 * sizeof (real64);
-
+
+ uint32 size = SafeUint32Mult (rawIFD.fBlackLevelDeltaVCount,
+ static_cast<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];
+ memset (maxDeltaH, 0, sizeof (maxDeltaH));
+
for (j = 0; j < fBlackLevelRepeatCols; j++)
{
maxDeltaH [j] = 0.0;
}
-
+
if (fBlackDeltaH.Get ())
{
-
+
real64 *table = fBlackDeltaH->Buffer_real64 ();
-
- uint32 entries = fBlackDeltaH->LogicalSize () / sizeof (table [0]);
-
+
+ uint32 entries = fBlackDeltaH->LogicalSize () / (uint32) sizeof (table [0]);
+
for (j = 0; j < entries; j++)
{
-
+
+ DNG_REQUIRE (fBlackLevelRepeatCols > 0,
+ "Bad fBlackLevelRepeatCols in dng_linearization_info::MaxBlackLevel");
+
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];
-
+
+ memset (maxDeltaV, 0, sizeof (maxDeltaV));
+
for (j = 0; j < fBlackLevelRepeatRows; j++)
{
maxDeltaV [j] = 0.0;
}
-
+
if (fBlackDeltaV.Get ())
{
-
+
real64 *table = fBlackDeltaV->Buffer_real64 ();
-
- uint32 entries = fBlackDeltaV->LogicalSize () / sizeof (table [0]);
-
+
+ uint32 entries = fBlackDeltaV->LogicalSize () / (uint32) sizeof (table [0]);
+
for (j = 0; j < entries; j++)
{
-
+
+ DNG_REQUIRE (fBlackLevelRepeatRows > 0,
+ "Bad fBlackLevelRepeatRows in dng_linearization_info::MaxBlackLevel");
+
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,
+ dng_negative &negative,
const dng_image &srcImage,
dng_image &dstImage)
{
+ bool allowPreserveBlackLevels = negative.SupportsPreservedBlackLevels (host);
+
+ if (allowPreserveBlackLevels &&
+ negative.ColorimetricReference () == crSceneReferred &&
+ dstImage.PixelType () == ttShort)
+ {
+
+ real64 zeroFract = 0.0;
+
+ for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
+ {
+
+ real64 maxBlackLevel = MaxBlackLevel (plane);
+ real64 whiteLevel = fWhiteLevel [plane];
+
+ if (maxBlackLevel > 0.0 && maxBlackLevel < whiteLevel)
+ {
+
+ zeroFract = Max_real64 (zeroFract, maxBlackLevel / whiteLevel);
+
+ }
+
+ }
+
+ zeroFract = Min_real64 (zeroFract, kMaxStage3BlackLevelNormalized);
+
+ uint16 dstBlackLevel = (uint16) Round_uint32 (65535.0 * zeroFract);
+
+ if (negative.GetMosaicInfo ())
+ {
+
+ // If we have a mosaic image that supports non-zero black levels,
+ // enforce a minimum black level to give the demosaic algorithms
+ // some "footroom".
+
+ dstBlackLevel = (uint16) Max_uint32 (dstBlackLevel, 0x0404);
+
+ }
+
+ negative.SetStage3BlackLevel (dstBlackLevel);
+
+ }
+
+ bool forceClipBlackLevel = !allowPreserveBlackLevels;
+
dng_linearize_image processor (host,
*this,
+ negative.Stage3BlackLevel (),
+ forceClipBlackLevel,
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/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.h b/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.h
index 16e8416165..a309fc8678 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_linearization_info.h
@@ -1,162 +1,161 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_linearization_info.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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".
+/// 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;
+ 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.
+
+ /// 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 negative Used to remember preserved black point.
/// \param srcImage Input pre-linearization RAW samples.
/// \param dstImage Output linearized image.
virtual void Linearize (dng_host &host,
+ dng_negative &negative,
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/core/libs/dngwriter/extra/dng_sdk/dng_local_string.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_local_string.cpp
new file mode 100644
index 0000000000..15083a8ab2
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_local_string.cpp
@@ -0,0 +1,191 @@
+/*****************************************************************************/
+// Copyright 2015-2019 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 "dng_local_string.h"
+
+/*****************************************************************************/
+
+dng_local_string::dng_local_string ()
+
+ : fDefaultText ()
+ , fDictionary ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_local_string::dng_local_string (const dng_string &s)
+
+ : fDefaultText (s)
+ , fDictionary ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_local_string::~dng_local_string ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+void dng_local_string::Clear ()
+ {
+
+ fDefaultText.Clear ();
+
+ fDictionary.clear ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_local_string::SetDefaultText (const dng_string &s)
+ {
+
+ fDefaultText = s;
+
+ }
+
+/*****************************************************************************/
+
+void dng_local_string::AddTranslation (const dng_string &language,
+ const dng_string &translation)
+ {
+
+ dng_string safeLanguage (language);
+
+ safeLanguage.Truncate (255);
+
+ fDictionary.push_back (dictionary_entry (safeLanguage,
+ translation));
+
+ }
+
+/*****************************************************************************/
+
+void dng_local_string::Set (const char *s)
+ {
+
+ dng_string defaultText;
+
+ defaultText.Set (s);
+
+ *this = dng_local_string (defaultText);
+
+ }
+
+/*****************************************************************************/
+
+const dng_string & dng_local_string::LocalText (const dng_string &locale) const
+ {
+
+ // Pass 1 - try for a match starting with the entire locale string.
+
+ if (locale.Length () >= 5)
+ {
+
+ for (uint32 index = 0; index < TranslationCount (); index++)
+ {
+
+ if (Language (index).StartsWith (locale.Get (), false))
+ {
+
+ return Translation (index);
+
+ }
+
+ }
+
+ }
+
+ // Pass 2 - try for a language only match.
+
+ if (locale.Length () >= 2)
+ {
+
+ dng_string languageOnly (locale);
+
+ languageOnly.Truncate (2);
+
+ for (uint32 index = 0; index < TranslationCount (); index++)
+ {
+
+ if (Language (index).StartsWith (languageOnly.Get (), false))
+ {
+
+ return Translation (index);
+
+ }
+
+ }
+
+ }
+
+ // Otherwise use default text.
+
+ return DefaultText ();
+
+ }
+
+/*****************************************************************************/
+
+bool dng_local_string::operator== (const dng_local_string &s) const
+ {
+
+ if (DefaultText () != s.DefaultText ())
+ {
+ return false;
+ }
+
+ if (TranslationCount () != s.TranslationCount ())
+ {
+ return false;
+ }
+
+ for (uint32 index = 0; index < TranslationCount (); index++)
+ {
+
+ if (Language (index) != s.Language (index))
+ {
+ return false;
+ }
+
+ if (Translation (index) != s.Translation (index))
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_local_string::Truncate (uint32 maxBytes)
+ {
+
+ fDefaultText.Truncate (maxBytes);
+
+ for (uint32 index = 0; index < TranslationCount (); index++)
+ {
+
+ fDictionary [index] . fTranslation . Truncate (maxBytes);
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_local_string.h b/core/libs/dngwriter/extra/dng_sdk/dng_local_string.h
new file mode 100644
index 0000000000..b7f0fc66d1
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_local_string.h
@@ -0,0 +1,119 @@
+/*****************************************************************************/
+// Copyright 2015-2019 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 __dng_local_string__
+#define __dng_local_string__
+
+/*****************************************************************************/
+
+#include "dng_classes.h"
+#include "dng_string.h"
+#include "dng_types.h"
+
+#include <vector>
+
+/*****************************************************************************/
+
+class dng_local_string
+ {
+
+ private:
+
+ dng_string fDefaultText;
+
+ struct dictionary_entry
+ {
+
+ dng_string fLanguage;
+
+ dng_string fTranslation;
+
+ dictionary_entry (const dng_string &language,
+ const dng_string &translation)
+
+ : fLanguage (language)
+ , fTranslation (translation)
+
+ {
+
+ }
+
+ };
+
+ std::vector<dictionary_entry> fDictionary;
+
+ public:
+
+ dng_local_string ();
+
+ dng_local_string (const dng_string &s);
+
+ ~dng_local_string ();
+
+ void Clear ();
+
+ void SetDefaultText (const dng_string &s);
+
+ void AddTranslation (const dng_string &language,
+ const dng_string &translation);
+
+ void Set (const char *s);
+
+ const dng_string & DefaultText () const
+ {
+ return fDefaultText;
+ }
+
+ dng_string & DefaultText ()
+ {
+ return fDefaultText;
+ }
+
+ uint32 TranslationCount () const
+ {
+ return (uint32) fDictionary.size ();
+ }
+
+ const dng_string & Language (uint32 index) const
+ {
+ return fDictionary [index] . fLanguage;
+ }
+
+ const dng_string & Translation (uint32 index) const
+ {
+ return fDictionary [index] . fTranslation;
+ }
+
+ const dng_string & LocalText (const dng_string &locale) const;
+
+ bool IsEmpty () const
+ {
+ return DefaultText ().IsEmpty ();
+ }
+
+ bool NotEmpty () const
+ {
+ return !IsEmpty ();
+ }
+
+ bool operator== (const dng_local_string &s) const;
+
+ bool operator!= (const dng_local_string &s) const
+ {
+ return !(*this == s);
+ }
+
+ void Truncate (uint32 maxBytes);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.cpp
index 220de476b4..fe5a824f17 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.cpp
@@ -1,3747 +1,3844 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_lossless_jpeg.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 "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)
+
+ 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
+
+ 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);
+ if (ul >= static_cast<int32> (sizeof(htbl->numbits) / sizeof (htbl->numbits [0])) ||
+ ul >= static_cast<int32> (sizeof(htbl->value ) / sizeof (htbl->value [0])))
+ {
+ ThrowBadFormat ();
+ }
+
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
+ * 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
+class dng_lossless_decoder: private dng_uncopyable
{
-
+
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 ();
+
+ #if qSupportHasselblad_3FR
+
+ bool IsHasselblad3FR ()
+ {
+ return fHasselblad3FR;
+ }
+
+ #endif
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 (a << 8) + 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)
+ 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.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.
+
+ // We can cast info.numComponents to a uint32 because the check above
+ // guarantees that it cannot be negative.
- compInfoBuffer.Allocate (info.numComponents *
- sizeof (JpegComponentInfo));
-
+ compInfoBuffer.Allocate (static_cast<uint32> (info.numComponents),
+ 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)
+ 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 ();
-
+ 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
+
+ do
{
c = GetJpegChar ();
}
while (c != 0xFF);
-
+
// skip any duplicate FFs, since extra FFs are legal
-
- do
+
+ 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))
+
+ 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 --
*
- * Initialize the rest of the fields in the decompression
+ * 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)
+ compPtr->vSampFactor != 1)
{
ThrowBadFormat ();
}
-
+
}
-
+
}
-
+
// Prepare array describing MCU composition.
- if (info.compsInScan > 4)
+ if (info.compsInScan < 0 ||
+ 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 * sizeof (ComponentType);
-
- mcuBuffer1.Allocate (info.imageWidth * sizeof (MCU));
- mcuBuffer2.Allocate (info.imageWidth * sizeof (MCU));
-
+
+ // This multiplication cannot overflow because info.compsInScan is
+ // guaranteed to be between 0 and 4 inclusive (see checks above).
+
+ int32 mcuSize = info.compsInScan * (uint32) sizeof (ComponentType);
+
+ mcuBuffer1.Allocate (info.imageWidth, sizeof (MCU));
+ mcuBuffer2.Allocate (info.imageWidth, sizeof (MCU));
+
mcuROW1 = (MCU *) mcuBuffer1.Buffer ();
mcuROW2 = (MCU *) mcuBuffer2.Buffer ();
-
- mcuBuffer3.Allocate (info.imageWidth * mcuSize);
- mcuBuffer4.Allocate (info.imageWidth * mcuSize);
-
+
+ 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)
- {
+ 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
- {
+
+ 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
+ * 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 ();
-
+
+ int32 c0 = 0;
+ int32 c1 = 0;
+ int32 c2 = 0;
+ int32 c3 = 0;
+
+ try
+ {
+ c0 = GetJpegChar ();
+ c1 = GetJpegChar ();
+ c2 = GetJpegChar ();
+ c3 = GetJpegChar ();
+ }
+
+ catch (dng_exception &except)
+ {
+
+ // If we got any exception other than EOF, rethrow.
+
+ if (except.ErrorCode () != dng_error_end_of_file)
+ {
+ throw except;
+ }
+
+ // Some Hasselblad files now use the JPEG end of image marker.
+ // If we DIDN'T hit that, rethrow.
+ // This sequence also sometimes occurs in the image data, so
+ // we can't simply check for it and exit - we need to wait until
+ // we throw the EOF and then look to see if we had it.
+
+ // Look for the marker in c1 and c2 as well.
+ // (if we get it in c2 and c3, we won't throw.)
+
+ if (!((c0 == 0xFF && c1 == 0xD9) ||
+ (c1 == 0xFF && c2 == 0xD9)))
+ {
+ throw except;
+ }
+
+ // Swallow the case where we hit EOF with the JPEG EOI marker.
+
+ }
+
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 (nbits > 16)
+ {
+ ThrowBadFormat ();
+ }
+
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])
+
+ 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)
+ 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.
*
*--------------------------------------------------------------
*/
+DNG_ATTRIB_NO_SANITIZE("undefined")
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 * sizeof (uint16));
-
+
+ fSpooler->Spool (sPtr, pixels * (uint32) sizeof (uint16));
+
}
/*****************************************************************************/
/*
*--------------------------------------------------------------
*
* DecodeFirstRow --
*
- * Decode the first raster line of samples at the start of
+ * 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++)
+ 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];
+ memset (ht, 0, sizeof (ht));
+
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);
- HuffExtend (d, s0);
+ if (s0 == 16)
+ {
+ d = -32768;
+ }
+ else
+ {
+ HuffExtend (d, s0);
+ }
p0 += d;
}
if (s1)
{
int32 d = get_bits (s1);
- HuffExtend (d, 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.
+ // calculations are based on PSV.
if (compsInScan == 2 && info.Ss == 1)
{
-
- // This is the combination used by both the Canon and Kodak raw formats.
+
+ // 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)
+ bool bug16,
+ uint64 endOfData)
{
-
+
dng_lossless_decoder decoder (&stream,
&spooler,
bug16);
-
+
uint32 imageWidth;
uint32 imageHeight;
uint32 imageChannels;
-
+
decoder.StartRead (imageWidth,
imageHeight,
imageChannels);
-
+
uint32 decodedSize = imageWidth *
imageHeight *
imageChannels *
- sizeof (uint16);
-
+ (uint32) sizeof (uint16);
+
if (decodedSize < minDecodedSize ||
decodedSize > maxDecodedSize)
{
ThrowBadFormat ();
}
-
+
decoder.FinishRead ();
-
+
+ uint64 streamPos = stream.Position ();
+
+ if (streamPos > endOfData)
+ {
+
+ bool throwBadFormat = true;
+
+ // Per Hasselblad's request:
+ // If we have a Hassy file with exactly four extra bytes,
+ // let it through; the file is likely still valid.
+
+ #if qSupportHasselblad_3FR
+
+ if (decoder.IsHasselblad3FR () &&
+ streamPos - endOfData == 4)
+ {
+ throwBadFormat = false;
+ }
+
+ #endif
+
+ if (throwBadFormat)
+ {
+ ThrowBadFormat ();
+ }
+ }
+
}
/*****************************************************************************/
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 = putBuffer >> 16;
+
+ 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.
+ * 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 difference value if
+ // 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.
+ * 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];
-
+
+ int32 predictor [4] = { 0, 0, 0, 0 };
+
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];
-
+
+ int32 predictor [4] = { 0, 0, 0, 0 };
+
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.
+ * Generate the optimal coding for the given counts.
* This algorithm is explained in section K.2 of the
- * JPEG standard.
+ * 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)
+
+ 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
- // chain c2 onto c1's tree branch
-
- others [c1] = c2;
-
+ others [c1] = (short) c2;
+
// Increment the codesize of everything in c2's tree branch.
codesize [c2] ++;
-
- while (others [c2] >= 0)
+
+ 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 ();
-
+
+ ThrowOverflow ("Huffman code size table overflow");
+
}
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.
+
+ // 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.
+ * the best PSV.
*
* Results:
- * Optimal Huffman tables are returned in cPtr->dcHuffTblPtrs[tbl].
- * Best PSV is returned in cPtr->Ss.
+ * 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 (mark);
-
+ 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, followed by the huffman data.
+ * 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 (index);
+
+ 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++)
- {
-
+ 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
-
+ 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.
+
+ // Count the times each difference category occurs.
// Construct the optimal Huffman table.
-
+
HuffOptimize ();
// Write the frame and scan headers.
- WriteFileHeader ();
-
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.h b/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.h
index 6e5c131d08..6939c530d7 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_lossless_jpeg.h
@@ -1,69 +1,65 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_lossless_jpeg.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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);
-
+ bool bug16,
+ uint64 endOfData);
+
/*****************************************************************************/
void EncodeLosslessJPEG (const uint16 *srcData,
uint32 srcRows,
uint32 srcCols,
uint32 srcChannels,
uint32 srcBitDepth,
int32 srcRowStep,
int32 srcColStep,
dng_stream &stream);
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_matrix.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_matrix.cpp
index 647a2362ae..315616cb77 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_matrix.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_matrix.cpp
@@ -1,1036 +1,1353 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_matrix.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_matrix.h"
+#include "dng_assertions.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 ()
+
+void dng_matrix::Clear ()
{
-
+
fRows = 0;
fCols = 0;
-
+
}
-
+
/*****************************************************************************/
-
-void dng_matrix::SetIdentity (uint32 count)
+
+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 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;
+
+ }
+/******************************************************************************/
+
+bool dng_matrix::IsIdentity () const
+ {
+
+ if (IsDiagonal ())
+ {
+
+ for (uint32 j = 0; j < Rows (); j++)
+ {
+
+ if (fData [j] [j] != 1.0)
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+ return false;
+
}
/******************************************************************************/
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 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 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;
-
+
}
-
+
}
-
+
}
/*****************************************************************************/
+bool dng_matrix::AlmostEqual (const dng_matrix &m,
+ real64 slop) 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 (Abs_real64 (fData [j] [k] - m [j] [k]) > slop)
+ {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_matrix::AlmostIdentity (real64 slop) const
+ {
+
+ dng_matrix m;
+
+ m.SetIdentity (Rows ());
+
+ return AlmostEqual (m, slop);
+
+ }
+
+/*****************************************************************************/
+
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_matrix_4by4::dng_matrix_4by4 ()
+ : dng_matrix (4, 4)
+
{
+ }
+
+/*****************************************************************************/
+
+dng_matrix_4by4::dng_matrix_4by4 (const dng_matrix &m)
+
+ : dng_matrix (m)
+
+ {
+
+ // Input must be either 3x3 or 4x4.
+
+ const bool is3by3 = (m.Rows () == 3 &&
+ m.Cols () == 3);
+
+ const bool is4by4 = (m.Rows () == 4 &&
+ m.Cols () == 4);
+
+ if (!is3by3 && !is4by4)
+ {
+
+ ThrowMatrixMath ();
+
+ }
+
+ // For 3x3 case, pad to 4x4 (equivalent 4x4 matrix).
+
+ if (is3by3)
+ {
+
+ fRows = 4;
+ fCols = 4;
+
+ fData [0] [3] = 0.0;
+ fData [1] [3] = 0.0;
+ fData [2] [3] = 0.0;
+
+ fData [3] [0] = 0.0;
+ fData [3] [1] = 0.0;
+ fData [3] [2] = 0.0;
+
+ fData [3] [3] = 1.0;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_matrix_4by4::dng_matrix_4by4 (real64 a00, real64 a01, real64 a02, real64 a03,
+ real64 a10, real64 a11, real64 a12, real64 a13,
+ real64 a20, real64 a21, real64 a22, real64 a23,
+ real64 a30, real64 a31, real64 a32, real64 a33)
+
+ : dng_matrix (4, 4)
+
+ {
+
fData [0] [0] = a00;
fData [0] [1] = a01;
fData [0] [2] = a02;
-
+ fData [0] [3] = a03;
+
fData [1] [0] = a10;
fData [1] [1] = a11;
fData [1] [2] = a12;
-
+ fData [1] [3] = a13;
+
fData [2] [0] = a20;
fData [2] [1] = a21;
fData [2] [2] = a22;
-
+ fData [2] [3] = a23;
+
fData [3] [0] = a30;
fData [3] [1] = a31;
fData [3] [2] = a32;
+ fData [3] [3] = a33;
+
+ }
+/*****************************************************************************/
+
+dng_matrix_4by4::dng_matrix_4by4 (real64 a00,
+ real64 a11,
+ real64 a22,
+ real64 a33)
+
+ : dng_matrix (4, 4)
+
+ {
+
+ fData [0] [0] = a00;
+ fData [1] [1] = a11;
+ fData [2] [2] = a22;
+ fData [3] [3] = a33;
+
}
/*****************************************************************************/
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 ()
+
+void dng_vector::Clear ()
{
-
+
fCount = 0;
-
+
}
-
+
/*****************************************************************************/
-
-void dng_vector::SetIdentity (uint32 count)
+
+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++)
+
+ 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++)
+
+ 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++)
+
+ 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;
+dng_vector operator- (const dng_vector &a,
+ const dng_vector &b)
+ {
+
+ uint32 count = a.Count ();
+
+ DNG_REQUIRE (count == b.Count (),
+ "Mismatch count in Dot");
+
+ if (!count)
+ {
+ return dng_vector ();
+ }
+
+ dng_vector result (count);
+
+ for (uint32 i = 0; i < count; i++)
+ {
+
+ result [i] = a [i] - b [i];
+
+ }
+
+ return result;
+
+ }
+
+/******************************************************************************/
+
+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 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;
+
+ const uint32 n = A.Rows ();
- uint32 n = A.Rows ();
+ const uint32 augmented_cols = 2 * n;
real64 temp [kMaxColorPlanes] [kMaxColorPlanes * 2];
+ memset (temp, 0, sizeof (temp));
+
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];
+ // Find row iMax with largest absolute entry in column i.
- if (Abs_real64 (alpha) < kNearZero)
+ uint32 iMax = i;
+ real64 vMax = -1.0;
+
+ for (k = i; k < n; k++)
{
+
+ real64 v = Abs_real64 (A [k] [i]);
- ThrowMatrixMath ();
+ if (v > vMax)
+ {
+ vMax = v;
+ iMax = k;
+ }
+
+ }
+ real64 alpha = temp [iMax] [i];
+
+ if (Abs_real64 (alpha) < kNearZero)
+ {
+
+ ThrowMatrixMath ();
+
}
+
+ // Swap rows i and iMax, column by column.
- for (j = 0; j < n * 2; j++)
+ if (i != iMax)
{
- temp [i] [j] /= alpha;
+ for (j = 0; j < augmented_cols; j++)
+ {
+
+ std::swap (temp [i ] [j],
+ temp [iMax] [j]);
+
+ }
}
+ for (j = 0; j < augmented_cols; 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++)
+
+ for (j = 0; j < augmented_cols; 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;
-
+
+ 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;
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+real64 Dot (const dng_vector &a,
+ const dng_vector &b)
+ {
+
+ DNG_REQUIRE (a.Count () == b.Count (),
+ "Cannot take dot product between vectors of different size.");
+
+ // DNG_REQUIRE (a.Count () > 0,
+ // "Cannot take dot product with an empty vector.");
+
+ real64 sum = 0.0;
+ for (uint32 j = 0; j < a.Count (); j++)
+ {
+
+ sum += (a [j] * b [j]);
+
}
+ return sum;
+
+ }
+
+/*****************************************************************************/
+
+real64 Distance (const dng_vector &a,
+ const dng_vector &b)
+ {
+
+ dng_vector c = a - b;
+
+ return sqrt (Dot (c, c));
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_matrix.h b/core/libs/dngwriter/extra/dng_sdk/dng_matrix.h
index 7e90204c77..b3f96a2818 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_matrix.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_matrix.h
@@ -1,294 +1,365 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_matrix.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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;
-
+
+ bool IsIdentity () const;
+
real64 MaxEntry () const;
-
+
real64 MinEntry () const;
void Scale (real64 factor);
-
+
void Round (real64 factor);
-
+
void SafeRound (real64 factor);
+
+ bool AlmostEqual (const dng_matrix &m,
+ real64 slop = 1.0e-8) const;
- };
+ bool AlmostIdentity (real64 slop = 1.0e-8) const;
+ };
+
/*****************************************************************************/
+/// \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 A 4x4 matrix. Handy for GPU APIs.
+
+class dng_matrix_4by4: public dng_matrix
+ {
+
+ public:
+
+ dng_matrix_4by4 ();
+
+ dng_matrix_4by4 (const dng_matrix &m);
+
+ dng_matrix_4by4 (real64 a00, real64 a01, real64 a02, real64 a03,
+ real64 a10, real64 a11, real64 a12, real64 a13,
+ real64 a20, real64 a21, real64 a22, real64 a23,
+ real64 a30, real64 a31, real64 a32, real64 a33);
+
+ dng_matrix_4by4 (real64 a00, real64 a11, real64 a22, real64 a33);
+
};
/*****************************************************************************/
+/// \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_vector operator- (const dng_vector &a,
+ const dng_vector &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
+real64 Dot (const dng_vector &a,
+ const dng_vector &b);
+
+/*****************************************************************************/
+
+real64 Distance (const dng_vector &a,
+ const dng_vector &b);
/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_memory.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_memory.cpp
index 04cf9825bd..48e6bdd764 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_memory.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_memory.cpp
@@ -1,174 +1,284 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_memory.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_memory.h"
+#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
+#ifdef _MSC_VER
+#include <Windows.h>
+#endif
+
/*****************************************************************************/
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 (const dng_safe_uint32 &size)
+ : fBuffer (NULL)
+
{
+
+ Allocate (size.Get ());
+
+ }
- Allocate (size);
+/*****************************************************************************/
+
+dng_memory_data::dng_memory_data (uint32 count,
+ std::size_t elementSize)
+ : fBuffer (NULL)
+
+ {
+
+ Allocate (count, elementSize);
+
}
/*****************************************************************************/
dng_memory_data::~dng_memory_data ()
{
-
+
Clear ();
-
+
}
-
+
/*****************************************************************************/
void dng_memory_data::Allocate (uint32 size)
{
-
+
Clear ();
-
+
if (size)
{
-
- fBuffer = malloc (size);
-
+ //printf("Calling malloc from %s\n", __FUNCTION__);
+ fBuffer = (char *) malloc (size);
+
if (!fBuffer)
{
-
+
ThrowMemoryFull ();
-
+
}
-
+
}
-
+
}
-
+
/*****************************************************************************/
-void dng_memory_data::Clear ()
+void dng_memory_data::Allocate (const dng_safe_uint32 &size)
{
+
+ Allocate (size.Get ());
+
+ }
- if (fBuffer)
- {
+/*****************************************************************************/
- free (fBuffer);
+void dng_memory_data::Allocate (uint32 count,
+ std::size_t elementSize)
+ {
+
+ // Convert elementSize to a uint32.
- fBuffer = NULL;
+ const uint32 elementSizeAsUint32 = static_cast<uint32> (elementSize);
+ if (static_cast<std::size_t> (elementSizeAsUint32) != elementSize)
+ {
+ ThrowOverflow ("elementSize overflow");
}
+
+ // Compute required number of bytes and allocate memory.
+
+ dng_safe_uint32 numBytes = dng_safe_uint32 (count) * elementSizeAsUint32;
+ Allocate (numBytes.Get ());
+
}
/*****************************************************************************/
-class dng_malloc_block : public dng_memory_block
+void dng_memory_data::Allocate (const dng_safe_uint32 &count,
+ std::size_t elementSize)
{
- private:
+ Allocate (count.Get (), elementSize);
- void *fMalloc;
+ }
- public:
+/*****************************************************************************/
- dng_malloc_block (uint32 logicalSize);
+void dng_memory_data::Clear ()
+ {
+
+ if (fBuffer)
+ {
+
+ free (fBuffer);
+
+ fBuffer = NULL;
+
+ }
+
+ }
+
+/*****************************************************************************/
- virtual ~dng_malloc_block ();
+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;
+
+ }
- private:
+/*****************************************************************************/
- // Hidden copy constructor and assignment operator.
+dng_malloc_block::dng_malloc_block (uint32 logicalSize)
- dng_malloc_block (const dng_malloc_block &block);
+ : dng_memory_block (logicalSize)
+
+ , fMalloc (NULL)
+
+ {
- dng_malloc_block & operator= (const dng_malloc_block &block);
+ #if qLinux
- };
+ // TO DO: Need to change this alignment for AVX support?
-/*****************************************************************************/
+ int err = ::posix_memalign ((void **) &fMalloc,
+ 16,
+ (size_t) PhysicalSize ());
-dng_malloc_block::dng_malloc_block (uint32 logicalSize)
+ if (err)
+ {
- : dng_memory_block (logicalSize)
+ ThrowMemoryFull ();
- , fMalloc (NULL)
+ }
- {
+ #elif qAndroid
+
+ fMalloc = memalign (16, (size_t) PhysicalSize ());
+
+ if (!fMalloc)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
+ #else
- fMalloc = malloc (PhysicalSize ());
+ //fMalloc = (char *) VirtualAlloc (NULL, PhysicalSize (), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ //printf("Calling malloc from %s\n", __FUNCTION__);
+ fMalloc = (char *)malloc(PhysicalSize());
if (!fMalloc)
{
-
+
ThrowMemoryFull ();
-
+
}
- SetBuffer (fMalloc);
+ //*(size_t*)(fMalloc) = size_t(PhysicalSize() + 16);
+ //fMalloc = (char*)fMalloc+16;
- }
+ #endif
+ SetBuffer (fMalloc);
+
+ }
+
/*****************************************************************************/
dng_malloc_block::~dng_malloc_block ()
{
-
+
if (fMalloc)
{
-
+
+ //size_t size = *(size_t*)((char*)fMalloc - 16);
+ //VirtualFree(fMalloc, 0, MEM_RELEASE);
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;
+
+ }
+
+/*****************************************************************************/
+void * dng_memory_allocator::Malloc (size_t size)
+ {
+
+ return malloc (size);
+
+ }
+
+/*****************************************************************************/
+
+void dng_memory_allocator::Free (void *ptr)
+ {
+
+ free (ptr);
+
}
/*****************************************************************************/
dng_memory_allocator gDefaultDNGMemoryAllocator;
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_memory.h b/core/libs/dngwriter/extra/dng_sdk/dng_memory.h
index de0fa825ed..c9b10f3732 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_memory.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_memory.h
@@ -1,492 +1,652 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_memory.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** Support for memory allocation.
*/
/*****************************************************************************/
#ifndef __dng_memory__
#define __dng_memory__
/*****************************************************************************/
+#include "dng_classes.h"
+#include "dng_exceptions.h"
+#include "dng_flags.h"
+#include "dng_safe_arithmetic.h"
#include "dng_types.h"
+#include "dng_uncopyable.h"
+
+#include <cstdlib>
+#include <vector>
+
+/*****************************************************************************/
+
+#if qDNGAVXSupport
+ #define DNG_ALIGN_SIMD(x) ((((uintptr) (x)) + 31) & ~((uintptr) 31))
+#else
+ #define DNG_ALIGN_SIMD(x) ((((uintptr) (x)) + 15) & ~((uintptr) 15))
+#endif
/*****************************************************************************/
/// \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
+class dng_memory_data: private dng_uncopyable
{
-
+
private:
-
- void *fBuffer;
-
+
+ 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);
+
+ dng_memory_data (const dng_safe_uint32 &size);
+
+ /// Note: This constructor is for internal use only and should not be
+ /// considered part of the DNG SDK API.
+ ///
+ /// Construct memory buffer of count elements of elementSize bytes each.
+ /// \param count Number of elements.
+ /// \param elementSize Size of each element.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ dng_memory_data (uint32 count,
+ std::size_t elementSize);
/// 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);
+ void Allocate (const dng_safe_uint32 &size);
+
+ /// Note: This method is for internal use only and should not be
+ /// considered part of the DNG SDK API.
+ ///
+ /// Clear existing memory buffer and allocate new memory of count
+ /// elements of elementSize bytes each.
+ /// \param count Number of elements.
+ /// \param elementSize Size of each element.
+ /// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
+
+ void Allocate (uint32 count,
+ std::size_t elementSize);
+
+ void Allocate (const dng_safe_uint32 &count,
+ std::size_t elementSize);
+
/// 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
+class dng_memory_block: private dng_uncopyable
{
-
+
private:
-
+
uint32 fLogicalSize;
-
- void *fBuffer;
-
+
+ char *fBuffer;
+
protected:
-
+
dng_memory_block (uint32 logicalSize)
: fLogicalSize (logicalSize)
, fBuffer (NULL)
{
}
-
+
uint32 PhysicalSize ()
{
- return fLogicalSize + 64;
- }
+
+ // 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.
+ //
+ // Please do NOT change the following padding unless you are very
+ // sure what you are doing.
+
+ dng_safe_uint32 safeLogicalSize (fLogicalSize);
+
+ #if qDNGAVXSupport
+
+ // Allow 32-byte alignment + 64-byte overread in both directions:
+ // 32 + 64 + 64 = 160.
+
+ return (safeLogicalSize + 160u).Get ();
+
+ #else
+
+ // Allow 16-byte alignment + overread.
+
+ return (safeLogicalSize + 64u).Get ();
+ #endif // qDNGAVXSupport
+
+ }
+
void SetBuffer (void *p)
{
- fBuffer = (void *) ((((uintptr) p) + 15) & ~((uintptr) 15));
+ fBuffer = (char *) DNG_ALIGN_SIMD (p);
}
-
+
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 ()
+
+ 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);
+ /// Directly allocate a block of at least 'size' bytes.
+ /// \param size Number of bytes in memory block.
+ /// \retval A pointer to a contiguous block of memory with at least
+ /// size bytes of valid storage.
+ /// Caller is responsible for freeing the memory with Free.
+ /// Default implementation uses standard library 'malloc' routine.
+
+ virtual void * Malloc (size_t size);
+
+ /// Free the specified block of memory previously allocated with Malloc.
+ /// Default implementation uses standard library 'free' routine.
+
+ virtual void Free (void *ptr);
+
};
/*****************************************************************************/
-/// \brief Default memory allocator used if NULL is passed in for allocator
+class dng_malloc_block : public dng_memory_block
+ {
+
+ private:
+
+ void *fMalloc;
+
+ public:
+
+ dng_malloc_block (uint32 logicalSize);
+
+ virtual ~dng_malloc_block ();
+
+ };
+
+/*****************************************************************************/
+
+/// \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.
+/// buffer.
extern dng_memory_allocator gDefaultDNGMemoryAllocator;
/*****************************************************************************/
+/// \brief C++ allocator (i.e. an implementation of the Allocator concept)
+/// that throws a dng_exception with error code dng_error_memory if it cannot
+/// allocate memory.
+
+template <typename T>
+class dng_std_allocator
+ {
+
+ public:
+
+ typedef T value_type;
+
+ #if defined(_MSC_VER) && _MSC_VER >= 1900
+
+ // Default implementations of default constructor and copy
+ // constructor.
+
+ dng_std_allocator () = default;
+
+ // dng_std_allocator (const dng_std_allocator &) = default;
+
+ template<class U> dng_std_allocator (const dng_std_allocator<U> &) {}
+
+ #endif
+
+ T * allocate (size_t n)
+ {
+ const size_t size = SafeSizetMult (n, sizeof (T));
+ T *retval = static_cast<T *> (malloc (size));
+ if (!retval)
+ {
+ ThrowMemoryFull ();
+ }
+ return retval;
+ }
+
+ void deallocate (T *ptr,
+ size_t /* n */)
+ {
+ free (ptr);
+ }
+
+ };
+
+template <class T>
+bool operator== (const dng_std_allocator<T> & /* a1 */,
+ const dng_std_allocator<T> & /* a2 */)
+ {
+ return true;
+ }
+
+template <class T>
+bool operator!= (const dng_std_allocator<T> & /* a1 */,
+ const dng_std_allocator<T> & /* a2 */)
+ {
+ return false;
+ }
+
+/*****************************************************************************/
+
+// std::vector specialized to use dng_std_allocator for allocation.
+
+#if 0
+// original implementation without using custom allocator
+#define dng_std_vector std::vector
+#else
+// preferred implementation using custom allocator, requires C++11
+template <class T> using dng_std_vector = std::vector<T, dng_std_allocator<T> >;
#endif
/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.cpp
index 0d074bf3ec..25cbb7aa0f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.cpp
@@ -1,254 +1,282 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_memory_stream.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_memory_stream.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
+#include "dng_safe_arithmetic.h"
#include "dng_utils.h"
/*****************************************************************************/
dng_memory_stream::dng_memory_stream (dng_memory_allocator &allocator,
dng_abort_sniffer *sniffer,
uint32 pageSize)
-
- : dng_stream (sniffer,
+
+ : dng_stream (sniffer,
kDefaultBufferSize,
kDNGStreamInvalidOffset)
-
+
, fAllocator (allocator)
, fPageSize (pageSize )
-
+
, fPageCount (0)
, fPagesAllocated (0)
, fPageList (NULL)
-
+
, fMemoryStreamLength (0)
+ , fLengthLimit (0)
+
{
-
+
}
-
+
/*****************************************************************************/
dng_memory_stream::~dng_memory_stream ()
{
-
+
if (fPageList)
{
-
+
for (uint32 index = 0; index < fPageCount; index++)
{
-
+
delete fPageList [index];
-
+
}
-
+
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)
{
-
+
+ if (fLengthLimit && length > fLengthLimit)
+ {
+
+ Throw_dng_error (dng_error_end_of_file,
+ "dng_memory_stream::fLengthLimit",
+ NULL,
+ true);
+
+ }
+
while (length > fPageCount * (uint64) fPageSize)
{
-
+
if (fPageCount == fPagesAllocated)
{
- uint32 newSize = Max_uint32 (fPagesAllocated + 32,
- fPagesAllocated * 2);
-
- dng_memory_block **list = (dng_memory_block **)
- malloc (newSize * sizeof (dng_memory_block *));
+ uint32 newSizeTemp1 = 0;
+ uint32 newSizeTemp2 = 0;
- if (!list)
+ if (!SafeUint32Add (fPagesAllocated, 32u, &newSizeTemp1) ||
+ !SafeUint32Mult (fPagesAllocated, 2u, &newSizeTemp2))
{
+ ThrowOverflow ("Arithmetic overflow in DoSetLength");
+ }
- ThrowMemoryFull ();
+ uint32 newSize = Max_uint32 (newSizeTemp1,
+ newSizeTemp2);
+ uint32 numBytes;
+
+ if (!SafeUint32Mult (newSize,
+ sizeof (dng_memory_block *),
+ &numBytes))
+ {
+ ThrowOverflow ("Arithmetic overflow in DoSetLength");
}
+ dng_memory_block **list = (dng_memory_block **) malloc (numBytes);
+
+ if (!list)
+ {
+
+ ThrowMemoryFull ();
+
+ }
+
if (fPageCount)
{
+
+ // The multiplication here is safe against overflow.
+ // fPageCount can never reach a value that is large enough to
+ // cause overflow because the computation of numBytes above
+ // would fail before a list of that size could be allocated.
DoCopyBytes (fPageList,
list,
- fPageCount * sizeof (dng_memory_block *));
-
+ fPageCount * (uint32) sizeof (dng_memory_block *));
+
}
-
+
if (fPageList)
{
-
+
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/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.h b/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.h
index 61fce53942..e0e83a2beb 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_memory_stream.h
@@ -1,93 +1,93 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_memory_stream.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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;
-
+
+ uint64 fLengthLimit;
+
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 ();
-
+
+ /// Sets a maximum length limit.
+
+ void SetLengthLimit (uint64 limit)
+ {
+ fLengthLimit = limit;
+ }
+
+ /// 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/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.cpp
index d440e0d0f9..2ac072db4d 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.cpp
@@ -1,1578 +1,1552 @@
/*****************************************************************************/
-// Copyright 2008-2009 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_misc_opcodes.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_negative.h"
#include "dng_rect.h"
+#include "dng_safe_arithmetic.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 (fRowPitch >= fArea.H () || fColPitch >= fArea.W ())
+ {
+
+ DNG_REPORT ("Bad rowPitch or colPitch in dng_area_spec::GetData");
+
+ fRowPitch = Min_uint32 (fRowPitch, fArea.H ());
+ fColPitch = Min_uint32 (fColPitch, fArea.W ());
- if (fArea.IsEmpty () && (fRowPitch != 1 || fColPitch != 1))
+ }
+
+ if (fArea.IsEmpty ())
{
- ThrowBadFormat ();
+
+ if (fRowPitch != 1 || fColPitch != 1)
+ {
+ ThrowBadFormat ();
+ }
+
}
+
+ else
+ {
- #if qDNGValidate
+ int32 width = 0;
+ int32 height = 0;
+
+ if (!SafeInt32Sub (fArea.b, fArea.t, &height) ||
+ !SafeInt32Sub (fArea.r, fArea.l, &width) ||
+ fRowPitch > static_cast<uint32> (height) ||
+ fColPitch > static_cast<uint32> (width))
+ {
+ 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)
+ , fBlackAdjustedTable ()
+
{
-
+
if (count == 0 || count > 0x10000)
{
ThrowProgramError ();
}
-
+
fTable.Reset (host.Allocate (0x10000 * sizeof (uint16)));
-
+
DoCopyBytes (table,
fTable->Buffer (),
- count * sizeof (uint16));
-
+ 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)
+
+ , fBlackAdjustedTable ()
{
-
+
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", j, table [j]);
+ printf (" Table [%5u] = %5u\n", (unsigned) j, (unsigned) table [j]);
}
-
+
if (fCount > gDumpLineLimit)
{
- printf (" ... %u table entries skipped\n", 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::Prepare (dng_negative &negative,
+ uint32 /* threadCount */,
+ const dng_point & /* tileSize */,
+ const dng_rect & /* imageBounds */,
+ uint32 /* imagePlanes */,
+ uint32 /* bufferPixelType */,
+ dng_memory_allocator &allocator)
+ {
+
+ fBlackAdjustedTable.Reset ();
+
+ int32 blackLevel = negative.Stage3BlackLevel ();
+
+ if (Stage () >= 2 && blackLevel != 0)
+ {
+
+ fBlackAdjustedTable.Reset (allocator.Allocate (0x10000 * sizeof (uint16)));
+
+ const uint16 *srcTable = fTable->Buffer_uint16 ();
+
+ uint16 *dstTable = fBlackAdjustedTable->Buffer_uint16 ();
+
+ real64 srcScale = 65535.0 / (65535.0 - blackLevel);
+
+ real64 dstScale = (65535.0 - blackLevel) / 65535.0;
+
+ for (int32 index = 0; index < 0x10000; index++)
+ {
+
+ real64 x = (index - blackLevel) * srcScale;
+
+ real64 y;
+
+ if (x < 0.0)
+ {
+
+ y = srcTable [0] * 2.0 - (real64) srcTable [Round_uint32 (-x)];
+
+ }
+
+ else
+ {
+
+ y = srcTable [Round_uint32 (x)];
+
+ }
+
+ dstTable [index] = Pin_uint16 (Round_int32 (y * dstScale) + blackLevel);
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
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 ())
{
-
+
+ const uint16 *table = fBlackAdjustedTable.Get () ? fBlackAdjustedTable->Buffer_uint16 ()
+ : fTable ->Buffer_uint16 ();
+
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 ());
-
+ table);
+
}
-
+
}
-
+
}
-
+
/*****************************************************************************/
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", k, fCoefficient [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 ();
- break;
+
}
-
+
}
-
+
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 */,
+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 ();
-
+
+ uint16 blackLevel = Stage () >= 2 ? negative.Stage3BlackLevel () : 0;
+
+ uint32 rowPitch = fAreaSpec.RowPitch ();
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);
-
- }
- break;
- }
-
- }
+ DoProcess (buffer,
+ overlap,
+ plane,
+ rowPitch,
+ colPitch,
+ fCoefficient32,
+ fDegree,
+ blackLevel);
+
+ }
+
+ }
+
+ }
- }
+/*****************************************************************************/
- }
+void dng_opcode_MapPolynomial::DoProcess (dng_pixel_buffer &buffer,
+ const dng_rect &area,
+ const uint32 plane,
+ const uint32 rowPitch,
+ const uint32 colPitch,
+ const real32 *coefficients,
+ const uint32 degree,
+ uint16 blackLevel) const
+ {
- }
+ DoBaselineMapPoly32 (buffer.DirtyPixel_real32 (area.t,
+ area.l,
+ plane),
+ buffer.RowStep () * (int32) rowPitch,
+ area.H (),
+ area.W (),
+ rowPitch,
+ colPitch,
+ coefficients,
+ degree,
+ blackLevel);
}
/*****************************************************************************/
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 ();
-
+
+ uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().H (),
+ fAreaSpec.RowPitch ());
+
if (deltas != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
-
+
if (dataSize != dng_area_spec::kDataSize + 4 + deltas * 4)
{
ThrowBadFormat ();
}
-
- fTable.Reset (host.Allocate (deltas * sizeof (real32)));
-
+
+ fTable.Reset (host.Allocate
+ (SafeUint32Mult (deltas,
+ static_cast<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", k, table [k]);
+ printf (" Delta [%u] = %f\n", (unsigned) k, table [k]);
}
-
+
if (deltas > gDumpLineLimit)
{
- printf (" ... %u deltas skipped\n", 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 ();
-
+
+ uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().H (),
+ 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 ();
- break;
+
}
-
+
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 */,
+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 ();
-
+
+ real32 scale = fScale;
+
+ if (Stage () >= 2 && negative.Stage3BlackLevel () != 0)
+ {
+ scale *= (real32) (1.0 - negative.Stage3BlackLevelNormalized ());
+ }
+
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 rowDelta = *(table++) * scale;
+
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);
-
+
+ dPtr [col] = Pin_real32 (-1.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 ();
-
+
+ uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().W (),
+ fAreaSpec.ColPitch ());
+
if (deltas != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
-
+
if (dataSize != dng_area_spec::kDataSize + 4 + deltas * 4)
{
ThrowBadFormat ();
}
-
- fTable.Reset (host.Allocate (deltas * sizeof (real32)));
-
+
+ fTable.Reset (host.Allocate
+ (SafeUint32Mult (deltas,
+ static_cast<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", k, table [k]);
+ printf (" Delta [%u] = %f\n", (unsigned) k, table [k]);
}
-
+
if (deltas > gDumpLineLimit)
{
- printf (" ... %u deltas skipped\n", 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 ();
-
+
+ uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().W (),
+ 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 ();
- break;
+
}
-
+
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 */,
+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.W () + fAreaSpec.RowPitch () - 1) /
+
+ uint32 rows = (overlap.H () + fAreaSpec.RowPitch () - 1) /
fAreaSpec.RowPitch ();
-
+
int32 rowStep = buffer.RowStep () * fAreaSpec.RowPitch ();
-
+
+ real32 scale = fScale;
+
+ if (Stage () >= 2 && negative.Stage3BlackLevel () != 0)
+ {
+ scale *= (real32) (1.0 - negative.Stage3BlackLevelNormalized ());
+ }
+
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 colDelta = *(table++) * scale;
+
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 [0] = Pin_real32 (-1.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 ();
-
+
+ uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().H (),
+ fAreaSpec.RowPitch ());
+
if (scales != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
-
+
if (dataSize != dng_area_spec::kDataSize + 4 + scales * 4)
{
ThrowBadFormat ();
}
-
- fTable.Reset (host.Allocate (scales * sizeof (real32)));
-
+
+ fTable.Reset (host.Allocate
+ (SafeUint32Mult (scales,
+ static_cast<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", k, table [k]);
+ printf (" Scale [%u] = %f\n", (unsigned) k, table [k]);
}
-
+
if (scales > gDumpLineLimit)
{
- printf (" ... %u scales skipped\n", 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 ();
-
+
+ uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().H (),
+ 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 */,
+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 ();
-
+
+ real32 blackOffset = 0.0f;
+
+ if (Stage () >= 2 && negative.Stage3BlackLevel () != 0)
+ {
+ blackOffset = (real32) negative.Stage3BlackLevelNormalized ();
+ }
+
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);
-
- }
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = (x - blackOffset) * rowScale + blackOffset;
+
+ dPtr [col] = Pin_real32 (-1.0f, 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 ();
-
+
+ uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().W (),
+ fAreaSpec.ColPitch());
+
if (scales != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
-
+
if (dataSize != dng_area_spec::kDataSize + 4 + scales * 4)
{
ThrowBadFormat ();
}
-
- fTable.Reset (host.Allocate (scales * sizeof (real32)));
-
+
+ fTable.Reset (host.Allocate
+ (SafeUint32Mult (scales,
+ static_cast<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", k, table [k]);
+ printf (" Scale [%u] = %f\n", (unsigned) k, table [k]);
}
-
+
if (scales > gDumpLineLimit)
{
- printf (" ... %u deltas skipped\n", 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 ();
-
+
+ uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().W (),
+ 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 */,
+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.W () + fAreaSpec.RowPitch () - 1) /
+
+ uint32 rows = (overlap.H () + fAreaSpec.RowPitch () - 1) /
fAreaSpec.RowPitch ();
-
+
int32 rowStep = buffer.RowStep () * fAreaSpec.RowPitch ();
-
+
+ real32 blackOffset = 0.0f;
+
+ if (Stage () >= 2 && negative.Stage3BlackLevel () != 0)
+ {
+ blackOffset = (real32) negative.Stage3BlackLevelNormalized ();
+ }
+
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);
-
+
+ real32 y = (x - blackOffset) * colScale + blackOffset;
+
+ dPtr [0] = Pin_real32 (-1.0f, y, 1.0f);
+
dPtr += rowStep;
-
+
}
-
+
}
-
+
}
-
+
}
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.h b/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.h
index 40468104e4..447d78bfe2 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_misc_opcodes.h
@@ -1,343 +1,445 @@
/*****************************************************************************/
-// Copyright 2008-2009 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_misc_opcodes.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+/** \file
+ * Miscellaneous DNG opcodes.
+ */
/*****************************************************************************/
#ifndef __dng_misc_opcodes__
#define __dng_misc_opcodes__
/*****************************************************************************/
+#include "dng_classes.h"
+
#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;
}
- const uint32 Plane () const
+ /// The first plane.
+
+ uint32 Plane () const
{
return fPlane;
}
- const uint32 Planes () const
+ /// The total number of planes.
+
+ uint32 Planes () const
{
return fPlanes;
}
- const uint32 RowPitch () const
+ /// The row pitch (i.e., stride). A pitch of 1 means all rows.
+
+ uint32 RowPitch () const
{
return fRowPitch;
}
-
- const uint32 ColPitch () const
+
+ /// 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;
-
+
+ AutoPtr<dng_memory_block> fBlackAdjustedTable;
+
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 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);
-
+
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:
-
+
+ protected:
+
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);
+ uint32 Degree () const
+ {
+ return fDegree;
+ }
+
+ const real64 * Coefficients () const
+ {
+ return fCoefficient;
+ }
+
+ protected:
+
+ virtual void DoProcess (dng_pixel_buffer &buffer,
+ const dng_rect &area,
+ const uint32 plane,
+ const uint32 rowPitch,
+ const uint32 colPitch,
+ const real32 *coefficients,
+ const uint32 degree,
+ uint16 blackLevel) const;
+
};
/*****************************************************************************/
+/// \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/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.cpp
index 70cf4dcc31..84b961abf4 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.cpp
@@ -1,1991 +1,2008 @@
/*****************************************************************************/
-// Copyright 2006-2009 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_mosaic_info.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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")
-
+
+ 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:
-
+
+ DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
uint32 DeltaRow (uint32 row, int32 delta)
{
- return (row + fPatRows + delta) % fPatRows;
+ return (row + fPatRows + (uint32) delta) % fPatRows;
}
-
+
+ DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
uint32 DeltaCol (uint32 col, int32 delta)
{
- return (col + fPatCols + delta) % fPatCols;
+ return (col + fPatCols + (uint32) delta) % fPatCols;
}
-
+
real32 LinearWeight1 (int32 d1, int32 d2)
{
if (d1 == d2)
- return 1.0;
+ return 1.0f;
else
return d2 / (real32) (d2 - d1);
}
-
+
real32 LinearWeight2 (int32 d1, int32 d2)
{
if (d1 == d2)
- return 0.0;
+ 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 ();
- break;
+
}
-
+
// 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,
+
+ 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;
+
+ 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,
+
+ : dng_filter_task ("dng_fast_interpolator",
+ 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];
-
+ uint32 c = Max_uint32 (count [plane], 1);
+
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 ();
-
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex];
+
// 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.
-
+
+ // 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 phaseV = 0; phaseV < fCFAPatternSize.v; phaseV++)
{
-
- for (int32 phaseH = 0; phaseH <= fCFAPatternSize.h - test.h; phaseH++)
+
+ for (int32 phaseH = 0; phaseH < fCFAPatternSize.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];
-
+
+ uint8 srcKey = fCFAPattern [(srcRow + phaseV) % fCFAPatternSize.v]
+ [(srcCol + phaseH) % fCFAPatternSize.h];
+
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;
-
+
+ dng_pixel_buffer srcBuffer (dng_rect (srcTileSize),
+ srcPlane,
+ 1,
+ srcImage.PixelType (),
+ pcInterleaved,
+ NULL);
+
+ uint32 srcBufferSize = ComputeBufferSize (srcBuffer.fPixelType,
+ srcTileSize,
+ srcBuffer.fPlanes,
+ padNone);
+
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;
-
+
+ dng_pixel_buffer dstBuffer (dng_rect (dstTileSize),
+ 0,
+ fColorPlanes,
+ dstImage.PixelType (),
+ pcRowInterleaved,
+ NULL);
+
+ uint32 dstBufferSize = ComputeBufferSize (dstBuffer.fPixelType,
+ dstTileSize,
+ dstBuffer.fPlanes,
+ padNone);
+
AutoPtr<dng_memory_block> dstData (host.Allocate (dstBufferSize));
-
+
dstBuffer.fData = dstData->Buffer ();
-
+
// Create interpolator.
- dng_bilinear_interpolator interpolator (*this,
- srcBuffer.fRowStep,
- srcBuffer.fColStep);
+ 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);
-
+
+ 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
+ uint32 srcPlane,
+ dng_matrix *scaleTransforms) const
{
-
+
+ if (scaleTransforms && downScale != dng_point (1, 1))
+ {
+
+ for (uint32 plane = 0; plane < dstImage.Planes (); plane++)
+ {
+
+ scaleTransforms [plane] = dng_matrix_3by3 (1.0 / downScale.v, 0.0, 0.0,
+ 0.0, 1.0 / downScale.h, 0.0,
+ 0.0, 0.0, 1.0);
+
+ }
+
+ }
+
if (downScale == dng_point (1, 1))
{
-
+
InterpolateGeneric (host,
negative,
srcImage,
dstImage,
srcPlane);
-
+
}
-
+
else
{
-
+
InterpolateFast (host,
negative,
srcImage,
dstImage,
downScale,
srcPlane);
-
+
}
+
+ }
+/*****************************************************************************/
+
+bool dng_mosaic_info::SupportsPreservedBlackLevels () const
+ {
+
+ return false;
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.h b/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.h
index b57a9da658..988aaefdef 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_mosaic_info.h
@@ -1,200 +1,198 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_mosaic_info.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 horizontal and vertical dimensions.
+ /// \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;
-
+ uint32 srcPlane = 0,
+ dng_matrix *scaleTransforms = NULL) const;
+
+ virtual bool SupportsPreservedBlackLevels () 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/core/libs/dngwriter/extra/dng_sdk/dng_mutex.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_mutex.cpp
index 2f097a042a..61f32ae3cc 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_mutex.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_mutex.cpp
@@ -1,390 +1,516 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_mutex.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
+#include "dng_abort_sniffer.h"
#include "dng_mutex.h"
#include "dng_assertions.h"
#include "dng_exceptions.h"
#include <stdlib.h>
/*****************************************************************************/
-#if qDNGThreadSafe
+// do mutex lock level tracking, asserts stripped in non-debug so don't track there
+#ifndef qDNGThreadTestMutexLevels
+#define qDNGThreadTestMutexLevels (qDNGThreadSafe && qDNGDebug)
+#endif
+#if qDNGThreadTestMutexLevels
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.");
+ (void) result;
+
+ #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 qDNGThreadSafe
-
+ #if qWinOS
+
+ // Win is already a recursive mutex by default
if (pthread_mutex_init (&fPthreadMutex, NULL) != 0)
{
ThrowMemoryFull ();
}
-
+
+ #else
+
+ // make recursive mutex, can lock within itself
+ pthread_mutexattr_t mta;
+ pthread_mutexattr_init(&mta);
+ pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+
+ if (pthread_mutex_init (&fPthreadMutex, &mta) != 0)
+ {
+ ThrowMemoryFull ();
+ }
+ #endif
+
#endif
}
/*****************************************************************************/
dng_mutex::~dng_mutex ()
{
-
+
#if qDNGThreadSafe
pthread_mutex_destroy (&fPthreadMutex);
#endif
}
/*****************************************************************************/
void dng_mutex::Lock ()
{
- #if qDNGThreadSafe
+ #if qDNGThreadSafe
+ #if qDNGThreadTestMutexLevels
dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
if (innermostMutex != NULL)
{
if (innermostMutex == this)
{
- fRecursiveLockCount++;
+ int result = pthread_mutex_lock (&fPthreadMutex);
+
+ if (result != 0)
+ {
+
+ DNG_ASSERT (result == 0, "pthread_mutex_lock failed.");
+
+ ThrowProgramError ();
+
+ }
+
+ fRecursiveLockCount++;
return;
}
- bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel /* ||
- (fMutexLevel == innermostMutex->fMutexLevel && innermostMutex < this) */;
-
+ bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel;
+
+ // to allow cloning of class internals both with a dng_mutex and get closer to the C++ mutex,
+ // test for MutexLevelIgnore and don't generate level violations
+ if (!lockOrderPreserved)
+ {
+
+ if ((fMutexLevel == kDNGMutexLevelIgnore) || (innermostMutex->fMutexLevel == kDNGMutexLevelIgnore))
+ lockOrderPreserved = true;
+
+ }
+
if (!lockOrderPreserved)
{
+
+ char msg[1024];
+
+ sprintf(msg,
+ "Lock order violation: This mutex: %s v Innermost mutex: %s",
+ this->MutexName (),
+ innermostMutex->MutexName ());
+
+ DNG_REPORT(msg); // asserts inside of mutex lock, any locks within that must be lower
+
+ }
- DNG_REPORT ("Lock ordering violation.");
+ }
- #if qDNGDebug
+ int result = pthread_mutex_lock (&fPthreadMutex);
- dng_show_message_f ("This mutex: %s v Innermost mutex: %s",
- this->MutexName (),
- innermostMutex->MutexName ());
+ if (result != 0)
+ {
- #endif
+ DNG_ASSERT (result == 0, "pthread_mutex_lock failed.");
- }
+ ThrowProgramError ();
}
- pthread_mutex_lock (&fPthreadMutex);
-
fPrevHeldMutex = innermostMutex;
gInnermostMutexHolder.SetInnermostMutex (this);
- #endif
+ #else
+
+ // Register the fact that we're trying to lock this mutex.
+
+ int result = pthread_mutex_lock (&fPthreadMutex);
+
+ if (result != 0)
+ {
+ DNG_REPORT ("pthread_mutex_lock failed");
+
+ ThrowProgramError ();
+
+ }
+
+ // Register the fact that we've now successfully acquired the mutex.
+
+ #endif
+ #endif
+
}
/*****************************************************************************/
void dng_mutex::Unlock ()
{
-
+
#if qDNGThreadSafe
-
+ #if qDNGThreadTestMutexLevels
+
DNG_ASSERT (gInnermostMutexHolder.GetInnermostMutex () == this, "Mutexes unlocked out of order!!!");
if (fRecursiveLockCount > 0)
{
-
+
fRecursiveLockCount--;
+ pthread_mutex_unlock (&fPthreadMutex);
+
return;
}
gInnermostMutexHolder.SetInnermostMutex (fPrevHeldMutex);
fPrevHeldMutex = NULL;
+ #endif
+
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 (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 ()
- {
+dng_unlock_mutex::dng_unlock_mutex (dng_mutex &mutex)
+ : fMutex (&mutex)
+
+ {
+
if (fMutex)
- fMutex->Lock ();
-
+ fMutex->Unlock ();
+
}
/*****************************************************************************/
-#if qDNGThreadSafe
+dng_unlock_mutex::~dng_unlock_mutex ()
+ {
+
+ if (fMutex)
+ fMutex->Lock ();
+
+ }
/*****************************************************************************/
dng_condition::dng_condition ()
+#if qDNGThreadSafe
: fPthreadCondition ()
+#endif
{
+#if qDNGThreadSafe
int result;
result = pthread_cond_init (&fPthreadCondition, NULL);
DNG_ASSERT (result == 0, "pthread_cond_init failed.");
if (result != 0)
{
ThrowProgramError ();
}
+#endif
}
/*****************************************************************************/
dng_condition::~dng_condition ()
{
-
+#if qDNGThreadSafe
pthread_cond_destroy (&fPthreadCondition);
-
+#endif
}
/*****************************************************************************/
bool dng_condition::Wait (dng_mutex &mutex, double timeoutSecs)
{
+#if qDNGThreadSafe
bool timedOut = false;
+ #if qDNGThreadTestMutexLevels
+
dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
DNG_ASSERT (innermostMutex == &mutex, "Attempt to wait on non-innermost mutex.");
+ (void) innermostMutex;
+
innermostMutex = mutex.fPrevHeldMutex;
gInnermostMutexHolder.SetInnermostMutex (innermostMutex);
mutex.fPrevHeldMutex = NULL;
-
+
+ #endif
+
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;
+ #if defined(_MSC_VER) && _MSC_VER >= 1900
+
+ struct dng_timespec tempNow;
+
+ tempNow.tv_sec = (long) now.tv_sec;
+ tempNow.tv_nsec = now.tv_nsec;
+
+ timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &tempNow) == ETIMEDOUT);
+
+ #else
+
+ timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &now) == ETIMEDOUT);
+
+ #endif
}
+ #if qDNGThreadTestMutexLevels
+
mutex.fPrevHeldMutex = innermostMutex;
gInnermostMutexHolder.SetInnermostMutex (&mutex);
-
+
+ #endif
+
return !timedOut;
+#else
+ return true;
+#endif
}
/*****************************************************************************/
void dng_condition::Signal ()
{
+#if qDNGThreadSafe
int result;
result = pthread_cond_signal (&fPthreadCondition);
DNG_ASSERT (result == 0, "pthread_cond_signal failed.");
if (result != 0)
ThrowProgramError ();
+#endif
}
/*****************************************************************************/
void dng_condition::Broadcast ()
{
+#if qDNGThreadSafe
int result;
result = pthread_cond_broadcast (&fPthreadCondition);
DNG_ASSERT (result == 0, "pthread_cond_broadcast failed.");
if (result != 0)
ThrowProgramError ();
-
+#endif
}
/*****************************************************************************/
-
-#endif // qDNGThreadSafe
-
-/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_mutex.h b/core/libs/dngwriter/extra/dng_sdk/dng_mutex.h
index d75106e94f..9a200ab9f0 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_mutex.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_mutex.h
@@ -1,177 +1,145 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_mutex.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/******************************************************************************/
-
#ifndef __dng_mutex__
#define __dng_mutex__
/******************************************************************************/
#include "dng_flags.h"
-
-/******************************************************************************/
-
#include "dng_types.h"
+#include "dng_uncopyable.h"
#if qDNGThreadSafe
-
#include "dng_pthread.h"
-
#endif
+#include <mutex>
+
+typedef std::mutex dng_std_mutex;
+typedef std::lock_guard<std::mutex> dng_lock_std_mutex;
+typedef std::unique_lock<std::mutex> dng_unique_lock;
+
+// We should try to phase out use of dng_mutex over time.
+//
+// Note that dng_mutex differs from dng_std_mutex (std::mutex) in that
+// dng_mutex supports recursive locking (hierarchical mutex).
+
/******************************************************************************/
-class dng_mutex
+class dng_mutex: private dng_uncopyable
{
-
+
public:
-
+
enum
{
- kDNGMutexLevelLeaf = 0xffffffffu
+ kDNGMutexLevelLeaf = 0x70000000u,
+ kDNGMutexLevelIgnore = 0x7FFFFFFFu
};
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
+class dng_lock_mutex: private dng_uncopyable
{
-
+
private:
-
+
dng_mutex *fMutex;
-
+
public:
-
+
dng_lock_mutex (dng_mutex *mutex);
-
+
+ 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
+class dng_unlock_mutex: private dng_uncopyable
{
-
+
private:
-
+
dng_mutex *fMutex;
-
+
public:
-
+
dng_unlock_mutex (dng_mutex *mutex);
-
+
+ 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
+class dng_condition: private dng_uncopyable
{
-
+
public:
dng_condition ();
~dng_condition ();
bool Wait (dng_mutex &mutex, double timeoutSecs = -1.0);
void Signal ();
-
+
void Broadcast ();
protected:
-
+
+
+#if qDNGThreadSafe
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 // qDNGThreadSafe
-
-/*****************************************************************************/
-
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_negative.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_negative.cpp
index 8bb7c4c572..bcd6f54358 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_negative.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_negative.cpp
@@ -1,3183 +1,5941 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_negative.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_negative.h"
+#include "dng_1d_table.h"
#include "dng_abort_sniffer.h"
+#include "dng_area_task.h"
+#include "dng_assertions.h"
#include "dng_bottlenecks.h"
#include "dng_camera_profile.h"
+#include "dng_color_space.h"
#include "dng_color_spec.h"
#include "dng_exceptions.h"
#include "dng_globals.h"
#include "dng_host.h"
#include "dng_image.h"
#include "dng_image_writer.h"
#include "dng_info.h"
+#include "dng_jpeg_image.h"
#include "dng_linearization_info.h"
+#include "dng_memory.h"
#include "dng_memory_stream.h"
+#include "dng_misc_opcodes.h"
#include "dng_mosaic_info.h"
#include "dng_preview.h"
+#include "dng_resample.h"
+#include "dng_safe_arithmetic.h"
#include "dng_simple_image.h"
#include "dng_tag_codes.h"
#include "dng_tag_values.h"
#include "dng_tile_iterator.h"
+#include "dng_uncopyable.h"
+#include "dng_utils.h"
#include "dng_xmp.h"
/*****************************************************************************/
dng_noise_profile::dng_noise_profile ()
: fNoiseFunctions ()
{
-
+
}
/*****************************************************************************/
-dng_noise_profile::dng_noise_profile (const std::vector<dng_noise_function> &functions)
+dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions)
: fNoiseFunctions (functions)
{
}
/*****************************************************************************/
bool dng_noise_profile::IsValid () const
{
if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes)
{
return false;
}
-
+
for (uint32 plane = 0; plane < NumFunctions (); plane++)
{
-
+
if (!NoiseFunction (plane).IsValid ())
{
return false;
}
-
+
}
return true;
-
+
}
/*****************************************************************************/
bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const
{
-
+
if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ()))
{
return false;
}
return IsValid ();
}
/*****************************************************************************/
const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const
{
-
+
if (NumFunctions () == 1)
{
return fNoiseFunctions.front ();
}
- DNG_REQUIRE (plane < NumFunctions (),
+ DNG_REQUIRE (plane < NumFunctions (),
"Bad plane index argument for NoiseFunction ().");
return fNoiseFunctions [plane];
-
+
}
/*****************************************************************************/
uint32 dng_noise_profile::NumFunctions () const
{
return (uint32) fNoiseFunctions.size ();
}
/*****************************************************************************/
-dng_negative::dng_negative (dng_memory_allocator &allocator)
+bool dng_noise_profile::operator== (const dng_noise_profile &profile) const
+ {
+
+ if (IsValid ())
+ {
+
+ if (!profile.IsValid ())
+ {
+ return false;
+ }
+
+ if (NumFunctions () != profile.NumFunctions ())
+ {
+ return false;
+ }
+
+ for (uint32 plane = 0; plane < NumFunctions (); plane++)
+ {
+
+ if (NoiseFunction (plane).Scale () != profile.NoiseFunction (plane).Scale () ||
+ NoiseFunction (plane).Offset () != profile.NoiseFunction (plane).Offset ())
+ {
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+ else
+ return !profile.IsValid ();
+
+ }
+
+/*****************************************************************************/
- : fAllocator (allocator)
+dng_metadata::dng_metadata (dng_host &host)
- , fModelName ()
- , fLocalName ()
- , fHasBaseOrientation (false)
+ : fHasBaseOrientation (false)
, fBaseOrientation ()
- , fDefaultCropSizeH ()
- , fDefaultCropSizeV ()
- , fDefaultCropOriginH (0, 1)
- , fDefaultCropOriginV (0, 1)
- , fDefaultScaleH (1, 1)
- , fDefaultScaleV (1, 1)
- , fBestQualityScale (1, 1)
- , fRawToFullScaleH (1.0)
- , fRawToFullScaleV (1.0)
- , fBaselineNoise (100, 100)
- , fNoiseReductionApplied (0, 0)
- , fNoiseProfile ()
- , fBaselineExposure ( 0, 100)
- , fBaselineSharpness (100, 100)
- , fChromaBlurRadius ()
- , fAntiAliasStrength (100, 100)
- , fLinearResponseLimit (100, 100)
- , fShadowScale (1, 1)
- , fColorimetricReference (crSceneReferred)
- , fColorChannels (0)
- , fAnalogBalance ()
- , fCameraNeutral ()
- , fCameraWhiteXY ()
- , fCameraCalibration1 ()
- , fCameraCalibration2 ()
- , fCameraCalibrationSignature ()
- , fCameraProfile ()
- , fAsShotProfileName ()
- , fRawImageDigest ()
- , fRawDataUniqueID ()
- , fOriginalRawFileName ()
- , fHasOriginalRawFileData (false)
- , fOriginalRawFileData ()
- , fOriginalRawFileDigest ()
- , fDNGPrivateData ()
, fIsMakerNoteSafe (false)
, fMakerNote ()
- , fExif ()
+ , fExif (host.Make_dng_exif ())
, fOriginalExif ()
, fIPTCBlock ()
, fIPTCOffset (kDNGStreamInvalidOffset)
- , fUsedUTF8forIPTC (false)
- , fXMP ()
- , fValidEmbeddedXMP (false)
+ , fXMP (host.Make_dng_xmp ())
+ , fEmbeddedXMPDigest ()
, fXMPinSidecar (false)
, fXMPisNewer (false)
- , fLinearizationInfo ()
- , fMosaicInfo ()
- , fOpcodeList1 (1)
- , fOpcodeList2 (2)
- , fOpcodeList3 (3)
- , fStage1Image ()
- , fStage2Image ()
- , fStage3Image ()
- , fStage3Gain (1.0)
- , fIsPreview (false)
- , fIsDamaged (false)
- , fRawImageStage (rawImageStageNone)
- , fRawImage ()
+ , fSourceMIME ()
{
-
}
/*****************************************************************************/
-dng_negative::~dng_negative ()
+dng_metadata::~dng_metadata ()
{
-
- // Delete any camera profiles owned by this negative.
-
- ClearProfiles ();
-
}
-
+
/******************************************************************************/
-void dng_negative::Initialize ()
+template< class T >
+T * CloneAutoPtr (const AutoPtr< T > &ptr)
{
-
- fExif.Reset (MakeExif ());
-
- fXMP.Reset (MakeXMP ());
-
+
+ return ptr.Get () ? ptr->Clone () : NULL;
+
}
/******************************************************************************/
-dng_negative * dng_negative::Make (dng_memory_allocator &allocator)
+template< class T, typename U >
+T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u)
{
+
+ return ptr.Get () ? ptr->Clone (u) : NULL;
+
+ }
- AutoPtr<dng_negative> result (new dng_negative (allocator));
-
- if (!result.Get ())
- {
- ThrowMemoryFull ();
- }
+/******************************************************************************/
- result->Initialize ();
+dng_metadata::dng_metadata (const dng_metadata &rhs,
+ dng_memory_allocator &allocator)
+
+ : fHasBaseOrientation (rhs.fHasBaseOrientation)
+ , fBaseOrientation (rhs.fBaseOrientation)
+ , fIsMakerNoteSafe (rhs.fIsMakerNoteSafe)
+ , fMakerNote (CloneAutoPtr (rhs.fMakerNote, allocator))
+ , fExif (CloneAutoPtr (rhs.fExif))
+ , fOriginalExif (CloneAutoPtr (rhs.fOriginalExif))
+ , fIPTCBlock (CloneAutoPtr (rhs.fIPTCBlock, allocator))
+ , fIPTCOffset (rhs.fIPTCOffset)
+ , fXMP (CloneAutoPtr (rhs.fXMP))
+ , fEmbeddedXMPDigest (rhs.fEmbeddedXMPDigest)
+ , fXMPinSidecar (rhs.fXMPinSidecar)
+ , fXMPisNewer (rhs.fXMPisNewer)
+ , fSourceMIME (rhs.fSourceMIME)
- return result.Release ();
+ {
}
/******************************************************************************/
-void dng_negative::SetBaseOrientation (const dng_orientation &orientation)
+dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const
{
-
- fHasBaseOrientation = true;
-
- fBaseOrientation = orientation;
-
+
+ return new dng_metadata (*this, allocator);
+
}
/******************************************************************************/
-dng_orientation dng_negative::Orientation () const
+void dng_metadata::SetBaseOrientation (const dng_orientation &orientation)
{
-
- return BaseOrientation ();
-
+
+ fHasBaseOrientation = true;
+
+ fBaseOrientation = orientation;
+
}
-
+
/******************************************************************************/
-void dng_negative::ApplyOrientation (const dng_orientation &orientation)
+void dng_metadata::ApplyOrientation (const dng_orientation &orientation)
{
-
+
fBaseOrientation += orientation;
-
+
fXMP->SetOrientation (fBaseOrientation);
}
+
+/*****************************************************************************/
-/******************************************************************************/
-
-void dng_negative::SetAnalogBalance (const dng_vector &b)
+void dng_metadata::ResetExif (dng_exif * newExif)
{
- real64 minEntry = b.MinEntry ();
-
- if (b.NotEmpty () && minEntry > 0.0)
- {
-
- fAnalogBalance = b;
-
- fAnalogBalance.Scale (1.0 / minEntry);
+ fExif.Reset (newExif);
- fAnalogBalance.Round (1000000.0);
+ }
- }
+/******************************************************************************/
- else
+dng_memory_block * dng_metadata::BuildExifBlock (dng_memory_allocator &allocator,
+ const dng_resolution *resolution,
+ bool includeIPTC,
+ const dng_jpeg_preview *thumbnail) const
+ {
+
+ dng_memory_stream stream (allocator);
+
{
+
+ // Create the main IFD
+
+ dng_tiff_directory mainIFD;
+
+ // Optionally include the resolution tags.
+
+ dng_resolution res;
+
+ if (resolution)
+ {
+ res = *resolution;
+ }
+
+ tag_urational tagXResolution (tcXResolution, res.fXResolution);
+ tag_urational tagYResolution (tcYResolution, res.fYResolution);
+
+ tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
+
+ if (resolution)
+ {
+ mainIFD.Add (&tagXResolution );
+ mainIFD.Add (&tagYResolution );
+ mainIFD.Add (&tagResolutionUnit);
+ }
- fAnalogBalance.Clear ();
-
+ // Optionally include IPTC block.
+
+ tag_iptc tagIPTC (IPTCData (),
+ IPTCLength ());
+
+ if (includeIPTC && tagIPTC.Count ())
+ {
+ mainIFD.Add (&tagIPTC);
+ }
+
+ // Exif tags.
+
+ exif_tag_set exifSet (mainIFD,
+ *GetExif (),
+ IsMakerNoteSafe (),
+ MakerNoteData (),
+ MakerNoteLength (),
+ false);
+
+ // Figure out the Exif IFD offset.
+
+ uint32 exifOffset = 8 + mainIFD.Size ();
+
+ exifSet.Locate (exifOffset);
+
+ // Thumbnail IFD (if any).
+
+ dng_tiff_directory thumbIFD;
+
+ tag_uint16 thumbCompression (tcCompression, ccOldJPEG);
+
+ tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1));
+ tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1));
+
+ tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch);
+
+ tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat , 0);
+ tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0);
+
+ if (thumbnail)
+ {
+
+ thumbIFD.Add (&thumbCompression);
+
+ thumbIFD.Add (&thumbXResolution);
+ thumbIFD.Add (&thumbYResolution);
+ thumbIFD.Add (&thumbResolutionUnit);
+
+ thumbIFD.Add (&thumbDataOffset);
+ thumbIFD.Add (&thumbDataLength);
+
+ thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ());
+
+ uint32 thumbOffset = exifOffset + exifSet.Size ();
+
+ mainIFD.SetChained (thumbOffset);
+
+ thumbDataOffset.Set (thumbOffset + thumbIFD.Size ());
+
+ }
+
+ // Don't write anything unless the main IFD has some tags.
+
+ if (mainIFD.Size () != 0)
+ {
+
+ // Write TIFF Header.
+
+ stream.SetWritePosition (0);
+
+ stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
+
+ stream.Put_uint16 (42);
+
+ stream.Put_uint32 (8);
+
+ // Write the IFDs.
+
+ mainIFD.Put (stream);
+
+ exifSet.Put (stream);
+
+ if (thumbnail)
+ {
+
+ thumbIFD.Put (stream);
+
+ stream.Put (thumbnail->fCompressedData->Buffer (),
+ thumbnail->fCompressedData->LogicalSize ());
+
+ }
+
+ // Trim the file to this length.
+
+ stream.Flush ();
+
+ stream.SetLength (stream.Position ());
+
+ }
+
}
-
+
+ return stream.AsMemoryBlock (allocator);
+
}
+
+/******************************************************************************/
-/*****************************************************************************/
+void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
+ {
+
+ fIPTCBlock.Reset (block.Release ());
+
+ fIPTCOffset = offset;
+
+ }
+
+/******************************************************************************/
-real64 dng_negative::AnalogBalance (uint32 channel) const
+void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block)
{
+
+ SetIPTC (block, kDNGStreamInvalidOffset);
+
+ }
+
+/******************************************************************************/
- DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
+void dng_metadata::ClearIPTC ()
+ {
+
+ fIPTCBlock.Reset ();
+
+ fIPTCOffset = kDNGStreamInvalidOffset;
+
+ }
+
+/*****************************************************************************/
- if (channel < fAnalogBalance.Count ())
+const void * dng_metadata::IPTCData () const
+ {
+
+ if (fIPTCBlock.Get ())
{
-
- return fAnalogBalance [channel];
-
+
+ return fIPTCBlock->Buffer ();
+
}
-
- return 1.0;
-
+
+ return NULL;
+
}
/*****************************************************************************/
-dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
+uint32 dng_metadata::IPTCLength () const
{
-
- dng_urational result;
-
- result.Set_real64 (AnalogBalance (channel), 1000000);
-
- return result;
-
+
+ if (fIPTCBlock.Get ())
+ {
+
+ return fIPTCBlock->LogicalSize ();
+
+ }
+
+ return 0;
+
}
+
+/*****************************************************************************/
-/******************************************************************************/
-
-void dng_negative::SetCameraNeutral (const dng_vector &n)
+uint64 dng_metadata::IPTCOffset () const
{
-
- real64 maxEntry = n.MaxEntry ();
-
- if (n.NotEmpty () && maxEntry > 0.0)
+
+ if (fIPTCBlock.Get ())
{
-
- fCameraNeutral = n;
-
- fCameraNeutral.Scale (1.0 / maxEntry);
-
- fCameraNeutral.Round (1000000.0);
-
+
+ return fIPTCOffset;
+
}
+
+ return kDNGStreamInvalidOffset;
+
+ }
+
+/*****************************************************************************/
- else
+dng_fingerprint dng_metadata::IPTCDigest (bool includePadding) const
+ {
+
+ if (IPTCLength ())
{
+
+ dng_md5_printer printer;
+
+ const uint8 *data = (const uint8 *) IPTCData ();
+
+ uint32 count = IPTCLength ();
+
+ // Because of some stupid ways of storing the IPTC data, the IPTC
+ // data might be padded with up to three zeros. The official Adobe
+ // logic is to include these zeros in the digest. However, older
+ // versions of the Camera Raw code did not include the padding zeros
+ // in the digest, so we support both methods and allow either to
+ // match.
+
+ if (!includePadding)
+ {
+
+ uint32 removed = 0;
+
+ while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
+ {
+ removed++;
+ count--;
+ }
+
+ }
+
+ printer.Process (data, count);
+
+ return printer.Result ();
+
+ }
+
+ return dng_fingerprint ();
+
+ }
+
+/******************************************************************************/
- fCameraNeutral.Clear ();
+void dng_metadata::RebuildIPTC (dng_memory_allocator &allocator,
+ bool padForTIFF)
+ {
+
+ ClearIPTC ();
+
+ fXMP->RebuildIPTC (*this, allocator, padForTIFF);
+
+ dng_fingerprint digest = IPTCDigest ();
+
+ fXMP->SetIPTCDigest (digest);
+
+ }
+
+/*****************************************************************************/
- }
+void dng_metadata::ResetXMP (dng_xmp * newXMP)
+ {
+
+ fXMP.Reset (newXMP);
}
/*****************************************************************************/
-dng_urational dng_negative::CameraNeutralR (uint32 channel) const
+void dng_metadata::ResetXMPSidecarNewer (dng_xmp * newXMP,
+ bool inSidecar,
+ bool isNewer )
{
- dng_urational result;
+ fXMP.Reset (newXMP);
- result.Set_real64 (CameraNeutral () [channel], 1000000);
+ fXMPinSidecar = inSidecar;
- return result;
+ fXMPisNewer = isNewer;
}
-/******************************************************************************/
+/*****************************************************************************/
-void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
+bool dng_metadata::SetXMP (dng_host &host,
+ const void *buffer,
+ uint32 count,
+ bool xmpInSidecar,
+ bool xmpIsNewer)
{
-
- if (coord.IsValid ())
+
+ bool result = false;
+
+ try
{
+
+ AutoPtr<dng_xmp> tempXMP (host.Make_dng_xmp ());
+
+ tempXMP->Parse (host, buffer, count);
+
+ ResetXMPSidecarNewer (tempXMP.Release (), xmpInSidecar, xmpIsNewer);
+
+ result = true;
+
+ }
+
+ catch (dng_exception &except)
+ {
+
+ // Don't ignore transient errors.
+
+ if (host.IsTransientError (except.ErrorCode ()))
+ {
+
+ throw;
+
+ }
+
+ // Eat other parsing errors.
+
+ }
+
+ catch (...)
+ {
+
+ // Eat unknown parsing exceptions.
+
+ }
+
+ return result;
+
+ }
- fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
- fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
+/*****************************************************************************/
+
+void dng_metadata::SetEmbeddedXMP (dng_host &host,
+ const void *buffer,
+ uint32 count)
+ {
+
+ if (SetXMP (host, buffer, count))
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (buffer, count);
+
+ fEmbeddedXMPDigest = printer.Result ();
+
+ // Remove any sidecar specific tags from embedded XMP.
+
+ if (fXMP.Get ())
+ {
+
+ fXMP->Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
+ fXMP->Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
+
+ }
+
+ }
+
+ else
+ {
+
+ fEmbeddedXMPDigest.Clear ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_metadata::SynchronizeMetadata ()
+ {
+
+ DNG_REQUIRE (fExif.Get (),
+ "Expected valid fExif field in "
+ "dng_metadata::SynchronizeMetadata");
+
+ if (!fOriginalExif.Get ())
+ {
+
+ fOriginalExif.Reset (fExif->Clone ());
+
+ }
+
+ fXMP->ValidateMetadata ();
+
+ fXMP->IngestIPTC (*this, fXMPisNewer);
+
+ fXMP->SyncExif (*fExif.Get ());
+
+ fXMP->SyncOrientation (*this, fXMPinSidecar);
+
+ }
+
+/*****************************************************************************/
+
+void dng_metadata::UpdateDateTime (const dng_date_time_info &dt)
+ {
+
+ fExif->UpdateDateTime (dt);
+
+ fXMP->UpdateDateTime (dt);
+
+ }
+
+/*****************************************************************************/
+
+void dng_metadata::UpdateDateTimeToNow ()
+ {
+
+ dng_date_time_info dt;
+
+ CurrentDateTimeAndZone (dt);
+
+ UpdateDateTime (dt);
+
+ fXMP->UpdateMetadataDate (dt);
+
+ }
+
+/*****************************************************************************/
+
+void dng_metadata::UpdateMetadataDateTimeToNow ()
+ {
+
+ dng_date_time_info dt;
+
+ CurrentDateTimeAndZone (dt);
+
+ fXMP->UpdateMetadataDate (dt);
+
+ }
+
+/*****************************************************************************/
+
+dng_negative::dng_negative (dng_host &host)
+
+ : fAllocator (host.Allocator ())
+
+ , fModelName ()
+ , fLocalName ()
+ , fDefaultCropSizeH ()
+ , fDefaultCropSizeV ()
+ , fDefaultCropOriginH (0, 1)
+ , fDefaultCropOriginV (0, 1)
+ , fDefaultUserCropT (0, 1)
+ , fDefaultUserCropL (0, 1)
+ , fDefaultUserCropB (1, 1)
+ , fDefaultUserCropR (1, 1)
+ , fDefaultScaleH (1, 1)
+ , fDefaultScaleV (1, 1)
+ , fBestQualityScale (1, 1)
+ , fOriginalDefaultFinalSize ()
+ , fOriginalBestQualityFinalSize ()
+ , fOriginalDefaultCropSizeH ()
+ , fOriginalDefaultCropSizeV ()
+ , fRawToFullScaleH (1.0)
+ , fRawToFullScaleV (1.0)
+ , fBaselineNoise (100, 100)
+ , fNoiseReductionApplied (0, 0)
+ , fRawNoiseReductionApplied (0, 0)
+ , fNoiseProfile ()
+ , fRawNoiseProfile ()
+ , fBaselineExposure ( 0, 100)
+ , fBaselineSharpness (100, 100)
+ , fRawBaselineSharpness (0, 0)
+ , fChromaBlurRadius ()
+ , fAntiAliasStrength (100, 100)
+ , fLinearResponseLimit (100, 100)
+ , fShadowScale (1, 1)
+ , fColorimetricReference (crSceneReferred)
+ , fFloatingPoint (false)
+ , fColorChannels (0)
+ , fAnalogBalance ()
+ , fCameraNeutral ()
+ , fCameraWhiteXY ()
+ , fCameraCalibration1 ()
+ , fCameraCalibration2 ()
+ , fCameraCalibrationSignature ()
+ , fCameraProfile ()
+ , fAsShotProfileName ()
+ , fRawImageDigest ()
+ , fNewRawImageDigest ()
+ , fRawDataUniqueID ()
+ , fOriginalRawFileName ()
+ , fHasOriginalRawFileData (false)
+ , fOriginalRawFileData ()
+ , fOriginalRawFileDigest ()
+ , fDNGPrivateData ()
+ , fMetadata (host)
+ , fLinearizationInfo ()
+ , fMosaicInfo ()
+ , fOpcodeList1 (1)
+ , fOpcodeList2 (2)
+ , fOpcodeList3 (3)
+ , fStage1Image ()
+ , fStage2Image ()
+ , fStage3Image ()
+ , fStage3Gain (1.0)
+ , fStage3BlackLevel (0)
+ , fIsPreview (false)
+ , fIsDamaged (false)
+ , fRawImageStage (rawImageStageNone)
+ , fRawImage ()
+ , fRawImageBlackLevel (0)
+ , fRawFloatBitDepth (0)
+ , fRawJPEGImage ()
+ , fRawJPEGImageDigest ()
+ , fTransparencyMask ()
+ , fRawTransparencyMask ()
+ , fRawTransparencyMaskBitDepth (0)
+ , fUnflattenedStage3Image ()
+ , fHasDepthMap (false)
+ , fDepthMap ()
+ , fRawDepthMap ()
+ , fDepthFormat (depthFormatUnknown)
+ , fDepthNear (0, 0)
+ , fDepthFar (0, 0)
+ , fDepthUnits (depthUnitsUnknown)
+ , fDepthMeasureType (depthMeasureUnknown)
+ , fEnhanceParams ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_negative::~dng_negative ()
+ {
+
+ // Delete any camera profiles owned by this negative.
+
+ ClearProfiles ();
+
+ }
+/******************************************************************************/
+
+void dng_negative::Initialize ()
+ {
+
+ }
+
+/******************************************************************************/
+
+dng_negative * dng_negative::Make (dng_host &host)
+ {
+
+ AutoPtr<dng_negative> result (new dng_negative (host));
+
+ if (!result.Get ())
+ {
+ ThrowMemoryFull ();
}
+
+ result->Initialize ();
+
+ return result.Release ();
+
+ }
+
+/******************************************************************************/
+
+dng_metadata * dng_negative::CloneInternalMetadata () const
+ {
+
+ return InternalMetadata ().Clone (Allocator ());
+
+ }
+
+/******************************************************************************/
+
+dng_orientation dng_negative::ComputeOrientation (const dng_metadata &metadata) const
+ {
+
+ return metadata.BaseOrientation ();
+
+ }
+
+/******************************************************************************/
+void dng_negative::SetAnalogBalance (const dng_vector &b)
+ {
+
+ real64 minEntry = b.MinEntry ();
+
+ if (b.NotEmpty () && minEntry > 0.0)
+ {
+
+ fAnalogBalance = b;
+
+ fAnalogBalance.Scale (1.0 / minEntry);
+
+ fAnalogBalance.Round (1000000.0);
+
+ }
+
else
{
+
+ fAnalogBalance.Clear ();
+
+ }
+
+ }
+
+/*****************************************************************************/
- fCameraWhiteXY.Clear ();
+real64 dng_negative::AnalogBalance (uint32 channel) const
+ {
+
+ DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
+
+ if (channel < fAnalogBalance.Count ())
+ {
+
+ return fAnalogBalance [channel];
+
+ }
+
+ return 1.0;
+
+ }
+
+/*****************************************************************************/
+
+dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
+ {
+
+ dng_urational result;
+
+ result.Set_real64 (AnalogBalance (channel), 1000000);
+
+ return result;
+
+ }
+
+/******************************************************************************/
+void dng_negative::SetCameraNeutral (const dng_vector &n)
+ {
+
+ real64 maxEntry = n.MaxEntry ();
+
+ if (n.NotEmpty () && maxEntry > 0.0)
+ {
+
+ fCameraNeutral = n;
+
+ fCameraNeutral.Scale (1.0 / maxEntry);
+
+ fCameraNeutral.Round (1000000.0);
+
+ }
+
+ else
+ {
+
+ fCameraNeutral.Clear ();
+
}
}
+
+/*****************************************************************************/
+
+dng_urational dng_negative::CameraNeutralR (uint32 channel) const
+ {
+
+ dng_urational result;
+
+ result.Set_real64 (CameraNeutral () [channel], 1000000);
+
+ return result;
+
+ }
+
+/******************************************************************************/
+void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
+ {
+
+ if (coord.IsValid ())
+ {
+
+ fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
+ fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
+
+ }
+
+ else
+ {
+
+ fCameraWhiteXY.Clear ();
+
+ }
+
+ }
+
/*****************************************************************************/
const dng_xy_coord & dng_negative::CameraWhiteXY () const
{
-
+
DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY");
return fCameraWhiteXY;
-
+
}
-
+
/*****************************************************************************/
void dng_negative::GetCameraWhiteXY (dng_urational &x,
dng_urational &y) const
{
-
+
dng_xy_coord coord = CameraWhiteXY ();
-
+
x.Set_real64 (coord.x, 1000000);
y.Set_real64 (coord.y, 1000000);
-
+
}
-
+
/*****************************************************************************/
void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
{
-
+
fCameraCalibration1 = m;
-
+
fCameraCalibration1.Round (10000);
-
+
}
/******************************************************************************/
void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
{
-
+
fCameraCalibration2 = m;
-
+
fCameraCalibration2.Round (10000);
-
+
}
/******************************************************************************/
void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile)
{
-
+
// Make sure we have a profile to add.
-
+
if (!profile.Get ())
{
-
+
return;
-
+
}
-
+
// We must have some profile name. Use "embedded" if nothing else.
-
+
if (profile->Name ().IsEmpty ())
{
-
+
profile->SetName (kProfileName_Embedded);
-
+
}
-
+
// Special case support for reading older DNG files which did not store
// the profile name in the main IFD profile.
-
+
if (fCameraProfile.size ())
{
-
+
// See the first profile has a default "embedded" name, and has
// the same data as the profile we are adding.
-
+
if (fCameraProfile [0]->NameIsEmbedded () &&
fCameraProfile [0]->EqualData (*profile.Get ()))
{
-
+
// If the profile we are deleting was read from DNG
// then the new profile should be marked as such also.
-
+
if (fCameraProfile [0]->WasReadFromDNG ())
{
-
+
profile->SetWasReadFromDNG ();
-
+
}
-
+
+ // If the profile we are deleting wasn't read from disk then the new
+ // profile should be marked as such also.
+
+ if (!fCameraProfile [0]->WasReadFromDisk ())
+ {
+
+ profile->SetWasReadFromDisk (false);
+
+ }
+
// Delete the profile with default name.
-
+
delete fCameraProfile [0];
-
+
fCameraProfile [0] = NULL;
-
+
fCameraProfile.erase (fCameraProfile.begin ());
-
+
}
-
+
}
-
+
// Duplicate detection logic. We give a preference to last added profile
// so the profiles end up in a more consistent order no matter what profiles
// happen to be embedded in the DNG.
-
+
for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
{
// Instead of checking for matching fingerprints, we check that the two
// profiles have the same color and have the same name. This allows two
// profiles that are identical except for copyright string and embed policy
// to be considered duplicates.
const bool equalColorAndSameName = (fCameraProfile [index]->EqualData (*profile.Get ()) &&
fCameraProfile [index]->Name () == profile->Name ());
if (equalColorAndSameName)
{
-
+
// If the profile we are deleting was read from DNG
// then the new profile should be marked as such also.
-
+
if (fCameraProfile [index]->WasReadFromDNG ())
{
-
+
profile->SetWasReadFromDNG ();
-
+
}
-
+
+ // If the profile we are deleting wasn't read from disk then the new
+ // profile should be marked as such also.
+
+ if (!fCameraProfile [index]->WasReadFromDisk ())
+ {
+
+ profile->SetWasReadFromDisk (false);
+
+ }
+
// Delete the duplicate profile.
-
+
delete fCameraProfile [index];
-
+
fCameraProfile [index] = NULL;
-
+
fCameraProfile.erase (fCameraProfile.begin () + index);
-
+
break;
-
+
}
-
+
}
-
+
// Now add to profile list.
-
+
fCameraProfile.push_back (NULL);
-
+
fCameraProfile [fCameraProfile.size () - 1] = profile.Release ();
-
+
}
-
+
/******************************************************************************/
void dng_negative::ClearProfiles ()
{
-
+
// Delete any camera profiles owned by this negative.
-
+
for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
{
-
+
if (fCameraProfile [index])
{
-
+
delete fCameraProfile [index];
-
+
fCameraProfile [index] = NULL;
-
+
}
-
+
}
-
+
// Now empty list.
-
+
fCameraProfile.clear ();
-
+
}
-/******************************************************************************/
+/*****************************************************************************/
-uint32 dng_negative::ProfileCount () const
+void dng_negative::ClearProfiles (bool clearBuiltinMatrixProfiles,
+ bool clearReadFromDisk)
{
- return (uint32) fCameraProfile.size ();
+ // If neither flag is set, then there's nothing to do.
- }
+ if (!clearBuiltinMatrixProfiles &&
+ !clearReadFromDisk)
+ {
+ return;
+ }
+
+ // Delete any camera profiles in this negative that match the specified criteria.
-/******************************************************************************/
+ dng_std_vector<dng_camera_profile *>::iterator iter = fCameraProfile.begin ();
+ dng_std_vector<dng_camera_profile *>::iterator next;
+
+ for (; iter != fCameraProfile.end (); iter = next)
+ {
-const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
- {
+ dng_camera_profile *profile = *iter;
- DNG_ASSERT (index < ProfileCount (),
- "Invalid index for ProfileByIndex");
+ // If the profile is invalid (i.e., NULL pointer), or meets one of the
+ // specified criteria, then axe it.
- return *fCameraProfile [index];
+ if (!profile ||
+ (clearBuiltinMatrixProfiles && profile->WasBuiltinMatrix ()) ||
+ (clearReadFromDisk && profile->WasReadFromDisk ()))
+ {
+
+ delete profile;
+ next = fCameraProfile.erase (iter);
+
+ }
+
+ // Otherwise, just advance to the next element.
+
+ else
+ {
+
+ next = iter + 1;
+
+ }
+
+ }
+
+ }
+
+/******************************************************************************/
+
+uint32 dng_negative::ProfileCount () const
+ {
+
+ return (uint32) fCameraProfile.size ();
+
}
+
+/******************************************************************************/
+const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
+ {
+
+ DNG_ASSERT (index < ProfileCount (),
+ "Invalid index for ProfileByIndex");
+
+ return *fCameraProfile [index];
+
+ }
+
/*****************************************************************************/
const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id,
bool useDefaultIfNoMatch) const
{
-
+
uint32 index;
-
+
// If this negative does not have any profiles, we are not going to
// find a match.
-
+
uint32 profileCount = ProfileCount ();
-
+
if (profileCount == 0)
{
return NULL;
}
-
+
// If we have both a profile name and fingerprint, try matching both.
-
+
if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ())
{
-
+
for (index = 0; index < profileCount; index++)
{
-
+
const dng_camera_profile &profile = ProfileByIndex (index);
-
+
if (id.Name () == profile.Name () &&
id.Fingerprint () == profile.Fingerprint ())
{
-
+
return &profile;
-
+
}
-
+
}
}
-
+
// If we have a name, try matching that.
-
+
if (id.Name ().NotEmpty ())
{
-
+
for (index = 0; index < profileCount; index++)
{
-
+
const dng_camera_profile &profile = ProfileByIndex (index);
-
+
if (id.Name () == profile.Name ())
{
-
+
return &profile;
-
+
}
-
+
}
}
-
+
// If we have a valid fingerprint, try matching that.
-
+
if (id.Fingerprint ().IsValid ())
{
-
+
for (index = 0; index < profileCount; index++)
{
-
+
const dng_camera_profile &profile = ProfileByIndex (index);
-
+
if (id.Fingerprint () == profile.Fingerprint ())
{
-
+
return &profile;
-
+
}
-
+
}
}
-
+
// Try "upgrading" profile name versions.
-
+
if (id.Name ().NotEmpty ())
{
-
+
dng_string baseName;
int32 version;
-
+
SplitCameraProfileName (id.Name (),
baseName,
version);
-
+
int32 bestIndex = -1;
int32 bestVersion = 0;
-
+
for (index = 0; index < profileCount; index++)
{
-
+
const dng_camera_profile &profile = ProfileByIndex (index);
-
+
if (profile.Name ().StartsWith (baseName.Get ()))
{
-
+
dng_string testBaseName;
int32 testVersion;
-
+
SplitCameraProfileName (profile.Name (),
testBaseName,
testVersion);
-
+
if (bestIndex == -1 || testVersion > bestVersion)
{
-
+
bestIndex = index;
bestVersion = testVersion;
-
+
}
-
+
}
-
+
}
-
+
if (bestIndex != -1)
{
-
+
return &ProfileByIndex (bestIndex);
-
+
}
-
+
}
-
+
// Did not find a match any way. See if we should return a default value.
-
+
if (useDefaultIfNoMatch)
{
-
+
return &ProfileByIndex (0);
-
+
}
-
+
// Found nothing.
-
+
return NULL;
-
+
}
/*****************************************************************************/
-const dng_camera_profile * dng_negative::CameraProfileToEmbed () const
+const dng_camera_profile * dng_negative::ComputeCameraProfileToEmbed
+ (const dng_metadata & /* metadata */) const
{
-
+
uint32 index;
-
+
uint32 count = ProfileCount ();
-
+
if (count == 0)
{
-
+
return NULL;
-
+
}
-
+
// First try to look for the first profile that was already in the DNG
// when we read it.
-
+
for (index = 0; index < count; index++)
{
-
+
const dng_camera_profile &profile (ProfileByIndex (index));
-
+
if (profile.WasReadFromDNG ())
{
-
+
return &profile;
-
+
}
-
+
}
-
+
// Next we look for the first profile that is legal to embed.
-
+
for (index = 0; index < count; index++)
{
-
+
const dng_camera_profile &profile (ProfileByIndex (index));
-
+
if (profile.IsLegalToEmbed ())
{
-
+
return &profile;
-
+
}
-
+
}
-
+
// Else just return the first profile.
-
+
return fCameraProfile [0];
-
+
}
-
+
/*****************************************************************************/
dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const
{
dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id));
-
+
if (!spec)
{
ThrowMemoryFull ();
}
-
+
return spec;
-
+
}
+
+/*****************************************************************************/
+
+dng_fingerprint dng_negative::FindImageDigest (dng_host &host,
+ const dng_image &image)
+ {
+
+ dng_md5_printer printer;
+
+ dng_pixel_buffer buffer (image.Bounds (),
+ 0,
+ image.Planes (),
+ image.PixelType (),
+ pcInterleaved,
+ NULL);
+
+ // Sometimes we expand 8-bit data to 16-bit data while reading or
+ // writing, so always compute the digest of 8-bit data as 16-bits.
+
+ if (buffer.fPixelType == ttByte)
+ {
+ buffer.fPixelType = ttShort;
+ buffer.fPixelSize = 2;
+ }
+
+ const uint32 kBufferRows = 16;
+
+ uint32 bufferBytes = 0;
+
+ if (!SafeUint32Mult (kBufferRows, buffer.fRowStep, &bufferBytes) ||
+ !SafeUint32Mult (bufferBytes, buffer.fPixelSize, &bufferBytes))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
+ AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
+
+ buffer.fData = bufferData->Buffer ();
+
+ dng_rect area;
+
+ dng_tile_iterator iter (dng_point (kBufferRows,
+ image.Width ()),
+ image.Bounds ());
+
+ while (iter.GetOneTile (area))
+ {
+
+ host.SniffForAbort ();
+
+ buffer.fArea = area;
+
+ image.Get (buffer);
+
+ uint32 count = buffer.fArea.H () *
+ buffer.fRowStep *
+ buffer.fPixelSize;
+
+ #if qDNGBigEndian
+
+ // We need to use the same byte order to compute
+ // the digest, no matter the native order. Little-endian
+ // is more common now, so use that.
+
+ switch (buffer.fPixelSize)
+ {
+
+ case 1:
+ break;
+
+ case 2:
+ {
+ DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
+ break;
+ }
+
+ case 4:
+ {
+ DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
+ break;
+ }
+
+ default:
+ {
+ DNG_REPORT ("Unexpected pixel size");
+ break;
+ }
+
+ }
+
+ #endif
+ printer.Process (buffer.fData,
+ count);
+
+ }
+
+ return printer.Result ();
+
+ }
+
/*****************************************************************************/
void dng_negative::FindRawImageDigest (dng_host &host) const
{
-
+
if (fRawImageDigest.IsNull ())
{
-
- const dng_image &image = RawImage ();
-
- dng_md5_printer printer;
-
- dng_pixel_buffer buffer;
-
- buffer.fPlane = 0;
- buffer.fPlanes = image.Planes ();
-
- buffer.fRowStep = image.Planes () * image.Width ();
- buffer.fColStep = image.Planes ();
- buffer.fPlaneStep = 1;
-
- buffer.fPixelType = image.PixelType ();
- buffer.fPixelSize = image.PixelSize ();
-
- // Sometimes we expand 8-bit data to 16-bit data while reading or
- // writing, so always compute the digest of 8-bit data as 16-bits.
-
- if (buffer.fPixelType == ttByte)
+
+ // Since we are adding the floating point and transparency support
+ // in DNG 1.4, and there are no legacy floating point or transparent
+ // DNGs, switch to using the more MP friendly algorithm to compute
+ // the digest for these images.
+
+ if (RawImage ().PixelType () == ttFloat || RawTransparencyMask ())
{
- buffer.fPixelType = ttShort;
- buffer.fPixelSize = 2;
+
+ FindNewRawImageDigest (host);
+
+ fRawImageDigest = fNewRawImageDigest;
+
}
-
- const uint32 kBufferRows = 16;
-
- uint32 bufferBytes = kBufferRows * buffer.fRowStep * buffer.fPixelSize;
-
- AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
-
- buffer.fData = bufferData->Buffer ();
-
- dng_rect area;
-
- dng_tile_iterator iter (dng_point (kBufferRows,
- image.Width ()),
- image.Bounds ());
-
- while (iter.GetOneTile (area))
+
+ else
{
+
+ #if qDNGValidate
+
+ dng_timer timeScope ("FindRawImageDigest time");
- host.SniffForAbort ();
-
- buffer.fArea = area;
+ #endif
+
+ fRawImageDigest = FindImageDigest (host, RawImage ());
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
- image.Get (buffer);
+class dng_find_new_raw_image_digest_task : public dng_area_task
+ {
+
+ private:
+
+ enum
+ {
+ kTileSize = 256
+ };
+
+ const dng_image &fImage;
+
+ uint32 fPixelType;
+ uint32 fPixelSize;
+
+ uint32 fTilesAcross;
+ uint32 fTilesDown;
+
+ uint32 fTileCount;
+
+ AutoArray<dng_fingerprint> fTileHash;
+
+ AutoPtr<dng_memory_block> fBufferData [kMaxMPThreads];
+
+ public:
+
+ dng_find_new_raw_image_digest_task (const dng_image &image,
+ uint32 pixelType)
+
+ : dng_area_task ("dng_find_new_raw_image_digest_task")
+
+ , fImage (image)
+ , fPixelType (pixelType)
+ , fPixelSize (TagTypeSize (pixelType))
+ , fTilesAcross (0)
+ , fTilesDown (0)
+ , fTileCount (0)
+ , fTileHash (NULL)
+
+ {
+
+ fMinTaskArea = 1;
+
+ fUnitCell = dng_point (Min_int32 (kTileSize, fImage.Bounds ().H ()),
+ Min_int32 (kTileSize, fImage.Bounds ().W ()));
+
+ fMaxTileSize = fUnitCell;
+
+ }
+
+ virtual void Start (uint32 threadCount,
+ const dng_rect & /* dstArea */,
+ const dng_point &tileSize,
+ dng_memory_allocator *allocator,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ if (tileSize != fUnitCell)
+ {
+ ThrowProgramError ();
+ }
+
+ fTilesAcross = (fImage.Bounds ().W () + fUnitCell.h - 1) / fUnitCell.h;
+ fTilesDown = (fImage.Bounds ().H () + fUnitCell.v - 1) / fUnitCell.v;
+
+ fTileCount = fTilesAcross * fTilesDown;
+
+ fTileHash.Reset (new dng_fingerprint [fTileCount]);
+
+ const uint32 bufferSize =
+ ComputeBufferSize (fPixelType,
+ tileSize,
+ fImage.Planes (),
+ padNone);
+
+ for (uint32 index = 0; index < threadCount; index++)
+ {
+
+ fBufferData [index].Reset (allocator->Allocate (bufferSize));
+
+ }
+
+ }
- uint32 count = buffer.fArea.H () *
- buffer.fRowStep *
+ virtual void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ int32 colIndex = (tile.l - fImage.Bounds ().l) / fUnitCell.h;
+ int32 rowIndex = (tile.t - fImage.Bounds ().t) / fUnitCell.v;
+
+ DNG_ASSERT (tile.l == fImage.Bounds ().l + colIndex * fUnitCell.h &&
+ tile.t == fImage.Bounds ().t + rowIndex * fUnitCell.v,
+ "Bad tile origin");
+
+ uint32 tileIndex = rowIndex * fTilesAcross + colIndex;
+
+ dng_pixel_buffer buffer (tile,
+ 0,
+ fImage.Planes (),
+ fPixelType,
+ pcPlanar,
+ fBufferData [threadIndex]->Buffer ());
+
+ fImage.Get (buffer);
+
+ uint32 count = buffer.fPlaneStep *
+ buffer.fPlanes *
buffer.fPixelSize;
-
+
#if qDNGBigEndian
-
+
// We need to use the same byte order to compute
// the digest, no matter the native order. Little-endian
// is more common now, so use that.
-
+
switch (buffer.fPixelSize)
{
-
+
case 1:
break;
-
+
case 2:
{
DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
break;
}
-
+
case 4:
{
DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
break;
}
-
+
default:
{
DNG_REPORT ("Unexpected pixel size");
break;
}
-
+
}
#endif
-
- printer.Process (buffer.fData,
- count);
-
+
+ dng_md5_printer printer;
+
+ printer.Process (buffer.fData, count);
+
+ fTileHash [tileIndex] = printer.Result ();
+
}
-
- fRawImageDigest = printer.Result ();
-
- }
-
- }
+
+ dng_fingerprint Result ()
+ {
+
+ dng_md5_printer printer;
+
+ for (uint32 tileIndex = 0; tileIndex < fTileCount; tileIndex++)
+ {
+
+ printer.Process (fTileHash [tileIndex] . data, 16);
+
+ }
+
+ return printer.Result ();
+
+ }
+
+ };
/*****************************************************************************/
-void dng_negative::ValidateRawImageDigest (dng_host &host)
+void dng_negative::FindNewRawImageDigest (dng_host &host) const
{
-
- if (Stage1Image () && !IsPreview () && fRawImageDigest.IsValid ())
+
+ if (fNewRawImageDigest.IsNull ())
{
+
+ #if qDNGValidate
+
+ dng_timer timeScope ("FindNewRawImageDigest time");
- dng_fingerprint oldDigest = fRawImageDigest;
-
- try
+ #endif
+
+ // Find fast digest of the raw image.
+
{
+
+ const dng_image &rawImage = RawImage ();
+
+ // Find pixel type that will be saved in the file. When saving DNGs, we convert
+ // some 16-bit data to 8-bit data, so we need to do the matching logic here.
+
+ uint32 rawPixelType = rawImage.PixelType ();
+
+ if (rawPixelType == ttShort)
+ {
+
+ // See if we are using a linearization table with <= 256 entries, in which
+ // case the useful data will all fit within 8-bits.
+
+ const dng_linearization_info *rangeInfo = GetLinearizationInfo ();
+
+ if (rangeInfo)
+ {
- fRawImageDigest.Clear ();
-
- FindRawImageDigest (host);
+ if (rangeInfo->fLinearizationTable.Get ())
+ {
+
+ uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
+
+ if (entries <= 256)
+ {
+
+ rawPixelType = ttByte;
+
+ }
+
+ }
+
+ }
+ }
+
+ // Find the fast digest on the raw image.
+
+ dng_find_new_raw_image_digest_task task (rawImage, rawPixelType);
+
+ host.PerformAreaTask (task, rawImage.Bounds ());
+
+ fNewRawImageDigest = task.Result ();
+
}
-
- catch (...)
+
+ // If there is a transparancy mask, we need to include that in the
+ // digest also.
+
+ if (RawTransparencyMask () != NULL)
{
-
- fRawImageDigest = oldDigest;
-
- throw;
-
+
+ // Find the fast digest on the raw mask.
+
+ dng_fingerprint maskDigest;
+
+ {
+
+ dng_find_new_raw_image_digest_task task (*RawTransparencyMask (),
+ RawTransparencyMask ()->PixelType ());
+
+ host.PerformAreaTask (task, RawTransparencyMask ()->Bounds ());
+
+ maskDigest = task.Result ();
+
+ }
+
+ // Combine the two digests into a single digest.
+
+ dng_md5_printer printer;
+
+ printer.Process (fNewRawImageDigest.data, 16);
+
+ printer.Process (maskDigest.data, 16);
+
+ fNewRawImageDigest = printer.Result ();
+
}
+
+ }
+
+ }
+
+/*****************************************************************************/
- if (oldDigest != fRawImageDigest)
+void dng_negative::ValidateRawImageDigest (dng_host &host)
+ {
+
+ if (Stage1Image () && !IsPreview () && (fRawImageDigest .IsValid () ||
+ fNewRawImageDigest.IsValid ()))
+ {
+
+ bool isNewDigest = fNewRawImageDigest.IsValid ();
+
+ dng_fingerprint &rawDigest = isNewDigest ? fNewRawImageDigest
+ : fRawImageDigest;
+
+ // For lossy compressed JPEG images, we need to compare the stored
+ // digest to the digest computed from the compressed data, since
+ // decompressing lossy JPEG data is itself a lossy process.
+
+ if (RawJPEGImageDigest ().IsValid () || RawJPEGImage ())
{
-
- #if qDNGValidate
-
- ReportError ("RawImageDigest does not match raw image");
-
- #else
-
- // Note that Lightroom 1.4 Windows had a bug that corrupts the
- // first four bytes of the RawImageDigest tag. So if the last
- // twelve bytes match, this is very likely the result of the
- // bug, and not an actual corrupt file. So don't report this
- // to the user--just fix it.
-
+
+ // Compute the raw JPEG image digest if we have not done so
+ // already.
+
+ FindRawJPEGImageDigest (host);
+
+ if (rawDigest != RawJPEGImageDigest ())
{
-
- bool matchLast12 = true;
-
- for (uint32 j = 4; j < 16; j++)
+
+ #if qDNGValidate
+
+ ReportError ("RawImageDigest does not match raw jpeg image");
+
+ #else
+
+ SetIsDamaged (true);
+
+ #endif
+
+ }
+
+ }
+
+ // Else we can compare the stored digest to the image in memory.
+
+ else
+ {
+
+ dng_fingerprint oldDigest = rawDigest;
+
+ try
+ {
+
+ rawDigest.Clear ();
+
+ if (isNewDigest)
{
- matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
+
+ FindNewRawImageDigest (host);
+
}
-
- if (matchLast12)
+
+ else
{
- return;
+
+ FindRawImageDigest (host);
+
}
-
+
}
-
- // Sometimes Lightroom 1.4 would corrupt more than the first four
- // bytes, but for all those files that I have seen so far the
- // resulting first four bytes are 0x08 0x00 0x00 0x00.
-
- if (oldDigest.data [0] == 0x08 &&
- oldDigest.data [1] == 0x00 &&
- oldDigest.data [2] == 0x00 &&
- oldDigest.data [3] == 0x00)
+
+ catch (...)
{
- return;
+
+ rawDigest = oldDigest;
+
+ throw;
+
}
-
- SetIsDamaged (true);
-
- #endif
-
+
+ if (oldDigest != rawDigest)
+ {
+
+ #if qDNGValidate
+
+ if (isNewDigest)
+ {
+ ReportError ("NewRawImageDigest does not match raw image");
+ }
+ else
+ {
+ ReportError ("RawImageDigest does not match raw image");
+ }
+
+ SetIsDamaged (true);
+
+ #else
+
+ if (!isNewDigest)
+ {
+
+ // Note that Lightroom 1.4 Windows had a bug that corrupts the
+ // first four bytes of the RawImageDigest tag. So if the last
+ // twelve bytes match, this is very likely the result of the
+ // bug, and not an actual corrupt file. So don't report this
+ // to the user--just fix it.
+
+ {
+
+ bool matchLast12 = true;
+
+ for (uint32 j = 4; j < 16; j++)
+ {
+ matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
+ }
+
+ if (matchLast12)
+ {
+ return;
+ }
+
+ }
+
+ // Sometimes Lightroom 1.4 would corrupt more than the first four
+ // bytes, but for all those files that I have seen so far the
+ // resulting first four bytes are 0x08 0x00 0x00 0x00.
+
+ if (oldDigest.data [0] == 0x08 &&
+ oldDigest.data [1] == 0x00 &&
+ oldDigest.data [2] == 0x00 &&
+ oldDigest.data [3] == 0x00)
+ {
+ return;
+ }
+
+ }
+
+ SetIsDamaged (true);
+
+ #endif
+
+ }
+
}
-
+
}
-
+
}
/*****************************************************************************/
+dng_fingerprint dng_negative::RawDataUniqueID () const
+ {
+
+ dng_lock_std_mutex lock (fRawDataUniqueIDMutex);
+
+ if (fRawDataUniqueID.IsValid () && fEnhanceParams.NotEmpty ())
+ {
+
+ dng_md5_printer printer;
+
+ printer.Process (fRawDataUniqueID.data, 16);
+
+ printer.Process (fEnhanceParams.Get (),
+ fEnhanceParams.Length ());
+
+ return printer.Result ();
+
+ }
+
+ return fRawDataUniqueID;
+
+ }
+
+/*****************************************************************************/
+
// If the raw data unique ID is missing, compute one based on a MD5 hash of
-// the raw image data and the model name, plus other commonly changed
+// the raw image hash and the model name, plus other commonly changed
// data that can affect rendering.
void dng_negative::FindRawDataUniqueID (dng_host &host) const
{
-
- if (fRawDataUniqueID.IsNull ())
+
+ if (RawDataUniqueID ().IsNull ())
{
-
- FindRawImageDigest (host);
-
+
dng_md5_printer_stream printer;
-
- printer.SetBigEndian ();
-
- // Include the raw image digest in the unique ID.
-
- printer.Put (fRawImageDigest.data, 16);
-
+
+ // If we have a raw jpeg image, it is much faster to
+ // use its digest as part of the unique ID since
+ // the data size is much smaller. We cannot use it
+ // if there a transparency mask, since that is not
+ // included in the RawJPEGImageDigest.
+
+ if (RawJPEGImage () && !RawTransparencyMask ())
+ {
+
+ FindRawJPEGImageDigest (host);
+
+ printer.Put (fRawJPEGImageDigest.data, 16);
+
+ }
+
+ // Include the new raw image digest in the unique ID.
+
+ else
+ {
+
+ FindNewRawImageDigest (host);
+
+ printer.Put (fNewRawImageDigest.data, 16);
+
+ }
+
// Include model name.
-
+
printer.Put (ModelName ().Get (),
ModelName ().Length ());
-
+
// Include default crop area, since DNG Recover Edges can modify
// these values and they affect rendering.
-
+
printer.Put_uint32 (fDefaultCropSizeH.n);
printer.Put_uint32 (fDefaultCropSizeH.d);
-
+
printer.Put_uint32 (fDefaultCropSizeV.n);
printer.Put_uint32 (fDefaultCropSizeV.d);
-
+
printer.Put_uint32 (fDefaultCropOriginH.n);
printer.Put_uint32 (fDefaultCropOriginH.d);
-
+
printer.Put_uint32 (fDefaultCropOriginV.n);
printer.Put_uint32 (fDefaultCropOriginV.d);
+ // Include default user crop.
+
+ printer.Put_uint32 (fDefaultUserCropT.n);
+ printer.Put_uint32 (fDefaultUserCropT.d);
+
+ printer.Put_uint32 (fDefaultUserCropL.n);
+ printer.Put_uint32 (fDefaultUserCropL.d);
+
+ printer.Put_uint32 (fDefaultUserCropB.n);
+ printer.Put_uint32 (fDefaultUserCropB.d);
+
+ printer.Put_uint32 (fDefaultUserCropR.n);
+ printer.Put_uint32 (fDefaultUserCropR.d);
+
// Include opcode lists, since lens correction utilities can modify
// these values and they affect rendering.
-
+
fOpcodeList1.FingerprintToStream (printer);
fOpcodeList2.FingerprintToStream (printer);
fOpcodeList3.FingerprintToStream (printer);
-
+
+ dng_lock_std_mutex lock (fRawDataUniqueIDMutex);
+
fRawDataUniqueID = printer.Result ();
-
+
}
-
+
}
-
+
/******************************************************************************/
// Forces recomputation of RawDataUniqueID, useful to call
// after modifying the opcode lists, etc.
void dng_negative::RecomputeRawDataUniqueID (dng_host &host)
{
-
+
fRawDataUniqueID.Clear ();
-
+
FindRawDataUniqueID (host);
-
+
}
-
+
/******************************************************************************/
void dng_negative::FindOriginalRawFileDigest () const
{
if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ())
{
-
+
dng_md5_printer printer;
-
+
printer.Process (fOriginalRawFileData->Buffer (),
fOriginalRawFileData->LogicalSize ());
-
+
fOriginalRawFileDigest = printer.Result ();
-
+
}
}
-
+
/*****************************************************************************/
void dng_negative::ValidateOriginalRawFileDigest ()
{
-
+
if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ())
{
-
+
dng_fingerprint oldDigest = fOriginalRawFileDigest;
-
+
try
{
-
+
fOriginalRawFileDigest.Clear ();
-
+
FindOriginalRawFileDigest ();
-
+
}
-
+
catch (...)
{
-
+
fOriginalRawFileDigest = oldDigest;
-
+
throw;
-
+
}
-
+
if (oldDigest != fOriginalRawFileDigest)
{
-
+
#if qDNGValidate
-
+
ReportError ("OriginalRawFileDigest does not match OriginalRawFileData");
-
+
#else
-
+
SetIsDamaged (true);
-
+
#endif
-
+
// Don't "repair" the original image data digest. Once it is
// bad, it stays bad. The user cannot tell by looking at the image
// whether the damage is acceptable and can be ignored in the
// future.
-
+
fOriginalRawFileDigest = oldDigest;
-
+
}
-
+
}
-
+
}
-
+
/******************************************************************************/
-dng_rect dng_negative::DefaultCropArea (real64 scaleH,
- real64 scaleV) const
+dng_rect dng_negative::DefaultCropArea () const
{
-
+
// First compute the area using simple rounding.
-
+
dng_rect result;
-
- result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH * scaleH);
- result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV * scaleV);
-
- result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH * scaleH);
- result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV * scaleV);
-
+
+ result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH);
+ result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV);
+
+ result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH);
+ result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV);
+
// Sometimes the simple rounding causes the resulting default crop
// area to slide off the scaled image area. So we force this not
// to happen. We only do this if the image is not stubbed.
-
+
const dng_image *image = Stage3Image ();
-
+
if (image)
{
-
- dng_point scaledSize;
-
- scaledSize.h = Round_int32 (image->Width () * scaleH);
- scaledSize.v = Round_int32 (image->Height () * scaleV);
-
- if (result.r > scaledSize.h)
+
+ dng_point imageSize = image->Size ();
+
+ if (result.r > imageSize.h)
{
- result.l -= result.r - scaledSize.h;
- result.r = scaledSize.h;
+ result.l -= result.r - imageSize.h;
+ result.r = imageSize.h;
}
-
- if (result.b > scaledSize.v)
+
+ if (result.b > imageSize.v)
{
- result.t -= result.b - scaledSize.v;
- result.b = scaledSize.v;
+ result.t -= result.b - imageSize.v;
+ result.b = imageSize.v;
}
-
+
}
-
+
return result;
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_negative::TotalBaselineExposure (const dng_camera_profile_id &profileID) const
+ {
+
+ real64 total = BaselineExposure ();
+
+ const dng_camera_profile *profile = ProfileByID (profileID);
+
+ if (profile)
+ {
+
+ real64 offset = profile->BaselineExposureOffset ().As_real64 ();
+
+ total += offset;
+
+ }
+ return total;
+
}
/******************************************************************************/
void dng_negative::SetShadowScale (const dng_urational &scale)
{
-
+
if (scale.d > 0)
{
-
+
real64 s = scale.As_real64 ();
-
+
if (s > 0.0 && s <= 1.0)
{
-
+
fShadowScale = scale;
-
+
}
-
+
}
-
+
}
-
+
/******************************************************************************/
-dng_memory_block * dng_negative::BuildExifBlock (const dng_resolution *resolution,
- bool includeIPTC,
- bool minimalEXIF,
- const dng_jpeg_preview *thumbnail) const
+void dng_negative::SetActiveArea (const dng_rect &area)
{
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fActiveArea = area;
+
+ }
- dng_memory_stream stream (Allocator ());
+/******************************************************************************/
+void dng_negative::SetMaskedAreas (uint32 count,
+ const dng_rect *area)
+ {
+
+ DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas");
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas);
+
+ for (uint32 index = 0; index < info.fMaskedAreaCount; index++)
{
+
+ info.fMaskedArea [index] = area [index];
+
+ }
+
+ }
+
+/*****************************************************************************/
- // Create the main IFD
-
- dng_tiff_directory mainIFD;
-
- // Optionally include the resolution tags.
+void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve)
+ {
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fLinearizationTable.Reset (curve.Release ());
+
+ }
+
+/*****************************************************************************/
- dng_resolution res;
+void dng_negative::SetBlackLevel (real64 black,
+ int32 plane)
+ {
- if (resolution)
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fBlackLevelRepeatRows = 1;
+ info.fBlackLevelRepeatCols = 1;
+
+ if (plane < 0)
+ {
+
+ for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
{
- res = *resolution;
+
+ info.fBlackLevel [0] [0] [j] = black;
+
}
+
+ }
+
+ else
+ {
+
+ info.fBlackLevel [0] [0] [plane] = black;
+
+ }
+
+ info.RoundBlacks ();
+
+ }
+
+/*****************************************************************************/
- tag_urational tagXResolution (tcXResolution, res.fXResolution);
- tag_urational tagYResolution (tcYResolution, res.fYResolution);
-
- tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
+void dng_negative::SetQuadBlacks (real64 black0,
+ real64 black1,
+ real64 black2,
+ real64 black3,
+ int32 plane)
+ {
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fBlackLevelRepeatRows = 2;
+ info.fBlackLevelRepeatCols = 2;
- if (resolution)
+ if (plane < 0)
+ {
+
+ for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
{
- mainIFD.Add (&tagXResolution );
- mainIFD.Add (&tagYResolution );
- mainIFD.Add (&tagResolutionUnit);
- }
- // Optionally include IPTC block.
-
- tag_iptc tagIPTC (IPTCData (),
- IPTCLength ());
+ info.fBlackLevel [0] [0] [j] = black0;
+ info.fBlackLevel [0] [1] [j] = black1;
+ info.fBlackLevel [1] [0] [j] = black2;
+ info.fBlackLevel [1] [1] [j] = black3;
- if (includeIPTC && tagIPTC.Count ())
- {
+ }
- mainIFD.Add (&tagIPTC);
+ }
- }
+ else
+ {
+
+ info.fBlackLevel [0] [0] [plane] = black0;
+ info.fBlackLevel [0] [1] [plane] = black1;
+ info.fBlackLevel [1] [0] [plane] = black2;
+ info.fBlackLevel [1] [1] [plane] = black3;
+
+ }
+
+ info.RoundBlacks ();
+
+ }
- // Exif tags.
+/*****************************************************************************/
- dng_exif exifBlock;
+void dng_negative::Set6x6Blacks (real64 blacks6x6 [36],
+ int32 plane)
+ {
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fBlackLevelRepeatRows = 6;
+ info.fBlackLevelRepeatCols = 6;
- if (!minimalEXIF)
+ if (plane < 0)
+ {
+
+ // Apply the black levels to each image plane up to kMaxSamplesPerPixel.
+
+ for (uint32 p = 0; p < kMaxSamplesPerPixel; p++)
{
- exifBlock = *GetExif ();
+
+ uint32 m = 0;
+
+ for (uint32 r = 0; r < info.fBlackLevelRepeatRows; r++)
+ for (uint32 c = 0; c < info.fBlackLevelRepeatCols; c++)
+ {
+
+ info.fBlackLevel [r] [c] [p] = blacks6x6 [m];
+
+ m++;
+
+ }
}
+ }
+
+ else
+ {
+
+ uint32 m = 0;
+
+ // Apply the black levels to a single plane.
+
+ for (uint32 r = 0; r < info.fBlackLevelRepeatRows; r++)
+ for (uint32 c = 0; c < info.fBlackLevelRepeatCols; c++)
+ {
+
+ info.fBlackLevel [r] [c] [plane] = blacks6x6 [m];
+
+ m++;
+
+ }
+
+ }
+
+ info.RoundBlacks ();
+
+ }
- exif_tag_set exifSet (mainIFD,
- exifBlock,
- IsMakerNoteSafe () && !minimalEXIF,
- MakerNoteData (),
- MakerNoteLength (),
- false);
+/*****************************************************************************/
- // Figure out the Exif IFD offset.
+void dng_negative::SetRowBlacks (const real64 *blacks,
+ uint32 count)
+ {
+
+ if (count)
+ {
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ dng_safe_uint32 byteCount =
+ dng_safe_uint32 (count) * (uint32) sizeof (real64);
+
+ info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount.Get ()));
+
+ DoCopyBytes (blacks,
+ info.fBlackDeltaV->Buffer (),
+ byteCount.Get ());
+
+ info.RoundBlacks ();
+
+ }
+
+ else if (fLinearizationInfo.Get ())
+ {
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fBlackDeltaV.Reset ();
+
+ }
+
+ }
+
+/*****************************************************************************/
- uint32 exifOffset = 8 + mainIFD.Size ();
+void dng_negative::SetColumnBlacks (const real64 *blacks,
+ uint32 count)
+ {
+
+ if (count)
+ {
+
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ dng_safe_uint32 byteCount =
+ dng_safe_uint32 (count) * (uint32) sizeof (real64);
+
+ info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount.Get ()));
+
+ DoCopyBytes (blacks,
+ info.fBlackDeltaH->Buffer (),
+ byteCount.Get ());
+
+ info.RoundBlacks ();
+
+ }
+
+ else if (fLinearizationInfo.Get ())
+ {
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ info.fBlackDeltaH.Reset ();
+
+ }
+
+ }
+
+/*****************************************************************************/
- exifSet.Locate (exifOffset);
+uint32 dng_negative::WhiteLevel (uint32 plane) const
+ {
+
+ if (fLinearizationInfo.Get ())
+ {
+
+ const dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ return Round_uint32 (info.fWhiteLevel [plane]);
+
+ }
+
+ if (RawImage ().PixelType () == ttFloat)
+ {
+
+ return 1;
+
+ }
+
+ return 0x0FFFF;
+
+ }
+
+/*****************************************************************************/
- // Thumbnail IFD (if any).
+void dng_negative::SetWhiteLevel (uint32 white,
+ int32 plane)
+ {
- dng_tiff_directory thumbIFD;
-
- tag_uint16 thumbCompression (tcCompression, ccOldJPEG);
-
- tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1));
- tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1));
-
- tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch);
-
- tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat , 0);
- tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0);
-
- if (thumbnail)
- {
-
- thumbIFD.Add (&thumbCompression);
-
- thumbIFD.Add (&thumbXResolution);
- thumbIFD.Add (&thumbYResolution);
- thumbIFD.Add (&thumbResolutionUnit);
-
- thumbIFD.Add (&thumbDataOffset);
- thumbIFD.Add (&thumbDataLength);
-
- thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ());
-
- uint32 thumbOffset = exifOffset + exifSet.Size ();
-
- mainIFD.SetChained (thumbOffset);
-
- thumbDataOffset.Set (thumbOffset + thumbIFD.Size ());
-
- }
-
- // Don't write anything unless the main IFD has some tags.
-
- if (mainIFD.Size () != 0)
- {
-
- // Write TIFF Header.
-
- stream.SetWritePosition (0);
-
- stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
-
- stream.Put_uint16 (42);
-
- stream.Put_uint32 (8);
-
- // Write the IFDs.
-
- mainIFD.Put (stream);
-
- exifSet.Put (stream);
-
- if (thumbnail)
- {
-
- thumbIFD.Put (stream);
-
- stream.Put (thumbnail->fCompressedData->Buffer (),
- thumbnail->fCompressedData->LogicalSize ());
-
- }
-
- // Trim the file to this length.
-
- stream.Flush ();
-
- stream.SetLength (stream.Position ());
-
- }
-
- }
-
- return stream.AsMemoryBlock (Allocator ());
-
- }
-
-/******************************************************************************/
-
-void dng_negative::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
- {
-
- fIPTCBlock.Reset (block.Release ());
-
- fIPTCOffset = offset;
-
- }
-
-/******************************************************************************/
-
-void dng_negative::SetIPTC (AutoPtr<dng_memory_block> &block)
- {
-
- SetIPTC (block, kDNGStreamInvalidOffset);
-
- }
-
-/******************************************************************************/
-
-void dng_negative::ClearIPTC ()
- {
-
- fIPTCBlock.Reset ();
-
- fIPTCOffset = kDNGStreamInvalidOffset;
-
- }
-
-/*****************************************************************************/
-
-const void * dng_negative::IPTCData () const
- {
-
- if (fIPTCBlock.Get ())
- {
-
- return fIPTCBlock->Buffer ();
-
- }
-
- return NULL;
-
- }
-
-/*****************************************************************************/
-
-uint32 dng_negative::IPTCLength () const
- {
-
- if (fIPTCBlock.Get ())
- {
-
- return fIPTCBlock->LogicalSize ();
-
- }
-
- return 0;
-
- }
-
-/*****************************************************************************/
-
-uint64 dng_negative::IPTCOffset () const
- {
-
- if (fIPTCBlock.Get ())
- {
-
- return fIPTCOffset;
-
- }
-
- return kDNGStreamInvalidOffset;
-
- }
-
-/*****************************************************************************/
-
-dng_fingerprint dng_negative::IPTCDigest (bool includePadding) const
- {
-
- if (IPTCLength ())
- {
-
- dng_md5_printer printer;
-
- const uint8 *data = (const uint8 *) IPTCData ();
-
- uint32 count = IPTCLength ();
-
- // Because of some stupid ways of storing the IPTC data, the IPTC
- // data might be padded with up to three zeros. The official Adobe
- // logic is to include these zeros in the digest. However, older
- // versions of the Camera Raw code did not include the padding zeros
- // in the digest, so we support both methods and allow either to
- // match.
-
- if (!includePadding)
- {
-
- uint32 removed = 0;
-
- while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
- {
- removed++;
- count--;
- }
-
- }
-
- printer.Process (data, count);
-
- return printer.Result ();
-
- }
-
- return dng_fingerprint ();
-
- }
-
-/******************************************************************************/
-
-void dng_negative::RebuildIPTC (bool padForTIFF,
- bool forceUTF8)
- {
-
- ClearIPTC ();
-
- fXMP->RebuildIPTC (*this, padForTIFF, forceUTF8);
-
- dng_fingerprint digest = IPTCDigest ();
-
- fXMP->SetIPTCDigest (digest);
-
- }
-
-/*****************************************************************************/
-
-bool dng_negative::SetXMP (dng_host &host,
- const void *buffer,
- uint32 count,
- bool xmpInSidecar,
- bool xmpIsNewer)
- {
-
- bool result = false;
-
- try
- {
-
- AutoPtr<dng_xmp> tempXMP (MakeXMP ());
-
- tempXMP->Parse (host, buffer, count);
-
- fXMP.Reset (tempXMP.Release ());
-
- fXMPinSidecar = xmpInSidecar;
-
- fXMPisNewer = xmpIsNewer;
-
- result = true;
-
- }
-
- catch (dng_exception &except)
- {
-
- // Don't ignore transient errors.
-
- if (host.IsTransientError (except.ErrorCode ()))
- {
-
- throw;
-
- }
-
- // Eat other parsing errors.
-
- }
-
- catch (...)
- {
-
- // Eat unknown parsing exceptions.
-
- }
-
- return result;
-
- }
-
-/******************************************************************************/
-
-void dng_negative::SetActiveArea (const dng_rect &area)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fActiveArea = area;
-
- }
-
-/******************************************************************************/
-
-void dng_negative::SetMaskedAreas (uint32 count,
- const dng_rect *area)
- {
-
- DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas");
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas);
-
- for (uint32 index = 0; index < info.fMaskedAreaCount; index++)
- {
-
- info.fMaskedArea [index] = area [index];
-
- }
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fLinearizationTable.Reset (curve.Release ());
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SetBlackLevel (real64 black,
- int32 plane)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fBlackLevelRepeatRows = 1;
- info.fBlackLevelRepeatCols = 1;
-
- if (plane < 0)
- {
-
- for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
- {
-
- info.fBlackLevel [0] [0] [j] = black;
-
- }
-
- }
-
- else
- {
-
- info.fBlackLevel [0] [0] [plane] = black;
-
- }
-
- info.RoundBlacks ();
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SetQuadBlacks (real64 black0,
- real64 black1,
- real64 black2,
- real64 black3)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fBlackLevelRepeatRows = 2;
- info.fBlackLevelRepeatCols = 2;
-
- for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
- {
-
- info.fBlackLevel [0] [0] [j] = black0;
- info.fBlackLevel [0] [1] [j] = black1;
- info.fBlackLevel [1] [0] [j] = black2;
- info.fBlackLevel [1] [1] [j] = black3;
-
- }
-
- info.RoundBlacks ();
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SetRowBlacks (const real64 *blacks,
- uint32 count)
- {
-
- if (count)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- uint32 byteCount = count * sizeof (real64);
-
- info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount));
-
- DoCopyBytes (blacks,
- info.fBlackDeltaV->Buffer (),
- byteCount);
-
- info.RoundBlacks ();
-
- }
-
- else if (fLinearizationInfo.Get ())
- {
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fBlackDeltaV.Reset ();
-
- }
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SetColumnBlacks (const real64 *blacks,
- uint32 count)
- {
-
- if (count)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- uint32 byteCount = count * sizeof (real64);
-
- info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount));
-
- DoCopyBytes (blacks,
- info.fBlackDeltaH->Buffer (),
- byteCount);
-
- info.RoundBlacks ();
-
- }
-
- else if (fLinearizationInfo.Get ())
- {
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- info.fBlackDeltaH.Reset ();
-
- }
-
- }
-
-/*****************************************************************************/
-
-uint32 dng_negative::WhiteLevel (uint32 plane) const
- {
-
- if (fLinearizationInfo.Get ())
- {
-
- const dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- return Round_uint32 (info.fWhiteLevel [plane]);
-
- }
-
- return 0x0FFFF;
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SetWhiteLevel (uint32 white,
- int32 plane)
- {
-
- NeedLinearizationInfo ();
-
- dng_linearization_info &info = *fLinearizationInfo.Get ();
-
- if (plane < 0)
- {
-
- for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
- {
-
- info.fWhiteLevel [j] = (real64) white;
-
- }
-
- }
-
- else
- {
-
- info.fWhiteLevel [plane] = (real64) white;
-
- }
-
- }
+ NeedLinearizationInfo ();
+
+ dng_linearization_info &info = *fLinearizationInfo.Get ();
+
+ if (plane < 0)
+ {
+
+ for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
+ {
+
+ info.fWhiteLevel [j] = (real64) white;
+
+ }
+
+ }
+
+ else
+ {
+
+ info.fWhiteLevel [plane] = (real64) white;
+
+ }
+
+ }
/******************************************************************************/
void dng_negative::SetColorKeys (ColorKeyCode color0,
ColorKeyCode color1,
ColorKeyCode color2,
ColorKeyCode color3)
{
-
+
NeedMosaicInfo ();
-
+
dng_mosaic_info &info = *fMosaicInfo.Get ();
-
+
info.fCFAPlaneColor [0] = color0;
info.fCFAPlaneColor [1] = color1;
info.fCFAPlaneColor [2] = color2;
info.fCFAPlaneColor [3] = color3;
-
+
}
/******************************************************************************/
void dng_negative::SetBayerMosaic (uint32 phase)
{
-
+
NeedMosaicInfo ();
-
+
dng_mosaic_info &info = *fMosaicInfo.Get ();
-
+
ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
-
+
info.fCFAPatternSize = dng_point (2, 2);
-
+
switch (phase)
{
-
+
case 0:
{
info.fCFAPattern [0] [0] = color1;
info.fCFAPattern [0] [1] = color0;
info.fCFAPattern [1] [0] = color2;
info.fCFAPattern [1] [1] = color1;
break;
}
-
+
case 1:
{
info.fCFAPattern [0] [0] = color0;
info.fCFAPattern [0] [1] = color1;
info.fCFAPattern [1] [0] = color1;
info.fCFAPattern [1] [1] = color2;
break;
}
-
+
case 2:
{
info.fCFAPattern [0] [0] = color2;
info.fCFAPattern [0] [1] = color1;
info.fCFAPattern [1] [0] = color1;
info.fCFAPattern [1] [1] = color0;
break;
}
-
+
case 3:
{
info.fCFAPattern [0] [0] = color1;
info.fCFAPattern [0] [1] = color2;
info.fCFAPattern [1] [0] = color0;
info.fCFAPattern [1] [1] = color1;
break;
}
-
+
}
-
+
info.fColorPlanes = 3;
-
+
info.fCFALayout = 1;
-
+
}
/******************************************************************************/
void dng_negative::SetFujiMosaic (uint32 phase)
{
-
+
NeedMosaicInfo ();
-
+
dng_mosaic_info &info = *fMosaicInfo.Get ();
-
+
ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
-
+
info.fCFAPatternSize = dng_point (2, 4);
-
+
switch (phase)
{
-
+
case 0:
{
info.fCFAPattern [0] [0] = color0;
info.fCFAPattern [0] [1] = color1;
info.fCFAPattern [0] [2] = color2;
info.fCFAPattern [0] [3] = color1;
info.fCFAPattern [1] [0] = color2;
info.fCFAPattern [1] [1] = color1;
info.fCFAPattern [1] [2] = color0;
info.fCFAPattern [1] [3] = color1;
break;
}
-
+
case 1:
{
info.fCFAPattern [0] [0] = color2;
info.fCFAPattern [0] [1] = color1;
info.fCFAPattern [0] [2] = color0;
info.fCFAPattern [0] [3] = color1;
info.fCFAPattern [1] [0] = color0;
info.fCFAPattern [1] [1] = color1;
info.fCFAPattern [1] [2] = color2;
info.fCFAPattern [1] [3] = color1;
break;
}
-
+
}
-
+
info.fColorPlanes = 3;
-
+
info.fCFALayout = 2;
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::SetFujiMosaic6x6 (uint32 phase)
+ {
+
+ NeedMosaicInfo ();
+
+ dng_mosaic_info &info = *fMosaicInfo.Get ();
+
+ ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
+ ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
+ ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
+
+ const uint32 patSize = 6;
+
+ info.fCFAPatternSize = dng_point (patSize, patSize);
+
+ info.fCFAPattern [0] [0] = color1;
+ info.fCFAPattern [0] [1] = color2;
+ info.fCFAPattern [0] [2] = color1;
+ info.fCFAPattern [0] [3] = color1;
+ info.fCFAPattern [0] [4] = color0;
+ info.fCFAPattern [0] [5] = color1;
+
+ info.fCFAPattern [1] [0] = color0;
+ info.fCFAPattern [1] [1] = color1;
+ info.fCFAPattern [1] [2] = color0;
+ info.fCFAPattern [1] [3] = color2;
+ info.fCFAPattern [1] [4] = color1;
+ info.fCFAPattern [1] [5] = color2;
+
+ info.fCFAPattern [2] [0] = color1;
+ info.fCFAPattern [2] [1] = color2;
+ info.fCFAPattern [2] [2] = color1;
+ info.fCFAPattern [2] [3] = color1;
+ info.fCFAPattern [2] [4] = color0;
+ info.fCFAPattern [2] [5] = color1;
+
+ info.fCFAPattern [3] [0] = color1;
+ info.fCFAPattern [3] [1] = color0;
+ info.fCFAPattern [3] [2] = color1;
+ info.fCFAPattern [3] [3] = color1;
+ info.fCFAPattern [3] [4] = color2;
+ info.fCFAPattern [3] [5] = color1;
+
+ info.fCFAPattern [4] [0] = color2;
+ info.fCFAPattern [4] [1] = color1;
+ info.fCFAPattern [4] [2] = color2;
+ info.fCFAPattern [4] [3] = color0;
+ info.fCFAPattern [4] [4] = color1;
+ info.fCFAPattern [4] [5] = color0;
+
+ info.fCFAPattern [5] [0] = color1;
+ info.fCFAPattern [5] [1] = color0;
+ info.fCFAPattern [5] [2] = color1;
+ info.fCFAPattern [5] [3] = color1;
+ info.fCFAPattern [5] [4] = color2;
+ info.fCFAPattern [5] [5] = color1;
+
+ DNG_REQUIRE (phase >= 0 && phase < patSize * patSize,
+ "Bad phase in SetFujiMosaic6x6.");
+
+ if (phase > 0)
+ {
+
+ dng_mosaic_info temp = info;
+ uint32 phaseRow = phase / patSize;
+
+ uint32 phaseCol = phase - (phaseRow * patSize);
+
+ for (uint32 dstRow = 0; dstRow < patSize; dstRow++)
+ {
+
+ uint32 srcRow = (dstRow + phaseRow) % patSize;
+
+ for (uint32 dstCol = 0; dstCol < patSize; dstCol++)
+ {
+
+ uint32 srcCol = (dstCol + phaseCol) % patSize;
+
+ temp.fCFAPattern [dstRow] [dstCol] = info.fCFAPattern [srcRow] [srcCol];
+
+ }
+
+ }
+
+ info = temp;
+
+ }
+
+ info.fColorPlanes = 3;
+
+ info.fCFALayout = 1;
+
}
/******************************************************************************/
void dng_negative::SetQuadMosaic (uint32 pattern)
{
-
+
// The pattern of the four colors is assumed to be repeat at least every two
// columns and eight rows. The pattern is encoded as a 32-bit integer,
// with every two bits encoding a color, in scan order for two columns and
// eight rows (lsb is first). The usual color coding is:
//
// 0 = Green
// 1 = Magenta
// 2 = Cyan
// 3 = Yellow
//
// Examples:
//
// PowerShot 600 uses 0xe1e4e1e4:
//
// 0 1 2 3 4 5
// 0 G M G M G M
// 1 C Y C Y C Y
// 2 M G M G M G
// 3 C Y C Y C Y
//
// PowerShot A5 uses 0x1e4e1e4e:
//
// 0 1 2 3 4 5
// 0 C Y C Y C Y
// 1 G M G M G M
// 2 C Y C Y C Y
// 3 M G M G M G
//
// PowerShot A50 uses 0x1b4e4b1e:
//
// 0 1 2 3 4 5
// 0 C Y C Y C Y
// 1 M G M G M G
// 2 Y C Y C Y C
// 3 G M G M G M
// 4 C Y C Y C Y
// 5 G M G M G M
// 6 Y C Y C Y C
// 7 M G M G M G
//
// PowerShot Pro70 uses 0x1e4b4e1b:
//
// 0 1 2 3 4 5
// 0 Y C Y C Y C
// 1 M G M G M G
// 2 C Y C Y C Y
// 3 G M G M G M
// 4 Y C Y C Y C
// 5 G M G M G M
// 6 C Y C Y C Y
// 7 M G M G M G
//
// PowerShots Pro90 and G1 use 0xb4b4b4b4:
//
// 0 1 2 3 4 5
// 0 G M G M G M
// 1 Y C Y C Y C
NeedMosaicInfo ();
-
+
dng_mosaic_info &info = *fMosaicInfo.Get ();
-
+
if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF))
{
info.fCFAPatternSize = dng_point (8, 2);
}
-
+
else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF))
{
info.fCFAPatternSize = dng_point (4, 2);
}
-
+
else
{
info.fCFAPatternSize = dng_point (2, 2);
}
-
+
for (int32 row = 0; row < info.fCFAPatternSize.v; row++)
{
-
+
for (int32 col = 0; col < info.fCFAPatternSize.h; col++)
{
-
+
uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3;
-
+
info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index];
-
+
}
-
+
}
info.fColorPlanes = 4;
-
+
info.fCFALayout = 1;
-
+
}
-
+
/******************************************************************************/
void dng_negative::SetGreenSplit (uint32 split)
{
-
+
NeedMosaicInfo ();
-
+
dng_mosaic_info &info = *fMosaicInfo.Get ();
-
+
info.fBayerGreenSplit = split;
-
+
}
/*****************************************************************************/
void dng_negative::Parse (dng_host &host,
dng_stream &stream,
dng_info &info)
{
-
+
// Shared info.
-
+
dng_shared &shared = *(info.fShared.Get ());
-
+
// Find IFD holding the main raw information.
-
- dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
-
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex];
+
// Model name.
-
+
SetModelName (shared.fUniqueCameraModel.Get ());
-
+
// Localized model name.
-
+
SetLocalName (shared.fLocalizedCameraModel.Get ());
-
+
// Base orientation.
-
+
{
-
+
uint32 orientation = info.fIFD [0]->fOrientation;
-
+
if (orientation >= 1 && orientation <= 8)
{
-
+
SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation));
-
+
}
-
+
}
-
+
// Default crop rectangle.
-
+
SetDefaultCropSize (rawIFD.fDefaultCropSizeH,
rawIFD.fDefaultCropSizeV);
SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH,
rawIFD.fDefaultCropOriginV);
- // Default scale.
+ // Default user crop rectangle.
+ SetDefaultUserCrop (rawIFD.fDefaultUserCropT,
+ rawIFD.fDefaultUserCropL,
+ rawIFD.fDefaultUserCropB,
+ rawIFD.fDefaultUserCropR);
+
+ // Default scale.
+
SetDefaultScale (rawIFD.fDefaultScaleH,
rawIFD.fDefaultScaleV);
-
+
// Best quality scale.
-
+
SetBestQualityScale (rawIFD.fBestQualityScale);
-
+
// Baseline noise.
- SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
+ SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
+
+ // NoiseReductionApplied.
+
+ // Kludge: DNG spec says that NoiseReductionApplied tag should be in the
+ // Raw IFD, not main IFD. However, our original DNG SDK implementation
+ // read/wrote this tag from/to the main IFD. We now support reading the
+ // NoiseReductionApplied tag from both locations, but prefer the raw IFD
+ // (correct location).
+
+ if (rawIFD.fNoiseReductionApplied.IsValid ())
+ {
+
+ SetNoiseReductionApplied (rawIFD.fNoiseReductionApplied);
+
+ }
+
+ else
+ {
+
+ const dng_ifd &ifd0 = *info.fIFD [0];
+
+ SetNoiseReductionApplied (ifd0.fNoiseReductionApplied);
+
+ }
+
+ // NoiseProfile.
+
+ // Kludge: DNG spec says that NoiseProfile tag should be in the Raw IFD,
+ // not main IFD. However, our original DNG SDK implementation read/wrote
+ // this tag from/to the main IFD. We now support reading the NoiseProfile
+ // tag from both locations, but prefer the raw IFD (correct location).
+
+ if (rawIFD.fNoiseProfile.IsValid ())
+ {
+
+ SetNoiseProfile (rawIFD.fNoiseProfile);
- // NoiseReductionApplied.
+ }
- SetNoiseReductionApplied (shared.fNoiseReductionApplied);
+ else
+ {
- // NoiseProfile.
+ const dng_ifd &ifd0 = *info.fIFD [0];
- SetNoiseProfile (shared.fNoiseProfile);
+ SetNoiseProfile (ifd0.fNoiseProfile);
+ }
+
// Baseline exposure.
-
+
SetBaselineExposure (shared.fBaselineExposure.As_real64 ());
// Baseline sharpness.
-
+
SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ());
// Chroma blur radius.
-
+
SetChromaBlurRadius (rawIFD.fChromaBlurRadius);
// Anti-alias filter strength.
-
+
SetAntiAliasStrength (rawIFD.fAntiAliasStrength);
-
+
// Linear response limit.
-
+
SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ());
-
+
// Shadow scale.
-
+
SetShadowScale (shared.fShadowScale);
-
+
// Colorimetric reference.
-
+
SetColorimetricReference (shared.fColorimetricReference);
- // Color channels.
+ // Floating point flag.
- SetColorChannels (shared.fCameraProfile.fColorPlanes);
+ SetFloatingPoint (rawIFD.fSampleFormat [0] == sfFloatingPoint);
+ // Color channels.
+
+ SetColorChannels (shared.fCameraProfile.fColorPlanes);
+
// Analog balance.
-
+
if (shared.fAnalogBalance.NotEmpty ())
{
-
+
SetAnalogBalance (shared.fAnalogBalance);
-
+
}
// Camera calibration matrices
if (shared.fCameraCalibration1.NotEmpty ())
{
-
+
SetCameraCalibration1 (shared.fCameraCalibration1);
-
+
}
-
+
if (shared.fCameraCalibration2.NotEmpty ())
{
-
+
SetCameraCalibration2 (shared.fCameraCalibration2);
-
+
}
-
+
if (shared.fCameraCalibration1.NotEmpty () ||
shared.fCameraCalibration2.NotEmpty ())
{
-
+
SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ());
-
+
}
// Embedded camera profiles.
-
+
if (shared.fCameraProfile.fColorPlanes > 1)
{
-
+
if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ())
{
-
+
// Add profile from main IFD.
-
+
{
-
+
AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
-
+
dng_camera_profile_info &profileInfo = shared.fCameraProfile;
-
+
profile->Parse (stream, profileInfo);
-
+
// The main embedded profile must be valid.
-
+
if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
{
-
+
ThrowBadFormat ();
-
+
}
-
+
profile->SetWasReadFromDNG ();
-
+
AddProfile (profile);
-
+
}
-
+
// Extra profiles.
for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++)
{
-
+
try
{
AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
-
+
dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index];
-
+
profile->Parse (stream, profileInfo);
-
+
if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
{
-
+
ThrowBadFormat ();
-
+
}
-
+
profile->SetWasReadFromDNG ();
-
+
AddProfile (profile);
}
-
+
catch (dng_exception &except)
{
-
+
// Don't ignore transient errors.
-
+
if (host.IsTransientError (except.ErrorCode ()))
{
-
+
throw;
-
+
}
-
+
// Eat other parsing errors.
-
+
#if qDNGValidate
-
+
ReportWarning ("Unable to parse extra profile");
-
+
#endif
-
+
}
-
+
}
-
+
}
-
+
// As shot profile name.
-
+
if (shared.fAsShotProfileName.NotEmpty ())
{
-
+
SetAsShotProfileName (shared.fAsShotProfileName.Get ());
-
+
}
-
+
}
-
+
// Raw image data digest.
-
+
if (shared.fRawImageDigest.IsValid ())
{
-
+
SetRawImageDigest (shared.fRawImageDigest);
-
+
}
-
+
+ // New raw image data digest.
+
+ if (shared.fNewRawImageDigest.IsValid ())
+ {
+
+ SetNewRawImageDigest (shared.fNewRawImageDigest);
+
+ }
+
// Raw data unique ID.
-
+
if (shared.fRawDataUniqueID.IsValid ())
{
-
+
SetRawDataUniqueID (shared.fRawDataUniqueID);
-
+
}
-
+
// Original raw file name.
-
+
if (shared.fOriginalRawFileName.NotEmpty ())
{
-
+
SetOriginalRawFileName (shared.fOriginalRawFileName.Get ());
-
+
}
-
+
// Original raw file data.
-
+
if (shared.fOriginalRawFileDataCount)
{
-
+
SetHasOriginalRawFileData (true);
-
+
if (host.KeepOriginalFile ())
{
-
+
uint32 count = shared.fOriginalRawFileDataCount;
-
+
AutoPtr<dng_memory_block> block (host.Allocate (count));
-
+
stream.SetReadPosition (shared.fOriginalRawFileDataOffset);
-
+
stream.Get (block->Buffer (), count);
-
+
SetOriginalRawFileData (block);
-
+
SetOriginalRawFileDigest (shared.fOriginalRawFileDigest);
-
+
ValidateOriginalRawFileDigest ();
-
+
}
-
+
}
-
+
// DNG private data.
-
+
if (shared.fDNGPrivateDataCount && (host.SaveDNGVersion () != dngVersion_None))
{
-
+
uint32 length = shared.fDNGPrivateDataCount;
-
+
AutoPtr<dng_memory_block> block (host.Allocate (length));
-
+
stream.SetReadPosition (shared.fDNGPrivateDataOffset);
-
+
stream.Get (block->Buffer (), length);
-
+
SetPrivateData (block);
-
+
}
-
+
// Hand off EXIF metadata to negative.
-
- fExif.Reset (info.fExif.Release ());
-
+
+ ResetExif (info.fExif.Release ());
+
// Parse linearization info.
-
+
NeedLinearizationInfo ();
-
+
fLinearizationInfo.Get ()->Parse (host,
stream,
info);
-
+
// Parse mosaic info.
-
+
if (rawIFD.fPhotometricInterpretation == piCFA)
{
-
+
NeedMosaicInfo ();
-
+
fMosaicInfo.Get ()->Parse (host,
stream,
info);
+
+ }
+
+ // Fill in original sizes.
+
+ if (shared.fOriginalDefaultFinalSize.h > 0 &&
+ shared.fOriginalDefaultFinalSize.v > 0)
+ {
+
+ SetOriginalDefaultFinalSize (shared.fOriginalDefaultFinalSize);
+
+ SetOriginalBestQualityFinalSize (shared.fOriginalDefaultFinalSize);
+
+ SetOriginalDefaultCropSize (dng_urational (shared.fOriginalDefaultFinalSize.h, 1),
+ dng_urational (shared.fOriginalDefaultFinalSize.v, 1));
+
+ }
+
+ if (shared.fOriginalBestQualityFinalSize.h > 0 &&
+ shared.fOriginalBestQualityFinalSize.v > 0)
+ {
+
+ SetOriginalBestQualityFinalSize (shared.fOriginalBestQualityFinalSize);
+
+ }
+
+ if (shared.fOriginalDefaultCropSizeH.As_real64 () >= 1.0 &&
+ shared.fOriginalDefaultCropSizeV.As_real64 () >= 1.0)
+ {
+
+ SetOriginalDefaultCropSize (shared.fOriginalDefaultCropSizeH,
+ shared.fOriginalDefaultCropSizeV);
+
+ }
+
+ if (shared.fDepthFormat <= depthFormatUnknown)
+ {
+
+ SetDepthFormat (shared.fDepthFormat);
+
+ }
+
+ if (shared.fDepthNear != dng_urational (0, 0))
+ {
+
+ SetDepthNear (shared.fDepthNear);
+
+ }
+
+ if (shared.fDepthFar != dng_urational (0, 0))
+ {
+
+ SetDepthFar (shared.fDepthFar);
+
+ }
+
+ if (shared.fDepthUnits != depthUnitsUnknown)
+ {
+
+ SetDepthUnits (shared.fDepthUnits);
+
+ }
+
+ if (shared.fDepthMeasureType != depthMeasureUnknown)
+ {
+
+ SetDepthMeasureType (shared.fDepthMeasureType);
+
+ }
+
+ }
+
+/*****************************************************************************/
+void dng_negative::SetDefaultOriginalSizes ()
+ {
+
+ // Fill in original sizes if we don't have them already.
+
+ if (OriginalDefaultFinalSize () == dng_point ())
+ {
+
+ SetOriginalDefaultFinalSize (dng_point (DefaultFinalHeight (),
+ DefaultFinalWidth ()));
+
+ }
+
+ if (OriginalBestQualityFinalSize () == dng_point ())
+ {
+
+ SetOriginalBestQualityFinalSize (dng_point (BestQualityFinalHeight (),
+ BestQualityFinalWidth ()));
+
+ }
+
+ if (OriginalDefaultCropSizeH ().NotValid () ||
+ OriginalDefaultCropSizeV ().NotValid ())
+ {
+
+ SetOriginalDefaultCropSize (DefaultCropSizeH (),
+ DefaultCropSizeV ());
+
}
}
/*****************************************************************************/
+void dng_negative::SetOriginalSizes (const dng_point &size)
+ {
+
+ SetOriginalDefaultFinalSize (size);
+
+ SetOriginalBestQualityFinalSize (size);
+
+ SetOriginalDefaultCropSize (dng_urational (size.h, 1),
+ dng_urational (size.v, 1));
+
+ }
+
+/*****************************************************************************/
+
void dng_negative::PostParse (dng_host &host,
dng_stream &stream,
dng_info &info)
{
-
+
// Shared info.
-
+
dng_shared &shared = *(info.fShared.Get ());
-
+
if (host.NeedsMeta ())
{
-
+
+ // Fill in original sizes if we don't have them already.
+
+ SetDefaultOriginalSizes ();
+
// MakerNote.
-
+
if (shared.fMakerNoteCount)
{
-
+
// See if we know if the MakerNote is safe or not.
-
+
SetMakerNoteSafety (shared.fMakerNoteSafety == 1);
-
+
// If the MakerNote is safe, preserve it as a MakerNote.
-
+
if (IsMakerNoteSafe ())
{
AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount));
-
+
stream.SetReadPosition (shared.fMakerNoteOffset);
-
+
stream.Get (block->Buffer (), shared.fMakerNoteCount);
-
+
SetMakerNote (block);
-
+
}
-
+
}
-
+
// IPTC metadata.
-
+
if (shared.fIPTC_NAA_Count)
{
-
+
AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count));
-
+
stream.SetReadPosition (shared.fIPTC_NAA_Offset);
-
+
uint64 iptcOffset = stream.PositionInOriginalFile();
-
- stream.Get (block->Buffer (),
+
+ stream.Get (block->Buffer (),
block->LogicalSize ());
-
+
SetIPTC (block, iptcOffset);
-
+
}
-
+
// XMP metadata.
-
+
if (shared.fXMPCount)
{
-
+
AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount));
-
+
stream.SetReadPosition (shared.fXMPOffset);
-
+
stream.Get (block->Buffer (),
block->LogicalSize ());
-
- fValidEmbeddedXMP = SetXMP (host,
- block->Buffer (),
- block->LogicalSize ());
-
+
+ Metadata ().SetEmbeddedXMP (host,
+ block->Buffer (),
+ block->LogicalSize ());
+
#if qDNGValidate
-
- if (!fValidEmbeddedXMP)
+
+ if (!Metadata ().HaveValidEmbeddedXMP ())
{
ReportError ("The embedded XMP is invalid");
}
-
+
#endif
-
+
}
-
+
// Color info.
-
+
if (!IsMonochrome ())
{
-
+
// If the ColorimetricReference is the ICC profile PCS,
- // then the data must be already be white balanced to the
- // ICC profile PCS white point.
-
- if (ColorimetricReference () == crICCProfilePCS)
- {
-
- ClearCameraNeutral ();
-
- SetCameraWhiteXY (PCStoXY ());
-
- }
-
- else
- {
-
- // AsShotNeutral.
-
- if (shared.fAsShotNeutral.Count () == ColorChannels ())
- {
-
- SetCameraNeutral (shared.fAsShotNeutral);
-
- }
-
- // AsShotWhiteXY.
-
- if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
- {
-
- SetCameraWhiteXY (shared.fAsShotWhiteXY);
-
- }
-
- }
-
- }
-
- }
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::SynchronizeMetadata ()
- {
-
- if (!fOriginalExif.Get ())
- {
-
- fOriginalExif.Reset (fExif->Clone ());
-
- }
-
- fXMP->ValidateMetadata ();
-
- fXMP->IngestIPTC (*this, fXMPisNewer);
-
- fXMP->SyncExif (*fExif.Get ());
-
- fXMP->SyncOrientation (*this, fXMPinSidecar);
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::UpdateDateTime (const dng_date_time_info &dt)
- {
-
- fExif->UpdateDateTime (dt);
-
- fXMP->UpdateDateTime (dt);
-
- }
-
-/*****************************************************************************/
-
-void dng_negative::UpdateDateTimeToNow ()
- {
-
- dng_date_time_info dt;
-
- CurrentDateTimeAndZone (dt);
-
- UpdateDateTime (dt);
-
+ // then the data must be already be white balanced to the
+ // ICC profile PCS white point.
+
+ if (ColorimetricReference () == crICCProfilePCS)
+ {
+
+ ClearCameraNeutral ();
+
+ SetCameraWhiteXY (PCStoXY ());
+
+ }
+
+ else
+ {
+
+ // AsShotNeutral.
+
+ if (shared.fAsShotNeutral.Count () == ColorChannels ())
+ {
+
+ SetCameraNeutral (shared.fAsShotNeutral);
+
+ }
+
+ // AsShotWhiteXY.
+
+ if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
+ {
+
+ SetCameraWhiteXY (shared.fAsShotWhiteXY);
+
+ }
+
+ }
+
+ }
+
+ }
+
}
-
+
/*****************************************************************************/
bool dng_negative::SetFourColorBayer ()
{
-
+
if (ColorChannels () != 3)
{
return false;
}
-
+
if (!fMosaicInfo.Get ())
{
return false;
}
-
+
if (!fMosaicInfo.Get ()->SetFourColorBayer ())
{
return false;
}
-
+
SetColorChannels (4);
-
+
if (fCameraNeutral.Count () == 3)
{
-
+
dng_vector n (4);
-
+
n [0] = fCameraNeutral [0];
n [1] = fCameraNeutral [1];
n [2] = fCameraNeutral [2];
n [3] = fCameraNeutral [1];
-
+
fCameraNeutral = n;
-
+
}
fCameraCalibration1.Clear ();
fCameraCalibration2.Clear ();
-
+
fCameraCalibrationSignature.Clear ();
-
+
for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
{
-
+
fCameraProfile [index]->SetFourColorBayer ();
-
+
}
-
+
return true;
-
+
}
-
+
/*****************************************************************************/
const dng_image & dng_negative::RawImage () const
{
-
+
if (fRawImage.Get ())
{
return *fRawImage.Get ();
}
-
+
if (fStage1Image.Get ())
{
return *fStage1Image.Get ();
}
-
- DNG_ASSERT (fStage3Image.Get (),
- "dng_negative::RawImage with no raw image");
-
+
+ if (fUnflattenedStage3Image.Get ())
+ {
+ return *fUnflattenedStage3Image.Get ();
+ }
+
+ DNG_REQUIRE (fStage3Image.Get (),
+ "dng_negative::RawImage with no raw image");
+
return *fStage3Image.Get ();
-
+
}
/*****************************************************************************/
-void dng_negative::ReadStage1Image (dng_host &host,
- dng_stream &stream,
- dng_info &info)
- {
+uint16 dng_negative::RawImageBlackLevel () const
+ {
+
+ if (fRawImage.Get ())
+ {
+ return fRawImageBlackLevel;
+ }
+
+ if (fStage1Image.Get ())
+ {
+ return 0;
+ }
+
+ return fStage3BlackLevel;
+
+ }
- dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
+/*****************************************************************************/
- fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
- rawIFD.fSamplesPerPixel,
- rawIFD.PixelType ()));
+const dng_jpeg_image * dng_negative::RawJPEGImage () const
+ {
- rawIFD.ReadImage (host,
- stream,
- *fStage1Image.Get ());
+ return fRawJPEGImage.Get ();
- // We are reading the main image, we should read the opcode lists
- // also.
+ }
- if (rawIFD.fOpcodeList1Count)
- {
+/*****************************************************************************/
- #if qDNGValidate
+void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage)
+ {
- if (gVerbose)
- {
- printf ("\nParsing OpcodeList1: ");
- }
+ fRawJPEGImage.Reset (jpegImage.Release ());
- #endif
+ }
- fOpcodeList1.Parse (host,
- stream,
- rawIFD.fOpcodeList1Count,
- rawIFD.fOpcodeList1Offset);
+/*****************************************************************************/
- }
+void dng_negative::ClearRawJPEGImage ()
+ {
+
+ fRawJPEGImage.Reset ();
- if (rawIFD.fOpcodeList2Count)
- {
+ }
- #if qDNGValidate
+/*****************************************************************************/
- if (gVerbose)
+void dng_negative::FindRawJPEGImageDigest (dng_host &host) const
+ {
+
+ if (fRawJPEGImageDigest.IsNull ())
+ {
+
+ if (fRawJPEGImage.Get ())
{
- printf ("\nParsing OpcodeList2: ");
+
+ #if qDNGValidate
+
+ dng_timer timer ("FindRawJPEGImageDigest time");
+
+ #endif
+
+ fRawJPEGImageDigest = fRawJPEGImage->FindDigest (host);
+
}
-
- #endif
-
- fOpcodeList2.Parse (host,
- stream,
- rawIFD.fOpcodeList2Count,
- rawIFD.fOpcodeList2Offset);
-
- }
-
- if (rawIFD.fOpcodeList3Count)
- {
-
- #if qDNGValidate
-
- if (gVerbose)
+
+ else
{
- printf ("\nParsing OpcodeList3: ");
+
+ ThrowProgramError ("No raw JPEG image");
+
}
+
+ }
+
+ }
- #endif
+/*****************************************************************************/
+
+void dng_negative::ReadOpcodeLists (dng_host &host,
+ dng_stream &stream,
+ dng_info &info)
+ {
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex];
+
+ if (rawIFD.fOpcodeList1Count)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\nParsing OpcodeList1: ");
+ }
+
+ #endif
+
+ fOpcodeList1.Parse (host,
+ stream,
+ rawIFD.fOpcodeList1Count,
+ rawIFD.fOpcodeList1Offset);
+
+ }
+
+ if (rawIFD.fOpcodeList2Count)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\nParsing OpcodeList2: ");
+ }
+
+ #endif
+
+ fOpcodeList2.Parse (host,
+ stream,
+ rawIFD.fOpcodeList2Count,
+ rawIFD.fOpcodeList2Offset);
+
+ }
+
+ if (rawIFD.fOpcodeList3Count)
+ {
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+ printf ("\nParsing OpcodeList3: ");
+ }
+
+ #endif
+
+ fOpcodeList3.Parse (host,
+ stream,
+ rawIFD.fOpcodeList3Count,
+ rawIFD.fOpcodeList3Offset);
+
+ }
+
+ }
- fOpcodeList3.Parse (host,
- stream,
- rawIFD.fOpcodeList3Count,
- rawIFD.fOpcodeList3Offset);
+/*****************************************************************************/
+void dng_negative::ReadStage1Image (dng_host &host,
+ dng_stream &stream,
+ dng_info &info)
+ {
+
+ // Allocate image we are reading.
+
+ dng_ifd &rawIFD = *info.fIFD [info.fMainIndex];
+
+ fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
+ rawIFD.fSamplesPerPixel,
+ rawIFD.PixelType ()));
+
+ // See if we should grab the compressed JPEG data.
+
+ AutoPtr<dng_jpeg_image> jpegImage;
+
+ if (host.SaveDNGVersion () >= dngVersion_1_4_0_0 &&
+ !host.PreferredSize () &&
+ !host.ForPreview () &&
+ rawIFD.fCompression == ccLossyJPEG)
+ {
+
+ jpegImage.Reset (new dng_jpeg_image);
+
+ }
+
+ // See if we need to compute the digest of the compressed JPEG data
+ // while reading.
+
+ bool needJPEGDigest = (RawImageDigest ().IsValid () ||
+ NewRawImageDigest ().IsValid ()) &&
+ rawIFD.fCompression == ccLossyJPEG &&
+ jpegImage.Get () == NULL;
+
+ dng_fingerprint jpegDigest;
+
+ // Read the image.
+
+ rawIFD.ReadImage (host,
+ stream,
+ *fStage1Image.Get (),
+ jpegImage.Get (),
+ needJPEGDigest ? &jpegDigest : NULL);
+
+ // Remember the raw floating point bit depth, if reading from
+ // a floating point image.
+
+ if (fStage1Image->PixelType () == ttFloat)
+ {
+
+ SetRawFloatBitDepth (rawIFD.fBitsPerSample [0]);
+
+ }
+
+ // Remember the compressed JPEG data if we read it.
+
+ if (jpegImage.Get ())
+ {
+
+ SetRawJPEGImage (jpegImage);
+
+ }
+
+ // Remember the compressed JPEG digest if we computed it.
+
+ if (jpegDigest.IsValid ())
+ {
+
+ SetRawJPEGImageDigest (jpegDigest);
+
}
+
+ // We are are reading the main image, we should read the opcode lists
+ // also.
+
+ ReadOpcodeLists (host,
+ stream,
+ info);
}
/*****************************************************************************/
+void dng_negative::ReadEnhancedImage (dng_host &host,
+ dng_stream &stream,
+ dng_info &info)
+ {
+
+ // Allocate image we are reading.
+
+ dng_ifd &enhancedIFD = *info.fIFD [info.fEnhancedIndex];
+
+ fStage3Image.Reset (host.Make_dng_image (enhancedIFD.Bounds (),
+ enhancedIFD.fSamplesPerPixel,
+ enhancedIFD.PixelType ()));
+
+ // Read the image.
+
+ enhancedIFD.ReadImage (host,
+ stream,
+ *fStage3Image.Get ());
+
+ // Remember the enhance parameters.
+
+ SetEnhanceParams (enhancedIFD.fEnhanceParams);
+
+ // Stage 3 black level.
+
+ SetStage3BlackLevel ((uint16) Round_uint32 (enhancedIFD.fBlackLevel [0] [0] [0]));
+
+ // We are are reading the enhanced image, we should read the opcode lists
+ // also, since we at least need to know about lens opcodes.
+
+ ReadOpcodeLists (host,
+ stream,
+ info);
+
+ // Should we read the raw image also?
+
+ bool needRawImage = host.SaveDNGVersion () != 0 &&
+ !host.SaveLinearDNG (*this);
+
+ // Read in raw image data if required.
+
+ if (needRawImage)
+ {
+
+ dng_ifd &mainIFD = *info.fIFD [info.fMainIndex];
+
+ fRawImage.Reset (host.Make_dng_image (mainIFD.Bounds (),
+ mainIFD.fSamplesPerPixel,
+ mainIFD.PixelType ()));
+
+ mainIFD.ReadImage (host,
+ stream,
+ *fRawImage.Get ());
+
+ }
+
+ // Baseline sharpness.
+
+ if (enhancedIFD.fBaselineSharpness.IsValid ())
+ {
+
+ SetRawBaselineSharpness ();
+
+ fBaselineSharpness = enhancedIFD.fBaselineSharpness;
+
+ }
+
+ // Noise reduction applied.
+
+ if (enhancedIFD.fNoiseReductionApplied.IsValid ())
+ {
+
+ SetRawNoiseReductionApplied ();
+
+ fNoiseReductionApplied = enhancedIFD.fNoiseReductionApplied;
+
+ }
+
+ // Noise profile.
+
+ if (enhancedIFD.fNoiseProfile.IsValidForNegative (*this))
+ {
+
+ SetRawNoiseProfile ();
+
+ fNoiseProfile = enhancedIFD.fNoiseProfile;
+
+ }
+
+ // Raw to full scale.
+
+ if (fLinearizationInfo.Get ())
+ {
+
+ if (fLinearizationInfo->fActiveArea.W ())
+ {
+ fRawToFullScaleH = (real64) fStage3Image->Bounds ().W () /
+ (real64) fLinearizationInfo->fActiveArea.W ();
+ }
+
+ if (fLinearizationInfo->fActiveArea.H ())
+ {
+ fRawToFullScaleV = (real64) fStage3Image->Bounds ().H () /
+ (real64) fLinearizationInfo->fActiveArea.H ();
+ }
+
+ }
+
+ if (!needRawImage)
+ {
+
+ ClearLinearizationInfo ();
+
+ ClearMosaicInfo ();
+
+ fOpcodeList1.Clear ();
+ fOpcodeList2.Clear ();
+ fOpcodeList3.Clear ();
+
+ fRawImageDigest .Clear ();
+ fNewRawImageDigest.Clear ();
+
+ fRawBaselineSharpness .Clear ();
+ fRawNoiseReductionApplied.Clear ();
+
+ fRawNoiseProfile = dng_noise_profile ();
+
+ if (fRawDataUniqueID.IsValid ())
+ {
+ fRawDataUniqueID = RawDataUniqueID ();
+ }
+
+ fEnhanceParams.Clear ();
+
+ }
+
+ }
+
+/*****************************************************************************/
+
void dng_negative::SetStage1Image (AutoPtr<dng_image> &image)
{
-
+
fStage1Image.Reset (image.Release ());
-
+
}
/*****************************************************************************/
void dng_negative::SetStage2Image (AutoPtr<dng_image> &image)
{
-
+
fStage2Image.Reset (image.Release ());
-
+
}
/*****************************************************************************/
void dng_negative::SetStage3Image (AutoPtr<dng_image> &image)
{
-
+
fStage3Image.Reset (image.Release ());
+ SetFloatingPoint (fStage3Image.Get () &&
+ (fStage3Image->PixelType () == ttFloat));
+
}
/*****************************************************************************/
-void dng_negative::DoBuildStage2 (dng_host &host,
- uint32 pixelType)
+void dng_negative::DoBuildStage2 (dng_host &host)
{
-
+
dng_image &stage1 = *fStage1Image.Get ();
-
+
dng_linearization_info &info = *fLinearizationInfo.Get ();
-
+
+ uint32 pixelType = ttShort;
+
+ if (stage1.PixelType () == ttLong ||
+ stage1.PixelType () == ttFloat)
+ {
+
+ pixelType = ttFloat;
+
+ }
+
fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (),
stage1.Planes (),
pixelType));
-
+
info.Linearize (host,
+ *this,
stage1,
*fStage2Image.Get ());
+
+ }
+
+/*****************************************************************************/
+void dng_negative::DoPostOpcodeList2 (dng_host & /* host */)
+ {
+
+ // Nothing by default.
+
}
/*****************************************************************************/
-void dng_negative::BuildStage2Image (dng_host &host,
- uint32 pixelType)
+bool dng_negative::NeedDefloatStage2 (dng_host &host)
+ {
+
+ if (fStage2Image->PixelType () == ttFloat)
+ {
+
+ if (fRawImageStage >= rawImageStagePostOpcode2 &&
+ host.SaveDNGVersion () != dngVersion_None &&
+ host.SaveDNGVersion () < dngVersion_1_4_0_0)
+ {
+
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::DefloatStage2 (dng_host & /* host */)
{
+
+ ThrowNotYetImplemented ("dng_negative::DefloatStage2");
+
+ }
+
+/*****************************************************************************/
+void dng_negative::BuildStage2Image (dng_host &host)
+ {
+
// If reading the negative to save in DNG format, figure out
// when to grab a copy of the raw data.
-
+
if (host.SaveDNGVersion () != dngVersion_None)
{
-
- if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () ||
- fOpcodeList3.AlwaysApply ())
+
+ // Transparency masks are only supported in DNG version 1.4 and
+ // later. In this case, the flattening of the transparency mask happens
+ // on the the stage3 image.
+
+ if (TransparencyMask () && host.SaveDNGVersion () < dngVersion_1_4_0_0)
+ {
+ fRawImageStage = rawImageStagePostOpcode3;
+ }
+
+ else if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () ||
+ fOpcodeList3.AlwaysApply ())
{
fRawImageStage = rawImageStagePostOpcode3;
}
+
+ // If we are not doing a full resolution read, then always save the DNG
+ // from the processed stage 3 image.
+ else if (host.PreferredSize ())
+ {
+ fRawImageStage = rawImageStagePostOpcode3;
+ }
+
else if (host.SaveLinearDNG (*this))
{
-
+
// If the opcode list 3 has optional tags that are beyond the
// the minimum version, and we are saving a linear DNG anyway,
// then go ahead and apply them.
-
+
if (fOpcodeList3.MinVersion (true) > host.SaveDNGVersion ())
{
fRawImageStage = rawImageStagePostOpcode3;
}
-
+
else
{
fRawImageStage = rawImageStagePreOpcode3;
}
-
+
}
-
+
else if (fOpcodeList2.MinVersion (false) > host.SaveDNGVersion () ||
fOpcodeList2.AlwaysApply ())
{
fRawImageStage = rawImageStagePostOpcode2;
}
-
+
else if (fOpcodeList1.MinVersion (false) > host.SaveDNGVersion () ||
fOpcodeList1.AlwaysApply ())
{
fRawImageStage = rawImageStagePostOpcode1;
}
-
+
else
{
fRawImageStage = rawImageStagePreOpcode1;
}
+
+ // We should not save floating point stage1 images unless the target
+ // DNG version is high enough to understand floating point images.
+ // We handle this by converting from floating point to integer if
+ // required after building stage2 image.
+
+ if (fStage1Image->PixelType () == ttFloat)
+ {
+
+ if (fRawImageStage < rawImageStagePostOpcode2)
+ {
+
+ if (host.SaveDNGVersion () < dngVersion_1_4_0_0)
+ {
+
+ fRawImageStage = rawImageStagePostOpcode2;
+
+ }
+
+ }
+
+ }
- }
+ // If the host is requesting a negative read for fast conversion to
+ // DNG, then check whether we can actually do a fast interpolation or
+ // not. For now, keep the logic simple. If the raw image stage is the
+ // pre-opcode stage 1 image (original), then proceed with trying a
+ // fast/downsampled interpolation when building the stage 3 image.
+ // Otherwise, turn off the attempted optimization.
- // Grab clone of raw image if required.
+ if (host.ForFastSaveToDNG () &&
+ (fRawImageStage > rawImageStagePreOpcode1))
+ {
+
+ // Disable/revert the optimization attempt, and do a normal
+ // interpolation when building the stage 3 image.
+ host.SetForFastSaveToDNG (false, 0);
+
+ }
+
+ }
+
+ // Grab clone of raw image if required.
+
if (fRawImageStage == rawImageStagePreOpcode1)
{
-
+
fRawImage.Reset (fStage1Image->Clone ());
-
+
+ if (fTransparencyMask.Get ())
+ {
+ fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
+ }
+
+ if (fDepthMap.Get ())
+ {
+ fRawDepthMap.Reset (fDepthMap->Clone ());
+ }
+
}
else
{
-
+
// If we are not keeping the most raw image, we need
// to recompute the raw image digest.
-
+
ClearRawImageDigest ();
-
+
+ // If we don't grab the unprocessed stage 1 image, then
+ // the raw JPEG image is no longer valid.
+
+ ClearRawJPEGImage ();
+
+ // Nor is the digest of the raw JPEG data.
+
+ ClearRawJPEGImageDigest ();
+
+ // We also don't know the raw floating point bit depth.
+
+ SetRawFloatBitDepth (0);
+
}
-
+
// Process opcode list 1.
-
+
host.ApplyOpcodeList (fOpcodeList1, *this, fStage1Image);
-
+
// See if we are done with the opcode list 1.
-
+
if (fRawImageStage > rawImageStagePreOpcode1)
{
-
+
fOpcodeList1.Clear ();
-
+
}
-
+
// Grab clone of raw image if required.
-
+
if (fRawImageStage == rawImageStagePostOpcode1)
{
-
+
fRawImage.Reset (fStage1Image->Clone ());
-
+
+ if (fTransparencyMask.Get ())
+ {
+ fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
+ }
+
+ if (fDepthMap.Get ())
+ {
+ fRawDepthMap.Reset (fDepthMap->Clone ());
+ }
+
}
// Finalize linearization info.
-
+
{
-
+
NeedLinearizationInfo ();
-
+
dng_linearization_info &info = *fLinearizationInfo.Get ();
-
+
info.PostParse (host, *this);
-
+
}
-
+
// Perform the linearization.
-
- DoBuildStage2 (host,
- pixelType);
-
+
+ DoBuildStage2 (host);
+
// Delete the stage1 image now that we have computed the stage 2 image.
-
+
fStage1Image.Reset ();
-
+
// Are we done with the linearization info.
-
+
if (fRawImageStage > rawImageStagePostOpcode1)
{
-
+
ClearLinearizationInfo ();
-
+
}
-
+
// Process opcode list 2.
-
+
host.ApplyOpcodeList (fOpcodeList2, *this, fStage2Image);
-
+
// See if we are done with the opcode list 2.
-
+
if (fRawImageStage > rawImageStagePostOpcode1)
{
-
+
fOpcodeList2.Clear ();
-
+
}
-
+
+ // Hook for any required processing just after opcode list 2.
+
+ DoPostOpcodeList2 (host);
+
+ // Convert from floating point to integer if required.
+
+ if (NeedDefloatStage2 (host))
+ {
+
+ DefloatStage2 (host);
+
+ }
+
// Grab clone of raw image if required.
-
+
if (fRawImageStage == rawImageStagePostOpcode2)
{
-
+
fRawImage.Reset (fStage2Image->Clone ());
-
+
+ fRawImageBlackLevel = fStage3BlackLevel;
+
+ if (fTransparencyMask.Get ())
+ {
+ fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
+ }
+
+ if (fDepthMap.Get ())
+ {
+ fRawDepthMap.Reset (fDepthMap->Clone ());
+ }
+
}
-
+
}
-
+
/*****************************************************************************/
void dng_negative::DoInterpolateStage3 (dng_host &host,
- int32 srcPlane)
+ int32 srcPlane,
+ dng_matrix *scaleTransforms)
{
-
+
dng_image &stage2 = *fStage2Image.Get ();
-
+
dng_mosaic_info &info = *fMosaicInfo.Get ();
+
+ dng_point downScale;
+
+ const bool fastSaveToDNG = host.ForFastSaveToDNG ();
+
+ const uint32 fastSaveSize = host.FastSaveToDNGSize ();
+
+ if (fastSaveToDNG && (fastSaveSize > 0))
+ {
+
+ downScale = info.DownScale (host.MinimumSize (),
+ host.FastSaveToDNGSize (),
+ host.CropFactor ());
+
+ }
+
+ else
+ {
- dng_point downScale = info.DownScale (host.MinimumSize (),
- host.PreferredSize (),
- host.CropFactor ());
+ downScale = info.DownScale (host.MinimumSize (),
+ host.PreferredSize (),
+ host.CropFactor ());
+ }
+
if (downScale != dng_point (1, 1))
{
SetIsPreview (true);
}
-
+
dng_point dstSize = info.DstSize (downScale);
-
+
fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize),
info.fColorPlanes,
stage2.PixelType ()));
if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ())
{
srcPlane = 0;
}
-
+
info.Interpolate (host,
*this,
stage2,
*fStage3Image.Get (),
downScale,
- srcPlane);
+ srcPlane,
+ scaleTransforms);
}
-
+
/*****************************************************************************/
// Interpolate and merge a multi-channel CFA image.
-void dng_negative::DoMergeStage3 (dng_host &host)
+void dng_negative::DoMergeStage3 (dng_host &host,
+ dng_matrix *scaleTransforms)
{
-
+
// The DNG SDK does not provide multi-channel CFA image merging code.
// It just grabs the first channel and uses that.
-
- DoInterpolateStage3 (host, 0);
-
+
+ DoInterpolateStage3 (host, 0, scaleTransforms);
+
// Just grabbing the first channel would often result in the very
// bright image using the baseline exposure value.
-
+
fStage3Gain = pow (2.0, BaselineExposure ());
-
+
}
-
+
/*****************************************************************************/
void dng_negative::DoBuildStage3 (dng_host &host,
- int32 srcPlane)
+ int32 srcPlane,
+ dng_matrix *scaleTransforms)
{
-
+
// If we don't have a mosaic pattern, then just move the stage 2
// image on to stage 3.
-
+
dng_mosaic_info *info = fMosaicInfo.Get ();
if (!info || !info->IsColorFilterArray ())
{
-
+
fStage3Image.Reset (fStage2Image.Release ());
-
+
}
-
+
else
{
-
+
// Remember the size of the stage 2 image.
-
+
dng_point stage2_size = fStage2Image->Size ();
-
+
// Special case multi-channel CFA interpolation.
-
+
if ((fStage2Image->Planes () > 1) && (srcPlane < 0))
{
-
- DoMergeStage3 (host);
-
+
+ DoMergeStage3 (host,
+ scaleTransforms);
+
}
-
+
// Else do a single channel interpolation.
-
+
else
{
-
- DoInterpolateStage3 (host, srcPlane);
-
+
+ DoInterpolateStage3 (host,
+ srcPlane,
+ scaleTransforms);
+
}
-
+
// Calculate the ratio of the stage 3 image size to stage 2 image size.
-
+
dng_point stage3_size = fStage3Image->Size ();
-
+
fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h;
fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v;
-
+
}
}
-
+
/*****************************************************************************/
void dng_negative::BuildStage3Image (dng_host &host,
int32 srcPlane)
{
-
+
// Finalize the mosaic information.
-
+
dng_mosaic_info *info = fMosaicInfo.Get ();
-
+
if (info)
{
-
+
info->PostParse (host, *this);
-
+
}
-
+
// Do the interpolation as required.
+
+ DoBuildStage3 (host, srcPlane, NULL);
+
+ // Delete the stage2 image now that we have computed the stage 3 image,
+ // unless the host wants to preserve it.
- DoBuildStage3 (host, srcPlane);
-
- // Delete the stage2 image now that we have computed the stage 3 image.
-
- fStage2Image.Reset ();
+ if (!host.WantsPreserveStage2 ())
+ {
+
+ fStage2Image.Reset ();
+ }
+
// Are we done with the mosaic info?
-
+
if (fRawImageStage >= rawImageStagePreOpcode3)
{
- ClearMosaicInfo ();
+ // If we're preserving the stage 2 image, also preserve the mosaic
+ // info.
+
+ if (!host.WantsPreserveStage2 ())
+ {
+
+ ClearMosaicInfo ();
+ }
+
// To support saving linear DNG files, to need to account for
// and upscaling during interpolation.
if (fRawToFullScaleH > 1.0)
{
-
+
uint32 adjust = Round_uint32 (fRawToFullScaleH);
-
+
fDefaultCropSizeH .n *= adjust;
fDefaultCropOriginH.n *= adjust;
fDefaultScaleH .d *= adjust;
-
+
fRawToFullScaleH /= (real64) adjust;
-
+
}
-
+
if (fRawToFullScaleV > 1.0)
{
-
+
uint32 adjust = Round_uint32 (fRawToFullScaleV);
-
+
fDefaultCropSizeV .n *= adjust;
fDefaultCropOriginV.n *= adjust;
fDefaultScaleV .d *= adjust;
-
+
fRawToFullScaleV /= (real64) adjust;
-
+
}
}
-
+
+ // Resample the transparency mask if required.
+
+ ResizeTransparencyToMatchStage3 (host);
+
// Grab clone of raw image if required.
-
+
if (fRawImageStage == rawImageStagePreOpcode3)
{
-
+
fRawImage.Reset (fStage3Image->Clone ());
+
+ fRawImageBlackLevel = fStage3BlackLevel;
+
+ if (fTransparencyMask.Get ())
+ {
+ fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
+ }
+ if (fDepthMap.Get ())
+ {
+ fRawDepthMap.Reset (fDepthMap->Clone ());
+ }
+
}
-
+
// Process opcode list 3.
-
+
host.ApplyOpcodeList (fOpcodeList3, *this, fStage3Image);
-
+
// See if we are done with the opcode list 3.
-
+
if (fRawImageStage > rawImageStagePreOpcode3)
{
- fOpcodeList3.Clear ();
+ // Currently re-use the same flag for preserving the opcode list.
- }
+ if (!host.WantsPreserveStage2 ())
+ {
+
+ fOpcodeList3.Clear ();
+ }
+
+ }
+
+ // Just in case the opcode list 3 changed the image size, resample the
+ // transparency mask again if required. This is nearly always going
+ // to be a fast NOP operation.
+
+ ResizeTransparencyToMatchStage3 (host);
+
+ // Depth maps are often lower resolution than the main image,
+ // so make sure we upsample if required.
+
+ ResizeDepthToMatchStage3 (host);
+
+ // Update Floating Point flag.
+
+ SetFloatingPoint (fStage3Image->PixelType () == ttFloat);
+
// Don't need to grab a copy of raw data at this stage since
// it is kept around as the stage 3 image.
-
+
}
+
+/******************************************************************************/
+
+// RESEARCH: Instead of using a constant slope, consider using a family
+// of slopes ranging from the original one (1/16) to a limit of 1/128,
+// depending on the histogram distribution.
+
+static const real64 kSceneProxyCurveSlope = 1.0 / 128.0;
+
+static inline real64 SceneProxyCurve (real64 x)
+ {
+
+ // The following code evaluates the inverse of:
+ //
+ // f (x) = (s * x) + ((1 - s) * x^3)
+ //
+ // where s is the slope of the function at the origin (x==0).
+
+ static const real64 s = kSceneProxyCurveSlope;
+
+ static const real64 k0 = pow (2.0, 1.0 / 3.0);
+
+ static const real64 k1 = 108.0 * s * s * s * (1.0 - s) * (1.0 - s) * (1.0 - s);
+
+ real64 k2 = (27.0 * x) - (54.0 * s * x) + (27.0 * x * s * s);
+
+ real64 k3 = pow (k2 + sqrt (k1 + k2 * k2), 1.0 / 3.0);
+
+ real64 y = (k3 / (3.0 * k0 * (1.0 - s))) - (k0 * s / k3);
+
+ y = Pin_real64 (0.0, y, 1.0);
+
+ DNG_ASSERT (Abs_real64 (x - (kSceneProxyCurveSlope * y +
+ (1.0 - kSceneProxyCurveSlope) * y * y * y)) < 0.0000001,
+ "SceneProxyCurve round trip error");
+
+ return y;
+
+ }
+
+/*****************************************************************************/
+
+static const real64 kOutputProxyCurveSlope = 1.0 / 16.0;
+
+static inline real64 OutputProxyCurve (real64 x)
+ {
+
+ DNG_ASSERT (kOutputProxyCurveSlope == 1.0 / 16.0,
+ "OutputProxyCurve unexpected slope");
+
+ real64 y = (sqrt (960.0 * x + 1.0) - 1.0) / 30.0;
+
+ DNG_ASSERT (Abs_real64 (x - (kOutputProxyCurveSlope * y +
+ (1.0 - kOutputProxyCurveSlope) * y * y)) < 0.0000001,
+ "OutputProxyCurve round trip error");
+
+ return y;
+
+ }
+
+/*****************************************************************************/
+
+class dng_gamma_encode_proxy : public dng_1d_function
+ {
+
+ private:
+
+ real64 fLower;
+ real64 fUpper;
+
+ bool fIsSceneReferred;
+
+ real64 fStage3BlackLevel;
+
+ real64 fBlackLevel;
+
+ public:
+
+ dng_gamma_encode_proxy (real64 lower,
+ real64 upper,
+ bool isSceneReferred,
+ real64 stage3BlackLevel,
+ real64 blackLevel)
+
+ : fLower (lower)
+ , fUpper (upper)
+ , fIsSceneReferred (isSceneReferred)
+ , fStage3BlackLevel (stage3BlackLevel)
+ , fBlackLevel (blackLevel / 255.0)
+
+ {
+
+ }
+
+ virtual real64 Evaluate (real64 x) const
+ {
+
+ real64 y;
+
+ if (fIsSceneReferred)
+ {
+
+ if (fLower < fStage3BlackLevel)
+ {
+
+ x = Pin_real64 (-1.0,
+ (x - fStage3BlackLevel) / (fUpper - fStage3BlackLevel),
+ 1.0);
+
+ if (x >= 0.0)
+ {
+
+ y = SceneProxyCurve (x);
+
+ }
+
+ else
+ {
+
+ y = -SceneProxyCurve (-x);
+
+ }
+
+ y = Pin_real64 (0.0, y * (1.0 - fBlackLevel) + fBlackLevel, 1.0);
+
+ }
+
+ else
+ {
+
+ x = Pin_real64 (0.0, (x - fLower) / (fUpper - fLower), 1.0);
+
+ y = SceneProxyCurve (x);
+
+ }
+
+ }
+
+ else
+ {
+
+ x = Pin_real64 (0.0, (x - fLower) / (fUpper - fLower), 1.0);
+
+ y = OutputProxyCurve (x);
+
+ }
+
+ return y;
+
+ }
+
+ };
/*****************************************************************************/
-dng_exif * dng_negative::MakeExif ()
+class dng_encode_proxy_task: public dng_area_task,
+ private dng_uncopyable
{
+
+ private:
+
+ const dng_image &fSrcImage;
+
+ dng_image &fDstImage;
+
+ AutoPtr<dng_memory_block> fTable16 [kMaxColorPlanes];
+
+ public:
+
+ dng_encode_proxy_task (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const real64 *lower,
+ const real64 *upper,
+ bool isSceneReferred,
+ real64 stage3BlackLevel,
+ real64 *blackLevel);
+
+ 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_exif *exif = new dng_exif ();
+/*****************************************************************************/
- if (!exif)
+dng_encode_proxy_task::dng_encode_proxy_task (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ const real64 *lower,
+ const real64 *upper,
+ bool isSceneReferred,
+ real64 stage3BlackLevel,
+ real64 *blackLevel)
+
+ : dng_area_task ("dng_encode_proxy_task")
+
+ , fSrcImage (srcImage)
+ , fDstImage (dstImage)
+
+ {
+
+ for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
{
- ThrowMemoryFull ();
+
+ fTable16 [plane] . Reset (host.Allocate (0x10000 * sizeof (uint16)));
+
+ dng_gamma_encode_proxy gamma (lower [plane],
+ upper [plane],
+ isSceneReferred,
+ stage3BlackLevel,
+ blackLevel [plane]);
+
+ // Compute fast approximation of encoding table.
+
+ dng_1d_table table32;
+
+ table32.Initialize (host.Allocator (), gamma);
+
+ table32.Expand16 (fTable16 [plane]->Buffer_uint16 ());
+
+ // The gamma curve has some fairly high curvature near
+ // the black point, and the above approximation can actually
+ // change results. So use exact math near the black point.
+ // Still very fast, since we are only computing a small
+ // faction of the range exactly.
+
+ {
+
+ const int32 kHighResRadius = 1024;
+
+ uint32 zeroPt = Round_uint32 (stage3BlackLevel * 65535.0);
+
+ uint32 highResLower = Max_int32 (0 , zeroPt - kHighResRadius);
+ uint32 highResUpper = Min_int32 (0x10000, zeroPt + kHighResRadius);
+
+ for (uint32 j = highResLower; j < highResUpper; j++)
+ {
+
+ real64 x = j * (1.0 / 65535.0);
+
+ real64 y = gamma.Evaluate (x);
+
+ uint16 z = Pin_uint16 (Round_int32 (y * 65535.0));
+
+ fTable16 [plane]->Buffer_uint16 () [j] = z;
+
+ }
+
+ }
+
}
+
+ }
- return exif;
+/*****************************************************************************/
+
+void dng_encode_proxy_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);
+
+ int32 sColStep = srcBuffer.fColStep;
+ int32 dColStep = dstBuffer.fColStep;
+
+ const uint16 *noise = dng_dither::Get ().NoiseBuffer16 ();
+
+ for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
+ {
+
+ const uint16 *map = fTable16 [plane]->Buffer_uint16 ();
+
+ for (int32 row = tile.t; row < tile.b; row++)
+ {
+
+ const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (row, tile.l, plane);
+
+ uint8 *dPtr = dstBuffer.DirtyPixel_uint8 (row, tile.l, plane);
+
+ const uint16 *rPtr = &noise [(row & dng_dither::kRNGMask) * dng_dither::kRNGSize];
+
+ for (int32 col = tile.l; col < tile.r; col++)
+ {
+
+ uint32 x = *sPtr;
+
+ uint32 r = rPtr [col & dng_dither::kRNGMask];
+
+ x = map [x];
+
+ x = (((x << 8) - x) + r) >> 16;
+
+ *dPtr = (uint8) x;
+
+ sPtr += sColStep;
+ dPtr += dColStep;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/******************************************************************************/
+bool dng_negative::SupportsPreservedBlackLevels (dng_host & /* host */)
+ {
+
+ return false;
+
}
-/*****************************************************************************/
+/******************************************************************************/
-dng_xmp * dng_negative::MakeXMP ()
+dng_image * dng_negative::EncodeRawProxy (dng_host &host,
+ const dng_image &srcImage,
+ dng_opcode_list &opcodeList,
+ real64 *blackLevel) const
{
+
+ if (srcImage.PixelType () != ttShort)
+ {
+ return NULL;
+ }
+
+ real64 lower [kMaxColorPlanes];
+ real64 upper [kMaxColorPlanes];
+
+ {
+
+ const real64 kClipFraction = 0.00001;
+
+ uint64 pixels = (uint64) srcImage.Bounds ().H () *
+ (uint64) srcImage.Bounds ().W ();
+
+ uint32 limit = Round_int32 ((real64) pixels * kClipFraction);
+
+ AutoPtr<dng_memory_block> histData (host.Allocate (65536 * sizeof (uint32)));
+
+ uint32 *hist = histData->Buffer_uint32 ();
+
+ for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
+ {
+
+ HistogramArea (host,
+ srcImage,
+ srcImage.Bounds (),
+ hist,
+ 65535,
+ plane);
+
+ uint32 total = 0;
+
+ uint32 upperIndex = 65535;
+
+ while (total + hist [upperIndex] <= limit && upperIndex > 255)
+ {
+
+ total += hist [upperIndex];
+
+ upperIndex--;
+
+ }
+
+ total = 0;
+
+ uint32 lowerIndex = 0;
+
+ while (total + hist [lowerIndex] <= limit && lowerIndex < upperIndex - 255)
+ {
+
+ total += hist [lowerIndex];
+
+ lowerIndex++;
+
+ }
- dng_xmp *xmp = new dng_xmp (Allocator ());
+ lower [plane] = lowerIndex / 65535.0;
+ upper [plane] = upperIndex / 65535.0;
+
+ }
+
+ }
+
+ bool isSceneReferred = (ColorimetricReference () == crSceneReferred);
+
+ real64 stage3BlackLevel = Stage3BlackLevelNormalized ();
+
+ for (uint32 n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ blackLevel [n] = 0.0;
+ }
+
+ if (isSceneReferred && stage3BlackLevel > 0.0)
+ {
+
+ for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
+ {
+
+ if (lower [plane] < stage3BlackLevel)
+ {
+
+ upper [plane] = Max_real64 (upper [plane],
+ stage3BlackLevel +
+ (stage3BlackLevel - lower [plane]) *
+ (1.0 / kMaxStage3BlackLevelNormalized - 1.0));
+
+ upper [plane] = Min_real64 (upper [plane], 1.0);
+
+ real64 negRange = SceneProxyCurve ((stage3BlackLevel - lower [plane]) /
+ (upper [plane] - stage3BlackLevel));
+
+ real64 outBlack = negRange / (1.0 + negRange);
+
+ blackLevel [plane] = Min_real64 (kMaxStage3BlackLevelNormalized * 255.0,
+ ceil (outBlack * 255.0));
+
+ }
+
+ }
+
+ }
+
+ // Apply the gamma encoding, using dither when downsampling to 8-bit.
+
+ AutoPtr<dng_image> dstImage (host.Make_dng_image (srcImage.Bounds (),
+ srcImage.Planes (),
+ ttByte));
- if (!xmp)
{
- ThrowMemoryFull ();
+
+ dng_encode_proxy_task task (host,
+ srcImage,
+ *dstImage,
+ lower,
+ upper,
+ isSceneReferred,
+ stage3BlackLevel,
+ blackLevel);
+
+ host.PerformAreaTask (task,
+ srcImage.Bounds ());
+
+ }
+
+ // Add opcodes to undo the gamma encoding.
+
+ {
+
+ for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
+ {
+
+ dng_area_spec areaSpec (srcImage.Bounds (),
+ plane);
+
+ real64 coefficient [4];
+
+ coefficient [0] = 0.0;
+
+ if (isSceneReferred)
+ {
+ coefficient [1] = kSceneProxyCurveSlope;
+ coefficient [2] = 0.0;
+ coefficient [3] = 1.0 - coefficient [1];
+ }
+ else
+ {
+ coefficient [1] = kOutputProxyCurveSlope;
+ coefficient [2] = 1.0 - coefficient [1];
+ coefficient [3] = 0.0;
+ }
+
+ if (lower [plane] < stage3BlackLevel)
+ {
+
+ real64 rescale = (upper [plane] - stage3BlackLevel) / (1.0 - stage3BlackLevel);
+
+ coefficient [0] *= rescale;
+ coefficient [1] *= rescale;
+ coefficient [2] *= rescale;
+ coefficient [3] *= rescale;
+
+ }
+
+ else
+ {
+
+ real64 rescale = (upper [plane] - lower [plane]) / (1.0 - stage3BlackLevel);
+
+ coefficient [0] *= rescale;
+ coefficient [1] *= rescale;
+ coefficient [2] *= rescale;
+ coefficient [3] *= rescale;
+
+ coefficient [0] += (lower [plane] - stage3BlackLevel) / (1.0 - stage3BlackLevel);
+
+ }
+
+ AutoPtr<dng_opcode> opcode (new dng_opcode_MapPolynomial (areaSpec,
+ isSceneReferred ? 3 : 2,
+ coefficient));
+
+ opcodeList.Append (opcode);
+
+ }
+
}
+
+ return dstImage.Release ();
+
+ }
+
+/******************************************************************************/
+
+void dng_negative::AdjustProfileForStage3 ()
+ {
+
+ // For dng_sdk, the stage3 image's color space is always the same as the
+ // raw image's color space.
+
+ }
+
+/******************************************************************************/
- return xmp;
+void dng_negative::ConvertToProxy (dng_host &host,
+ dng_image_writer &writer,
+ uint32 proxySize,
+ uint64 proxyCount)
+ {
+
+ if (!proxySize)
+ {
+ proxySize = kMaxImageSide;
+ }
+
+ if (!proxyCount)
+ {
+ proxyCount = (uint64) proxySize * proxySize;
+ }
+
+ // Don't need to keep private data around in non-full size proxies.
+
+ if (proxySize < kMaxImageSide ||
+ proxyCount < kMaxImageSide * kMaxImageSide)
+ {
+
+ ClearMakerNote ();
+
+ ClearPrivateData ();
+
+ }
+
+ // See if we already have an acceptable proxy image.
+
+ if (fRawImage.Get () &&
+ fRawImage->PixelType () == ttByte &&
+ fRawImage->Bounds () == DefaultCropArea () &&
+ fRawImage->Bounds ().H () <= proxySize &&
+ fRawImage->Bounds ().W () <= proxySize &&
+ (uint64) fRawImage->Bounds ().H () *
+ (uint64) fRawImage->Bounds ().W () <= proxyCount &&
+ fRawToFullScaleH == 1.0 &&
+ fRawToFullScaleV == 1.0 &&
+ (!GetMosaicInfo () || !GetMosaicInfo ()->IsColorFilterArray ()) &&
+ fRawJPEGImage.Get () &&
+ (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
+ {
+
+ return;
+
+ }
+
+ if (fRawImage.Get () &&
+ fRawImage->PixelType () == ttFloat &&
+ fRawImage->Bounds ().H () <= proxySize &&
+ fRawImage->Bounds ().W () <= proxySize &&
+ (uint64) fRawImage->Bounds ().H () *
+ (uint64) fRawImage->Bounds ().W () <= proxyCount &&
+ fRawToFullScaleH == 1.0 &&
+ fRawToFullScaleV == 1.0 &&
+ RawFloatBitDepth () == 16 &&
+ (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
+ {
+
+ return;
+
+ }
+
+ // Clear any grabbed raw image, since we are going to start
+ // building the proxy with the stage3 image.
+
+ fRawImage.Reset ();
+
+ fRawImageBlackLevel = 0;
+
+ ClearRawJPEGImage ();
+
+ SetRawFloatBitDepth (0);
+
+ ClearLinearizationInfo ();
+
+ ClearMosaicInfo ();
+
+ fOpcodeList1.Clear ();
+ fOpcodeList2.Clear ();
+ fOpcodeList3.Clear ();
+
+ // Adjust the profile to match the stage 3 image, if required.
+
+ AdjustProfileForStage3 ();
+
+ // Not saving the raw-most image, do the old raw digest is no
+ // longer valid.
+
+ ClearRawImageDigest ();
+
+ ClearRawJPEGImageDigest ();
+
+ // Trim off extra pixels outside the default crop area.
+
+ dng_rect defaultCropArea = DefaultCropArea ();
+
+ if (Stage3Image ()->Bounds () != defaultCropArea)
+ {
+
+ fStage3Image->Trim (defaultCropArea);
+
+ if (fTransparencyMask.Get ())
+ {
+ fTransparencyMask->Trim (defaultCropArea);
+ }
+
+ if (fDepthMap.Get ())
+ {
+ fDepthMap->Trim (defaultCropArea);
+ fRawDepthMap.Reset ();
+ }
+
+ fDefaultCropOriginH = dng_urational (0, 1);
+ fDefaultCropOriginV = dng_urational (0, 1);
+
+ }
+
+ // Figure out the requested proxy pixel size.
+
+ real64 aspectRatio = AspectRatio ();
+
+ dng_point newSize (proxySize, proxySize);
+
+ if (aspectRatio >= 1.0)
+ {
+ newSize.v = Max_int32 (1, Round_int32 (proxySize / aspectRatio));
+ }
+ else
+ {
+ newSize.h = Max_int32 (1, Round_int32 (proxySize * aspectRatio));
+ }
+
+ newSize.v = Min_int32 (newSize.v, DefaultFinalHeight ());
+ newSize.h = Min_int32 (newSize.h, DefaultFinalWidth ());
+
+ if ((uint64) newSize.v *
+ (uint64) newSize.h > proxyCount)
+ {
+ if (aspectRatio >= 1.0)
+ {
+
+ newSize.h = (uint32) sqrt (proxyCount * aspectRatio);
+
+ newSize.v = Max_int32 (1, Round_int32 (newSize.h / aspectRatio));
+
+ }
+
+ else
+ {
+
+ newSize.v = (uint32) sqrt (proxyCount / aspectRatio);
+
+ newSize.h = Max_int32 (1, Round_int32 (newSize.v * aspectRatio));
+
+ }
+
+ }
+
+ // If this is fewer pixels, downsample the stage 3 image to that size.
+
+ dng_point oldSize = defaultCropArea.Size ();
+
+ real64 pixelAspect = PixelAspectRatio ();
+
+ if ((uint64) newSize.v * (uint64) newSize.h <
+ (uint64) oldSize.v * (uint64) oldSize.h ||
+ pixelAspect < 0.99 ||
+ pixelAspect > 1.01)
+ {
+
+ const dng_image &srcImage (*Stage3Image ());
+
+ AutoPtr<dng_image> dstImage (host.Make_dng_image (newSize,
+ srcImage.Planes (),
+ srcImage.PixelType ()));
+
+ host.ResampleImage (srcImage,
+ *dstImage);
+
+ fStage3Image.Reset (dstImage.Release ());
+
+ fDefaultCropSizeH = dng_urational (newSize.h, 1);
+ fDefaultCropSizeV = dng_urational (newSize.v, 1);
+
+ fDefaultScaleH = dng_urational (1, 1);
+ fDefaultScaleV = dng_urational (1, 1);
+
+ fBestQualityScale = dng_urational (1, 1);
+
+ fRawToFullScaleH = 1.0;
+ fRawToFullScaleV = 1.0;
+
+ }
+
+ // If there is still a raw to full scale factor, we need to
+ // remove it and adjust the crop coordinates.
+
+ else if (fRawToFullScaleH != 1.0 ||
+ fRawToFullScaleV != 1.0)
+ {
+
+ fDefaultCropSizeH = dng_urational (oldSize.h, 1);
+ fDefaultCropSizeV = dng_urational (oldSize.v, 1);
+
+ fDefaultScaleH = dng_urational (1, 1);
+ fDefaultScaleV = dng_urational (1, 1);
+
+ fBestQualityScale = dng_urational (1, 1);
+
+ fRawToFullScaleH = 1.0;
+ fRawToFullScaleV = 1.0;
+
+ }
+
+ // Convert 32-bit floating point images to 16-bit floating point to
+ // save space.
+
+ if (Stage3Image ()->PixelType () == ttFloat)
+ {
+
+ fRawImage.Reset (host.Make_dng_image (Stage3Image ()->Bounds (),
+ Stage3Image ()->Planes (),
+ ttFloat));
+
+ fRawImageBlackLevel = 0;
+
+ LimitFloatBitDepth (host,
+ *Stage3Image (),
+ *fRawImage,
+ 16,
+ 32768.0f);
+
+ SetRawFloatBitDepth (16);
+
+ SetWhiteLevel (32768);
+
+ }
+
+ else
+ {
+
+ // Convert 16-bit deep images to 8-bit deep image for saving.
+
+ real64 blackLevel [kMaxSamplesPerPixel];
+
+ fRawImage.Reset (EncodeRawProxy (host,
+ *Stage3Image (),
+ fOpcodeList2,
+ blackLevel));
+
+ fRawImageBlackLevel = 0;
+
+ if (fRawImage.Get ())
+ {
+
+ SetWhiteLevel (255);
+
+ for (uint32 plane = 0; plane < fRawImage->Planes (); plane++)
+ {
+ SetBlackLevel (blackLevel [plane], plane);
+ }
+
+ // Compute JPEG compressed version.
+
+ if (fRawImage->PixelType () == ttByte &&
+ host.SaveDNGVersion () >= dngVersion_1_4_0_0)
+ {
+
+ AutoPtr<dng_jpeg_image> jpegImage (new dng_jpeg_image);
+
+ jpegImage->Encode (host,
+ *this,
+ writer,
+ *fRawImage);
+
+ SetRawJPEGImage (jpegImage);
+
+ }
+
+ }
+
+ }
+
+ // Deal with transparency mask.
+
+ if (TransparencyMask ())
+ {
+
+ const bool convertTo8Bit = true;
+
+ ResizeTransparencyToMatchStage3 (host, convertTo8Bit);
+
+ fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
+
+ }
+
+ // Deal with depth map.
+
+ if (DepthMap ())
+ {
+
+ ResizeDepthToMatchStage3 (host);
+
+ if (fRawDepthMap.Get ())
+ {
+
+ if (fRawDepthMap->Bounds ().W () > fDepthMap->Bounds ().W () ||
+ fRawDepthMap->Bounds ().H () > fDepthMap->Bounds ().H ())
+ {
+ fRawDepthMap.Reset ();
+ }
+
+ }
+
+ }
+
+ // Recompute the raw data unique ID, since we changed the image data.
+
+ RecomputeRawDataUniqueID (host);
+
}
/*****************************************************************************/
+bool dng_negative::IsProxy () const
+ {
+
+ return (DefaultCropSizeH () != OriginalDefaultCropSizeH ()) &&
+ (DefaultCropSizeV () != OriginalDefaultCropSizeV ());
+
+ }
+
+/*****************************************************************************/
+
dng_linearization_info * dng_negative::MakeLinearizationInfo ()
{
-
+
dng_linearization_info *info = new dng_linearization_info ();
-
+
if (!info)
{
ThrowMemoryFull ();
}
-
+
return info;
-
+
}
/*****************************************************************************/
void dng_negative::NeedLinearizationInfo ()
{
-
+
if (!fLinearizationInfo.Get ())
{
-
+
fLinearizationInfo.Reset (MakeLinearizationInfo ());
-
+
}
-
+
}
/*****************************************************************************/
dng_mosaic_info * dng_negative::MakeMosaicInfo ()
{
-
+
dng_mosaic_info *info = new dng_mosaic_info ();
-
+
if (!info)
{
ThrowMemoryFull ();
}
-
+
return info;
-
+
}
/*****************************************************************************/
void dng_negative::NeedMosaicInfo ()
{
-
+
if (!fMosaicInfo.Get ())
{
-
+
fMosaicInfo.Reset (MakeMosaicInfo ());
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::SetTransparencyMask (AutoPtr<dng_image> &image,
+ uint32 bitDepth)
+ {
+
+ fTransparencyMask.Reset (image.Release ());
+
+ fRawTransparencyMaskBitDepth = bitDepth;
+
+ }
+
+/*****************************************************************************/
+const dng_image * dng_negative::TransparencyMask () const
+ {
+
+ return fTransparencyMask.Get ();
+
+ }
+
+/*****************************************************************************/
+
+const dng_image * dng_negative::RawTransparencyMask () const
+ {
+
+ if (fRawTransparencyMask.Get ())
+ {
+
+ return fRawTransparencyMask.Get ();
+
+ }
+
+ return TransparencyMask ();
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_negative::RawTransparencyMaskBitDepth () const
+ {
+
+ if (fRawTransparencyMaskBitDepth)
+ {
+
+ return fRawTransparencyMaskBitDepth;
+
+ }
+
+ const dng_image *mask = RawTransparencyMask ();
+
+ if (mask)
+ {
+
+ switch (mask->PixelType ())
+ {
+
+ case ttByte:
+ return 8;
+
+ case ttShort:
+ return 16;
+
+ case ttFloat:
+ return 32;
+
+ default:
+ ThrowProgramError ();
+
+ }
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::ReadTransparencyMask (dng_host &host,
+ dng_stream &stream,
+ dng_info &info)
+ {
+
+ if (info.fMaskIndex != -1)
+ {
+
+ // Allocate image we are reading.
+
+ dng_ifd &maskIFD = *info.fIFD [info.fMaskIndex];
+
+ fTransparencyMask.Reset (host.Make_dng_image (maskIFD.Bounds (),
+ 1,
+ maskIFD.PixelType ()));
+
+ // Read the image.
+
+ maskIFD.ReadImage (host,
+ stream,
+ *fTransparencyMask.Get ());
+
+ // Remember the pixel depth.
+
+ fRawTransparencyMaskBitDepth = maskIFD.fBitsPerSample [0];
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::ResizeTransparencyToMatchStage3 (dng_host &host,
+ bool convertTo8Bit)
+ {
+
+ if (TransparencyMask ())
+ {
+
+ if ((TransparencyMask ()->Bounds () != fStage3Image->Bounds ()) ||
+ (TransparencyMask ()->PixelType () != ttByte && convertTo8Bit))
+ {
+
+ AutoPtr<dng_image> newMask (host.Make_dng_image (fStage3Image->Bounds (),
+ 1,
+ convertTo8Bit ?
+ ttByte :
+ TransparencyMask ()->PixelType ()));
+
+ host.ResampleImage (*TransparencyMask (),
+ *newMask);
+
+ fTransparencyMask.Reset (newMask.Release ());
+
+ if (!fRawTransparencyMask.Get ())
+ {
+ fRawTransparencyMaskBitDepth = 0;
+ }
+
+ else if (convertTo8Bit)
+ {
+ fRawTransparencyMaskBitDepth = 8;
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+bool dng_negative::NeedFlattenTransparency (dng_host & /* host */)
+ {
+
+ return false;
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::FlattenTransparency (dng_host & /* host */)
+ {
+
+ ThrowNotYetImplemented ();
+
+ }
+
+/*****************************************************************************/
+
+const dng_image * dng_negative::UnflattenedStage3Image () const
+ {
+
+ if (fUnflattenedStage3Image.Get ())
+ {
+
+ return fUnflattenedStage3Image.Get ();
+
}
+
+ return fStage3Image.Get ();
+
+ }
+
+/*****************************************************************************/
+void dng_negative::SetDepthMap (AutoPtr<dng_image> &depthMap)
+ {
+
+ fDepthMap.Reset (depthMap.Release ());
+
+ SetHasDepthMap (fDepthMap.Get () != NULL);
+
}
/*****************************************************************************/
+
+void dng_negative::ReadDepthMap (dng_host &host,
+ dng_stream &stream,
+ dng_info &info)
+ {
+
+ if (info.fDepthIndex != -1)
+ {
+
+ // Allocate image we are reading.
+
+ dng_ifd &depthIFD = *info.fIFD [info.fDepthIndex];
+
+ fDepthMap.Reset (host.Make_dng_image (depthIFD.Bounds (),
+ 1,
+ depthIFD.PixelType ()));
+
+ // Read the image.
+
+ depthIFD.ReadImage (host,
+ stream,
+ *fDepthMap.Get ());
+
+ SetHasDepthMap (fDepthMap.Get () != NULL);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_negative::ResizeDepthToMatchStage3 (dng_host &host)
+ {
+
+ if (DepthMap ())
+ {
+
+ if (DepthMap ()->Bounds () != fStage3Image->Bounds ())
+ {
+
+ // If we are upsampling, and have not grabbed the raw depth map
+ // yet, do so now.
+
+ if (!fRawDepthMap.Get ())
+ {
+
+ uint64 imagePixels = fStage3Image->Bounds ().H () * (uint64)
+ fStage3Image->Bounds ().W ();
+
+ uint64 depthPixels = DepthMap ()->Bounds ().H () * (uint64)
+ DepthMap ()->Bounds ().W ();
+
+ if (depthPixels < imagePixels)
+ {
+ fRawDepthMap.Reset (fDepthMap->Clone ());
+ }
+
+ }
+
+ AutoPtr<dng_image> newMap (host.Make_dng_image (fStage3Image->Bounds (),
+ 1,
+ DepthMap ()->PixelType ()));
+
+ host.ResampleImage (*DepthMap (),
+ *newMap);
+
+ fDepthMap.Reset (newMap.Release ());
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_negative.h b/core/libs/dngwriter/extra/dng_sdk/dng_negative.h
index 06c52e7e8c..98b558fbc4 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_negative.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_negative.h
@@ -1,1656 +1,2713 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_negative.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \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_mutex.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
+
+/*****************************************************************************/
+
/// \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);
}
- real64 Scale () const
- {
- return fScale;
+ /// The scale (slope, gain) of the noise function.
+
+ real64 Scale () const
+ {
+ return fScale;
}
- real64 Offset () const
- {
- return fOffset;
+ /// 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;
+ dng_std_vector<dng_noise_function> fNoiseFunctions;
public:
+ /// Create empty (invalid) noise profile.
+
dng_noise_profile ();
- explicit dng_noise_profile (const std::vector<dng_noise_function> &functions);
+ /// Create noise profile with the specified noise functions (1 per plane).
+
+ explicit dng_noise_profile (const dng_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;
+
+ /// Equality test.
+
+ bool operator== (const dng_noise_profile &profile) const;
+
+ bool operator!= (const dng_noise_profile &profile) const
+ {
+ return !(*this == profile);
+ }
};
/*****************************************************************************/
+/// \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 fSourceMIME;
+
+ 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 MIME type.
+
+ void SetSourceMIME (const char *s)
+ {
+ fSourceMIME.Set (s);
+ }
+
+ const dng_string & SourceMIME () const
+ {
+ return fSourceMIME;
+ }
+
+ };
+
+/*****************************************************************************/
+
+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 object stores an associated allocator. It does not do
+
+ // 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_negative object.
-
+ // 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;
-
- // Base orientation of both the thumbnail and raw data. This is
- // generally based on the EXIF values.
-
- bool fHasBaseOrientation;
-
- dng_orientation fBaseOrientation;
-
+
// 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;
+ // Enhanced images can change the applied noise reduction, so we
+ // need to keep around the original value.
+
+ dng_urational fRawNoiseReductionApplied;
+
// Amount of noise for this negative (see dng_noise_profile for details).
dng_noise_profile fNoiseProfile;
-
+
+ // Enhanced images can change the noise profile, so we
+ // need to keep around the original value.
+
+ dng_noise_profile fRawNoiseProfile;
+
// 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;
-
+
+ // Enhanced images can change the baseline sharpness, so we
+ // need to keep around the original value.
+
+ dng_urational fRawBaselineSharpness;
+
// 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;
-
- // Colorimetric reference.
-
+
+ // Colormetric reference.
+
uint32 fColorimetricReference;
- // Number of color channels for this image (e.g. 1, 3, or 4).
+ // Is the stage 3 image floating point?
+ bool fFloatingPoint;
+
+ // 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.
-
+ // 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;
-
+
+ dng_std_vector<dng_camera_profile *> fCameraProfile;
+
// "As shot" camera profile name.
-
+
dng_string fAsShotProfileName;
-
- // Raw image data digest. This is a MD5 fingerprint of the raw image data
- // in the file, computed using a specific algorithm. It can be used
- // verify the raw data has not been corrupted.
-
+
+ // 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 identifier for the actual
+ // 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;
+ mutable dng_std_mutex fRawDataUniqueIDMutex;
+
// Original raw file name. Just the file name, not the full path.
-
+
dng_string fOriginalRawFileName;
-
- // Is the original raw file data available?
-
+
+ // 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;
-
- // 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;
-
- // Did the legacy ITPC block use UTF8?
-
- bool fUsedUTF8forIPTC;
-
- // XMP data.
-
- AutoPtr<dng_xmp> fXMP;
-
- // Was there a valid embedded XMP block?
-
- bool fValidEmbeddedXMP;
-
- // 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;
-
+
+ // 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 demosaic the raw data.
-
+
+ // 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;
+
+ // Additional gain applied when building the stage 3 image.
+
+ real64 fStage3Gain;
- // Additiona gain applied when building the stage 3 image.
+ // Optical black level of stage 3 image (in [0,65535]).
- real64 fStage3Gain;
+ uint16 fStage3BlackLevel;
// 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 black level of the raw image (if not encoded by linearization info).
+
+ uint16 fRawImageBlackLevel;
+
+ // 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;
+
+ // Depth map.
+
+ bool fHasDepthMap;
+
+ AutoPtr<dng_image> fDepthMap;
+
+ // Grabbed depth map, if we are not saving the current map.
+
+ AutoPtr<dng_image> fRawDepthMap;
+
+ // Depth metadata.
+
+ uint32 fDepthFormat;
+ dng_urational fDepthNear;
+ dng_urational fDepthFar;
+ uint32 fDepthUnits;
+ uint32 fDepthMeasureType;
+
+ // Enhance metadata.
+
+ dng_string fEnhanceParams;
+
public:
-
+
virtual ~dng_negative ();
-
- static dng_negative * Make (dng_memory_allocator &allocator);
-
+
+ static dng_negative * Make (dng_host &host);
+
/// Provide access to the memory allocator used for this object.
-
+
dng_memory_allocator & Allocator () const
{
return fAllocator;
}
-
+
/// 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
- /// Setter for BaseOrientation.
+ /// Make a copy of the internal metadata generally as a basis for further
+ /// changes.
- void SetBaseOrientation (const dng_orientation &orientation);
+ dng_metadata * CloneInternalMetadata () const;
+
+ protected:
- /// Has BaseOrientation been set?
+ /// 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.
- bool HasBaseOrientation () const
+ const dng_metadata &InternalMetadata () const
{
- return fHasBaseOrientation;
+ 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 () const
+
+ const dng_orientation & BaseOrientation () METACONST
{
- return fBaseOrientation;
+ return Metadata ().BaseOrientation ();
}
-
+
/// Hook to allow SDK host code to add additional rotations.
-
- virtual dng_orientation Orientation () const;
-
+
+ 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);
-
+
+ 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;
}
- /// Setter for DefaultScale.
+ /// Is there a default user crop?
+
+ bool HasDefaultUserCrop () const
+ {
+ return (fDefaultUserCropT.As_real64 () != 0.0 ||
+ fDefaultUserCropL.As_real64 () != 0.0 ||
+ fDefaultUserCropB.As_real64 () != 1.0 ||
+ fDefaultUserCropR.As_real64 () != 1.0);
+ }
+
+ /// 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;
}
-
+
+ /// Is the best quality scale different than the default scale?
+
+ bool HasBestQualityScale () const
+ {
+ return fBestQualityScale.As_real64 () != 1.0;
+ }
+
/// 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 specifying a single scale factor, we use the horizontal
+ /// 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 ());
}
-
- /// The default crop area after applying the specified horizontal and
- /// vertical scale factors to the stage 3 image.
-
- dng_rect DefaultCropArea (real64 scaleH = 1.0,
- real64 scaleV = 1.0) const;
-
+
+ /// 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 ();
+
+ /// Set all the original size fields to a specific size.
+
+ void SetOriginalSizes (const dng_point &size);
+
+ /// 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;
}
+ // Sets the raw noise reduction applied to be a copy of the unenhanced
+ // noise reduction applied, if not set yet.
+
+ void SetRawNoiseReductionApplied ()
+ {
+ if (fRawNoiseReductionApplied.NotValid ())
+ {
+ fRawNoiseReductionApplied = fNoiseReductionApplied;
+ }
+ }
+
+ // Gets the raw NoiseReductionApplied value.
+
+ const dng_urational & RawNoiseReductionApplied () const
+ {
+ return fRawNoiseReductionApplied;
+ }
+
/// 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;
}
-
+
+ // Does this negative have a valid raw noise profile?
+
+ bool HasRawNoiseProfile () const
+ {
+ return fRawNoiseProfile.IsValidForNegative (*this);
+ }
+
+ // Sets the raw noise profile to be a copy of the unenhanced
+ // noise profile, if not set yet.
+
+ void SetRawNoiseProfile ()
+ {
+ if (!HasRawNoiseProfile ())
+ {
+ fRawNoiseProfile = fNoiseProfile;
+ }
+ }
+
+ // Getter for raw noise profile.
+
+ const dng_noise_profile & RawNoiseProfile () const
+ {
+ return fRawNoiseProfile;
+ }
+
/// 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 ();
}
- /// Setter for BaselineSharpness.
+ /// 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 ();
}
-
+
+ // Sets the raw baseline sharpness to be a copy of the baseline
+ // sharpness, if not set yet.
+
+ void SetRawBaselineSharpness ()
+ {
+ if (fRawBaselineSharpness.d == 0)
+ {
+ fRawBaselineSharpness = fBaselineSharpness;
+ }
+ }
+
+ // Gets the raw baseline sharpness value.
+
+ const dng_urational & RawBaselineSharpness () const
+ {
+ if (fRawBaselineSharpness.d != 0)
+ {
+ return fRawBaselineSharpness;
+ }
+ return fBaselineSharpness;
+ }
+
/// 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.
+ // Floating point flag.
+
+ void SetFloatingPoint (bool isFloatingPoint)
+ {
+ fFloatingPoint = isFloatingPoint;
+ }
+
+ bool IsFloatingPoint () const
+ {
+ return fFloatingPoint;
+ }
+
+ // HDR/NDR.
+ bool IsHighDynamicRange () const
+ {
+ return IsFloatingPoint () &&
+ ColorimetricReference () == crSceneReferred;
+ }
+
+ bool IsNormalDynamicRange () const
+ {
+ return !IsHighDynamicRange ();
+ }
+
+ /// 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;
-
- const dng_camera_profile * ProfileByID (const dng_camera_profile_id &id,
- bool useDefaultIfNoMatch = true) 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 * CameraProfileToEmbed () const;
-
+
+ // 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;
-
- // API for RawImageDigest:
-
+
+ // Compute a MD5 hash on an image, using a fixed algorithm.
+ // The results must be stable across different hardware, OSes,
+ // and software versions.
+
+ static dng_fingerprint FindImageDigest (dng_host &host,
+ const dng_image &image);
+
+ // API for RawImageDigest and NewRawImageDigest:
+
void SetRawImageDigest (const dng_fingerprint &digest)
{
fRawImageDigest = digest;
}
-
- void ClearRawImageDigest ()
+
+ void SetNewRawImageDigest (const dng_fingerprint &digest)
{
- fRawImageDigest.Clear ();
+ 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;
- }
-
+
+ dng_fingerprint RawDataUniqueID () const;
+
void FindRawDataUniqueID (dng_host &host) const;
-
- void RecomputeRawDataUniqueID (dng_host &host);
+
+ virtual 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)
{
- fIsMakerNoteSafe = safe;
+ Metadata ().SetMakerNoteSafety (safe);
}
-
- bool IsMakerNoteSafe () const
+
+ bool IsMakerNoteSafe () METACONST
{
- return fIsMakerNoteSafe;
+ return Metadata ().IsMakerNoteSafe ();
}
-
+
void SetMakerNote (AutoPtr<dng_memory_block> &block)
{
- fMakerNote.Reset (block.Release ());
+ Metadata ().SetMakerNote (block);
}
-
+
void ClearMakerNote ()
{
- fMakerNote.Reset ();
+ Metadata ().ClearMakerNote ();
}
-
- const void * MakerNoteData () const
+
+ const void * MakerNoteData () METACONST
{
- return fMakerNote.Get () ? fMakerNote->Buffer ()
- : NULL;
+ return Metadata ().MakerNoteData ();
}
-
- uint32 MakerNoteLength () const
+
+ uint32 MakerNoteLength () METACONST
{
- return fMakerNote.Get () ? fMakerNote->LogicalSize ()
- : 0;
+ return Metadata ().MakerNoteLength ();
}
-
+
// API for EXIF metadata:
-
+
dng_exif * GetExif ()
{
- return fExif.Get ();
+ return Metadata ().GetExif ();
}
-
+
+ #if qMetadataOnConst
+
const dng_exif * GetExif () const
{
- return fExif.Get ();
+ return Metadata ().GetExif ();
}
-
- virtual dng_memory_block * BuildExifBlock (const dng_resolution *resolution = NULL,
- bool includeIPTC = false,
- bool minimalEXIF = false,
- const dng_jpeg_preview *thumbnail = NULL) const;
-
+
+ #endif // qMetadataOnConst
+
+ void ResetExif (dng_exif * newExif)
+ {
+ Metadata ().ResetExif (newExif);
+ }
+
// API for original EXIF metadata.
-
+
dng_exif * GetOriginalExif ()
{
- return fOriginalExif.Get ();
+ return Metadata ().GetOriginalExif ();
}
-
+
+ #if qMetadataOnConst
+
const dng_exif * GetOriginalExif () const
{
- return fOriginalExif.Get ();
+ return Metadata ().GetOriginalExif ();
}
-
+
+ #endif // qMetadataOnConst
+
// 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 (bool padForTIFF,
- bool forceUTF8);
-
- bool UsedUTF8forIPTC () const
+ uint64 offset)
{
- return fUsedUTF8forIPTC;
+ Metadata ().SetIPTC (block, offset);
}
-
- void SetUsedUTF8forIPTC (bool used)
+
+ void SetIPTC (AutoPtr<dng_memory_block> &block)
{
- fUsedUTF8forIPTC = used;
+ 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);
-
+ bool xmpIsNewer = false)
+ {
+ return Metadata ().SetXMP (host,
+ buffer,
+ count,
+ xmpInSidecar,
+ xmpIsNewer);
+ }
+
dng_xmp * GetXMP ()
{
- return fXMP.Get ();
+ return Metadata ().GetXMP ();
}
-
+
+ #if qMetadataOnConst
+
const dng_xmp * GetXMP () const
{
- return fXMP.Get ();
+ return Metadata ().GetXMP ();
}
-
- bool XMPinSidecar () const
+
+ #endif // qMetadataOnConst
+
+ bool XMPinSidecar () METACONST
{
- return fXMPinSidecar;
+ 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 MIME type.
+
+ void SetSourceMIME (const char *s)
+ {
+ Metadata ().SetSourceMIME (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);
-
+ real64 black3,
+ int32 plane = -1);
+
+ void Set6x6Blacks (real64 blacks6x6 [36],
+ 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 SetQuadMosaic (uint32 pattern);
+ 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.
-
- virtual void SynchronizeMetadata ();
-
+
+ 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);
-
- void UpdateDateTimeToNow ();
-
+
+ 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;
-
- // Read the stage 1 image.
-
- virtual void ReadStage1Image (dng_host &host,
- dng_stream &stream,
- dng_info &info);
-
+
+ // Returns the raw image black level in 16-bit space.
+
+ uint16 RawImageBlackLevel () 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 opcode lists.
+
+ virtual void ReadOpcodeLists (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ // Read the stage 1 image.
+
+ virtual void ReadStage1Image (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ // Read the enhanced image directly into the stage 3 image.
+
+ virtual void ReadEnhancedImage (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,
- uint32 pixelType = ttShort);
-
+
+ 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;
}
- // IsPreview API:
+ // Optical black level of stage 3 image (in [0,65535]).
+
+ void SetStage3BlackLevel (uint16 level)
+ {
+ fStage3BlackLevel = level;
+ }
+
+ uint16 Stage3BlackLevel () const
+ {
+ return fStage3BlackLevel;
+ }
+
+ // Optical black level of stage 3 image (in [0,1]).
+
+ real64 Stage3BlackLevelNormalized () const
+ {
+ return fStage3BlackLevel * (1.0 / 65535.0);
+ }
+ // Is this negative permitted to support deferred black subtraction
+ // (by preserving offset or negative black values in the stage 3
+ // image)?
+ //
+ // If false, then fStage3BlackLevel must be zero.
+ // If true, then fStage3BlackLevel may or may not be zero.
+ //
+ // Default implementation return false.
+
+ virtual bool SupportsPreservedBlackLevels (dng_host &host);
+
+ // Adaptively encode a proxy image down to 8-bits/channel.
+
+ dng_image * EncodeRawProxy (dng_host &host,
+ const dng_image &srcImage,
+ dng_opcode_list &opcodeList,
+ real64 *blackLevel) const;
+
+ // Convert to a proxy negative.
+
+ void ConvertToProxy (dng_host &host,
+ dng_image_writer &writer,
+ uint32 proxySize = 0,
+ uint64 proxyCount = 0);
+
+ // IsProxy API:
+
+ bool IsProxy () const;
+
+ // 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 void ResizeTransparencyToMatchStage3 (dng_host &host,
+ bool convertTo8Bit = false);
+
+ virtual bool NeedFlattenTransparency (dng_host &host);
+
+ virtual void FlattenTransparency (dng_host &host);
+
+ const dng_image * UnflattenedStage3Image () const;
+
+ // Depth map API:
+
+ bool HasDepthMap () const
+ {
+ return fHasDepthMap;
+ }
+
+ void SetHasDepthMap (bool hasDepthMap)
+ {
+ fHasDepthMap = hasDepthMap;
+ }
+
+ const dng_image * DepthMap () const
+ {
+ return fDepthMap.Get ();
+ }
+
+ void SetDepthMap (AutoPtr<dng_image> &depthMap);
+
+ bool HasDepthMapImage () const
+ {
+ return (fDepthMap.Get () != NULL);
+ }
+
+ const dng_image * RawDepthMap () const
+ {
+ if (fRawDepthMap.Get ())
+ {
+ return fRawDepthMap.Get ();
+ }
+ return DepthMap ();
+ }
+
+ void ReadDepthMap (dng_host &host,
+ dng_stream &stream,
+ dng_info &info);
+
+ virtual void ResizeDepthToMatchStage3 (dng_host &host);
+
+ uint32 DepthFormat () const
+ {
+ return fDepthFormat;
+ }
+
+ void SetDepthFormat (uint32 format)
+ {
+ fDepthFormat = format;
+ }
+
+ const dng_urational & DepthNear () const
+ {
+ return fDepthNear;
+ }
+
+ void SetDepthNear (const dng_urational &dist)
+ {
+ fDepthNear = dist;
+ }
+
+ const dng_urational & DepthFar () const
+ {
+ return fDepthFar;
+ }
+
+ void SetDepthFar (const dng_urational &dist)
+ {
+ fDepthFar = dist;
+ }
+
+ uint32 DepthUnits () const
+ {
+ return fDepthUnits;
+ }
+
+ void SetDepthUnits (uint32 units)
+ {
+ fDepthUnits = units;
+ }
+
+ uint32 DepthMeasureType () const
+ {
+ return fDepthMeasureType;
+ }
+
+ void SetDepthMeasureType (uint32 measure)
+ {
+ fDepthMeasureType = measure;
+ }
+
+ // EnhanceParams API:
+
+ const dng_string & EnhanceParams () const
+ {
+ return fEnhanceParams;
+ }
+
+ void SetEnhanceParams (const dng_string &s)
+ {
+ fEnhanceParams = s;
+ }
+
+ void SetEnhanceParams (const char *s)
+ {
+ fEnhanceParams.Set (s);
+ }
+
protected:
-
- dng_negative (dng_memory_allocator &allocator);
-
+
+ dng_negative (dng_host &host);
+
virtual void Initialize ();
-
- virtual dng_exif * MakeExif ();
-
- virtual dng_xmp * MakeXMP ();
-
+
virtual dng_linearization_info * MakeLinearizationInfo ();
-
+
void NeedLinearizationInfo ();
-
+
virtual dng_mosaic_info * MakeMosaicInfo ();
-
+
void NeedMosaicInfo ();
-
- virtual void DoBuildStage2 (dng_host &host,
- uint32 pixelType);
-
+
+ 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);
-
+ int32 srcPlane,
+ dng_matrix *scaleTransforms);
+
+ virtual void DoMergeStage3 (dng_host &host,
+ dng_matrix *scaleTransforms);
+
virtual void DoBuildStage3 (dng_host &host,
- int32 srcPlane);
-
+ int32 srcPlane,
+ dng_matrix *scaleTransforms);
+
+ virtual void AdjustProfileForStage3 ();
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.cpp
index 8b488dd4d9..98ad4f311b 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.cpp
@@ -1,259 +1,272 @@
/*****************************************************************************/
-// Copyright 2008-2009 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_opcode_list.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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)
{
+ DNG_REQUIRE (image.Get (), "Bad image in dng_opcode_list::Apply");
+
for (uint32 index = 0; index < Count (); index++)
{
-
+
dng_opcode &opcode (Entry (index));
-
- if (opcode.AboutToApply (host, negative))
+
+ if (opcode.AboutToApply (host,
+ negative,
+ image->Bounds (),
+ image->Planes ()))
{
-
+
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", count);
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.h b/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.h
index dc3f4afbd3..9a4d1928fa 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_opcode_list.h
@@ -1,114 +1,153 @@
/*****************************************************************************/
-// Copyright 2008-2009 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_opcode_list.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 "dng_uncopyable.h"
#include <vector>
/*****************************************************************************/
-class dng_opcode_list
- {
+/// A list of opcodes.
+class dng_opcode_list: private dng_uncopyable
+ {
+
private:
-
- std::vector<dng_opcode *> fList;
-
+
+ dng_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/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.cpp
index e436e5a8e9..e25949e390 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.cpp
@@ -1,572 +1,563 @@
/*****************************************************************************/
-// Copyright 2008 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_opcodes.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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)
+ dng_negative &negative,
+ const dng_rect &imageBounds,
+ uint32 imagePlanes)
{
-
+
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 ())
{
+ DoAboutToApply (host,
+ negative,
+ imageBounds,
+ imagePlanes);
+
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,
+
+ : dng_filter_task ("dng_filter_opcode_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_rect &dstArea,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer)
{
-
+
dng_filter_task::Start (threadCount,
+ dstArea,
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 ()
-
+
+ : dng_area_task ("dng_inplace_opcode_task")
+
, fOpcode (opcode)
, fNegative (negative)
, fImage (image)
, fPixelType (opcode.BufferPixelType (image.PixelType ()))
-
+
{
-
+
}
-
+
virtual void Start (uint32 threadCount,
+ const dng_rect & /* dstArea */,
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 ();
-
+
+ uint32 bufferSize = ComputeBufferSize (fPixelType,
+ tileSize,
+ fImage.Planes (),
+ padSIMDBytes);
+
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 ();
-
+
+ dng_pixel_buffer buffer (tile,
+ 0,
+ fImage.Planes (),
+ fPixelType,
+ pcRowInterleavedAlignSIMD,
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.h b/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.h
index 6e565785db..77fd5d64e3 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_opcodes.h
@@ -1,336 +1,523 @@
/*****************************************************************************/
-// Copyright 2008 Adobe Systems Incorporated
+// Copyright 2008-2019 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_3/dng_sdk/source/dng_opcodes.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+/** \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,
- kFlag_Optional = 1,
- kFlag_SkipIfPreview = 2
+ 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:
+ // This helper routine will be called by AboutToApply if AboutToApply
+ // passes its internal checking and plans to return true. This is an
+ // opportunity for subclasses to perform some internal preparation
+ // based on the negative, image bounds, and number of image planes.
+ virtual void DoAboutToApply (dng_host & /* host */,
+ dng_negative & /* negative */,
+ const dng_rect & /* imageBounds */,
+ uint32 /* imagePlanes */)
+ {
+ }
+
+ 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);
+ dng_negative &negative,
+ const dng_rect &imageBounds,
+ uint32 imagePlanes);
+
+ /// 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 */)
+ const dng_rect &imageBounds)
{
+ (void) 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 ();
}
- virtual void Prepare (dng_negative & /* negative */,
- uint32 /* threadCount */,
- const dng_point & /* tileSize */,
- const dng_rect & /* imageBounds */,
- uint32 /* imagePlanes */,
- uint32 /* bufferPixelType */,
- dng_memory_allocator & /* allocator */)
+ /// 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 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)
{
+ (void) negative;
+ (void) threadCount;
+ (void) tileSize;
+ (void) imageBounds;
+ (void) imagePlanes;
+ (void) bufferPixelType;
+ (void) 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;
}
-
- virtual void Prepare (dng_negative & /* negative */,
- uint32 /* threadCount */,
- const dng_point & /* tileSize */,
- const dng_rect & /* imageBounds */,
- uint32 /* imagePlanes */,
- uint32 /* bufferPixelType */,
- dng_memory_allocator & /* allocator */)
+
+ /// 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 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)
{
+ (void) negative;
+ (void) threadCount;
+ (void) tileSize;
+ (void) imageBounds;
+ (void) imagePlanes;
+ (void) bufferPixelType;
+ (void) 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 buffer Source and 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/core/libs/dngwriter/extra/dng_sdk/dng_orientation.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_orientation.cpp
index 3ffcdc2bb6..99c92c3a48 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_orientation.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_orientation.cpp
@@ -1,234 +1,391 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_orientation.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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;
- break;
}
}
-
+
}
/*****************************************************************************/
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;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_orientation::CalcForwardMatrix3by3 (dng_matrix &orientationMatrix,
+ const bool horizontalFirstRow) const
+ {
+
+ bool hasOrient = false;
+
+ orientationMatrix.SetIdentity (3);
+
+ if (FlipH ())
+ {
+
+ hasOrient = true;
+
+ if (horizontalFirstRow)
+ {
+
+ orientationMatrix = dng_matrix_3by3 (-1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ else
+ {
+
+ orientationMatrix = dng_matrix_3by3 (1.0, 0.0, 0.0,
+ 0.0, -1.0, 1.0,
+ 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ }
+
+ if (FlipV ())
+ {
+
+ hasOrient = true;
+
+ if (horizontalFirstRow)
+ {
+
+ orientationMatrix = dng_matrix_3by3 (1.0, 0.0, 0.0,
+ 0.0, -1.0, 1.0,
+ 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ else
+ {
+
+ orientationMatrix = dng_matrix_3by3 (-1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ }
+
+ if (FlipD ())
+ {
+
+ hasOrient = true;
+
+ orientationMatrix = dng_matrix_3by3 (0.0, 1.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ return hasOrient;
+
+ }
+
+/*****************************************************************************/
+
+bool dng_orientation::CalcForwardMatrix4by4 (dng_matrix &orientationMatrix,
+ const bool horizontalFirstRow) const
+ {
+
+ bool hasOrient = false;
+
+ orientationMatrix.SetIdentity (4);
+
+ if (FlipH ())
+ {
+
+ hasOrient = true;
+
+ if (horizontalFirstRow)
+ {
+
+ orientationMatrix = dng_matrix_4by4 (-1.0, 0.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+
+ }
+
+ else
+ {
+
+ orientationMatrix = dng_matrix_4by4 (1.0, 0.0, 0.0, 0.0,
+ 0.0, -1.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+
+ }
+
+ }
+
+ if (FlipV ())
+ {
+
+ hasOrient = true;
+
+ if (horizontalFirstRow)
+ {
+
+ orientationMatrix = dng_matrix_4by4 (1.0, 0.0, 0.0, 0.0,
+ 0.0, -1.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ else
+ {
+
+ orientationMatrix = dng_matrix_4by4 (-1.0, 0.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+
+ }
+
+ if (FlipD ())
+ {
+
+ hasOrient = true;
+
+ orientationMatrix = dng_matrix_4by4 (0.0, 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0) *
+ orientationMatrix;
+
+ }
+ return hasOrient;
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_orientation.h b/core/libs/dngwriter/extra/dng_sdk/dng_orientation.h
index ab097825a6..5bf991b2d2 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_orientation.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_orientation.h
@@ -1,189 +1,197 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_orientation.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/******************************************************************************/
-
#ifndef __dng_orientation__
#define __dng_orientation__
/******************************************************************************/
+#include "dng_matrix.h"
#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
};
-
- uint32 fAdobeOrientation;
-
- public:
-
+
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;
}
+ // If horizontalFirstRow is true, then the x (horizontal h) component
+ // of the transform will be in the first row of the resulting matrix,
+ // and the y (vertical v) component will be in the second row.
+ //
+ // If horizontalFirstRow is false, then the y (vertical v) component
+ // of the transform will be in the first row of the resulting matrix,
+ // and the x (horizontal h) component will be in the second row.
+
+ bool CalcForwardMatrix3by3 (dng_matrix &matrix,
+ bool horizontalFirstRow) const;
+
+ bool CalcForwardMatrix4by4 (dng_matrix &matrix,
+ bool horizontalFirstRow) const;
+
};
/******************************************************************************/
#endif
-
+
/******************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.cpp
index 77cc41fc20..04eb4b6624 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.cpp
@@ -1,3238 +1,3431 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_parse_utils.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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" }
+ { tcAdobePSD, "Adobe PSD" },
+ { tcPNG, "PNG" },
+ { tcHEIC, "HEIC" }
};
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" },
+ { tcOffsetTime, "OffsetTime" },
+ { tcOffsetTimeOriginal, "OffsetTimeOriginal" },
+ { tcOffsetTimeDigitized, "OffsetTimeDigitized" },
{ 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" },
+ { tcTemperature, "Temperature" },
+ { tcHumidity, "Humidity" },
+ { tcPressure, "Pressure" },
+ { tcWaterDepth, "WaterDepth" },
+ { tcAcceleration, "Acceleration" },
+ { tcCameraElevationAngle, "CameraElevationAngle" },
{ 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" },
- { tcKodakKDCPrivateIFD, "KodakKDCPrivateIFD" }
+ { tcOriginalDefaultFinalSize, "OriginalDefaultFinalSize" },
+ { tcOriginalBestQualityFinalSize, "OriginalBestQualityFinalSize" },
+ { tcOriginalDefaultCropSize, "OriginalDefaultCropSize" },
+ { tcProfileHueSatMapEncoding, "ProfileHueSatMapEncoding" },
+ { tcProfileLookTableEncoding, "ProfileLookTableEncoding" },
+ { tcBaselineExposureOffset, "BaselineExposureOffset" },
+ { tcDefaultBlackRender, "DefaultBlackRender" },
+ { tcNewRawImageDigest, "NewRawImageDigest" },
+ { tcRawToPreviewGain, "RawToPreviewGain" },
+ { tcCacheBlob, "CacheBlob" },
+ { tcCacheVersion, "CacheVersion" },
+ { tcDefaultUserCrop, "DefaultUserCrop" },
+ { tcDepthFormat, "DepthFormat" },
+ { tcDepthNear, "DepthNear" },
+ { tcDepthFar, "DepthFar" },
+ { tcDepthUnits, "DepthUnits" },
+ { tcDepthMeasureType, "DepthMeasureType" },
+ { tcEnhanceParams, "EnhanceParams" },
+ { 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" }
+ { 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)
+ (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" },
- { sfAltPreviewImage, "Alt Preview Image" }
+ { sfMainImage , "Main Image" },
+ { sfPreviewImage , "Preview Image" },
+ { sfTransparencyMask , "Transparency Mask" },
+ { sfPreviewMask , "Preview Mask" },
+ { sfDepthMap , "Depth Map" },
+ { sfPreviewDepthMap , "Preview Depth Map" },
+ { sfEnhancedImage , "Enhanced Image" },
+ { 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" }
+ { 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" },
+ { piWhiteIsZero, "WhiteIsZero" },
{ piBlackIsZero, "BlackIsZero" },
{ piRGB, "RGB" },
{ piRGBPalette, "RGBPalette" },
{ piTransparencyMask, "TransparencyMask" },
+ { piDepth, "Depth" },
{ 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" }
+ { 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 - 5400K)" },
- { lsCoolWhiteFluorescent, "Cool white fluorescent (W 3900 - 4500K)" },
- { lsWhiteFluorescent, "White fluorescent (WW 3200 - 3700K)" },
+ { 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;
}
/*****************************************************************************/
-void DumpHexAscii (dng_stream &stream,
- uint32 count)
+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;
- uint32 rows = (count + 15) >> 4;
+ }
+/*****************************************************************************/
+
+const char * LookupDepthFormat (uint32 key)
+ {
+
+ const dng_name_table kDepthFormatNames [] =
+ {
+ { depthFormatUnknown, "Unknown" },
+ { depthFormatLinear, "Linear" },
+ { depthFormatInverse, "Inverse" },
+ };
+
+ const char *name = LookupName (key,
+ kDepthFormatNames,
+ sizeof (kDepthFormatNames ) /
+ sizeof (kDepthFormatNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupDepthUnits (uint32 key)
+ {
+
+ const dng_name_table kDepthUnitNames [] =
+ {
+ { depthUnitsUnknown, "Unknown" },
+ { depthUnitsMeters, "Meters" },
+ };
+
+ const char *name = LookupName (key,
+ kDepthUnitNames,
+ sizeof (kDepthUnitNames ) /
+ sizeof (kDepthUnitNames [0]));
+
+ if (name)
+ {
+ return name;
+ }
+
+ static char s [32];
+
+ sprintf (s, "%u", (unsigned) key);
+
+ return s;
+
+ }
+
+/*****************************************************************************/
+
+const char * LookupDepthMeasureType (uint32 key)
+ {
+
+ const dng_name_table kDepthMeasureTypeNames [] =
+ {
+ { depthMeasureUnknown, "Unknown" },
+ { depthMeasureOpticalAxis, "Optical Axis" },
+ { depthMeasureOpticalRay, "Optical Ray" },
+ };
+
+ const char *name = LookupName (key,
+ kDepthMeasureTypeNames,
+ sizeof (kDepthMeasureTypeNames ) /
+ sizeof (kDepthMeasureTypeNames [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);
- break;
}
-
+
}
-
+
}
-
+
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);
-
+
}
-
- break;
+
}
-
+
}
-
+
}
/*****************************************************************************/
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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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,
- bool isASCII)
+ 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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
#endif
-
- }
-
- if (isASCII)
- {
- s.Set_ASCII (buffer);
- }
- else
- {
- s.Set (buffer);
+
}
-
- #if qDNGValidate
-
- if (parentCode < tcFirstMakerNoteIFD)
- {
-
- if (isASCII && !s.IsASCII ())
- {
-
- char message [256];
-
- sprintf (message,
- "%s %s has non-ASCII characters",
- LookupParentCode (parentCode),
- LookupTagCode (parentCode, tagCode));
-
- ReportWarning (message);
-
- }
-
- }
-
- #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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (void) parentCode; // Unused
+ (void) tagCode; // Unused
+
#endif
-
- }
-
- s1.Set_ASCII (buffer);
- s2.Set_ASCII (NULL );
-
+
+ }
+
+ // 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)
{
-
- s2.Set_ASCII (buffer + j + 1);
+
+ // Medata working group - Allow UTF-8
+
+ s2.Set_UTF8_or_System (buffer + j + 1);
break;
-
- }
-
- }
-
- #if qDNGValidate
-
- {
-
- if (!s1.IsASCII () ||
- !s2.IsASCII ())
- {
-
- char message [256];
-
- sprintf (message,
- "%s %s has non-ASCII characters",
- LookupParentCode (parentCode),
- LookupTagCode (parentCode, tagCode));
-
- ReportWarning (message);
-
+
}
-
+
}
-
- #endif
-
+
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
-
- parentCode; // Unused
- tagCode; // Unused
-
+
+ (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:
{
- s.Set_ASCII (buffer);
+
+ // 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 formatted. So relax this test and allow these
+ // 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/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.h b/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.h
index 7fb48c034c..bae975c5aa 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_parse_utils.h
@@ -1,227 +1,231 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_parse_utils.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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);
+
+const char * LookupDepthFormat (uint32 key);
+
+const char * LookupDepthUnits (uint32 key);
+
+const char * LookupDepthMeasureType (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,
- bool isASCII = true);
-
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.cpp
index 6054cac425..1d597a1725 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.cpp
@@ -1,1818 +1,1947 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_pixel_buffer.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_tag_values.h"
#include "dng_utils.h"
/*****************************************************************************/
+static bool SafeUint32ToInt32Mult (uint32 arg1,
+ uint32 arg2,
+ int32 *result)
+ {
+
+ uint32 uint32_result;
+
+ return (SafeUint32Mult (arg1,
+ arg2,
+ &uint32_result) &&
+
+ ConvertUint32ToInt32 (uint32_result,
+ result));
+
+ }
+
+/*****************************************************************************/
+
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_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint32 pixelType,
+ uint32 planarConfiguration,
+ void *data)
+
+ : fArea (area)
+ , fPlane (plane)
+ , fPlanes (planes)
+ , fRowStep (0)
+ , fColStep (0)
+ , fPlaneStep (0)
+ , fPixelType (pixelType)
+ , fPixelSize (TagTypeSize (pixelType))
+ , fData (data)
+ , fDirty (true)
+
{
+
+ const char *overflowMessage = "Arithmetic overflow in pixel buffer setup";
+
+ // Initialize fRowStep, fColStep and fPlaneStep according to the desired
+ // pixel layout.
+
+ switch (planarConfiguration)
+ {
+
+ case pcInterleaved:
+ {
+
+ fPlaneStep = 1;
+
+ if (!ConvertUint32ToInt32 (fPlanes, &fColStep) ||
+ !SafeUint32ToInt32Mult (fArea.W (), fPlanes, &fRowStep))
+ {
+ ThrowOverflow (overflowMessage);
+ }
+
+ break;
+
+ }
+
+ case pcPlanar:
+ {
+
+ fColStep = 1;
+
+ // Even though we've hardened dng_rect::W() to guarantee that it
+ // will never return a result that's out of range for an int32, we
+ // still protect the conversion for defense in depth.
+
+ if (!ConvertUint32ToInt32 (fArea.W (), &fRowStep) ||
+ !SafeUint32ToInt32Mult (fArea.H (), fArea.W (), &fPlaneStep))
+ {
+ ThrowOverflow (overflowMessage);
+ }
+
+ break;
+
+ }
+
+ case pcRowInterleaved:
+ case pcRowInterleavedAlignSIMD:
+ {
+
+ fColStep = 1;
+
+ uint32 planeStepUint32;
+
+ if (planarConfiguration == pcRowInterleaved)
+ {
+ planeStepUint32 = fArea.W ();
+ }
+
+ else
+ {
+
+ if (!RoundUpForPixelSize (fArea.W (),
+ fPixelSize,
+ &planeStepUint32))
+ {
+ ThrowOverflow (overflowMessage);
+ }
+
+ }
+
+ if (!ConvertUint32ToInt32 (planeStepUint32, &fPlaneStep) ||
+ !SafeUint32ToInt32Mult (planeStepUint32, fPlanes, &fRowStep))
+ {
+ ThrowOverflow (overflowMessage);
+ }
+
+ break;
+
+ }
+ default:
+ {
+ ThrowProgramError ("Invalid value for 'planarConfiguration'");
+ break;
+ }
+
+ }
+
}
/*****************************************************************************/
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
/*****************************************************************************/
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 ();
- break;
+
}
-
+
}
-
+
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,
+ 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 ();
- break;
+
}
-
+
}
-
+
}
-
+
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
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 ();
- break;
+
}
-
+
}
-
+
}
-
+
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 (repeatV == 0 ||
+ repeatH == 0)
+ {
+ DNG_REPORT ("Bad srcArea in RepeatPhase");
+ return dng_point ();
+ }
+
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 ();
- break;
+
}
-
+
}
-
+
}
/*****************************************************************************/
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,
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.h b/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.h
index 97c257511d..7da3da05d1 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_pixel_buffer.h
@@ -1,680 +1,764 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_pixel_buffer.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_safe_arithmetic.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
{
+ // TO DO: review this. do we set up buffers sometimes with "col" parameter
+ // equal to 0, which would then cause this exception to throw?!
+
+ #if 0
+
+ // Ensure pixel to be accessed lies inside valid area.
+ if (row < fArea.t || row >= fArea.b ||
+ col < fArea.l || col >= fArea.r ||
+ plane < fPlane || (plane - fPlane) >= fPlanes)
+ {
+ ThrowProgramError ("Out-of-range pixel access");
+ }
+
+ // Compute offset of pixel.
+ const int64 rowOffset = SafeInt64Mult(fRowStep,
+ static_cast<int64> (row) - static_cast<int64> (fArea.t));
+ const int64 colOffset = SafeInt64Mult(fColStep,
+ static_cast<int64> (col) - static_cast<int64> (fArea.l));
+ const int64 planeOffset = SafeInt64Mult(fPlaneStep,
+ static_cast<int64> (plane - fPlane));
+ const int64 offset = SafeInt64Mult(static_cast<int64>(fPixelSize),
+ SafeInt64Add(SafeInt64Add(rowOffset, colOffset), planeOffset));
+
+ // Add offset to buffer base address.
+ return static_cast<void *> (static_cast<uint8 *> (fData) + offset);
+
+ #else
+
+ #if qDNG64Bit
+
return (void *)
- (((uint8 *) fData) + (int32)fPixelSize *
- (fRowStep * (row - fArea.t) +
- fColStep * (col - fArea.l) +
- fPlaneStep * (int32)(plane - fPlane )));
+ (((uint8 *) fData) + (int64) fPixelSize *
+ (fRowStep * (int64) (row - fArea.t) +
+ fColStep * (int64) (col - fArea.l) +
+ fPlaneStep * (int64) (plane - fPlane )));
+
+ #else
- }
+ return (void *)
+ (((uint8 *) fData) + (int32) fPixelSize *
+ (fRowStep * (int32) (row - fArea.t) +
+ fColStep * (int32) (col - fArea.l) +
+ fPlaneStep * (int32) (plane - fPlane )));
- #if qDebugPixelType
+ #endif
- void CheckPixelType (uint32 pixelType) const;
+ #endif
+ }
+
+ #if qDebugPixelType
+
+ void CheckPixelType (uint32 pixelType) const;
+
#endif
-
+
public:
-
+
dng_pixel_buffer ();
-
+
+ /// Note: This constructor is for internal use only and should not be
+ /// considered part of the DNG SDK API.
+ ///
+ /// Initialize the pixel buffer according to the given parameters (see
+ /// below). May throw an error if arithmetic overflow occurs when
+ /// computing the row, column or plane step, or if an invalid value
+ /// was passed for planarConfiguration.
+ ///
+ /// \param area Area covered by the pixel buffer
+ /// \param plane Index of the first plane
+ /// \param planes Number of planes
+ /// \param pixelType Pixel data type (one of the values defined in
+ /// dng_tag_types.h)
+ /// \param planarConfiguration Layout of the pixel planes in memory: One
+ /// of pcInterleaved, pcPlanar, or pcRowInterleaved (defined in
+ /// dng_tag_values.h)
+ /// \param data Pointer to the pixel data
+
+ dng_pixel_buffer (const dng_rect &area,
+ uint32 plane,
+ uint32 planes,
+ uint32 pixelType,
+ uint32 planarConfiguration,
+ void *data);
+
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);
-
+
}
+ const uint8 * ConstPixel_uint8_overrideType (int32 row,
+ int32 col,
+ uint32 plane = 0) const
+ {
+
+ // No type check
+
+ 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);
-
+
}
+ uint8 * DirtyPixel_uint8_overrideType (int32 row,
+ int32 col,
+ uint32 plane = 0)
+ {
+
+ // No type check
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_point.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_point.cpp
index 64a00e062b..ff1b9b235c 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_point.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_point.cpp
@@ -1,22 +1,15 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_point.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_point.h"
/*****************************************************************************/
// Currently all inlined.
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_point.h b/core/libs/dngwriter/extra/dng_sdk/dng_point.h
index ad80861389..17fc314282 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_point.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_point.h
@@ -1,198 +1,313 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_point.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_point__
#define __dng_point__
/*****************************************************************************/
+#include <cmath>
+
#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);
}
+ real64 Length () const
+ {
+ return hypot ((real64) v, (real64) h);
+ }
+
};
/*****************************************************************************/
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));
}
+ real64 Length () const
+ {
+ return hypot (v, h);
+ }
+
+ void Scale (real64 scale)
+ {
+ v *= scale;
+ h *= scale;
+ }
+
+ void Normalize ()
+ {
+ Scale (1.0 / Length ());
+ }
+
};
/*****************************************************************************/
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 Distance (const dng_point_real64 &a,
+ const dng_point_real64 &b)
+
+
+ {
+
+ return (a - b).Length ();
+
}
/*****************************************************************************/
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);
-
+
}
/*****************************************************************************/
+// Finds distance squared from point p to line segment from v to w.
+
+inline real64 DistanceSquared (const dng_point_real64 &p,
+ const dng_point_real64 &v,
+ const dng_point_real64 &w)
+ {
+
+ real64 len2 = DistanceSquared (v, w);
+
+ if (len2 == 0.0)
+ return DistanceSquared (p, v);
+
+ real64 t = ((p.h - v.h) * (w.h - v.h) +
+ (p.v - v.v) * (w.v - v.v)) / len2;
+
+ if (t <= 0.0)
+ return DistanceSquared (p, v);
+
+ if (t >= 1.0)
+ return DistanceSquared (p, w);
+
+ dng_point_real64 z;
+
+ z.h = v.h + t * (w.h - v.h);
+ z.v = v.v + t * (w.v - v.v);
+
+ return DistanceSquared (p, z);
+
+ }
+
+/*****************************************************************************/
+
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);
+
+ }
+/*****************************************************************************/
+
+inline dng_point_real64 Lerp (const dng_point_real64 &a,
+ const dng_point_real64 &b,
+ const real64 t)
+ {
+
+ return dng_point_real64 (Lerp_real64 (a.v, b.v, t),
+ Lerp_real64 (a.h, b.h, t));
+
}
/*****************************************************************************/
-#endif
+inline real64 Dot (const dng_point_real64 &a,
+ const dng_point_real64 &b)
+ {
+
+ return (a.h * b.h) + (a.v * b.v);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point_real64 operator* (const real64 scale,
+ const dng_point_real64 &pt)
+ {
+
+ dng_point_real64 result = pt;
+
+ result.h *= scale;
+ result.v *= scale;
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point MakePerpendicular (const dng_point &pt)
+ {
+
+ return dng_point (-pt.h, pt.v);
+
+ }
+
+/*****************************************************************************/
+
+inline dng_point_real64 MakePerpendicular (const dng_point_real64 &pt)
+ {
+
+ return dng_point_real64 (-pt.h, pt.v);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_preview.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_preview.cpp
index b0f070a101..58ae869fb6 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_preview.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_preview.cpp
@@ -1,459 +1,802 @@
/*****************************************************************************/
-// Copyright 2007 Adobe Systems Incorporated
+// Copyright 2007-2019 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_3/dng_sdk/source/dng_preview.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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];
+
+ tag_urational_ptr fBlackLevelTag;
+
+ dng_urational fBlackLevelData [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 ())
+
+ , fBlackLevelTag (tcBlackLevel,
+ fBlackLevelData,
+ 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);
+
+ }
+
+ else
+ {
+
+ bool nonZeroBlack = false;
+
+ for (uint32 j = 0; j < preview.fImage->Planes (); j++)
+ {
+
+ fBlackLevelData [j].Set_real64 (preview.fBlackLevel [j], 1);
+
+ nonZeroBlack = nonZeroBlack || (preview.fBlackLevel [j] != 0.0);
+
+ }
+
+ if (nonZeroBlack)
+ {
+
+ directory.Add (&fBlackLevelTag);
+
+ }
+
+ }
+
}
/*****************************************************************************/
-dng_preview_list::dng_preview_list ()
+dng_raw_preview_tag_set::~dng_raw_preview_tag_set ()
+ {
+
+ }
- : fCount (0)
+/*****************************************************************************/
+dng_raw_preview::dng_raw_preview ()
+
+ : fImage ()
+ , fOpcodeList2Data ()
+ , fCompressionQuality (-1)
+ , fIFD ()
+
{
+
+ for (uint32 n = 0; n < kMaxSamplesPerPixel; n++)
+ {
+ fBlackLevel [n] = 0.0;
+ }
+
+ }
+
+/*****************************************************************************/
+dng_raw_preview::~dng_raw_preview ()
+ {
+
}
/*****************************************************************************/
-dng_preview_list::~dng_preview_list ()
+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 ()
+ {
+
}
/*****************************************************************************/
-void dng_preview_list::Append (AutoPtr<dng_preview> &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_depth_preview::dng_depth_preview ()
+
+ : fImage ()
+ , fCompressionQuality (-1)
+ , fFullResolution (false)
+ , fIFD ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+dng_depth_preview::~dng_depth_preview ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_basic_tag_set * dng_depth_preview::AddTagSet (dng_tiff_directory &directory) const
+ {
+
+ fIFD.fNewSubFileType = fFullResolution ? sfDepthMap
+ : sfPreviewDepthMap;
+
+ fIFD.fImageWidth = fImage->Width ();
+ fIFD.fImageLength = fImage->Height ();
+
+ fIFD.fSamplesPerPixel = 1;
+
+ fIFD.fPhotometricInterpretation = piDepth;
+
+ 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_depth_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/core/libs/dngwriter/extra/dng_sdk/dng_preview.h b/core/libs/dngwriter/extra/dng_sdk/dng_preview.h
index f282fc09d6..818b5bfbcf 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_preview.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_preview.h
@@ -1,166 +1,241 @@
/*****************************************************************************/
-// Copyright 2007 Adobe Systems Incorporated
+// Copyright 2007-2019 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_3/dng_sdk/source/dng_preview.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include "dng_uncopyable.h"
/*****************************************************************************/
-class dng_preview
+class dng_preview: private dng_uncopyable
{
-
+
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:
+/*****************************************************************************/
+
+class dng_raw_preview: public dng_preview
+ {
+
+ public:
+
+ AutoPtr<dng_image> fImage;
+
+ AutoPtr<dng_memory_block> fOpcodeList2Data;
+
+ real64 fBlackLevel [kMaxSamplesPerPixel];
+
+ int32 fCompressionQuality;
- // Hidden copy constructor and assignment operator.
+ 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;
+
+ };
- dng_jpeg_preview (const dng_jpeg_preview &preview);
+/*****************************************************************************/
- dng_jpeg_preview & operator= (const dng_jpeg_preview &preview);
+class dng_depth_preview: public dng_preview
+ {
+
+ public:
+
+ AutoPtr<dng_image> fImage;
+
+ int32 fCompressionQuality;
+
+ bool fFullResolution;
+ private:
+
+ mutable dng_ifd fIFD;
+
+ public:
+
+ dng_depth_preview ();
+
+ virtual ~dng_depth_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;
+
};
/*****************************************************************************/
+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;
+
+ };
+
+/*****************************************************************************/
+
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/core/libs/dngwriter/extra/dng_sdk/dng_pthread.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_pthread.cpp
index 5131a065df..4887081aa9 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_pthread.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_pthread.cpp
@@ -1,1142 +1,1307 @@
/*****************************************************************************/
-// Copyright 2002-2008 Adobe Systems Incorporated
+// Copyright 2002-2019 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_3/dng_sdk/source/dng_pthread.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
#include "dng_pthread.h"
/*****************************************************************************/
#if qDNGThreadSafe
/*****************************************************************************/
#include "dng_assertions.h"
/*****************************************************************************/
#if qWinOS
#pragma warning(disable : 4786)
+/* Not supporting Win98, check WINVER if this is still needed
+
// 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
/*****************************************************************************/
+// Turning off qDNGUseConditionVariable because the WakeConditionVariable and
+// WakeAllConditionVariable Microsoft API routines are only available on
+// Vista, and Camera Raw and DNG Converter 8.3 need to continue working on
+// Windows XP. -erichan 2013-11-08.
+
+#define qDNGUseConditionVariable 0
+
+/*****************************************************************************/
+
+#ifndef qDNGUseConditionVariable
+#if WINVER >= 0x0600 // Vista introduces a real condition variable support
+#define qDNGUseConditionVariable 1
+#else
+#define qDNGUseConditionVariable 0
+#endif
+#endif
+
+/*****************************************************************************/
+
+#if !qDNGUseConditionVariable
namespace {
+
struct waiter {
struct waiter *prev;
struct waiter *next;
HANDLE semaphore;
bool chosen_by_signal;
};
}
+#endif
/*****************************************************************************/
struct dng_pthread_mutex_impl
{
CRITICAL_SECTION lock;
- dng_pthread_mutex_impl() { ::InitializeCriticalSection(&lock); }
- ~dng_pthread_mutex_impl() { ::DeleteCriticalSection(&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
+
+#if qDNGUseConditionVariable
+ // so much simpler, but Vista+ only
+ CONDITION_VARIABLE cond;
+
+ dng_pthread_cond_impl() { InitializeConditionVariable(&cond); }
+ ~dng_pthread_cond_impl() { } // no delete listed
+
+#else
+
+ 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() { } ;
+ ~dng_pthread_cond_impl() { }
+#endif
// 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 &) { }
};
+
+#if !qDNGUseConditionalVariable
+ // DONE: avoid this serialization lock
+ // do allocation at init, and then just assert ?
+
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);
}
-
+#endif
+
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);
- result = _beginthreadex(NULL, (unsigned)stacksize, trampoline, args.get(), CREATE_SUSPENDED, &threadID);
- if (result == NULL)
- return -1; // ENOMEM
- args.release();
-
{
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");
}
- ::ResumeThread((HANDLE)result);
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 qWinRT
+ if (!::WinRT_CloseThreadHandle(primaryHandle))
+#else
if (!::CloseHandle(primaryHandle))
+#endif
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);
}
+#if qWinRT
+ ::WinRT_CloseThreadHandle(primaryHandle);
+#else
::CloseHandle(primaryHandle);
+#endif
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)
{
+#if qDNGUseConditionVariable
+ int result = 0;
+
+ BOOL success = SleepConditionVariableCS(&(*cond)->cond, &(*mutex)->lock, timeout_milliseconds);
+ if (!success)
+ if (GetLastError() == ERROR_TIMEOUT)
+ result = DNG_ETIMEDOUT;
+
+ return result;
+
+#else
+
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;
+#endif
}
/*****************************************************************************/
int dng_pthread_cond_wait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex)
{
ValidateCond(cond);
- return cond_wait_internal(cond, mutex, INFINITE);
+ return cond_wait_internal(cond, mutex, INFINITE);
}
/*****************************************************************************/
int dng_pthread_cond_timedwait(dng_pthread_cond_t *cond, dng_pthread_mutex_t *mutex, struct dng_timespec *latest_time)
{
ValidateCond(cond);
-
+
struct dng_timespec sys_timespec;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1900
+
+ struct timespec temp;
+ dng_pthread_now (&temp);
+
+ sys_timespec.tv_sec = (long)temp.tv_sec;
+ sys_timespec.tv_nsec = temp.tv_nsec;
+
+#else
dng_pthread_now (&sys_timespec);
+#endif
+
__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);
+ return cond_wait_internal(cond, mutex, wait_millisecs);
}
/*****************************************************************************/
int dng_pthread_cond_signal(dng_pthread_cond_t *cond)
{
ValidateCond(cond);
+#if qDNGUseConditionVariable
+
+ WakeConditionVariable(&(*cond)->cond);
+ return 0;
+
+#else
+
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;
+#endif
}
/*****************************************************************************/
int dng_pthread_cond_broadcast(dng_pthread_cond_t *cond)
{
ValidateCond(cond);
+#if qDNGUseConditionVariable
+
+ WakeAllConditionVariable(&(*cond)->cond);
+ return 0;
+
+#else
+
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;
+#endif
}
/*****************************************************************************/
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);
}
/*****************************************************************************/
+#if !qDNGUseConditionVariable
+
namespace {
struct rw_waiter {
struct rw_waiter *prev;
struct rw_waiter *next;
HANDLE semaphore;
bool is_writer;
};
}
+#endif
+
struct dng_pthread_rwlock_impl
{
- dng_pthread_mutex_impl mutex;
+
+
+#if qDNGUseConditionVariable
+ SRWLOCK rwlock;
+ bool fWriteLockExclusive;
+
+ dng_pthread_rwlock_impl () { InitializeSRWLock(&rwlock); }
+ ~dng_pthread_rwlock_impl () { } // no delete listed
+
+
+#else
+ dng_pthread_mutex_impl mutex;
- rw_waiter *head_waiter;
+ 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);
}
+#endif
+
+ // Non copyable
+private:
+ dng_pthread_rwlock_impl &operator=(const dng_pthread_rwlock_impl &) { }
+ dng_pthread_rwlock_impl(const dng_pthread_rwlock_impl &) { }
+
};
/*****************************************************************************/
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;
+#if !qDNGUseConditionVariable
+
{
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
}
-
+#endif
+
delete *rwlock;
*rwlock = NULL;
return 0;
}
/*****************************************************************************/
+#if !qDNGUseConditionVariable
+
#define CHECK_RWLOCK_STATE(real_rwlock) \
DNG_ASSERT (!real_rwlock.writer_active || real_rwlock.readers_active == 0, "dng_pthread_rwlock_t logic error")
+#endif
+
/*****************************************************************************/
int dng_pthread_rwlock_rdlock(dng_pthread_rwlock_t *rwlock)
{
+#if qDNGUseConditionVariable
+ // Note: Aquire cannot be called resursively from same thread, once aquired or deadlock will occur
+
+ AcquireSRWLockShared(&(*rwlock)->rwlock);
+ (*rwlock)->fWriteLockExclusive = false;
+
+ return 0;
+
+#else
+
dng_pthread_rwlock_impl &real_rwlock = **rwlock;
struct rw_waiter this_wait;
bool doWait = false;;
int result = 0;
- HANDLE semaphore;
+ 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;
+#endif
}
/*****************************************************************************/
int dng_pthread_rwlock_tryrdlock(dng_pthread_rwlock_t *rwlock)
{
+#if qDNGUseConditionVariable
+
+ if (TryAcquireSRWLockExclusive(&(*rwlock)->rwlock) == 0)
+ return 0;
+
+ (*rwlock)->fWriteLockExclusive = false;
+ return -1;
+
+#else
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;
+#endif
}
/*****************************************************************************/
int dng_pthread_rwlock_trywrlock(dng_pthread_rwlock_t *rwlock)
{
+#if qDNGUseConditionVariable
+
+ if (TryAcquireSRWLockShared(&(*rwlock)->rwlock) == 0)
+ return 0;
+
+ (*rwlock)->fWriteLockExclusive = true;
+ return -1;
+
+#else
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;
+#endif
}
/*****************************************************************************/
int dng_pthread_rwlock_unlock(dng_pthread_rwlock_t *rwlock)
{
+#if qDNGUseConditionVariable
+
+ if ((*rwlock)->fWriteLockExclusive)
+ ReleaseSRWLockExclusive(&(*rwlock)->rwlock);
+ else
+ ReleaseSRWLockShared(&(*rwlock)->rwlock);
+
+ return 0;
+
+#else
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;
+#endif
}
/*****************************************************************************/
int dng_pthread_rwlock_wrlock(dng_pthread_rwlock_t *rwlock)
{
+#if qDNGUseConditionVariable
+
+ AcquireSRWLockExclusive(&(*rwlock)->rwlock);
+ (*rwlock)->fWriteLockExclusive = true;
+
+ return 0;
+
+#else
dng_pthread_rwlock_impl &real_rwlock = **rwlock;
int result = 0;
struct rw_waiter this_wait;
- HANDLE semaphore;
+ 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;
+#endif
}
/*****************************************************************************/
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 11644473600LL
-
+ #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
+#endif // qDNGThreadSafe
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_pthread.h b/core/libs/dngwriter/extra/dng_sdk/dng_pthread.h
index 99f639e0b2..bccda513d1 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_pthread.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_pthread.h
@@ -1,258 +1,250 @@
/*****************************************************************************/
-// Copyright 2002-2008 Adobe Systems Incorporated
+// Copyright 2002-2019 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_3/dng_sdk/source/dng_pthread.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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>
+#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;
};
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, struct dng_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 _MSC_VER < 1900
#define timespec dng_timespec
+#endif
/* 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/core/libs/dngwriter/extra/dng_sdk/dng_rational.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_rational.cpp
index 4e8dc2c750..b9de06fece 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_rational.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_rational.cpp
@@ -1,150 +1,143 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_rational.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_rational.h b/core/libs/dngwriter/extra/dng_sdk/dng_rational.h
index 8456679d75..17e2589ec3 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_rational.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_rational.h
@@ -1,123 +1,144 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_rational.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_read_image.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_read_image.cpp
index 80046ac50a..edc6ebf5c6 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_read_image.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_read_image.cpp
@@ -1,1293 +1,3541 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_read_image.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_globals.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_safe_arithmetic.h"
#include "dng_tag_types.h"
#include "dng_tag_values.h"
+#include "dng_uncopyable.h"
#include "dng_utils.h"
-/*****************************************************************************/
+#include "zlib.h"
-dng_row_interleaved_image::dng_row_interleaved_image (dng_image &image,
- uint32 factor)
+#if qDNGUseLibJPEG
+#include "jpeglib.h"
+#include "jerror.h"
+#endif
+
+/******************************************************************************/
- : dng_image (image.Bounds (),
- image.Planes (),
- image.PixelType ())
+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;
+
+ }
- , fImage (image )
- , fFactor (factor)
+ }
+
+/******************************************************************************/
+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;
+
+ }
+
+ }
+
/*****************************************************************************/
-int32 dng_row_interleaved_image::MapRow (int32 row) const
+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;
- uint32 rows = Height ();
+ }
+
+ }
+
+ 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;
- int32 top = Bounds ().t;
+ }
+
+ }
+
+ 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;
- uint32 fieldRow = row - top;
+ }
+
+ }
+
+ else
+ {
+
+ for (int32 col = 1; col < cols; ++col)
+ {
+
+ for (int32 chan = 0; chan < channels; ++chan)
+ {
+
+ bytePtr [chan + channels] += bytePtr [chan];
+
+ }
+
+ bytePtr += channels;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
- for (uint32 field = 0; true; field++)
+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;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
- uint32 fieldRows = (rows - field + fFactor - 1) / fFactor;
+bool DecodePackBits (dng_stream &stream,
+ uint8 *dPtr,
+ int32 dstCount)
+ {
- if (fieldRow < fieldRows)
+ 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;
- return fieldRow * fFactor + field + top;
+ dstCount -= runCount;
+
+ if (dstCount < 0)
+ return false;
+
+ uint8 x = stream.Get_uint8 ();
+
+ while (runCount--)
+ {
+
+ *(dPtr++) = x;
+
+ }
}
+
+ }
- fieldRow -= fieldRows;
+ return true;
+
+ }
+
+/******************************************************************************/
+
+class dng_lzw_expander: private dng_uncopyable
+ {
+
+ 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);
+
+ };
+
+/******************************************************************************/
+
+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 + 1) * sizeof (LZWExpanderNode));
+
+ fTable = (LZWExpanderNode *) fBuffer.Buffer ();
+
+ }
+
+/******************************************************************************/
+
+void dng_lzw_expander::InitTable ()
+ {
+
+ fCodeSize = 9;
+
+ fNextCode = 258;
+
+ LZWExpanderNode *node = &fTable [0];
+
+ for (int32 code = 0; code <= kTableSize; 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;
}
- ThrowProgramError ();
+ return true;
+
+ }
+
+/******************************************************************************/
+
+bool dng_lzw_expander::Expand (const uint8 *sPtr,
+ uint8 *dPtr,
+ int32 sCount,
+ int32 dCount)
+ {
+
+ if (sCount < 0 || dCount < 0)
+ {
+ return false;
+ }
+
+ 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;
+
+ (void) inChar;
+
+ *(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;
- return 0;
+ *(--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;
+
+ (void) dCount;
+
+ 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;
+
}
/*****************************************************************************/
-void dng_row_interleaved_image::DoGet (dng_pixel_buffer &buffer) const
+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)
+
{
+
+ }
+
+/*****************************************************************************/
- dng_pixel_buffer tempBuffer (buffer);
+int32 dng_row_interleaved_image::MapRow (int32 row) const
+ {
- for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
+ uint32 rows = Height ();
+
+ int32 top = Bounds ().t;
+
+ uint32 fieldRow = row - top;
+
+ uint32 field;
+
+ for (field = 0; true; field++)
{
+
+ uint32 fieldRows = (rows - field + fFactor - 1) / fFactor;
+
+ if (fieldRow < fieldRows)
+ {
+
+ break;
+
+ }
+
+ fieldRow -= fieldRows;
+
+ }
+
+ return fieldRow * fFactor + field + top;
- tempBuffer.fArea.t = MapRow (row);
+ }
+
+/*****************************************************************************/
+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;
-
+
+ uint32 tempBufferSize = ComputeBufferSize (buffer.fPixelType,
+ buffer.fArea.Size (),
+ buffer.fPlanes,
+ padNone);
+
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
+class dng_image_spooler: public dng_spooler,
+ private dng_uncopyable
{
-
+
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 bytesPerRow = fTileArea.W () * fPlanes * sizeof (uint16);
-
+ DNG_REQUIRE (bytesPerRow > 0, "Bad bytesPerRow in dng_image_spooler");
+
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;
-
+
+ dng_pixel_buffer buffer (fTileStrip,
+ fPlane,
+ fPlanes,
+ ttShort,
+ pcInterleaved,
+ fBuffer);
+
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 * sizeof (uint16);
-
+ fPlanes * (uint32) sizeof (uint16);
+
}
}
-
+
}
/*****************************************************************************/
dng_read_image::dng_read_image ()
- : fCompressedBuffer ()
- , fUncompressedBuffer ()
- , fSubTileBlockBuffer ()
-
+ : 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)
+ 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;
+
+ if (uncompressedBuffer.Get () == NULL)
+ {
- dng_pixel_buffer buffer;
-
- buffer.fArea = tileArea;
-
- buffer.fPlane = plane;
- buffer.fPlanes = planes;
-
- buffer.fRowStep = planes * tileArea.W ();
+ #if qDNGValidate
+
+ ReportError ("Fuzz: Missing uncompressed buffer");
+
+ #endif
- if (ifd.fPlanarConfiguration == pcRowInterleaved)
+ ThrowBadFormat ();
+
+ }
+
+ uint32 bitDepth = ifd.fBitsPerSample [plane];
+
+ uint32 pixelType = ttUndefined;
+
+ if (bitDepth == 8)
{
- buffer.fColStep = 1;
- buffer.fPlaneStep = tileArea.W ();
+
+ pixelType = ttByte;
+
+ stream.Get (uncompressedBuffer->Buffer (), samplesPerTile);
+
}
-
- else
+
+ else if (bitDepth == 16 && ifd.fSampleFormat [0] == sfFloatingPoint)
{
- buffer.fColStep = planes;
- buffer.fPlaneStep = 1;
+
+ pixelType = ttFloat;
+
+ uint32 *p_uint32 = (uint32 *) uncompressedBuffer->Buffer ();
+
+ for (uint32 j = 0; j < samplesPerTile; j++)
+ {
+
+ p_uint32 [j] = DNG_HalfToFloat (stream.Get_uint16 ());
+
+ }
+
}
-
- buffer.fData = fUncompressedBuffer->Buffer ();
-
- uint32 bitDepth = ifd.fBitsPerSample [plane];
-
- if (bitDepth == 8)
+
+ else if (bitDepth == 24 && ifd.fSampleFormat [0] == sfFloatingPoint)
{
-
- buffer.fPixelType = ttByte;
- buffer.fPixelSize = 1;
-
- stream.Get (buffer.fData, samplesPerTile);
-
+
+ pixelType = ttFloat;
+
+ uint32 *p_uint32 = (uint32 *) uncompressedBuffer->Buffer ();
+
+ 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);
-
+
+ pixelType = ttShort;
+
+ stream.Get (uncompressedBuffer->Buffer (), samplesPerTile * 2);
+
if (stream.SwapBytes ())
{
-
- DoSwapBytes16 ((uint16 *) buffer.fData,
+
+ DoSwapBytes16 ((uint16 *) uncompressedBuffer->Buffer (),
samplesPerTile);
-
+
}
-
+
}
-
+
else if (bitDepth == 32)
{
-
- buffer.fPixelType = ttLong;
- buffer.fPixelSize = 4;
-
- stream.Get (buffer.fData, samplesPerTile * 4);
-
+
+ pixelType = image.PixelType ();
+
+ stream.Get (uncompressedBuffer->Buffer (), samplesPerTile * 4);
+
if (stream.SwapBytes ())
{
-
- DoSwapBytes32 ((uint32 *) buffer.fData,
+
+ DoSwapBytes32 ((uint32 *) uncompressedBuffer->Buffer (),
samplesPerTile);
-
+
}
-
+
}
-
+
else if (bitDepth == 12)
{
-
- buffer.fPixelType = ttShort;
- buffer.fPixelSize = 2;
-
- uint16 *p = (uint16 *) buffer.fData;
-
+
+ pixelType = ttShort;
+
+ uint16 *p = (uint16 *) uncompressedBuffer->Buffer ();
+
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;
-
+
+ pixelType = ttShort;
+
+ uint16 *p = (uint16 *) uncompressedBuffer->Buffer ();
+
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;
-
+
+ pixelType = ttLong;
+
+ uint32 *p = (uint32 *) uncompressedBuffer->Buffer ();
+
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;
+
+ }
+
+ dng_pixel_buffer buffer (tileArea,
+ plane,
+ planes,
+ pixelType,
+ ifd.fPlanarConfiguration,
+ uncompressedBuffer->Buffer ());
+
+ if (ifd.fSampleBitShift)
+ {
+
+ buffer.ShiftRight (ifd.fSampleBitShift);
+
+ }
+
+ if (ifd.fSubTileBlockRows > 1)
+ {
+
+ ReorderSubTileBlocks (host,
+ ifd,
+ buffer,
+ subTileBlockBuffer);
+
+ }
+
+ image.Put (buffer);
+
+ return true;
+
+ }
+/*****************************************************************************/
+
+#if qDNGUseLibJPEG
+
+/*****************************************************************************/
+
+static void dng_error_exit (j_common_ptr cinfo)
+ {
+
+ // Output message.
+
+ (*cinfo->err->output_message) (cinfo);
+
+ // Convert to a dng_exception.
+
+ switch (cinfo->err->msg_code)
+ {
+
+ case JERR_OUT_OF_MEMORY:
+ {
+ ThrowMemoryFull ();
+ break;
+ }
+
+ default:
+ {
+ ThrowBadFormat ();
+ }
+
}
+
+ }
- else
+/*****************************************************************************/
+
+static void dng_output_message (j_common_ptr cinfo)
+ {
+
+ // Format message to string.
+
+ char buffer [JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+ // Report the libjpeg message as a warning.
+
+ ReportWarning ("libjpeg", buffer);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
+
+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,
+ bool /* usingMultipleThreads */)
+ {
+
+ #if qDNGUseLibJPEG
+
+ struct jpeg_decompress_struct cinfo;
+
+ // Setup the error manager.
+
+ struct jpeg_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error (&jerr);
+
+ jerr.error_exit = dng_error_exit;
+ jerr.output_message = dng_output_message;
+
+ try
{
+
+ // Create the decompression context.
+
+ jpeg_create_decompress (&cinfo);
+
+ // Set up the memory data source manager.
+
+ jpeg_mem_src (&cinfo,
+ jpegDataInMemory,
+ jpegDataSize);
+
+ // Read the JPEG header.
+
+ jpeg_read_header (&cinfo, TRUE);
+
+ // Check header.
+
+ {
- return false;
+ // Number of components may not be negative.
+
+ if (cinfo.num_components < 0)
+ {
+ ThrowBadFormat ("invalid cinfo.num_components");
+ }
+
+ // Convert relevant values from header to uint32.
+
+ uint32 imageWidthAsUint32 = 0;
+ uint32 imageHeightAsUint32 = 0;
+ uint32 numComponentsAsUint32 = 0;
+
+ ConvertUnsigned (cinfo.image_width, &imageWidthAsUint32);
+ ConvertUnsigned (cinfo.image_height, &imageHeightAsUint32);
+
+ // num_components is an int. Casting to unsigned is safe because
+ // the test above guarantees num_components is not negative.
+
+ ConvertUnsigned (static_cast<unsigned> (cinfo.num_components),
+ &numComponentsAsUint32);
+
+ // Check that dimensions of JPEG correspond to dimensions of tile.
+
+ if (imageWidthAsUint32 != tileArea.W () ||
+ imageHeightAsUint32 != tileArea.H () ||
+ numComponentsAsUint32 != planes)
+ {
+ ThrowBadFormat ("JPEG dimensions do not match tile");
+ }
+
+ }
+
+ // Start the compression.
+
+ jpeg_start_decompress (&cinfo);
+
+ // Setup a one-scanline size buffer.
+
+ dng_pixel_buffer buffer (tileArea,
+ plane,
+ planes,
+ ttByte,
+ pcInterleaved,
+ NULL);
+
+ buffer.fArea.b = tileArea.t + 1;
+
+ buffer.fDirty = true;
+
+ AutoPtr<dng_memory_block> bufferData (host.Allocate (buffer.fRowStep));
+
+ buffer.fData = bufferData->Buffer ();
+
+ uint8 *sampArray [1];
+
+ sampArray [0] = bufferData->Buffer_uint8 ();
+
+ // Read each scanline and save to image.
+
+ while (buffer.fArea.t < tileArea.b)
+ {
+
+ jpeg_read_scanlines (&cinfo, sampArray, 1);
+
+ image.Put (buffer);
+
+ buffer.fArea.t = buffer.fArea.b;
+ buffer.fArea.b = buffer.fArea.t + 1;
+
+ }
+
+ // Cleanup.
+
+ jpeg_finish_decompress (&cinfo);
+ jpeg_destroy_decompress (&cinfo);
+
+ }
+
+ catch (...)
+ {
+
+ jpeg_destroy_decompress (&cinfo);
+
+ throw;
+
}
+
+ #else
+
+ // 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");
+
+ #endif
+
+ }
+
+/*****************************************************************************/
- if (ifd.fSampleBitShift)
+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)
+ {
+
+ // Ensure the "tileOffset += 2" operation below will not wrap around.
+
+ if (tileOffset > std::numeric_limits<uint64>::max () - 2)
+ {
+ ThrowEndOfFile ();
+ }
+
+ tablesByteCount -= 2;
+
+ tileOffset += 2;
+ tileByteCount -= 2;
+
+ }
+
+ // Allocate buffer.
+
+ AutoPtr<dng_memory_block> buffer
+ (host.Allocate (SafeUint32Add (tablesByteCount, tileByteCount)));
+
+ // Read in table.
+
+ if (tablesByteCount)
{
-
- buffer.ShiftRight (ifd.fSampleBitShift);
-
+
+ DoCopyBytes (tablesBlock->Buffer (),
+ buffer->Buffer (),
+ tablesByteCount);
+
}
-
- if (ifd.fSubTileBlockRows > 1)
+
+ // Read in tile data.
+
+ stream.SetReadPosition (tileOffset);
+
+ stream.Get (buffer->Buffer_uint8 () + tablesByteCount, tileByteCount);
+
+ // Patch first byte, if required.
+
+ if (patchFirstByte)
{
-
- ReorderSubTileBlocks (host,
- ifd,
- buffer,
- fSubTileBlockBuffer);
-
+
+ buffer->Buffer_uint8 () [0] = 0xFF;
+
}
-
- image.Put (buffer);
-
- return true;
-
+
+ // 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 */)
+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,
+ bool usingMultipleThreads)
{
+
+ // 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 (),
+ usingMultipleThreads);
+
+ }
+
+ else
+ {
+
+ if (ifd.fPatchFirstJPEGByte && tileByteCount)
+ {
+ jpegDataInMemory [0] = 0xFF;
+ }
- // The dng_sdk does not include a baseline JPEG decoder. Override this
- // this method to add baseline JPEG support.
-
- return false;
-
+ DecodeLossyJPEG (host,
+ image,
+ tileArea,
+ plane,
+ planes,
+ ifd.fPhotometricInterpretation,
+ tileByteCount,
+ jpegDataInMemory,
+ usingMultipleThreads);
+
+ }
+
+ 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)
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
{
+
+ // If the tile area is empty, there's nothing to read.
- if (fUncompressedBuffer.Get () == NULL)
+ if (tileArea.IsEmpty ())
{
-
- uint32 bytesPerRow = tileArea.W () * planes * sizeof (uint16);
-
- uint32 rowsPerStrip = Pin_uint32 (ifd.fSubTileBlockRows,
- kImageBufferSize / bytesPerRow,
- tileArea.H ());
-
- rowsPerStrip = rowsPerStrip / ifd.fSubTileBlockRows
- * ifd.fSubTileBlockRows;
-
- uint32 bufferSize = bytesPerRow * rowsPerStrip;
-
- fUncompressedBuffer.Reset (host.Allocate (bufferSize));
-
+ return true;
}
+ dng_safe_uint32 bytesPerRow =
+ (dng_safe_uint32 (tileArea.W ()) * planes *
+ static_cast<uint32> (sizeof (uint16)));
+
+ uint32 rowsPerStrip = Pin_uint32 (ifd.fSubTileBlockRows,
+ kImageBufferSize / bytesPerRow.Get (),
+ tileArea.H ());
+
+ rowsPerStrip = rowsPerStrip / ifd.fSubTileBlockRows
+ * ifd.fSubTileBlockRows;
+
+ dng_safe_uint32 bufferSize = bytesPerRow * rowsPerStrip;
+
+ if (uncompressedBuffer.Get () &&
+ uncompressedBuffer->LogicalSize () < bufferSize.Get ())
+ {
+
+ uncompressedBuffer.Reset ();
+
+ }
+
+ if (uncompressedBuffer.Get () == NULL)
+ {
+
+ uncompressedBuffer.Reset (host.Allocate (bufferSize.Get ()));
+
+ }
+
dng_image_spooler spooler (host,
ifd,
image,
tileArea,
plane,
planes,
- *fUncompressedBuffer.Get (),
- fSubTileBlockBuffer);
-
- uint32 decodedSize = tileArea.W () *
- tileArea.H () *
- planes * sizeof (uint16);
-
+ *uncompressedBuffer.Get (),
+ subTileBlockBuffer);
+
+
+
+ dng_safe_uint32 decodedSize = (dng_safe_uint32 (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 ();
- }
+ decodedSize.Get (),
+ decodedSize.Get (),
+ bug16,
+ tileOffset + tileByteCount);
return true;
-
+
}
-
+
/*****************************************************************************/
bool dng_read_image::CanReadTile (const dng_ifd &ifd)
{
-
- if (ifd.fSampleFormat [0] != sfUnsignedInteger)
+
+ 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 false;
-
+
+ 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 */)
+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)
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ bool usingMultipleThreads)
{
-
+
switch (ifd.fCompression)
{
+
+ case ccLZW:
+ case ccDeflate:
+ case ccOldDeflate:
+ case ccPackBits:
+ {
+
+ // Figure out uncompressed size.
+
+ dng_safe_uint32 bytesPerSample = (ifd.fBitsPerSample [0] >> 3);
+
+ dng_safe_uint32 sampleCount = (dng_safe_uint32 (planes) *
+ dng_safe_uint32 (tileArea.W ()) *
+ dng_safe_uint32 (tileArea.H ()));
+
+ dng_safe_uint32 uncompressedSize = sampleCount * bytesPerSample;
+
+ // Setup pixel buffer to hold uncompressed data.
+
+ uint32 pixelType = ttUndefined;
+
+ if (ifd.fSampleFormat [0] == sfFloatingPoint)
+ {
+ pixelType = ttFloat;
+ }
+
+ else if (ifd.fBitsPerSample [0] == 8)
+ {
+ pixelType = ttByte;
+ }
+
+ else if (ifd.fBitsPerSample [0] == 16)
+ {
+ pixelType = ttShort;
+ }
+
+ else if (ifd.fBitsPerSample [0] == 32)
+ {
+ pixelType = ttLong;
+ }
+
+ else
+ {
+ ThrowBadFormat ();
+ }
+
+ dng_pixel_buffer buffer (tileArea,
+ plane,
+ planes,
+ pixelType,
+ pcInterleaved,
+ NULL);
+
+ // Specify custom pixel size (e.g., ttFloat pixel type but
+ // pixel size may be 2 for stored 16-bit half-float).
+
+ buffer.fPixelSize = bytesPerSample.Get ();
+
+ dng_safe_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 += (dng_safe_uint32 (dng_safe_int32 (buffer.fRowStep)) *
+ dng_safe_uint32 (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.Get (),
+ (sampleCount * 4u).Get ());
+ }
+
+ // 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.Get ())
+ {
+
+ uncompressedBuffer.Reset ();
+
+ }
+
+ if (uncompressedBuffer.Get () == NULL)
+ {
+
+ uncompressedBuffer.Reset (host.Allocate (bufferSize.Get ()));
+
+ }
+
+ 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.Get ()))
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ else if (ifd.fCompression == ccPackBits)
+ {
+
+ dng_stream subStream (compressedBuffer->Buffer_uint8 (),
+ tileByteCount);
+
+ if (!DecodePackBits (subStream,
+ (uint8 *) buffer.fData,
+ uncompressedSize.Get ()))
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ else
+ {
+
+ uLongf dstLen = uncompressedSize.Get ();
+
+ int err = uncompress ((Bytef *) buffer.fData,
+ &dstLen,
+ (const Bytef *) compressedBuffer->Buffer (),
+ tileByteCount);
+
+ if (err != Z_OK)
+ {
+
+ if (err == Z_MEM_ERROR)
+ {
+ ThrowMemoryFull ();
+ }
+
+ else if (err == Z_DATA_ERROR)
+ {
+ // Most other TIFF readers do not fail for this error
+ // so we should not either, even if it means showing
+ // a corrupted image to the user. Watson #2530216
+ // - tknoll 12/20/11
+ }
+
+ else
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ if (dstLen != uncompressedSize.Get ())
+ {
+ ThrowBadFormat ();
+ }
+
+ }
+
+ // 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.Get ());
+
+ }
+
+ 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.Get () - 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.Get () - 1) * 3;
+ uint32 *dstPtr = ((uint32 *) buffer.fData) + (sampleCount.Get () - 1);
+
+ if (stream.BigEndian () || ifd.fPredictor == cpFloatingPoint ||
+ ifd.fPredictor == cpFloatingPointX2 ||
+ ifd.fPredictor == cpFloatingPointX4)
+ {
+
+ for (uint32 index = 0; index < sampleCount.Get (); index++)
+ {
+
+ *(dstPtr--) = DNG_FP24ToFloat (srcPtr);
+
+ srcPtr -= 3;
+
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 index = 0; index < sampleCount.Get (); 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))
+ planes,
+ uncompressedBuffer,
+ subTileBlockBuffer))
{
-
+
return;
-
+
}
-
+
break;
-
+
}
-
+
case ccJPEG:
{
-
+
if (ifd.IsBaselineJPEG ())
{
-
+
// Baseline JPEG.
-
+
if (ReadBaselineJPEG (host,
ifd,
stream,
image,
tileArea,
plane,
planes,
- tileByteCount))
+ tileByteCount,
+ compressedBuffer.Get () ? compressedBuffer->Buffer_uint8 () : NULL,
+ usingMultipleThreads))
{
-
+
return;
-
+
}
-
+
}
-
+
else
{
-
+
// Otherwise is should be lossless JPEG.
-
+
if (ReadLosslessJPEG (host,
ifd,
stream,
image,
tileArea,
plane,
planes,
- tileByteCount))
+ tileByteCount,
+ uncompressedBuffer,
+ subTileBlockBuffer))
{
-
+
return;
-
+
}
-
+
}
-
+
break;
-
+
}
-
+
+ case ccLossyJPEG:
+ {
+
+ if (ReadBaselineJPEG (host,
+ ifd,
+ stream,
+ image,
+ tileArea,
+ plane,
+ planes,
+ tileByteCount,
+ compressedBuffer.Get () ? compressedBuffer->Buffer_uint8 () : NULL,
+ usingMultipleThreads))
+ {
+
+ 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;
+
+ }
+
+/*****************************************************************************/
+
+dng_read_tiles_task::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)
+
+ : dng_area_task ("dng_read_tiles_task")
+
+ , 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 dng_read_tiles_task::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++;
+
+ ReadTask (tileIndex,
+ byteCount,
+ compressedBuffer.Get ());
}
+ ProcessTask (tileIndex,
+ byteCount,
+ sniffer,
+ compressedBuffer,
+ uncompressedBuffer,
+ subTileBlockBuffer);
+
}
- if (!CanReadTile (ifd))
+ }
+
+/*****************************************************************************/
+
+void dng_read_tiles_task::ReadTask (uint32 tileIndex,
+ uint32 &byteCount,
+ dng_memory_block *compressedBuffer)
+ {
+
+ TempStreamSniffer noSniffer (fStream, NULL);
+
+ fStream.SetReadPosition (fTileOffset [tileIndex]);
+
+ byteCount = fTileByteCount [tileIndex];
+
+ if (fJPEGImage)
{
- return false;
+
+ fJPEGImage->fJPEGData [tileIndex] . Reset (fHost.Allocate (byteCount));
+
}
- return true;
+ fStream.Get (fJPEGImage ? fJPEGImage->fJPEGData [tileIndex]->Buffer ()
+ : compressedBuffer->Buffer (),
+ byteCount);
+
+ }
+
+/*****************************************************************************/
+
+void dng_read_tiles_task::ProcessTask (uint32 tileIndex,
+ uint32 byteCount,
+ dng_abort_sniffer *sniffer,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer)
+ {
+
+ 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,
+ true);
}
/*****************************************************************************/
void dng_read_image::Read (dng_host &host,
const dng_ifd &ifd,
dng_stream &stream,
- dng_image &image)
+ dng_image &image,
+ dng_jpeg_image *jpegImage,
+ dng_fingerprint *jpegDigest)
{
+
+ // Reject images that are too big.
+
+ // Allow up to 2 * kMaxImageSide to deal with intermediate image objects
+ // (e.g., rotated and padded).
+ static const uint32 kLimit = 2 * kMaxImageSide;
+
+ if (ifd.fImageWidth > kLimit ||
+ ifd.fImageLength > kLimit)
+ {
+
+ ThrowBadFormat ("dng_read_image::Read image too large");
+
+ }
+
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);
-
+ 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;
-
+
+ uint32 tileCount = SafeUint32Mult (tilesAcross, tilesDown, outerSamples);
+
// Find the tile offsets.
-
- dng_memory_data tileOffsetData (tileCount * sizeof (uint64));
-
+
+ dng_memory_data tileOffsetData (tileCount, 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;
-
+
+ uint32 bytesPerRow = SafeUint32Mult (ifd.fTileWidth,
+ innerSamples,
+ bytesPerPixel);
+
subTileLength = Pin_uint32 (ifd.fSubTileBlockRows,
- kImageBufferSize / bytesPerRow,
+ kImageBufferSize / bytesPerRow,
ifd.fTileLength);
-
+
subTileLength = subTileLength / ifd.fSubTileBlockRows
* ifd.fSubTileBlockRows;
-
- fUncompressedBuffer.Reset (host.Allocate (subTileLength * bytesPerRow));
-
+
+ uncompressedSize = SafeUint32Mult (subTileLength, bytesPerRow);
+
}
-
+
// Else we need to know the byte counts.
-
+
else
{
-
- tileByteCountData.Allocate (tileCount * sizeof (uint32));
-
+
+ tileByteCountData.Allocate (tileCount, 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 ();
-
+
}
-
+
}
-
+
}
-
- // See if we need to allocate the compressed tile data buffer.
-
- if (tileByteCount && NeedsCompressedBuffer (ifd))
+
+ // Find maximum tile size, if possible.
+
+ uint32 maxTileByteCount = 0;
+
+ if (tileByteCount)
{
-
- // Find maximum compressed tile size.
-
- uint32 maxTileByteCount = 0;
-
+
for (tileIndex = 0; tileIndex < tileCount; tileIndex++)
{
-
+
maxTileByteCount = Max_uint32 (maxTileByteCount,
tileByteCount [tileIndex]);
-
+
}
-
- // Allocate buffer that size.
-
- if (maxTileByteCount)
+
+ }
+
+ // Do we need a compressed data buffer?
+
+ uint32 compressedSize = 0;
+
+ bool needsCompressedBuffer = NeedsCompressedBuffer (ifd);
+
+ if (needsCompressedBuffer)
+ {
+
+ if (!tileByteCount)
{
-
- fCompressedBuffer.Reset (host.Allocate (maxTileByteCount));
-
+ ThrowBadFormat ();
}
-
+
+ compressedSize = maxTileByteCount;
+
}
-
- // Now read in each tile.
-
- tileIndex = 0;
-
- for (uint32 plane = 0; plane < outerSamples; plane++)
+
+ // Are we keeping the compressed JPEG image data?
+
+ if (jpegImage)
{
-
- if (plane >= image.Planes ())
+
+ if (ifd.IsBaselineJPEG ())
{
- return; // Don't waste time reading planes we are not saving.
+
+ 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]);
+
}
-
- for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
+
+ else
{
-
- for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
+
+ 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
+ [SafeUint32Add (tileCount, (fJPEGTables.Get () ? 1 : 0))]);
+
+ }
+
+ // Don't read planes we are not actually saving.
+
+ outerSamples = Min_uint32 (image.Planes (), outerSamples);
+
+ // Performance optimization. We are reading in a potentially large image, which
+ // is usually in a fairly contiguous byte range in the file. See if it makes sense
+ // to increase the stream buffer size for this operation.
+
+ uint64 contiguousByteCount = 0;
+
+ {
+
+ bool tilesInOrder = true;
+
+ uint64 totalTileBytes = 0;
+
+ uint64 minFileOffset = tileOffset [0];
+ uint64 maxFileOffset = tileOffset [0];
+
+ tileIndex = 0;
+
+ for (uint32 plane = 0; plane < outerSamples; plane++)
+ {
+
+ for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
{
-
- 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++)
+
+ for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
{
+
+ uint64 thisOffset = tileOffset [tileIndex];
+
+ uint64 thisByteCount;
+
+ if (tileByteCount)
+ {
+
+ thisByteCount = tileByteCount [tileIndex];
+
+ }
+
+ else
+ {
+
+ thisByteCount = ifd.TileByteCount (ifd.TileArea (rowIndex, colIndex));
+
+ }
+
+ if (thisOffset < maxFileOffset)
+ {
+ tilesInOrder = false;
+ }
+
+ totalTileBytes += thisByteCount;
+
+ minFileOffset = Min_uint64 (minFileOffset, thisOffset);
+ maxFileOffset = Max_uint64 (maxFileOffset, thisOffset + thisByteCount);
+
+ tileIndex++;
+
+ }
+
+ }
+
+ }
+
+ // Quick check for enough data in file.
+
+ if (maxFileOffset > stream.Length ())
+ {
+
+ ThrowBadFormat ();
+
+ }
+
+ // Are all the tiles in order?
+
+ if (tilesInOrder)
+ {
+
+ // And are going to read at least 90% of the bytes in the range?
+
+ uint64 totalFileBytes = maxFileOffset - minFileOffset;
+
+ if (totalTileBytes >= totalFileBytes * 9 / 10)
+ {
+
+ contiguousByteCount = totalFileBytes;
+
+ }
+
+ }
+
+ }
+
+ dng_stream_contiguous_read_hint readHint (stream,
+ host.Allocator (),
+ tileOffset [0],
+ contiguousByteCount);
+
+ // 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 (useMultipleThreads)
+ {
- host.SniffForAbort ();
-
- dng_rect subArea (tileArea);
+ DoReadTiles (host,
+ ifd,
+ stream,
+ image,
+ jpegImage,
+ jpegTileDigest.Get (),
+ outerSamples,
+ innerSamples,
+ tilesDown,
+ tilesAcross,
+ tileOffset,
+ tileByteCount,
+ maxTileByteCount,
+ uncompressedSize);
+
+ }
+
+ // 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,
+ useMultipleThreads);
+
+ }
+
+ tileIndex++;
+
+ }
+
+ }
- subArea.t = tileArea.t + subIndex * subTileLength;
+ }
+
+ }
+
+ // 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 ());
+
+ }
- subArea.b = Min_int32 (subArea.t + subTileLength,
- tileArea.b);
+ }
- uint32 subByteCount;
+/*****************************************************************************/
- if (tileByteCount)
- {
- subByteCount = tileByteCount [tileIndex];
- }
- else
- {
- subByteCount = ifd.TileByteCount (subArea);
- }
+void dng_read_image::DoReadTiles (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)
+ {
+
+ uint32 threadCount = Min_uint32 (outerSamples * tilesDown * tilesAcross,
+ host.PerformAreaTaskThreads ());
- ReadTile (host,
+ dng_read_tiles_task task (*this,
+ host,
ifd,
stream,
image,
- subArea,
- plane,
+ jpegImage,
+ jpegTileDigest,
+ outerSamples,
innerSamples,
- subByteCount);
-
- }
-
- tileIndex++;
-
- }
-
- }
-
- }
-
+ tilesDown,
+ tilesAcross,
+ tileOffset,
+ tileByteCount,
+ compressedSize,
+ uncompressedSize);
+
+ host.PerformAreaTask (task,
+ dng_rect (0, 0, 16, 16 * threadCount));
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_read_image.h b/core/libs/dngwriter/extra/dng_sdk/dng_read_image.h
index 63d7754bd1..af8a60300c 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_read_image.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_read_image.h
@@ -1,152 +1,263 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_read_image.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
/** \file
* Support for DNG image reading.
*/
/*****************************************************************************/
#ifndef __dng_read_image__
#define __dng_read_image__
/*****************************************************************************/
+#include "dng_area_task.h"
#include "dng_auto_ptr.h"
#include "dng_classes.h"
#include "dng_image.h"
#include "dng_memory.h"
+#include "dng_mutex.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> fCompressedBuffer;
-
- AutoPtr<dng_memory_block> fUncompressedBuffer;
-
- AutoPtr<dng_memory_block> fSubTileBlockBuffer;
-
+
+ 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_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);
-
+ 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,
+ bool usingMultipleThreads);
+
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);
-
+ uint32 tileByteCount,
+ uint8 *jpegDataInMemory,
+ bool usingMultipleThreads);
+
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);
-
+ 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);
+ uint32 tileByteCount,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer,
+ bool usingMultipleThreads);
+
+ virtual void DoReadTiles (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);
+
+ };
+
+/*****************************************************************************/
+
+class dng_read_tiles_task : public dng_area_task,
+ private dng_uncopyable
+ {
+
+ protected:
+
+ 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);
+
+ void Process (uint32 threadIndex,
+ const dng_rect &tile,
+ dng_abort_sniffer *sniffer);
+ protected:
+
+ void ReadTask (uint32 tileIndex,
+ uint32 &byteCount,
+ dng_memory_block *compressedBuffer);
+
+ void ProcessTask (uint32 tileIndex,
+ uint32 byteCount,
+ dng_abort_sniffer *sniffer,
+ AutoPtr<dng_memory_block> &compressedBuffer,
+ AutoPtr<dng_memory_block> &uncompressedBuffer,
+ AutoPtr<dng_memory_block> &subTileBlockBuffer);
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_rect.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_rect.cpp
index 0dd8872448..18c44ae557 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_rect.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_rect.cpp
@@ -1,168 +1,182 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_rect.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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;
+
+ }
+/*****************************************************************************/
+
+dng_rect_real64 Bounds (const dng_point_real64 &a,
+ const dng_point_real64 &b,
+ const dng_point_real64 &c,
+ const dng_point_real64 &d)
+ {
+
+ real64 xMin = Min_real64 (a.h, Min_real64 (b.h, Min_real64 (c.h, d.h)));
+ real64 xMax = Max_real64 (a.h, Max_real64 (b.h, Max_real64 (c.h, d.h)));
+
+ real64 yMin = Min_real64 (a.v, Min_real64 (b.v, Min_real64 (c.v, d.v)));
+ real64 yMax = Max_real64 (a.v, Max_real64 (b.v, Max_real64 (c.v, d.v)));
+
+ return dng_rect_real64 (yMin,
+ xMin,
+ yMax,
+ xMax);
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_rect.h b/core/libs/dngwriter/extra/dng_sdk/dng_rect.h
index 5c75a5a9a0..a986742f31 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_rect.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_rect.h
@@ -1,471 +1,626 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_rect.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_rect__
#define __dng_rect__
/*****************************************************************************/
-#include "dng_types.h"
+#include "dng_exceptions.h"
#include "dng_point.h"
+#include "dng_safe_arithmetic.h"
+#include "dng_types.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)
{
}
+
+ // Constructs a dng_rect from the top-left and bottom-right corner.
+ // Throws an exception if the resulting height or width are too large
+ // to be represented as an int32. The intent of this is to protect
+ // code that may be computing the height or width directly from the
+ // member variables (instead of going through H() or W()).
dng_rect (int32 tt, int32 ll, int32 bb, int32 rr)
: t (tt)
, l (ll)
, b (bb)
, r (rr)
{
- }
+ int32 dummy;
+
+ if (!SafeInt32Sub (r, l, &dummy) ||
+ !SafeInt32Sub (b, t, &dummy))
+ {
+ ThrowProgramError ("Overflow in dng_rect constructor");
+ }
+
+ }
+
dng_rect (uint32 h, uint32 w)
: t (0)
, l (0)
- , b (h)
- , r (w)
{
- }
+ if (!ConvertUint32ToInt32 (h, &b) ||
+ !ConvertUint32ToInt32 (w, &r))
+ {
+ ThrowProgramError ("Overflow in dng_rect constructor");
+ }
+
+ }
+
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 ();
}
+
+ // Returns the width of the rectangle, or 0 if r is smaller than l.
+ // Throws an exception if the width is too large to be represented as
+ // a _signed_ int32 (even if it would fit in a uint32). This is
+ // consciously conservative -- there are existing uses of W() where
+ // the result is converted to an int32 without an overflow check, and
+ // we want to make sure no overflow can occur in such cases. We
+ // provide this check in addition to the check performed in the
+ // "two-corners" constructor to protect client code that produes a
+ // dng_rect with excessive size by initializing or modifying the
+ // member variables directly.
uint32 W () const
{
- return (r >= l ? (uint32) (r - l) : 0);
+
+ if (r >= l)
+ {
+
+ int32 width;
+
+ if (!SafeInt32Sub (r, l, &width))
+ {
+ ThrowProgramError ("Overflow computing rectangle width");
+ }
+
+ return static_cast<uint32> (width);
+
+ }
+
+ else
+ {
+ return 0;
+ }
+
}
+
+ // Returns the height of the rectangle, or 0 if b is smaller than t.
+ // Throws an exception if the height is too large to be represented as
+ // a _signed_ int32 (see W() for rationale).
uint32 H () const
{
- return (b >= t ? (uint32) (b - t) : 0);
- }
+ if (b >= t)
+ {
+
+ int32 height;
+
+ if (!SafeInt32Sub (b, t, &height))
+ {
+ ThrowProgramError ("Overflow computing rectangle height");
+ }
+
+ return static_cast<uint32> (height);
+
+ }
+
+ else
+ {
+ return 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 (H (), W ());
+ return dng_point ((int32) H (), (int32) W ());
}
+ uint32 LongSide () const
+ {
+ return Max_uint32 (W (), H ());
+ }
+
+ uint32 ShortSide () const
+ {
+ return Min_uint32 (W (), H ());
+ }
+
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 LongSide () const
+ {
+ return Max_real64 (W (), H ());
+ }
+
+ real64 ShortSide () const
+ {
+ return Min_real64 (W (), H ());
+ }
+
real64 Diagonal () const
{
return hypot (W (), H ());
}
-
+
+ dng_point_real64 Center () const
+ {
+ return dng_point_real64 ((t + b) * 0.5,
+ (l + r) * 0.5);
+ }
+
};
/*****************************************************************************/
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 + (rect.W () >> 1);
- rect.b = rect.t + (rect.H () >> 1);
+ 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 + (rect.W () << 1);
- rect.b = rect.t + (rect.H () << 1);
+ 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
+inline dng_rect_real64 MakeOuterPadRect (const dng_rect_real64 &rect,
+ const real64 pad)
+ {
+ dng_rect_real64 result = rect;
+
+ result.t -= pad;
+ result.l -= pad;
+ result.b += pad;
+ result.r += pad;
+
+ return result;
+
+ }
+
+/*****************************************************************************/
+
+inline dng_rect_real64 Lerp (const dng_rect_real64 &a,
+ const dng_rect_real64 &b,
+ const real64 t)
+ {
+
+ return dng_rect_real64 (Lerp_real64 (a.t, b.t, t),
+ Lerp_real64 (a.l, b.l, t),
+ Lerp_real64 (a.b, b.b, t),
+ Lerp_real64 (a.r, b.r, t));
+
+ }
+
+/*****************************************************************************/
+
+dng_rect_real64 Bounds (const dng_point_real64 &a,
+ const dng_point_real64 &b,
+ const dng_point_real64 &c,
+ const dng_point_real64 &d);
+
+/*****************************************************************************/
+
+#endif
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_ref_counted_block.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_ref_counted_block.cpp
new file mode 100644
index 0000000000..eff57c5f1f
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_ref_counted_block.cpp
@@ -0,0 +1,194 @@
+/*****************************************************************************/
+// Copyright 2006-2019 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 <new>
+
+#include "dng_ref_counted_block.h"
+
+#include "dng_exceptions.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 = 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_std_mutex lock (blockHeader->fMutex);
+
+ if (--blockHeader->fRefCount == 0)
+ doFree = true;
+
+ }
+
+ if (doFree)
+ {
+
+ blockHeader->~header ();
+
+ 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;
+
+ if (blockHeader)
+ {
+
+ dng_lock_std_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;
+
+ if (blockHeader)
+ {
+
+ dng_lock_std_mutex lock (blockHeader->fMutex);
+
+ blockHeader->fRefCount++;
+
+ fBuffer = blockHeader;
+
+ }
+
+ }
+
+ return *this;
+
+ }
+
+/*****************************************************************************/
+
+void dng_ref_counted_block::EnsureWriteable ()
+ {
+
+ if (fBuffer)
+ {
+
+ header *possiblySharedHeader = (header *) fBuffer;
+
+ {
+
+ dng_lock_std_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/core/libs/dngwriter/extra/dng_sdk/dng_memory.h b/core/libs/dngwriter/extra/dng_sdk/dng_ref_counted_block.h
similarity index 50%
copy from core/libs/dngwriter/extra/dng_sdk/dng_memory.h
copy to core/libs/dngwriter/extra/dng_sdk/dng_ref_counted_block.h
index de0fa825ed..8c5228eb1b 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_memory.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_ref_counted_block.h
@@ -1,492 +1,287 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_memory.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/** Support for memory allocation.
+/** Support for a refcounted block, with optional copy-on-write
*/
/*****************************************************************************/
-#ifndef __dng_memory__
-#define __dng_memory__
+#ifndef __dng_ref_counted_block__
+#define __dng_ref_counted_block__
/*****************************************************************************/
#include "dng_types.h"
+#include "dng_mutex.h"
+
+#include <mutex>
/*****************************************************************************/
/// \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
+class dng_ref_counted_block
{
-
+
private:
+
+ struct header
+ {
- void *fBuffer;
+ dng_std_mutex fMutex;
- public:
+ uint32 fRefCount;
+
+ uint32 fSize;
+
+ header (uint32 size)
+ : fMutex ()
+ , 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_memory_data ();
-
+ 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_memory_data (uint32 size);
-
+ dng_ref_counted_block (uint32 size);
+
/// Release memory buffer using free.
- ~dng_memory_data ();
+ ~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.
- void * Buffer ()
+ uint32 LogicalSize () const
{
- return fBuffer;
+ return fBuffer ? ((header *) fBuffer)->fSize : 0;
}
+ void * Buffer ()
+ {
+ return fBuffer ? (void *) ((char *) fBuffer + sizeof (header)) : NULL;
+ }
+
/// 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 fBuffer ? (const void *) ((char *) fBuffer + sizeof (header)) : NULL;
}
-
+
/// 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;
-
- void *fBuffer;
-
- protected:
-
- dng_memory_block (uint32 logicalSize)
- : fLogicalSize (logicalSize)
- , fBuffer (NULL)
- {
- }
-
- uint32 PhysicalSize ()
- {
- return fLogicalSize + 64;
- }
-
- void SetBuffer (void *p)
- {
- fBuffer = (void *) ((((uintptr) p) + 15) & ~((uintptr) 15));
- }
-
- public:
-
- virtual ~dng_memory_block ()
- {
- }
-
- /// 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/core/libs/dngwriter/extra/dng_sdk/dng_reference.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_reference.cpp
index 80155783e6..fc41de6a23 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_reference.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_reference.cpp
@@ -1,2578 +1,3204 @@
/*****************************************************************************/
-// Copyright 2006-2009 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_reference.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_reference.h"
#include "dng_1d_table.h"
+#include "dng_flags.h"
#include "dng_hue_sat_map.h"
#include "dng_matrix.h"
#include "dng_resample.h"
+#include "dng_simd_type.h"
#include "dng_utils.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)
+template <SIMDType simd, typename destType>
+void RefSetArea (destType *dPtr,
+ destType value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep)
{
- for (uint32 row = 0; row < rows; row++)
- {
+ INTEL_COMPILER_NEEDED_NOTE
+ SET_CPU_FEATURE(simd);
- uint16 *dPtr1 = dPtr;
+ if ((planeStep == 0) && (colStep == 1))
+ {
- for (uint32 col = 0; col < cols; col++)
+ for (uint32 row = 0; row < rows; row++)
{
- uint16 *dPtr2 = dPtr1;
-
- for (uint32 plane = 0; plane < planes; plane++)
+ INTEL_PRAGMA_SIMD_ASSERT
+ for (uint32 col = 0; col < cols; col++)
{
-
- *dPtr2 = value;
-
- dPtr2 += planeStep;
+
+ dPtr [col] = value;
}
-
- dPtr1 += colStep;
-
+
+ dPtr += rowStep;
+
}
+ }
- dPtr += rowStep;
+ else if (planeStep == 1)
+ {
- }
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ destType *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ destType *dPtr2 = dPtr1;
- }
+ INTEL_PRAGMA_SIMD_ASSERT
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ dPtr2 [plane] = value;
+
+ }
+
+ 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++)
+ else
{
- uint32 *dPtr1 = dPtr;
-
- for (uint32 col = 0; col < cols; col++)
+ for (uint32 row = 0; row < rows; row++)
{
-
- uint32 *dPtr2 = dPtr1;
-
- for (uint32 plane = 0; plane < planes; plane++)
+
+ destType *dPtr1 = dPtr;
+
+ for (uint32 col = 0; col < cols; col++)
{
-
- *dPtr2 = value;
-
- dPtr2 += planeStep;
+
+ destType *dPtr2 = dPtr1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = value;
+
+ dPtr2 += planeStep;
+
+ }
+
+ dPtr1 += colStep;
}
-
- dPtr1 += colStep;
-
+
+ dPtr += rowStep;
+
}
- dPtr += rowStep;
-
}
-
+
}
/*****************************************************************************/
+#if !qDNGIntelCompiler
+template
+void RefSetArea<Scalar, uint16>(uint16 *dPtr,
+ uint16 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+template
+void RefSetArea<Scalar, uint32>(uint32 *dPtr,
+ uint32 value,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 rowStep,
+ int32 colStep,
+ int32 planeStep);
+#else
+template SetArea16Proc RefSetArea<Scalar, uint16>;
+template SetArea16Proc RefSetArea<AVX2, uint16>;
+template SetArea32Proc RefSetArea<Scalar, uint32>;
+template SetArea32Proc RefSetArea<AVX2, uint32>;
+#endif
+
+/*****************************************************************************/
+
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;
-
+
}
-
+
}
/*****************************************************************************/
+template <SIMDType simd>
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)
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep)
{
+ INTEL_COMPILER_NEEDED_NOTE
+ SET_CPU_FEATURE(simd);
+
for (uint32 row = 0; row < rows; row++)
{
const uint16 *sPtr1 = sPtr;
- int16 *dPtr1 = dPtr;
+ int16 *dPtr1 = dPtr;
for (uint32 col = 0; col < cols; col++)
{
const uint16 *sPtr2 = sPtr1;
- int16 *dPtr2 = dPtr1;
+ int16 *dPtr2 = dPtr1;
+
+ // Vectorizing if both sPlaneStep and dPlaneStep are 1. Else,
+ // regular operation is performed.
- for (uint32 plane = 0; plane < planes; plane++)
+ if (sPlaneStep == 1 && dPlaneStep == 1)
{
- *dPtr2 = *sPtr2 ^ 0x8000;
+ INTEL_PRAGMA_SIMD_ASSERT
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
- sPtr2 += sPlaneStep;
- dPtr2 += dPlaneStep;
+ *dPtr2 = *sPtr2 ^ 0x8000;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+ }
+
+ }
+
+ else
+ {
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ *dPtr2 = *sPtr2 ^ 0x8000;
+
+ sPtr2 += sPlaneStep;
+ dPtr2 += dPlaneStep;
+
+ }
}
sPtr1 += sColStep;
dPtr1 += dColStep;
}
sPtr += sRowStep;
dPtr += dRowStep;
}
}
/*****************************************************************************/
+INTEL_COMPILER_NEEDED_NOTE
+#if !qDNGIntelCompiler
+template
+void RefCopyArea16_S16<Scalar> (const uint16 *sPtr,
+ int16 *dPtr,
+ uint32 rows,
+ uint32 cols,
+ uint32 planes,
+ int32 sRowStep,
+ int32 sColStep,
+ int32 sPlaneStep,
+ int32 dRowStep,
+ int32 dColStep,
+ int32 dPlaneStep);
+#else
+template CopyArea16_S16Proc RefCopyArea16_S16<Scalar>;
+template CopyArea16_S16Proc RefCopyArea16_S16<AVX2>;
+#endif
+
+/*****************************************************************************/
+
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) (*sPtr2 * scale + 0.5f);
-
+
+ *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) (*sPtr2 * scale + 0.5f);
-
+
+ *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) (*sPtr2 * scale + 0.5f);
-
+
+ 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_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);
+ real32 sScale = (real32) ((int32) satDivisions - 1);
+ real32 vScale = (real32) ((int32) valDivisions - 1);
+
+ int32 maxHueIndex0 = (int32) hueDivisions - 1;
+ int32 maxSatIndex0 = (int32) satDivisions - 2;
+ int32 maxValIndex0 = (int32) valDivisions - 2;
- 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 dng_hue_sat_map::HSBModify *tableBase = lut.GetDeltas ();
+ 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 = v * vScale;
-
+ 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 +
+
+ 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);
- v = Min_real32 (v * valScale, 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] = 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 [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 [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 [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 [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,
+ uint16 blackLevel)
+ {
+
+ real32 *basePtr = sPtr;
+
+ real32 blackScale1 = 1.0f;
+ real32 blackScale2 = 1.0f;
+ real32 blackOffset1 = 0.0f;
+ real32 blackOffset2 = 0.0f;
+
+ if (blackLevel != 0)
+ {
+
+ blackOffset2 = ((real32) blackLevel) / 65535.0f;
+ blackScale2 = 1.0f - blackOffset2;
+ blackScale1 = 1.0f / blackScale2;
+ blackOffset1 = 1.0f - blackScale1;
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ real32 *dPtr = basePtr + plane * sPlaneStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ dPtr [col] = dPtr [col] * blackScale1 + blackOffset1;
+
+ }
+
+ dPtr += sRowStep;
+
+ }
+
+ }
+
+ }
+
+ 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;
+
+ }
+
+ }
+
+ if (blackLevel != 0)
+ {
+
+ for (uint32 plane = 0; plane < planes; plane++)
+ {
+
+ real32 *dPtr = basePtr + plane * sPlaneStep;
+
+ for (uint32 row = 0; row < rows; row++)
+ {
+
+ for (uint32 col = 0; col < cols; col++)
+ {
+
+ dPtr [col] = dPtr [col] * blackScale2 + blackOffset2;
+
+ }
+
+ dPtr += sRowStep;
+
+ }
+
+ }
+
+ }
+
}
/******************************************************************************/
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;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void RefBaselineMapPoly32 (real32 *dPtr,
+ const int32 rowStep,
+ const uint32 rows,
+ const uint32 cols,
+ const uint32 rowPitch,
+ const uint32 colPitch,
+ const real32 *coefficients,
+ const uint32 degree,
+ uint16 blackLevel)
+ {
+
+ real32 blackScale1 = 1.0f;
+ real32 blackScale2 = 1.0f;
+ real32 blackOffset1 = 0.0f;
+ real32 blackOffset2 = 0.0f;
+
+ if (blackLevel != 0)
+ {
+
+ blackOffset2 = ((real32) blackLevel) / 65535.0f;
+ blackScale2 = 1.0f - blackOffset2;
+ blackScale1 = 1.0f / blackScale2;
+ blackOffset1 = 1.0f - blackScale1;
+
+ }
+
+ for (uint32 row = 0; row < rows; row += rowPitch)
+ {
+
+ if (blackLevel != 0)
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = dPtr [col] * blackScale1 + blackOffset1;
+
+ }
+
+ }
+
+ switch (degree)
+ {
+
+ case 0:
+ {
+
+ real32 y = Pin_real32 (-1.0f,
+ coefficients [0],
+ 1.0f);
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = y;
}
- d1 += step1;
+ break;
}
- dPtr += step0;
+ case 1:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = coefficients [0] + x * coefficients [1];
+
+ dPtr [col] = Pin_real32 (-1.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ case 2:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y;
+
+ if (x < 0.0f)
+ {
+
+ y = coefficients [0] + x *
+ (coefficients [1] - x *
+ (coefficients [2]));
+
+ }
+
+ else
+ {
+
+ y = coefficients [0] + x *
+ (coefficients [1] + x *
+ (coefficients [2]));
+
+ }
+
+ dPtr [col] = Pin_real32 (-1.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ case 3:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y;
+
+ if (x < 0.0f)
+ {
+
+ y = coefficients [0] + x *
+ (coefficients [1] - x *
+ (coefficients [2] - x *
+ (coefficients [3])));
+
+ }
+
+ else
+ {
+
+ y = coefficients [0] + x *
+ (coefficients [1] + x *
+ (coefficients [2] + x *
+ (coefficients [3])));
+
+ }
+
+ dPtr [col] = Pin_real32 (-1.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ case 4:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y;
+
+ if (x < 0.0f)
+ {
+
+ y = coefficients [0] + x *
+ (coefficients [1] - x *
+ (coefficients [2] - x *
+ (coefficients [3] - x *
+ (coefficients [4]))));
+
+ }
+
+ else
+ {
+
+ y = coefficients [0] + x *
+ (coefficients [1] + x *
+ (coefficients [2] + x *
+ (coefficients [3] + x *
+ (coefficients [4]))));
+
+ }
+
+ dPtr [col] = Pin_real32 (-1.0f, y, 1.0f);
+
+ }
+
+ break;
+
+ }
+
+ default:
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ real32 x = dPtr [col];
+
+ real32 y = coefficients [0];
+
+ if (x < 0.0f)
+ {
+
+ x = -x;
+
+ real32 xx = x;
+
+ for (uint32 j = 1; j <= degree; j++)
+ {
+
+ y -= coefficients [j] * xx;
+
+ xx *= x;
+
+ }
+
+ }
+
+ else
+ {
+
+ real32 xx = x;
+
+ for (uint32 j = 1; j <= degree; j++)
+ {
+
+ y += coefficients [j] * xx;
+
+ xx *= x;
+
+ }
+
+ }
+
+ dPtr [col] = Pin_real32 (-1.0f, y, 1.0f);
+
+ }
+
+ }
}
+ if (blackLevel != 0)
+ {
+
+ for (uint32 col = 0; col < cols; col += colPitch)
+ {
+
+ dPtr [col] = dPtr [col] * blackScale2 + blackOffset2;
+
+ }
+
+ }
+
+ // Advance to the next row. Note that rowStep already accounts for the
+ // row pitch.
+
+ dPtr += rowStep;
+
}
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_reference.h b/core/libs/dngwriter/extra/dng_sdk/dng_reference.h
index af4bf8b84c..75f7151508 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_reference.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_reference.h
@@ -1,507 +1,522 @@
/*****************************************************************************/
-// Copyright 2006-2009 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_reference.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_reference__
#define __dng_reference__
/*****************************************************************************/
#include "dng_bottlenecks.h"
+#include "dng_simd_type.h"
+#include "dng_flags.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,
+template <SIMDType simd, typename destType>
+void RefSetArea (destType *dPtr,
+ destType 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);
+template <SIMDType simd>
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_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,
+ uint16 blackLevel);
+
+/*****************************************************************************/
+
void RefMapArea16 (uint16 *dPtr,
uint32 count0,
uint32 count1,
uint32 count2,
int32 step0,
int32 step1,
int32 step2,
const uint16 *map);
/*****************************************************************************/
-#endif
+void RefBaselineMapPoly32 (real32 *dPtr,
+ const int32 rowStep,
+ const uint32 rows,
+ const uint32 cols,
+ const uint32 rowPitch,
+ const uint32 colPitch,
+ const real32 *coefficients,
+ const uint32 degree,
+ uint16 blackLevel);
/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_render.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_render.cpp
index a41882e6b5..06b61a6e80 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_render.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_render.cpp
@@ -1,1281 +1,1491 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_render.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_safe_arithmetic.h"
#include "dng_utils.h"
/*****************************************************************************/
+dng_function_zero_offset::dng_function_zero_offset (real64 zeroOffset)
+
+ : fZeroOffset (zeroOffset)
+
+ , fScale (1.0 / (1.0 - zeroOffset))
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+real64 dng_function_zero_offset::Evaluate (real64 x) const
+ {
+
+ return Pin_real64 (0.0, (x - fZeroOffset) * fScale, 1.0);
+
+ }
+
+/*****************************************************************************/
+
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 quadratic parameters that match this darking at the crossover
+
+ // 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_image *fSrcMask;
+
const dng_negative &fNegative;
-
+
const dng_render &fParams;
-
+
dng_point fSrcOffset;
-
+
+ dng_1d_table fZeroOffsetRamp;
+
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_memory_block> fTempBuffer [kMaxMPThreads];
+ 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];
+
+ AutoPtr<dng_memory_block> fMaskBuffer [kMaxMPThreads];
+
public:
-
+
dng_render_task (const dng_image &srcImage,
+ const dng_image *srcMask,
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_rect &dstArea,
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,
+ const dng_image *srcMask,
dng_image &dstImage,
const dng_negative &negative,
const dng_render &params,
const dng_point &srcOffset)
-
- : dng_filter_task (srcImage,
+
+ : dng_filter_task ("dng_render_task",
+ srcImage,
dstImage)
+ , fSrcMask (srcMask )
, fNegative (negative )
, fParams (params )
, fSrcOffset (srcOffset)
+ , fZeroOffsetRamp ()
+
, 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_rect &dstArea,
const dng_point &tileSize,
dng_memory_allocator *allocator,
dng_abort_sniffer *sniffer)
{
-
+
dng_filter_task::Start (threadCount,
+ dstArea,
tileSize,
allocator,
sniffer);
-
+
+ // Compute zero offset ramp, if any.
+
+ if (fNegative.Stage3BlackLevel ())
+ {
+
+ dng_function_zero_offset offsetFunction (fNegative.Stage3BlackLevelNormalized ());
+
+ fZeroOffsetRamp.Initialize (*allocator, offsetFunction);
+
+ }
+
// Compute camera space to linear ProPhoto RGB parameters.
-
+
+ dng_camera_profile_id profileID; // Default profile ID.
+
if (!fNegative.IsMonochrome ())
{
-
- dng_camera_profile_id profileID; // Default profile ID.
-
+
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.BaselineExposure () -
+ 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 compensation to perform
+
+ // 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 * sizeof (real32) * 3;
-
+
+ uint32 tempBufferSize = 0;
+
+ if (!SafeUint32Mult (tileSize.h, (uint32) sizeof (real32), &tempBufferSize) ||
+ !SafeUint32Mult (tempBufferSize, 3, &tempBufferSize))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
{
-
+
fTempBuffer [threadIndex] . Reset (allocator->Allocate (tempBufferSize));
-
+
}
+
+ // Allocate mask buffer to hold one tile of mask data, if needed.
+
+ if (fSrcMask)
+ {
+
+ uint32 maskBufferSize = 0;
+
+ if (!SafeUint32Mult (tileSize.h, tileSize.v, &maskBufferSize) ||
+ !SafeUint32Mult (maskBufferSize, (uint32) sizeof (real32), &maskBufferSize))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
+ for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
+ {
+
+ fMaskBuffer [threadIndex] . Reset (allocator->Allocate (maskBufferSize));
+
+ }
+
+ }
}
-
+
/*****************************************************************************/
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;
+
+ dng_pixel_buffer maskBuffer;
+
+ if (fSrcMask)
+ {
+
+ maskBuffer.fArea = srcArea;
+ maskBuffer.fPlane = 0;
+ maskBuffer.fPlanes = 1;
+ maskBuffer.fRowStep = srcArea.W ();
+ maskBuffer.fColStep = 1;
+ maskBuffer.fPlaneStep = 0;
+ maskBuffer.fPixelType = ttFloat;
+ maskBuffer.fPixelSize = sizeof (real32);
+ maskBuffer.fData = fMaskBuffer [threadIndex]->Buffer_real32 ();
+ maskBuffer.fDirty = true;
+
+ fSrcMask->Get (maskBuffer);
+
+ }
for (int32 srcRow = srcArea.t; srcRow < srcArea.b; srcRow++)
{
-
+
+ if (fNegative.Stage3BlackLevel ())
+ {
+
+ for (uint32 plane = 0; plane < fSrcPlanes; plane++)
+ {
+
+ real32 *sPtr = (real32 *)
+ srcBuffer.DirtyPixel (srcRow,
+ srcArea.l,
+ plane);
+
+ DoBaseline1DTable (sPtr,
+ sPtr,
+ srcCols,
+ fZeroOffsetRamp);
+
+ }
+
+ }
+
// 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 * sizeof (real32));
- DoCopyBytes (sPtrA, tPtrG, srcCols * sizeof (real32));
- DoCopyBytes (sPtrA, tPtrB, srcCols * sizeof (real32));
-
+
+ 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 ());
-
+ *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 Hue/Sat map, if any.
-
+
+ // Apply look table, if any.
+
if (fLookTable.Get ())
{
-
+
DoBaselineHueSatMap (tPtrR,
tPtrG,
tPtrB,
tPtrR,
tPtrG,
tPtrB,
srcCols,
- *fLookTable.Get ());
-
+ *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);
-
+
}
-
+
+ if (fSrcMask)
+ {
+
+ const real32 *mPtr = maskBuffer.ConstPixel_real32 (srcRow,
+ srcArea.l,
+ 0);
+
+ for (uint32 dstPlane = 0; dstPlane < fDstPlanes; dstPlane++)
+ {
+
+ real32 *dPtr = dstBuffer.DirtyPixel_real32 (dstRow,
+ dstArea.l,
+ dstPlane);
+
+ for (uint32 col = 0; col < srcCols; col++)
+ {
+
+ // White Matte
+
+ dPtr [col] = 1.0f - (1.0f - dPtr [col]) * mPtr [col];
+
+ }
+
+ }
+
+ }
+
}
-
+
}
-
+
/*****************************************************************************/
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-scence referred data.
-
+
+ // 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 ();
-
+
+ const dng_image *srcMask = fNegative.TransparencyMask ();
+
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;
-
+
+ AutoPtr<dng_image> tempMask;
+
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 ());
-
+
+ if (srcMask != NULL)
+ {
+
+ tempMask.Reset (fHost.Make_dng_image (dstSize,
+ srcMask->Planes (),
+ srcMask->PixelType ()));
+
+ ResampleImage (fHost,
+ *srcMask,
+ *tempMask.Get (),
+ srcBounds,
+ tempMask->Bounds (),
+ dng_resample_bicubic::Get ());
+
+ srcMask = tempMask.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,
+ srcMask,
*dstImage.Get (),
fNegative,
*this,
srcBounds.TL ());
-
+
fHost.PerformAreaTask (task,
dstImage->Bounds ());
-
+
return dstImage.Release ();
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_render.h b/core/libs/dngwriter/extra/dng_sdk/dng_render.h
index e0f09ed85a..57180b2d94 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_render.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_render.h
@@ -1,310 +1,321 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_render.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_uncopyable.h"
#include "dng_xy_coord.h"
/******************************************************************************/
-/// \brief Curve for pre-exposure-compensation adjustment based on noise floor, shadows, and highlight level.
+/// \brief Curve for removing zero offset from stage3 image.
+
+class dng_function_zero_offset: public dng_1d_function
+ {
+
+ public:
+
+ real64 fZeroOffset;
+
+ real64 fScale;
+
+ public:
+
+ dng_function_zero_offset (real64 zeroOffset);
+
+ virtual real64 Evaluate (real64 x) const;
+
+ };
+
+/******************************************************************************/
+
+/// \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; // Quadratic scale.
-
+
+ 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 quadratic for roll-off.
+/// \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
+class dng_render: private dng_uncopyable
{
-
+
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/core/libs/dngwriter/extra/dng_sdk/dng_resample.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_resample.cpp
index cd4b90576e..5d7aead7ae 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_resample.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_resample.cpp
@@ -1,781 +1,841 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_resample.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_safe_arithmetic.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;
-
+
+ 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 = 0;
+ uint32 bufferSize = 0;
- uint32 dstEntries = RoundUp8 (dstCount);
+ if (!RoundUpUint32ToMultiple (dstCount, 8, &dstEntries) ||
+ !SafeUint32Mult (dstEntries, sizeof (int32), &bufferSize))
+ {
- fCoords.Reset (allocator.Allocate (dstEntries * sizeof (int32)));
+ ThrowOverflow ("Arithmetic overflow computing size for coordinate "
+ "buffer");
- int32 *coords = fCoords->Buffer_int32 ();
+ }
+ fCoords.Reset (allocator.Allocate (bufferSize));
+
+ 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);
-
+
+ if (!RoundUpUint32ToMultiple (width, 8, &fWeightStep))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing fWeightStep");
+
+ }
+
// Allocate and zero weight tables.
-
- fWeights32.Reset (allocator.Allocate (fWeightStep *
- kResampleSubsampleCount *
- sizeof (real32)));
-
+
+ uint32 bufferSize = 0;
+
+ if (!SafeUint32Mult (fWeightStep, kResampleSubsampleCount, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, (uint32) sizeof (real32), &bufferSize))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
+ fWeights32.Reset (allocator.Allocate (bufferSize));
+
DoZeroBytes (fWeights32->Buffer (),
fWeights32->LogicalSize ());
-
- fWeights16.Reset (allocator.Allocate (fWeightStep *
- kResampleSubsampleCount *
- sizeof (int16)));
-
+
+ if (!SafeUint32Mult (fWeightStep, kResampleSubsampleCount, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, (uint32) sizeof (int16), &bufferSize))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
+ fWeights16.Reset (allocator.Allocate (bufferSize));
+
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;
-
+
+ int32 k = (int32) j - (int32) 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.
+
+ uint32 width = 0;
+ uint32 widthSqr = 0;
+ uint32 step = 0;
+
+ if (!SafeUint32Mult (fRadius, 2, &width) ||
+ !SafeUint32Mult (width, width, &widthSqr) ||
+ !RoundUpUint32ToMultiple (widthSqr, 8, &step) ||
+ !SafeUint32Mult (step, kResampleSubsampleCount2D, &fRowStep))
+ {
- const uint32 width = fRadius * 2;
- const uint32 widthSqr = width * width;
-
- const uint32 step = RoundUp8 (width * width);
+ ThrowOverflow ("Arithmetic overflow computing row step.");
+
+ }
- fRowStep = step * kResampleSubsampleCount2D;
fColStep = step;
-
+
// Allocate and zero weight tables.
+
+ uint32 bufferSize = 0;
- fWeights32.Reset (allocator.Allocate (step *
- kResampleSubsampleCount2D *
- kResampleSubsampleCount2D *
- sizeof (real32)));
-
+ if (!SafeUint32Mult (step, kResampleSubsampleCount2D, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, kResampleSubsampleCount2D, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, (uint32) sizeof (real32), &bufferSize))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
+ fWeights32.Reset (allocator.Allocate (bufferSize));
+
DoZeroBytes (fWeights32->Buffer (),
fWeights32->LogicalSize ());
+
+ if (!SafeUint32Mult (step, kResampleSubsampleCount2D, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, kResampleSubsampleCount2D, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, (uint32) sizeof (int16), &bufferSize))
+ {
- fWeights16.Reset (allocator.Allocate (step *
- kResampleSubsampleCount2D *
- kResampleSubsampleCount2D *
- sizeof (int16)));
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+ }
+
+ fWeights16.Reset (allocator.Allocate (bufferSize));
+
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,
+
+ 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;
+
+ int32 yInt = ((int32) i) - (int32) fRadius + 1;
real64 yPos = yInt - yFract;
for (uint32 j = 0; j < width; j++)
{
-
- int32 xInt = ((int32) j) - fRadius + 1;
+
+ int32 xInt = ((int32) j) - (int32) 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,
+
+ 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_rect &dstArea,
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,
+
+ : dng_filter_task ("dng_resample_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_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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_rect &dstArea,
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 tile.
-
+
+ // 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 = 0;
- uint32 tempBufferSize = RoundUp8 (fSrcTileSize.h) * sizeof (real32);
-
+ if (!RoundUpUint32ToMultiple (fSrcTileSize.h, 8, &tempBufferSize) ||
+ !SafeUint32Mult (tempBufferSize,
+ static_cast<uint32> (sizeof (real32)),
+ &tempBufferSize))
+ {
+
+ ThrowOverflow ("Arithmetic overflow computing buffer size.");
+
+ }
+
for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
{
-
+
fTempBuffer [threadIndex] . Reset (allocator->Allocate (tempBufferSize));
-
+
}
-
+
// Allocate the pixel buffers.
dng_filter_task::Start (threadCount,
+ dstArea,
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);
-
+
+ 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);
-
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_resample.h b/core/libs/dngwriter/extra/dng_sdk/dng_resample.h
index c1b6f6a207..b61a2ed43e 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_resample.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_resample.h
@@ -1,261 +1,268 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_resample.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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);
}
-
- const int32 Pixel (int32 index) const
+
+ 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");
-
+
+ if (fract >= kResampleSubsampleCount)
+ {
+
+ ThrowBadFormat ();
+
+ }
+
return fWeights32->Buffer_real32 () + fract * fWeightStep;
-
+
}
const int16 *Weights16 (uint32 fract) const
{
-
+
DNG_ASSERT (fWeights16->Buffer (), "Weights16 is NULL");
-
+
+ if (fract >= kResampleSubsampleCount)
+ {
+
+ ThrowBadFormat ();
+
+ }
+
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/core/libs/dngwriter/extra/dng_sdk/dng_safe_arithmetic.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_safe_arithmetic.cpp
new file mode 100644
index 0000000000..7d12d7a9c7
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_safe_arithmetic.cpp
@@ -0,0 +1,264 @@
+/*****************************************************************************/
+// Copyright 2015-2019 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 "dng_safe_arithmetic.h"
+
+#include <limits>
+
+#include "dng_exceptions.h"
+
+// Implementation of safe integer arithmetic follows guidelines from
+// https://www.securecoding.cert.org/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
+// and
+// https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
+
+namespace {
+
+// Template functions for safe arithmetic. These functions are not exposed in
+// the header for the time being to avoid having to add checks for the various
+// constraints on the template argument (e.g. that it is integral and possibly
+// signed or unsigned only). This should be done using a static_assert(), but
+// we want to be portable to pre-C++11 compilers.
+
+// Returns the result of adding arg1 and arg2 if it will fit in a T (where T is
+// a signed or unsigned integer type). Otherwise, throws a dng_exception with
+// error code dng_error_unknown.
+template <class T>
+T SafeAdd(T arg1, T arg2) {
+ // The condition is reformulated relative to the version on
+ // www.securecoding.cert.org to check for valid instead of invalid cases. It
+ // seems safer to enumerate the valid cases (and potentially miss one) than
+ // enumerate the invalid cases.
+ // If T is an unsigned type, the second half of the condition always evaluates
+ // to false and will presumably be compiled out by the compiler.
+ if ((arg1 >= 0 && arg2 <= std::numeric_limits<T>::max() - arg1) ||
+ (arg1 < 0 && arg2 >= std::numeric_limits<T>::min() - arg1)) {
+ return arg1 + arg2;
+ } else {
+ ThrowOverflow ("Arithmetic overflow in SafeAdd");
+
+ // Dummy return statement.
+ return 0;
+ }
+}
+
+// Returns the result of multiplying arg1 and arg2 if it will fit in a T (where
+// T is an unsigned integer type). Otherwise, throws a dng_exception with error
+// code dng_error_unknown.
+template <class T>
+T SafeUnsignedMult(T arg1, T arg2) {
+ if (arg1 == 0 || arg2 <= std::numeric_limits<T>::max() / arg1) {
+ return arg1 * arg2;
+ } else {
+ ThrowOverflow ("Arithmetic overflow in SafeUnsignedMult");
+
+ // Dummy return statement.
+ return 0;
+ }
+}
+
+} // namespace
+
+bool SafeInt32Add(int32 arg1, int32 arg2, int32 *result) {
+ try {
+ *result = SafeInt32Add(arg1, arg2);
+ return true;
+ } catch (const dng_exception &) {
+ return false;
+ }
+}
+
+int32 SafeInt32Add(int32 arg1, int32 arg2) {
+ return SafeAdd<int32>(arg1, arg2);
+}
+
+int64 SafeInt64Add(int64 arg1, int64 arg2) {
+ return SafeAdd<int64>(arg1, arg2);
+}
+
+bool SafeUint32Add(uint32 arg1, uint32 arg2,
+ uint32 *result) {
+ try {
+ *result = SafeUint32Add(arg1, arg2);
+ return true;
+ } catch (const dng_exception &) {
+ return false;
+ }
+}
+
+uint32 SafeUint32Add(uint32 arg1, uint32 arg2) {
+ return SafeAdd<uint32>(arg1, arg2);
+}
+
+bool SafeInt32Sub(int32 arg1, int32 arg2, int32 *result) {
+ if ((arg2 >= 0 && arg1 >= std::numeric_limits<int32_t>::min() + arg2) ||
+ (arg2 < 0 && arg1 <= std::numeric_limits<int32_t>::max() + arg2)) {
+ *result = arg1 - arg2;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int32 SafeInt32Sub(int32 arg1, int32 arg2) {
+ int32 result = 0;
+
+ if (!SafeInt32Sub(arg1, arg2, &result)) {
+ ThrowOverflow ("Arithmetic overflow in SafeInt32Sub");
+ }
+
+ return result;
+}
+
+bool SafeUint32Mult(uint32 arg1, uint32 arg2,
+ uint32 *result) {
+ try {
+ *result = SafeUint32Mult(arg1, arg2);
+ return true;
+ } catch (const dng_exception &) {
+ return false;
+ }
+}
+
+bool SafeUint32Mult(uint32 arg1, uint32 arg2, uint32 arg3,
+ uint32 *result) {
+ try {
+ *result = SafeUint32Mult(arg1, arg2, arg3);
+ return true;
+ } catch (const dng_exception &) {
+ return false;
+ }
+}
+
+bool SafeUint32Mult(uint32 arg1, uint32 arg2, uint32 arg3,
+ uint32 arg4, uint32 *result) {
+ try {
+ *result = SafeUint32Mult(arg1, arg2, arg3, arg4);
+ return true;
+ } catch (const dng_exception &) {
+ return false;
+ }
+}
+
+uint32 SafeUint32Mult(uint32 arg1, uint32 arg2) {
+ return SafeUnsignedMult<uint32>(arg1, arg2);
+}
+
+uint32 SafeUint32Mult(uint32 arg1, uint32 arg2,
+ uint32 arg3) {
+ return SafeUint32Mult(SafeUint32Mult(arg1, arg2), arg3);
+}
+
+uint32 SafeUint32Mult(uint32 arg1, uint32 arg2,
+ uint32 arg3, uint32 arg4) {
+ return SafeUint32Mult(SafeUint32Mult(arg1, arg2, arg3), arg4);
+}
+
+std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2) {
+ return SafeUnsignedMult<std::size_t>(arg1, arg2);
+}
+
+int64 SafeInt64Mult(int64 arg1, int64 arg2) {
+ bool overflow = true;
+
+ if (arg1 > 0) {
+ if (arg2 > 0) {
+ overflow = (arg1 > INT64_MAX / arg2);
+ } else {
+ overflow = (arg2 < INT64_MIN / arg1);
+ }
+ } else {
+ if (arg2 > 0) {
+ overflow = (arg1 < INT64_MIN / arg2);
+ } else {
+ overflow = (arg1 != 0 && arg2 < INT64_MAX / arg1);
+ }
+ }
+
+ if (overflow) {
+ ThrowOverflow ("Arithmetic overflow");
+
+ // Dummy return.
+ return 0;
+ } else {
+ return arg1 * arg2;
+ }
+}
+
+uint32 SafeUint32DivideUp(uint32 arg1, uint32 arg2) {
+ // It might seem more intuitive to implement this function simply as
+ //
+ // return arg2 == 0 ? 0 : (arg1 + arg2 - 1) / arg2;
+ //
+ // but the expression "arg1 + arg2" can wrap around.
+
+ if (arg2 == 0) {
+ ThrowProgramError("Division by zero");
+
+ // Dummy return to avoid compiler error about missing return statement.
+ return 0;
+ } else if (arg1 == 0) {
+ // If arg1 is zero, return zero to avoid wraparound in the expression
+ // "arg1 - 1" below.
+ return 0;
+ } else {
+ return (arg1 - 1) / arg2 + 1;
+ }
+}
+
+bool RoundUpUint32ToMultiple(uint32 val, uint32 multiple_of,
+ uint32 *result) {
+ if (multiple_of == 0) {
+ return false;
+ }
+
+ const uint32 remainder = val % multiple_of;
+ if (remainder == 0) {
+ *result = val;
+ return true;
+ } else {
+ return SafeUint32Add(val, multiple_of - remainder, result);
+ }
+}
+
+bool ConvertUint32ToInt32(uint32 val, int32 *result) {
+ const uint32 kInt32MaxAsUint32 =
+ static_cast<uint32>(std::numeric_limits<int32>::max());
+
+ if (val <= kInt32MaxAsUint32) {
+ *result = static_cast<int32>(val);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*****************************************************************************/
+
+dng_safe_uint32::dng_safe_uint32 (const dng_safe_int32 &x)
+ {
+
+ if (x.Get () < 0)
+ {
+ ThrowOverflow ("Overflow in dng_safe_uint32");
+ }
+
+ fValue = static_cast<uint32> (x.Get ());
+
+ }
+
+/*****************************************************************************/
+
+dng_safe_int32::dng_safe_int32 (const dng_safe_uint32 &x)
+ {
+
+ Set_uint32 (x.Get ());
+
+ }
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_safe_arithmetic.h b/core/libs/dngwriter/extra/dng_sdk/dng_safe_arithmetic.h
new file mode 100644
index 0000000000..8a0a019d1b
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_safe_arithmetic.h
@@ -0,0 +1,336 @@
+/*****************************************************************************/
+// Copyright 2015-2019 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.
+/*****************************************************************************/
+
+/*
+ *
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+// Functions for safe arithmetic (guarded against overflow) on integer types.
+
+#ifndef __dng_safe_arithmetic__
+#define __dng_safe_arithmetic__
+
+#include <cstddef>
+//#include <cstdint>
+#include <limits>
+
+#include "dng_exceptions.h"
+#include "dng_types.h"
+
+// If the result of adding arg1 and arg2 will fit in an int32_t (without
+// under-/overflow), stores this result in *result and returns true. Otherwise,
+// returns false and leaves *result unchanged.
+bool SafeInt32Add(int32 arg1, int32 arg2, int32 *result);
+
+// Returns the result of adding arg1 and arg2 if it will fit in the result type
+// (without under-/overflow). Otherwise, throws a dng_exception with error code
+// dng_error_unknown.
+int32 SafeInt32Add(int32 arg1, int32 arg2);
+int64 SafeInt64Add(int64 arg1, int64 arg2);
+
+// If the result of adding arg1 and arg2 will fit in a uint32_t (without
+// wraparound), stores this result in *result and returns true. Otherwise,
+// returns false and leaves *result unchanged.
+bool SafeUint32Add(uint32 arg1, uint32 arg2,
+ uint32 *result);
+
+// Returns the result of adding arg1 and arg2 if it will fit in a uint32_t
+// (without wraparound). Otherwise, throws a dng_exception with error code
+// dng_error_unknown.
+uint32 SafeUint32Add(uint32 arg1, uint32 arg2);
+
+// If the subtraction of arg2 from arg1 will not result in an int32_t under- or
+// overflow, stores this result in *result and returns true. Otherwise,
+// returns false and leaves *result unchanged.
+bool SafeInt32Sub(int32 arg1, int32 arg2, int32 *result);
+
+// Returns the result of subtracting arg2 from arg1 if this operation will not
+// result in an int32_t under- or overflow. Otherwise, throws a dng_exception
+// with error code dng_error_unknown.
+int32 SafeInt32Sub(int32 arg1, int32 arg2);
+
+// If the result of multiplying arg1, ..., argn will fit in a uint32_t (without
+// wraparound), stores this result in *result and returns true. Otherwise,
+// returns false and leaves *result unchanged.
+bool SafeUint32Mult(uint32 arg1, uint32 arg2,
+ uint32 *result);
+bool SafeUint32Mult(uint32 arg1, uint32 arg2, uint32 arg3,
+ uint32 *result);
+bool SafeUint32Mult(uint32 arg1, uint32 arg2, uint32 arg3,
+ uint32 arg4, uint32 *result);
+
+// Returns the result of multiplying arg1, ..., argn if it will fit in a
+// uint32_t (without wraparound). Otherwise, throws a dng_exception with error
+// code dng_error_unknown.
+uint32 SafeUint32Mult(uint32 arg1, uint32 arg2);
+uint32 SafeUint32Mult(uint32 arg1, uint32 arg2,
+ uint32 arg3);
+uint32 SafeUint32Mult(uint32 arg1, uint32 arg2,
+ uint32 arg3, uint32 arg4);
+
+// Returns the result of multiplying arg1 and arg2 if it will fit in a size_t
+// (without overflow). Otherwise, throws a dng_exception with error code
+// dng_error_unknown.
+std::size_t SafeSizetMult(std::size_t arg1, std::size_t arg2);
+
+// Returns the result of multiplying arg1 and arg2 if it will fit in an int64_t
+// (without overflow). Otherwise, throws a dng_exception with error code
+// dng_error_unknown.
+int64 SafeInt64Mult(int64 arg1, int64 arg2);
+
+// Returns the result of dividing arg1 by arg2; if the result is not an integer,
+// rounds up to the next integer. If arg2 is zero, throws a dng_exception with
+// error code dng_error_unknown.
+// The function is safe against wraparound and will return the correct result
+// for all combinations of arg1 and arg2.
+uint32 SafeUint32DivideUp(uint32 arg1, uint32 arg2);
+
+// Finds the smallest integer multiple of 'multiple_of' that is greater than or
+// equal to 'val'. If this value will fit in a uint32_t, stores it in *result
+// and returns true. Otherwise, or if 'multiple_of' is zero, returns false and
+// leaves *result unchanged.
+bool RoundUpUint32ToMultiple(uint32 val, uint32 multiple_of,
+ uint32 *result);
+
+// If the uint32_t value val will fit in a int32_t, converts it to a int32_t and
+// stores it in *result. Otherwise, returns false and leaves *result unchanged.
+bool ConvertUint32ToInt32(uint32 val, int32 *result);
+
+// Converts a value of the unsigned integer type TSrc to the unsigned integer
+// type TDest. If the value in 'src' cannot be converted to the type TDest
+// without truncation, throws a dng_exception with error code dng_error_unknown.
+//
+// Note: Though this function is typically used where TDest is a narrower type
+// than TSrc, it is designed to work also if TDest is wider than from TSrc or
+// identical to TSrc. This is useful in situations where the width of the types
+// involved can change depending on the architecture -- for example, the
+// conversion from size_t to uint32_t may either be narrowing, identical or even
+// widening (though the latter admittedly happens only on architectures that
+// aren't relevant to us).
+template <class TSrc, class TDest>
+static void ConvertUnsigned(TSrc src, TDest *dest) {
+#if 0
+// sub-optimal run-time implementation pre-C++11
+ if (!(std::numeric_limits<TSrc>::is_integer &&
+ !std::numeric_limits<TSrc>::is_signed &&
+ std::numeric_limits<TDest>::is_integer &&
+ !std::numeric_limits<TDest>::is_signed))
+ {
+ ThrowProgramError ("TSrc and TDest must be unsigned integer types");
+ }
+#else
+ // preferred compile-time implementation; requires C++11
+ static_assert(std::numeric_limits<TSrc>::is_integer &&
+ !std::numeric_limits<TSrc>::is_signed &&
+ std::numeric_limits<TDest>::is_integer &&
+ !std::numeric_limits<TDest>::is_signed,
+ "TSrc and TDest must be unsigned integer types");
+#endif
+
+ const TDest converted = static_cast<TDest>(src);
+
+ // Convert back to TSrc to check whether truncation occurred in the
+ // conversion to TDest.
+ if (static_cast<TSrc>(converted) != src) {
+ ThrowProgramError("Overflow in unsigned integer conversion");
+ }
+
+ *dest = converted;
+}
+
+/*****************************************************************************/
+
+class dng_safe_int32;
+class dng_safe_uint32;
+
+/*****************************************************************************/
+
+#define CHECK_SAFE_UINT32 \
+ static_assert (std::numeric_limits<T>::is_integer && \
+ !std::numeric_limits<T>::is_signed && \
+ (sizeof (T) == 4), \
+ "src must be unsigned 32-bit integer")
+
+class dng_safe_uint32
+ {
+
+ private:
+
+ uint32 fValue;
+
+ public:
+
+ template<typename T>
+ dng_safe_uint32 (T x)
+ {
+ CHECK_SAFE_UINT32;
+ fValue = x;
+ }
+
+ explicit dng_safe_uint32 (const dng_safe_int32 &x);
+
+ inline uint32 Get () const
+ {
+ return fValue;
+ }
+
+ // Compound assignment operators.
+
+ dng_safe_uint32 & operator+= (const dng_safe_uint32 &x)
+ {
+ fValue = SafeUint32Add (fValue, x.fValue);
+ return *this;
+ }
+
+ template<typename T>
+ dng_safe_uint32 & operator+= (T x)
+ {
+ CHECK_SAFE_UINT32;
+ fValue = SafeUint32Add (fValue, x);
+ return *this;
+ }
+
+ dng_safe_uint32 & operator*= (const dng_safe_uint32 &x)
+ {
+ fValue = SafeUint32Mult (fValue, x.fValue);
+ return *this;
+ }
+
+ template<typename T>
+ dng_safe_uint32 & operator*= (T x)
+ {
+ CHECK_SAFE_UINT32;
+ fValue = SafeUint32Mult (fValue, x);
+ return *this;
+ }
+
+ // Binary operators.
+
+ const dng_safe_uint32 operator+ (const dng_safe_uint32 &x) const
+ {
+ return dng_safe_uint32 (*this) += x;
+ }
+
+ template<typename T>
+ const dng_safe_uint32 operator+ (T x) const
+ {
+ CHECK_SAFE_UINT32;
+ return dng_safe_uint32 (*this) += x;
+ }
+
+ const dng_safe_uint32 operator* (const dng_safe_uint32 &x) const
+ {
+ return dng_safe_uint32 (*this) *= x;
+ }
+
+ template<typename T>
+ const dng_safe_uint32 operator* (T x) const
+ {
+ CHECK_SAFE_UINT32;
+ return dng_safe_uint32 (*this) *= x;
+ }
+
+ };
+
+#undef CHECK_SAFE_UINT32
+
+/*****************************************************************************/
+
+#define CHECK_SAFE_INT32 \
+ static_assert (std::numeric_limits<T>::is_integer && \
+ std::numeric_limits<T>::is_signed && \
+ (sizeof (T) == 4), \
+ "src must be signed 32-bit integer")
+
+class dng_safe_int32
+ {
+
+ private:
+
+ int32 fValue;
+
+ public:
+
+ template<typename T>
+ dng_safe_int32 (T x)
+ {
+ CHECK_SAFE_INT32;
+ fValue = x;
+ }
+
+ // Construct int32 from uint32. Throws exception dng_error_overflow if
+ // source uint32 cannot be represented as int32.
+
+ explicit dng_safe_int32 (const dng_safe_uint32 &x);
+
+ inline int32 Get () const
+ {
+ return fValue;
+ }
+
+ // Assign from uint32. Throws exception dng_error_overflow if source
+ // uint32 cannot be represented as int32.
+
+ void Set_uint32 (uint32 x)
+ {
+ if (!ConvertUint32ToInt32 (x, &fValue))
+ {
+ ThrowProgramError ("Overflow in Set_uint32");
+ }
+ }
+
+ // Compound assignment operators.
+
+ dng_safe_int32 & operator+= (const dng_safe_int32 &x)
+ {
+ fValue = SafeInt32Add (fValue, x.fValue);
+ return *this;
+ }
+
+ template<typename T>
+ dng_safe_int32 & operator+= (T x)
+ {
+ CHECK_SAFE_INT32;
+ fValue = SafeInt32Add (fValue, x);
+ return *this;
+ }
+
+ dng_safe_int32 & operator-= (const dng_safe_int32 &x)
+ {
+ fValue = SafeInt32Sub (fValue, x.fValue);
+ return *this;
+ }
+
+ template<typename T>
+ dng_safe_int32 & operator-= (T x)
+ {
+ CHECK_SAFE_INT32;
+ fValue = SafeInt32Sub (fValue, x);
+ return *this;
+ }
+
+ };
+
+#undef CHECK_SAFE_INT32
+
+/*****************************************************************************/
+
+#endif // __dng_safe_arithmetic__
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_sdk_limits.h b/core/libs/dngwriter/extra/dng_sdk/dng_sdk_limits.h
index ee14362c43..1d6d5c773f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_sdk_limits.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_sdk_limits.h
@@ -1,74 +1,81 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_sdk_limits.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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;
+/// The maximum number of tone curve points supported.
+
+const uint32 kMaxToneCurvePoints = 8192;
+
/// Maximum number of MP threads for dng_area_task operations.
+#if qDNG64Bit
+const uint32 kMaxMPThreads = 128; // EP! Needs much larger max!
+#else
const uint32 kMaxMPThreads = 8;
+#endif
+
+/// Maximum supported value of Stage3BlackLevelNormalized.
+
+const real64 kMaxStage3BlackLevelNormalized = 0.2;
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_shared.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_shared.cpp
index 01451155b7..b525b93783 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_shared.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_shared.cpp
@@ -1,2927 +1,3366 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 Adobe Systems Incorporated
// All Rights Reserved.
//
-// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// 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_3/dng_sdk/source/dng_shared.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_shared.h"
#include "dng_camera_profile.h"
#include "dng_exceptions.h"
#include "dng_globals.h"
+#include "dng_memory.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)
+ , fHueSatDeltas1Count (0)
, fHueSatDeltas2Offset (0)
- , fHueSatDeltas2Count (0)
+ , fHueSatDeltas2Count (0)
+ , fHueSatMapEncoding (encoding_Linear)
+
, fLookTableHues (0)
, fLookTableSats (0)
, fLookTableVals (0)
-
+
, fLookTableOffset (0)
- , fLookTableCount (0)
+ , fLookTableCount (0)
+
+ , fLookTableEncoding (encoding_Linear)
- , fToneCurveOffset (0)
- , fToneCurveCount (0)
+ , fBaselineExposureOffset (0, 100)
+
+ , fDefaultBlackRender (defaultBlackRender_Auto)
+ , fToneCurveOffset (0)
+ , fToneCurveCount (0)
+
, fUniqueCameraModel ()
{
-
+
}
-
+
/*****************************************************************************/
dng_camera_profile_info::~dng_camera_profile_info ()
{
-
+
}
-
+
/*****************************************************************************/
+DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
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,
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,
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,
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 (fProfileSats == 0)
+ return false;
+ dng_safe_uint32 hueCount (fProfileHues);
+ dng_safe_uint32 valCount (fProfileVals);
+
+ bool skipSat0 = (tagCount == (hueCount *
+ (fProfileSats - 1) *
+ (valCount * 3u)).Get ());
+
if (!skipSat0)
{
- if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues *
- fProfileSats *
- fProfileVals * 3))
+ dng_safe_uint32 expected = hueCount * valCount * fProfileSats * 3u;
+
+ if (!CheckTagCount (parentCode,
+ tagCode,
+ tagCount,
+ expected.Get ()))
+ {
return false;
-
+ }
+
}
-
+
fBigEndian = stream.BigEndian ();
-
+
fHueSatDeltas1Offset = tagOffset;
- fHueSatDeltas1Count = tagCount;
-
+ 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;
+
+ if (fProfileSats == 0)
+ return false;
- bool skipSat0 = (tagCount == fProfileHues *
- (fProfileSats - 1) *
- fProfileVals * 3);
-
+ dng_safe_uint32 hueCount (fProfileHues);
+ dng_safe_uint32 valCount (fProfileVals);
+
+ bool skipSat0 = (tagCount == (hueCount *
+ (fProfileSats - 1) *
+ (valCount * 3u)).Get ());
+
if (!skipSat0)
{
-
- if (!CheckTagCount (parentCode, tagCode, tagCount, fProfileHues *
- fProfileSats *
- fProfileVals * 3))
+
+ dng_safe_uint32 expected = hueCount * valCount * fProfileSats * 3u;
+
+ if (!CheckTagCount (parentCode,
+ tagCode,
+ tagCount,
+ expected.Get ()))
+ {
return false;
-
+ }
+
}
-
+
fBigEndian = stream.BigEndian ();
-
+
fHueSatDeltas2Offset = tagOffset;
- fHueSatDeltas2Count = tagCount;
-
+ 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;
+
+ if (fLookTableSats == 0)
+ return false;
- bool skipSat0 = (tagCount == fLookTableHues *
- (fLookTableSats - 1) *
- fLookTableVals * 3);
-
+ dng_safe_uint32 hueCount (fLookTableHues);
+ dng_safe_uint32 valCount (fLookTableVals);
+
+ bool skipSat0 = (tagCount == (hueCount *
+ (fLookTableSats - 1) *
+ valCount * 3u).Get ());
+
if (!skipSat0)
{
-
- if (!CheckTagCount (parentCode, tagCode, tagCount, fLookTableHues *
- fLookTableSats *
- fLookTableVals * 3))
+
+ dng_safe_uint32 expected = hueCount * valCount * fLookTableSats * 3u;
+
+ if (!CheckTagCount (parentCode,
+ tagCode,
+ tagCount,
+ expected.Get ()))
+ {
return false;
-
+ }
+
}
-
+
fBigEndian = stream.BigEndian ();
-
+
fLookTableOffset = tagOffset;
- fLookTableCount = tagCount;
-
+ fLookTableCount = tagCount;
+
#if qDNGValidate
if (gVerbose)
{
-
+
printf ("ProfileLookTableData:\n");
-
+
DumpHueSatMap (stream,
fLookTableHues,
fLookTableSats,
fLookTableVals,
skipSat0);
-
+
}
-
+
#endif
break;
-
+
}
- case tcProfileToneCurve:
+ case tcProfileLookTableEncoding:
{
- if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
- return false;
+ CheckTagType (parentCode, tagCode, tagType, ttLong);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fLookTableEncoding = stream.TagValue_uint32 (tagType);
- if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount))
- return false;
+ #if qDNGValidate
- if ((tagCount & 1) != 0)
+ if (gVerbose)
{
+
+ const char *encoding = NULL;
- #if qDNGValidate
-
+ switch (fLookTableEncoding)
{
- char message [256];
-
- sprintf (message,
- "%s %s has odd count (%u)",
- LookupParentCode (parentCode),
- LookupTagCode (parentCode, tagCode),
- (unsigned) tagCount);
+ case encoding_Linear:
+ encoding = "Linear";
+ break;
- ReportWarning (message);
+ case encoding_sRGB:
+ encoding = "sRGB";
+ break;
+ default:
+ encoding = "INVALID VALUE";
+
}
- #endif
-
- return false;
-
+ printf ("ProfileLookTableEncoding: %s\n", encoding);
+
}
- fBigEndian = stream.BigEndian ();
+ #endif
- fToneCurveOffset = tagOffset;
- fToneCurveCount = tagCount;
+ 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 ();
+
+ 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)
+
+ : fExifIFD (0)
+ , fGPSInfo (0)
, fInteroperabilityIFD (0)
- , fKodakDCRPrivateIFD (0)
- , fKodakKDCPrivateIFD (0)
-
+ , fKodakDCRPrivateIFD (0)
+ , fKodakKDCPrivateIFD (0)
+
, fXMPCount (0)
, fXMPOffset (0)
-
- , fIPTC_NAA_Count (0)
+
+ , fIPTC_NAA_Count (0)
, fIPTC_NAA_Offset (0)
-
- , fMakerNoteCount (0)
+
+ , fMakerNoteCount (0)
, fMakerNoteOffset (0)
, fMakerNoteSafety (0)
-
- , fDNGVersion (0)
+
+ , fDNGVersion (0)
, fDNGBackwardVersion (0)
-
- , fUniqueCameraModel ()
+
+ , fUniqueCameraModel ()
, fLocalizedCameraModel ()
-
+
, fCameraProfile ()
-
+
, fExtraCameraProfiles ()
-
+
, fCameraCalibration1 ()
, fCameraCalibration2 ()
-
- , fCameraCalibrationSignature ()
+
+ , fCameraCalibrationSignature ()
, fAnalogBalance ()
-
+
, fAsShotNeutral ()
-
+
, fAsShotWhiteXY ()
-
- , fBaselineExposure (0, 1)
- , fBaselineNoise (1, 1)
- , fNoiseReductionApplied (0, 0)
- , fBaselineSharpness (1, 1)
+
+ , fBaselineExposure (0, 1)
+ , fBaselineNoise (1, 1)
+ , fBaselineSharpness (1, 1)
, fLinearResponseLimit (1, 1)
- , fShadowScale (1, 1)
-
+ , fShadowScale (1, 1)
+
+ , fHasBaselineExposure (false)
+ , fHasShadowScale (false)
+
, fDNGPrivateDataCount (0)
, fDNGPrivateDataOffset (0)
-
- , fRawImageDigest ()
-
+
+ , fRawImageDigest ()
+ , fNewRawImageDigest ()
+
, fRawDataUniqueID ()
-
+
, fOriginalRawFileName ()
-
+
, fOriginalRawFileDataCount (0)
, fOriginalRawFileDataOffset (0)
-
+
, fOriginalRawFileDigest ()
-
- , fAsShotICCProfileCount (0)
+
+ , fAsShotICCProfileCount (0)
, fAsShotICCProfileOffset (0)
-
+
, fAsShotPreProfileMatrix ()
-
- , fCurrentICCProfileCount (0)
+
+ , fCurrentICCProfileCount (0)
, fCurrentICCProfileOffset (0)
-
+
, fCurrentPreProfileMatrix ()
-
+
, fColorimetricReference (crSceneReferred)
, fAsShotProfileName ()
- , fNoiseProfile ()
+ , fOriginalDefaultFinalSize ()
+ , fOriginalBestQualityFinalSize ()
+
+ , fOriginalDefaultCropSizeH ()
+ , fOriginalDefaultCropSizeV ()
- {
+ , fDepthFormat (depthFormatUnknown)
+ , fDepthNear (0, 0)
+ , fDepthFar (0, 0)
+ , fDepthUnits (depthUnitsUnknown)
+ , fDepthMeasureType (depthMeasureUnknown)
+ {
+
}
-
+
/*****************************************************************************/
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))
+ 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);
-
+
+ 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);
-
- fIPTC_NAA_Count = tagCount * TagTypeSize (tagType);
+
+ CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined);
+
+ fIPTC_NAA_Count = (dng_safe_uint32 (tagCount) * TagTypeSize (tagType)).Get ();
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,
+ 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,
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,
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 ());
-
+ 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", numPlanes);
-
- for (uint32 plane = 0; plane < numPlanes; plane++)
- {
-
- printf (" Noise function for plane %u: scale = %.8lf, offset = %.8lf\n",
- 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 ());
-
+ 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,
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;
+
+ 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;
+
+ 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 tcAsShotProfileName:
+
+ case tcOriginalDefaultCropSize:
{
-
- CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
-
- ParseStringTag (stream,
- parentCode,
- tagCode,
- tagCount,
- fAsShotProfileName,
- false,
- false);
-
+
+ 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 ("AsShotProfileName: ");
-
- DumpString (fAsShotProfileName);
-
- printf ("\n");
-
+
+ printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n",
+ fOriginalDefaultCropSizeH.As_real64 (),
+ fOriginalDefaultCropSizeV.As_real64 ());
+
}
-
+
#endif
-
+
break;
-
- }
-
+
+ }
+
+ case tcDepthFormat:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDepthFormat = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DepthFormat: %s\n",
+ LookupDepthFormat (fDepthFormat));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDepthNear:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDepthNear = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DepthNear: ");
+
+ if (fDepthNear == dng_urational (0, 0))
+ {
+ printf ("Unknown");
+ }
+ else if (fDepthNear.d == 0)
+ {
+ printf ("Infinity");
+ }
+ else
+ {
+ printf ("%0.2f", fDepthNear.As_real64 ());
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDepthFar:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttRational);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDepthFar = stream.TagValue_urational (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DepthFar: ");
+
+ if (fDepthFar == dng_urational (0, 0))
+ {
+ printf ("Unknown");
+ }
+ else if (fDepthFar.d == 0)
+ {
+ printf ("Infinity");
+ }
+ else
+ {
+ printf ("%0.2f", fDepthFar.As_real64 ());
+ }
+
+ printf ("\n");
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDepthUnits:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDepthUnits = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DepthUnits: %s\n",
+ LookupDepthUnits (fDepthUnits));
+
+ }
+
+ #endif
+
+ break;
+
+ }
+
+ case tcDepthMeasureType:
+ {
+
+ CheckTagType (parentCode, tagCode, tagType, ttShort);
+
+ CheckTagCount (parentCode, tagCode, tagCount, 1);
+
+ fDepthMeasureType = stream.TagValue_uint32 (tagType);
+
+ #if qDNGValidate
+
+ if (gVerbose)
+ {
+
+ printf ("DepthMeasureType: %s\n",
+ LookupDepthMeasureType (fDepthMeasureType));
+
+ }
+
+ #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)
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset)
{
-
+
switch (tagCode)
{
-
+
case tcMakerNote:
{
-
+
CheckTagType (parentCode, tagCode, tagType, ttUndefined);
-
- fMakerNoteCount = tagCount;
+
+ 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
+ // 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
- // compatibility.
+ // compatiblity.
if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA &&
- fCameraProfile.fCalibrationIlluminant2 == lsD65 &&
+ 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.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 ("Missing or invalid DNGVersion");
+ ReportError ("Invalid DNGVersion");
- #endif
+ }
+
+ #if qDNGValidateTarget
+
+ else
+ {
- return false;
+ ReportError ("Missing DNGVersion");
+ }
+
+ #endif
+
+ #endif
+
+ return false;
+
}
-
+
// Check DNGBackwardVersion value.
-
+
if (fDNGBackwardVersion > dngVersion_Current)
{
-
+
#if qDNGValidate
-
+
ReportError ("DNGBackwardVersion (or DNGVersion) is too high");
-
+
#endif
-
- return false;
-
+
+ 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 invertible.
-
+
+ // Make sure it is invertable.
+
try
{
-
+
(void) Invert (fCameraCalibration1);
-
+
}
-
+
catch (...)
{
-
+
#if qDNGValidate
-
- ReportError ("CameraCalibration1 is not invertible");
-
+
+ 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 invertible.
-
+
+ // Make sure it is invertable.
+
try
{
-
+
(void) Invert (fCameraCalibration2);
-
+
}
-
+
catch (...)
{
-
+
#if qDNGValidate
-
- ReportError ("CameraCalibration2 is not invertible");
-
+
+ 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 invertible");
-
+
+ ReportError ("AnalogBalance is not invertable");
+
#endif
-
+
return false;
-
+
}
-
+
}
-
+
}
-
+
return true;
-
+
}
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_shared.h b/core/libs/dngwriter/extra/dng_sdk/dng_shared.h
index 07fb52ee89..bb6634e39c 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_shared.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_shared.h
@@ -1,230 +1,243 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_shared.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_shared__
#define __dng_shared__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_fingerprint.h"
#include "dng_matrix.h"
+#include "dng_memory.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_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;
+
+ uint32 fDepthFormat;
+ dng_urational fDepthNear;
+ dng_urational fDepthFar;
+ uint32 fDepthUnits;
+ uint32 fDepthMeasureType;
+
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);
-
+ 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);
-
+ dng_exif &exif,
+ uint32 parentCode,
+ uint32 tagCode,
+ uint32 tagType,
+ uint32 tagCount,
+ uint64 tagOffset);
+
};
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_simd_type.h b/core/libs/dngwriter/extra/dng_sdk/dng_simd_type.h
new file mode 100644
index 0000000000..061a0b76d4
--- /dev/null
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_simd_type.h
@@ -0,0 +1,194 @@
+/*****************************************************************************/
+// Copyright 2017-2019 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 __dng_simd_type__
+#define __dng_simd_type__
+
+/*****************************************************************************/
+
+#include "dng_flags.h"
+
+/*****************************************************************************/
+
+#if qDNGIntelCompiler
+#include <immintrin.h>
+#endif // qDNGIntelCompiler
+
+/*****************************************************************************/
+
+enum SIMDType
+ {
+
+ Scalar,
+
+ SSE2, // Pentium 4
+ AVX, // Sandy Bridge
+ AVX2, // Haswell
+ F16C = AVX2, //Ivy bridge
+ AVX512_SKX, // Sky Lake Server
+
+ SIMD_Sentinel
+
+ };
+
+/*****************************************************************************/
+
+template <int SIMDType>
+class SIMDTraits
+{
+public:
+ static const int kVecSizeFloat = 1;
+ static const int kVecSizeInt32 = 1;
+};
+
+template <>
+class SIMDTraits<SSE2>
+{
+public:
+ static const int kVecSizeFloat = 4;
+ static const int kVecSizeInt32 = 4;
+};
+
+template <>
+class SIMDTraits<AVX>
+{
+public:
+ static const int kVecSizeFloat = 8;
+ static const int kVecSizeInt32 = 4;
+};
+
+template <>
+class SIMDTraits<AVX2>
+{
+public:
+ static const int kVecSizeFloat = 8;
+ static const int kVecSizeInt32 = 8;
+};
+
+template <>
+class SIMDTraits<AVX512_SKX>
+{
+public:
+ static const int kVecSizeFloat = 16;
+ static const int kVecSizeInt32 = 16;
+};
+
+const SIMDType SIMDTypeMaxValue = SIMDType(SIMD_Sentinel - 1);
+
+extern SIMDType gDNGMaxSIMD;
+
+/*****************************************************************************/
+
+#if qDNGIntelCompiler
+
+// Intel compiler.
+
+// Macros are preferred for "#pragma simd" because at some point these will
+// all change to OpenMP 4.x compliant "#pragma omp simd" directives (no longer
+// Intel-specific).
+//
+// Note that _Pragma(x) requires C99 or C++11 support.
+
+// Pre-defined feature levels.
+
+#define CR_SIMD_MIN_FEATURE (_FEATURE_SSE2)
+#define CR_AVX_FEATURE (_FEATURE_AVX)
+#define CR_AVX2_FEATURE (_FEATURE_AVX|_FEATURE_FMA|_FEATURE_AVX2)
+#define CR_F16C_FEATURE CR_AVX2_FEATURE
+#define CR_AVX512_SKX_FEATURE (_FEATURE_AVX512F|_FEATURE_AVX512CD|_FEATURE_AVX512BW|_FEATURE_AVX512DQ|_FEATURE_AVX512VL)
+#define CR_COMPILER_USING_AVX512_SKX (__AVX512F__ && __AVX512VL__ && __AVX512BW__ && __AVX512DQ__ && __AVX512CD__)
+
+#define __SIMDTYPE_TFY(x) #x
+#define _SIMDTYPE_TFY(x) __SIMDTYPE_TFY(x)
+
+#if qDNGDebug
+
+// Debug build.
+
+//#define INTEL_PRAGMA_SIMD_ASSERT_C(clause) _Pragma(PM2__STR1__(simd clause))
+#define INTEL_PRAGMA_SIMD_ASSERT _Pragma("simd")
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeFloat ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeInt32 ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT16(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeInt32*2 ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT8(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeInt32*4 ) ))
+
+#else
+
+// Release build.
+
+//#define INTEL_PRAGMA_SIMD_ASSERT_C(clause) _Pragma(PM2__STR1__(simd assert clause))
+#define INTEL_PRAGMA_SIMD_ASSERT _Pragma("simd assert")
+#if 1
+#if (__INTEL_COMPILER < 1800)
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(s) _Pragma(_SIMDTYPE_TFY(simd assert vectorlength( SIMDTraits<s>::kVecSizeFloat ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(s) _Pragma(_SIMDTYPE_TFY(simd assert vectorlength( SIMDTraits<s>::kVecSizeInt32 ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT16(s) _Pragma(_SIMDTYPE_TFY(simd assert vectorlength( SIMDTraits<s>::kVecSizeInt32*2 ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT8(s) _Pragma(_SIMDTYPE_TFY(simd assert vectorlength( SIMDTraits<s>::kVecSizeInt32*4 ) ))
+#else
+// FIX_ME_ERIC_CHAN: I removed the assert to fix compile time error when using Intel compiler version 18.
+// Need to figure out correct fix when we switch to newer version. - tknoll 10/30/2017.
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeFloat ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeInt32 ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT16(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeInt32*2 ) ))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT8(s) _Pragma(_SIMDTYPE_TFY(simd vectorlength( SIMDTraits<s>::kVecSizeInt32*4 ) ))
+#endif
+#else
+// Don't force
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(s) _Pragma(_SIMDTYPE_TFY(simd assert))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(s) _Pragma(_SIMDTYPE_TFY(simd assert))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT16(s) _Pragma(_SIMDTYPE_TFY(simd assert))
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT8(s) _Pragma(_SIMDTYPE_TFY(simd assert))
+#endif
+#endif
+
+#define SET_CPU_FEATURE(simd) _allow_cpu_features( (simd >= AVX512_SKX) ? CR_AVX512_SKX_FEATURE : (simd >= AVX2) ? CR_AVX2_FEATURE : ((simd >= AVX) ? CR_AVX_FEATURE : CR_SIMD_MIN_FEATURE) )
+//#define SET_CPU_FEATURE_NOFMA(simd) _allow_cpu_features( ((simd >= AVX512_SKX) ? CR_AVX512_SKX_FEATURE : (simd >= AVX2) ? CR_AVX2_FEATURE : ((simd >= AVX) ? CR_AVX_FEATURE : CR_SIMD_MIN_FEATURE)) & ~_FEATURE_FMA )
+#define SET_CPU_FEATURE_NOFMA(simd) _allow_cpu_features( (simd >= AVX) ? CR_AVX_FEATURE : CR_SIMD_MIN_FEATURE)
+#define INTEL_PRAGMA_NOVECTOR _Pragma("novector")
+#define INTEL_COMPILER_NEEDED_NOTE
+
+#else
+
+// Non-Intel compiler. Use empty definitions for the macros.
+// Credit: http://www.highprogrammer.com/alan/windev/visualstudio.html, but avoid using $ character
+#define Stringize( L ) #L
+#define MakeString( M, L ) M(L)
+#define _x_Line MakeString( Stringize, __LINE__ )
+
+#if qDNGValidateTarget
+// Do not warn about Intel compiler if building dng_validate.
+#define INTEL_COMPILER_NEEDED_NOTE
+#else
+#if !(defined (IOS_ENV) || defined(ANDROID_ENV)) && (defined(__x86_64__) || defined(__i386__))
+#ifndef _MSC_VER
+#define INTEL_COMPILER_NEEDED_NOTE _Pragma("message(\"NOTE: Intel Compiler needed for optimizations in \" __FILE__ \":\" _x_Line )")
+#else
+// Intel compiler understands C99 _Pragma, but not Microsoft, so use MS-specific __pragma instead
+#define INTEL_COMPILER_NEEDED_NOTE __pragma(message("NOTE: Intel Compiler needed for optimizations in " __FILE__ ":" _x_Line " in " __FUNCTION__))
+#endif
+#else
+#define INTEL_COMPILER_NEEDED_NOTE
+#endif
+#endif
+
+#define INTEL_PRAGMA_SIMD_ASSERT
+//#define INTEL_PRAGMA_SIMD_ASSERT_C(clause)
+#define SET_CPU_FEATURE(simd)
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(simd)
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT16(simd)
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(simd)
+#define INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT8(simd)
+#define INTEL_PRAGMA_NOVECTOR
+
+#endif // qDNGIntelCompiler
+
+/*****************************************************************************/
+
+#endif // __dng_simd_type__
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.cpp
index fa50558f67..956d697cc0 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.cpp
@@ -1,197 +1,185 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_simple_image.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_simple_image.h"
#include "dng_memory.h"
#include "dng_orientation.h"
#include "dng_tag_types.h"
+#include "dng_tag_values.h"
/*****************************************************************************/
dng_simple_image::dng_simple_image (const dng_rect &bounds,
uint32 planes,
- uint32 pixelType,
- dng_memory_allocator &allocator)
-
+ uint32 pixelType,
+ dng_memory_allocator &allocator)
+
: dng_image (bounds,
planes,
pixelType)
-
- , fMemory ()
- , fBuffer ()
+
+ , fBuffer ()
+ , fMemory ()
, fAllocator (allocator)
-
+
{
-
- uint32 pixelSize = TagTypeSize (pixelType);
-
- uint32 bytes = bounds.H () * bounds.W () * planes * pixelSize;
-
+
+ uint32 bytes = ComputeBufferSize (pixelType,
+ bounds.Size (),
+ planes,
+ padSIMDBytes);
+
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 ();
-
+
+ fBuffer = dng_pixel_buffer (bounds,
+ 0,
+ planes,
+ pixelType,
+ pcInterleaved,
+ 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.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.fArea.l,
+ buffer.fPlane);
+
buffer.fDirty = dirty;
-
+
}
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.h b/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.h
index 9329a5570b..db6068dfe8 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_simple_image.h
@@ -1,82 +1,75 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_simple_image.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_spline.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_spline.cpp
index cafe0db279..3dece851ca 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_spline.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_spline.cpp
@@ -1,233 +1,226 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_spline.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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");
-
+
+ DNG_REQUIRE (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;
-
+ dng_std_vector<real64> E;
+ dng_std_vector<real64> F;
+ dng_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/core/libs/dngwriter/extra/dng_sdk/dng_spline.h b/core/libs/dngwriter/extra/dng_sdk/dng_spline.h
index bb1eff508c..c175939de8 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_spline.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_spline.h
@@ -1,91 +1,75 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_spline.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_spline__
#define __dng_spline__
/*****************************************************************************/
#include "dng_1d_function.h"
-
-#include <vector>
+#include "dng_memory.h"
/*****************************************************************************/
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;
-
+
+ dng_std_vector<real64> X;
+ dng_std_vector<real64> Y;
+
+ dng_std_vector<real64> S;
+
public:
-
+
dng_spline_solver ();
-
+
virtual ~dng_spline_solver ();
-
+
void Reset ();
void Add (real64 x, real64 y);
- void Solve ();
+ virtual void Solve ();
virtual bool IsIdentity () const;
virtual real64 Evaluate (real64 x) const;
- private:
-
- // Hidden copy constructor and assignment operator.
-
- dng_spline_solver (const dng_spline_solver &solver);
-
- dng_spline_solver & operator= (const dng_spline_solver &solver);
-
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_stream.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_stream.cpp
index c33e512abb..a54fa9d18f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_stream.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_stream.cpp
@@ -1,1219 +1,1358 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_stream.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_globals.h"
#include "dng_flags.h"
#include "dng_memory.h"
#include "dng_tag_types.h"
+#include "dng_assertions.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)
+ , fMemBlock ()
+ , fBuffer (NULL)
+ , fBufferSize (Max_uint32 (bufferSize, gDNGStreamBlockSize * 2))
, fBufferStart (0)
, fBufferEnd (0)
, fBufferLimit (bufferSize)
, fBufferDirty (false)
, fSniffer (sniffer)
-
+
{
-
+
+ fMemBlock.Reset (gDefaultDNGMemoryAllocator.Allocate (fBufferSize));
+
+ fBuffer = fMemBlock->Buffer_uint8 ();
+
}
-
+
/*****************************************************************************/
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));
-
+
}
+
+/*****************************************************************************/
+
+void dng_stream::SetBufferSize (dng_memory_allocator &allocator,
+ uint32 newBufferSize)
+ {
+
+ if (newBufferSize != fBufferSize &&
+ newBufferSize >= gDNGStreamBlockSize * 2 &&
+ !Data () &&
+ !fBufferDirty)
+ {
+
+ try
+ {
+
+ fMemBlock.Reset (allocator.Allocate (newBufferSize));
+
+ fBuffer = fMemBlock->Buffer_uint8 ();
+
+ fBufferSize = newBufferSize;
+
+ fBufferStart = 0;
+ fBufferEnd = 0;
+ fBufferLimit = newBufferSize;
+
+ }
+
+ catch (...)
+ {
+
+ }
+
+ }
+
+ }
/*****************************************************************************/
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)
+void dng_stream::Get (void *data, uint32 count, uint32 maxOverRead)
{
-
+
while (count)
{
-
+
// See if the request is totally inside buffer.
-
+
if (fPosition >= fBufferStart && fPosition + count <= fBufferEnd)
{
-
- DoCopyBytes (fBuffer + (uint32) (fPosition - fBufferStart),
- data,
- count);
-
+
+ memcpy (data,
+ fBuffer + (uint32) (fPosition - fBufferStart),
+ 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);
-
+
+ memcpy (data,
+ fBuffer + (fPosition - fBufferStart),
+ block);
+
count -= block;
-
+
data = (void *) (((char *) data) + block);
-
+
fPosition += block;
-
+
}
-
+
// Flush buffer if dirty.
-
+
Flush ();
-
+
// Do large reads unbuffered.
-
+
if (count > fBufferSize)
{
-
+ DNG_ASSERT(maxOverRead == 0, "Over-read of large size unexpected");
if (fPosition + count > Length ())
{
-
+
ThrowEndOfFile ();
-
+
}
-
+
DoRead (data,
count,
fPosition);
-
+
fPosition += count;
-
+
return;
-
+
}
-
+
// Figure out new buffer range.
-
+
fBufferStart = fPosition;
-
- if (fBufferSize >= 4096)
+
+ if (fBufferSize >= gDNGStreamBlockSize)
{
-
- // Align to a 4K file block.
-
- fBufferStart &= 0xFFFFFFFFFFFFF000LL;
-
+
+ // Align to a file block.
+
+ fBufferStart &= (uint64) ~((int64) (gDNGStreamBlockSize - 1));
+
}
-
+
fBufferEnd = Min_uint64 (fBufferStart + fBufferSize, Length ());
+ if ((fBufferEnd - fPosition) < maxOverRead)
+ return; // ep, allow over-read requests
+ else
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);
-
+
+ memcpy (fBuffer + (uint32) (fPosition - fBufferStart),
+ data,
+ count);
+
if (fBufferEnd < endPosition)
fBufferEnd = endPosition;
-
+
}
-
+
// Else we need to write to the file.
-
+
else
{
+
+ // Write initial part of the data to buffer, if possible.
+
+ if (fBufferDirty &&
+ fPosition >= fBufferStart &&
+ fPosition <= fBufferEnd &&
+ fPosition < fBufferLimit)
+ {
+
+ uint32 subCount = (uint32) (fBufferLimit - fPosition);
+
+ memcpy (fBuffer + (uint32) (fPosition - fBufferStart),
+ data,
+ subCount);
+
+ count -= subCount;
+ data = (const void *) (((const uint8 *) data) + subCount);
+
+ fPosition = fBufferLimit;
+ fBufferEnd = fBufferLimit;
+
+ }
// Write existing buffer.
-
+
Flush ();
-
- // Write large blocks unbuffered.
-
- if (count >= fBufferSize)
+
+ // Figure out how much space we have in buffer from
+ // current position to end of file block.
+
+ uint64 blockRound = gDNGStreamBlockSize - 1;
+
+ uint64 blockMask = ~((int64) blockRound);
+
+ uint32 alignedSize = (uint32)
+ (((fPosition + fBufferSize) & blockMask) - fPosition);
+
+ // If write request will not fit in buffer, then write everything except
+ // for the final unaligned part of the data.
+
+ if (count > alignedSize)
{
-
+
+ uint32 alignedCount = (uint32)
+ (((fPosition + count) & blockMask) - fPosition);
+
dng_abort_sniffer::SniffForAbort (fSniffer);
-
- DoWrite (data, count, fPosition);
-
+
+ DoWrite (data, alignedCount, fPosition);
+
+ count -= alignedCount;
+ data = (const void *) (((const uint8 *) data) + alignedCount);
+
+ fPosition += alignedCount;
+
}
-
+
// Start a new buffer with small blocks.
-
- else
+
+ if (count > 0)
{
-
+
fBufferDirty = true;
-
+
fBufferStart = fPosition;
fBufferEnd = endPosition;
- fBufferLimit = fBufferStart + fBufferSize;
-
- DoCopyBytes (data,
- fBuffer,
- count);
-
+ fBufferLimit = (fBufferStart + fBufferSize) & blockMask;
+
+ memcpy (fBuffer,
+ data,
+ 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 (),
+
+ 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);
-
+
}
- break;
+
}
-
+
}
-
+
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);
-
+
}
- break;
+
}
-
+
}
-
+
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 ());
}
/*****************************************************************************/
+dng_stream_contiguous_read_hint::dng_stream_contiguous_read_hint
+ (dng_stream &stream,
+ dng_memory_allocator &allocator,
+ uint64 offset,
+ uint64 count)
+
+ : fStream (stream)
+ , fAllocator (allocator)
+ , fOldBufferSize (stream.BufferSize ())
+
+ {
+
+ fStream.Flush (); // Cannot change buffer size with dirty buffer
+
+ // Don't bother changing buffer size if only a small change.
+
+ if (count > fOldBufferSize * 4)
+ {
+
+ // Round contiguous size up and down to stream blocks.
+
+ uint64 blockRound = gDNGStreamBlockSize - 1;
+
+ uint64 blockMask = ~((int64) blockRound);
+
+ count = (count + (offset & blockRound) + blockRound) & blockMask;
+
+ // Limit to maximum buffer size.
+
+ uint64 newBufferSize = Min_uint64 (gDNGMaxStreamBufferSize, count);
+
+ // To avoid reading too many bytes with the final read, adjust buffer
+ // size the to make an exact number of buffers fit.
+
+ uint64 numBuffers = (count + newBufferSize - 1) / newBufferSize;
+
+ newBufferSize = (count + numBuffers - 1) / numBuffers;
+
+ // Finally round up to a block size.
+
+ newBufferSize = (newBufferSize + blockRound) & blockMask;
+
+ // Change the buffer size.
+
+ fStream.SetBufferSize (fAllocator, (uint32) newBufferSize);
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+dng_stream_contiguous_read_hint::~dng_stream_contiguous_read_hint ()
+ {
+
+ fStream.SetBufferSize (fAllocator, fOldBufferSize);
+
+ }
+
+/*****************************************************************************/
+
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/core/libs/dngwriter/extra/dng_sdk/dng_stream.h b/core/libs/dngwriter/extra/dng_sdk/dng_stream.h
index 5d83fe386d..014b33109f 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_stream.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_stream.h
@@ -1,698 +1,766 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_stream.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_auto_ptr.h"
#include "dng_classes.h"
#include "dng_types.h"
#include "dng_memory.h"
#include "dng_rational.h"
+#include "dng_uncopyable.h"
#include "dng_utils.h"
/*****************************************************************************/
// Constants for invalid offset in streams.
-const uint64 kDNGStreamInvalidOffset = 0xFFFFFFFFFFFFFFFFLL;
+const uint64 kDNGStreamInvalidOffset = (uint64) (int64) -1;
/*****************************************************************************/
/// Base stream abstraction. Has support for going between stream and pointer
/// abstraction.
-class dng_stream
+class dng_stream: private dng_uncopyable
{
-
+
public:
-
+
enum
{
-
- kSmallBufferSize = 4 * 1024,
+
+ kSmallBufferSize = 8 * 1024,
kBigBufferSize = 64 * 1024,
-
+
kDefaultBufferSize = kSmallBufferSize
-
+
};
-
+
private:
-
+
bool fSwapBytes;
-
+
bool fHaveLength;
-
+
uint64 fLength;
-
+
const uint64 fOffsetInOriginalFile;
-
+
uint64 fPosition;
-
- dng_memory_data fMemBlock;
-
+
+ AutoPtr<dng_memory_block> 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;
}
+ /// Change the buffer size on the stream, if possible.
+
+ void SetBufferSize (dng_memory_allocator &allocator,
+ uint32 newBufferSize);
+
/// 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
+ /// \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
+
+ /// 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
+
+ /// Quick check to see if data range in completely buffered.
+
+ bool DataInBuffer (uint32 count,
+ uint64 offset)
+ {
+ return (offset >= fBufferStart &&
+ offset + count <= fBufferEnd);
+ }
+
+ /// 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
+ /// \exception dng_exception with fErrorCode equal to dng_error_end_of_file
/// if not enough data in stream.
-
- void Get (void *data, uint32 count);
+
+ void Get (void *data, uint32 count, uint32 maxOverRead=0);
/// 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 available data in stream.
+ /// \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
+ /// \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.
+
+ /// 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.
+
+ /// 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();
+
+#if !qDNGBigEndian
+ inline // ep, enable compiler inlining
+ uint32 Get_uint32_LE ()
+ {
+
+ uint32 x;
+
+ Get (&x, 4, 3); // Allow 3-byte overread (undefined data returned but not used)
+
+ // No check for fSwapBytes
- uint32 Get_uint32 ();
+ return x;
+
+ }
+#endif
- /// Put an unsigned 32-bit integer to stream and advance write position.
+ /// 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.
+
+ /// 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.
+
+ /// 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.
+ /// 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
+ /// \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.
+ /// 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.
+
+ /// 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
+
+ /// 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
+ /// \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
+ /// (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.
+ /// 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.
+ /// 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
+ /// \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
+
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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:
+class dng_stream_double_buffered : public dng_stream
+ {
+
+ private:
+
+ dng_stream &fStream;
+
+ public:
+
+ dng_stream_double_buffered (dng_stream &stream,
+ uint32 bufferSize = kDefaultBufferSize)
+
+ : dng_stream ((dng_abort_sniffer *) NULL,
+ bufferSize,
+ stream.OffsetInOriginalFile ())
+
+ , fStream (stream)
+
+ {
+ SetBigEndian (fStream.BigEndian ());
+ }
+
+ protected:
+
+ virtual uint64 DoGetLength ()
+ {
+ return fStream.Length ();
+ }
+
+ virtual void DoRead (void *data,
+ uint32 count,
+ uint64 offset)
+ {
+ fStream.SetReadPosition (offset);
+ fStream.Get (data, count);
+ }
- // Hidden copy constructor and assignment operator.
+ };
- dng_stream (const dng_stream &stream);
+/*****************************************************************************/
- dng_stream & operator= (const dng_stream &stream);
-
- };
+class dng_stream_contiguous_read_hint
+ {
+
+ private:
+
+ dng_stream &fStream;
+
+ dng_memory_allocator &fAllocator;
+
+ uint32 fOldBufferSize;
+
+ public:
+
+ dng_stream_contiguous_read_hint (dng_stream &stream,
+ dng_memory_allocator &allocator,
+ uint64 offset,
+ uint64 count);
+
+ ~dng_stream_contiguous_read_hint ();
+
+ };
/*****************************************************************************/
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
+class TempStreamSniffer: private dng_uncopyable
{
-
+
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);
-
+
+ ~TempStreamSniffer ();
+
};
-
+
/*****************************************************************************/
-class PreserveStreamReadPosition
+class PreserveStreamReadPosition: private dng_uncopyable
{
-
+
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/core/libs/dngwriter/extra/dng_sdk/dng_string.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_string.cpp
index 84c81ac5ad..b556cc7d14 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_string.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_string.cpp
@@ -1,2044 +1,2458 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_string.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include "dng_safe_arithmetic.h"
#if qMacOS
#include <CoreServices/CoreServices.h>
#endif
#if qWinOS
#include <windows.h>
#endif
+#if qiPhone || qAndroid
+#include <ctype.h> // for isdigit
+#endif
+
/*****************************************************************************/
const uint32 kREPLACEMENT_CHARACTER = 0x0000FFFD;
/*****************************************************************************/
-#if qMacOS
+// Returns the length of the zero-terminated string 's'. Throws a dng_exception
+// if the length of 's' is too large to be represented as a uint32.
-static void Assign_Multibyte (dng_string &dngString,
- const char *otherString,
- TextEncoding encoding)
+static uint32 strlenAsUint32 (const char *s)
{
+
+ uint32 lengthAsUint32 = 0;
- uint32 aSize = (uint32) strlen (otherString);
+ ConvertUnsigned (strlen (s), &lengthAsUint32);
+
+ return lengthAsUint32;
+
+ }
- if (aSize > 0)
+/*****************************************************************************/
+
+// Checks whether there is enough space left in the buffer pointed to by
+// 'currentPos' to write at least 'space' elements of type T (to positions
+// currentPos[0] through currentPos[space - 1]. Throws a dng_exception if
+// there is not enough space left in the buffer. 'bufferEnd' should point one
+// element beyond the end of the buffer. For example, if the buffer is "T
+// buffer[3];", then bufferEnd should point to T + 3.
+
+template <class T>
+static void CheckSpaceLeftInBuffer(const T *currentPos,
+ const T *bufferEnd,
+ size_t space)
+ {
+
+ if (bufferEnd < currentPos || static_cast<size_t> (bufferEnd - currentPos) < space)
{
+ ThrowMemoryFull ("Buffer overrun");
+ }
+
+ }
- uint32 aBufSize = aSize * 6 + 256;
+/*****************************************************************************/
- dng_memory_data aBuf (aBufSize + 1);
+#if qMacOS
- UnicodeMapping aMapping;
+static void Assign_Multibyte (dng_string &dngString,
+ const char *otherString,
+ TextEncoding encoding)
+ {
+
+ dng_safe_uint32 aSize (strlenAsUint32 (otherString));
+
+ if (aSize.Get () > 0)
+ {
+ dng_safe_uint32 aBufSize = aSize * 6u + 256u;
+
+ dng_memory_data aBuf (aBufSize + 1u);
+
+ 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,
+ aSize.Get (),
otherString,
kUnicodeUseFallbacksMask |
kUnicodeLooseMappingsMask,
0,
NULL,
NULL,
NULL,
- aBufSize,
+ aBufSize.Get (),
&aInput,
&aOutput,
(UniChar *) aBuf.Buffer ());
-
+
::DisposeTextToUnicodeInfo (&aInfo);
-
- if (aOutput > 0 && aOutput <= aBufSize)
+
+ if (aOutput > 0 && aOutput <= aBufSize.Get ())
{
-
+
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)
+
+ dng_safe_uint32 aSize (dngString.Length ());
+
+ if (aSize.Get () > 0)
{
-
- uint32 aBufSize = (aSize * 2) + 256;
-
+
+ dng_safe_uint32 aBufSize = aSize * 2u + 256u;
+
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,
+ aSize.Get (),
(const UniChar *) dngString.Get (),
kUnicodeUseFallbacksMask |
kUnicodeLooseMappingsMask |
kUnicodeDefaultDirectionMask,
0,
NULL,
NULL,
NULL,
- aBufSize,
+ aBufSize.Get (),
&aInput,
&aOutput,
tempBuffer.Buffer_char ());
-
+
::DisposeUnicodeToTextInfo (&aInfo);
-
+
if (aOutput > 0)
{
- buffer.Allocate (aOutput + 1);
+ uint32 aOutputAsUint32 = 0;
+ ConvertUnsigned (aOutput, &aOutputAsUint32);
+
+ buffer.Allocate (dng_safe_uint32 (aOutputAsUint32) + 1u);
+
memcpy (buffer.Buffer (),
tempBuffer.Buffer (),
- aOutput);
-
- buffer.Buffer_char () [aOutput] = 0;
-
- return (uint32) aOutput;
-
+ aOutputAsUint32);
+
+ buffer.Buffer_char () [aOutputAsUint32] = 0;
+
+ return aOutputAsUint32;
+
}
-
+
}
-
+
}
-
+
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");
+
+ const dng_safe_uint32 otherStringLen (strlenAsUint32 (otherString));
- int aSize = (int) strlen (otherString);
+ const dng_safe_int32 aSize (otherStringLen);
- if (aSize > 0)
+ if (aSize.Get () > 0)
{
+
+ dng_safe_uint32 aBufCharsUint32 = otherStringLen * 3u + 128u;
- int aBufChars = aSize * 3 + 128;
+ dng_safe_int32 aBufChars (aBufCharsUint32);
- dng_memory_data aBuf ((aBufChars + 1) << 1);
+ dng_safe_uint32 bytesToAllocate = (aBufCharsUint32 + 1u) * 2u;
+ dng_memory_data aBuf (bytesToAllocate);
+
int aResult = ::MultiByteToWideChar (encoding,
0,
otherString,
- aSize,
+ aSize.Get (),
(WCHAR *) aBuf.Buffer (),
- aBufChars);
-
- if (aResult > 0 && aResult <= aBufChars)
+ aBufChars.Get ());
+
+ if (aResult > 0 && aResult <= aBufChars.Get ())
{
-
+
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;
+ if (aCount < 0)
+ {
+ return 0;
+ }
- dng_memory_data dBuffer (dBufSize);
+ dng_safe_uint32 aCountAsUint32 (static_cast<uint32> (aCount));
+ dng_safe_uint32 dBufSize = aCountAsUint32 * 2u + 256u;
+
+ dng_memory_data dBuffer (dBufSize);
+
int aResult = ::WideCharToMultiByte (encoding,
0,
(WCHAR *) sBuffer.Buffer (),
aCount,
dBuffer.Buffer_char (),
- dBufSize,
+ dBufSize.Get (),
NULL,
NULL);
-
+
if (aResult < 0)
aResult = 0;
- buffer.Allocate (aResult + 1);
-
+ dng_safe_uint32 aResultAsUint32 (static_cast<uint32> (aResult));
+
+ buffer.Allocate (aResultAsUint32 + 1u);
+
memcpy (buffer.Buffer (),
dBuffer.Buffer (),
aResult);
-
+
buffer.Buffer_char () [aResult] = 0;
- return (uint32) aResult;
-
+ return aResultAsUint32.Get ();
+
}
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);
-
+
+ uint32 newLen = (s != NULL ? strlenAsUint32 (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);
-
+
+ fData.Allocate (dng_safe_uint32 (newLen) + 1u);
+
}
-
+
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;
-
+
+ dng_safe_uint32 len (strlenAsUint32 (s));
+
+ const char *sEnd = s + len.Get ();
+
// Worst case expansion is 1-byte characters expanding to
// replacement character, which requires 3 bytes.
+
+ const dng_safe_uint32 destBufferLength = len * 3u + 1u;
- dng_memory_data buffer (len * 3 + 1);
-
+ dng_memory_data buffer (destBufferLength);
+
uint8 *d = buffer.Buffer_uint8 ();
-
+ uint8 * const destEnd = d + destBufferLength.Get ();
+
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)
+
+ if (aChar < 0x00000080)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 1);
*(d++) = (uint8) aChar;
}
-
+
else if (aChar < 0x00000800)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 2);
*(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
*(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
}
-
+
else if (aChar < 0x00010000)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 3);
*(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
*(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
}
-
+
else if (aChar < 0x00200000)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 4);
*(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)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 5);
*(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
{
+ CheckSpaceLeftInBuffer (d, destEnd, 6);
*(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);
}
-
+
}
-
+
+ CheckSpaceLeftInBuffer (d, destEnd, 1);
*d = 0;
-
+
Set (buffer.Buffer_char ());
-
+
}
-
+
/*****************************************************************************/
uint32 dng_string::Get_SystemEncoding (dng_memory_data &buffer) const
{
-
+
if (IsASCII ())
{
+
+ dng_safe_uint32 len (Length ());
+
+ const dng_safe_uint32 destBufferLength = len + 1u;
- uint32 len = Length ();
-
- buffer.Allocate (len + 1);
-
- memcpy (buffer.Buffer (), Get (), len + 1);
-
- return len;
+ buffer.Allocate (destBufferLength);
+ memcpy (buffer.Buffer (), Get (), destBufferLength.Get ());
+
+ return len.Get ();
+
}
-
+
else
{
-
+
#if qMacOS || 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 || qWinOS
-
+
Assign_SystemEncoding (*this, s);
-
+
#else
-
+
// Fallback logic that just grabs the ASCII characters and
// ignores the non-ASCII characters.
+
+ dng_safe_uint32 len = strlenAsUint32 (s);
+
+ const dng_safe_uint32 destBufferLength = len + 1u;
- uint32 len = (uint32) strlen (s);
-
- dng_memory_data buffer (len + 1);
-
+ dng_memory_data buffer (destBufferLength);
+
uint8 *d = buffer.Buffer_uint8 ();
-
+ uint8 * const destEnd = d + destBufferLength.Get ();
+
while (*s)
{
-
+
uint8 c = (uint8) *(s++);
-
+
if ((c & 0x80) == 0)
{
-
+
+ CheckSpaceLeftInBuffer (d, destEnd, 1);
*(d++) = c;
-
+
}
-
+
}
-
+
+ CheckSpaceLeftInBuffer (d, destEnd, 1);
*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 || 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)
+ 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;
- switch (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:
- return ((aChar << 6) + nBuf[1]) - 0x00003080UL;
-
+ {
+
+ aChar = ((aChar << 6) + nBuf [1]) - (uint32) 0x00003080UL;
+
+ break;
+
+ }
+
case 3:
- return ((((aChar << 6) + nBuf[1])
- << 6) + nBuf[2]) - 0x000E2080UL;
-
+ {
+
+ aChar = ((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2]) - (uint32) 0x000E2080UL;
+
+ break;
+
+ }
+
case 4:
- return ((((((aChar << 6) + nBuf[1])
- << 6) + nBuf[2])
- << 6) + nBuf[3]) - 0x03C82080UL;
-
+ {
+
+ aChar = ((((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2])
+ << 6) + nBuf [3]) - (uint32) 0x03C82080UL;
+
+ break;
+
+ }
+
case 5:
- return ((((((((aChar << 6) + nBuf[1])
- << 6) + nBuf[2])
- << 6) + nBuf[3])
- << 6) + nBuf[4]) - 0xFA082080UL;
-
+ {
+
+ aChar = ((((((((aChar << 6) + nBuf [1])
+ << 6) + nBuf [2])
+ << 6) + nBuf [3])
+ << 6) + nBuf [4]) - (uint32) 0xFA082080UL;
+
+ break;
+
+ }
+
case 6:
- return ((((((((((aChar << 6) + nBuf[1])
- << 6) + nBuf[2])
- << 6) + nBuf[3])
- << 6) + nBuf[4])
- << 6) + nBuf[5]) - 0x82082080UL;
-
+ {
+
+ 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;
+
+ }
- return kREPLACEMENT_CHARACTER;
+/*****************************************************************************/
+bool dng_string::IsUTF8 (const char *s)
+ {
+
+ uint32 len = strlenAsUint32 (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;
+
}
/*****************************************************************************/
-uint32 dng_string::Get_UTF16 (dng_memory_data &buffer) const
+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 count = 0;
+/*****************************************************************************/
+uint32 dng_string::Get_UTF16 (dng_memory_data &buffer) const
+ {
+
+ dng_safe_uint32 count = 0u;
+
const char *sPtr = Get ();
-
+
while (*sPtr)
{
-
+
uint32 x = DecodeUTF8 (sPtr);
-
+
if (x <= 0x0000FFFF ||
x > 0x0010FFFF)
{
-
- count += 1;
-
+
+ count += 1u;
+
}
-
+
else
{
-
- count += 2;
-
+
+ count += 2u;
+
}
-
+
}
- buffer.Allocate ((count + 1) * sizeof (uint16));
+ const dng_safe_uint32 destBufferLength = count + 1u;
+ buffer.Allocate (destBufferLength.Get (),
+ sizeof (uint16));
+
uint16 *dPtr = buffer.Buffer_uint16 ();
-
+ uint16 * const destEnd = dPtr + destBufferLength.Get ();
+
sPtr = Get ();
-
+
while (*sPtr)
{
-
+
uint32 x = DecodeUTF8 (sPtr);
-
+
if (x <= 0x0000FFFF)
{
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*(dPtr++) = (uint16) x;
-
+
}
-
+
else if (x > 0x0010FFFF)
{
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*(dPtr++) = (uint16) kREPLACEMENT_CHARACTER;
-
+
}
-
+
else
{
-
+
x -= 0x00010000;
-
- *(dPtr++) = (uint16) ((x >> 10 ) + 0x0000D800);
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 2);
+ *(dPtr++) = (uint16) ((x >> 10 ) + 0x0000D800);
*(dPtr++) = (uint16) ((x & 0x000003FF) + 0x0000DC00);
-
+
}
-
+
}
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*dPtr = 0;
-
- return count;
+
+ return count.Get ();
}
-
+
/*****************************************************************************/
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)
+ dng_safe_uint32 length16 (0u);
+
+ while (s [length16.Get ()] != 0)
{
- length16++;
+ length16 += 1u;
}
+
+ const uint16 *sEnd = s + length16.Get ();
+
+ const dng_safe_uint32 destBufferSize = length16 * 6u + 1u;
- const uint16 *sEnd = s + length16;
-
- dng_memory_data buffer (length16 * 6 + 1);
-
+ dng_memory_data buffer (destBufferSize);
+
uint8 *d = buffer.Buffer_uint8 ();
-
+ uint8 * const destEnd = d + destBufferSize.Get ();
+
while (s < sEnd)
{
-
+
uint32 aChar = *s++;
-
+
if (swap)
{
aChar = ((aChar << 8) | (aChar >> 8)) & 0x0000FFFF;
}
-
- if ((aChar >= 0x0000D800) && (aChar <= 0x0000DBFF) && (s < sEnd))
+
+ 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)
+
+ if (aChar < 0x00000080)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 1);
*(d++) = (uint8) aChar;
}
-
+
else if (aChar < 0x00000800)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 2);
*(d++) = (uint8) ((aChar >> 6) | 0x000000C0);
*(d++) = (uint8) ((aChar & 0x0000003F) | 0x00000080);
}
-
+
else if (aChar < 0x00010000)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 3);
*(d++) = (uint8) ( (aChar >> 12) | 0x000000E0);
*(d++) = (uint8) (((aChar >> 6) & 0x0000003F) | 0x00000080);
*(d++) = (uint8) ( (aChar & 0x0000003F) | 0x00000080);
}
-
+
else if (aChar < 0x00200000)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 4);
*(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)
{
+ CheckSpaceLeftInBuffer (d, destEnd, 5);
*(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
{
+ CheckSpaceLeftInBuffer (d, destEnd, 6);
*(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);
}
-
+
}
-
+
+ CheckSpaceLeftInBuffer (d, destEnd, 1);
*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);
-
+
+ uint32 len = strlenAsUint32 (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);
-
+
+ return strlenAsUint32 (s);
+
}
/*****************************************************************************/
bool dng_string::operator== (const dng_string &s) const
{
-
+
const char *s1 = Get ();
const char *s2 = s.Get ();
-
- return strcmp (s1, s2) == 0;
-
+
+ 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);
-
+
+ uint32 len2 = strlenAsUint32 (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);
-
+
+ uint32 len2 = strlenAsUint32 (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);
-
+
+ uint32 len2 = strlenAsUint32 (old_string);
+ uint32 len3 = strlenAsUint32 (new_string);
+
if (len2 == len3)
{
+ DNG_REQUIRE (fData.Buffer_char (), "Bad string in dng_string::Replace");
+
strncpy (fData.Buffer_char () + match_offset,
new_string,
len3);
-
+
}
-
+
else if (len2 > len3)
{
-
+
+ DNG_REQUIRE (fData.Buffer_char (), "Bad string in dng_string::Replace");
+
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
{
+
+ // "len1 - len2" cannot wrap around because we know that if this
+ // string contains old_string, len1 >= len2 must hold.
- dng_memory_data tempBuffer (len1 - len2 + len3 + 1);
-
+ dng_memory_data tempBuffer
+ (dng_safe_uint32 (len1 - len2) + len3 + 1u);
+
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
+ DNG_REQUIRE (fData.Buffer_char (), "Bad string in dng_string::Replace");
+
strncpy (tempBuffer.Buffer_char () + match_offset + len3,
fData .Buffer_char () + match_offset + len2,
extra);
-
+
Set (tempBuffer.Buffer_char ());
}
-
+
return true;
-
+
}
-
+
return false;
-
+
}
+
+/*****************************************************************************/
+void dng_string::ReplaceChars (char oldChar,
+ char newChar)
+ {
+
+ if (fData.Buffer ())
+ {
+
+ uint32 len = Length ();
+
+ char *dPtr = fData.Buffer_char ();
+
+ for (uint32 j = 0; j < len; j++)
+ {
+
+ if (dPtr [j] == oldChar)
+ {
+
+ dPtr [j] = newChar;
+
+ }
+
+ }
+
+ }
+
+ }
+
/*****************************************************************************/
bool dng_string::TrimLeading (const char *s,
bool case_sensitive)
{
-
+
if (StartsWith (s, case_sensitive))
{
-
- Set (Get () + (uint32) strlen (s));
-
+
+ Set (Get () + strlenAsUint32 (s));
+
return true;
-
+
}
-
+
return false;
-
+
}
/*****************************************************************************/
void dng_string::Append (const char *s)
{
-
- uint32 len2 = (uint32) strlen (s);
-
- if (len2)
+
+ dng_safe_uint32 len2 (strlenAsUint32 (s));
+
+ if (len2.Get ())
{
-
- uint32 len1 = Length ();
-
- dng_memory_data temp (len1 + len2 + 1);
-
+
+ dng_safe_uint32 len1 (Length ());
+
+ dng_memory_data temp (len1 + len2 + 1u);
+
char *buffer = temp.Buffer_char ();
-
- if (len1)
+
+ if (len1.Get ())
{
- memcpy (buffer, Get (), len1);
+ memcpy (buffer, Get (), len1.Get ());
}
-
- memcpy (buffer + len1, s, len2 + 1);
-
+
+ memcpy (buffer + len1.Get (), s, (len2 + 1u).Get ());
+
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_safe_uint32 tempBufferSize = dng_safe_uint32 (Length ()) * 3u + 1u;
- dng_memory_data tempBuffer (Length () * 3 + 1);
-
+ dng_memory_data tempBuffer (tempBufferSize);
+
char *dPtr = tempBuffer.Buffer_char ();
-
+ char * const destEnd = dPtr + tempBufferSize.Get ();
+
const char *sPtr = Get ();
-
+
while (*sPtr)
{
-
+
uint32 x = DecodeUTF8 (sPtr);
-
+
if (x <= 0x007F)
{
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*(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)
{
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*(dPtr++) = *(ascii++);
-
+
}
-
+
}
-
+
else
{
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*(dPtr++) ='?';
-
+
}
-
+
}
-
+
}
-
+
+ CheckSpaceLeftInBuffer (dPtr, destEnd, 1);
*dPtr = 0;
-
+
Set (tempBuffer.Buffer_char ());
-
+
}
-
+
}
+
+/******************************************************************************/
+static dng_std_mutex gProtectUCCalls;
+
/******************************************************************************/
-int32 dng_string::Compare (const dng_string &s) const
+int32 dng_string::Compare (const dng_string &s,
+ bool digitsAsNumber) const
{
-
+
#if qMacOS
-
+
{
-
+
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.
-
- static dng_mutex sProtectUCCalls ("sProtectUCCalls");
-
- dng_lock_mutex lockMutex (&sProtectUCCalls);
+
+ dng_lock_std_mutex lockMutex (gProtectUCCalls);
UCCollateOptions aOptions = kUCCollateStandardOptions |
kUCCollatePunctuationSignificantMask;
-
+
+ if (digitsAsNumber)
+ {
+
+ aOptions |= kUCCollateDigitsOverrideMask |
+ kUCCollateDigitsAsNumberMask;
+
+ }
+
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,
+ if (digitsAsNumber)
+ {
+ aFlags |= SORT_DIGITSASNUMBERS;
+ }
+
+ int aOrder = ::CompareStringW (locale,
aFlags,
- (const WCHAR *) aStrA.Buffer_uint16 (),
+ (const WCHAR *) aStrA.Buffer_uint16 (),
aLenA,
- (const WCHAR *) aStrB.Buffer_uint16 (),
+ (const WCHAR *) aStrB.Buffer_uint16 (),
aLenB);
if (aOrder == CSTR_EQUAL)
{
return 0;
}
else if (aOrder == CSTR_GREATER_THAN)
{
return 1;
- }
-
- else
+ }
+
+ else
{
return -1;
}
}
- else
+ else
{
return 1;
}
}
- else
+ else
{
- if (aLenB > 0)
+ 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)
+
+ if (digitsAsNumber)
+ {
+
+ uint32 aNumber = 0;
+ uint32 aDigits = 0;
+
+ if (a >= (uint32) '0' && a <= (uint32) '9')
+ {
+
+ aNumber = a - (uint32) '0';
+ aDigits = 1;
+
+ while (aDigits < 6 && *aPtr >= '0' && *aPtr <= '9')
+ {
+ aNumber = aNumber * 10 + ((uint32) *aPtr -
+ (uint32) '0');
+ aDigits++;
+ aPtr++;
+ }
+
+ }
+
+ uint32 bNumber = 0;
+ uint32 bDigits = 0;
+
+ if (b >= (uint32) '0' && b <= (uint32) '9')
+ {
+
+ bNumber = b - (uint32) '0';
+ bDigits = 1;
+
+ while (bDigits < 6 && *bPtr >= '0' && *bPtr <= '9')
+ {
+ bNumber = bNumber * 10 + ((uint32) *bPtr -
+ (uint32) '0');
+ bDigits++;
+ bPtr++;
+ }
+
+ }
+
+ if (aDigits > 0 && bDigits > 0)
+ {
+
+ if (aNumber > bNumber)
+ {
+ return 1;
+ }
+
+ if (aNumber < bNumber)
+ {
+ return -1;
+ }
+
+ if (aDigits > bDigits)
+ {
+ return 1;
+ }
+
+ if (aDigits < bDigits)
+ {
+ return -1;
+ }
+
+ continue;
+
+ }
+
+ }
+
+ if (a > b)
{
return 1;
}
-
+
else if (a < b)
{
return -1;
}
-
+
}
-
+
}
-
+
}
-
+
#endif
-
+
return 0;
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_string.h b/core/libs/dngwriter/extra/dng_sdk/dng_string.h
index a6560cfe45..a803dafb3e 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_string.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_string.h
@@ -1,152 +1,164 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_string.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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);
+ 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);
-
+
+ void ReplaceChars (char oldChar,
+ char newChar);
+
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,
+ bool digitsAsNumber = true) const;
- int32 Compare (const dng_string &s) const;
+ // A utility to convert fields of numbers into comma separated numbers.
- };
+ void NormalizeAsCommaSeparatedNumbers ();
+ };
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_string_list.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_string_list.cpp
index fcec98e11e..be4364bbc7 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_string_list.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_string_list.cpp
@@ -1,163 +1,156 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_string_list.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#include "dng_string_list.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_string.h"
#include "dng_utils.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 **)
malloc (newSize * sizeof (dng_string *));
-
+
if (!list)
{
-
+
ThrowMemoryFull ();
-
+
}
-
+
if (fCount)
{
-
- DoCopyBytes (fList, list, fCount * sizeof (dng_string *));
-
+
+ memcpy (list, fList, fCount * (uint32) sizeof (dng_string *));
+
}
-
+
if (fList)
{
-
+
free (fList);
-
+
}
-
+
fList = list;
-
+
fAllocated = newSize;
-
+
}
-
+
}
-
+
/*****************************************************************************/
-void dng_string_list::Insert (uint32 index,
+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];
-
+
}
-
+
free (fList);
-
+
fList = NULL;
-
+
}
-
+
fCount = 0;
fAllocated = 0;
-
+
}
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_string_list.h b/core/libs/dngwriter/extra/dng_sdk/dng_string_list.h
index da4dd3e837..424b344adb 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_string_list.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_string_list.h
@@ -1,86 +1,72 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_string_list.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_string_list__
#define __dng_string_list__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_types.h"
+#include "dng_uncopyable.h"
/*****************************************************************************/
-class dng_string_list
+class dng_string_list: private dng_uncopyable
{
-
+
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,
+
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_tag_codes.h b/core/libs/dngwriter/extra/dng_sdk/dng_tag_codes.h
index cba164e2c3..c18a849ac2 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tag_codes.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tag_codes.h
@@ -1,496 +1,561 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_tag_codes.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+#ifndef __dng_tag_codes__
+#define __dng_tag_codes__
/*****************************************************************************/
-#ifndef __dng_tag_codes__
-#define __dng_tag_codes__
+#include "dng_flags.h"
/*****************************************************************************/
// 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 tag number 51125 registered at:
+// http://partners.adobe.com/asn/tech/tiff/tiffregister.jsp
+// on 2012-05-31, purpose "Digital Negative".
+
+// TIFF tags numbers 51177 through 51191 registered at:
+// Manual update on 2018-06-17, 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,
+ 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,
+ tcOffsetTime = 36880,
+ tcOffsetTimeOriginal = 36881,
+ tcOffsetTimeDigitized = 36882,
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,
+ 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,
+ tcTemperature = 37888,
+ tcHumidity = 37889,
+ tcPressure = 37890,
+ tcWaterDepth = 37891,
+ tcAcceleration = 37892,
+ tcCameraElevationAngle = 37893,
tcFlashPixVersion = 40960,
tcColorSpace = 40961,
tcPixelXDimension = 40962,
tcPixelYDimension = 40963,
tcRelatedSoundFile = 40964,
tcInteroperabilityIFD = 40965,
tcFlashEnergyExif = 41483,
- tcSpatialFrequencyResponseExif = 41484,
+ tcSpatialFrequencyResponseExif = 41484,
tcFocalPlaneXResolutionExif = 41486,
tcFocalPlaneYResolutionExif = 41487,
tcFocalPlaneResolutionUnitExif = 41488,
tcSubjectLocation = 41492,
- tcExposureIndexExif = 41493,
+ 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,
+ 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,
+ tcDepthFormat = 51177,
+ tcDepthNear = 51178,
+ tcDepthFar = 51179,
+ tcDepthUnits = 51180,
+ tcDepthMeasureType = 51181,
+ tcEnhanceParams = 51182,
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
-
+ tcAdobePSD,
+ tcPNG,
+ tcHEIC,
+ tcCanonCR3
+
};
/*****************************************************************************/
// 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
+ 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_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_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_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_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_COM = 0xfe,
M_ERROR = 0x100
-
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.cpp
index 4ea365ef72..5a3c06abef 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.cpp
@@ -1,66 +1,59 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_tag_types.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.h b/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.h
index 707f7b9f6c..eb8caf6aba 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tag_types.h
@@ -1,52 +1,45 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_tag_types.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_tag_values.h b/core/libs/dngwriter/extra/dng_sdk/dng_tag_values.h
index 1de66f0d42..0bec5e049a 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tag_values.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tag_values.h
@@ -1,362 +1,534 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_tag_values.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+#ifndef __dng_tag_values__
+#define __dng_tag_values__
/*****************************************************************************/
-#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 (reduced resolution raw) transparency mask.
+
+ sfPreviewMask = sfPreviewImage + sfTransparencyMask,
+
+ // Depth map.
+
+ sfDepthMap = 8,
+
+ // Preview (reduced resolution raw) depth map.
+
+ sfPreviewDepthMap = sfPreviewImage + sfDepthMap,
+
+ // Enhanced image (processed stage 3).
+
+ sfEnhancedImage = 16,
+
// 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
+ piLinearRaw = 34892,
+ piDepth = 51177
+
};
/******************************************************************************/
// Values for PlanarConfiguration tag.
enum
{
-
+
pcInterleaved = 1,
pcPlanar = 2,
-
- pcRowInterleaved = 100000 // Internal use only
-
+
+ // Ordering, using an RGB image as an example:
+ //
+ // RRRRRRRRRR
+ // GGGGGGGGGG
+ // BBBBBBBBBB
+ // RRRRRRRRRR
+ // GGGGGGGGGG
+ // BBBBBBBBBB
+ //
+ // The "AlignSIMD" variant additionally ensures that the offset of each
+ // plane's row is aligned to an integer multiple of SIMD vector width (16
+ // or 32) bytes from the beginning of the buffer.
+ pcRowInterleaved = 100000, // Internal use only
+ pcRowInterleavedAlignSIMD = 100001 // 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,
- ccPackBits = 32773,
- ccOldDeflate = 32946
+ #if qDNGSupportVC5
+ ccVc5 = 9,
+ #endif // qDNGSupportVC5
+
+ 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
-
+ 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 - 5400K
- lsCoolWhiteFluorescent = 14, // W 3900 - 4500K
- lsWhiteFluorescent = 15, // WW 3200 - 3700K
+ 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 embeddable and copyable into installations that encounter this
+
+ // 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 embedded in a DNG for portable processing, but cannot be used
+
+ // 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.
+
+ // 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
+ // 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
+
};
/*****************************************************************************/
+// Values for the DepthFormat tag.
+
+enum
+ {
+ depthFormatUnknown = 0,
+ depthFormatLinear = 1,
+ depthFormatInverse = 2
+ };
+
+// Values for the DepthUnits tag.
+
+enum
+ {
+ depthUnitsUnknown = 0,
+ depthUnitsMeters = 1
+ };
+
+// Values for DepthMeasureType tag.
+
+enum
+ {
+ depthMeasureUnknown = 0,
+ depthMeasureOpticalAxis = 1,
+ depthMeasureOpticalRay = 2
+ };
+
+/*****************************************************************************/
+
// 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_1_5_0_0 = 0x01050000,
- dngVersion_Current = dngVersion_1_3_0_0,
-
- dngVersion_SaveDefault = dngVersion_Current
-
+ dngVersion_Current = dngVersion_1_5_0_0,
+
+ dngVersion_SaveDefault = dngVersion_1_4_0_0
+
};
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_temperature.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_temperature.cpp
index 85094f2b11..272a5664a9 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_temperature.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_temperature.cpp
@@ -1,259 +1,254 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_temperature.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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 },
+ { 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));
-
+ 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));
-
+ kTempTable [index ] . u * (1.0 - f));
+
vv = v - (kTempTable [index - 1] . v * f +
- kTempTable [index ] . v * (1.0 - 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 +
+
+ real64 u = kTempTable [index ] . u * f +
kTempTable [index + 1] . u * (1.0 - f);
-
- real64 v = kTempTable [index ] . v * 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);
-
+ result.y = v / (u - 4.0 * v + 2.0);
+
break;
-
- }
-
+
+ }
+
}
-
+
return result;
-
+
}
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_temperature.h b/core/libs/dngwriter/extra/dng_sdk/dng_temperature.h
index c9f7153c9e..1e2bb75876 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_temperature.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_temperature.h
@@ -1,92 +1,92 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_temperature.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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)
-
+ , fTint (0.0)
+
{
}
-
+
dng_temperature (real64 temperature,
real64 tint)
-
+
: fTemperature (temperature)
- , fTint (tint )
-
+ , fTint (tint )
+
{
-
+
}
-
+
dng_temperature (const dng_xy_coord &xy)
-
+
: fTemperature (0.0)
- , fTint (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/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.cpp
index ab3c541e34..428b0d8618 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.cpp
@@ -1,199 +1,281 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_tile_iterator.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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;
+
+ }
+
+/*****************************************************************************/
+
+dng_tile_reverse_iterator::dng_tile_reverse_iterator (const dng_image &image,
+ const dng_rect &area)
+
+ : fTiles ()
+
+ , fIndex (0)
+
+ {
+
+ dng_tile_forward_iterator iterator (image, area);
+
+ Initialize (iterator);
+
+ }
+
+/*****************************************************************************/
+
+dng_tile_reverse_iterator::dng_tile_reverse_iterator (const dng_point &tileSize,
+ const dng_rect &area)
+
+ : fTiles ()
+
+ , fIndex (0)
+
+ {
+
+ dng_tile_forward_iterator iterator (tileSize, area);
+
+ Initialize (iterator);
+
+ }
+
+/*****************************************************************************/
+
+dng_tile_reverse_iterator::dng_tile_reverse_iterator (const dng_rect &tile,
+ const dng_rect &area)
+
+ : fTiles ()
+
+ , fIndex (0)
+
+ {
+
+ dng_tile_forward_iterator iterator (tile, area);
+
+ Initialize (iterator);
+
+ }
+
+/*****************************************************************************/
+
+bool dng_tile_reverse_iterator::GetOneTile (dng_rect &tile)
+ {
+
+ if (fIndex == 0)
+ {
+
+ return false;
+
+ }
+
+ fIndex--;
+
+ tile = fTiles [fIndex];
return true;
}
/*****************************************************************************/
+
+void dng_tile_reverse_iterator::Initialize (dng_tile_forward_iterator &iterator)
+ {
+
+ dng_rect tile;
+
+ while (iterator.GetOneTile (tile))
+ {
+
+ fTiles.push_back (tile);
+
+ }
+
+ fIndex = fTiles.size ();
+
+ }
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.h b/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.h
index ff5869be8a..58827aafbb 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tile_iterator.h
@@ -1,76 +1,128 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_tile_iterator.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
+#include <vector>
+
/*****************************************************************************/
-class dng_tile_iterator
+class dng_base_tile_iterator
{
+
+ public:
+
+ virtual ~dng_base_tile_iterator ()
+ {
+ }
- private:
+ virtual bool GetOneTile (dng_rect &tile) = 0;
+
+ };
- dng_rect fArea;
+/*****************************************************************************/
+class dng_tile_iterator: public dng_base_tile_iterator
+ {
+
+ protected:
+
+ 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);
+
+ virtual ~dng_tile_iterator ()
+ {
+ }
- bool GetOneTile (dng_rect &tile);
-
+ virtual bool GetOneTile (dng_rect &tile);
+
private:
-
+
void Initialize (const dng_rect &tile,
const dng_rect &area);
-
+
};
/*****************************************************************************/
-#endif
+typedef dng_tile_iterator dng_tile_forward_iterator;
/*****************************************************************************/
+
+class dng_tile_reverse_iterator: public dng_base_tile_iterator
+ {
+
+ public:
+
+ std::vector<dng_rect> fTiles;
+
+ size_t fIndex;
+
+ public:
+
+ dng_tile_reverse_iterator (const dng_image &image,
+ const dng_rect &area);
+
+ dng_tile_reverse_iterator (const dng_point &tileSize,
+ const dng_rect &area);
+
+ dng_tile_reverse_iterator (const dng_rect &tile,
+ const dng_rect &area);
+
+ virtual ~dng_tile_reverse_iterator ()
+ {
+ }
+
+ virtual bool GetOneTile (dng_rect &tile);
+
+ private:
+
+ void Initialize (dng_tile_iterator &iterator);
+
+ };
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.cpp
index 6cd6fe0de0..bcd274bffc 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.cpp
@@ -1,138 +1,131 @@
/*****************************************************************************/
-// Copyright 2007 Adobe Systems Incorporated
+// Copyright 2007-2019 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_3/dng_sdk/source/dng_tone_curve.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.h b/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.h
index 596113aed6..6eb6fd4475 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_tone_curve.h
@@ -1,62 +1,60 @@
/*****************************************************************************/
-// Copyright 2007 Adobe Systems Incorporated
+// Copyright 2007-2019 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_3/dng_sdk/source/dng_tone_curve.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+/** \file
+ * Representation of 1-dimensional tone curve.
+ */
/*****************************************************************************/
#ifndef __dng_tone_curve__
#define __dng_tone_curve__
/*****************************************************************************/
#include "dng_classes.h"
+#include "dng_memory.h"
#include "dng_point.h"
-#include <vector>
-
/*****************************************************************************/
class dng_tone_curve
{
-
+
public:
-
- std::vector<dng_point_real64> fCoord;
-
+
+ dng_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/core/libs/dngwriter/extra/dng_sdk/dng_types.h b/core/libs/dngwriter/extra/dng_sdk/dng_types.h
index c8915d99ae..71e8244e96 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_types.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_types.h
@@ -1,111 +1,108 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_types.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_types__
#define __dng_types__
/*****************************************************************************/
#include "dng_flags.h"
/*****************************************************************************/
// Standard integer types.
#ifdef _MSC_VER
#include <stddef.h>
-#else
-#include <stdint.h>
#endif
+#include <stdint.h>
+
/*****************************************************************************/
-#ifdef qDNGUseStdInt
+#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
/*****************************************************************************/
// Visual Studio now prefers _hypot to hypot
#ifdef _MSC_VER
#ifdef hypot
#undef hypot
#endif
#define hypot _hypot
#endif
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_uncopyable.h
similarity index 59%
copy from core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp
copy to core/libs/dngwriter/extra/dng_sdk/dng_uncopyable.h
index 031b5076df..01c0e8c389 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_globals.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_uncopyable.h
@@ -1,28 +1,41 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2012-2019 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_3/dng_sdk/source/dng_globals.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+#ifndef __dng_uncopyable__
+#define __dng_uncopyable__
/*****************************************************************************/
-#include "dng_globals.h"
+// Virtual base class to prevent object copies.
-/*****************************************************************************/
+class dng_uncopyable
+ {
+
+ protected:
-#if qDNGValidate
+ dng_uncopyable ()
+ {
+ }
-bool gVerbose = false;
+ ~dng_uncopyable ()
+ {
+ }
-uint32 gDumpLineLimit = 100;
+ private:
+
+ dng_uncopyable (const dng_uncopyable &);
+
+ dng_uncopyable & operator= (const dng_uncopyable &);
+
+ };
-#endif
+/*****************************************************************************/
+#endif // __dng_uncopyable__
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_utils.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_utils.cpp
index cb894fbf0d..5df5936be7 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_utils.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_utils.cpp
@@ -1,219 +1,888 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_utils.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
-#include "dng_point.h"
-#include "dng_rect.h"
#include "dng_utils.h"
+#include "dng_area_task.h"
#include "dng_assertions.h"
+#include "dng_bottlenecks.h"
+#include "dng_flags.h"
+#include "dng_globals.h"
+#include "dng_host.h"
+#include "dng_image.h"
+#include "dng_mutex.h"
+#include "dng_point.h"
+#include "dng_rect.h"
+#include "dng_simd_type.h"
+#include "dng_tile_iterator.h"
#if qMacOS
#include <CoreServices/CoreServices.h>
#endif
+#if qiPhone || qMacOS
+// these provide timers
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#endif
+
+#if qiPhone || qLinux
+#include <signal.h> // for raise
+#endif
+
#if qWinOS
#include <windows.h>
#else
#include <sys/time.h>
+#include <stdarg.h> // for va_start/va_end
#endif
+#include <atomic>
+
/*****************************************************************************/
#if qDNGDebug
-void dng_show_message (const char *s)
- {
-
- #if qDNGPrintMessages
-
- {
+/*****************************************************************************/
- fprintf (stderr, "%s\n", s);
+#if qMacOS
+ #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
+#elif qiPhone
+ #if qiPhoneSimulator
+ // simulator is running on Intel
+ #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
+ #else
+ // You'll be one level deeper in __kill. Works on Linux, Android too.
+ #define DNG_DEBUG_BREAK raise(SIGTRAP)
+ #endif
+#elif qWinOS
+ // DebugBreak has to be emulated on WinRT
+ #define DNG_DEBUG_BREAK DebugBreak()
+#elif qAndroid
+ #define DNG_DEBUG_BREAK raise(SIGTRAP)
+#elif qLinux
+ #define DNG_DEBUG_BREAK raise(SIGTRAP)
+#else
+ #define DNG_DEBUG_BREAK
+#endif
- }
+/*****************************************************************************/
+void dng_show_message (const char *s)
+ {
+ // only append a newline if there isn't already one
+ const char* nl = "\n";
+ if (s[0] && (s[strlen(s)-1] == '\n'))
+ nl = "";
+
+ #if qDNGPrintMessages
+
+ // display the message
+ if (gPrintAsserts)
+ fprintf (stderr, "%s%s", s, nl);
+
+ #elif qiPhone || qAndroid || qLinux
+
+ if (gPrintAsserts)
+ fprintf (stderr, "%s%s", s, nl);
+
+ // 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];
-
- strcpy (ss, s);
-
- uint32 len = strlen (ss);
-
- for (uint32 j = len + 1; j >= 1; j--)
- ss [j] = ss [j - 1];
-
- ss [0] = (char) len;
-
+
+ uint32 len = (uint32) strlen (s);
+ if (len > 255)
+ len = 255;
+ strncpy (&(ss [1]), s, len );
+ ss [0] = (unsigned char) len;
+
DebugStr ((unsigned char *) ss);
-
}
-
- #elif qWinOS
-
+ else if (gPrintAsserts)
{
-
- MessageBoxA (NULL, (LPSTR) s, NULL, MB_OK);
-
+ fprintf (stderr, "%s%s", s, nl);
}
-
+
+ #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%s", s, nl);
+
#endif
}
-#endif
-
/*****************************************************************************/
-#if qDNGDebug
-
void dng_show_message_f (const char *fmt, ... )
{
-
- char buffer [1024];
-
+
+ char buffer [2048];
+
va_list ap;
va_start (ap, fmt);
vsnprintf (buffer, sizeof (buffer), fmt, ap);
-
+
va_end (ap);
-
+
dng_show_message (buffer);
-
+
}
+/*****************************************************************************/
+
#endif
/*****************************************************************************/
-real64 TickTimeInSeconds ()
+uint32 ComputeBufferSize (uint32 pixelType,
+ const dng_point &tileSize,
+ uint32 numPlanes,
+ PaddingType paddingType)
{
- #if qWinOS
+ // Convert tile size to uint32.
+
+ if (tileSize.h < 0 || tileSize.v < 0)
+ {
+ ThrowMemoryFull ("Negative tile size");
+ }
+
+ const uint32 tileSizeH = static_cast<uint32> (tileSize.h);
+ const uint32 tileSizeV = static_cast<uint32> (tileSize.v);
+
+ const uint32 pixelSize = TagTypeSize (pixelType);
+
+ // Add padding to width if necessary.
+
+ uint32 paddedWidth = tileSizeH;
+
+ if (paddingType == padSIMDBytes)
+ {
+
+ if (!RoundUpForPixelSize (paddedWidth,
+ pixelSize,
+ &paddedWidth))
+ {
+ ThrowOverflow ("Arithmetic overflow computing buffer size");
+ }
+ }
+
+ // Compute buffer size.
+
+ uint32 bufferSize;
+
+ if (!SafeUint32Mult (paddedWidth, tileSizeV, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, pixelSize, &bufferSize) ||
+ !SafeUint32Mult (bufferSize, numPlanes, &bufferSize))
+ {
+ ThrowOverflow ("Arithmetic overflow computing buffer size");
+ }
+
+ return bufferSize;
+
+ }
+
+/*****************************************************************************/
+
+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 frequency needs to be retrieved each time.
-
+ // 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.
+ // but QPC/QPF is not tied to speed step, it's the northbridge timer.
+ // caching the invFrequency also avoids a costly divide
+
+ static real64 freqMultiplier = 0.0;
+
+ if (freqMultiplier == 0.0)
+ {
+
+ LARGE_INTEGER freq;
+
+ QueryPerformanceFrequency (&freq);
+
+ freqMultiplier = 1.0 / (real64) freq.QuadPart;
+
+ }
- LARGE_INTEGER freq;
LARGE_INTEGER cycles;
- QueryPerformanceFrequency (&freq );
- QueryPerformanceCounter (&cycles);
+ QueryPerformanceCounter (&cycles);
- return (real64) cycles.QuadPart /
- (real64) freq .QuadPart;
+ return (real64) cycles.QuadPart * freqMultiplier;
+
+ #elif qiPhone || qMacOS
+
+ // cache frequency of high-perf timer
+ 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 + tv.tv_usec / 1000000.0;
-
+ return tv.tv_sec + (real64)tv.tv_usec * 1.0e-6;
+
#endif
}
/*****************************************************************************/
real64 TickCountInSeconds ()
{
+
+ return TickTimeInSeconds ();
+
+ }
- #if qWinOS
-
- return GetTickCount () * (1.0 / 1000.0);
-
- #elif qMacOS
+/*****************************************************************************/
- return TickCount () * (1.0 / 60.0);
+static std::atomic_int sTimerLevel (0);
- #else
+/*****************************************************************************/
- return TickTimeInSeconds ();
+void DNGIncrementTimerLevel ()
+ {
+
+ // This isn't thread coherent, multiple threads can create/destroy cr_timer
+ // causing the tabbing to be invalid. Imagecore disables this.
+
+ if (!gImagecore)
+ {
+
+ sTimerLevel++;
+
+ }
+
+ }
- #endif
+/*****************************************************************************/
- }
+int32 DNGDecrementTimerLevel ()
+ {
+
+ if (gImagecore)
+ {
+
+ return 0;
+
+ }
+
+ else
+ {
+
+ return (int32) (--sTimerLevel);
+
+ }
+
+ }
/*****************************************************************************/
dng_timer::dng_timer (const char *message)
: fMessage (message )
, fStartTime (TickTimeInSeconds ())
-
+
{
+ DNGIncrementTimerLevel ();
+
}
/*****************************************************************************/
dng_timer::~dng_timer ()
{
+
+ uint32 level = Pin_int32 (0, DNGDecrementTimerLevel (), 10);
+
+ if (!gDNGShowTimers)
+ return;
real64 totalTime = TickTimeInSeconds () - fStartTime;
-
- fprintf (stderr, "%s: %0.3f sec\n", fMessage, totalTime);
-
- }
+
+ #if defined(qCRLogging) && qCRLogging && defined(cr_logi)
+
+ if (gImagecore)
+ {
+ // Imagecore force includes cr_log and overrides DNG to go to its logging under a mutex.
+ // don't use indenting or fprintf to stderr, want these buffered
+ cr_logi("timer", "%s: %0.3f sec\n", fMessage, totalTime);
+ return;
+ }
+
+ #endif
+
+ fprintf (stderr, "%*s%s: %0.3f sec\n", level*2, "", fMessage, totalTime);
+
+ }
/*****************************************************************************/
real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
const dng_rect_real64 &rect)
{
-
- real64 distSqr = DistanceSquared (point,
+
+ real64 distSqr = DistanceSquared (point,
rect.TL ());
distSqr = Max_real64 (distSqr,
- DistanceSquared (point,
+ DistanceSquared (point,
rect.BL ()));
distSqr = Max_real64 (distSqr,
- DistanceSquared (point,
+ DistanceSquared (point,
rect.BR ()));
distSqr = Max_real64 (distSqr,
- DistanceSquared (point,
+ DistanceSquared (point,
rect.TR ()));
return distSqr;
-
+
}
/*****************************************************************************/
real64 MaxDistancePointToRect (const dng_point_real64 &point,
const dng_rect_real64 &rect)
{
- return sqrt (MaxSquaredDistancePointToRect (point,
+ 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++)
+ {
+
+ // The correct math for 16 to 8-bit dither would be:
+ //
+ // y = (x * 255 + r) / 65535; (0 <= r <= 65534)
+ //
+ // The bottlnecks are using a faster approximation of
+ // this math (using a power of two for the division):
+ //
+ // y = (x * 255 + r) / 65536; (255 <= r <= 65535)
+ //
+ // To insure that all exact 8 bit values in 16 bit space
+ // round trip exactly to the same 8-bit, we need to limit
+ // r values to the range 255 to 65535.
+ //
+ // This results in the dither effect being slightly
+ // imperfect, but correct round-tripping of 8-bit values
+ // is far more important.
+
+ uint16 value;
+
+ do
+ {
+
+ seed = DNG_Random (seed);
+
+ value = (uint16) seed;
+
+ }
+ while (value < 255);
+
+ buffer [i] = value;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+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;
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+template <SIMDType simd>
+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);
+
+ };
+
+/*****************************************************************************/
+
+template <SIMDType simd>
+dng_limit_float_depth_task<simd>::dng_limit_float_depth_task
+ (const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale)
+
+ : dng_area_task ("dng_limit_float_depth_task")
+
+ , fSrcImage (srcImage)
+ , fDstImage (dstImage)
+ , fBitDepth (bitDepth)
+ , fScale (scale)
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+template <SIMDType simd>
+void dng_limit_float_depth_task<simd>::Process (uint32 /* threadIndex */,
+ const dng_rect &tile,
+ dng_abort_sniffer * /* sniffer */)
+ {
+
+ INTEL_COMPILER_NEEDED_NOTE
+
+ SET_CPU_FEATURE (simd);
+
+ 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;
+ INTEL_PRAGMA_SIMD_ASSERT_VECLEN_FLOAT(simd)
+ 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)
+ {
+
+ //start by using intrinsic __m256 _mm256_cvtph_ps (__m128i a)
+ //once the intrinsic is written, merge this branch with previous one
+
+ uint32 *dPtr2 = (uint32 *) dPtr1;
+
+ INTEL_PRAGMA_SIMD_ASSERT_VECLEN_INT32(simd)
+
+ 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;
+
+ }
+
+ }
+
+/******************************************************************************/
+
+template <SIMDType simd>
+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<simd> task (srcImage,
+ dstImage,
+ bitDepth,
+ scale);
+
+ host.PerformAreaTask (task, dstImage.Bounds ());
+
+ }
+
+/*****************************************************************************/
+
+template
+void LimitFloatBitDepth<Scalar> (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale);
+
+/*****************************************************************************/
+
+#if qDNGIntelCompiler
+
+template
+void LimitFloatBitDepth<AVX2> (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale);
+
+#endif // qDNGIntelCompiler
+
+/*****************************************************************************/
+
+void LimitFloatBitDepth (dng_host &host,
+ const dng_image &srcImage,
+ dng_image &dstImage,
+ uint32 bitDepth,
+ real32 scale)
+ {
+
+ // Kludge: Turning this off for now because the AVX2 path produces
+ // slightly different results from the Scalar routine causing a mis-match
+ // in raw digest values when building HDR merge result negatives which
+ // causes the client to display a "file appears to be damaged" warning.
+ // -bury 11/13/2017
+
+ #if (qDNGIntelCompiler && qDNGExperimental && 0)
+
+ if (gDNGMaxSIMD >= AVX2)
+ {
+
+ LimitFloatBitDepth<AVX2> (host,
+ srcImage,
+ dstImage,
+ bitDepth,
+ scale);
+
+ }
+
+ else
+
+ #endif // qDNGIntelCompiler && qDNGExperimental
+
+ {
+
+ LimitFloatBitDepth<Scalar> (host,
+ srcImage,
+ dstImage,
+ bitDepth,
+ scale);
+
+ }
+
+ }
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_utils.h b/core/libs/dngwriter/extra/dng_sdk/dng_utils.h
index 3b8611b66a..0127ac9f20 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_utils.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_utils.h
@@ -1,712 +1,1383 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_utils.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
-
-/*****************************************************************************/
-
#ifndef __dng_utils__
#define __dng_utils__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_flags.h"
+#include "dng_memory.h"
+#include "dng_safe_arithmetic.h"
#include "dng_types.h"
+#include "dng_uncopyable.h"
/*****************************************************************************/
+// The unsigned integer overflow is intended here since a wrap around is used to
+// calculate the abs() in the branchless version.
+
+DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
inline uint32 Abs_int32 (int32 x)
{
-
+
#if 0
-
+
// Reference version.
-
+
return (uint32) (x < 0 ? -x : x);
-
+
#else
-
+
// Branchless version.
-
- uint32 mask = x >> 31;
-
- return (uint32) ((x + mask) ^ mask);
-
+
+ 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) & ~1;
-
+
+ return (x + 1) & (uint32) ~1;
+
}
inline uint32 RoundUp4 (uint32 x)
{
-
- return (x + 3) & ~3;
-
+
+ return (x + 3) & (uint32) ~3;
+
}
inline uint32 RoundUp8 (uint32 x)
{
-
- return (x + 7) & ~7;
-
+
+ return (x + 7) & (uint32) ~7;
+
}
inline uint32 RoundUp16 (uint32 x)
{
+
+ return (x + 15) & (uint32) ~15;
+
+ }
- return (x + 15) & ~15;
-
+inline uint32 RoundUp32 (uint32 x)
+ {
+
+ return (x + 31) & (uint32) ~31;
+
}
-inline uint32 RoundUp4096 (uint32 x)
+inline uint32 RoundUpSIMD (uint32 x)
{
- return (x + 4095) & ~4095;
+ #if qDNGAVXSupport
+ return RoundUp32 (x);
+ #else
+ return RoundUp16 (x);
+ #endif
+
+ }
+inline uint32 RoundUp4096 (uint32 x)
+ {
+
+ return (x + 4095) & (uint32) ~4095;
+
}
/******************************************************************************/
inline uint32 RoundDown2 (uint32 x)
{
-
- return x & ~1;
-
+
+ return x & (uint32) ~1;
+
}
inline uint32 RoundDown4 (uint32 x)
{
-
- return x & ~3;
-
+
+ return x & (uint32) ~3;
+
}
inline uint32 RoundDown8 (uint32 x)
{
-
- return x & ~7;
-
+
+ return x & (uint32) ~7;
+
}
inline uint32 RoundDown16 (uint32 x)
{
+
+ return x & (uint32) ~15;
+
+ }
- return x & ~15;
+inline uint32 RoundDown32 (uint32 x)
+ {
+
+ return x & (uint32) ~31;
+
+ }
+inline uint32 RoundDownSIMD (uint32 x)
+ {
+
+ #if qDNGAVXSupport
+ return RoundDown32 (x);
+ #else
+ return RoundDown16 (x);
+ #endif
+
}
/******************************************************************************/
-inline uint32 RoundUpForPixelSize (uint32 x, uint32 pixelSize)
+inline bool RoundUpForPixelSize (uint32 x,
+ uint32 pixelSize,
+ uint32 *result)
{
+ #if qDNGAVXSupport
+ static const uint32 kTargetMultiple = 32;
+ #else
+ static const uint32 kTargetMultiple = 16;
+ #endif
+
+ uint32 multiple;
+
switch (pixelSize)
{
-
+
case 1:
- return RoundUp16 (x);
-
case 2:
- return RoundUp8 (x);
-
case 4:
- return RoundUp4 (x);
-
case 8:
- return RoundUp2 (x);
-
+ {
+ multiple = kTargetMultiple / pixelSize;
+ break;
+ }
+
default:
- return RoundUp16 (x);
+ {
+ multiple = kTargetMultiple;
+ break;
+ }
+
+ }
+
+ return RoundUpUint32ToMultiple (x, multiple, result);
+ }
+
+/******************************************************************************/
+
+inline uint32 RoundUpForPixelSize (uint32 x,
+ uint32 pixelSize)
+ {
+
+ uint32 result = 0;
+
+ if (!RoundUpForPixelSize (x, pixelSize, &result))
+ {
+ ThrowOverflow ("RoundUpForPixelSize");
}
+ return result;
+
}
/******************************************************************************/
-inline uint64 Abs_int64 (int64 x)
+inline int32 RoundUpForPixelSizeAsInt32 (uint32 x,
+ uint32 pixelSize)
+ {
+
+ uint32 result = 0;
+
+ if (!RoundUpForPixelSize (x, pixelSize, &result))
+ {
+ ThrowOverflow ("RoundUpForPixelSize");
+ }
+
+ dng_safe_uint32 safeResult (result);
+
+ return dng_safe_int32 (safeResult).Get ();
+
+ }
+
+/******************************************************************************/
+
+// Type of padding to be performed by ComputeBufferSize.
+
+enum PaddingType
{
+ // Don't perform any padding.
+
+ padNone,
+
+ // Pad each scanline to an integer multiple of SIMD vector width (16 or
+ // 32) bytes (in the same way that RoundUpForPixelSize() does).
+
+ padSIMDBytes
+
+ };
+
+// Returns the number of bytes required for an image tile with the given pixel
+// type, tile size, number of image planes, and desired padding. Throws a
+// dng_exception with dng_error_memory error code if one of the components of
+// tileSize is negative or if arithmetic overflow occurs during the
+// computation.
+
+uint32 ComputeBufferSize (uint32 pixelType,
+ const dng_point &tileSize,
+ uint32 numPlanes,
+ PaddingType paddingType);
+
+/******************************************************************************/
+
+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 Lerp_real32 (real32 a, real32 b, real32 t)
+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;
+
+ }
- return a + t * (b - a);
+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);
-
+
}
+DNG_ATTRIB_NO_SANITIZE("float-cast-overflow")
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 (x << 8) |
- (x >> 8);
-
+
+ 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)
+
+ 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
+void DNGIncrementTimerLevel ();
+
+int32 DNGDecrementTimerLevel ();
+
+/******************************************************************************/
+
+class dng_timer: private dng_uncopyable
{
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
+
+DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
+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: private dng_uncopyable
+ {
+
+ 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 ();
+
+ 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);
+
+/*****************************************************************************/
+
+#if qMacOS
+
+/*****************************************************************************/
+
+template<typename T>
+class CFReleaseHelper
+ {
+
+ private:
+
+ T fRef;
+
+ public:
+
+ CFReleaseHelper (T ref)
+ : fRef (ref)
+ {
+ }
+
+ ~CFReleaseHelper ()
+ {
+ if (fRef)
+ {
+ CFRelease (fRef);
+ }
+ }
+
+ T Get () const
+ {
+ return fRef;
+ }
+
+ };
+
+/*****************************************************************************/
+
+#endif // qMacOS
+
+/*****************************************************************************/
+
+#endif
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_validate.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_validate.cpp
index a97a5425cd..f6b71f0157 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_validate.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_validate.cpp
@@ -1,769 +1,1038 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_validate.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $Author: tknoll $ */
+// Process exit codes
+// ------------------
+//
+// As usual, 0 indicates success.
+//
+// If an exception occurs, the exit code will be equal to:
+//
+// DNG SDK error code - 100000 + 100
+//
+// For example, the error dng_error_memory, which has a DNG SDK error code of
+// 100005, is returned as an exit code of 105.
+//
+// This convention accounts for the fact that the shell truncates process exit
+// codes to 8 bits and that the exit code 1 is used by ASAN to signal that a
+// memory error occurred (so mapping the first DNG SDK error code to an exit
+// code of 1 would not be a good idea).
/*****************************************************************************/
#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.3"
-
+#define kDNGValidateVersion "1.5"
+
/*****************************************************************************/
-static uint32 gMathDataType = ttShort;
-
static bool gFourColorBayer = false;
-
+
static int32 gMosaicPlane = -1;
+static bool gIgnoreEnhanced = false;
+
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 gDumpTransparency;
+static dng_string gDumpDepthMap;
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 (true);
-
+
+ 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);
-
+
+ if (info.fEnhancedIndex != -1 && !gIgnoreEnhanced)
+ {
+
+ dng_timer timer ("Read enhanced image time");
+
+ negative->ReadEnhancedImage (host, stream, info);
+
+ }
+
+ else
{
-
+
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);
+
+ }
+
+ if (info.fDepthIndex != -1)
+ {
+
+ dng_timer timer ("Depth map read time");
+
+ negative->ReadDepthMap (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);
+
+ if (negative->Stage1Image ())
+ {
+
+ 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.
-
+
+ if (negative->Stage1Image ())
{
-
+
dng_timer timer ("Linearization time");
-
- negative->BuildStage2Image (host,
- gMathDataType);
-
+
+ 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);
-
+
+ if (negative->Stage2Image ())
+ {
+
+ const dng_image &stage2 = *negative->Stage2Image ();
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ stage2,
+ stage2.Planes () >= 3 ? piRGB
+ : piBlackIsZero);
+
+ }
+
gDumpStage2.Clear ();
-
+
}
-
+
+ // Four color Bayer option.
+
+ if (gFourColorBayer)
+ {
+ negative->SetFourColorBayer ();
+ }
+
// Build stage 3 image.
-
+
+ if (negative->Stage2Image ())
{
-
+
dng_timer timer ("Interpolate time");
-
+
negative->BuildStage3Image (host,
gMosaicPlane);
-
+
}
-
+
+ else
+ {
+
+ negative->ResizeTransparencyToMatchStage3 (host);
+
+ negative->ResizeDepthToMatchStage3 (host);
+
+ }
+
+ // 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
+ stage3.Planes () >= 3 ? piRGB
: piBlackIsZero);
-
+
gDumpStage3.Clear ();
-
+
}
-
- // Update metadata.
-
- negative->UpdateDateTimeToNow ();
+
+ if (gDumpTransparency.NotEmpty ())
+ {
+
+ if (negative->TransparencyMask ())
+ {
+
+ dng_file_stream stream2 (gDumpTransparency.Get (), true);
+
+ const dng_image &transparencyMask = *negative->TransparencyMask ();
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ transparencyMask,
+ piBlackIsZero);
+
+ }
+
+ gDumpTransparency.Clear ();
+
+ }
+
+ if (gDumpDepthMap.NotEmpty ())
+ {
+
+ if (negative->HasDepthMap ())
+ {
+
+ dng_file_stream stream2 (gDumpDepthMap.Get (), true);
+
+ const dng_image &depthMap = *negative->DepthMap ();
+
+ dng_image_writer writer;
+
+ writer.WriteTIFF (host,
+ stream2,
+ depthMap,
+ piBlackIsZero);
+
+ }
+
+ gDumpDepthMap.Clear ();
+
+ }
// Output DNG file if requested.
-
+
if (gDumpDNG.NotEmpty ())
{
-
- // Build thumbnail image.
-
- dng_image_preview thumbnail;
-
+
+ // 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_timer timer ("Build thumbnail time");
-
- dng_render render (host, *negative);
-
- render.SetFinalSpace (negative->IsMonochrome () ? dng_space_GrayGamma22::Get ()
- : dng_space_sRGB ::Get ());
-
- render.SetFinalPixelType (ttByte);
-
- render.SetMaximumSize (256);
-
- thumbnail.fImage.Reset (render.Render ());
-
- thumbnail.fInfo.fApplicationName .Set ("dng_validate");
- thumbnail.fInfo.fApplicationVersion.Set (kDNGValidateVersion);
-
- thumbnail.fInfo.fSettingsName.Set ("Default");
-
- thumbnail.fInfo.fColorSpace = thumbnail.fImage->Planes () == 1 ?
- previewColorSpace_GrayGamma22 :
- previewColorSpace_sRGB;
-
- dng_date_time_info dateTimeInfo;
-
- CurrentDateTimeAndZone (dateTimeInfo);
-
- thumbnail.fInfo.fDateTime = dateTimeInfo.Encode_ISO_8601 ();
-
+ 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_image_writer writer;
-
+
{
-
+
dng_timer timer ("Write DNG time");
-
+
+ dng_image_writer writer;
+
writer.WriteDNG (host,
stream2,
*negative.Get (),
- thumbnail,
- ccJPEG);
+ &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);
-
+ negative->GetXMP ()->RemoveProperties (XMP_NS_CRD);
+
}
-
+
// Write TIF file.
-
+
dng_file_stream stream2 (gDumpTIF.Get (), true);
-
- dng_image_writer writer;
-
+
{
-
+
dng_timer timer ("Write TIFF time");
-
+
+ dng_image_writer writer;
+
writer.WriteTIFF (host,
stream2,
*finalImage.Get (),
- finalImage->Planes () >= 3 ? piRGB
+ 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-2009 Adobe Systems, Inc.\n"
+ "Copyright 2005-2019 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"
- "-f Use floating point math\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"
- "-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"
+ "-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"
+ "-ignoreEnhanced Ignore the enhanced image IFD\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"
+ "-transparency <file> Write transparency mask to \"<file>.tif\"\n"
+ "-depthMap <file> Write depth map 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 ("f", true))
- {
- gMathDataType = ttFloat;
- }
-
+
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 ("ignoreEnhanced", true))
+ {
+ gIgnoreEnhanced = 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 ("transparency"))
+ {
+
+ gDumpTransparency.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpTransparency.Set (argv [++index]);
+ }
+
+ if (gDumpTransparency.IsEmpty () || gDumpTransparency.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -transparency\n");
+ return 1;
+ }
+
+ if (!gDumpTransparency.EndsWith (".tif"))
+ {
+ gDumpTransparency.Append (".tif");
+ }
+
+ }
+
+ else if (option.Matches ("depthMap"))
+ {
+
+ gDumpDepthMap.Clear ();
+
+ if (index + 1 < argc)
+ {
+ gDumpDepthMap.Set (argv [++index]);
+ }
+
+ if (gDumpDepthMap.IsEmpty () || gDumpDepthMap.StartsWith ("-"))
+ {
+ fprintf (stderr, "*** Missing file name after -depthMap\n");
+ return 1;
+ }
+
+ if (!gDumpDepthMap.EndsWith (".tif"))
+ {
+ gDumpDepthMap.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)
{
+
+ dng_error_code error_code = dng_validate (argv [index++]);
- if (dng_validate (argv [index++]) != dng_error_none)
+ if (error_code != dng_error_none)
{
-
- result = 1;
-
+
+ result = error_code - dng_error_unknown + 100;
+
}
-
+
}
-
+
dng_xmp_sdk::TerminateSDK ();
-
+
return result;
-
+
}
-
+
catch (...)
{
-
+
}
-
+
fprintf (stderr, "*** Exception thrown in main routine\n");
-
+
return 1;
-
+
}
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_xmp.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_xmp.cpp
index cdbc7ee58e..4622672ebc 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_xmp.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_xmp.cpp
@@ -1,3673 +1,4757 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_xmp.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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"
/*****************************************************************************/
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)
+dng_string dng_xmp::EncodeFingerprint (const dng_fingerprint &f,
+ bool allowInvalid)
{
-
+
dng_string result;
-
- if (f.IsValid ())
+
+ if (f.IsValid () || allowInvalid)
{
-
- char s [33];
-
- for (uint32 j = 0; j < 16; j++)
- {
-
- sprintf (s + j * 2,
- "%02X",
- f.data [j]);
-
- }
-
+
+ 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)
- {
-
- for (uint32 j = 0; j < 16; j++)
- {
-
- unsigned x = 0;
-
- sscanf (s.Get () + j * 2, "%02X", &x);
-
- result.data [j] = (uint8) x;
-
- }
-
- }
-
+ 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) 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",
- coord [0].n,
- coord [1].n,
- coord [2].n,
+ (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);
-
+
+ // Round to fractional seven decimal places.
+
+ uint64 y = (uint64) Round_int64 (x * 10000000.0);
+
// Split into degrees and minutes.
-
- uint32 d = y / (60 * 10000);
- uint32 m = y % (60 * 10000);
-
+
+ uint32 d = (uint32) (y / (60 * 10000000));
+ uint32 m = (uint32) (y % (60 * 10000000));
+
char min [32];
-
- sprintf (min, "%.4f", m * (1.0 / 10000.0));
+
+ sprintf (min, "%.7f", m * (1.0 / 10000000.0));
TrimDecimal (min);
-
+
sprintf (s,
"%u,%s%c",
- d,
+ (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);
-
- unsigned degrees = 0;
-
+
+ ss.NormalizeAsCommaSeparatedNumbers ();
+
+ int degrees = 0;
+
real64 minutes = 0.0;
real64 seconds = 0.0;
-
+
int count = sscanf (ss.Get (),
- "%u,%lf,%lf",
+ "%d,%lf,%lf",
&degrees,
&minutes,
&seconds);
-
- if (count < 2)
+
+ 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)
+
+ if (count <= 2)
{
- coord [1].Set_real64 (minutes, 10000);
- coord [2].Clear ();
+ coord [1].Set_real64 (minutes, 10000000);
+ coord [2] = dng_urational (0, 1);
}
else
{
coord [1].Set_real64 (minutes, 1);
- coord [2].Set_real64 (seconds, 100);
+ coord [2].Set_real64 (seconds, 100000);
}
-
+
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 (),
+
+ 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",
+ "%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) const
+ bool forJPEG,
+ bool compact) const
{
-
+
return fSDK->Serialize (fAllocator,
asPacket,
targetBytes,
padBytes,
- forJPEG);
-
+ 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::RemoveProperties (const char *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);
+
+ }
+
+ }
- fSDK->RemoveProperties (ns);
+/*****************************************************************************/
+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)
+
+ 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 preferred.
-
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
if ((options & preferNonXMP) && !isDefault)
{
-
- SetString (ns, path, s);
-
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ SetString (ns, path, s);
+
+ }
+
return false;
-
+
}
-
- // Sync 3: From XMP to non-XMP if XMP is preferred or default non-XMP.
-
+
+ // 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 & requireASCII)
+
+ if (options & removeXMP)
{
-
- if (options & preferNonXMP)
- {
-
- if (!s.IsASCII ())
- {
-
- // We prefer non-XMP, but we also require
- // ASCII and the XMP contains non-ASCII
- // characters. So keep the non-XMP as a
- // null string.
-
- s.Clear ();
-
- }
-
- }
-
- else
- {
-
- s.ForceASCII ();
-
- }
-
- }
+
+ Remove (ns, path);
+
+ }
return true;
-
+
}
-
+
}
-
+
// Sync 4: From non-XMP to XMP.
-
- if (!isDefault)
+
+ 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 preferred.
-
+
+ // 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 preferred or default non-XMP.
-
+
+ // 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);
}
/*****************************************************************************/
+void dng_xmp::SetLocalString (const char *ns,
+ const char *path,
+ const dng_local_string &s)
+ {
+
+ fSDK->SetLocalString (ns, path, s);
+
+ }
+
+/*****************************************************************************/
+
bool dng_xmp::GetAltLangDefault (const char *ns,
const char *path,
- dng_string &s) const
+ dng_string &s,
+ bool silent) const
{
+
+ return fSDK->GetAltLangDefault (ns, path, s, silent);
+
+ }
+
+/*****************************************************************************/
- return fSDK->GetAltLangDefault (ns, path, s);
+bool dng_xmp::GetLocalString (const char *ns,
+ const char *path,
+ dng_local_string &s) const
+ {
+
+ return fSDK->GetLocalString (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 preferred.
-
+
+ // 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 preferred or default non-XMP.
-
+
+ // Sync 3: From XMP to non-XMP if XMP is prefered or default non-XMP.
+
if ((options & preferXMP) || isDefault)
{
-
+
if (GetAltLangDefault (ns, path, s))
{
-
- if (options & requireASCII)
- {
-
- if (options & preferNonXMP)
- {
-
- if (!s.IsASCII ())
- {
-
- // We prefer non-XMP, but we also require
- // ASCII and the XMP contains non-ASCII
- // characters. So keep the non-XMP as a
- // null string.
-
- s.Clear ();
-
- }
-
- }
-
- else
- {
-
- s.ForceASCII ();
-
- }
-
- }
-
+
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)
+
+ 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 preferred.
-
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
if ((options & preferNonXMP) && !isDefault)
{
-
- Set_uint32 (ns, path, x);
-
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_uint32 (ns, path, x);
+
+ }
+
return;
-
+
}
-
- // Sync 3: From XMP to non-XMP if XMP is preferred or default non-XMP.
-
+
+ // 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 (!isDefault)
+
+ 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)
+
+ 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 preferred.
-
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
if ((options & preferNonXMP) && !isDefault)
{
-
- Set_urational (ns, path, r);
-
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_urational (ns, path, r);
+
+ }
+
return;
-
+
}
-
- // Sync 3: From XMP to non-XMP if XMP is preferred or default non-XMP.
-
+
+ // 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 (!isDefault)
+
+ 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)
+
+ 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 preferred.
-
+
+ // Sync 2: From non-XMP to XMP if non-XMP is prefered.
+
if ((options & preferNonXMP) && !isDefault)
{
-
- Set_srational (ns, path, r);
-
+
+ if (options & removeXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ Set_srational (ns, path, r);
+
+ }
+
return;
-
+
}
-
- // Sync 3: From XMP to non-XMP if XMP is preferred or default non-XMP.
-
+
+ // 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 (!isDefault)
+
+ 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)
+ const dng_fingerprint &print,
+ bool allowInvalid)
{
-
- dng_string s = EncodeFingerprint (print);
-
+
+ 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 >= 0 && x <= 9)
+
+ 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 ());
-
+
}
-
+
}
-
- SyncString (XMP_NS_PHOTOSHOP,
- "Author",
- iptc.fAuthor,
- options);
-
+
+ {
+
+ 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_negative &negative,
+void dng_xmp::IngestIPTC (dng_metadata &metadata,
bool xmpIsNewer)
{
-
- if (negative.IPTCLength ())
+
+ if (metadata.IPTCLength ())
{
-
+
// Parse the IPTC block.
-
+
dng_iptc iptc;
-
- iptc.Parse (negative.IPTCData (),
- negative.IPTCLength (),
- negative.IPTCOffset ());
-
- if (iptc.fForceUTF8)
- {
-
- negative.SetUsedUTF8forIPTC (true);
-
- }
-
+
+ iptc.Parse (metadata.IPTCData (),
+ metadata.IPTCLength (),
+ metadata.IPTCOffset ());
+
// Compute fingerprint of IPTC data both ways, including and
// excluding the padding data.
-
- dng_fingerprint iptcDigest1 = negative.IPTCDigest (true );
- dng_fingerprint iptcDigest2 = negative.IPTCDigest (false);
-
+
+ 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.
-
- negative.ClearIPTC ();
+
+ metadata.ClearIPTC ();
}
-
+
/*****************************************************************************/
-void dng_xmp::RebuildIPTC (dng_negative &negative,
- bool padForTIFF,
- bool forceUTF8)
+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 ())
{
-
- iptc.fForceUTF8 = forceUTF8;
-
- AutoPtr<dng_memory_block> block (iptc.Spool (negative.Allocator (),
+
+ AutoPtr<dng_memory_block> block (iptc.Spool (allocator,
padForTIFF));
-
- negative.SetIPTC (block);
-
+
+ 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", (flashState >> 1) & 3);
-
+
+ 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", (flashState >> 3) & 3);
-
+
+ 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::GenerateDefaultLensName (dng_exif &exif)
+ {
+
+ // 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);
+
+ // Don't generate exifEX for now.
+
+ // SetString (XMP_NS_EXIFEX,
+ // "LensModel",
+ // exif.fLensName);
+
}
+
+ }
+
+/*****************************************************************************/
+void dng_xmp::SyncLensName (dng_exif &exif)
+ {
+
+ // EXIF lens names are sometimes missing or wrong (esp. when non-OEM lenses
+ // are used). So prefer the value from XMP.
+
+ // Check XMP for the lens model in the aux namespace first. If not there,
+ // then check the exifEX namespace.
+
+ if (!SyncString (XMP_NS_AUX,
+ "Lens",
+ exif.fLensName,
+ preferXMP))
+ {
+
+ SyncString (XMP_NS_EXIFEX,
+ "LensModel",
+ exif.fLensName,
+ preferXMP);
+
+ }
+
+ GenerateDefaultLensName (exif);
+
}
/*****************************************************************************/
void dng_xmp::SyncExif (dng_exif &exif,
const dng_exif *originalExif,
- bool doingUpdateFromXMP)
+ bool doingUpdateFromXMP,
+ bool removeFromXMP)
{
-
+
DNG_ASSERT (!doingUpdateFromXMP || originalExif,
"Must have original EXIF if doingUpdateFromXMP");
-
+
// Default synchronization options for the read-only fields.
-
- uint32 options = doingUpdateFromXMP ? ignoreXMP
- : preferNonXMP;
-
+
+ uint32 readOnly = doingUpdateFromXMP ? ignoreXMP
+ : preferNonXMP;
+
+ // Option for removable fields.
+
+ uint32 removable = removeFromXMP ? removeXMP
+ : 0;
+
// Make:
-
+
SyncString (XMP_NS_TIFF,
"Make",
exif.fMake,
- options | requireASCII);
-
+ readOnly + removable);
+
// Model:
-
+
SyncString (XMP_NS_TIFF,
"Model",
exif.fModel,
- options | requireASCII);
-
+ 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,
- options);
-
- 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");
-
- }
-
+
+ // Find version number in XMP, if any.
+
+ uint32 xmpVersion = 0;
+
+ {
+
+ dng_string s;
+
+ if (GetString (XMP_NS_EXIF, "ExifVersion", s))
+ {
+
+ unsigned b0;
+ unsigned b1;
+ unsigned b2;
+ unsigned b3;
+
+ if (sscanf (s.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';
+
+ xmpVersion = (b0 << 24) |
+ (b1 << 16) |
+ (b2 << 8) |
+ (b3 );
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Use maximum logic for merging.
+
+ exif.fExifVersion = Max_uint32 (exif.fExifVersion, xmpVersion);
+
+ // Provide default value for ExifVersion.
+
+ if (!exif.fExifVersion)
+ {
+ exif.SetVersion0231 ();
+ }
+
+ // Update XMP.
+
+ dng_string xmpString;
+
+ 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);
+
+ xmpString.Set (s);
+
+ }
+
+ }
+
+ if (removeFromXMP || xmpString.IsEmpty ())
+ {
+
+ Remove (XMP_NS_EXIF, "ExifVersion");
+
+ }
+
+ else
+ {
+
+ SetString (XMP_NS_EXIF, "ExifVersion", xmpString);
+
+ }
+
}
-
+
// 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,
- options);
-
+ readOnly);
+
if (et.IsValid ())
{
-
+
exif.SetExposureTime (et.As_real64 (), false);
-
+
}
-
+
dng_srational ss = exif.fShutterSpeedValue;
-
+
Sync_srational (XMP_NS_EXIF,
"ShutterSpeedValue",
ss,
- options);
-
+ 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,
- options);
-
+ readOnly);
+
if (fs.IsValid ())
{
-
+
exif.SetFNumber (fs.As_real64 ());
-
+
}
-
+
dng_urational av = exif.fApertureValue;
-
+
Sync_urational (XMP_NS_EXIF,
"ApertureValue",
av,
- options);
-
+ 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,
- options);
-
+ 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++)
{
- if (exif.fISOSpeedRatings [j] == 0)
+ // 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,
- options);
+ 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");
+
+ }
+
+ }
+
}
- // ExposureIndex:
+ // 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,
- options);
-
- UpdateExifDates( exif );
-
+ readOnly + removable);
+
// Brightness Value:
-
+
Sync_srational (XMP_NS_EXIF,
"BrightnessValue",
exif.fBrightnessValue,
- options);
-
+ readOnly + removable);
+
// Exposure Bias:
-
+
Sync_srational (XMP_NS_EXIF,
"ExposureBiasValue",
exif.fExposureBiasValue,
- options);
-
+ readOnly + removable);
+
// Max Aperture:
-
+
Sync_urational (XMP_NS_EXIF,
"MaxApertureValue",
exif.fMaxApertureValue,
- options);
+ readOnly + removable);
// Subject Distance:
-
+
Sync_urational (XMP_NS_EXIF,
"SubjectDistance",
exif.fSubjectDistance,
- options);
-
+ readOnly + removable);
+
// Metering Mode:
-
+
Sync_uint32 (XMP_NS_EXIF,
"MeteringMode",
exif.fMeteringMode,
exif.fMeteringMode == 0xFFFFFFFF,
- options);
-
+ readOnly + removable);
+
// Light Source:
-
+
Sync_uint32 (XMP_NS_EXIF,
"LightSource",
exif.fLightSource,
exif.fLightSource > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Flash State:
-
+
SyncFlash (exif.fFlash,
exif.fFlashMask,
- options);
+ readOnly);
+
+ if (removeFromXMP)
+ {
+ Remove (XMP_NS_EXIF, "Flash");
+ }
// Focal Length:
-
+
Sync_urational (XMP_NS_EXIF,
"FocalLength",
exif.fFocalLength,
- options);
-
+ readOnly + removable);
+
// Sensing Method.
-
+
Sync_uint32 (XMP_NS_EXIF,
"SensingMethod",
exif.fSensingMethod,
exif.fSensingMethod > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// File Source.
-
+
Sync_uint32 (XMP_NS_EXIF,
"FileSource",
exif.fFileSource,
exif.fFileSource > 0x0FF,
- options);
-
+ readOnly + removable);
+
// Scene Type.
-
+
Sync_uint32 (XMP_NS_EXIF,
"SceneType",
exif.fSceneType,
exif.fSceneType > 0x0FF,
- options);
-
+ readOnly + removable);
+
// Focal Length in 35mm Film:
-
+
Sync_uint32 (XMP_NS_EXIF,
"FocalLengthIn35mmFilm",
exif.fFocalLengthIn35mmFilm,
exif.fFocalLengthIn35mmFilm == 0,
- options);
-
+ readOnly + removable);
+
// Custom Rendered:
-
+
Sync_uint32 (XMP_NS_EXIF,
"CustomRendered",
exif.fCustomRendered,
exif.fCustomRendered > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Exposure Mode:
-
+
Sync_uint32 (XMP_NS_EXIF,
"ExposureMode",
exif.fExposureMode,
exif.fExposureMode > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// White Balance:
-
+
Sync_uint32 (XMP_NS_EXIF,
"WhiteBalance",
exif.fWhiteBalance,
exif.fWhiteBalance > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Scene Capture Type:
-
+
Sync_uint32 (XMP_NS_EXIF,
"SceneCaptureType",
exif.fSceneCaptureType,
exif.fSceneCaptureType > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Gain Control:
-
+
Sync_uint32 (XMP_NS_EXIF,
"GainControl",
exif.fGainControl,
exif.fGainControl > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Contrast:
-
+
Sync_uint32 (XMP_NS_EXIF,
"Contrast",
exif.fContrast,
exif.fContrast > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Saturation:
-
+
Sync_uint32 (XMP_NS_EXIF,
"Saturation",
exif.fSaturation,
exif.fSaturation > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Sharpness:
-
+
Sync_uint32 (XMP_NS_EXIF,
"Sharpness",
exif.fSharpness,
exif.fSharpness > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Subject Distance Range:
-
+
Sync_uint32 (XMP_NS_EXIF,
"SubjectDistanceRange",
exif.fSubjectDistanceRange,
exif.fSubjectDistanceRange > 0x0FFFF,
- options);
-
+ readOnly + removable);
+
// Subject Area:
-
+
Sync_uint32_array (XMP_NS_EXIF,
"SubjectArea",
exif.fSubjectArea,
exif.fSubjectAreaCount,
sizeof (exif.fSubjectArea ) /
sizeof (exif.fSubjectArea [0]),
- options);
-
+ readOnly);
+
+ if (removeFromXMP)
+ {
+ Remove (XMP_NS_EXIF, "SubjectArea");
+ }
+
// Digital Zoom Ratio:
-
+
Sync_urational (XMP_NS_EXIF,
"DigitalZoomRatio",
exif.fDigitalZoomRatio,
- options);
-
+ readOnly + removable);
+
// Focal Plane Resolution:
-
+
Sync_urational (XMP_NS_EXIF,
"FocalPlaneXResolution",
exif.fFocalPlaneXResolution,
- options);
-
+ readOnly + removable);
+
Sync_urational (XMP_NS_EXIF,
"FocalPlaneYResolution",
exif.fFocalPlaneYResolution,
- options);
-
+ readOnly + removable);
+
Sync_uint32 (XMP_NS_EXIF,
"FocalPlaneResolutionUnit",
exif.fFocalPlaneResolutionUnit,
exif.fFocalPlaneResolutionUnit > 0x0FFFF,
- options);
-
- // ImageDescription: (XMP is always preferred)
-
+ readOnly + removable);
+
+ // ImageDescription: (XMP is is always preferred)
+
if (fSDK->GetAltLangDefault (XMP_NS_DC,
"description",
exif.fImageDescription))
-
+
{
-
- if (!exif.fImageDescription.IsASCII ())
- {
-
- exif.fImageDescription.Clear ();
-
- }
-
+
}
-
+
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 always preferred)
-
+
+ // 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)
{
-
- if (xmpList [0].IsASCII ())
+
+ uint32 j;
+
+ uint32 bufferSize = xmpList.Count () * 4 + 1;
+
+ for (j = 0; j < xmpList.Count (); j++)
{
-
- exif.fArtist = xmpList [0];
-
+
+ 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;
-
- newList.Append (exif.fArtist);
-
+
+ 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 always preferred)
-
+
+ // Software: (XMP is is always preferred)
+
if (fSDK->GetString (XMP_NS_XAP,
"CreatorTool",
exif.fSoftware))
-
+
{
-
- if (!exif.fSoftware.IsASCII ())
- {
-
- exif.fSoftware.Clear ();
-
- }
-
+
}
-
+
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 always preferred)
-
+
+ // Copyright: (XMP is is always preferred)
+
if (fSDK->GetAltLangDefault (XMP_NS_DC,
"rights",
exif.fCopyright))
-
+
{
-
- if (!exif.fCopyright.IsASCII ())
- {
-
- exif.fCopyright.Clear ();
-
- }
-
+
}
-
+
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,
- options | requireASCII);
-
+ 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);
-
+
}
-
+
+ // Check XMP for the lens specification in the aux namespace first. If
+ // not there, then check the exifEX namespace.
+
SyncString (XMP_NS_AUX,
"LensInfo",
s,
- options | requireASCII);
+ 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:
-
- {
-
- // Since lens names are sometimes missing or wrong, allow user to edit the
- // XMP and have the value stick. So prefer the XMP value if in conflict.
-
- SyncString (XMP_NS_AUX,
- "Lens",
- exif.fLensName,
- preferXMP);
-
- // Generate default lens name from lens info if required.
- // Ignore 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 ())
+ else
{
- char s [256];
+ // Not found in aux, so examine exifEX.
- real64 minFL = exif.fLensInfo [0].As_real64 ();
- real64 maxFL = exif.fLensInfo [1].As_real64 ();
+ dng_string_list strList;
- // The f-stop numbers are optional.
+ SyncStringList (XMP_NS_EXIFEX,
+ "LensSpecification",
+ strList,
+ false,
+ readOnly);
- if (exif.fLensInfo [2].IsValid ())
+ if (strList.Count () == 4)
{
- 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);
+ const dng_string &s0 = strList [0];
+ const dng_string &s1 = strList [1];
+ const dng_string &s2 = strList [2];
+ const dng_string &s3 = strList [3];
- else if (minFS == maxFS)
- sprintf (s, "%.1f-%.1f mm f/%.1f", minFL, maxFL, minFS);
+ unsigned n [4];
+ unsigned d [4];
- else
- sprintf (s, "%.1f-%.1f mm f/%.1f-%.1f", minFL, maxFL, minFS, maxFS);
+ if (sscanf (s0.Get (), "%u/%u", &n [0], &d [0]) == 2 &&
+ sscanf (s1.Get (), "%u/%u", &n [1], &d [1]) == 2 &&
+ sscanf (s2.Get (), "%u/%u", &n [2], &d [2]) == 2 &&
+ sscanf (s3.Get (), "%u/%u", &n [3], &d [3]) == 2)
+ {
- }
+ for (uint32 j = 0; j < 4; j++)
+ {
- else
- {
+ exif.fLensInfo [j] = dng_urational (n [j], d [j]);
- 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 name:
+
+ SyncLensName (exif);
// Lens ID:
-
+
SyncString (XMP_NS_AUX,
"LensID",
exif.fLensID,
- options);
+ readOnly);
+
+ // Lens Make:
+
+ if (!SyncString (XMP_NS_EXIF,
+ "LensMake",
+ exif.fLensMake,
+ readOnly + removable))
- // Lens Serial Number:
+ {
+ SyncString (XMP_NS_EXIFEX,
+ "LensMake",
+ exif.fLensMake,
+ readOnly + removable);
+
+ }
+
+ // Lens Serial Number:
+
SyncString (XMP_NS_AUX,
"LensSerialNumber",
exif.fLensSerialNumber,
- options);
-
+ readOnly);
+
// Image Number:
-
- Sync_uint32 (XMP_NS_AUX,
+
+ Sync_uint32 (XMP_NS_AUX,
"ImageNumber",
exif.fImageNumber,
exif.fImageNumber == 0xFFFFFFFF,
- options);
-
+ preferXMP); // CR-4197237: Preserve aux:ImageNumber in XMP when Updating Metadata
+
// 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:
- // Flash Compensation:
+ SyncApproximateFocusDistance (exif,
+ readOnly);
+
+ // LensDistortInfo:
+ {
+
+ dng_string s;
+
+ if (exif.HasLensDistortInfo ())
+ {
+
+ char ss [256];
+
+ sprintf (ss,
+ "%d/%d %d/%d %d/%d %d/%d",
+ (int) exif.fLensDistortInfo [0].n,
+ (int) exif.fLensDistortInfo [0].d,
+ (int) exif.fLensDistortInfo [1].n,
+ (int) exif.fLensDistortInfo [1].d,
+ (int) exif.fLensDistortInfo [2].n,
+ (int) exif.fLensDistortInfo [2].d,
+ (int) exif.fLensDistortInfo [3].n,
+ (int) exif.fLensDistortInfo [3].d);
+
+ s.Set (ss);
+
+ }
+
+ SyncString (XMP_NS_AUX,
+ "LensDistortInfo",
+ s,
+ readOnly);
+
+ if (s.NotEmpty ())
+ {
+
+ int n [4];
+ int d [4];
+
+ if (sscanf (s.Get (),
+ "%d/%d %d/%d %d/%d %d/%d",
+ &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.fLensDistortInfo [j] = dng_srational (n [j], d [j]);
+
+ }
+
+ }
+
+
+ }
+
+ }
+
+ // Flash Compensation:
+
Sync_srational (XMP_NS_AUX,
"FlashCompensation",
exif.fFlashCompensation,
- options);
-
- // Owner Name:
+ readOnly);
+ // Owner Name: (allow XMP updates)
+
SyncString (XMP_NS_AUX,
"OwnerName",
exif.fOwnerName,
- options);
-
+ preferXMP);
+
// Firmware:
-
+
SyncString (XMP_NS_AUX,
"Firmware",
exif.fFirmware,
- options);
-
+ readOnly);
+
// Image Unique ID:
-
+
{
-
+
dng_string s = EncodeFingerprint (exif.fImageUniqueID);
-
+
SyncString (XMP_NS_EXIF,
"ImageUniqueID",
s,
- options);
-
+ readOnly + removable);
+
exif.fImageUniqueID = DecodeFingerprint (s);
-
+
}
-
+
+ // For the following GPS related fields, we offer an option to prefer XMP to
+ // the EXIF values. This is to allow the host app to modify the XMP for manual
+ // geo-tagging and overwrite the EXIF values during export. It also allows the user
+ // to correct the GPS values via changes in a sidecar XMP file, without modifying
+ // the original GPS data recorded in the raw file by the camera.
+
+ bool preferGPSFromXMP = false;
+
+ uint32 gpsSyncOption = preferNonXMP;
+
+ #if qDNGPreferGPSMetadataFromXMP
+ preferGPSFromXMP = true;
+ #endif
+
+ // Allow EXIF GPS to be updated via updates from XMP.
+
+ if (doingUpdateFromXMP || preferGPSFromXMP)
+ {
+
+ // 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);
+
+ if (preferGPSFromXMP)
+ {
+
+ gpsSyncOption = preferXMP;
+
+ }
+ }
+
+ }
+
// GPS Version ID:
-
+
{
-
+
dng_string s = EncodeGPSVersion (exif.fGPSVersionID);
-
+
if (SyncString (XMP_NS_EXIF,
"GPSVersionID",
s,
- options))
+ gpsSyncOption + removable))
{
-
+
exif.fGPSVersionID = DecodeGPSVersion (s);
-
+
}
-
+
}
-
+
// GPS Latitude:
-
+
{
-
+
dng_string s = EncodeGPSCoordinate (exif.fGPSLatitudeRef,
exif.fGPSLatitude);
-
+
if (SyncString (XMP_NS_EXIF,
"GPSLatitude",
s,
- options))
+ gpsSyncOption + removable))
{
-
+
DecodeGPSCoordinate (s,
exif.fGPSLatitudeRef,
exif.fGPSLatitude);
-
+
}
-
+
}
-
+
// GPS Longitude:
-
+
{
-
+
dng_string s = EncodeGPSCoordinate (exif.fGPSLongitudeRef,
exif.fGPSLongitude);
-
+
if (SyncString (XMP_NS_EXIF,
"GPSLongitude",
s,
- options))
+ gpsSyncOption + 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",
- exif.fGPSAltitudeRef,
- exif.fGPSAltitudeRef == 0xFFFFFFFF,
- options);
-
+ altitudeRef,
+ altitudeRef == 0xFFFFFFFF,
+ gpsSyncOption + removable);
+
// GPS Altitude:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSAltitude",
- exif.fGPSAltitude,
- options);
-
+ altitude,
+ gpsSyncOption + removable);
+
// GPS Date/Time:
-
+
{
-
+
dng_string s = EncodeGPSDateTime (exif.fGPSDateStamp,
exif.fGPSTimeStamp);
-
+
if (SyncString (XMP_NS_EXIF,
"GPSTimeStamp",
s,
- options))
+ preferNonXMP + removable))
{
-
+
DecodeGPSDateTime (s,
exif.fGPSDateStamp,
exif.fGPSTimeStamp);
-
+
}
-
+
}
-
+
// GPS Satellites:
-
+
SyncString (XMP_NS_EXIF,
"GPSSatellites",
exif.fGPSSatellites,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Status:
SyncString (XMP_NS_EXIF,
"GPSStatus",
exif.fGPSStatus,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Measure Mode:
-
+
SyncString (XMP_NS_EXIF,
"GPSMeasureMode",
exif.fGPSMeasureMode,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS DOP:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSDOP",
exif.fGPSDOP,
- options);
-
+ preferNonXMP + removable);
+
// GPS Speed Reference:
-
+
SyncString (XMP_NS_EXIF,
"GPSSpeedRef",
exif.fGPSSpeedRef,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Speed:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSSpeed",
exif.fGPSSpeed,
- options);
-
+ preferNonXMP + removable);
+
// GPS Track Reference:
-
+
SyncString (XMP_NS_EXIF,
"GPSTrackRef",
exif.fGPSTrackRef,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Track:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSTrack",
exif.fGPSTrack,
- options);
-
+ preferNonXMP + removable);
+
// GPS Image Direction Reference:
-
+
SyncString (XMP_NS_EXIF,
"GPSImgDirectionRef",
exif.fGPSImgDirectionRef,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Image Direction:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSImgDirection",
exif.fGPSImgDirection,
- options);
-
+ preferNonXMP + removable);
+
// GPS Map Datum:
-
+
SyncString (XMP_NS_EXIF,
"GPSMapDatum",
exif.fGPSMapDatum,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Destination Latitude:
-
+
{
-
+
dng_string s = EncodeGPSCoordinate (exif.fGPSDestLatitudeRef,
exif.fGPSDestLatitude);
-
+
if (SyncString (XMP_NS_EXIF,
"GPSDestLatitude",
s,
- options))
+ 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,
- options))
+ preferNonXMP + removable))
{
-
+
DecodeGPSCoordinate (s,
exif.fGPSDestLongitudeRef,
exif.fGPSDestLongitude);
-
+
}
-
+
}
// GPS Destination Bearing Reference:
-
+
SyncString (XMP_NS_EXIF,
"GPSDestBearingRef",
exif.fGPSDestBearingRef,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Destination Bearing:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSDestBearing",
exif.fGPSDestBearing,
- options);
-
+ preferNonXMP + removable);
+
// GPS Destination Distance Reference:
-
+
SyncString (XMP_NS_EXIF,
"GPSDestDistanceRef",
exif.fGPSDestDistanceRef,
- options | requireASCII);
-
+ preferNonXMP + removable);
+
// GPS Destination Distance:
-
+
Sync_urational (XMP_NS_EXIF,
"GPSDestDistance",
exif.fGPSDestDistance,
- options);
-
+ preferNonXMP + removable);
+
// GPS Processing Method:
-
+
SyncString (XMP_NS_EXIF,
"GPSProcessingMethod",
exif.fGPSProcessingMethod,
- options);
-
+ preferNonXMP + removable);
+
// GPS Area Information:
-
+
SyncString (XMP_NS_EXIF,
"GPSAreaInformation",
exif.fGPSAreaInformation,
- options);
-
+ preferNonXMP + removable);
+
// GPS Differential:
-
+
Sync_uint32 (XMP_NS_EXIF,
"GPSDifferential",
exif.fGPSDifferential,
exif.fGPSDifferential == 0xFFFFFFFF,
- options);
-
+ preferNonXMP + removable);
+
+ // GPS Horizontal Positioning Error:
+
+ Sync_urational (XMP_NS_EXIF,
+ "GPSHPositioningError",
+ exif.fGPSHPositioningError,
+ preferNonXMP + removable);
+
+ // Sync date/times.
+
+ UpdateExifDates (exif, removeFromXMP);
+
+ // EXIF 2.3.1 tags.
+
+ Sync_srational (XMP_NS_EXIFEX,
+ "Temperature",
+ exif.fTemperature,
+ readOnly + removable);
+
+ Sync_urational (XMP_NS_EXIFEX,
+ "Humidity",
+ exif.fHumidity,
+ readOnly + removable);
+
+ Sync_urational (XMP_NS_EXIFEX,
+ "Pressure",
+ exif.fPressure,
+ readOnly + removable);
+
+ Sync_srational (XMP_NS_EXIFEX,
+ "WaterDepth",
+ exif.fWaterDepth,
+ readOnly + removable);
+
+ Sync_urational (XMP_NS_EXIFEX,
+ "Acceleration",
+ exif.fAcceleration,
+ readOnly + removable);
+
+ Sync_srational (XMP_NS_EXIFEX,
+ "CameraElevationAngle",
+ exif.fCameraElevationAngle,
+ readOnly + removable);
+
// 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");
-
+
+ // Fake EXIF fields.
+
+ SyncAltLangDefault (XMP_NS_DC,
+ "title",
+ exif.fTitle,
+ preferXMP);
+
}
-/******************************************************************************/
+/*****************************************************************************/
+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");
-
+
}
-
+
/******************************************************************************/
-void dng_xmp::UpdateExifDates (dng_exif &exif)
- {
-
- // 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.
-
- // DateTime:
-
- {
-
- dng_string s = exif.fDateTime.Encode_ISO_8601 ();
-
- SyncString (XMP_NS_TIFF,
- "DateTime",
- s,
- preferXMP);
-
- if (s.NotEmpty ())
- {
-
- exif.fDateTime.Decode_ISO_8601 (s.Get ());
-
- }
-
- }
-
- // DateTimeOriginal:
-
- {
-
- dng_string s = exif.fDateTimeOriginal.Encode_ISO_8601 ();
-
- SyncString (XMP_NS_EXIF,
- "DateTimeOriginal",
- s,
- preferXMP);
-
- if (s.NotEmpty ())
- {
-
- exif.fDateTimeOriginal.Decode_ISO_8601 (s.Get ());
-
- // If the XAP create date is missing or empty, set it to the
- // DateTimeOriginal value.
-
- dng_string ss;
-
- if (!GetString (XMP_NS_XAP, "CreateDate", ss) || ss.IsEmpty ())
- {
-
- SetString (XMP_NS_XAP, "CreateDate", s);
-
- }
-
- }
-
- }
-
- // Date Time Digitized:
+void dng_xmp::SyncExifDate (const char *ns,
+ const char *path,
+ dng_date_time_info &exifDateTime,
+ bool canRemoveFromXMP,
+ bool removeFromXMP,
+ const dng_time_zone &fakeTimeZone)
+ {
+
+ dng_string s;
+
+ // Find information on XMP side.
+
+ dng_date_time_info xmpDateTime;
+
+ if (GetString (ns, path, s))
+ {
+
+ if (s.IsEmpty ())
+ {
+
+ // XMP contains an NULL string. Clear EXIF date,
+ // and remove XMP tag if possible.
+
+ exifDateTime.Clear ();
+
+ if (canRemoveFromXMP && removeFromXMP)
+ {
+ Remove (ns, path);
+ }
+
+ return;
+
+ }
+
+ xmpDateTime.Decode_ISO_8601 (s.Get ());
+
+ // If the time zone matches the fake time zone,
+ // ignore it on the XMP side.
+
+ if (fakeTimeZone.IsValid () &&
+ xmpDateTime.TimeZone ().IsValid () &&
+ xmpDateTime.TimeZone ().OffsetMinutes () == fakeTimeZone.OffsetMinutes ())
+ {
+
+ xmpDateTime.ClearZone ();
+
+ }
+
+ }
+
+ // If both are valid, we need to resolve.
+
+ if (exifDateTime.IsValid () && xmpDateTime.IsValid ())
+ {
+
+ // Kludge: The Nikon D4 is writing date only date/times into XMP, so
+ // prefer the EXIF values if the XMP only contains a date.
+
+ if (xmpDateTime.IsDateOnly ())
+ {
+
+ xmpDateTime = exifDateTime;
+
+ }
+
+ // Kludge: Nikon sometimes writes XMP values without a time zone
+ // but the EXIF contains a valid time zone. So in that case,
+ // prefer the EXIF. This case also deals with sidecar files
+ // created by pre-Exif 2.3.1 aware cr_sdk versions.
+
+ else if (exifDateTime.DateTime () == xmpDateTime.DateTime () &&
+ exifDateTime.TimeZone ().IsValid () &&
+ !xmpDateTime.TimeZone ().IsValid ())
+ {
+
+ xmpDateTime = exifDateTime;
+
+ }
+
+ // Else assume that XMP is correct.
+
+ else
+ {
+
+ exifDateTime = xmpDateTime;
+
+ }
+
+ }
+
+ // Else just pick the valid one.
+
+ else if (xmpDateTime.IsValid ())
+ {
+
+ exifDateTime = xmpDateTime;
+
+ }
+
+ else if (exifDateTime.IsValid ())
+ {
+
+ xmpDateTime = exifDateTime;
+
+ }
+
+ // Else nothing is valid.
+
+ else
+ {
+
+ // Remove XMP side, if any.
+
+ Remove (ns, path);
+
+ return;
+
+ }
+
+ // Should we just remove the XMP version?
+
+ if (canRemoveFromXMP && removeFromXMP)
+ {
+
+ Remove (ns, path);
+
+ }
+
+ else
+ {
+
+ s = exifDateTime.Encode_ISO_8601 ();
+
+ SetString (ns, path, s);
+
+ }
+
+ }
+/******************************************************************************/
+
+void dng_xmp::UpdateExifDates (dng_exif &exif,
+ bool removeFromXMP)
+ {
+
+ // Kludge: Early versions of the XMP library did not support date
+ // encodings without explict time zones, so software had to fill in
+ // fake time zones on the XMP side. The usual way was to fill in
+ // local time zone for the date/time at the import location.
+ // Attempt to detect these cases and ignore the fake time zones.
+
+ dng_time_zone fakeTimeZone; // Initialized to invalid
+
+ if (!exif.AtLeastVersion0231 ()) // Real time zones supported in EXIF 2.3.1
+ {
+
+ // Look at DateTimeOriginal since it an EXIF only field (not aliased
+ // to other fields in XMP)
+
+ dng_string s;
+
+ if (GetString (XMP_NS_EXIF, "DateTimeOriginal", s) && s.NotEmpty ())
+ {
+
+ dng_date_time_info xmpDateTimeOriginal;
+
+ xmpDateTimeOriginal.Decode_ISO_8601 (s.Get ());
+
+ // If this field has a time zone in XMP, it can only
+ // be fake.
+
+ if (xmpDateTimeOriginal.TimeZone ().IsValid ())
+ {
+
+ fakeTimeZone = xmpDateTimeOriginal.TimeZone ();
+
+ }
+
+ }
+
+ }
+
+ // For the following three date/time fields, we generally 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.
+
+ // Modification Date/Time:
+ // exif.fDateTime
+ // kXMP_NS_XMP:"ModifyDate" & kXMP_NS_TIFF:"DateTime" are aliased
+
+ SyncExifDate (XMP_NS_TIFF,
+ "DateTime",
+ exif.fDateTime,
+ false, // Cannot remove because aliased
+ removeFromXMP,
+ fakeTimeZone);
+
+ // 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.fDateTimeDigitized.Encode_ISO_8601 ();
-
- SyncString (XMP_NS_EXIF,
- "DateTimeDigitized",
- s,
- preferXMP);
-
- if (s.NotEmpty ())
- {
-
- exif.fDateTimeDigitized.Decode_ISO_8601 (s.Get ());
-
- }
-
+
+ SyncExifDate (XMP_NS_EXIF,
+ "DateTimeOriginal",
+ exif.fDateTimeOriginal,
+ true,
+ removeFromXMP,
+ fakeTimeZone);
+
+ // Sync the IPTC value to the EXIF value if only the EXIF
+ // value exists.
+
+ if (exif.fDateTimeOriginal.IsValid ())
+ {
+
+ // See if the fake time zone was cloned into DateCreated
+ // field.
+
+ bool forceUpdate = false;
+
+ if (fakeTimeZone.IsValid ())
+ {
+
+ dng_string s;
+
+ if (GetString (XMP_NS_PHOTOSHOP, "DateCreated", s) && s.NotEmpty ())
+ {
+
+ dng_date_time_info info;
+
+ info.Decode_ISO_8601 (s.Get ());
+
+ if (info.DateTime () == exif.fDateTimeOriginal.DateTime ())
+ {
+
+ forceUpdate = true;
+
+ }
+
+ }
+
+ }
+
+ if (!Exists (XMP_NS_PHOTOSHOP, "DateCreated") || forceUpdate)
+ {
+
+ dng_string s = exif.fDateTimeOriginal.Encode_ISO_8601 ();
+
+ SetString (XMP_NS_PHOTOSHOP, "DateCreated", s);
+
+ }
+
+ }
+
}
-
+
+ // Date Time Digitized:
+ // XMP_NS_EXIF:"DateTimeDigitized" & kXMP_NS_XMP:"CreateDate" are aliased
+
+ SyncExifDate (XMP_NS_EXIF,
+ "DateTimeDigitized",
+ exif.fDateTimeDigitized,
+ false, // Cannot remove because aliased
+ removeFromXMP,
+ fakeTimeZone);
+
}
/******************************************************************************/
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 || !negative.HasBaseOrientation ()))
+
+ if (xmpHasOrientation && (xmpIsMaster || !metadata.HasBaseOrientation ()))
{
-
- negative.SetBaseOrientation (GetOrientation ());
-
+
+ metadata.SetBaseOrientation (GetOrientation ());
+
}
-
+
else
{
-
- SetOrientation (negative.BaseOrientation ());
-
+
+ SetOrientation (metadata.BaseOrientation ());
+
}
}
-
+
/******************************************************************************/
-void dng_xmp::ClearItemInfo ()
+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", bitsPerSample);
-
+
+ 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 *srcMIME)
+ {
+
+ fSDK->DocOpsOpenXMP (srcMIME);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DocOpsPrepareForSave (const char *srcMIME,
+ const char *dstMIME,
+ bool newPath)
+ {
+
+ fSDK->DocOpsPrepareForSave (srcMIME,
+ dstMIME,
+ newPath);
+
+ }
+
+/*****************************************************************************/
+
+void dng_xmp::DocOpsUpdateMetadata (const char *srcMIME)
+ {
+
+ fSDK->DocOpsUpdateMetadata (srcMIME);
+
+ }
+
+/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_xmp.h b/core/libs/dngwriter/extra/dng_sdk/dng_xmp.h
index 4e210a1fd1..35a39aab85 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_xmp.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_xmp.h
@@ -1,348 +1,425 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_xmp.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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
- requireASCII = 8 // Non-XMP values must be ASCII
- };
-
+ 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;
+
+ dng_memory_allocator & Allocator () const
+ {
+ return fAllocator;
+ }
+
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) const;
-
+ 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 RequireMeta ()
+ {
+ fSDK->RequireMeta ();
+ }
+
+ 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);
-
+ 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);
+ void SetLocalString (const char *ns,
+ const char *path,
+ const dng_local_string &s);
+
bool GetAltLangDefault (const char *ns,
const char *path,
- dng_string &s) const;
-
+ dng_string &s,
+ bool silent = false) const;
+
+ bool GetLocalString (const char *ns,
+ const char *path,
+ dng_local_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);
-
+ 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 IngestIPTC (dng_negative &negative,
+
+ void ClearIPTCDigest ();
+
+ void IngestIPTC (dng_metadata &metadata,
bool xmpIsNewer = false);
-
- void RebuildIPTC (dng_negative &negative,
- bool padForTIFF,
- bool forceUTF8);
-
+
+ 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 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);
-
+ 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);
-
- void ClearItemInfo ();
-
+ // 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);
-
+ 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 *srcMIME);
+
+ void DocOpsPrepareForSave (const char *srcMIME,
+ const char *dstMIME,
+ bool newPath = true);
+
+ void DocOpsUpdateMetadata (const char *srcMIME);
+
+ #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);
+
+ void SyncExifDate (const char *ns,
+ const char *path,
+ dng_date_time_info &exifDateTime,
+ bool canRemoveFromXMP,
+ bool removeFromXMP,
+ const dng_time_zone &fakeTimeZone);
+
+ virtual void SyncApproximateFocusDistance (dng_exif &exif,
+ const uint32 readOnly);
+
+ virtual void SyncLensName (dng_exif &exif);
+
+ virtual void GenerateDefaultLensName (dng_exif &exif);
private:
-
+
// Hidden assignment operator.
dng_xmp & operator= (const dng_xmp &xmp);
-
+
};
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.cpp
index 6b1b3d1b34..c31795fdb0 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.cpp
@@ -1,1364 +1,1846 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_xmp_sdk.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_local_string.h"
#include "dng_memory.h"
#include "dng_string.h"
#include "dng_string_list.h"
#include "dng_utils.h"
/*****************************************************************************/
#if qMacOS
#ifndef MAC_ENV
#define MAC_ENV 1
#endif
#endif
#if qWinOS
#ifndef WIN_ENV
#define WIN_ENV 1
#endif
#endif
#include <new>
#include <string>
-#ifdef _MSC_VER
-#pragma warning ( disable : 4267 ) // possible loss of data
-#endif
-
#define TXMP_STRING_TYPE std::string
-#include "XMP.incl_cpp"
+#define XMP_INCLUDE_XMPFILES qDNGXMPFiles
+
+#define XMP_StaticBuild 1
+
+#if qiPhone
+#undef UNIX_ENV
+#endif
-using namespace DngXmpSdk;
+#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_EXIFEX = "http://cipa.jp/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_CRD = "http://ns.adobe.com/camera-raw-defaults/1.0/";
+
+const char *XMP_NS_LCP = "http://ns.adobe.com/photoshop/1.0/camera-profile";
+
const char *XMP_NS_AUX = "http://ns.adobe.com/exif/1.0/aux/";
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/";
+
+const char *XMP_NS_PANO = "http://ns.adobe.com/photoshop/1.0/panorama-profile";
+
/******************************************************************************/
-#define CATCH_XMP(routine, fatal)\
+#define CATCH_XMP_ALT(routine, fatal, silent)\
\
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);\
+ if (!silent)\
+ {\
+ 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 ();\
}
+#define CATCH_XMP(routine, fatal) CATCH_XMP_ALT(routine, fatal, false)
+
/*****************************************************************************/
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);
-
+
+ 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)
+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]
-
+ // We no longer read this, but we do need to register
+ // it so we can clean up this namespace when saving
+ // new settings.
+
{
-
+
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 CRD defaults namespace
+
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (XMP_NS_CRD,
+ "crd",
+ &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 panorama metadata namespace
+
+ {
+
+ TXMP_STRING_TYPE ss;
+
+ SXMPMeta::RegisterNamespace (XMP_NS_PANO,
+ "panorama",
+ &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 || qAndroid
+ 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 ns;
+
+ TXMP_STRING_TYPE nsTemp;
TXMP_STRING_TYPE prop;
-
- if (iter.Next (&ns,
+
+ 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,
+
+ 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)
-
+
+ catch (...)
+ {
+
+ // Array is probably bogus. Don't need to report.
+
+ }
+
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)
-
+
+ CATCH_XMP ("GetStringList", false)
+
}
-
+
return result;
-
+
}
-
+
/*****************************************************************************/
bool dng_xmp_sdk::GetAltLangDefault (const char *ns,
const char *path,
- dng_string &s) const
+ dng_string &s,
+ bool silent) 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_ALT ("GetLocalizedText", false, silent)
+
+ }
+
+ return result;
+
+ }
+
+/*****************************************************************************/
- CATCH_XMP ("GetLocalizedText", false)
+bool dng_xmp_sdk::GetLocalString (const char *ns,
+ const char *path,
+ dng_local_string &s) const
+ {
- }
+ dng_string defaultText;
- return result;
+ if (GetAltLangDefault (ns, path, defaultText, true))
+ {
- }
+ s.SetDefaultText (defaultText);
+
+ try
+ {
+
+ int32 count = CountArrayItems (ns, path);
+
+ if (count > 1)
+ {
+
+ for (int32 index = 1; index <= count; index++)
+ {
+
+ dng_string arrayItemPath;
+
+ ComposeArrayItemPath (ns,
+ path,
+ index + 1,
+ arrayItemPath);
+
+ TXMP_STRING_TYPE langS;
+
+ if (fPrivate->fMeta->GetQualifier (ns,
+ arrayItemPath.Get (),
+ kXMP_NS_XML,
+ "lang",
+ &langS,
+ NULL))
+ {
+
+ dng_string language;
+
+ language.Set (langS.c_str ());
+
+ if (language.IsEmpty () ||
+ language.Matches ("x-default"))
+ {
+ continue;
+ }
+
+ TXMP_STRING_TYPE tranS;
+
+ if (fPrivate->fMeta->GetProperty (ns,
+ arrayItemPath.Get (),
+ &tranS,
+ NULL))
+ {
+
+ dng_string translation;
+
+ translation.Set (tranS.c_str ());
+
+ s.AddTranslation (language,
+ translation);
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ CATCH_XMP ("GetLocalString", false)
+
+ return true;
+
+ }
+
+ return false;
+
+ }
+
/*****************************************************************************/
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::SetLocalString (const char *ns,
+ const char *path,
+ const dng_local_string &s)
+ {
+
+ SetAltLangDefault (ns, path, s.DefaultText ());
+
+ try
+ {
+ for (uint32 index = 0; index < s.TranslationCount (); index++)
+ {
+
+ dng_string arrayItemPath;
+
+ ComposeArrayItemPath (ns,
+ path,
+ index + 2,
+ arrayItemPath);
+
+ fPrivate->fMeta->SetProperty (ns,
+ arrayItemPath.Get (),
+ s.Translation (index).Get ());
+
+ fPrivate->fMeta->SetQualifier (ns,
+ arrayItemPath.Get (),
+ kXMP_NS_XML,
+ "lang",
+ s.Language (index).Get (),
+ 0);
+
+ }
+
+ }
+
+ 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) const
+ bool forJPEG,
+ bool compact) const
{
-
- // The largest XMP packet you can embed in JPEG using normal methods:
-
+
+ // 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;
-
- uint32 formatOption = forJPEG ? kXMP_UseCompactFormat : 0;
-
+
+ // 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::AppendXMP (const dng_xmp_sdk *xmp)
- {
-
- if (xmp && xmp->HasMeta ())
- {
-
- NeedMeta ();
-
- try
- {
-
- SXMPUtils::AppendProperties (*xmp->fPrivate->fMeta,
- fPrivate->fMeta,
- kXMPUtil_DoAllProperties |
- kXMPUtil_ReplaceOldValues);
-
- }
-
- CATCH_XMP ("AppendProperties", 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 *srcMIME)
+ {
+
+ if (srcMIME [0])
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPDocOps docOps;
+
+ docOps.OpenXMP (fPrivate->fMeta,
+ srcMIME);
+
}
+
+ CATCH_XMP ("DocOpsOpenXMP", false)
+
+ Set (XMP_NS_DC,
+ "format",
+ srcMIME);
+
+ }
+
+ }
- CATCH_XMP ("IteratePaths", true)
+/*****************************************************************************/
+void dng_xmp_sdk::DocOpsPrepareForSave (const char *srcMIME,
+ const char *dstMIME,
+ bool newPath)
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPDocOps docOps;
+
+ docOps.OpenXMP (fPrivate->fMeta,
+ srcMIME,
+ "old path");
+
+ docOps.NoteChange (kXMP_Part_All);
+
+ docOps.PrepareForSave (dstMIME,
+ newPath ? "new path" : "old path");
+
}
+
+ CATCH_XMP ("DocOpsPrepareForSave", false)
+
+ Set (XMP_NS_DC,
+ "format",
+ dstMIME);
+
+ }
- return true;
+/*****************************************************************************/
+void dng_xmp_sdk::DocOpsUpdateMetadata (const char *srcMIME)
+ {
+
+ NeedMeta ();
+
+ try
+ {
+
+ SXMPDocOps docOps;
+
+ docOps.OpenXMP (fPrivate->fMeta,
+ srcMIME);
+
+ docOps.NoteChange (kXMP_Part_Metadata);
+
+ docOps.PrepareForSave (srcMIME);
+
+ }
+
+ CATCH_XMP ("DocOpsUpdateMetadata", false)
+
}
/*****************************************************************************/
+
+#endif
+
+/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.h b/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.h
index 2702e39de6..539250a1a0 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_xmp_sdk.h
@@ -1,211 +1,249 @@
/*****************************************************************************/
-// Copyright 2006-2008 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_xmp_sdk.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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_EXIFEX;
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_CRD;
+
+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;
+
+extern const char *XMP_NS_PANO;
+
/*****************************************************************************/
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);
-
+
+ static void InitializeSDK (dng_xmp_namespace * extraNamespaces = NULL,
+ const char *software = NULL);
+
static void TerminateSDK ();
-
+
bool HasMeta () const;
+ void RequireMeta ()
+ {
+ NeedMeta ();
+ }
+
+ 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);
-
+ 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;
-
+ dng_string &s,
+ bool silent = false) const;
+
+ bool GetLocalString (const char *ns,
+ const char *path,
+ dng_local_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 SetLocalString (const char *ns,
+ const char *path,
+ const dng_local_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) const;
-
+ 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 AppendXMP (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 *srcMIME);
+
+ void DocOpsPrepareForSave (const char *srcMIME,
+ const char *dstMIME,
+ bool newPath = true);
+
+ void DocOpsUpdateMetadata (const char *srcMIME);
+
+ #endif
+
private:
void ClearMeta ();
void MakeMeta ();
void NeedMeta ();
-
+
// Hidden assignment operator.
-
+
dng_xmp_sdk & operator= (const dng_xmp_sdk &sdk);
};
-
+
/*****************************************************************************/
#endif
-
+
/*****************************************************************************/
diff --git a/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.cpp b/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.cpp
index 0680ac7499..3eeddb5cc2 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.cpp
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.cpp
@@ -1,89 +1,82 @@
/*****************************************************************************/
-// Copyright 2006-2007 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_xy_coord.cpp#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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);
-
+ 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);
-
+ 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/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.h b/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.h
index 8adcbcad2c..4c5a64df18 100644
--- a/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.h
+++ b/core/libs/dngwriter/extra/dng_sdk/dng_xy_coord.h
@@ -1,183 +1,182 @@
/*****************************************************************************/
-// Copyright 2006 Adobe Systems Incorporated
+// Copyright 2006-2019 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_3/dng_sdk/source/dng_xy_coord.h#1 $ */
-/* $DateTime: 2009/06/22 05:04:49 $ */
-/* $Change: 578634 $ */
-/* $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/core/libs/dngwriter/extra/md5/XMP_MD5.cpp b/core/libs/dngwriter/extra/md5/XMP_MD5.cpp
index 752ddd1f01..fd6720f9f6 100644
--- a/core/libs/dngwriter/extra/md5/XMP_MD5.cpp
+++ b/core/libs/dngwriter/extra/md5/XMP_MD5.cpp
@@ -1,327 +1,327 @@
#include "XMP_MD5.h"
#include <cassert>
#include <cstring>
using namespace std;
/******************************************************************************/
/*
MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights
+ 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.
+ 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.
*/
/******************************************************************************/
/* Constants for MD5Transform routine. */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
-static void MD5Transform (unsigned long [4], unsigned char [64]);
-static void Encode (unsigned char *, unsigned long *, unsigned int);
-static void Decode (unsigned long *, unsigned char *, unsigned int);
+static void MD5Transform (XMP_Uns32 [4], XMP_Uns8 [64]);
+static void Encode (XMP_Uns8 *, XMP_Uns32 *, XMP_Uns32);
+static void Decode (XMP_Uns32 *, XMP_Uns8 *, XMP_Uns32);
-static unsigned char PADDING[64] =
+static XMP_Uns8 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
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) += F ((b), (c), (d)) + (x) + (XMP_Uns32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) += G ((b), (c), (d)) + (x) + (XMP_Uns32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) += H ((b), (c), (d)) + (x) + (XMP_Uns32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (unsigned long)(ac); \
+ (a) += I ((b), (c), (d)) + (x) + (XMP_Uns32)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (MD5_CTX * context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the context.
*/
void MD5Update ( MD5_CTX *context, /* context */
- unsigned char *input, /* input block */
- unsigned int inputLen) /* length of input block */
+ XMP_Uns8 *input, /* input block */
+ XMP_Uns32 inputLen) /* length of input block */
{
using namespace std;
- unsigned int i, index, partLen;
+ XMP_Uns32 i, index, partLen;
/* Compute number of bytes mod 64 */
- index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+ index = (XMP_Uns32)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
- if ((context->count[0] += ((unsigned long)inputLen << 3))
- < ((unsigned long)inputLen << 3))
+ if ((context->count[0] += ((XMP_Uns32)inputLen << 3))
+ < ((XMP_Uns32)inputLen << 3))
context->count[1]++;
- context->count[1] += ((unsigned long)inputLen >> 29);
+ context->count[1] += ((XMP_Uns32)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
std::memcpy (&context->buffer[index], input, partLen); // AUDIT: From public MD5 code, assumed safe.
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
std::memcpy (&context->buffer[index], &input[i], inputLen-i); // AUDIT: From public MD5 code, assumed safe.
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
-void MD5Final ( unsigned char digest[16], /* message digest */
+void MD5Final ( XMP_Uns8 digest[16], /* message digest */
MD5_CTX *context /* context */)
{
- unsigned char bits[8];
- unsigned int index, padLen;
+ XMP_Uns8 bits[8];
+ XMP_Uns32 index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
- index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ index = (XMP_Uns32)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
assert ( sizeof(*context) == sizeof(MD5_CTX) );
memset ( context, 0, sizeof (*context) ); // AUDIT: Safe, using sizeof destination.
}
/* MD5 basic transformation. Transforms state based on block.
*/
-static void MD5Transform ( unsigned long state[4],
- unsigned char block[64])
+static void MD5Transform ( XMP_Uns32 state[4],
+ XMP_Uns8 block[64])
{
- unsigned long a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+ XMP_Uns32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* 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;
/* Zeroize sensitive information.
*/
memset (x, 0, sizeof (x));
}
-/* Encodes input (unsigned long) into output (unsigned char). Assumes len is
+/* Encodes input (XMP_Uns32) into output (XMP_Uns8). Assumes len is
a multiple of 4.
*/
-static void Encode ( unsigned char *output,
- unsigned long *input,
- unsigned int len)
+static void Encode ( XMP_Uns8 *output,
+ XMP_Uns32 *input,
+ XMP_Uns32 len)
{
- unsigned int i, j;
+ XMP_Uns32 i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ output[j] = (XMP_Uns8)(input[i] & 0xff);
+ output[j+1] = (XMP_Uns8)((input[i] >> 8) & 0xff);
+ output[j+2] = (XMP_Uns8)((input[i] >> 16) & 0xff);
+ output[j+3] = (XMP_Uns8)((input[i] >> 24) & 0xff);
}
}
-/* Decodes input (unsigned char) into output (unsigned long). Assumes len is
+/* Decodes input (XMP_Uns8) into output (XMP_Uns32). Assumes len is
a multiple of 4.
*/
-static void Decode ( unsigned long *output,
- unsigned char *input,
- unsigned int len)
+static void Decode ( XMP_Uns32 *output,
+ XMP_Uns8 *input,
+ XMP_Uns32 len)
{
- unsigned int i, j;
+ XMP_Uns32 i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((unsigned long)input[j]) | (((unsigned long)input[j+1]) << 8) |
- (((unsigned long)input[j+2]) << 16) | (((unsigned long)input[j+3]) << 24);
+ output[i] = ((XMP_Uns32)input[j]) | (((XMP_Uns32)input[j+1]) << 8) |
+ (((XMP_Uns32)input[j+2]) << 16) | (((XMP_Uns32)input[j+3]) << 24);
}
diff --git a/core/libs/dngwriter/extra/md5/XMP_MD5.h b/core/libs/dngwriter/extra/md5/XMP_MD5.h
index 0332cb09b7..056eaf3dbe 100644
--- a/core/libs/dngwriter/extra/md5/XMP_MD5.h
+++ b/core/libs/dngwriter/extra/md5/XMP_MD5.h
@@ -1,46 +1,48 @@
#ifndef __MD5_h__
#define __MD5_h__
/******************************************************************************/
/*
MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights
+ 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.
+ 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.
*/
/******************************************************************************/
+#include "XMP_Const.h" // For safe fixed integer sizes.
+
/* MD5 context. */
struct MD5_CTX
{
- unsigned long state[4]; /* state (ABCD) */
- unsigned long count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
+ XMP_Uns32 state[4]; /* state (ABCD) */
+ XMP_Uns32 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ XMP_Uns8 buffer[64]; /* input buffer */
};
extern void MD5Init (MD5_CTX *);
-extern void MD5Update (MD5_CTX *, unsigned char *, unsigned int);
-extern void MD5Final(unsigned char [16], MD5_CTX *);
+extern void MD5Update (MD5_CTX *, XMP_Uns8 *, XMP_Uns32);
+extern void MD5Final(XMP_Uns8 [16], MD5_CTX *);
/******************************************************************************/
#endif
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/ExpatAdapter.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/ExpatAdapter.cpp
deleted file mode 100644
index ffdad54219..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/ExpatAdapter.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
-// =================================================================================================
-// Copyright 2005-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.
-// =================================================================================================
-
-#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;
-
-namespace DngXmpSdk {
-#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()
-{
- return new ExpatAdapter;
-} // XMP_NewExpatAdapter
-
-// =================================================================================================
-
-ExpatAdapter::ExpatAdapter() : parser(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_Throw ( "Failure creating Expat parser", kXMPErr_ExternalFailure );
-
- 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;
-
-} // 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_Throw ( "DOCTYPE is not allowed", kXMPErr_BadXML );
- #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_Throw ( errMsg, kXMPErr_BadXML );
-
- }
-
-} // 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 ( 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 = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &prefixLen );
- if ( ! found ) XMP_Throw ( "Unknown URI in Expat full name", kXMPErr_ExternalFailure );
- 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.
-
- #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning.
- ExpatAdapter * thiz = (ExpatAdapter*)userData;
- #endif
-
- 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) XMPMeta::RegisterNamespace ( uri, prefix, &voidStringPtr, &voidStringLen );
-
-} // 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_Throw ( "Expat attribute info has odd length", kXMPErr_ExternalFailure );
- 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 ( 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 ( 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
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/ParseRDF.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/ParseRDF.cpp
deleted file mode 100644
index 11aae73396..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/ParseRDF.cpp
+++ /dev/null
@@ -1,1344 +0,0 @@
-// =================================================================================================
-// 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.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "ExpatAdapter.hpp"
-
-#include <cstring>
-
-#if DEBUG
- #include <iostream>
-#endif
-
-using namespace std;
-
-namespace DngXmpSdk {
-#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.
-
-static void
-RDF_RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode );
-
-static void
-RDF_NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
-
-static void
-RDF_NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
-enum { kIsTopLevel = true, kNotTopLevel = false };
-
-static void
-RDF_PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-static void
-RDF_EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
-
-
-// =================================================================================================
-
-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 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
-
-
-// =================================================================================================
-
-
-// -------------------------------------------------------------------------------------------------
-// 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;
-
-} // IsCoreSyntaxTerm
-
-// -------------------------------------------------------------------------------------------------
-// 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;
-
-} // IsSyntaxTerm
-
-// -------------------------------------------------------------------------------------------------
-// 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;
-
-} // IsOldTerm
-
-// -------------------------------------------------------------------------------------------------
-// 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 ));
-
-} // IsNodeElementName
-
-// -------------------------------------------------------------------------------------------------
-// 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 ));
-
-} // IsPropertyElementName
-
-// -------------------------------------------------------------------------------------------------
-// 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 ));
-
-} // IsPropertyAttributeName
-
-
-// =================================================================================================
-// AddChildNode
-// ============
-
-static XMP_Node *
-AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel )
-{
- #if 0
- cout << "AddChildNode, parent = " << xmpParent->name << ", child = " << xmlNode.name;
- cout << ", value = \"" << value << '"';
- if ( isTopLevel ) cout << ", top level";
- cout << endl;
- #endif
-
- if ( xmlNode.ns.empty() ) {
- XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF );
- }
-
- XMP_StringPtr childName = xmlNode.name.c_str();
- const bool isArrayItem = (xmlNode.name == "rdf:li");
- const bool isValueNode = (xmlNode.name == "rdf:value");
- XMP_OptionBits childOptions = 0;
-
- 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;
- }
-
- }
-
- // Make sure that this is not a duplicate of a named node.
- if ( ! (isArrayItem | isValueNode) ) {
- if ( FindChildNode ( xmpParent, childName, kXMP_ExistingOnly ) != 0 ) {
- XMP_Throw ( "Duplicate property or field node", kXMPErr_BadXMP );
- }
-
- }
-
- // 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 );
- }
- if ( isValueNode ) {
- if ( isTopLevel || (! (xmpParent->options & kXMP_PropValueIsStruct)) ) XMP_Throw ( "Misplaced rdf:value element", kXMPErr_BadRDF );
- xmpParent->options |= kRDF_HasValueElem;
- }
-
- if ( isArrayItem ) {
- if ( ! (xmpParent->options & kXMP_PropValueIsArray) ) XMP_Throw ( "Misplaced rdf:li element", kXMPErr_BadRDF );
- newChild->name = kXMP_ArrayItemName;
- #if 0 // *** XMP_DebugBuild
- newChild->_namePtr = newChild->name.c_str();
- #endif
- }
-
- return newChild;
-
-} // AddChildNode
-
-
-// =================================================================================================
-// AddQualifierNode
-// ================
-
-static XMP_Node *
-AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value )
-{
-
- #if 0
- cout << "AddQualifierNode, parent = " << xmpParent->name << ", name = " << name;
- cout << ", value = \"" << value << '"' << endl;
- #endif
-
- 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;
-
-} // AddQualifierNode
-
-
-// =================================================================================================
-// AddQualifierNode
-// ================
-
-static XMP_Node *
-AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr )
-{
- if ( attr.ns.empty() ) {
- XMP_Throw ( "XML namespace required for all elements and attributes", kXMPErr_BadRDF );
- }
-
- return AddQualifierNode ( xmpParent, attr.name, attr.value );
-
-} // AddQualifierNode
-
-
-// =================================================================================================
-// 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.
-
-static void
-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. Check for duplicate names between the value node's qualifiers and the parent's
- // children. The parent's children are about to become qualifiers. Check here, between the
- // groups. Intra-group duplicates are caught by AddChildNode.
-
- qualNum = 0;
- qualLim = valueNode->qualifiers.size();
-
- if ( valueNode->options & kXMP_PropHasLang ) {
-
- if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Redundant xml:lang for rdf:value element", kXMPErr_BadXMP );
-
- XMP_Node * langQual = valueNode->qualifiers[0];
-
- XMP_Assert ( langQual->name == "xml:lang" );
- langQual->parent = xmpParent;
- xmpParent->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];
- if ( FindChildNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly ) != 0 ) {
- XMP_Throw ( "Duplicate qualifier node", kXMPErr_BadXMP );
- }
-
- 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");
-
- currQual->options |= kXMP_PropIsQualifier;
- currQual->parent = xmpParent;
-
- if ( isLang ) {
- if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Duplicate xml:lang qualifier", kXMPErr_BadXMP );
- 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 qualifiers.
-
- }
-
- 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 );
- #if 0 // *** XMP_DebugBuild
- xmpParent->_valuePtr = xmpParent->value.c_str();
- #endif
-
- xmpParent->children[0] = 0; // ! Remove the value node itself before the swap.
- xmpParent->children.swap ( valueNode->children );
-
- for ( size_t childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
- XMP_Node * currChild = xmpParent->children[childNum];
- currChild->parent = xmpParent;
- }
-
- delete valueNode;
-
-} // FixupQualifiedNode
-
-
-// =================================================================================================
-// ProcessRDF
-// ==========
-//
-// Parse the XML tree of the RDF and build the corresponding XMP tree.
-
-// *** Throw an exception if no XMP is found? By option?
-// *** Do parsing exceptions cause the partial tree to be deleted?
-
-void ProcessRDF ( XMP_Node * xmpTree, const XML_Node & rdfNode, XMP_OptionBits options )
-{
- IgnoreParam(options);
-
- RDF_RDF ( xmpTree, rdfNode );
-
-} // ProcessRDF
-
-
-// =================================================================================================
-// RDF_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.
-
-static void
-RDF_RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode )
-{
-
- if ( ! xmlNode.attrs.empty() ) XMP_Throw ( "Invalid attributes of rdf:RDF element", kXMPErr_BadRDF );
- RDF_NodeElementList ( xmpTree, xmlNode, kIsTopLevel );
-
-} // RDF_RDF
-
-
-// =================================================================================================
-// RDF_NodeElementList
-// ===================
-//
-// 7.2.10 nodeElementList
-// ws* ( nodeElement ws* )*
-
-static void
-RDF_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;
- RDF_NodeElement ( xmpParent, **currChild, isTopLevel );
- }
-
-} // RDF_NodeElementList
-
-
-// =================================================================================================
-// RDF_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.
-
-static void
-RDF_NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
- if ( (nodeTerm != kRDFTerm_Description) && (nodeTerm != kRDFTerm_Other) ) {
- XMP_Throw ( "Node element must be rdf:Description or typedNode", kXMPErr_BadRDF );
- }
-
- if ( isTopLevel && (nodeTerm == kRDFTerm_Other) ) {
- XMP_Throw ( "Top level typedNode not allowed", kXMPErr_BadXMP );
- } else {
- RDF_NodeElementAttrs ( xmpParent, xmlNode, isTopLevel );
- RDF_PropertyElementList ( xmpParent, xmlNode, isTopLevel );
- }
-
-} // RDF_NodeElement
-
-
-// =================================================================================================
-// RDF_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);
-
-static void
-RDF_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_Throw ( "Mutally exclusive about, ID, nodeID attributes", kXMPErr_BadRDF );
- 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_Throw ( "Mismatched top level rdf:about values", kXMPErr_BadXMP );
- }
- }
-
- break;
-
- case kRDFTerm_Other :
- AddChildNode ( xmpParent, **currAttr, (*currAttr)->value.c_str(), isTopLevel );
- break;
-
- default :
- XMP_Throw ( "Invalid nodeElement attribute", kXMPErr_BadRDF );
- break;
-
- }
-
- }
-
-} // RDF_NodeElementAttrs
-
-
-// =================================================================================================
-// RDF_PropertyElementList
-// =======================
-//
-// 7.2.13 propertyEltList
-// ws* ( propertyElt ws* )*
-
-static void
-RDF_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_Throw ( "Expected property element node not found", kXMPErr_BadRDF );
- }
- RDF_PropertyElement ( xmpParent, **currChild, isTopLevel );
- }
-
-} // RDF_PropertyElementList
-
-
-// =================================================================================================
-// RDF_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 attribute counts below.
-
-static void
-RDF_PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
- if ( ! IsPropertyElementName ( nodeTerm ) ) XMP_Throw ( "Invalid property element name", kXMPErr_BadRDF );
-
- if ( xmlNode.attrs.size() > 3 ) {
-
- // Only an emptyPropertyElt can have more than 3 attributes.
- RDF_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" ) {
- RDF_LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
- } else if ( *attrName != "rdf:parseType" ) {
- RDF_EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
- } else if ( attrValue == "Literal" ) {
- RDF_ParseTypeLiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
- } else if ( attrValue == "Resource" ) {
- RDF_ParseTypeResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
- } else if ( attrValue == "Collection" ) {
- RDF_ParseTypeCollectionPropertyElement ( xmpParent, xmlNode, isTopLevel );
- } else {
- RDF_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() ) {
-
- RDF_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 ) {
- RDF_LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
- } else {
- RDF_ResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
- }
-
- }
-
- }
-
- }
-
-} // RDF_PropertyElement
-
-
-// =================================================================================================
-// RDF_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 typedNodes.
-// It also catches and cleans up qualified properties written with rdf:Description and rdf:value.
-
-static void
-RDF_ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- if ( isTopLevel && (xmlNode.name == "iX:changes") ) return; // Strip old "punchcard" chaff.
-
- XMP_Node * newCompound = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
-
- 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" ) {
- AddQualifierNode ( newCompound, **currAttr );
- } else if ( attrName == "rdf:ID" ) {
- continue; // Ignore all rdf:ID attributes.
- } else {
- XMP_Throw ( "Invalid attribute for resource property element", kXMPErr_BadRDF );
- }
- }
-
- XML_cNodePos currChild = xmlNode.content.begin();
- XML_cNodePos endChild = xmlNode.content.end();
-
- for ( ; currChild != endChild; ++currChild ) {
- if ( ! (*currChild)->IsWhitespaceNode() ) break;
- }
- if ( currChild == endChild ) XMP_Throw ( "Missing child of resource property element", kXMPErr_BadRDF );
- if ( (*currChild)->kind != kElemNode ) XMP_Throw ( "Children of resource property element must be XML elements", kXMPErr_BadRDF );
-
- 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 {
- newCompound->options |= kXMP_PropValueIsStruct;
- if ( (*currChild)->name != "rdf:Description" ) {
- XMP_VarString typeName ( (*currChild)->ns );
- size_t colonPos = (*currChild)->name.find_first_of(':');
- if ( colonPos == XMP_VarString::npos ) XMP_Throw ( "All XML elements must be in a namespace", kXMPErr_BadXMP );
- typeName.append ( (*currChild)->name, colonPos, XMP_VarString::npos );
- AddQualifierNode ( newCompound, XMP_VarString("rdf:type"), typeName );
- }
- }
-
- RDF_NodeElement ( newCompound, **currChild, kNotTopLevel );
- if ( newCompound->options & kRDF_HasValueElem ) {
- FixupQualifiedNode ( newCompound );
- } else if ( newCompound->options & kXMP_PropArrayIsAlternate ) {
- DetectAltText ( newCompound );
- }
-
- for ( ++currChild; currChild != endChild; ++currChild ) {
- if ( ! (*currChild)->IsWhitespaceNode() ) XMP_Throw ( "Invalid child of resource property element", kXMPErr_BadRDF );
- }
-
-} // RDF_ResourcePropertyElement
-
-
-// =================================================================================================
-// RDF_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.
-
-static void
-RDF_LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- XMP_Node * newChild = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
-
- 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" ) {
- AddQualifierNode ( newChild, **currAttr );
- } else if ( (attrName == "rdf:ID") || (attrName == "rdf:datatype") ) {
- continue; // Ignore all rdf:ID and rdf:datatype attributes.
- } else {
- XMP_Throw ( "Invalid attribute for literal property element", kXMPErr_BadRDF );
- }
- }
-
- XML_cNodePos currChild = xmlNode.content.begin();
- XML_cNodePos endChild = xmlNode.content.end();
- size_t textSize = 0;
-
- for ( ; currChild != endChild; ++currChild ) {
- if ( (*currChild)->kind != kCDataNode ) XMP_Throw ( "Invalid child of literal property element", kXMPErr_BadRDF );
- textSize += (*currChild)->value.size();
- }
-
- newChild->value.reserve ( textSize );
-
- for ( currChild = xmlNode.content.begin(); currChild != endChild; ++currChild ) {
- newChild->value += (*currChild)->value;
- }
-
- #if 0 // *** XMP_DebugBuild
- newChild->_valuePtr = newChild->value.c_str();
- #endif
-
-} // RDF_LiteralPropertyElement
-
-
-// =================================================================================================
-// RDF_ParseTypeLiteralPropertyElement
-// ===================================
-//
-// 7.2.17 parseTypeLiteralPropertyElt
-// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
-// literal
-// end-element()
-
-static void
-RDF_ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
-
- XMP_Throw ( "ParseTypeLiteral property element not allowed", kXMPErr_BadXMP );
-
-} // RDF_ParseTypeLiteralPropertyElement
-
-
-// =================================================================================================
-// RDF_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.
-
-static void
-RDF_ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
-
- XMP_Node * newStruct = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
- 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" ) {
- AddQualifierNode ( newStruct, **currAttr );
- } else if ( attrName == "rdf:ID" ) {
- continue; // Ignore all rdf:ID attributes.
- } else {
- XMP_Throw ( "Invalid attribute for ParseTypeResource property element", kXMPErr_BadRDF );
- }
- }
-
- RDF_PropertyElementList ( newStruct, xmlNode, kNotTopLevel );
-
- if ( newStruct->options & kRDF_HasValueElem ) FixupQualifiedNode ( newStruct );
-
- // *** Need to look for arrays using rdf:Description and rdf:type.
-
-} // RDF_ParseTypeResourcePropertyElement
-
-
-// =================================================================================================
-// RDF_ParseTypeCollectionPropertyElement
-// ======================================
-//
-// 7.2.19 parseTypeCollectionPropertyElt
-// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
-// nodeElementList
-// end-element()
-
-static void
-RDF_ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
-
- XMP_Throw ( "ParseTypeCollection property element not allowed", kXMPErr_BadXMP );
-
-} // RDF_ParseTypeCollectionPropertyElement
-
-
-// =================================================================================================
-// RDF_ParseTypeOtherPropertyElement
-// =================================
-//
-// 7.2.20 parseTypeOtherPropertyElt
-// start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
-// propertyEltList
-// end-element()
-
-static void
-RDF_ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
-{
- IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
-
- XMP_Throw ( "ParseTypeOther property element not allowed", kXMPErr_BadXMP );
-
-} // RDF_ParseTypeOtherPropertyElement
-
-
-// =================================================================================================
-// RDF_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="https://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.
-
-static void
-RDF_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_Throw ( "Nested content not allowed with rdf:resource or property attributes", kXMPErr_BadRDF );
-
- // 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_Throw ( "Empty property element can't have both rdf:resource and rdf:nodeID", kXMPErr_BadRDF );
- if ( hasValueAttr ) XMP_Throw ( "Empty property element can't have both rdf:value and rdf:resource", kXMPErr_BadXMP );
- hasResourceAttr = true;
- if ( ! hasValueAttr ) valueNode = *currAttr;
- break;
-
- case kRDFTerm_nodeID :
- if ( hasResourceAttr ) XMP_Throw ( "Empty property element can't have both rdf:resource and rdf:nodeID", kXMPErr_BadRDF );
- hasNodeIDAttr = true;
- break;
-
- case kRDFTerm_Other :
- if ( (*currAttr)->name == "rdf:value" ) {
- if ( hasResourceAttr ) XMP_Throw ( "Empty property element can't have both rdf:value and rdf:resource", kXMPErr_BadXMP );
- hasValueAttr = true;
- valueNode = *currAttr;
- } else if ( (*currAttr)->name != "xml:lang" ) {
- hasPropertyAttrs = true;
- }
- break;
-
- default :
- XMP_Throw ( "Unrecognized attribute of empty property element", kXMPErr_BadRDF );
- break;
-
- }
-
- }
-
- // 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 = AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
- 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.w
-
- case kRDFTerm_resource :
- AddQualifierNode ( childNode, **currAttr );
- break;
-
- case kRDFTerm_Other :
- if ( (! childIsStruct) || (*currAttr)->name == "xml:lang" ) {
- AddQualifierNode ( childNode, **currAttr );
- } else {
- AddChildNode ( childNode, **currAttr, (*currAttr)->value.c_str(), false );
- }
- break;
-
- default :
- XMP_Throw ( "Unrecognized attribute of empty property element", kXMPErr_BadRDF );
- break;
-
- }
-
- }
-
-} // RDF_EmptyPropertyElement
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPIterator.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPIterator.cpp
deleted file mode 100644
index f904e4e45b..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPIterator.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-// =================================================================================================
-// Copyright 2002-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 "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "XMPIterator.hpp"
-#include "client-glue/WXMPIterator.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
-
-namespace DngXmpSdk {
-// =================================================================================================
-// CTor/DTor Wrappers
-// ==================
-
-void
-WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPIterator_PropCTor_1" )
-
- if ( schemaNS == 0 ) schemaNS = "";
- if ( propName == 0 ) propName = "";
-
- const XMPMeta & xmpObj = WtoXMPMeta_Ref ( xmpRef );
- XMPIterator * iter = new XMPIterator ( xmpObj, schemaNS, propName, options );
- ++iter->clientRefs;
- XMP_Assert ( iter->clientRefs == 1 );
- wResult->ptrResult = XMPIteratorRef ( iter );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPIterator_TableCTor_1" )
-
- 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_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER ( "WXMPIterator_IncrementRefCount_1" )
-
- XMPIterator * thiz = (XMPIterator*)iterRef;
-
- ++thiz->clientRefs;
- XMP_Assert ( thiz->clientRefs > 1 );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER ( "WXMPIterator_DecrementRefCount_1" )
-
- XMPIterator * thiz = (XMPIterator*)iterRef;
-
- XMP_Assert ( thiz->clientRefs > 0 );
- --thiz->clientRefs;
- if ( thiz->clientRefs <= 0 ) delete ( thiz );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPIterator_Unlock_1 ( XMP_OptionBits options )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPIterator_Unlock_1" )
-
- XMPIterator::Unlock ( options );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// =================================================================================================
-// Class Method Wrappers
-// =====================
-
-void
-WXMPIterator_Next_1 ( XMPIteratorRef iterRef,
- XMP_StringPtr * schemaNS,
- XMP_StringLen * nsSize,
- XMP_StringPtr * propPath,
- XMP_StringLen * pathSize,
- XMP_StringPtr * propValue,
- XMP_StringLen * valueSize,
- XMP_OptionBits * propOptions,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPIterator_Next_1" )
-
- if ( schemaNS == 0 ) schemaNS = &voidStringPtr;
- if ( nsSize == 0 ) nsSize = &voidStringLen;
- if ( propPath == 0 ) propPath = &voidStringPtr;
- if ( pathSize == 0 ) pathSize = &voidStringLen;
- if ( propValue == 0 ) propValue = &voidStringPtr;
- if ( valueSize == 0 ) valueSize = &voidStringLen;
- if ( propOptions == 0 ) propOptions = &voidOptionBits;
-
- XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef );
- XMP_Bool found = iter->Next ( schemaNS, nsSize, propPath, pathSize, propValue, valueSize, propOptions );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPIterator_Skip_1 ( XMPIteratorRef iterRef,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPIterator_Skip_1" )
-
- XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef );
- iter->Skip ( options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef,
- XMP_OptionBits options )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_UnlockIter_1" )
-
- XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef );
- iter->UnlockIter ( options );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// =================================================================================================
-
-
-#if __cplusplus
-} /* extern "C" */
-#endif
-
-} // namespace DngXmpSdk
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPMeta.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPMeta.cpp
deleted file mode 100644
index 4514b389b0..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPMeta.cpp
+++ /dev/null
@@ -1,1319 +0,0 @@
-// =================================================================================================
-// 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.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "XMPMeta.hpp"
-#include "client-glue/WXMPMeta.hpp"
-
-namespace DngXmpSdk {
-
-#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_WRAPPER_NO_LOCK ( "WXMPMeta_GetVersionInfo_1" )
-
- XMPMeta::GetVersionInfo ( info );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_Initialize_1 ( WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Initialize_1" )
-
- bool ok = XMPMeta::Initialize();
- wResult->int32Result = ok;
-
- XMP_EXIT_WRAPPER
-}
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_Terminate_1()
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Terminate_1" )
-
- XMPMeta::Terminate();
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// =================================================================================================
-// CTor/DTor Wrappers
-// ==================
-
-void
-WXMPMeta_CTor_1 ( WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_CTor_1" )
-
- XMPMeta * xmpObj = new XMPMeta();
- ++xmpObj->clientRefs;
- XMP_Assert ( xmpObj->clientRefs == 1 );
- wResult->ptrResult = XMPMetaRef ( xmpObj );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER ( "WXMPMeta_IncrementRefCount_1" )
-
- XMPMeta * thiz = (XMPMeta*)xmpRef;
-
- ++thiz->clientRefs;
- XMP_Assert ( thiz->clientRefs > 0 );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER ( "WXMPMeta_DecrementRefCount_1" )
-
- XMPMeta * thiz = (XMPMeta*)xmpRef;
-
- XMP_Assert ( thiz->clientRefs > 0 );
- --thiz->clientRefs;
- if ( thiz->clientRefs <= 0 ) delete ( thiz );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// =================================================================================================
-// Class Static Wrappers
-// =====================
-//
-// These are DLL-entry wrappers for class-static functions. They all follow a simple pattern:
-//
-// try
-// acquire toolbox lock
-// validate parameters
-// call through to the implementation
-// retain toolbox lock if necessary
-// catch anything and return an appropriate XMP_Error object
-// return null (no error if we get to here)
-//
-// The toolbox lock is acquired through a local wrapper object that automatically unlocks when the
-// try-block is exited. The lock must be retained if the function is returning a string result. The
-// output string is owned by the toolkit, the client must copy the string then release the lock.
-// The lock used here is the overall toolkit lock. For simplicity at this time the lock is a simple
-// mutual exclusion lock, we do not allow multiple concurrent readers.
-//
-// The one exception to this model is UnlockToolkit. It does not acquire the toolkit lock since this
-// is the function the client calls to release the lock after copying an output string!
-//
-// =================================================================================================
-
-/* class static */ void
-WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_GetGlobalOptions_1" )
-
- XMP_OptionBits options = XMPMeta::GetGlobalOptions();
- wResult->int32Result = options;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_SetGlobalOptions_1" )
-
- XMPMeta::SetGlobalOptions ( options );
-
- XMP_EXIT_WRAPPER
-}
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
- void * refCon,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc,
- void * refCon,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_DumpAliases_1" )
-
- if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
-
- XMP_Status status = XMPMeta::DumpAliases ( outProc, refCon );
- wResult->int32Result = status;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_Unlock_1 ( XMP_OptionBits options )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Unlock_1" )
-
- XMPMeta::Unlock ( options );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
- XMP_StringPtr suggestedPrefix,
- XMP_StringPtr * registeredPrefix,
- XMP_StringLen * prefixSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( registeredPrefix == 0 ) registeredPrefix = &voidStringPtr;
- if ( prefixSize == 0 ) prefixSize = &voidStringLen;
-
- bool prefixMatch = XMPMeta::RegisterNamespace ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize );
- wResult->int32Result = prefixMatch;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned!
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
- XMP_StringPtr * namespacePrefix,
- XMP_StringLen * prefixSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespacePrefix_1" )
-
- if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
-
- if ( namespacePrefix == 0 ) namespacePrefix = &voidStringPtr;
- if ( prefixSize == 0 ) prefixSize = &voidStringLen;
-
- bool found = XMPMeta::GetNamespacePrefix ( namespaceURI, namespacePrefix, prefixSize );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
- XMP_StringPtr * namespaceURI,
- XMP_StringLen * uriSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespaceURI_1" )
-
- if ( (namespacePrefix == 0) || (*namespacePrefix == 0) ) XMP_Throw ( "Empty namespace prefix", kXMPErr_BadSchema );
-
- if ( namespaceURI == 0 ) namespaceURI = &voidStringPtr;
- if ( uriSize == 0 ) uriSize = &voidStringLen;
-
- bool found = XMPMeta::GetNamespaceURI ( namespacePrefix, namespaceURI, uriSize );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteNamespace_1" )
-
- if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema );
-
- XMPMeta::DeleteNamespace ( namespaceURI );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr actualNS,
- XMP_StringPtr actualProp,
- XMP_OptionBits arrayForm,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterAlias_1" )
-
- if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema );
- if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath );
- if ( (actualNS == 0) || (*actualNS == 0) ) XMP_Throw ( "Empty actual namespace URI", kXMPErr_BadSchema );
- if ( (actualProp == 0) || (*actualProp == 0) ) XMP_Throw ( "Empty actual property name", kXMPErr_BadXPath );
-
- XMPMeta::RegisterAlias ( aliasNS, aliasProp, actualNS, actualProp, arrayForm );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr * actualNS,
- XMP_StringLen * nsSize,
- XMP_StringPtr * actualProp,
- XMP_StringLen * propSize,
- XMP_OptionBits * arrayForm,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_ResolveAlias_1" )
-
- if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema );
- if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath );
-
- if ( actualNS == 0 ) actualNS = &voidStringPtr;
- if ( nsSize == 0 ) nsSize = &voidStringLen;
- if ( actualProp == 0 ) actualProp = &voidStringPtr;
- if ( propSize == 0 ) propSize = &voidStringLen;
- if ( arrayForm == 0 ) arrayForm = &voidOptionBits;
-
- bool found = XMPMeta::ResolveAlias ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteAlias_1" )
-
- if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema );
- if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath );
-
- XMPMeta::DeleteAlias ( aliasNS, aliasProp );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-/* class static */ void
-WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterStandardAliases_1" )
-
- if ( schemaNS == 0 ) schemaNS = "";
-
- XMPMeta::RegisterStandardAliases ( schemaNS );
-
- XMP_EXIT_WRAPPER
-}
-
-// =================================================================================================
-// Class Method Wrappers
-// =====================
-//
-// These are DLL-entry wrappers for the methods. They all follow a simple pattern:
-//
-// validate parameters
-// try
-// acquire object lock
-// call through to the implementation
-// retain object lock if necessary
-// catch anything and return an appropriate XMP_Error object
-// return null (no error if we get to here)
-//
-// The object lock is acquired through a local wrapper object that automatically unlocks when the
-// try-block is exited. The lock must be retained if the function is returning a string result. The
-// output string is owned by the object, the client must copy the string then release the lock. The
-// lock used here is the per-object lock. For simplicity at this time the lock is a simple mutual
-// exclusion lock, we do not allow multiple concurrent readers.
-//
-// The one exception to this model is UnlockObject. It does not acquire the object lock since this
-// is the function the client calls to release the lock after copying an output string!
-//
-// =================================================================================================
-
-void
-WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr * propValue,
- XMP_StringLen * valueSize,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( propValue == 0 ) propValue = &voidStringPtr;
- if ( valueSize == 0 ) valueSize = &voidStringLen;
- if ( options == 0 ) options = &voidOptionBits;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetProperty ( schemaNS, propName, propValue, valueSize, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- XMP_StringPtr * itemValue,
- XMP_StringLen * valueSize,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( itemValue == 0 ) itemValue = &voidStringPtr;
- if ( valueSize == 0 ) valueSize = &voidStringLen;
- if ( options == 0 ) options = &voidOptionBits;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, valueSize, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr structName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- XMP_StringPtr * fieldValue,
- XMP_StringLen * valueSize,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( fieldValue == 0 ) fieldValue = &voidStringPtr;
- if ( valueSize == 0 ) valueSize = &voidStringLen;
- if ( options == 0 ) options = &voidOptionBits;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr qualNS,
- XMP_StringPtr qualName,
- XMP_StringPtr * qualValue,
- XMP_StringLen * valueSize,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( qualValue == 0 ) qualValue = &voidStringPtr;
- if ( valueSize == 0 ) valueSize = &voidStringLen;
- if ( options == 0 ) options = &voidOptionBits;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, valueSize, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr propValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetProperty ( schemaNS, propName, propValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- XMP_StringPtr itemValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_OptionBits arrayOptions,
- XMP_StringPtr itemValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-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 )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-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 )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->DeleteProperty ( schemaNS, propName );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->DeleteArrayItem ( schemaNS, arrayName, itemIndex );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr structName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->DeleteStructField ( schemaNS, structName, fieldNS, fieldName );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr qualNS,
- XMP_StringPtr qualName,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->DeleteQualifier ( schemaNS, propName, qualNS, qualName );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.DoesPropertyExist ( schemaNS, propName );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.DoesArrayItemExist ( schemaNS, arrayName, itemIndex );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr structName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.DoesStructFieldExist ( schemaNS, structName, fieldNS, fieldName );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr qualNS,
- XMP_StringPtr qualName,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.DoesQualifierExist ( schemaNS, propName, qualNS, qualName );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef,
- 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,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( actualLang == 0 ) actualLang = &voidStringPtr;
- if ( langSize == 0 ) langSize = &voidStringLen;
- if ( itemValue == 0 ) itemValue = &voidStringPtr;
- if ( valueSize == 0 ) valueSize = &voidStringLen;
- if ( options == 0 ) options = &voidOptionBits;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetLocalizedText ( schemaNS, arrayName, genericLang, specificLang,
- actualLang, langSize, itemValue, valueSize, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( found )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr genericLang,
- XMP_StringPtr specificLang,
- XMP_StringPtr itemValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 = "";
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, itemValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_Bool * propValue,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool value;
- bool found = meta.GetProperty_Bool ( schemaNS, propName, &value, options );
- if ( propValue != 0 ) *propValue = value;
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_Int32 * propValue,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetProperty_Int ( schemaNS, propName, propValue, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_Int64 * propValue,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetProperty_Int64 ( schemaNS, propName, propValue, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- double * propValue,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetProperty_Float ( schemaNS, propName, propValue, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_DateTime * propValue,
- XMP_OptionBits * options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- bool found = meta.GetProperty_Date ( schemaNS, propName, propValue, options );
- wResult->int32Result = found;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_Bool propValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetProperty_Bool ( schemaNS, propName, propValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_Int32 propValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetProperty_Int ( schemaNS, propName, propValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_Int64 propValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetProperty_Int64 ( schemaNS, propName, propValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- double propValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetProperty_Float ( schemaNS, propName, propValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- const XMP_DateTime & propValue,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetProperty_Date ( schemaNS, propName, propValue, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef,
- XMP_TextOutputProc outProc,
- void * refCon,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_DumpObject_1" )
-
- if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam );
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- XMP_Status status = meta.DumpObject ( outProc, refCon );
- wResult->int32Result = status;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_Sort_1 ( XMPMetaRef xmpRef,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_Sort_1" )
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->Sort();
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_Erase_1 ( XMPMetaRef xmpRef,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_Erase_1" )
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->Erase();
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_Clone_1 ( XMPMetaRef xmpRef,
- XMP_OptionBits options,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_Clone_1" )
-
- const XMPMeta & xOriginal = WtoXMPMeta_Ref ( xmpRef );
- XMPMeta * xClone = new XMPMeta;
- xOriginal.Clone ( xClone, options );
- XMP_Assert ( xClone->clientRefs == 0 ); // ! Gets incremented in TXMPMeta::Clone.
- wResult->ptrResult = xClone;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- XMP_Index count = meta.CountArrayItems ( schemaNS, arrayName );
- wResult->int32Result = count;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef,
- XMP_OptionBits options ) /* const */
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_UnlockObject_1" )
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- meta.UnlockObject ( options );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr * namePtr,
- XMP_StringLen * nameLen,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectName_1" )
-
- if ( namePtr == 0 ) namePtr = &voidStringPtr;
- if ( nameLen == 0 ) nameLen = &voidStringLen;
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- meta.GetObjectName ( namePtr, nameLen );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned!
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr name,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectName_1" )
-
- if ( name == 0 ) name = "";
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetObjectName ( name );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectOptions_1" )
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- XMP_OptionBits options = meta.GetObjectOptions();
- wResult->int32Result = options;
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectOptions_1" )
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->SetObjectOptions ( options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr buffer,
- XMP_StringLen bufferSize,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_ParseFromBuffer_1" )
-
- XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef );
- meta->ParseFromBuffer ( buffer, bufferSize, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr * rdfString,
- XMP_StringLen * rdfSize,
- XMP_OptionBits options,
- XMP_StringLen padding,
- XMP_StringPtr newline,
- XMP_StringPtr indent,
- XMP_Index baseIndent,
- WXMP_Result * wResult ) /* const */
-{
- XMP_ENTER_WRAPPER ( "WXMPMeta_SerializeToBuffer_1" )
-
- if ( rdfString == 0 ) rdfString = &voidStringPtr;
- if ( rdfSize == 0 ) rdfSize = &voidStringLen;
-
- if ( newline == 0 ) newline = "";
- if ( indent == 0 ) indent = "";
-
- const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef );
- meta.SerializeToBuffer ( rdfString, rdfSize, options, padding, newline, indent, baseIndent );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned!
-}
-
-// =================================================================================================
-
-
-
-#if __cplusplus
-} /* extern "C" */
-#endif
-
-} // namespace DngXmpSdk
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPUtils.cpp
deleted file mode 100644
index 1401ea8cef..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/WXMPUtils.cpp
+++ /dev/null
@@ -1,629 +0,0 @@
-// =================================================================================================
-// 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.
-// =================================================================================================
-
-// *** Should change "type * inParam" to "type & inParam"
-
-#include "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "XMPUtils.hpp"
-#include "client-glue/WXMPUtils.hpp"
-
-namespace DngXmpSdk {
-
-#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_Unlock_1 ( XMP_OptionBits options )
-{
- WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro.
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_Unlock_1" )
-
- XMPUtils::Unlock ( options );
-
- XMP_EXIT_WRAPPER_NO_THROW
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( fullPath == 0 ) fullPath = &voidStringPtr;
- if ( pathSize == 0 ) pathSize = &voidStringLen;
-
- XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, fullPath, pathSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
- XMP_StringPtr structName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( fullPath == 0 ) fullPath = &voidStringPtr;
- if ( pathSize == 0 ) pathSize = &voidStringLen;
-
- XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr qualNS,
- XMP_StringPtr qualName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( fullPath == 0 ) fullPath = &voidStringPtr;
- if ( pathSize == 0 ) pathSize = &voidStringLen;
-
- XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, fullPath, pathSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr langName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
-
- if ( fullPath == 0 ) fullPath = &voidStringPtr;
- if ( pathSize == 0 ) pathSize = &voidStringLen;
-
- XMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName, fullPath, pathSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- XMP_StringPtr fieldValue,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 = "";
-
- if ( fullPath == 0 ) fullPath = &voidStringPtr;
- if ( pathSize == 0 ) pathSize = &voidStringLen;
-
- XMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromBool_1" )
-
- if ( strValue == 0 ) strValue = &voidStringPtr;
- if ( strSize == 0 ) strSize = &voidStringLen;
-
- XMPUtils::ConvertFromBool ( binValue, strValue, strSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt_1" )
-
- if ( format == 0 ) format = "";
-
- if ( strValue == 0 ) strValue = &voidStringPtr;
- if ( strSize == 0 ) strSize = &voidStringLen;
-
- XMPUtils::ConvertFromInt ( binValue, format, strValue, strSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt64_1" )
-
- if ( format == 0 ) format = "";
-
- if ( strValue == 0 ) strValue = &voidStringPtr;
- if ( strSize == 0 ) strSize = &voidStringLen;
-
- XMPUtils::ConvertFromInt64 ( binValue, format, strValue, strSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertFromFloat_1 ( double binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromFloat_1" )
-
- if ( format == 0 ) format = "";
-
- if ( strValue == 0 ) strValue = &voidStringPtr;
- if ( strSize == 0 ) strSize = &voidStringLen;
-
- XMPUtils::ConvertFromFloat ( binValue, format, strValue, strSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromDate_1" )
-
- if ( strValue == 0 ) strValue = &voidStringPtr;
- if ( strSize == 0 ) strSize = &voidStringLen;
-
- XMPUtils::ConvertFromDate( binValue, strValue, strSize );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "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_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "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_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "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_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "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_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
- XMP_DateTime * binValue,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToDate_1" )
-
- if ( binValue == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); // ! Pointer is from the client.
- XMPUtils::ConvertToDate ( strValue, binValue );
-
- XMP_EXIT_WRAPPER
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CurrentDateTime_1" )
-
- if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
- XMPUtils::CurrentDateTime ( time );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_SetTimeZone_1" )
-
- if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
- XMPUtils::SetTimeZone ( time );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToUTCTime_1" )
-
- if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
- XMPUtils::ConvertToUTCTime ( time );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToLocalTime_1" )
-
- if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam);
- XMPUtils::ConvertToLocalTime ( time );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
- const XMP_DateTime & right,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CompareDateTime_1" )
-
- int result = XMPUtils::CompareDateTime ( left, right );
- wResult->int32Result = result;
-
- XMP_EXIT_WRAPPER
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
- XMP_StringLen rawLen,
- XMP_StringPtr * encodedStr,
- XMP_StringLen * encodedLen,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_EncodeToBase64_1" )
-
- if ( encodedStr == 0 ) encodedStr = &voidStringPtr;
- if ( encodedLen == 0 ) encodedLen = &voidStringLen;
-
- XMPUtils::EncodeToBase64 ( rawStr, rawLen, encodedStr, encodedLen );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
- XMP_StringLen encodedLen,
- XMP_StringPtr * rawStr,
- XMP_StringLen * rawLen,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_DecodeFromBase64_1" )
-
- if ( rawStr == 0 ) rawStr = &voidStringPtr;
- if ( rawLen == 0 ) rawLen = &voidStringLen;
-
- XMPUtils::DecodeFromBase64 ( encodedStr, encodedLen, rawStr, rawLen );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_PackageForJPEG_1 ( XMPMetaRef wxmpObj,
- XMP_StringPtr * stdStr,
- XMP_StringLen * stdLen,
- XMP_StringPtr * extStr,
- XMP_StringLen * extLen,
- XMP_StringPtr * digestStr,
- XMP_StringLen * digestLen,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_PackageForJPEG_1" )
-
- if ( stdStr == 0 ) stdStr = &voidStringPtr;
- if ( stdLen == 0 ) stdLen = &voidStringLen;
- if ( extStr == 0 ) extStr = &voidStringPtr;
- if ( extLen == 0 ) extLen = &voidStringLen;
- if ( digestStr == 0 ) digestStr = &voidStringPtr;
- if ( digestLen == 0 ) digestLen = &voidStringLen;
-
- const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj );
- XMPUtils::PackageForJPEG ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef wfullXMP,
- XMPMetaRef wextendedXMP,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_MergeFromJPEG_1" )
-
- if ( wfullXMP == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
-
- XMPMeta * fullXMP = WtoXMPMeta_Ptr ( wfullXMP );
- const XMPMeta & extendedXMP = WtoXMPMeta_Ref ( wextendedXMP );
- XMPUtils::MergeFromJPEG ( fullXMP, extendedXMP );
-
- XMP_EXIT_WRAPPER
-}
-
-// =================================================================================================
-
-void
-WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef wxmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr separator,
- XMP_StringPtr quotes,
- XMP_OptionBits options,
- XMP_StringPtr * catedStr,
- XMP_StringLen * catedLen,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 = "\"";
-
- if ( catedStr == 0 ) catedStr = &voidStringPtr;
- if ( catedLen == 0 ) catedLen = &voidStringLen;
-
- const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj );
- XMPUtils::CatenateArrayItems ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedStr, catedLen );
-
- XMP_EXIT_WRAPPER_KEEP_LOCK ( true )
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef wxmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_OptionBits options,
- XMP_StringPtr catedStr,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
- XMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_RemoveProperties_1 ( XMPMetaRef wxmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "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 );
- XMPUtils::RemoveProperties ( xmpObj, schemaNS, propName, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-void
-WXMPUtils_AppendProperties_1 ( XMPMetaRef wSource,
- XMPMetaRef wDest,
- XMP_OptionBits options,
- WXMP_Result * wResult )
-{
- XMP_ENTER_WRAPPER ( "WXMPUtils_AppendProperties_1" )
-
- if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam );
-
- const XMPMeta & source = WtoXMPMeta_Ref ( wSource );
- XMPMeta * dest = WtoXMPMeta_Ptr ( wDest );
- XMPUtils::AppendProperties ( source, dest, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// -------------------------------------------------------------------------------------------------
-
-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_WRAPPER ( "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 );
- XMPMeta * dest = WtoXMPMeta_Ptr ( wDest );
- XMPUtils::DuplicateSubtree ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options );
-
- XMP_EXIT_WRAPPER
-}
-
-// =================================================================================================
-
-
-
-#if __cplusplus
-} /* extern "C" */
-#endif
-
-} // namespace DngXmpSdk
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPCore_Impl.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPCore_Impl.cpp
deleted file mode 100644
index c01fbcecf6..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPCore_Impl.cpp
+++ /dev/null
@@ -1,1467 +0,0 @@
-// =================================================================================================
-// Copyright 2002-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 "XMP_Environment.h" // ! This must be the first include!
-#include "XMP_Version.h"
-#include "XMPCore_Impl.hpp"
-#include "XMPMeta.hpp" // *** For use of GetNamespacePrefix in FindSchemaNode.
-
-#include "UnicodeInlines.incl_cpp"
-
-#include <algorithm>
-
-using namespace std;
-
-namespace DngXmpSdk {
-
-#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
-
-// *** Add debug codegen checks, e.g. that typical masking operations really work
-// *** Make option constants 0x...UL.
-
-// Internal code should be using #if with XMP_MacBuild, XMP_WinBuild, or XMP_UNIXBuild.
-// This is a sanity check in case of accidental use of *_ENV. Some clients use the poor
-// practice of defining the *_ENV macro with an empty value.
-#if defined ( MAC_ENV )
- #if ! MAC_ENV
- #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
- #endif
-#elif defined ( WIN_ENV )
- #if ! WIN_ENV
- #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
- #endif
-#elif defined ( UNIX_ENV )
- #if ! UNIX_ENV
- #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
- #endif
-#endif
-
-// =================================================================================================
-// Static Variables
-// ================
-
-XMP_Int32 sXMP_InitCount = 0;
-
-XMP_StringMap * sNamespaceURIToPrefixMap = 0;
-XMP_StringMap * sNamespacePrefixToURIMap = 0;
-
-XMP_AliasMap * sRegisteredAliasMap = 0; // Needed by XMPIterator.
-
-XMP_VarString * sOutputNS = 0;
-XMP_VarString * sOutputStr = 0;
-XMP_VarString * sExceptionMessage = 0;
-
-XMP_Mutex sXMPCoreLock;
-int sLockCount = 0;
-
-#if TraceXMPCalls
- FILE * xmpOut = stderr;
-#endif
-
-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;
-
-// =================================================================================================
-// Mutex Utilities
-// ===============
-
-// ! Note that the mutex need not be "recursive", allowing the same thread to acquire it multiple
-// ! times. There is a single XMP lock which is acquired in the wrapper classes. Internal calls
-// ! never go back out to the wrappers.
-
-#if XMP_WinBuild
-
- bool XMP_InitMutex ( XMP_Mutex * mutex ) {
- InitializeCriticalSection ( mutex );
- return true;
- }
-
- void XMP_TermMutex ( XMP_Mutex & mutex ) {
- DeleteCriticalSection ( &mutex );
- }
-
- void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) {
- EnterCriticalSection ( &mutex );
- }
-
- void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) {
- LeaveCriticalSection ( &mutex );
- }
-
-#else
-
- // Use pthread for both Mac and generic UNIX.
- // ! Would be nice to specify PTHREAD_MUTEX_ERRORCHECK, but the POSIX documentation is useless.
- // ! Would be OK but overkill to specify PTHREAD_MUTEX_RECURSIVE.
-
- bool XMP_InitMutex ( XMP_Mutex * mutex ) {
- int err = pthread_mutex_init ( mutex, 0 );
- return (err == 0 );
- }
-
- void XMP_TermMutex ( XMP_Mutex & mutex ) {
- (void) pthread_mutex_destroy ( &mutex );
- }
-
- void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) {
- int err = pthread_mutex_lock ( &mutex );
- if ( err != 0 ) XMP_Throw ( "XMP_EnterCriticalRegion - pthread_mutex_lock failure", kXMPErr_ExternalFailure );
- }
-
- void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) {
- int err = pthread_mutex_unlock ( &mutex );
- if ( err != 0 ) XMP_Throw ( "XMP_ExitCriticalRegion - pthread_mutex_unlock failure", kXMPErr_ExternalFailure );
- }
-
-#endif
-
-// =================================================================================================
-// 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_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( XMP_VarString ( schemaURI ) );
- if ( uriPos == sNamespaceURIToPrefixMap->end() ) {
- 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 ( uriPos->second, 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 );
- XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix );
- if ( prefixPos == sNamespacePrefixToURIMap->end() ) {
- XMP_Throw ( "Unknown schema namespace prefix", kXMPErr_BadSchema );
- }
- if ( prefix != uriPos->second ) {
- 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 );
- XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix );
- if ( prefixPos == sNamespacePrefixToURIMap->end() ) {
- 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
-// -------------
-
-// *** Might be useful elsewhere?
-
-static 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 );
- break;
-
- }
-
- }
-
-} // 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) );
- XMP_StringPtr prefixPtr;
- XMP_StringLen prefixLen;
- bool found = XMPMeta::GetNamespacePrefix ( nsURI, &prefixPtr, &prefixLen ); // *** Use map directly?
- XMP_Assert ( found );
-
- schemaNode->value.assign ( prefixPtr, prefixLen );
- 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 )
-{
- 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];
- XMP_Node * cloneQual = new XMP_Node ( cloneParent, origQual->name, origQual->value, origQual->options );
- CloneOffspring ( origQual, cloneQual );
- 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];
- XMP_Node * cloneChild = new XMP_Node ( cloneParent, origChild->name, origChild->value, origChild->options );
- CloneOffspring ( origChild, cloneChild );
- cloneParent->children.push_back ( cloneChild );
- }
-
- }
-
-} // CloneOffspring
-
-// =================================================================================================
-// CloneSubtree
-// ============
-
-XMP_Node *
-CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent )
-{
- #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 ) ;
- 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 supersedes 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
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPCore_Impl.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPCore_Impl.hpp
deleted file mode 100644
index 54cce7c0c4..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPCore_Impl.hpp
+++ /dev/null
@@ -1,534 +0,0 @@
-#ifndef __XMPCore_Impl_hpp__
-#define __XMPCore_Impl_hpp__
-
-// =================================================================================================
-// 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.
-// =================================================================================================
-
-#include "XMP_Environment.h" // ! Must be the first #include!
-#include "XMP_Const.h"
-#include "XMP_BuildInfo.h"
-
-#include "client-glue/WXMPMeta.hpp"
-
-#include <vector>
-#include <string>
-#include <cstring>
-#include <map>
-
-#include <cassert>
-
-#if XMP_WinBuild
- #include <Windows.h>
-#else
- // Use pthread for both Mac and generic UNIX.
- #include <pthread.h>
-#endif
-
-#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
-
-namespace DngXmpSdk {
-// =================================================================================================
-// 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 std::string XMP_VarString;
-typedef XMP_VarString::iterator XMP_VarStringPos;
-typedef XMP_VarString::const_iterator XMP_cVarStringPos;
-
-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;
-
-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_AliasMap * sRegisteredAliasMap;
-
-extern XMP_StringMap * sNamespaceURIToPrefixMap;
-extern XMP_StringMap * sNamespacePrefixToURIMap;
-
-extern XMP_VarString * sOutputNS;
-extern XMP_VarString * sOutputStr;
-
-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) (std::strcmp((s),(l)) == 0)
-#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0)
- // *** Use the above macros!
-
-#define kTab ((char)0x09)
-#define kLF ((char)0x0A)
-#define kCR ((char)0x0D)
-
-#if XMP_WinBuild
- #define snprintf _snprintf
-#endif
-
-#define WtoXMPMeta_Ref(xmpRef) *((const XMPMeta *)(xmpRef))
-#define WtoXMPMeta_Ptr(xmpRef) (((xmpRef) == 0) ? 0 : (XMPMeta *)(xmpRef))
-
-#define WtoXMPIterator_Ref(iterRef) *((const XMPIterator *)(iterRef))
-#define WtoXMPIterator_Ptr(iterRef) (((iterRef) == 0) ? 0 : (XMPIterator *)(iterRef))
-
-#define WtoXMPDocOps_Ref(docRef) *((const XMPDocOps *)(docRef))
-#define WtoXMPDocOps_Ptr(docRef) (((docRef) == 0) ? 0 : (XMPDocOps *)(docRef))
-
-#define IgnoreParam(p) voidVoidPtr = (void*)&p
-
-// =================================================================================================
-// 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 " " XMP_API_VERSION_STRING
-// =================================================================================================
-// Support for asserts
-
-#define _MakeStr(p) #p
-#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l)
-
-#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 ); \
- }
-// =================================================================================================
-// Support for exceptions and thread locking
-
-#ifndef TraceXMPCalls
- #define TraceXMPCalls 0
-#endif
-
-#if ! TraceXMPCalls
-
- #define AnnounceThrow(msg) /* Do nothing. */
- #define AnnounceCatch(msg) /* Do nothing. */
-
- #define AnnounceEntry(proc) /* Do nothing. */
- #define AnnounceNoLock(proc) /* Do nothing. */
- #define AnnounceExit() /* Do nothing. */
-
- #define ReportLock() ++sLockCount
- #define ReportUnlock() --sLockCount
- #define ReportKeepLock() /* Do nothing. */
-
-#else
-
- extern FILE * xmpCoreOut;
-
- #define AnnounceThrow(msg) \
- fprintf ( xmpCoreOut, "XMP_Throw: %s\n", msg ); fflush ( xmpOut )
- #define AnnounceCatch(msg) \
- fprintf ( xmpCoreOut, "Catch in %s: %s\n", procName, msg ); fflush ( xmpOut )
-
- #define AnnounceEntry(proc) \
- const char * procName = proc; \
- fprintf ( xmpCoreOut, "Entering %s\n", procName ); fflush ( xmpOut )
- #define AnnounceNoLock(proc) \
- const char * procName = proc; \
- fprintf ( xmpCoreOut, "Entering %s (no lock)\n", procName ); fflush ( xmpOut )
- #define AnnounceExit() \
- fprintf ( xmpCoreOut, "Exiting %s\n", procName ); fflush ( xmpOut )
-
- #define ReportLock() \
- ++sLockCount; fprintf ( xmpCoreOut, " Auto lock, count = %d\n", sLockCount ); fflush ( xmpOut )
- #define ReportUnlock() \
- --sLockCount; fprintf ( xmpCoreOut, " Auto unlock, count = %d\n", sLockCount ); fflush ( xmpOut )
- #define ReportKeepLock() \
- fprintf ( xmpCoreOut, " Keeping lock, count = %d\n", sLockCount ); fflush ( xmpOut )
-
-#endif
-
-#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); }
-
-// -------------------------------------------------------------------------------------------------
-
-#if XMP_WinBuild
- typedef CRITICAL_SECTION XMP_Mutex;
-#else
- // Use pthread for both Mac and generic UNIX.
- typedef pthread_mutex_t XMP_Mutex;
-#endif
-
-extern XMP_Mutex sXMPCoreLock;
-extern int sLockCount; // Keep signed to catch unlock errors.
-extern XMP_VarString * sExceptionMessage;
-
-extern bool XMP_InitMutex ( XMP_Mutex * mutex );
-extern void XMP_TermMutex ( XMP_Mutex & mutex );
-
-extern void XMP_EnterCriticalRegion ( XMP_Mutex & mutex );
-extern void XMP_ExitCriticalRegion ( XMP_Mutex & mutex );
-
-class XMP_AutoMutex {
-public:
- XMP_AutoMutex() : mutex(&sXMPCoreLock) { XMP_EnterCriticalRegion ( *mutex ); ReportLock(); };
- ~XMP_AutoMutex() { if ( mutex != 0 ) { ReportUnlock(); XMP_ExitCriticalRegion ( *mutex ); mutex = 0; } };
- void KeepLock() { ReportKeepLock(); mutex = 0; };
-private:
- XMP_Mutex * mutex;
-};
-
-// *** Switch to XMPEnterObjectWrapper & XMPEnterStaticWrapper, to allow for per-object locks.
-
-// ! Don't do the initialization check (sXMP_InitCount > 0) for the no-lock case. That macro is used
-// ! by WXMPMeta_Initialize_1.
-
-#define XMP_ENTER_WRAPPER_NO_LOCK(proc) \
- AnnounceNoLock ( proc ); \
- XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \
- try { \
- wResult->errMessage = 0;
-
-#define XMP_ENTER_WRAPPER(proc) \
- AnnounceEntry ( proc ); \
- XMP_Assert ( sXMP_InitCount > 0 ); \
- XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \
- try { \
- XMP_AutoMutex mutex; \
- wResult->errMessage = 0;
-
-#define XMP_EXIT_WRAPPER \
- XMP_CATCH_EXCEPTIONS \
- AnnounceExit();
-
-#define XMP_EXIT_WRAPPER_KEEP_LOCK(keep) \
- if ( keep ) mutex.KeepLock(); \
- XMP_CATCH_EXCEPTIONS \
- AnnounceExit();
-
-#define XMP_EXIT_WRAPPER_NO_THROW \
- } 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
-
-// =================================================================================================
-// 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 );
-
-extern XMP_Node *
-CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent );
-
-extern bool
-CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode );
-
-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 = std::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 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 ) ) {};
-};
-
-extern void ProcessRDF ( XMP_Node * xmpTree, const XML_Node & xmlTree, XMP_OptionBits options );
-
-// =================================================================================================
-
-} // namespace DngXmpSdk
-#endif // __XMPCore_Impl_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPIterator.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPIterator.cpp
deleted file mode 100644
index afc2b169a5..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPIterator.cpp
+++ /dev/null
@@ -1,736 +0,0 @@
-// =================================================================================================
-// Copyright 2002-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 "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
-// =================================================================================================
-
-namespace DngXmpSdk {
-
-#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 )
-{
- info = info; // Avoid unused parameter warning.
- #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
-
-// -------------------------------------------------------------------------------------------------
-// AddSchemaAliases
-// ----------------
-//
-// Add the aliases to the IterNode for a schema, if the corresponding actual exists.
-
-static void
-AddSchemaAliases ( IterInfo & info, IterNode & iterSchema, XMP_StringPtr schemaURI )
-{
-
- // We're showing 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.
-
- #if TraceIterators
- printf ( " Adding aliases\n", schemaURI );
- #endif
-
- XMP_StringPtr nsPrefix;
- XMP_StringLen nsLen;
- bool found = XMPMeta::GetNamespacePrefix ( schemaURI, &nsPrefix, &nsLen );
- if ( ! found ) XMP_Throw ( "Unknown iteration namespace", kXMPErr_BadSchema );
-
- XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin();
- XMP_AliasMapPos endAlias = sRegisteredAliasMap->end();
-
- for ( ; currAlias != endAlias; ++currAlias ) {
- if ( XMP_LitNMatch ( currAlias->first.c_str(), nsPrefix, nsLen ) ) {
- const XMP_Node * actualProp = FindConstNode ( &info.xmpObj->tree, currAlias->second );
- if ( actualProp != 0 ) {
- iterSchema.children.push_back ( IterNode ( (actualProp->options | kXMP_PropIsAlias), currAlias->first, 0 ) );
- #if TraceIterators
- printf ( " %s => %s\n", currAlias->first.c_str(), actualProp->name.c_str() );
- #endif
- }
- }
- }
-
-} // AddSchemaAliases
-
-// -------------------------------------------------------------------------------------------------
-// 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), "[%d]", 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 statement,
- // 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
-
-// -------------------------------------------------------------------------------------------------
-// Unlock
-// ------
-
-void
-XMPIterator::Unlock ( XMP_OptionBits options )
-{
- options = options; // Avoid unused parameter warning.
-
- XMPMeta::Unlock ( 0 );
-
-} // Unlock
-
-// =================================================================================================
-// 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 ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, schemaNS );
-
- 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 ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, xmpSchema->name.c_str() );
- if ( iterSchema.children.empty() ) info.tree.children.pop_back(); // No properties, remove the schema node.
- }
-
- }
-
- if ( info.options & kXMP_IterIncludeAliases ) {
-
- // Add the schema that only have aliases. The most convenient, and safest way, is to go
- // through the registered namespaces, see if it exists, and let AddSchemaAliases do its
- // thing if not. Don't combine with the above loop, it is nicer to have the "real" stuff
- // be in storage order (not subject to the namespace map order).
-
- // ! We don't do the kXMP_IterJustChildren handing in the same way here as above. The
- // ! existing schema (presumably) have actual children. We need to call AddSchemaAliases
- // ! here to determine if the namespace has any aliases to existing properties. We then
- // ! strip the children if necessary.
-
- XMP_cStringMapPos currNS = sNamespaceURIToPrefixMap->begin();
- XMP_cStringMapPos endNS = sNamespaceURIToPrefixMap->end();
- for ( ; currNS != endNS; ++currNS ) {
- XMP_StringPtr schemaName = currNS->first.c_str();
- if ( FindConstSchema ( &xmpObj.tree, schemaName ) != 0 ) continue;
- info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaName, 0 ) );
- IterNode & iterSchema = info.tree.children.back();
- AddSchemaAliases ( info, iterSchema, schemaName );
- if ( iterSchema.children.empty() ) {
- info.tree.children.pop_back(); // No aliases, remove the schema node.
- } else if ( info.options & kXMP_IterJustChildren ) {
- iterSchema.children.clear(); // Get rid of the children.
- }
- }
-
- }
-
- }
-
- // 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;
- }
-
- 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 position 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
-
-// -------------------------------------------------------------------------------------------------
-// UnlockIter
-// ----------
-
-void
-XMPIterator::UnlockIter ( XMP_OptionBits options )
-{
- options = options; // Avoid unused parameter warning.
-
- XMPMeta::Unlock ( 0 );
-
-} // UnlockIter
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPIterator.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPIterator.hpp
deleted file mode 100644
index e1c9dfe7a0..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPIterator.hpp
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef __XMPIterator_hpp__
-#define __XMPIterator_hpp__
-
-// =================================================================================================
-// Copyright 2002-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 "XMP_Environment.h"
-#include "XMP_Const.h"
-#include "XMPMeta.hpp"
-
-// =================================================================================================
-
-namespace DngXmpSdk {
-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!
-
- static void
- Unlock ( XMP_OptionBits options );
-
- 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 );
-
- void
- UnlockIter ( 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.
- 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 ); };
-
-};
-
-// =================================================================================================
-
-} // namespace DngXmpSdk
-#endif // __XMPIterator_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-GetSet.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-GetSet.cpp
deleted file mode 100644
index 74cfaf3012..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-GetSet.cpp
+++ /dev/null
@@ -1,1212 +0,0 @@
-// =================================================================================================
-// 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.
-//
-// 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 "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "XMPMeta.hpp"
-#include "XMPIterator.hpp"
-#include "XMPUtils.hpp"
-#include "XMP_Version.h"
-#include "UnicodeInlines.incl_cpp"
-#include "UnicodeConversions.hpp"
-#include "ExpatAdapter.hpp"
-
-#if XMP_DebugBuild
- #include <iostream>
-#endif
-
-using namespace std;
-
-namespace DngXmpSdk {
-
-#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
-
- node->value = value;
-
- XMP_Uns8* chPtr = (XMP_Uns8*) node->value.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 ) (void) GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8.
- }
-
- if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &node->value );
-
- #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, itemValue, (kXMP_PropHasQualifiers | kXMP_PropHasLang) );
- XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", itemLang, kXMP_PropIsQualifier );
- 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) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
-
- XMP_StringPtr itemPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
- return GetProperty ( schemaNS, itemPath, 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) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
-
- XMP_StringPtr fieldPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
- return GetProperty ( schemaNS, fieldPath, 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) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
-
- XMP_StringPtr qualPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
- return GetProperty ( schemaNS, qualPath, 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_StringPtr fieldPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
- SetProperty ( schemaNS, fieldPath, 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_StringPtr qualPath;
- XMP_StringLen pathLen;
-
- 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 );
-
- XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
- SetProperty ( schemaNS, qualPath, 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_StringPtr itemPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
- DeleteProperty ( schemaNS, itemPath );
-
-} // 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_StringPtr fieldPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
- DeleteProperty ( schemaNS, fieldPath );
-
-} // 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_StringPtr qualPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
- DeleteProperty ( schemaNS, qualPath );
-
-} // 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_StringPtr itemPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
- return DoesPropertyExist ( schemaNS, itemPath );
-
-} // 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_StringPtr fieldPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
- return DoesPropertyExist ( schemaNS, fieldPath );
-
-} // 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_StringPtr qualPath;
- XMP_StringLen pathLen;
-
- XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
- return DoesPropertyExist ( schemaNS, qualPath );
-
-} // 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 )
-{
- options = options; // Avoid unused parameter warning.
-
- 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 ( 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 ( 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 ( 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 );
- break;
-
- }
-
- // Add an x-default at the front if needed.
- if ( (! haveXDefault) && (arrayNode->children.size() == 1) ) {
- AppendLangItem ( arrayNode, "x-default", itemValue );
- }
-
-} // SetLocalizedText
-
-
-// -------------------------------------------------------------------------------------------------
-// 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_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::ConvertToInt ( valueStr );
- }
- return found;
-
-} // 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 );
- *propValue = XMPUtils::ConvertToInt64 ( valueStr );
- }
- 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 );
- *propValue = XMPUtils::ConvertToFloat ( valueStr );
- }
- 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_StringPtr valueStr;
- XMP_StringLen valueLen;
-
- XMPUtils::ConvertFromBool ( propValue, &valueStr, &valueLen );
- SetProperty ( schemaNS, propName, valueStr, 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_StringPtr valueStr;
- XMP_StringLen valueLen;
-
- XMPUtils::ConvertFromInt ( propValue, "", &valueStr, &valueLen );
- SetProperty ( schemaNS, propName, valueStr, 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_StringPtr valueStr;
- XMP_StringLen valueLen;
-
- XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr, &valueLen );
- SetProperty ( schemaNS, propName, valueStr, 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_StringPtr valueStr;
- XMP_StringLen valueLen;
-
- XMPUtils::ConvertFromFloat ( propValue, "", &valueStr, &valueLen );
- SetProperty ( schemaNS, propName, valueStr, 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_StringPtr valueStr;
- XMP_StringLen valueLen;
-
- XMPUtils::ConvertFromDate ( propValue, &valueStr, &valueLen );
- SetProperty ( schemaNS, propName, valueStr, options );
-
-} // SetProperty_Date
-
-} // namespace DngXmpSdk
-// =================================================================================================
-
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-Parse.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-Parse.cpp
deleted file mode 100644
index f780b4a1c1..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-Parse.cpp
+++ /dev/null
@@ -1,1290 +0,0 @@
-// =================================================================================================
-// 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.
-//
-// 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 "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;
-
-namespace DngXmpSdk {
-
-#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
-// ------------
-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 ( XMPMeta * thiz, 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;
-
- // We have a root node. Try to extract previous toolkit version number.
-
- XMP_StringPtr verStr = "";
-
- 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;
-
- for ( size_t attrNum = 0, attrLim = rootNode->parent->attrs.size(); attrNum < attrLim; ++attrNum ) {
- const XML_Node * currAttr =rootNode->parent->attrs[attrNum];
- if ( (currAttr->name == "x:xmptk") || (currAttr->name == "x:xaptk") ) {
- verStr = currAttr->value.c_str();
- break;
- }
- }
-
- // Decode the version number into MMmmuubbb digits. If any part is too big, peg it at 99 or 999.
-
- unsigned long part;
- while ( (*verStr != 0) && ((*verStr < '0') || (*verStr > '9')) ) ++verStr;
-
- part = 0;
- while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
- part = (part * 10) + (*verStr - '0');
- ++verStr;
- }
- if ( part > 99 ) part = 99;
- thiz->prevTkVer = part * 100*100*1000;
-
- part = 0;
- if ( *verStr == '.' ) ++verStr;
- while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
- part = (part * 10) + (*verStr - '0');
- ++verStr;
- }
- if ( part > 99 ) part = 99;
- thiz->prevTkVer += part * 100*1000;
-
- part = 0;
- if ( *verStr == '.' ) ++verStr;
- while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
- part = (part * 10) + (*verStr - '0');
- ++verStr;
- }
- if ( part > 99 ) part = 99;
- thiz->prevTkVer += part * 1000;
-
- part = 0;
- if ( *verStr == '-' ) ++verStr;
- while ( (*verStr != 0) && ('0' <= *verStr) && (*verStr <= '9') ) {
- part = (part * 10) + (*verStr - '0');
- ++verStr;
- }
- if ( part > 999 ) part = 999;
- thiz->prevTkVer += part;
-
- 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;
- 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, 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()) ) {
- XMP_Throw ( "Mismatch between alias and base nodes", kXMPErr_BadXMP );
- }
- if ( ! outerCall ) {
- if ( (aliasNode->name != baseNode->name) ||
- (aliasNode->options != baseNode->options) ||
- (aliasNode->qualifiers.size() != baseNode->qualifiers.size()) ) {
- XMP_Throw ( "Mismatch between alias and base nodes", kXMPErr_BadXMP );
- }
- }
-
- 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, 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, false );
- }
-
-} // CompareAliasedSubtrees
-
-
-// -------------------------------------------------------------------------------------------------
-// TransplantArrayItemAlias
-// ------------------------
-
-static void
-TransplantArrayItemAlias ( XMP_Node * oldParent, size_t oldNum, XMP_Node * newParent )
-{
- XMP_Node * childNode = oldParent->children[oldNum];
-
- if ( newParent->options & kXMP_PropArrayIsAltText ) {
- if ( childNode->options & kXMP_PropHasLang ) {
- XMP_Throw ( "Alias to x-default already has a language qualifier", kXMPErr_BadXMP ); // *** 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 )
-{
- 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 );
- }
-
- } 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 );
- 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 );
- } else {
- if ( strictAliasing ) CompareAliasedSubtrees ( currProp, itemNode );
- 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;
-
- XMP_StringPtr goodStr;
- XMP_StringLen goodLen;
- XMPUtils::ConvertFromDate ( binGPSStamp, &goodStr, &goodLen );
-
- gpsDateTime->value.assign ( goodStr, goodLen );
-
-} // 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 )
-{
- 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 assumptions: 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
-
-
-// -------------------------------------------------------------------------------------------------
-// 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.
-
- this->tree.ClearNode(); // Make sure the target XMP object is totally empty.
-
- if ( this->xmlParser == 0 ) {
- if ( (xmpSize == 0) && lastClientCall ) return; // Tolerate empty parse. Expat complains if there are no XML elements.
- this->xmlParser = XMP_NewExpatAdapter();
- }
-
- XMLParserAdapter& parser = *this->xmlParser;
-
- #if 0 // XMP_DebugBuild
- if ( parser.parseLog != 0 ) {
- char message [200]; // AUDIT: Using sizeof(message) below for snprintf length is safe.
- snprintf ( message, sizeof(message), "<!-- ParseFromBuffer, length = %d, options = %X%s -->", // AUDIT: See above.
- xmpSize, options, (lastClientCall ? " (last)" : "") );
- fwrite ( message, 1, strlen(message), parser.parseLog );
- fflush ( parser.parseLog );
- }
- #endif
-
- try { // Cleanup the tree and xmlParser if anything fails.
-
- // Determine the character encoding before doing any real parsing. This is needed to do the
- // 8-bit special processing.
-
- 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;
- 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 weird 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;
- size_t bytesDone = ProcessUTF8Portion ( &parser, 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;
-
- }
-
- }
-
- // Done with the pending input, process the current buffer.
-
- size_t bytesDone = ProcessUTF8Portion ( &parser, (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; // Wait for the next buffer.
-
- }
-
- }
-
- if ( lastClientCall ) {
-
- #if XMP_DebugBuild && DumpXMLParseTree
- if ( parser.parseLog == 0 ) parser.parseLog = stdout;
- DumpXMLTree ( parser.parseLog, parser.tree, 0 );
- #endif
-
- const XML_Node * xmlRoot = FindRootNode ( this, *this->xmlParser, options );
-
- if ( xmlRoot != 0 ) {
-
- ProcessRDF ( &this->tree, *xmlRoot, options );
- NormalizeDCArrays ( &this->tree );
- if ( this->tree.options & kXMP_PropHasAliases ) MoveExplicitAliases ( &this->tree, options );
- TouchUpDataModel ( this );
-
- // 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 );
- }
- }
-
- }
-
- delete this->xmlParser;
- this->xmlParser = 0;
-
- }
-
- } catch ( ... ) {
-
- delete this->xmlParser;
- this->xmlParser = 0;
- prevTkVer = 0;
- this->tree.ClearNode();
- throw;
-
- }
-
-} // ParseFromBuffer
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-Serialize.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-Serialize.cpp
deleted file mode 100644
index dff3e3a088..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta-Serialize.cpp
+++ /dev/null
@@ -1,1355 +0,0 @@
-// =================================================================================================
-// 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.
-//
-// 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 "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "XMPMeta.hpp"
-
-#include "XMP_Version.h"
-#include "UnicodeInlines.incl_cpp"
-#include "UnicodeConversions.hpp"
-
-#if XMP_DebugBuild
- #include <iostream>
-#endif
-
-using namespace std;
-
-namespace DngXmpSdk {
-
-#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 * kPXMP_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 ( const XMP_VarString & nsPrefix,
- const XMP_VarString & nsURI,
- XMP_VarString & usedNS, // ! A concatenation of the prefixes with colons.
- XMP_VarString & outputStr,
- XMP_StringPtr newline,
- XMP_StringPtr indentStr,
- XMP_Index indent )
-{
- size_t nsPos = usedNS.find ( nsPrefix );
-
- 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_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix );
- XMP_Enforce ( prefixPos != sNamespacePrefixToURIMap->end() );
- DeclareOneNamespace ( nsPrefix, prefixPos->second, usedNS, outputStr, newline, indentStr, indent );
- }
-
-} // DeclareElemNamespace
-
-
-// -------------------------------------------------------------------------------------------------
-// DeclareUsedNamespaces
-// ---------------------
-
-// ??? Should iterators be passed by reference to avoid temp copies?
-
-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, currNode->name, 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
-// ---------------
-
-// ??? Should iterators be passed by reference to avoid temp copies?
-
-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;", 5 );
- 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
-
-
-// -------------------------------------------------------------------------------------------------
-// SerializePrettyRDFProperty
-// --------------------------
-//
-// 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 rdf:parseType="Resource"> (If no rdf:resource qualifier)
-// ... Fields, same forms as top level properties
-// </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:parseType="Resource">
-// <rdf:value> ... Property "value" following the unqualified forms ... </rdf:value>
-// ... Qualifiers looking like named struct fields
-// </ns:QualifiedProperty>
-
-static void
-SerializePrettyRDFProperty ( const XMP_Node * propNode,
- XMP_VarString & outputStr,
- XMP_StringPtr newline,
- XMP_StringPtr indentStr,
- XMP_Index indent,
- bool emitAsRDFValue = false )
-{
- 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;
-
- #define isCompact false
- bool hasGeneralQualifiers = isCompact; // Might also become true later.
- 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 );
- }
-
- outputStr += " rdf:parseType=\"Resource\">";
- outputStr += newline;
-
- SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true );
-
- for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
- const XMP_Node * currQual = propNode->qualifiers[qualNum];
- if ( IsRDFAttrQualifier ( currQual->name ) ) continue;
- SerializePrettyRDFProperty ( currQual, outputStr, newline, indentStr, 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];
- SerializePrettyRDFProperty ( currChild, outputStr, newline, indentStr, indent+2 );
- }
- EmitRDFArrayTag ( propForm, outputStr, newline, indentStr, indent+1, propNode->children.size(), kIsEndTag );
-
-
- } else if ( ! hasRDFResourceQual ) {
-
- // This is a "normal" struct, use the rdf:parseType="Resource" form.
- XMP_Assert ( propForm & kXMP_PropValueIsStruct );
- if ( propNode->children.size() == 0 ) {
- outputStr += " rdf:parseType=\"Resource\"/>";
- outputStr += newline;
- emitEndTag = false;
- } else {
- outputStr += " rdf:parseType=\"Resource\">";
- outputStr += newline;
- for ( size_t childNum = 0, childLim = propNode->children.size(); childNum < childLim; ++childNum ) {
- const XMP_Node * currChild = propNode->children[childNum];
- SerializePrettyRDFProperty ( currChild, outputStr, newline, indentStr, 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;
- }
-
-} // SerializePrettyRDFProperty
-
-
-// -------------------------------------------------------------------------------------------------
-// SerializePrettyRDFSchema
-// ------------------------
-//
-// Each schema's properties are written in a separate 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 SerializePrettyRDFProperty
-//
-// <!-- ns1:Alias is aliased to ns2:Actual --> ... If alias comments are wanted
-//
-// </rdf:Description>
-
-static void
-SerializePrettyRDFSchema ( const XMP_VarString & treeName,
- const XMP_Node * schemaNode,
- XMP_VarString & outputStr,
- XMP_OptionBits options,
- XMP_StringPtr newline,
- XMP_StringPtr indentStr,
- XMP_Index baseIndent )
-{
- XMP_Assert ( schemaNode->options & kXMP_SchemaNode );
- XMP_Assert ( schemaNode->qualifiers.empty() );
-
- // Write the rdf:Description start tag with the namespace declarations.
-
- XMP_Index level;
- for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
- outputStr += kRDF_SchemaStart;
- outputStr += '"';
- outputStr += treeName;
- outputStr += '"';
-
- size_t totalLen = 8; // Start at 8 for "xml:rdf:".
- XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin();
- XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end();
- for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size();
-
- XMP_VarString usedNS;
- usedNS.reserve ( totalLen );
- usedNS = "xml:rdf:";
- DeclareUsedNamespaces ( schemaNode, usedNS, outputStr, newline, indentStr, baseIndent+4 );
-
- outputStr += ">";
- outputStr += newline;
-
- // Write alias comments, if wanted.
-
- if ( options & kXMP_WriteAliasComments ) { // *** Hoist into a routine, used for Plain XMP also.
-
- #if 0 // *** Buggy, disable for now.
-
- XMP_cAliasMapPos aliasPos = sRegisteredAliasMap->begin();
- XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end();
-
- for ( ; aliasPos != aliasEnd; ++aliasPos ) {
-
- size_t nsPos = aliasPos->first.find ( schemaNode->value );
- if ( nsPos == XMP_VarString::npos ) continue;
- XMP_Assert ( nsPos == 0 );
-
- for ( level = baseIndent+3; level > 0; --level ) outputStr += indentStr;
-
- outputStr += "<!-- ";
- outputStr += aliasPos->first;
- outputStr += " is aliased to ";
- for ( size_t step = 1, stepLim = aliasPos->second.size(); step != stepLim; ++step ) {
- outputStr += aliasPos->second[step].step;
- }
- outputStr += " -->";
- outputStr += newline;
-
- }
-
- #endif
-
- }
-
- // Write each of the schema's actual properties.
- for ( size_t propNum = 0, propLim = schemaNode->children.size(); propNum < propLim; ++propNum ) {
- const XMP_Node * currProp = schemaNode->children[propNum];
- SerializePrettyRDFProperty ( currProp, 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;
-
-} // SerializePrettyRDFSchema
-
-
-// -------------------------------------------------------------------------------------------------
-// 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;
-
- #define isCompact false
- bool hasGeneralQualifiers = isCompact; // Might also become true later.
- 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 SerializePrettyRDFProperty with emitAsRDFValue set.
-
- // *** We're losing compactness in the calls to SerializePrettyRDFProperty.
- // *** Should refactor to have SerializeCompactRDFProperty that does one node.
-
- outputStr += " rdf:parseType=\"Resource\">";
- outputStr += newline;
-
- SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true );
-
- 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];
- SerializePrettyRDFProperty ( currQual, outputStr, newline, indentStr, indent+1 );
- }
-
- } 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;
-
- // Begin the rdf:Description start tag.
- for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr;
- outputStr += kRDF_SchemaStart;
- outputStr += '"';
- outputStr += xmpTree.name;
- outputStr += '"';
-
- // Write all necessary xmlns attributes.
-
- size_t totalLen = 8; // Start at 8 for "xml:rdf:".
- XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin();
- XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end();
- for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size();
-
- XMP_VarString usedNS;
- usedNS.reserve ( totalLen );
- usedNS = "xml:rdf:";
-
- for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) {
- const XMP_Node * currSchema = xmpTree.children[schema];
- DeclareUsedNamespaces ( currSchema, usedNS, outputStr, newline, indentStr, baseIndent+4 );
- }
-
- // 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.
- // *** Elide the end tag if everything (all props in all schema) is an attr.
- 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 SerializePrettyRDFSchema 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 pretty 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;
-
- headStr.erase();
- headStr.reserve ( outputLen );
-
- // 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 "\">";
- headStr += newline;
- }
-
- // Write the rdf:RDF start tag.
- for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr;
- headStr += kRDF_RDFStart;
- headStr += newline;
-
- // Write all of the properties.
- if ( options & kXMP_UseCompactFormat ) {
- SerializeCompactRDFSchemas ( xmpObj.tree, headStr, newline, indentStr, baseIndent );
- } else {
- if ( xmpObj.tree.children.size() > 0 ) {
- for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) {
- const XMP_Node * currSchema = xmpObj.tree.children[schemaNum];
- SerializePrettyRDFSchema ( xmpObj.tree.name, currSchema, headStr, options, newline, indentStr, baseIndent );
- }
- } else {
- for ( XMP_Index level = baseIndent+2; level > 0; --level ) headStr += indentStr;
- headStr += kRDF_SchemaStart; // Special case an empty XMP object.
- headStr += '"';
- headStr += xmpObj.tree.name;
- headStr += "\"/>";
- headStr += newline;
- }
- }
-
- // Write the rdf:RDF end tag.
- for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr;
- headStr += kRDF_RDFEnd;
- 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';
- }
-
- // ! This assert is just a performance check, to see if the reserve was enough.
- // *** XMP_Assert ( headStr.size() <= outputLen );
- // *** Don't use an assert. Think of some way to track this without risk of aborting the client.
-
-} // SerializeAsRDF
-
-// -------------------------------------------------------------------------------------------------
-// SerializeToBuffer
-// -----------------
-
-void
-XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString,
- XMP_StringLen * rdfSize,
- XMP_OptionBits options,
- XMP_StringLen padding,
- XMP_StringPtr newline,
- XMP_StringPtr indentStr,
- XMP_Index baseIndent ) const
-{
- XMP_Assert ( (rdfString != 0) && (rdfSize != 0) && (newline != 0) && (indentStr != 0) );
-
- // 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 ( padding == 0 ) padding = kDefaultPad * unicodeUnitSize;
- 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, *sOutputStr, tailStr, options, newline, indentStr, baseIndent );
- if ( charEncoding == kXMP_EncodeUTF8 ) {
-
- if ( options & kXMP_ExactPacketLength ) {
- size_t minSize = sOutputStr->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 ) {
- sOutputStr->append ( padding, ' ' );
- } else {
- padding -= newlineLen; // Write this newline last.
- while ( padding >= (100 + newlineLen) ) {
- sOutputStr->append ( 100, ' ' );
- *sOutputStr += newline;
- padding -= (100 + newlineLen);
- }
- sOutputStr->append ( padding, ' ' );
- *sOutputStr += newline;
- }
-
- *sOutputStr += 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 ( *sOutputStr );
- ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian );
- utf8Str.swap ( tailStr );
- ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian );
-
- if ( options & kXMP_ExactPacketLength ) {
- size_t minSize = sOutputStr->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 ) *sOutputStr += padStr;
- } else {
- padding -= newlineLen; // Write this newline last.
- while ( padding >= (200 + newlineLen) ) {
- for ( int i = 100; i > 0; --i ) *sOutputStr += padStr;
- *sOutputStr += newlineStr;
- padding -= (200 + newlineLen);
- }
- for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr;
- *sOutputStr += newlineStr;
- }
-
- *sOutputStr += 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 ( *sOutputStr );
- ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian );
- utf8Str.swap ( tailStr );
- ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian );
-
- if ( options & kXMP_ExactPacketLength ) {
- size_t minSize = sOutputStr->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 ) *sOutputStr += padStr;
- } else {
- padding -= newlineLen; // Write this newline last.
- while ( padding >= (400 + newlineLen) ) {
- for ( int i = 100; i > 0; --i ) *sOutputStr += padStr;
- *sOutputStr += newlineStr;
- padding -= (400 + newlineLen);
- }
- for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr;
- *sOutputStr += newlineStr;
- }
-
- *sOutputStr += tailStr;
-
- }
-
- }
-
- // Return the finished string.
-
- *rdfString = sOutputStr->c_str();
- *rdfSize = sOutputStr->size();
-
-} // SerializeToBuffer
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta.cpp
deleted file mode 100644
index 88ee909649..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta.cpp
+++ /dev/null
@@ -1,1695 +0,0 @@
-// =================================================================================================
-// 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.
-//
-// 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 "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-
-#include <stdio.h>
-
-#include "XMPMeta.hpp"
-#include "XMPIterator.hpp"
-#include "XMPUtils.hpp"
-#include "XMP_Version.h"
-#include "UnicodeInlines.incl_cpp"
-#include "UnicodeConversions.hpp"
-
-#include <algorithm> // For sort and stable_sort.
-#include <stdio.h> // For snprintf.
-
-#if XMP_DebugBuild
- #include <iostream>
-#endif
-
-using namespace std;
-
-namespace DngXmpSdk {
-
-#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;
-
-// These are embedded version strings.
-
-const char * kXMPCore_EmbeddedVersion = kXMPCore_VersionMessage;
-const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr;
-
-// =================================================================================================
-// Local 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() { status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) goto EXIT; }
-
-#define OutProcNChars(p,n) { status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) goto EXIT; }
-
-#define OutProcLiteral(lit) { status = (*outProc) ( refCon, (lit), strlen(lit) ); if ( status != 0 ) goto EXIT; }
-
-#define OutProcString(str) { status = (*outProc) ( refCon, (str).c_str(), (str).size() ); if ( status != 0 ) goto EXIT; }
-
-#define OutProcDecInt(num) { snprintf ( buffer, sizeof(buffer), "%d", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
- status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
-
-#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
- status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
-
-#define OutProcHexByte(num) { snprintf ( buffer, sizeof(buffer), "%.2X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
- status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
-
-static const char * kIndent = " ";
-#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); }
-
-
-// -------------------------------------------------------------------------------------------------
-// DumpClearString
-// ---------------
-
-static XMP_Status
-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, (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 status;
- }
- spanStart = spanEnd;
-
- }
-
-EXIT:
- return status;
-
-} // DumpClearString
-
-
-// -------------------------------------------------------------------------------------------------
-// DumpStringMap
-// -------------
-
-static XMP_Status
-DumpStringMap ( const XMP_StringMap & map, XMP_StringPtr label, XMP_TextOutputProc outProc, void * refCon )
-{
- XMP_Status status;
- 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();
- }
-
-EXIT:
- return status;
-
-} // DumpStringMap
-
-
-// -------------------------------------------------------------------------------------------------
-// DumpNodeOptions
-// ---------------
-
-static XMP_Status
-DumpNodeOptions ( XMP_OptionBits options,
- XMP_TextOutputProc outProc,
- void * refCon )
-{
- XMP_Status status;
- char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
-
- 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 );
-
- }
-
-EXIT:
- return status;
-
-} // DumpNodeOptions
-
-
-// -------------------------------------------------------------------------------------------------
-// DumpPropertyTree
-// ----------------
-
-// *** Extract the validation code into a separate routine to call on exit in debug builds.
-
-static XMP_Status
-DumpPropertyTree ( const XMP_Node * currNode,
- int indent,
- size_t itemIndex,
- XMP_TextOutputProc outProc,
- void * refCon )
-{
- XMP_Status status;
- 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 );
- status = DumpNodeOptions ( currNode->options, outProc, refCon );
- if ( status != 0 ) goto EXIT;
- }
-
- 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 => " );
- }
-
- status = DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon );
- if ( status != 0 ) goto EXIT;
-
- }
-
- 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 => " );
- }
-
- status = DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon );
- if ( status != 0 ) goto EXIT;
-
- }
-
-EXIT:
- return status;
-
-} // 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
-
-
-// =================================================================================================
-// Constructors
-// ============
-
-
-XMPMeta::XMPMeta() : tree(XMP_Node(0,"",0)), clientRefs(0), prevTkVer(0), xmlParser(0)
-{
- // Nothing more to do, clientRefs is incremented in wrapper.
- #if XMP_TraceCTorDTor
- printf ( "Default construct XMPMeta @ %.8X\n", this );
- #endif
-} // 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 = XMP_API_VERSION_MAJOR;
- info->minor = XMP_API_VERSION_MINOR;
- info->micro = XMP_API_VERSION_MICRO;
- info->isDebug = kXMPCore_DebugFlag;
- info->flags = 0; // ! None defined yet.
- info->message = kXMPCore_VersionMessage;
-
-} // GetVersionInfo
-
-// -------------------------------------------------------------------------------------------------
-// Initialize
-// ----------
-
-/* class-static */ bool
-XMPMeta::Initialize()
-{
- // Allocate and initialize static objects.
-
- ++sXMP_InitCount;
- if ( sXMP_InitCount > 1 ) return true;
-
- #if TraceXMPCalls
- // xmpOut = fopen ( "xmp.out", "w" ); // Coordinate with client glue in WXMP_Common.hpp
- fprintf ( xmpOut, "XMP initializing\n" ); fflush ( xmpOut );
- #endif
-
- sExceptionMessage = new XMP_VarString();
- XMP_InitMutex ( &sXMPCoreLock );
- sOutputNS = new XMP_VarString;
- sOutputStr = new XMP_VarString;
-
- xdefaultName = new XMP_VarString ( "x-default" );
-
- sNamespaceURIToPrefixMap = new XMP_StringMap;
- sNamespacePrefixToURIMap = new XMP_StringMap;
- 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_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_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_DICOM, "DICOM", &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 );
-
- XMPMeta::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 miscellaneous 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_OptionBits) == 4 ); // Check that option masking work on all 32 bits.
- XMP_OptionBits flag = ~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 = ~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
-// ---------
-
-#define EliminateGlobal(g) delete ( g ); g = 0
-
-/* class-static */ void
-XMPMeta::Terminate() RELEASE_NO_THROW
-{
- --sXMP_InitCount;
- if ( sXMP_InitCount > 0 ) return;
-
- #if TraceXMPCalls
- fprintf ( xmpOut, "XMP terminating\n" ); fflush ( xmpOut );
- // fclose ( xmpOut ); // Coordinate with fopen in XMPMeta::Initialize.
- #endif
-
- XMPIterator::Terminate();
- XMPUtils::Terminate();
- EliminateGlobal ( sNamespaceURIToPrefixMap );
- EliminateGlobal ( sNamespacePrefixToURIMap );
- EliminateGlobal ( sRegisteredAliasMap );
-
- EliminateGlobal ( xdefaultName );
- EliminateGlobal ( sOutputNS );
- EliminateGlobal ( sOutputStr );
- EliminateGlobal ( sExceptionMessage );
-
- XMP_TermMutex ( sXMPCoreLock );
-
-} // Terminate
-
-
-// -------------------------------------------------------------------------------------------------
-// Unlock
-// ------
-
-/* class-static */ void
-XMPMeta::Unlock ( XMP_OptionBits options )
-{
- options = options; // Avoid unused parameter warning. // *** Need IgnoreParam macro.
-
- #if TraceXMPLocking
- fprintf ( xmpOut, " Unlocking XMP toolkit, count = %d\n", sLockCount ); fflush ( xmpOut );
- #endif
- --sLockCount;
- XMP_Assert ( sLockCount == 0 );
- XMP_ExitCriticalRegion ( sXMPCoreLock );
-
-} // Unlock
-
-
-// -------------------------------------------------------------------------------------------------
-// UnlockObject
-// ------------
-
-void
-XMPMeta::UnlockObject ( XMP_OptionBits options ) const
-{
- options = options; // Avoid unused parameter warning.
-
- XMPMeta::Unlock ( 0 );
-
-} // UnlockObject
-
-
-// -------------------------------------------------------------------------------------------------
-// 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 )
-{
- XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
- XMP_Status status = 0;
-
- XMP_StringMapPos p2uEnd = sNamespacePrefixToURIMap->end(); // ! Move up to avoid gcc complaints.
- XMP_StringMapPos u2pEnd = sNamespaceURIToPrefixMap->end();
-
- status = DumpStringMap ( *sNamespacePrefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon );
- if ( status != 0 ) goto EXIT;
-
- if ( sNamespacePrefixToURIMap->size() != sNamespaceURIToPrefixMap->size() ) {
- OutProcLiteral ( "** bad namespace map sizes **" );
- XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
- }
-
- for ( XMP_StringMapPos nsLeft = sNamespacePrefixToURIMap->begin(); nsLeft != p2uEnd; ++nsLeft ) {
-
- XMP_StringMapPos nsOther = sNamespaceURIToPrefixMap->find ( nsLeft->second );
- if ( (nsOther == u2pEnd) || (nsLeft != sNamespacePrefixToURIMap->find ( nsOther->second )) ) {
- OutProcLiteral ( " ** bad namespace URI ** " );
- DumpClearString ( nsLeft->second, outProc, refCon );
- goto FAILURE;
- }
-
- for ( XMP_StringMapPos 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 );
- goto FAILURE;
- }
- }
-
- }
-
- for ( XMP_StringMapPos nsLeft = sNamespaceURIToPrefixMap->begin(); nsLeft != u2pEnd; ++nsLeft ) {
-
- XMP_StringMapPos nsOther = sNamespacePrefixToURIMap->find ( nsLeft->second );
- if ( (nsOther == p2uEnd) || (nsLeft != sNamespaceURIToPrefixMap->find ( nsOther->second )) ) {
- OutProcLiteral ( " ** bad namespace prefix ** " );
- DumpClearString ( nsLeft->second, outProc, refCon );
- goto FAILURE;
- }
-
- for ( XMP_StringMapPos 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 );
- goto FAILURE;
- }
- }
-
- }
-
-EXIT:
- return status;
-
-FAILURE:
- OutProcNewline();
- (void) DumpStringMap ( *sNamespaceURIToPrefixMap, "Dumping namespace URI to prefix map", outProc, refCon );
- XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
- return 0;
-
-} // DumpNamespaces
-
-
-// -------------------------------------------------------------------------------------------------
-// DumpAliases
-// -----------
-
-/* class-static */ XMP_Status
-XMPMeta::DumpAliases ( XMP_TextOutputProc outProc,
- void * refCon )
-{
- XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
- XMP_Status status = 0;
-
- XMP_Assert ( sRegisteredAliasMap != 0 );
-
- XMP_cAliasMapPos aliasPos;
- XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end();
-
- size_t maxLen = 0;
- for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) {
- size_t currLen = aliasPos->first.size();
- if ( currLen > maxLen ) maxLen = currLen;
- }
-
- OutProcLiteral ( "Dumping alias name to actual path map" );
- OutProcNewline();
-
- for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) {
-
- OutProcNChars ( " ", 3 );
- DumpClearString ( aliasPos->first, outProc, refCon );
- OutProcPadding ( maxLen - aliasPos->first.size() );
- OutProcNChars ( " => ", 4 );
-
- size_t actualPathSize = aliasPos->second.size();
- for ( size_t stepNum = 1; stepNum < actualPathSize; ++stepNum ) OutProcString ( aliasPos->second[stepNum].step );
-
- XMP_OptionBits arrayForm = aliasPos->second[1].options & kXMP_PropArrayFormMask;
-
- if ( arrayForm == 0 ) {
- if ( actualPathSize != 2 ) OutProcLiteral ( " ** bad actual path **" );
- } else {
- OutProcNChars ( " ", 2 );
- DumpNodeOptions ( arrayForm, outProc, refCon );
- if ( ! (arrayForm & kXMP_PropValueIsArray) ) OutProcLiteral ( " ** bad array form **" );
- if ( actualPathSize != 3 ) OutProcLiteral ( " ** bad actual path **" );
- }
-
- if ( aliasPos->second[0].options != kXMP_SchemaNode ) OutProcLiteral ( " ** bad schema form **" );
-
- OutProcNewline();
-
- }
-
-EXIT:
- return status;
-
-} // DumpAliases
-
-
-// -------------------------------------------------------------------------------------------------
-// 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 )
-{
- bool prefixMatches = false;
-
- XMP_Assert ( (registeredPrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper.
- if ( (*namespaceURI == 0) || (*suggestedPrefix == 0) ) {
- XMP_Throw ( "Empty namespace URI or prefix", kXMPErr_BadParam );
- }
-
- XMP_VarString nsURI ( namespaceURI );
- XMP_VarString suggPrefix ( suggestedPrefix );
- if ( suggPrefix[suggPrefix.size()-1] != ':' ) suggPrefix += ':';
- VerifySimpleXMLName ( suggestedPrefix, suggestedPrefix+suggPrefix.size()-1 ); // Exclude the colon.
-
- XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI );
-
- if ( uriPos == sNamespaceURIToPrefixMap->end() ) {
-
- // The URI is not yet registered, make sure we use a unique prefix.
-
- XMP_VarString uniqPrefix ( suggPrefix );
- int suffix = 0;
- char buffer [32];
-
- while ( true ) {
- if ( sNamespacePrefixToURIMap->find ( uniqPrefix ) == sNamespacePrefixToURIMap->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 ( nsURI, uniqPrefix );
- uriPos = sNamespaceURIToPrefixMap->insert ( sNamespaceURIToPrefixMap->end(), newNS );
-
- newNS.first.swap ( newNS.second );
- (void) sNamespacePrefixToURIMap->insert ( sNamespacePrefixToURIMap->end(), newNS );
-
- }
-
- // Return the actual prefix and see if it matches the suggested prefix.
-
- *registeredPrefix = uriPos->second.c_str();
- *prefixSize = uriPos->second.size();
-
- prefixMatches = ( uriPos->second == suggPrefix );
- return prefixMatches;
-
-} // RegisterNamespace
-
-
-// -------------------------------------------------------------------------------------------------
-// GetNamespacePrefix
-// ------------------
-
-/* class-static */ bool
-XMPMeta::GetNamespacePrefix ( XMP_StringPtr namespaceURI,
- XMP_StringPtr * namespacePrefix,
- XMP_StringLen * prefixSize )
-{
- bool found = false;
-
- XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper.
- XMP_Assert ( (namespacePrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper.
-
- XMP_VarString nsURI ( namespaceURI );
- XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI );
-
- if ( uriPos != sNamespaceURIToPrefixMap->end() ) {
- *namespacePrefix = uriPos->second.c_str();
- *prefixSize = uriPos->second.size();
- found = true;
- }
-
- return found;
-
-} // GetNamespacePrefix
-
-
-// -------------------------------------------------------------------------------------------------
-// GetNamespaceURI
-// ---------------
-
-/* class-static */ bool
-XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix,
- XMP_StringPtr * namespaceURI,
- XMP_StringLen * uriSize )
-{
- bool found = false;
-
- XMP_Assert ( *namespacePrefix != 0 ); // ! Enforced by wrapper.
- XMP_Assert ( (namespacePrefix != 0) && (namespaceURI != 0) ); // ! Enforced by wrapper.
-
- XMP_VarString nsPrefix ( namespacePrefix );
- if ( nsPrefix[nsPrefix.size()-1] != ':' ) nsPrefix += ':';
-
- XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix );
-
- if ( prefixPos != sNamespacePrefixToURIMap->end() ) {
- *namespaceURI = prefixPos->second.c_str();
- *uriSize = prefixPos->second.size();
- found = true;
- }
-
- return found;
-
-} // 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_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( namespaceURI );
- if ( uriPos == sNamespaceURIToPrefixMap->end() ) return;
-
- XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( uriPos->second );
- XMP_Assert ( prefixPos != sNamespacePrefixToURIMap->end() );
-
- sNamespaceURIToPrefixMap->erase ( uriPos );
- sNamespacePrefixToURIMap->erase ( prefixPos );
-
-} // DeleteNamespace
-
-
-// -------------------------------------------------------------------------------------------------
-// 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.
-
-/* class-static */ void
-XMPMeta::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
-
-
-// -------------------------------------------------------------------------------------------------
-// ResolveAlias
-// ------------
-
-/* class-static */ bool
-XMPMeta::ResolveAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr * actualNS,
- XMP_StringLen * nsSize,
- XMP_StringPtr * actualProp,
- XMP_StringLen * propSize,
- XMP_OptionBits * arrayForm )
-{
- XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper.
- XMP_Assert ( (actualNS != 0) && (nsSize != 0) && (actualProp != 0) && (propSize != 0) && (arrayForm != 0) ); // Enforced by wrapper.
-
- // Expand the input path and look up the first component in the alias table. Return if not an alias.
-
- XMP_ExpandedXPath fullPath, minPath;
- ExpandXPath ( aliasNS, aliasProp, &fullPath );
- XMP_Assert ( fullPath.size() >= 2 );
-
- minPath.push_back ( fullPath[kSchemaStep] );
- minPath.push_back ( fullPath[kRootPropStep] );
- XMP_AliasMapPos mapPos = sRegisteredAliasMap->find ( minPath[kRootPropStep].step );
- if ( mapPos == sRegisteredAliasMap->end() ) return false;
-
- // Replace the alias portion of the full expanded path. Compose the output path string.
-
- const XMP_ExpandedXPath & actualPath = mapPos->second;
-
- fullPath[kSchemaStep] = actualPath[kSchemaStep];
- fullPath[kRootPropStep] = actualPath[kRootPropStep];
- if ( actualPath.size() > 2 ) { // This is an alias to an array item.
- XMP_ExpandedXPathPos insertPos = fullPath.begin() + kAliasIndexStep;
- fullPath.insert ( insertPos, actualPath[kAliasIndexStep] );
- }
-
- *sOutputNS = fullPath[kSchemaStep].step;
- *actualNS = sOutputNS->c_str();
- *nsSize = sOutputNS->size();
-
- ComposeXPath ( fullPath, sOutputStr );
- *actualProp = sOutputStr->c_str();
- *propSize = sOutputStr->size();
-
- *arrayForm = actualPath[kRootPropStep].options & kXMP_PropArrayFormMask;
-
- #if XMP_DebugBuild // Test that the output string is valid and unchanged by round trip expand/compose.
- XMP_ExpandedXPath rtPath;
- ExpandXPath ( *actualNS, *actualProp, &rtPath );
- std::string rtString;
- ComposeXPath ( rtPath, &rtString );
- XMP_Assert ( rtString == *sOutputStr );
- #endif
-
- return true;
-
-} // ResolveAlias
-
-
-// -------------------------------------------------------------------------------------------------
-// DeleteAlias
-// -----------
-
-/* class-static */ void
-XMPMeta::DeleteAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp )
-{
-
- XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper.
- XMP_Throw ( "Unimplemented method XMPMeta::DeleteAlias", kXMPErr_Unimplemented ); // *** #error "write me"
- void * p; p = &aliasNS; p = &aliasProp; // Avoid unused param warnings.
-
-} // DeleteAlias
-
-
-// -------------------------------------------------------------------------------------------------
-// RegisterStandardAliases
-// -----------------------
-
-/* class-static */ void
-XMPMeta::RegisterStandardAliases ( XMP_StringPtr schemaNS )
-{
- XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
-
- const bool doAll = (*schemaNS == 0);
-
- if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_XMP ) ) {
- // Aliases from XMP to DC.
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 );
- }
-
- if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PDF ) ) {
- // Aliases from PDF to DC and XMP.
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
- XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
- }
-
- if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_Photoshop ) ) {
- // Aliases from PHOTOSHOP to DC and XMP.
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText );
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
- XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 );
- }
-
- if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_TIFF ) || XMP_LitMatch ( schemaNS, kXMP_NS_EXIF ) ) {
- // Aliases from TIFF and EXIF to DC and XMP.
- XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
- XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
- }
-
- if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PNG ) ) { // ! From Acrobat ImageCapture:
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText);
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText);
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
- XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText);
- }
-
-} // RegisterStandardAliases
-
-
-// =================================================================================================
-// Class Methods
-// =============
-//
-//
-// =================================================================================================
-
-
-// -------------------------------------------------------------------------------------------------
-// DumpObject
-// ----------
-
-XMP_Status
-XMPMeta::DumpObject ( XMP_TextOutputProc outProc,
- void * refCon ) const
-{
- XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
- XMP_Status status = 0;
-
- OutProcLiteral ( "Dumping XMPMeta object \"" );
- DumpClearString ( tree.name, outProc, refCon );
- OutProcNChars ( "\" ", 3 );
- status = DumpNodeOptions ( tree.options, outProc, refCon );
- if ( status != 0 ) goto EXIT;
- #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 ) {
- status = 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 );
- status = DumpNodeOptions ( currSchema->options, outProc, refCon );
- if ( status != 0 ) goto EXIT;
- #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 childNum = 0, childLim = currSchema->children.size(); childNum < childLim; ++childNum ) {
- DumpPropertyTree ( currSchema->children[childNum], 2, 0, outProc, refCon );
- }
-
- }
-
- }
-
-EXIT:
- return status;
-
-} // 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()
-{
-
- this->prevTkVer = 0;
- 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;
-
- #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
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta.hpp
deleted file mode 100644
index dee21eb502..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPMeta.hpp
+++ /dev/null
@@ -1,423 +0,0 @@
-#ifndef __XMPMeta_hpp__
-#define __XMPMeta_hpp__
-
-// =================================================================================================
-// 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.
-// =================================================================================================
-
-#include "XMP_Environment.h"
-#include "XMP_Const.h"
-#include "XMPCore_Impl.hpp"
-#include "XMLParserAdapter.hpp"
-
-// -------------------------------------------------------------------------------------------------
-
-namespace DngXmpSdk {
-
-#ifndef DumpXMLParseTree
- #define DumpXMLParseTree 0
-#endif
-
-extern XMP_VarString * xdefaultName;
-
-class XMPIterator;
-class XMPUtils;
-
-// -------------------------------------------------------------------------------------------------
-
-class XMPMeta {
-public:
-
- static void
- GetVersionInfo ( XMP_VersionInfo * info );
-
- static bool
- Initialize();
- static void
- Terminate() RELEASE_NO_THROW;
-
- static void
- Unlock ( XMP_OptionBits options );
-
- // ---------------------------------------------------------------------------------------------
-
- 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 XMP_Status
- DumpAliases ( 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 );
-
- // ---------------------------------------------------------------------------------------------
-
- static void
- RegisterAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr actualNS,
- XMP_StringPtr actualProp,
- XMP_OptionBits arrayForm );
-
- static bool
- ResolveAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr * actualNS,
- XMP_StringLen * nsSize,
- XMP_StringPtr * actualProp,
- XMP_StringLen * propSize,
- XMP_OptionBits * arrayForm );
-
- static void
- DeleteAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp );
-
- static void
- RegisterStandardAliases ( XMP_StringPtr schemaNS );
-
- // ---------------------------------------------------------------------------------------------
-
- void
- UnlockObject ( XMP_OptionBits options ) const;
-
- // ---------------------------------------------------------------------------------------------
-
- 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 );
-
- // ---------------------------------------------------------------------------------------------
-
- 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;
-
- XMP_Status
- DumpObject ( XMP_TextOutputProc outProc,
- void * refCon ) const;
-
- // ---------------------------------------------------------------------------------------------
-
- void
- ParseFromBuffer ( XMP_StringPtr buffer,
- XMP_StringLen bufferSize,
- XMP_OptionBits options );
-
- void
- SerializeToBuffer ( XMP_StringPtr * rdfString,
- XMP_StringLen * rdfSize,
- XMP_OptionBits options,
- XMP_StringLen padding,
- XMP_StringPtr newline,
- XMP_StringPtr indent,
- XMP_Index baseIndent ) 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_Int32 prevTkVer; // Previous toolkit version as MMmmuubbb (major, minor, micro, build).
- XMP_Node tree;
-
- XMLParserAdapter * xmlParser;
-
- friend class XMPIterator;
- friend class XMPUtils;
-
-private:
-
- // ! These are hidden on purpose:
- XMPMeta ( const XMPMeta & /* original */ ) : tree(XMP_Node(0,"",0)), clientRefs(0), prevTkVer(0), xmlParser(0)
- { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
- void operator= ( const XMPMeta & /* rhs */ )
- { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); };
-
-}; // class XMPMeta
-
-
-} // namespace DngXmpSdk
-// =================================================================================================
-
-#endif // __XMPMeta_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils-FileInfo.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils-FileInfo.cpp
deleted file mode 100644
index c1f4fb15ab..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils-FileInfo.cpp
+++ /dev/null
@@ -1,1345 +0,0 @@
-// =================================================================================================
-// 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.
-// =================================================================================================
-
-#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.
-
-namespace DngXmpSdk {
-
-#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 to 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;
- } 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;
- 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 occurrence. 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!
-
-#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" ) isInternal = true;
-
- } else if ( schema == kXMP_NS_CameraRaw ) {
-
- if ( (prop == "crs:Version") ||
- (prop == "crs:RawFileName") ||
- (prop == "crs:ToneCurveName") ) {
- 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 replaceOld, const bool deleteEmpty )
-{
- XMP_NodePtrPos destPos;
- XMP_Node * destNode = FindChildNode ( destParent, sourceNode->name.c_str(), kXMP_ExistingOnly, &destPos );
-
- bool valueIsEmpty = false;
- if ( deleteEmpty ) {
- if ( XMP_PropIsSimple ( sourceNode->options ) ) {
- valueIsEmpty = sourceNode->value.empty();
- } else {
- valueIsEmpty = sourceNode->children.empty();
- }
- }
-
- if ( deleteEmpty & valueIsEmpty ) {
-
- if ( destNode != 0 ) {
- delete ( destNode );
- destParent->children.erase ( destPos );
- }
-
- } else if ( destNode == 0 ) {
-
- // The one easy case, the destination does not exist.
- CloneSubtree ( sourceNode, destParent );
-
- } else if ( replaceOld ) {
-
- // The destination exists and should be replaced.
-
- destNode->value = sourceNode->value; // *** Should use SetNode.
- destNode->options = sourceNode->options;
- destNode->RemoveChildren();
- destNode->RemoveQualifiers();
- CloneOffspring ( sourceNode, destNode );
-
- #if 0 // *** XMP_DebugBuild
- destNode->_valuePtr = destNode->value.c_str();
- #endif
-
- } else {
-
- // The destination exists and is not totally replaced. Structs and arrays are merged.
-
- XMP_OptionBits sourceForm = sourceNode->options & kXMP_PropCompositeMask;
- XMP_OptionBits destForm = destNode->options & kXMP_PropCompositeMask;
- if ( 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; ++sourceNum ) {
- const XMP_Node * sourceField = sourceNode->children[sourceNum];
- AppendSubtree ( sourceField, destNode, 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.
-
- for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++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 ( deleteEmpty && sourceItem->value.empty() ) {
-
- if ( 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 ) continue; // Not replacing, keep the existing item.
-
- if ( (sourceItem->qualifiers[0]->value != "x-default") || destNode->children.empty() ) {
- CloneSubtree ( sourceItem, destNode );
- } else {
- XMP_Node * destItem = new XMP_Node ( destNode, sourceItem->name, sourceItem->value, sourceItem->options );
- CloneOffspring ( sourceItem, destItem );
- 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 );
-
- }
-
- }
-
- }
-
-} // 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_StringPtr * catedStr,
- XMP_StringLen * catedLen )
-{
- XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // ! Enforced by wrapper.
- XMP_Assert ( (separator != 0) && (quotes != 0) && (catedStr != 0) && (catedLen != 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.
-
- sCatenatedItems->erase();
-
- XMP_ExpandedXPath arrayPath;
- ExpandXPath ( schemaNS, arrayName, &arrayPath );
-
- arrayNode = FindConstNode ( &xmpObj.tree, arrayPath );
- if ( arrayNode == 0 ) goto EXIT; // ! Need to set the output pointer and length.
-
- 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() ) goto EXIT; // ! Need to set the output pointer and length.
-
- // 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 preceding separator.
-
- currItem = arrayNode->children[0];
-
- if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam );
- *sCatenatedItems = currItem->value;
- ApplyQuotes ( sCatenatedItems, openQuote, closeQuote, allowCommas );
-
- for ( size_t itemNum = 1, itemLim = arrayNode->children.size(); itemNum != itemLim; ++itemNum ) {
- const XMP_Node * currItem = arrayNode->children[itemNum];
- if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam );
- XMP_VarString tempStr ( currItem->value );
- ApplyQuotes ( &tempStr, openQuote, closeQuote, allowCommas );
- *sCatenatedItems += separator;
- *sCatenatedItems += tempStr;
- }
-
-EXIT:
- *catedStr = sCatenatedItems->c_str();
- *catedLen = sCatenatedItems->size();
-
-} // 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
-
-
-// -------------------------------------------------------------------------------------------------
-// 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
-
-
-// -------------------------------------------------------------------------------------------------
-// AppendProperties
-// ----------------
-
-/* class static */ void
-XMPUtils::AppendProperties ( const XMPMeta & source,
- XMPMeta * dest,
- XMP_OptionBits options )
-{
- XMP_Assert ( dest != 0 ); // ! Enforced by wrapper.
-
- const bool doAll = ((options & kXMPUtil_DoAllProperties) != 0);
- const bool replaceOld = ((options & kXMPUtil_ReplaceOldValues) != 0);
- const bool deleteEmpty = ((options & kXMPUtil_DeleteEmptyValues) != 0);
-
- for ( size_t schemaNum = 0, schemaLim = source.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {
-
- const XMP_Node * sourceSchema = source.tree.children[schemaNum];
-
- // Make sure we have a destination schema node. Remember if it is newly created.
-
- XMP_Node * destSchema = FindSchemaNode ( &dest->tree, sourceSchema->name.c_str(), kXMP_ExistingOnly );
- const bool newDestSchema = (destSchema == 0);
- if ( newDestSchema ) {
- destSchema = new XMP_Node ( &dest->tree, sourceSchema->name, sourceSchema->value, kXMP_SchemaNode );
- dest->tree.children.push_back ( destSchema );
- }
-
- // Process the source schema's children. Do this backwards in case deleteEmpty is set.
-
- for ( long propNum = ((long)sourceSchema->children.size() - 1); propNum >= 0; --propNum ) {
- const XMP_Node * sourceProp = sourceSchema->children[propNum];
- if ( doAll || IsExternalProperty ( sourceSchema->name, sourceProp->name ) ) {
- AppendSubtree ( sourceProp, destSchema, replaceOld, deleteEmpty );
-// *** RemoveMultiValueInfo ( dest, sourceSchema->name.c_str(), sourceProp->name.c_str() );
- }
- }
-
- if ( destSchema->children.empty() ) {
- if ( newDestSchema ) {
- delete ( destSchema );
- dest->tree.children.pop_back();
- } else if ( deleteEmpty ) {
- DeleteEmptySchema ( destSchema );
- }
- }
-
- }
-
-} // AppendProperties
-
-
-// -------------------------------------------------------------------------------------------------
-// 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 )
-{
- options = options; // Avoid unused parameter warning.
-
- 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 sourcePath;
- ExpandXPath ( sourceNS, sourceRoot, &sourcePath );
- sourceNode = FindConstNode ( &source.tree, sourcePath );
-
- 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 ( ':' );
- 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
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils.cpp
deleted file mode 100644
index 152a3d4a5c..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils.cpp
+++ /dev/null
@@ -1,2123 +0,0 @@
-// =================================================================================================
-// Copyright 2002-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 "XMP_Environment.h" // ! This must be the first include!
-#include "XMPCore_Impl.hpp"
-#include "XMPUtils.hpp"
-
-#include "XMP_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
-namespace DngXmpSdk {
-
-// =================================================================================================
-// Local Types and Constants
-// =========================
-
-static const char * sBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-// =================================================================================================
-// Static Variables
-// ================
-
-XMP_VarString * sComposedPath = 0; // *** Only really need 1 string. Shrink periodically?
-XMP_VarString * sConvertedValue = 0;
-XMP_VarString * sBase64Str = 0;
-XMP_VarString * sCatenatedItems = 0;
-XMP_VarString * sStandardXMP = 0;
-XMP_VarString * sExtendedXMP = 0;
-XMP_VarString * sExtendedDigest = 0;
-
-// =================================================================================================
-// Local Utilities
-// ===============
-
-
-// -------------------------------------------------------------------------------------------------
-// ANSI Time Functions
-// -------------------
-//
-// A bit of hackery to use the best available time functions. Mac and UNIX have thread safe versions
-// of gmtime and localtime. On Mac the CodeWarrior functions are buggy, use Apple's.
-
-#if XMP_UNIXBuild
-
- 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
-
-#elif XMP_MacBuild
-
- #if ! __MWERKS__
-
- 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
-
- #else
-
- // ! The CW versions are buggy. Use Apple's code, time_t, and "struct tm".
-
- #include <mach-o/dyld.h>
-
- typedef _BSD_TIME_T_ ansi_tt;
-
- typedef struct apple_tm {
- int tm_sec; /* seconds after the minute [0-60] */
- int tm_min; /* minutes after the hour [0-59] */
- int tm_hour; /* hours since midnight [0-23] */
- int tm_mday; /* day of the month [1-31] */
- int tm_mon; /* months since January [0-11] */
- int tm_year; /* years since 1900 */
- int tm_wday; /* days since Sunday [0-6] */
- int tm_yday; /* days since January 1 [0-365] */
- int tm_isdst; /* Daylight Savings Time flag */
- long tm_gmtoff; /* offset from CUT in seconds */
- char *tm_zone; /* timezone abbreviation */
- } ansi_tm;
-
-
- typedef ansi_tt (* GetTimeProc) ( ansi_tt * ttTime );
- typedef ansi_tt (* MakeTimeProc) ( ansi_tm * tmTime );
- typedef double (* DiffTimeProc) ( ansi_tt t1, ansi_tt t0 );
-
- typedef void (* ConvertTimeProc) ( const ansi_tt * ttTime, ansi_tm * tmTime );
-
- static GetTimeProc ansi_time = 0;
- static MakeTimeProc ansi_mktime = 0;
- static DiffTimeProc ansi_difftime = 0;
-
- static ConvertTimeProc ansi_gmtime = 0;
- static ConvertTimeProc ansi_localtime = 0;
-
- static void LookupTimeProcs()
- {
- _dyld_lookup_and_bind_with_hint ( "_time", "libSystem", (XMP_Uns32*)&ansi_time, 0 );
- _dyld_lookup_and_bind_with_hint ( "_mktime", "libSystem", (XMP_Uns32*)&ansi_mktime, 0 );
- _dyld_lookup_and_bind_with_hint ( "_difftime", "libSystem", (XMP_Uns32*)&ansi_difftime, 0 );
- _dyld_lookup_and_bind_with_hint ( "_gmtime_r", "libSystem", (XMP_Uns32*)&ansi_gmtime, 0 );
- _dyld_lookup_and_bind_with_hint ( "_localtime_r", "libSystem", (XMP_Uns32*)&ansi_localtime, 0 );
- }
-
- #endif
-
-#endif
-
-
-// -------------------------------------------------------------------------------------------------
-// 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 pathological 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
-// ---------
-
-static XMP_Int32
-GatherInt ( XMP_StringPtr strValue, size_t * _pos, const char * errMsg )
-{
- size_t pos = *_pos;
- XMP_Int32 value = 0;
-
- for ( char ch = strValue[pos]; ('0' <= ch) && (ch <= '9'); ++pos, ch = strValue[pos] ) {
- value = (value * 10) + (ch - '0');
- }
-
- if ( pos == *_pos ) XMP_Throw ( errMsg, kXMPErr_BadParam );
- *_pos = pos;
- return 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 );
- 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()
-{
- sComposedPath = new XMP_VarString();
- sConvertedValue = new XMP_VarString();
- sBase64Str = new XMP_VarString();
- sCatenatedItems = new XMP_VarString();
- sStandardXMP = new XMP_VarString();
- sExtendedXMP = new XMP_VarString();
- sExtendedDigest = new XMP_VarString();
-
- #if XMP_MacBuild && __MWERKS__
- LookupTimeProcs();
- #endif
-
- return true;
-
-} // Initialize
-
-
-// -------------------------------------------------------------------------------------------------
-// Terminate
-// ---------
-
-#define EliminateGlobal(g) delete ( g ); g = 0
-
-/* class static */ void
-XMPUtils::Terminate() RELEASE_NO_THROW
-{
- EliminateGlobal ( sComposedPath );
- EliminateGlobal ( sConvertedValue );
- EliminateGlobal ( sBase64Str );
- EliminateGlobal ( sCatenatedItems );
- EliminateGlobal ( sStandardXMP );
- EliminateGlobal ( sExtendedXMP );
- EliminateGlobal ( sExtendedDigest );
-
- return;
-
-} // Terminate
-
-
-// -------------------------------------------------------------------------------------------------
-// Unlock
-// ------
-
-/* class static */ void
-XMPUtils::Unlock ( XMP_OptionBits options )
-{
- options = options; // Avoid unused parameter warning.
-
- XMPMeta::Unlock ( 0 );
-
-} // Unlock
-
-// -------------------------------------------------------------------------------------------------
-// ComposeArrayItemPath
-// --------------------
-//
-// Return "arrayName[index]".
-
-/* class static */ void
-XMPUtils::ComposeArrayItemPath ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize )
-{
- XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
- XMP_Assert ( *arrayName != 0 ); // Enforced by wrapper.
- XMP_Assert ( (fullPath != 0) && (pathSize != 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.
-
- sComposedPath->erase();
- sComposedPath->reserve ( reserveLen );
- sComposedPath->append ( reserveLen, ' ' );
-
- if ( itemIndex != kXMP_ArrayLastItem ) {
- // AUDIT: Using string->size() for the snprintf length is safe.
- snprintf ( const_cast<char*>(sComposedPath->c_str()), sComposedPath->size(), "%s[%d]", arrayName, itemIndex );
- } else {
- *sComposedPath = arrayName;
- *sComposedPath += "[last()] ";
- (*sComposedPath)[sComposedPath->size()-1] = 0; // ! Final null is for the strlen at exit.
- }
-
- *fullPath = sComposedPath->c_str();
- *pathSize = strlen ( *fullPath ); // ! Don't use sComposedPath->size()!
-
- XMP_Enforce ( *pathSize < sComposedPath->size() ); // Rather late, but complain about buffer overflow.
-
-} // ComposeArrayItemPath
-
-
-// -------------------------------------------------------------------------------------------------
-// ComposeStructFieldPath
-// ----------------------
-//
-// Return "structName/ns:fieldName".
-
-/* class static */ void
-XMPUtils::ComposeStructFieldPath ( XMP_StringPtr schemaNS,
- XMP_StringPtr structName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize )
-{
- XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) ); // Enforced by wrapper.
- XMP_Assert ( (*structName != 0) && (*fieldName != 0) ); // Enforced by wrapper.
- XMP_Assert ( (fullPath != 0) && (pathSize != 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;
-
- sComposedPath->erase();
- sComposedPath->reserve ( reserveLen );
- *sComposedPath = structName;
- *sComposedPath += '/';
- *sComposedPath += fieldPath[kRootPropStep].step;
-
- *fullPath = sComposedPath->c_str();
- *pathSize = sComposedPath->size();
-
-} // ComposeStructFieldPath
-
-
-// -------------------------------------------------------------------------------------------------
-// ComposeQualifierPath
-// --------------------
-//
-// Return "propName/?ns:qualName".
-
-/* class static */ void
-XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr qualNS,
- XMP_StringPtr qualName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize )
-{
- XMP_Assert ( (schemaNS != 0) && (qualNS != 0) ); // Enforced by wrapper.
- XMP_Assert ( (*propName != 0) && (*qualName != 0) ); // Enforced by wrapper.
- XMP_Assert ( (fullPath != 0) && (pathSize != 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;
-
- sComposedPath->erase();
- sComposedPath->reserve ( reserveLen );
- *sComposedPath = propName;
- *sComposedPath += "/?";
- *sComposedPath += qualPath[kRootPropStep].step;
-
- *fullPath = sComposedPath->c_str();
- *pathSize = sComposedPath->size();
-
-} // 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_StringPtr * fullPath,
- XMP_StringLen * pathSize )
-{
- XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
- XMP_Assert ( (*arrayName != 0) && (*_langName != 0) ); // Enforced by wrapper.
- XMP_Assert ( (fullPath != 0) && (pathSize != 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;
-
- sComposedPath->erase();
- sComposedPath->reserve ( reserveLen );
- *sComposedPath = arrayName;
- *sComposedPath += "[?xml:lang=\"";
- *sComposedPath += langName;
- *sComposedPath += "\"]";
-
- *fullPath = sComposedPath->c_str();
- *pathSize = sComposedPath->size();
-
-} // 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_StringPtr * fullPath,
- XMP_StringLen * pathSize )
-{
- XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) && (fieldValue != 0) ); // Enforced by wrapper.
- XMP_Assert ( (*arrayName != 0) && (*fieldName != 0) ); // Enforced by wrapper.
- XMP_Assert ( (fullPath != 0) && (pathSize != 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;
-
- sComposedPath->erase();
- sComposedPath->reserve ( reserveLen );
- *sComposedPath = arrayName;
- *sComposedPath += '[';
- *sComposedPath += fieldPath[kRootPropStep].step;
- *sComposedPath += "=\"";
- *sComposedPath += fieldValue;
- *sComposedPath += "\"]";
-
- *fullPath = sComposedPath->c_str();
- *pathSize = sComposedPath->size();
-
-} // ComposeFieldSelector
-
-
-// -------------------------------------------------------------------------------------------------
-// ConvertFromBool
-// ---------------
-
-/* class static */ void
-XMPUtils::ConvertFromBool ( bool binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize )
-{
- XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
-
- if ( binValue ) {
- *strValue = kXMP_TrueStr;
- *strSize = strlen ( kXMP_TrueStr );
- } else {
- *strValue = kXMP_FalseStr;
- *strSize = strlen ( kXMP_FalseStr );
- }
-
-} // ConvertFromBool
-
-
-// -------------------------------------------------------------------------------------------------
-// ConvertFromInt
-// --------------
-
-/* class static */ void
-XMPUtils::ConvertFromInt ( XMP_Int32 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize )
-{
- XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
-
- if ( *format == 0 ) format = "%d";
-
- sConvertedValue->erase();
- sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value.
- sConvertedValue->append ( 100, ' ' );
-
- // AUDIT: Using string->size() for the snprintf length is safe.
- snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue );
-
- *strValue = sConvertedValue->c_str();
- *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()!
-
- XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow.
-
-} // ConvertFromInt
-
-
-// -------------------------------------------------------------------------------------------------
-// ConvertFromInt64
-// ----------------
-
-/* class static */ void
-XMPUtils::ConvertFromInt64 ( XMP_Int64 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize )
-{
- XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
-
- if ( *format == 0 ) format = "%lld";
-
- sConvertedValue->erase();
- sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value.
- sConvertedValue->append ( 100, ' ' );
-
- // AUDIT: Using string->size() for the snprintf length is safe.
- snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue );
-
- *strValue = sConvertedValue->c_str();
- *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()!
-
- XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow.
-
-} // ConvertFromInt64
-
-
-// -------------------------------------------------------------------------------------------------
-// ConvertFromFloat
-// ----------------
-
-/* class static */ void
-XMPUtils::ConvertFromFloat ( double binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize )
-{
- XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
-
- if ( *format == 0 ) format = "%f";
-
- sConvertedValue->erase();
- sConvertedValue->reserve ( 1000 ); // More than enough for any reasonable format and value.
- sConvertedValue->append ( 1000, ' ' );
-
- // AUDIT: Using string->size() for the snprintf length is safe.
- snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue );
-
- *strValue = sConvertedValue->c_str();
- *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()!
-
- XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow.
-
-} // ConvertFromFloat
-
-
-// -------------------------------------------------------------------------------------------------
-// ConvertFromDate
-// ---------------
-//
-// Format a date 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".
-
-// *** Need to check backward compatibility for partial forms!
-
-/* class static */ void
-XMPUtils::ConvertFromDate ( const XMP_DateTime & binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize )
-{
- XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper.
-
- bool addTimeZone = false;
- char buffer [100]; // Plenty long enough.
-
- // 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 tempDate = binValue;
-
- // Temporary fix for bug 1269463, silently fix out of range month or day.
-
- bool haveDay = (tempDate.day != 0);
- bool haveTime = ( (tempDate.hour != 0) || (tempDate.minute != 0) ||
- (tempDate.second != 0) || (tempDate.nanoSecond != 0) ||
- (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) );
-
- if ( tempDate.month == 0 ) {
- if ( haveDay || haveTime ) tempDate.month = 1;
- } else {
- if ( tempDate.month < 1 ) tempDate.month = 1;
- if ( tempDate.month > 12 ) tempDate.month = 12;
- }
-
- if ( tempDate.day == 0 ) {
- if ( haveTime ) tempDate.day = 1;
- } else {
- if ( tempDate.day < 1 ) tempDate.day = 1;
- if ( tempDate.day > 31 ) tempDate.day = 31;
- }
-
- // Now carry on with the original logic.
-
- if ( tempDate.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 ( (tempDate.day == 0) && (tempDate.hour == 0) && (tempDate.minute == 0) &&
- (tempDate.second == 0) && (tempDate.nanoSecond == 0) &&
- (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) {
- snprintf ( buffer, sizeof(buffer), "%.4d", tempDate.year ); // AUDIT: Using sizeof for snprintf length is safe.
- } else if ( (tempDate.year == 0) && (tempDate.day == 0) ) {
- FormatFullDateTime ( tempDate, buffer, sizeof(buffer) );
- addTimeZone = true;
- } else {
- XMP_Throw ( "Invalid partial date", kXMPErr_BadParam);
- }
-
- } else if ( tempDate.day == 0 ) {
-
- // Output YYYY-MM.
- if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam);
- if ( (tempDate.hour != 0) || (tempDate.minute != 0) ||
- (tempDate.second != 0) || (tempDate.nanoSecond != 0) ||
- (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) ) {
- XMP_Throw ( "Invalid partial date, non-zeros after zero month and day", kXMPErr_BadParam);
- }
- snprintf ( buffer, sizeof(buffer), "%.4d-%02d", tempDate.year, tempDate.month ); // AUDIT: Using sizeof for snprintf length is safe.
-
- } else if ( (tempDate.hour == 0) && (tempDate.minute == 0) &&
- (tempDate.second == 0) && (tempDate.nanoSecond == 0) &&
- (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) {
-
- // Output YYYY-MM-DD.
- if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam);
- if ( (tempDate.day < 1) || (tempDate.day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam);
- snprintf ( buffer, sizeof(buffer), "%.4d-%02d-%02d", tempDate.year, tempDate.month, tempDate.day ); // AUDIT: Using sizeof for snprintf length is safe.
-
- } else {
-
- FormatFullDateTime ( tempDate, buffer, sizeof(buffer) );
- addTimeZone = true;
-
- }
-
- sConvertedValue->assign ( buffer );
-
- if ( addTimeZone ) {
-
- if ( (tempDate.tzHour < 0) || (tempDate.tzHour > 23) ||
- (tempDate.tzMinute < 0 ) || (tempDate.tzMinute > 59) ||
- (tempDate.tzSign < -1) || (tempDate.tzSign > +1) ||
- ((tempDate.tzSign != 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0)) ||
- ((tempDate.tzSign == 0) && ((tempDate.tzHour != 0) || (tempDate.tzMinute != 0))) ) {
- XMP_Throw ( "Invalid time zone values", kXMPErr_BadParam );
- }
-
- if ( tempDate.tzSign == 0 ) {
- *sConvertedValue += 'Z';
- } else {
- snprintf ( buffer, sizeof(buffer), "+%02d:%02d", tempDate.tzHour, tempDate.tzMinute ); // AUDIT: Using sizeof for snprintf length is safe.
- if ( tempDate.tzSign < 0 ) buffer[0] = '-';
- *sConvertedValue += buffer;
- }
-
- }
-
- *strValue = sConvertedValue->c_str();
- *strSize = sConvertedValue->size();
-
-} // 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 );
- setlocale ( LC_ALL, "C" );
- }
-
- errno = 0;
- char * numEnd;
- double result = strtod ( strValue, &numEnd );
-
- if ( oldLocalePtr != 0 ) setlocale ( LC_ALL, oldLocalePtr ); // ! Reset locale before possible throw!
- if ( (errno != 0) || (*numEnd != 0) ) XMP_Throw ( "Invalid float string", kXMPErr_BadParam );
-
- return result;
-
-} // ConvertToFloat
-
-
-// -------------------------------------------------------------------------------------------------
-// ConvertToDate
-// -------------
-//
-// Parse a date 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".
-
-// ! Tolerate missing TZD, assume is UTC. Photoshop 8 writes dates like this for exif:GPSTimeStamp.
-// ! Tolerate missing date portion, in case someone foolishly writes a time-only value that way.
-
-// *** 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.
-
- bool timeOnly = ( (strValue[0] == 'T') ||
- ((strlen(strValue) >= 2) && (strValue[1] == ':')) ||
- ((strlen(strValue) >= 3) && (strValue[2] == ':')) );
-
- if ( ! timeOnly ) {
-
- 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 ( strValue[pos] == 'T' ) {
- ++pos;
- } else if ( ! timeOnly ) {
- XMP_Throw ( "Invalid date string, missing 'T' after date", kXMPErr_BadParam );
- }
-
- 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] == 'Z' ) {
-
- ++pos;
-
- } else if ( strValue[pos] != 0 ) {
-
- 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_StringPtr * encodedStr,
- XMP_StringLen * encodedLen )
-{
- if ( (rawStr == 0) && (rawLen != 0) ) XMP_Throw ( "Null raw data buffer", kXMPErr_BadParam );
- if ( rawLen == 0 ) {
- *encodedStr = 0;
- *encodedLen = 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.
-
- sBase64Str->erase();
- sBase64Str->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 ) {
- sBase64Str->append ( 1, kLF );
- out = 0;
- }
- sBase64Str->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 ) sBase64Str->append ( 1, kLF );
- sBase64Str->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 ) sBase64Str->append ( 1, kLF );
- sBase64Str->append ( encChunk, 4 );
- break;
-
- }
-
- // -------------------------
- // Assign the output values.
-
- *encodedStr = sBase64Str->c_str();
- *encodedLen = sBase64Str->size();
-
-} // 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_StringPtr * rawStr,
- XMP_StringLen * rawLen )
-{
- if ( (encodedStr == 0) && (encodedLen != 0) ) XMP_Throw ( "Null encoded data buffer", kXMPErr_BadParam );
- if ( encodedLen == 0 ) {
- *rawStr = 0;
- *rawLen = 0;
- return;
- }
-
- unsigned char ch, rawChunk[3];
- unsigned long inStr, inChunk, inLimit, merge, padding;
-
- XMP_StringLen outputSize = (encodedLen / 4) * 3; // Only a close approximation.
-
- sBase64Str->erase();
- sBase64Str->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);
-
- sBase64Str->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);
- sBase64Str->append ( (char*)rawChunk, 1 );
-
- } else if ( padding == 1 ) {
-
- rawChunk[0] = (unsigned char) (merge >> 10);
- rawChunk[1] = (unsigned char) ((merge >> 2) & 0xFF);
- sBase64Str->append ( (char*)rawChunk, 2 );
-
- } else {
-
- rawChunk[0] = (unsigned char) (merge >> 16);
- rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF);
- rawChunk[2] = (unsigned char) (merge & 0xFF);
- sBase64Str->append ( (char*)rawChunk, 3 );
-
- }
-
- // -------------------------
- // Assign the output values.
-
- *rawStr = sBase64Str->c_str();
- *rawLen = sBase64Str->size();
-
-} // DecodeFromBase64
-
-
-// -------------------------------------------------------------------------------------------------
-// PackageForJPEG
-// --------------
-
-/* class static */ void
-XMPUtils::PackageForJPEG ( const XMPMeta & origXMP,
- XMP_StringPtr * stdStr,
- XMP_StringLen * stdLen,
- XMP_StringPtr * extStr,
- XMP_StringLen * extLen,
- XMP_StringPtr * digestStr,
- XMP_StringLen * digestLen )
-{
- enum { kStdXMPLimit = 65000 };
- static const char * kPacketTrailer = "<?xpacket end=\"w\"?>";
- static size_t kTrailerLen = strlen ( kPacketTrailer );
-
- XMP_StringPtr tempStr;
- XMP_StringLen tempLen;
-
- XMPMeta stdXMP, extXMP;
-
- sStandardXMP->clear(); // Clear the static strings that get returned to the client.
- sExtendedXMP->clear();
- sExtendedDigest->clear();
-
- XMP_OptionBits keepItSmall = kXMP_UseCompactFormat | kXMP_OmitAllFormatting;
-
- // 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, &tempLen, keepItSmall, 1, "", "", 0 );
- #if Trace_PackageForJPEG
- printf ( "\nXMPUtils::PackageForJPEG - Full serialize %d bytes\n", tempLen );
- #endif
-
- if ( tempLen > 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, &tempLen, keepItSmall, 1, "", "", 0 );
- #if Trace_PackageForJPEG
- printf ( " Delete xmp:Thumbnails, %d bytes left\n", tempLen );
- #endif
- }
-
- }
-
- if ( tempLen > 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, &tempLen, keepItSmall, 1, "", "", 0 );
- #if Trace_PackageForJPEG
- printf ( " Move Camera Raw schema, %d bytes left\n", tempLen );
- #endif
- }
-
- }
-
- if ( tempLen > kStdXMPLimit ) {
-
- // Still doesn't fit, move photoshop:History.
-
- bool moved = MoveOneProperty ( stdXMP, &extXMP, kXMP_NS_Photoshop, "photoshop:History" );
-
- if ( moved ) {
- stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
- #if Trace_PackageForJPEG
- printf ( " Move photoshop:History, %d bytes left\n", tempLen );
- #endif
- }
-
- }
-
- if ( tempLen > 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 ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) {
-
- // Inner loop, move what seems to be enough according to the estimates.
-
- 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, &tempLen, keepItSmall, 1, "", "", 0 );
-
- }
-
- }
-
- if ( tempLen > 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.
- sStandardXMP->assign ( tempStr, tempLen );
-
- } else {
-
- // Have extended XMP. Serialize it, compute the digest, reset xmpNote:HasExtendedXMP, and
- // reserialize the standard XMP.
-
- extXMP.SerializeToBuffer ( &tempStr, &tempLen, (keepItSmall | kXMP_OmitPacketWrapper), 0, "", "", 0 );
- sExtendedXMP->assign ( tempStr, tempLen );
-
- MD5_CTX context;
- XMP_Uns8 digest [16];
- MD5Init ( &context );
- MD5Update ( &context, (XMP_Uns8*)tempStr, tempLen );
- MD5Final ( digest, &context );
-
- sExtendedDigest->reserve ( 32 );
- for ( size_t i = 0; i < 16; ++i ) {
- XMP_Uns8 byte = digest[i];
- sExtendedDigest->push_back ( kHexDigits [ byte>>4 ] );
- sExtendedDigest->push_back ( kHexDigits [ byte&0xF ] );
- }
-
- stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", sExtendedDigest->c_str(), 0 );
- stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 );
- sStandardXMP->assign ( tempStr, tempLen );
-
- }
-
- // Adjust the standard XMP padding to be up to 2KB.
-
- XMP_Assert ( (sStandardXMP->size() > kTrailerLen) && (sStandardXMP->size() <= kStdXMPLimit) );
- const char * packetEnd = sStandardXMP->c_str() + sStandardXMP->size() - kTrailerLen;
- XMP_Assert ( XMP_LitMatch ( packetEnd, kPacketTrailer ) );
-
- size_t extraPadding = kStdXMPLimit - sStandardXMP->size(); // ! Do this before erasing the trailer.
- if ( extraPadding > 2047 ) extraPadding = 2047;
- sStandardXMP->erase ( sStandardXMP->size() - kTrailerLen );
- sStandardXMP->append ( extraPadding, ' ' );
- sStandardXMP->append ( kPacketTrailer );
-
- // Assign the output pointer and sizes.
-
- *stdStr = sStandardXMP->c_str();
- *stdLen = sStandardXMP->size();
- *extStr = sExtendedXMP->c_str();
- *extLen = sExtendedXMP->size();
- *digestStr = sExtendedDigest->c_str();
- *digestLen = sExtendedDigest->size();
-
-} // 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 )
-{
-
- XMPUtils::AppendProperties ( extendedXMP, fullXMP, kXMPUtil_DoAllProperties );
- 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->hour = currTime.tm_hour;
- xmpTime->minute = currTime.tm_min;
- xmpTime->second = currTime.tm_sec;
-
- xmpTime->nanoSecond = 0;
- xmpTime->tzSign = 0;
- xmpTime->tzHour = 0;
- xmpTime->tzMinute = 0;
-
- 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.
-
- if ( (xmpTime->tzSign != 0) || (xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0) ) {
- XMP_Throw ( "SetTimeZone can only be used on \"zoneless\" 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
- // 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) );
-
- // *** 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.
-
- 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.
-
- 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.
- 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;
-
- XMP_DateTime left = _in_left;
- XMP_DateTime right = _in_right;
-
- ConvertToUTCTime ( &left );
- ConvertToUTCTime ( &right );
-
- // *** We could use memcmp if the XMP_DateTime struct has no holes.
-
- 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;
- } else 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
-
-} // namespace DngXmpSdk
-// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils.hpp
deleted file mode 100644
index 6d8270386f..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/XMPUtils.hpp
+++ /dev/null
@@ -1,223 +0,0 @@
-#ifndef __XMPUtils_hpp__
-#define __XMPUtils_hpp__
-
-// =================================================================================================
-// Copyright 2002-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 "XMP_Environment.h"
-#include "XMP_Const.h"
-
-#include "XMPMeta.hpp"
-#include "XMPCore_Impl.hpp"
-#include "client-glue/WXMPUtils.hpp"
-
-// -------------------------------------------------------------------------------------------------
-namespace DngXmpSdk {
-
-extern XMP_VarString * sComposedPath; // *** Only really need 1 string. Shrink periodically?
-extern XMP_VarString * sConvertedValue;
-extern XMP_VarString * sBase64Str;
-extern XMP_VarString * sCatenatedItems;
-extern XMP_VarString * sStandardXMP;
-extern XMP_VarString * sExtendedXMP;
-extern XMP_VarString * sExtendedDigest;
-
-// -------------------------------------------------------------------------------------------------
-
-class XMPUtils {
-public:
-
- static bool
- Initialize(); // ! For internal use only!
-
- static void
- Terminate() RELEASE_NO_THROW; // ! For internal use only!
-
- static void
- Unlock ( XMP_OptionBits options );
-
- // ---------------------------------------------------------------------------------------------
-
- static void
- ComposeArrayItemPath ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_Index itemIndex,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize );
-
- static void
- ComposeStructFieldPath ( XMP_StringPtr schemaNS,
- XMP_StringPtr structName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize );
-
- static void
- ComposeQualifierPath ( XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_StringPtr qualNS,
- XMP_StringPtr qualName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize );
-
- static void
- ComposeLangSelector ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr langName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize );
-
- static void
- ComposeFieldSelector ( XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr fieldNS,
- XMP_StringPtr fieldName,
- XMP_StringPtr fieldValue,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize );
-
- // ---------------------------------------------------------------------------------------------
-
- static void
- ConvertFromBool ( bool binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize );
-
- static void
- ConvertFromInt ( XMP_Int32 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize );
-
- static void
- ConvertFromInt64 ( XMP_Int64 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize );
-
- static void
- ConvertFromFloat ( double binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize );
-
- static void
- ConvertFromDate ( const XMP_DateTime & binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize );
-
- // ---------------------------------------------------------------------------------------------
-
- 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_StringPtr * encodedStr,
- XMP_StringLen * encodedLen );
-
- static void
- DecodeFromBase64 ( XMP_StringPtr encodedStr,
- XMP_StringLen encodedLen,
- XMP_StringPtr * rawStr,
- XMP_StringLen * rawLen );
-
- // ---------------------------------------------------------------------------------------------
-
- static void
- PackageForJPEG ( const XMPMeta & xmpObj,
- XMP_StringPtr * stdStr,
- XMP_StringLen * stdLen,
- XMP_StringPtr * extStr,
- XMP_StringLen * extLen,
- XMP_StringPtr * digestStr,
- XMP_StringLen * digestLen );
-
- 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_StringPtr * catedStr,
- XMP_StringLen * catedLen );
-
- static void
- SeparateArrayItems ( XMPMeta * xmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_OptionBits options,
- XMP_StringPtr catedStr );
-
- static void
- RemoveProperties ( XMPMeta * xmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_OptionBits options );
-
- static void
- AppendProperties ( const XMPMeta & source,
- XMPMeta * dest,
- 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 );
-
-}; // XMPUtils
-
-// =================================================================================================
-
-} // namespace DngXmpSdk
-#endif // __XMPUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/ExpatAdapter.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/ExpatAdapter.cpp
new file mode 100644
index 0000000000..a8c00cb446
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/ExpatAdapter.cpp
@@ -0,0 +1,527 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "source/ExpatAdapter.hpp"
+#include "XMPCore/source/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, static_cast< XMP_StringLen >( 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/";
+ if (thiz->registeredNamespaces == sRegisteredNamespaces) {
+ (void)XMPMeta::RegisterNamespace(uri, prefix, 0, 0);
+ }
+ else {
+ (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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/ParseRDF.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/ParseRDF.cpp
new file mode 100644
index 0000000000..b163867065
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/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/source/XMPCore_Impl.hpp"
+#include "XMPCore/source/XMPMeta.hpp"
+#include "source/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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPIterator.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPIterator.cpp
new file mode 100644
index 0000000000..1c3ebab2bc
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPIterator.cpp
@@ -0,0 +1,173 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+#include "XMPCore/source/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 = NULL;
+ if (!iter) {
+
+ 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPMeta.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPMeta.cpp
new file mode 100644
index 0000000000..b547f76482
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPMeta.cpp
@@ -0,0 +1,1262 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+#include "XMPCore/source/XMPMeta.hpp"
+#include "XMPCore/source/XMPMeta2.hpp"
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+ #include "XMPCore/Interfaces/IMetadata_I.h"
+#endif
+
+#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( NULL );
+ XMP_Bool isCreated = false;
+
+#if ENABLE_CPP_DOM_MODEL
+ if ( sUseNewCoreAPIs ) {
+ xmpObj = new XMPMeta2();
+ isCreated = true;
+ }
+#endif
+
+ if(!isCreated)
+ 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 ( NULL );
+ XMP_Bool isCloned = false;
+#if ENABLE_CPP_DOM_MODEL
+ if(sUseNewCoreAPIs) {
+ isCloned = true;
+ try {
+ const XMPMeta2 & temp = dynamic_cast< const XMPMeta2 & >( thiz );
+ xClone = new XMPMeta2;
+ }
+ catch ( ... ) {
+ xClone = new XMPMeta;
+ }
+ }
+#endif
+ if(!isCloned) {
+ xClone = new XMPMeta;
+ }
+
+
+ thiz.Clone ( xClone, options );
+ XMP_Assert ( xClone->clientRefs == 0 ); // ! Gets incremented in TXMPMeta::Clone.
+ wResult->ptrResult = xClone;
+
+ XMP_EXIT
+}
+
+void
+WXMPMeta_GetIXMPMetadata_1(XMPMetaRef xmpObjRef,
+ WXMP_Result * wResult )
+{
+ XMP_ENTER_ObjRead( XMPMeta, "WXMPMeta_GetIXMPMetadata_1" )
+ XMP_Bool haveResult = false;
+#if ENABLE_CPP_DOM_MODEL
+ if(sUseNewCoreAPIs){
+ haveResult = true;
+ try {
+ const XMPMeta2 & temp = dynamic_cast< const XMPMeta2 & >( thiz );
+ auto ptr = temp.mDOM.get();
+ wResult->ptrResult = ptr;
+ } catch ( ... ) {
+ wResult->ptrResult = NULL;
+ wResult->errMessage = "Not Available";
+ }
+ }
+#endif
+ if(!haveResult) {
+ wResult->ptrResult = NULL;
+ wResult->errMessage = "Not Available";
+ }
+
+ 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(), static_cast< XMP_StringLen >( 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
+}
+
+void WXMPMeta_Use_CPP_DOM_APIs_1(XMP_Bool useNewCoreAPIs,
+ WXMP_Result * wResult )
+{
+#if ENABLE_CPP_DOM_MODEL
+ XMP_ENTER_Static ( "WXMPMeta_Use_CPP_DOM_APIs_1" )
+ sUseNewCoreAPIs = useNewCoreAPIs;
+ XMP_EXIT
+#endif
+
+}
+// =================================================================================================
+#if __cplusplus
+} /* extern "C" */
+#endif
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPUtils.cpp
new file mode 100644
index 0000000000..a31453ce31
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/WXMPUtils.cpp
@@ -0,0 +1,633 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+#include "XMPCore/source/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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( localStdStr.size()) );
+ if ( extStr != 0 ) (*SetClientString) ( extStr, localExtStr.c_str(), static_cast< XMP_StringLen >( localExtStr.size()) );
+ if ( digestStr != 0 ) (*SetClientString) ( digestStr, localDigestStr.c_str(), static_cast< XMP_StringLen >( 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(), static_cast< XMP_StringLen >( 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.cpp
new file mode 100644
index 0000000000..daec535b73
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.cpp
@@ -0,0 +1,1476 @@
+// =================================================================================================
+// 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_Version.h"
+#include "XMPCore/source/XMPCore_Impl.hpp"
+#include "XMPCore/source/XMPMeta.hpp" // *** For use of GetNamespacePrefix in FindSchemaNode.
+#include "source/UnicodeInlines.incl_cpp"
+#include <algorithm>
+
+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
+
+// *** Add debug codegen checks, e.g. that typical masking operations really work
+// *** Make option constants 0x...UL.
+
+// Internal code should be using #if with XMP_MacBuild, XMP_WinBuild, XMP_UNIXBuild or XMP_iOSBuild.
+// This is a sanity check in case of accidental use of *_ENV. Some clients use the poor
+// practice of defining the *_ENV macro with an empty value.
+#if defined ( MAC_ENV )
+ #if ! MAC_ENV
+ #error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
+ #endif
+#elif defined ( WIN_ENV )
+ #if ! WIN_ENV
+ #error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
+ #endif
+#elif defined ( UNIX_ENV )
+ #if ! UNIX_ENV
+ #error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
+ #endif
+#elif defined ( IOS_ENV )
+ #if ! IOS_ENV
+ #error "IOS_ENV must be defined so that \"#if IOS_ENV\" is true"
+ #endif
+#endif
+
+// =================================================================================================
+// Static Variables
+// ================
+
+XMP_Int32 sXMP_InitCount = 0;
+
+XMP_NamespaceTable * sRegisteredNamespaces = 0;
+
+XMP_AliasMap * sRegisteredAliasMap = 0;
+
+XMP_ReadWriteLock * sDefaultNamespacePrefixMapLock = 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;
+
+ #if ENABLE_CPP_DOM_MODEL
+ XMP_Bool sUseNewCoreAPIs = false;
+ #endif
+
+ #if ! XMP_StaticBuild
+
+ #undef malloc
+ #undef free
+ typedef void * (*XMP_AllocateProc) (size_t size);
+
+ typedef void(*XMP_DeleteProc) (void * ptr);
+
+ XMP_AllocateProc sXMP_MemAlloc = malloc;
+ XMP_DeleteProc sXMP_MemFree = free;
+ #define malloc(size) (*sXMP_MemAlloc) ( size )
+ #define free(addr) (*sXMP_MemFree) ( addr )
+
+ void * operator new ( size_t len ) throw ( std::bad_alloc )
+ {
+ void * mem = (*sXMP_MemAlloc) ( len );
+ if ( (mem == 0) && (len != 0) ) throw std::bad_alloc();
+ return mem;
+ }
+
+ void * operator new( std::size_t len, const std::nothrow_t & nothrow ) throw () {
+ void * mem = (*sXMP_MemAlloc) ( len );
+ return mem;
+ }
+
+ void * operator new[] ( size_t len ) throw ( std::bad_alloc )
+ {
+ void * mem = (*sXMP_MemAlloc) ( len );
+ if ( (mem == 0) && (len != 0) ) throw std::bad_alloc();
+ return mem;
+ }
+
+ void operator delete ( void * ptr ) throw()
+ {
+ if ( ptr != 0 ) (*sXMP_MemFree) ( ptr );
+ }
+
+ void operator delete ( void * ptr, const std::nothrow_t & nothrow ) throw ()
+ {
+ return operator delete( ptr );
+ }
+
+ void operator delete[] ( void * ptr ) throw()
+ {
+ if ( ptr != 0 ) (*sXMP_MemFree) ( ptr );
+ }
+
+#endif
+
+
+// =================================================================================================
+// 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.
+
+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 )
+{
+ size_t index;
+
+ if ( qualName == "xml:lang" ) {
+
+ // *** Should check that the value is legit RFC 1766/3066.
+ NormalizeLangValue ( &qualValue );
+ index = LookupLangItem ( arrayNode, qualValue ) ;
+
+ } else {
+
+ size_t 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 static_cast<XMP_Index>( 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 = static_cast<XMP_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 = 0 , nameEnd = 0;
+ 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 */,
+ PrefixSearchFnPtr prefixSearchFnPtr/* = NULL*/,
+ void * privateData/* = NULL*/ )
+{
+ 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 ( false );
+ if (prefixSearchFnPtr && privateData) {
+ found = prefixSearchFnPtr ( privateData, nsURI, &prefixPtr, &prefixLen );
+ }
+ else {
+ 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 )
+{
+ size_t 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 static_cast<XMP_Index>( 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 );
+ }
+
+ size_t index = 0;
+ size_t 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 static_cast<XMP_Index>( 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.hpp
new file mode 100644
index 0000000000..52aa114147
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPCore_Impl.hpp
@@ -0,0 +1,418 @@
+#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 "build/XMP_BuildInfo.h"
+#include "source/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;
+
+typedef void * (*XMP_AllocateProc) (size_t size);
+
+typedef void(*XMP_DeleteProc) (void * ptr);
+
+#if ! XMP_StaticBuild
+
+ extern XMP_AllocateProc sXMP_MemAlloc;
+ extern XMP_DeleteProc sXMP_MemFree;
+
+ #define malloc(size) (*sXMP_MemAlloc) ( size )
+ #define free(addr) (*sXMP_MemFree) ( addr )
+
+#endif
+
+
+extern XMP_Bool sUseNewCoreAPIs;
+extern XMP_NamespaceTable * sRegisteredNamespaces;
+
+extern XMP_AliasMap * sRegisteredAliasMap;
+
+extern XMP_ReadWriteLock * sDefaultNamespacePrefixMapLock;
+
+#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 );
+
+typedef bool (*PrefixSearchFnPtr) ( void * privateData, XMP_StringPtr nsURI, XMP_StringPtr * namespacePrefix, XMP_StringLen * prefixSize );
+
+extern XMP_Node *
+FindSchemaNode ( XMP_Node * xmpTree,
+ XMP_StringPtr nsURI,
+ bool createNodes,
+ XMP_NodePtrPos * ptrPos = 0,
+ PrefixSearchFnPtr prefixSearchFnPtr = NULL,
+ void * privateData = NULL );
+
+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 = static_cast< XMP_StringLen >( 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 GetFullQualifiedName( XMP_StringPtr * uriStr, XMP_StringLen * uriSize, XMP_StringPtr * nameStr, XMP_StringLen * nameSize ) 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();
+ }
+
+ void SetValue( XMP_StringPtr value );
+
+ 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator.cpp
new file mode 100644
index 0000000000..275e32f47f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator.cpp
@@ -0,0 +1,636 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/source/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)
+{
+ void * p; p = &schemaNS; p = &propName; p = &options; // Avoid unused param warnings.
+ XMP_Throw("Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented);
+
+} // 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 = static_cast<XMP_StringLen>(info.currSchema.size());
+
+ *propOptions = info.currPos->options;
+
+ *propPath = "";
+ *pathSize = 0;
+ *propValue = "";
+ *valueSize = 0;
+
+ if ( ! (*propOptions & kXMP_SchemaNode) ) {
+
+ *propPath = info.currPos->fullPath.c_str();
+ *pathSize = static_cast<XMP_StringLen>(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 = static_cast<XMP_StringLen>(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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator.hpp
new file mode 100644
index 0000000000..544bf3469d
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/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 "XMPCore/source/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;
+
+ virtual bool
+ Next ( XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions );
+
+ virtual 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator2.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator2.cpp
new file mode 100644
index 0000000000..586fa357e6
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator2.cpp
@@ -0,0 +1,542 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+#include "XMPCore/source/XMPIterator2.hpp"
+#include "XMPCore/source/XMPMeta2.hpp"
+#include "XMPCore/source/XMPUtils.hpp"
+#include "XMPCore/Interfaces/IMetadata_I.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
+#include "XMPCommon/Interfaces/IUTF8String_I.h"
+#include "XMPCore/Interfaces/ISimpleNode_I.h"
+#include <map>
+#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
+
+
+XMP_VarString GetNameSpace( const AdobeXMPCommon::spcIUTF8String & nameSpace )
+{
+ auto defaultMap = AdobeXMPCore::INameSpacePrefixMap::GetDefaultNameSpacePrefixMap()->GetINameSpacePrefixMap_I();
+ auto prefix = defaultMap->GetPrefix( nameSpace );
+ return prefix->c_str();
+}
+
+
+XMP_VarString NodeFullName( const AdobeXMPCore::spcINode & node )
+{
+ XMP_VarString name = GetNameSpace(node->GetNameSpace()) + ":" + node->GetName()->c_str();
+ return name;
+}
+
+void XMPIterator2::AddSchemaProperties(IteratorNode & iterSchema, const char * nameSpace)
+{
+ using namespace AdobeXMPCore;
+
+ for (auto childIter = mDOM->Iterator(); childIter; childIter = childIter->Next()) {
+
+ spINode childNode = childIter->GetNode();
+ //TODO check name
+ if (!strcmp(childNode->GetNameSpace()->c_str(), nameSpace)) {
+ iterSchema.nodeChildren.push_back(IteratorNode( XMPUtils::GetIXMPOptions(childNode), NodeFullName(childNode), 0 ));
+ }
+
+ }
+
+}
+ void XMPIterator2::SetCurrentSchema(XMP_StringPtr schemaName)
+{
+
+ info.currSchema = schemaName;
+
+} // SetCurrSchema
+
+ void XMPIterator2::SetCurrentSchema(XMP_VarString & schemaName)
+{
+
+ info.currSchema = schemaName;
+
+} // SetCurrSchema
+
+void XMPIterator2::AdvanceIteratorPosition()
+{
+
+ while (true) {
+
+ if (info.currPos == info.endPos) {
+
+ if (info.ancestors.empty()) break;
+
+ IteratorPosPair & parent = info.ancestors.back();
+ info.currPos = parent.first;
+ info.endPos = parent.second;
+ info.ancestors.pop_back();
+ }
+ else {
+
+ if (info.currPos->visitStage == kIter_BeforeVisit) {
+ if (info.currPos->options & kXMP_SchemaNode) SetCurrentSchema(info.currPos->fullPath);
+ break;
+ }
+
+
+ if (info.currPos->visitStage == kIter_VisitSelf) {
+
+ info.currPos->visitStage = kIter_VisitQualifiers;
+ if (!info.currPos->nodeQualifiers.empty()) {
+
+ info.ancestors.push_back(IteratorPosPair(info.currPos, info.endPos));
+ info.endPos = info.currPos->nodeQualifiers.end();
+ info.currPos = info.currPos->nodeQualifiers.begin();
+ break;
+ }
+ }
+
+ if (info.currPos->visitStage == kIter_VisitQualifiers) { // Just finished visiting the qualifiers.
+ info.currPos->nodeQualifiers.clear();
+ info.currPos->visitStage = kIter_VisitChildren; // Start visiting the children.
+ if (!info.currPos->nodeChildren.empty()) {
+ info.ancestors.push_back(IteratorPosPair(info.currPos, info.endPos));
+ info.endPos = info.currPos->nodeChildren.end(); // ! Set the parent's endPos before changing currPos!
+ info.currPos = info.currPos->nodeChildren.begin();
+ break;
+ }
+ }
+
+ if (info.currPos->visitStage == kIter_VisitChildren) {
+ info.currPos->nodeChildren.clear();
+ ++info.currPos;
+ continue;
+ }
+ }
+ }
+
+ XMP_Assert((info.currPos == info.endPos) || (info.currPos->visitStage == kIter_BeforeVisit));
+
+}
+
+AdobeXMPCore::spINode XMPIterator2::GetNextNode(bool & isSchema)
+{
+ using namespace AdobeXMPCore;
+ spINode xmpNode = spINode();
+
+ if (info.currPos->visitStage != kIter_BeforeVisit) AdvanceIteratorPosition();
+
+ bool isSchemaNode = false;
+ XMP_ExpandedXPath exPath;
+
+ while (info.currPos != info.endPos) {
+
+ isSchemaNode = XMP_NodeIsSchema(info.currPos->options);
+ if (isSchemaNode) {
+
+ SetCurrentSchema(info.currPos->fullPath);
+
+ isSchema = isSchemaNode;
+ }
+ else {
+
+ ExpandXPath(info.currSchema.c_str(), info.currPos->fullPath.c_str(), &exPath);
+ bool found = XMPUtils::FindCnstNode(mDOM, exPath, xmpNode);
+ }
+ if (xmpNode || isSchemaNode) break;
+
+ info.currPos->visitStage = kIter_VisitChildren;
+ info.currPos->nodeChildren.clear();
+ info.currPos->nodeQualifiers.clear();
+
+ AdvanceIteratorPosition();
+ }
+
+ if (info.currPos == info.endPos) return spINode();
+
+ XMP_Assert(info.currPos->visitStage == kIter_BeforeVisit);
+
+ if (info.currPos->visitStage == kIter_BeforeVisit) {
+
+ if (!isSchemaNode && !(info.options & kXMP_IterJustChildren)) {
+
+ AddNodeOffSpring(*info.currPos, xmpNode);
+ }
+ info.currPos->visitStage = kIter_VisitSelf;
+ }
+
+ return xmpNode;
+}
+
+void XMPIterator2::AddNodeOffSpring(IteratorNode &iterParent, const AdobeXMPCore::spINode & xmpParent)
+{
+
+ using namespace AdobeXMPCore;
+ XMP_VarString currPath(iterParent.fullPath);
+ size_t leafOffset = currPath.size();
+ if (xmpParent->HasQualifiers() && (!(info.options & kXMP_IterOmitQualifiers))) {
+
+ currPath += "/?"; // All qualifiers are named and use paths like "Prop/?Qual".
+ leafOffset += 2;
+
+ for ( auto qualIter = xmpParent->QualifiersIterator(); qualIter; qualIter = qualIter->Next() ) {
+
+ spINode qualNode = qualIter->GetNode();
+ //TOTO Add prefix too
+ currPath += NodeFullName( qualNode );
+
+ iterParent.nodeQualifiers.push_back( IteratorNode( XMPUtils::GetIXMPOptions( qualNode ), currPath, leafOffset ) );
+ currPath.erase( leafOffset );
+ }
+
+ leafOffset -= 2;
+ currPath.erase(leafOffset);
+
+ }
+ if (XMPUtils::GetNodeChildCount(xmpParent)) {
+
+
+
+ if (xmpParent->GetNodeType() == INode::kNTStructure) {
+ currPath += '/';
+ leafOffset += 1;
+ }
+ size_t childIdx = 0;
+ for (auto childIter = XMPUtils::GetNodeChildIterator(xmpParent); childIter; childIter = childIter->Next(), ++childIdx) {
+
+ spcINode xmpChild = childIter->GetNode();
+ if (xmpParent->GetNodeType() != INode::kNTArray) {
+ //TODO Add prefix as well
+ currPath += NodeFullName(xmpChild);
+ }
+ else {
+
+ char buffer[32]; // AUDIT: Using sizeof(buffer) below for snprintf length is safe.
+ #if XMP_WinBuild
+ snprintf(buffer, sizeof(buffer), "[%Iu]", childIdx + 1); // ! XPath indices are one-based.
+ #else
+ snprintf(buffer, sizeof(buffer), "[%zu]", childIdx + 1);
+ #endif
+ currPath += buffer;
+ }
+
+ iterParent.nodeChildren.push_back(IteratorNode(XMPUtils::GetIXMPOptions(xmpChild), currPath, leafOffset));
+ currPath.erase(leafOffset);
+
+ }
+
+
+ }
+
+
+
+ } // AddNodeOffspring
+
+// =================================================================================================
+// 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.
+
+XMPIterator2::XMPIterator2 ( const XMPMeta & xmpObjBase,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options) :XMPIterator(xmpObjBase, schemaNS, propName, options)
+{
+ using namespace AdobeXMPCore;
+ if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) {
+ XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions );
+ }
+ iteratorOptions = options;
+ info.options = options;
+
+ if(sUseNewCoreAPIs) {
+
+ const XMPMeta2 & tempPtr = dynamic_cast<const XMPMeta2 &>(xmpObjBase);
+
+ }
+ else {
+ XMP_Throw("Unsupported iteration kind", kXMPErr_BadOptions);
+ }
+
+ const XMPMeta2 & xmpObj = dynamic_cast<const XMPMeta2 &>(xmpObjBase);
+
+ spIMetadata root = xmpObj.mDOM;
+ mDOM = xmpObj.mDOM;
+ // *** Lock the XMPMeta object if we ever stop using a full DLL lock.
+
+ if ( *propName != 0 ) {
+ XMP_ExpandedXPath propPath;
+ ExpandXPath(schemaNS, propName, &propPath);
+ spINode destNode;
+ XMP_OptionBits destOptions = 0;
+ bool nodeFound = XMPUtils::FindCnstNode(root, propPath, destNode,&destOptions);
+
+ if (nodeFound) {
+
+ 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.nodeChildren.push_back( IteratorNode( destOptions, propName, leafOffset ) );
+ SetCurrentSchema(propPath[kSchemaStep].step.c_str());
+ if (options & kXMP_IterJustChildren) {
+
+ AddNodeOffSpring(info.tree.nodeChildren.back(), destNode);
+ }
+
+ }
+
+
+ } else if ( *schemaNS != 0 ) {
+
+ info.tree.nodeChildren.push_back(IteratorNode(kXMP_SchemaNode, schemaNS, 0));
+ IteratorNode & iterSchema = info.tree.nodeChildren.back();
+
+ bool schemaFound = false;
+
+ for (auto childIter = mDOM->Iterator(); childIter; childIter = childIter->Next()) {
+
+ if (!strcmp(childIter->GetNode()->GetNameSpace()->c_str(), schemaNS)) {
+
+ schemaFound = true;
+ break;
+ }
+ }
+
+
+ if (schemaFound) AddSchemaProperties(iterSchema, schemaNS);
+
+ if (iterSchema.nodeChildren.empty()) {
+ info.tree.nodeChildren.pop_back(); // No properties, remove the schema node.
+ }
+ else {
+ SetCurrentSchema(schemaNS);
+ }
+
+
+ } else {
+
+ std::map < XMP_VarString, bool > schemaProperties;
+
+ for (auto childIter = mDOM->Iterator(); childIter; childIter = childIter->Next()) {
+
+ spINode childNode = childIter->GetNode();
+
+ schemaProperties[childNode->GetNameSpace()->c_str()] = true;
+ }
+
+
+ for (auto key : schemaProperties) {
+ //TODO check name
+ info.tree.nodeChildren.push_back(IteratorNode( kXMP_SchemaNode, key.first, 0 ));
+
+ IteratorNode & iterSchema = info.tree.nodeChildren.back();
+
+ if (!(info.options & kXMP_IterJustChildren)) {
+ AddSchemaProperties(iterSchema, key.first.c_str());
+ // if (iterSchema.nodeChildren.empty()) info.tree.nodeChildren.pop_back(); // No properties, remove the schema node.
+ }
+ }
+
+
+
+
+ }
+
+ info.currPos = info.tree.nodeChildren.begin();
+ info.endPos = info.tree.nodeChildren.end();
+
+ if ((info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0)) {
+ info.currPos->visitStage = kIter_VisitSelf;
+ }
+
+
+
+} // XMPIterator for XMPMeta objects
+
+// -------------------------------------------------------------------------------------------------
+// XMPIterator
+// -----------
+//
+// Constructor for iterations over global tables such as registered namespaces or aliases.
+
+XMPIterator2::XMPIterator2 ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options) : XMPIterator(schemaNS, propName, options)
+{
+ void * p; p = &schemaNS; p = &propName; p = &options; // Avoid unused param warnings.
+ XMP_Throw("Unimplemented XMPIterator constructor for global tables", kXMPErr_Unimplemented);
+
+} // XMPIterator for global tables
+
+// -------------------------------------------------------------------------------------------------
+// ~XMPIterator
+// -----------
+
+XMPIterator2::~XMPIterator2() RELEASE_NO_THROW
+{
+
+ // 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
+XMPIterator2::Next ( XMP_StringPtr * schemaNS,
+ XMP_StringLen * nsSize,
+ XMP_StringPtr * propPath,
+ XMP_StringLen * pathSize,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * propOptions )
+{
+
+ if (info.currPos == info.endPos) return false;
+ using namespace AdobeXMPCore;
+ using namespace AdobeXMPCommon;
+ bool isSchema = false;
+ spcINode xmpNode = GetNextNode(isSchema);
+ if (!xmpNode && !isSchema) return false;
+ bool isSchemaNode = isSchema;
+ if (info.options & kXMP_IterJustLeafNodes) {
+ while (isSchemaNode || ( xmpNode && XMPUtils::GetNodeChildCount(xmpNode))) {
+ info.currPos->visitStage = kIter_VisitQualifiers; // Skip to this node's children.
+ xmpNode = GetNextNode(isSchemaNode);
+ if (xmpNode == 0 && !isSchemaNode) 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;
+ if (! xmpNode->IsArrayItem()) {
+ *schemaNS = xmpNode->GetNameSpace()->c_str();
+ *nsSize = xmpNode->GetNameSpace()->size();
+ }
+ else {
+ *schemaNS = "";
+ *nsSize = 0;
+ }
+
+ }
+
+ if (!(*propOptions & kXMP_PropCompositeMask)) {
+ spcIUTF8String nodeValue = xmpNode->ConvertToSimpleNode()->GetValue();
+ *propValue = nodeValue->c_str();
+ *valueSize = nodeValue->size();
+ }
+
+ }
+
+ 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
+XMPIterator2::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 (iterOptions & kXMP_IterSkipSubtree) {
+
+ info.currPos->visitStage = kIter_VisitChildren;
+ }
+ else if (iterOptions & kXMP_IterSkipSiblings) {
+
+ info.currPos = info.endPos;
+ AdvanceIteratorPosition();
+ }
+
+} // Skip
+
+
+
+// =================================================================================================
+#endif // ENABLE_CPP_DOM_MODEL
\ No newline at end of file
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator2.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator2.hpp
new file mode 100644
index 0000000000..6664a532df
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPIterator2.hpp
@@ -0,0 +1,153 @@
+#ifndef __XMPIterator2_hpp__
+#define __XMPIterator2_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/source/XMPMeta.hpp"
+#include "XMPCore/source/XMPIterator.hpp"
+#include "XMPCore/XMPCoreFwdDeclarations_I.h"
+#include "XMPCore/Interfaces/IMetadata_I.h"
+#include "XMPCore/Interfaces/INodeIterator_I.h"
+#include <vector>
+// =================================================================================================
+
+
+// =================================================================================================
+
+
+struct IteratorNode;
+
+typedef std::vector< IteratorNode > IteratorOffSpring;
+typedef IteratorOffSpring::iterator IteratorPos;
+typedef std::pair<IteratorPos, IteratorPos> IteratorPosPair;
+typedef std::vector< IteratorPosPair> IteratorPosStack;
+struct IteratorNode
+{
+ AdobeXMPCore::spINode node;
+ XMP_Uns8 visitStage;
+ IteratorOffSpring nodeQualifiers, nodeChildren;
+ XMP_VarString fullPath;
+ size_t leafOffset;
+ XMP_OptionBits options;
+
+
+
+ IteratorNode() : options(0), leafOffset(0), visitStage(kIter_BeforeVisit)
+ {
+
+ };
+
+ IteratorNode(XMP_OptionBits _options, const XMP_VarString& _fullPath, size_t _leafOffset)
+ : options(_options), fullPath(_fullPath), leafOffset(_leafOffset), visitStage(kIter_BeforeVisit)
+ {
+
+ };
+};
+
+
+
+struct IteratorState
+{
+
+ XMP_VarString schema;
+ XMP_OptionBits options;
+
+ XMP_VarString currSchema;
+ IteratorPos currPos, endPos;
+ IteratorPosStack ancestors;
+ IteratorNode tree;
+
+
+
+ IteratorState() : options(0)
+ {
+
+ };
+
+ IteratorState(XMP_OptionBits _options) : options(_options)
+ {
+
+ };
+
+
+ IteratorState(const AdobeXMPCore::spINode & inNode, XMP_VarString inSchema, XMP_VarString inPath) {
+
+
+ /* schema = inSchema;
+ path = inPath;*/
+ }
+
+ IteratorState(const AdobeXMPCore::spcINode & inNode, XMP_VarString inSchema, XMP_VarString inPath) {
+
+ /*node = inNode;
+ schema = inSchema;
+ path = inPath;*/
+ }
+
+
+};
+class XMPIterator2: public XMPIterator {
+
+public:
+
+
+
+ XMPIterator2(const XMPMeta & xmpObj, // Construct a property iterator.
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options);
+
+ XMPIterator2(XMP_StringPtr schemaNS, // Construct a table iterator.
+ XMP_StringPtr propName,
+ XMP_OptionBits options);
+
+ virtual ~XMPIterator2() 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.
+
+
+
+
+private:
+
+
+
+ void AddNodeOffSpring(IteratorNode &iterParent, const AdobeXMPCore::spINode & xmpParent);
+ AdobeXMPCore::spINode GetNextNode(bool &);
+ void AdvanceIteratorPosition();
+ void SetCurrentSchema(XMP_VarString &fullPath);
+ void SetCurrentSchema(const char * fullPath);
+ void AddSchemaProperties(IteratorNode & iterSchema, const char * nameSpace);
+ XMP_OptionBits iteratorOptions;
+ XMP_VarString fullPath;
+ AdobeXMPCore::spINode currNode;
+ IteratorState info;
+ AdobeXMPCore::spIMetadata mDOM;
+
+
+};
+
+// =================================================================================================
+
+#endif // __XMPIterator2_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-GetSet.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-GetSet.cpp
new file mode 100644
index 0000000000..18c024c8cf
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-GetSet.cpp
@@ -0,0 +1,1358 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/source/XMPMeta.hpp"
+#include "XMPCore/source/XMPIterator.hpp"
+#include "XMPCore/source/XMPUtils.hpp"
+
+#include "public/include/XMP_Version.h"
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+#include "source/ExpatAdapter.hpp"
+
+
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+#include "third-party/zuid/interfaces/MD5.h"
+#include "XMPCore/Interfaces/IMetadata_I.h"
+#include "XMPCore/Interfaces/IPathSegment_I.h"
+#include "XMPCore/Interfaces/IPath_I.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
+#include "XMPCore/Interfaces/IDOMImplementationRegistry_I.h"
+#include "XMPCore/XMPCoreFwdDeclarations_I.h"
+#include "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCore/Interfaces/IStructureNode_I.h"
+#include "XMPCore/Interfaces/ISimpleNode_I.h"
+#include "XMPCore/Interfaces/IArrayNode_I.h"
+#include "XMPCore/Interfaces/INodeIterator.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+#include "XMPCommon/Interfaces/IUTF8String_I.h"
+#include "XMPCore/Interfaces/INode_I.h"
+#endif
+
+
+#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;
+
+#if XMP_MARKER_EXTENSIBILITY_BACKWARD_COMPATIBILITY
+extern "C" {
+ void ReleaseXMP_Node(void * node) {
+ if (node) {
+ XMP_Node * ptr = (XMP_Node *)node;
+ delete ptr;
+ ptr = NULL;
+ }
+ }
+}
+
+#if ENABLE_CPP_DOM_MODEL
+extern "C" {
+ void ReleaseIStructureNode(void * node) {
+ if (node) {
+ AdobeXMPCore::pIStructureNode_base ptr = ( AdobeXMPCore::pIStructureNode_base )node;
+ ptr->Release();
+ node = NULL;
+ }
+ }
+}
+#endif
+#endif
+
+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 )
+{
+ node->SetValue( value );
+} //SetNodeValue
+
+void XMP_Node::SetValue( XMP_StringPtr value )
+{
+
+ #if XMP_DebugBuild // ! Hack to force an assert.
+ if ( (this->name == "xmp:TestAssertNotify") && XMP_LitMatch ( value, "DoIt!" ) ) {
+ XMP_Assert ( this->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_BadUnicode );
+ }
+ }
+
+ }
+
+ if ( XMP_PropIsQualifier(this->options) && (this->name == "xml:lang") ) NormalizeLangValue ( &newValue );
+
+ this->value.swap ( newValue );
+
+ #if 0 // *** XMP_DebugBuild
+ this->_valuePtr = this->value.c_str();
+ #endif
+
+} // XMP_Node::SetValue
+
+
+// -------------------------------------------------------------------------------------------------
+// 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 = static_cast<XMP_Index>( 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 = static_cast<XMP_StringLen>( 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 = static_cast<XMP_Index>( itemNode->qualifiers[0]->value.size() );
+ *itemValue = itemNode->value.c_str();
+ *valueSize = static_cast<XMP_Index>( 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-Parse.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-Parse.cpp
new file mode 100644
index 0000000000..49d900724b
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-Parse.cpp
@@ -0,0 +1,1279 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/source/XMPMeta.hpp"
+#include "XMPCore/source/XMPUtils.hpp"
+
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+#include "source/ExpatAdapter.hpp"
+#define STATIC_SAFE_API
+#include "source/SafeStringAPIs.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)
+ #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.
+
+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
+// -------------------
+
+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 = static_cast<XMP_Index>( 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 = static_cast<int>( 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
+// ----------------
+
+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 static_cast<int>(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, strnlen_safe(replacement, Max_XMP_Uns32), 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 = static_cast<XMP_Index>(strnlen_safe(buffer, Max_XMP_Uns32));
+
+ 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-Serialize.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-Serialize.cpp
new file mode 100644
index 0000000000..9d41036e7f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta-Serialize.cpp
@@ -0,0 +1,1393 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/source/XMPMeta.hpp"
+
+#include "public/include/XMP_Version.h"
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+#include "XMP_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;
+ if (outputStr[outputStr.size ( ) - 1] == ':')
+ outputStr[outputStr.size ( ) - 1] = '='; // Change the colon to =.
+ else
+ outputStr += '=';
+ 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, static_cast<XMP_Index>(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, static_cast<XMP_Index>(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, static_cast<XMP_Index>(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, static_cast<XMP_Index>(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;
+ MD5_CTX context;
+ MD5Init ( &context );
+ MD5Update ( &context, (XMP_Uns8*)rdfstring.c_str(), (unsigned int)rdfstring.size() );
+ MD5Final ( digestBin, &context );
+ 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 = static_cast<XMP_StringLen>(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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta.cpp
new file mode 100644
index 0000000000..b2f02b64f1
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta.cpp
@@ -0,0 +1,1492 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/source/XMPMeta.hpp"
+#include "XMPCore/source/XMPIterator.hpp"
+#include "XMPCore/source/XMPUtils.hpp"
+#include "public/include/XMP_Version.h"
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+
+
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+ #include "XMPCommon/XMPCommon_I.h"
+ #include "XMPCore/Interfaces/ICoreConfigurationManager_I.h"
+ #include "XMPCommon/Interfaces/IMemoryAllocator.h"
+ #include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
+ #include "XMPCommon/ImplHeaders/SharedObjectImpl.h"
+ #include "XMPCore/Interfaces/ICoreObjectFactory_I.h"
+ #include "XMPCore/Interfaces/IDOMImplementationRegistry_I.h"
+#endif
+
+
+#include <algorithm> // For sort and stable_sort.
+#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
+
+
+ #if ENABLE_CPP_DOM_MODEL
+ #if !XMP_StaticBuild
+
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+ #endif
+ class InternalClientAllocator
+ : public AdobeXMPCommon::IMemoryAllocator
+ {
+ public:
+ virtual void * APICALL allocate( AdobeXMPCommon::sizet size ) __NOTHROW__ {
+ return sXMP_MemAlloc( size );
+ }
+
+ virtual void APICALL deallocate( void * ptr ) __NOTHROW__ {
+ sXMP_MemFree( ptr );
+ }
+
+ virtual void * APICALL reallocate( void * ptr, AdobeXMPCommon::sizet size ) __NOTHROW__ {
+ return NULL;
+ }
+
+ virtual ~InternalClientAllocator(){}
+
+ };
+ static InternalClientAllocator * sInternalClientAllocator( NULL );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+
+ #endif // !XMP_StaticBuild
+ #endif // ENABLE_CPP_DOM_MODEL
+
+
+// *** 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
+// ---------------
+
+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", kXMP_PropArrayIsAltText );
+ 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;
+
+ #if ENABLE_CPP_DOM_MODEL
+ try {
+ AdobeXMPCore_Int::InitializeXMPCommonFramework();
+
+ } catch ( ... ) {
+ return false;
+ }
+ AdobeXMPCore_Int::INameSpacePrefixMap_I::CreateDefaultNameSpacePrefixMap();
+ sDefaultNamespacePrefixMapLock = new XMP_ReadWriteLock;
+
+ // Explicitly setting sUseNewCoreAPIs as false (default value)
+ sUseNewCoreAPIs = false;
+ #endif
+
+ 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 );
+
+ (void) RegisterNamespace( kXMP_NS_iXML, "iXML", &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_CPP_DOM_MODEL
+ AdobeXMPCore_Int::INameSpacePrefixMap_I::DestroyDefaultNameSapcePrefixMap();
+ AdobeXMPCore_Int::IDOMImplementationRegistry_I::DestoryDOMImplementationRegistry();
+ AdobeXMPCore_Int::ICoreObjectFactory_I::DestroyCoreObjectFactory();
+ AdobeXMPCore_Int::ICoreConfigurationManager_I::DestroyCoreConfigurationManager();
+ AdobeXMPCore_Int::TerminateXMPCommonFramework();
+ EliminateGlobal( sDefaultNamespacePrefixMapLock );
+ // Explicitly setting sUseNewCoreAPIs as false (default value)
+ sUseNewCoreAPIs = false;
+ #if !XMP_StaticBuild
+ EliminateGlobal( sInternalClientAllocator );
+ #endif
+#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 )
+{
+
+ void * p; p = &options; // Avoid unused param warnings.
+ XMP_Throw("Unimplemented method XMPMeta::SetGlobalOptions", kXMPErr_Unimplemented);
+
+} // SetGlobalOptions
+
+
+// -------------------------------------------------------------------------------------------------
+// RegisterNamespace
+// -----------------
+
+/* class-static */ bool
+XMPMeta::RegisterNamespace ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ XMP_StringPtr * registeredPrefix,
+ XMP_StringLen * prefixSize )
+{
+
+ bool returnValue = sRegisteredNamespaces->Define ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize );
+#if ENABLE_CPP_DOM_MODEL
+ const char * prefix = NULL;
+ XMP_StringLen len = 0;
+ sRegisteredNamespaces->GetPrefix( namespaceURI, &prefix, &len );
+ XMP_VarString prefixWithoutColon( prefix, len - 1 );
+ {
+ XMP_AutoLock aLock( sDefaultNamespacePrefixMapLock, true );
+ AdobeXMPCore_Int::INameSpacePrefixMap_I::InsertInDefaultNameSpacePrefixMap( prefixWithoutColon.c_str(), prefixWithoutColon.size(), namespaceURI, AdobeXMPCommon::npos );
+ }
+#endif
+ return returnValue;
+} // 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 static_cast<XMP_Index>( arrayNode->children.size() );
+
+} // CountArrayItems
+
+
+// -------------------------------------------------------------------------------------------------
+// GetObjectName
+// -------------
+
+void
+XMPMeta::GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const
+{
+
+ *namePtr = tree.name.c_str();
+ *nameLen = static_cast<XMP_Index>( 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 )
+{
+ void * p; p = &options; // Avoid unused param warnings.
+ XMP_Throw ( "Unimplemented method XMPMeta::SetObjectOptions", kXMPErr_Unimplemented );
+
+
+} // 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 = static_cast<XMP_StringLen>( 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 );
+
+ }
+
+}
+
+void XMP_Node::GetFullQualifiedName( XMP_StringPtr * uriStr, XMP_StringLen * uriSize, XMP_StringPtr * nameStr, XMP_StringLen * nameSize ) const
+{
+ if ( uriStr != 0 ) *uriStr = ""; // Set up empty defaults.
+ if ( uriSize != 0 ) *uriSize = 0;
+ if ( nameStr != 0 ) *nameStr = "";
+ if ( nameSize != 0 ) *nameSize = 0;
+
+ if ( this->name.empty() ) return;
+
+ if ( XMP_NodeIsSchema ( this->options ) ) {
+
+ if ( uriStr != 0 ) *uriStr = this->name.c_str();
+ if ( uriSize != 0 ) *uriSize = static_cast<XMP_StringLen>( this->name.size() );
+ if ( nameStr != 0 ) *nameStr = this->value.c_str();
+ if ( nameSize != 0 ) *nameSize = static_cast<XMP_StringLen>( this->value.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 );
+ *nameStr = this->name.c_str() + colonPos + 1;
+ *nameSize = static_cast<XMP_StringLen>( this->name.size() - colonPos - 1 );
+ }
+}
+
+// =================================================================================================
+// 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta.hpp
new file mode 100644
index 0000000000..34b71aaf60
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/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/source/XMPCore_Impl.hpp"
+#include "source/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 );
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual bool
+ GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ virtual bool
+ GetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr * itemValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ virtual bool
+ GetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr * fieldValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ virtual bool
+ GetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr * qualValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual void
+ SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options );
+
+ virtual void
+ SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ virtual 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 );
+
+ virtual void
+ SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options );
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual void
+ DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName );
+
+ virtual void
+ DeleteArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex );
+
+ virtual void
+ DeleteStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName );
+
+ virtual void
+ DeleteQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName );
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual 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;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual 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;
+
+ virtual void
+ SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ virtual 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 );
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual void
+ GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const;
+
+ virtual void
+ SetObjectName ( XMP_StringPtr name );
+
+ XMP_OptionBits
+ GetObjectOptions() const;
+
+ void
+ SetObjectOptions ( XMP_OptionBits options );
+
+ virtual void
+ Sort();
+
+ virtual void
+ Erase();
+
+ virtual void
+ Clone ( XMPMeta * clone, XMP_OptionBits options ) const;
+
+ virtual XMP_Index
+ CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const;
+
+ virtual void
+ DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual void
+ ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options );
+
+ virtual 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 );
+
+ virtual void
+ SetErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit );
+
+ virtual 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta2-GetSet.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta2-GetSet.cpp
new file mode 100644
index 0000000000..f7f1d9bd50
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta2-GetSet.cpp
@@ -0,0 +1,1356 @@
+// =================================================================================================
+// 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 "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+#include "public/include/XMP_Environment.h" // ! This must be the first include!
+#include "XMPCore/source/XMPCore_Impl.hpp"
+
+
+#include "XMPCore/source/XMPMeta2.hpp"
+#include "XMPCore/source/XMPIterator.hpp"
+#include "XMPCore/source/XMPUtils.hpp"
+
+#include "public/include/XMP_Version.h"
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+#include "source/ExpatAdapter.hpp"
+#include "third-party/zuid/interfaces/MD5.h"
+#include "XMPCore/Interfaces/IMetadata_I.h"
+#include "XMPCore/Interfaces/IArrayNode_I.h"
+#include "XMPCore/Interfaces/ISimpleNode_I.h"
+#include "XMPCommon/Interfaces/IUTF8String_I.h"
+#include "XMPCore/Interfaces/IPathSegment_I.h"
+#include "XMPCore/Interfaces/IPath_I.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
+#include "XMPCore/Interfaces/IDOMImplementationRegistry_I.h"
+#include "XMPCore/Interfaces/IDOMParser.h"
+#include "XMPCore/Interfaces/IDOMSerializer.h"
+#include "XMPCore/Interfaces/INodeIterator.h"
+#include "XMPCore/Interfaces/IDOMParser_I.h"
+#include "XMPCore/Interfaces/IDOMSerializer_I.h"
+#include "XMPCore/Interfaces/ICoreConfigurationManager.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
+// =========================
+
+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
+};
+const XMP_VarString xmlNameSpace = "http://www.w3.org/XML/1998/namespace";
+
+// =================================================================================================
+// Static Variables
+// ================
+
+
+// =================================================================================================
+// Local Utilities
+// ===============
+extern void SplitNameAndValue ( const XMP_VarString & selStep, XMP_VarString * nameStr, XMP_VarString * valueStr );
+
+extern void DumpNodeOptions ( XMP_OptionBits options,XMP_TextOutputProc outProc,void *refCon );
+using namespace AdobeXMPCore_Int;
+using namespace AdobeXMPCommon_Int;
+
+
+
+
+static void
+AppendIXMPLangItem ( const spIArrayNode & arrayNode, XMP_StringPtr itemLang, XMP_StringPtr itemValue )
+{
+
+
+
+ spISimpleNode newItem = ISimpleNode::CreateSimpleNode( arrayNode->GetNameSpace()->c_str(), arrayNode->GetNameSpace()->size(), arrayNode->GetName()->c_str(), arrayNode->GetName()->size(), "", AdobeXMPCommon::npos );
+ spISimpleNode langQual = ISimpleNode::CreateSimpleNode( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos, "", AdobeXMPCommon::npos );
+
+ try {
+
+ XMPUtils::SetNode(newItem,itemValue,(kXMP_PropHasQualifiers | kXMP_PropHasLang));
+ XMPUtils::SetNode(langQual, itemLang, kXMP_PropIsQualifier);
+
+ } catch (...) {
+
+ newItem->Clear();
+ langQual->Clear();
+ throw;
+ }
+
+
+ newItem->InsertQualifier(langQual);
+ if ( (!arrayNode->ChildCount() || !XMP_LitMatch(langQual->GetValue()->c_str(),"x-default") )) {
+
+ size_t arraySize = arrayNode->ChildCount();
+ arrayNode->InsertNodeAtIndex(newItem, arraySize + 1);
+
+ } else {
+
+ arrayNode->InsertNodeAtIndex(newItem, 1);
+ }
+
+} // AppendLangItem
+
+
+
+
+// -------------------------------------------------------------------------------------------------
+// GetProperty
+// -----------
+
+
+
+
+
+XMPMeta2::XMPMeta2()
+{
+ mDOM = IMetadata::CreateMetadata();
+ mDOM->EnableFeature("alias", 5);
+ spRegistry = IDOMImplementationRegistry::GetDOMImplementationRegistry();
+ spParser = spRegistry->GetParser( "rdf" );
+}
+
+XMPMeta2::~XMPMeta2()
+{
+
+}
+
+
+
+bool
+XMPMeta2::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 );
+
+
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+ spINode destNode = mDOM;
+ bool qualifierFlag = false;
+ size_t pathStartIdx = 1;
+ if (expPath[kRootPropStep].options & kXMP_StepIsAlias) {
+
+ if (!XMPUtils::HandleConstAliasStep(mDOM, destNode, expPath, 0)) return false;
+ pathStartIdx = 2;
+
+ }
+ for ( size_t i = pathStartIdx, endIndex = expPath.size(); i < endIndex; i++ ) {
+
+ if(!destNode) return false;
+ XMP_VarString stepStr = expPath[i].step;
+ XMP_VarString prevStep = ( i == 0 ) ? "" : expPath[i - 1].step;
+ spcIUTF8String nameSpace ;
+
+ switch( expPath[i].options ) {
+ case kXMP_StructFieldStep:
+ {
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr( 0, colonPos );
+ // get the namespace from the prefix
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ if(destNode->GetNodeType() == INode::kNTStructure) {
+ spIStructureNode tempNode = destNode->ConvertToStructureNode();
+ destNode = tempNode->GetNode(nameSpace->c_str(), AdobeXMPCommon::npos, stepStr.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ }
+ else {
+ return false;
+ }
+ }
+ break;
+ case kXMP_ArrayIndexStep:
+ {
+
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ return false;
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+ XMP_Index index = 0;
+ XMP_Assert ( (stepStr.length() >= 2) && (*( stepStr.begin()) == '[') && (stepStr[stepStr.length()-1] == ']') );
+ for ( size_t chNum = 1,chEnd = stepStr.length() -1 ; chNum != chEnd; ++chNum ) {
+ XMP_Assert ( ('0' <= stepStr[chNum]) && (stepStr[chNum] <= '9') );
+ index = (index * 10) + (stepStr[chNum] - '0');
+ }
+ if ( index < 1) XMP_Throw ( "Array index must be larger than one", kXMPErr_BadXPath );
+ size_t colonPos = prevStep.find(':');
+ XMP_VarString prefix = prevStep.substr( 0, colonPos );
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ destNode = tempNode->GetNodeAtIndex( index );
+ }
+ break;
+ case kXMP_ArrayLastStep:
+ {
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ return false;
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+
+ size_t colonPos = prevStep.find(':');
+ XMP_VarString prefix = prevStep.substr( 0, colonPos );
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ spINode parentNode = destNode;
+ if(parentNode && parentNode->GetNodeType()== INode::kNTArray) {
+ size_t childCount = parentNode->ConvertToArrayNode()->ChildCount();
+ if(!childCount) {
+ XMP_Throw ( "Array index overflow", kXMPErr_BadXPath );
+ }
+ destNode = tempNode->GetNodeAtIndex(childCount);
+ }
+
+ }
+ break;
+ case kXMP_QualifierStep:
+ {
+
+ XMP_Assert(stepStr[0]=='?');
+ stepStr = stepStr.substr(1);
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr( 0, colonPos);
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ destNode = destNode->GetQualifier(nameSpace->c_str(), nameSpace->size(), stepStr.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ qualifierFlag = true;
+ }
+
+ break;
+
+ case kXMP_QualSelectorStep:
+ {
+
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ return false;
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+ XMP_VarString qualName, qualValue, qualNameSpace;
+ SplitNameAndValue (stepStr, &qualName, &qualValue );
+ spINode parentNode = destNode;
+ size_t colonPos = qualName.find(':');
+ XMP_VarString prefix = qualName.substr( 0, colonPos);
+ qualNameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() )->c_str();
+ bool indexFound = false;
+ if(parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ size_t arrayChildCount = parentArrayNode->ChildCount();
+ for(size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+ spINode currentArrayItem = parentArrayNode->GetNodeAtIndex(arrayIdx);
+ spINode qualNode = currentArrayItem->GetQualifier(qualNameSpace.c_str(), qualNameSpace.size(), qualName.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if(!qualNode) continue;
+ XMP_VarString currentQualValue = qualNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if( currentQualValue == qualValue) {
+ indexFound = true;
+ destNode = parentArrayNode->GetNodeAtIndex( arrayIdx);
+ break;
+ }
+ }
+
+ }
+ if(!indexFound) {
+ return false;
+ }
+ }
+ break;
+
+ case kXMP_FieldSelectorStep :
+ {
+
+ XMP_VarString fieldName, fieldValue, fieldNameSpace;
+ SplitNameAndValue (stepStr, &fieldName, &fieldValue );
+ spINode parentNode = destNode;
+ size_t colonPos = fieldName.find(':');
+ XMP_VarString prefix = fieldName.substr( 0, colonPos);
+ fieldNameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() )->c_str();
+ bool indexFound = false;
+ if(parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ size_t arrayChildCount = parentArrayNode->ChildCount();
+ for(size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+
+ spINode currentItem = parentArrayNode->GetNodeAtIndex(arrayIdx);
+
+ if(currentItem->GetNodeType() != INode::kNTStructure) {
+ return false;
+ }
+
+ spINode fieldNode = currentItem->ConvertToStructureNode()->GetNode(fieldNameSpace.c_str(), fieldNameSpace.size(), fieldName.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if(!fieldNode || fieldNode->GetNodeType() != INode::kNTSimple) continue;
+ XMP_VarString currentFieldValue = fieldNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if( currentFieldValue == fieldValue) {
+ indexFound = true;
+ destNode = parentArrayNode->GetNodeAtIndex( arrayIdx);
+ break;
+ }
+ }
+ }
+ if(!indexFound) {
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+
+ }
+
+
+ if (!destNode) {
+ return false;
+ }
+ if(options)*options = XMPUtils::GetIXMPOptions(destNode);
+ if ( destNode->GetNodeType() == INode::kNTSimple ) {
+
+ spcIUTF8String value = destNode->ConvertToSimpleNode()->GetValue();
+ *propValue = value->c_str();
+ *valueSize = static_cast<XMP_StringLen>( value->size() );
+ }
+ return true;
+
+} // GetProperty
+
+// -------------------------------------------------------------------------------------------------
+// CountArrayItems
+// ---------------
+
+XMP_Index
+XMPMeta2::CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, arrayName, &expPath );
+
+ spINode arrayNode ;
+ XMP_OptionBits arrayOptions = 0;
+ if(!XMPUtils::FindCnstNode(this->mDOM, expPath, arrayNode, &arrayOptions)) return false;
+
+
+ if ( ! (arrayOptions & kXMP_PropValueIsArray) ) XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
+ return static_cast<XMP_Index>( XMPUtils::GetNodeChildCount(arrayNode) );
+
+} // CountArrayItems
+
+
+void XMPMeta2::ParseFromBuffer ( XMP_StringPtr buffer, XMP_StringLen bufferSize, XMP_OptionBits options )
+{
+ bool lastClientCall = (options & kXMP_ParseMoreBuffers) ? false : true;
+ if (!mBuffer) {
+ mBuffer = IUTF8String_I::CreateUTF8String("", 0);
+ }
+ sizet bufferSizeIn64Bits = static_cast<sizet>(bufferSize);
+ if (bufferSize == kXMP_UseNullTermination) {
+ bufferSizeIn64Bits = std::string::npos;
+ }
+ mBuffer->append(buffer, bufferSizeIn64Bits);
+
+
+ if (!lastClientCall) {
+ return;
+ }
+
+ spParser->GetIDOMParser_I()->SetErrorCallback(&errorCallback);
+ mDOM = spParser->Parse( mBuffer->c_str(), mBuffer->size() );
+ mBuffer->clear();
+}
+
+void XMPMeta2::SerializeToBuffer ( XMP_VarString * rdfString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent ) const
+{
+ auto spRegistry = IDOMImplementationRegistry::GetDOMImplementationRegistry();
+ auto rdfSerializer = spRegistry->GetSerializer( "rdf" );
+ auto str = rdfSerializer->GetIDOMSerializer_I()->SerializeInternal( mDOM, options, padding, newline, indent, baseIndent);
+ rdfString->clear();
+ if (str)
+ rdfString->append( str->c_str() );
+}
+
+
+void
+XMPMeta2::Sort()
+{
+ // need internal implementation of sort here
+ return;
+
+} // Sort
+
+void
+XMPMeta2::Erase()
+{
+
+ if ( this->xmlParser != 0 ) {
+ delete ( this->xmlParser );
+ this->xmlParser = 0;
+ }
+ mDOM->Clear();
+}
+// DoesPropertyExist
+// -----------------
+
+bool
+XMPMeta2::DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const
+{
+ XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
+
+ XMP_ExpandedXPath expPath;
+ ExpandXPath ( schemaNS, propName, &expPath );
+ spINode destNode;
+ XMP_OptionBits options;
+ return XMPUtils::FindCnstNode ( this->mDOM, expPath, destNode, &options );
+
+
+} // DoesPropertyExist
+
+// SetProperty
+// -----------
+
+// *** Should handle array items specially, calling SetArrayItem.
+
+void
+XMPMeta2::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 );
+
+ spINode node ;
+ bool propertyFound = XMPUtils::FindNode ( mDOM, expPath, kXMP_CreateNodes, options, node, 0 );
+ if (!propertyFound) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
+
+ XMPUtils::SetNode ( node, propValue, options );
+
+} // SetProperty
+// -------------------------------------------------------------------------------------------------'
+// -------------------------------------------------------------------------------------------------
+// SetArrayItem
+// ------------
+
+void
+XMPMeta2::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 );
+ spINode destNode;
+ if(!XMPUtils::FindNode ( mDOM, arrayPath, false,options, destNode ) ) {
+ XMP_Throw ( "Specified array does not exist", kXMPErr_BadXPath );
+ }
+ int x = destNode->GetNodeType();
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ XMP_Throw ( "Specified array does not exist", kXMPErr_BadXPath );
+ }
+
+ spIArrayNode arrayNode = destNode->ConvertToArrayNode();
+ XMPUtils::DoSetArrayItem ( arrayNode, itemIndex, itemValue, options );
+
+} // SetArrayItem
+
+
+// -------------------------------------------------------------------------------------------------
+// AppendArrayItem
+// ---------------
+
+void
+XMPMeta2::AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ // TO DO check in case array node doesn't already exist, and the parent of the array to be created is also an array -currently appending the array at the end of the existing array
+ 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 );
+ }
+
+
+ XMP_ExpandedXPath arrayPath;
+ ExpandXPath ( schemaNS, arrayName, &arrayPath );
+ spINode destNode;
+ spIArrayNode arrayNode;
+ XMP_OptionBits dummyOptions;
+ XMP_Index insertIndex = 0;
+ // either destNode will be the array node or it will be the parent node of the array
+ if(XMPUtils::FindCnstNode (mDOM, arrayPath, destNode, &dummyOptions )) {
+
+ if ( destNode->GetNodeType() != INode::kNTArray) {
+
+ XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
+
+ }
+
+
+ }
+ else {
+
+ if ( arrayOptions == 0 ) XMP_Throw ( "Explicit arrayOptions required to create new array", kXMPErr_BadOptions );
+ XPathStepInfo lastPathSegment( arrayPath.back());
+ XMP_VarString arrayStep = lastPathSegment.step;
+ //arrayPath.pop_back();
+
+ if(!XMPUtils::FindNode(this->mDOM, arrayPath, kXMP_CreateNodes, arrayOptions, destNode, &insertIndex)) {
+ XMP_Throw ( "Failure creating array node", kXMPErr_BadXPath );
+ }
+
+ }
+ arrayNode = destNode->ConvertToArrayNode();
+ XMPUtils::DoSetArrayItem ( arrayNode, kXMP_ArrayLastItem, itemValue, (options | kXMP_InsertAfterItem) );
+
+
+
+} // AppendArrayItem
+
+// -------------------------------------------------------------------------------------------------
+// SetQualifier
+// ------------
+
+void
+XMPMeta2::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 );
+ spINode destNode ;
+
+ if(!XMPUtils::FindCnstNode ( mDOM, expPath, destNode) )
+ 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
+
+// Clone
+// -----
+
+void
+XMPMeta2::Clone ( XMPMeta * clone, XMP_OptionBits options ) const
+{
+
+ XMPMeta2 * xmpMeta2Ptr = dynamic_cast<XMPMeta2 *>(clone);
+ // Possible to do a safer/better cast?
+ if (xmpMeta2Ptr== 0 ) XMP_Throw ( "Null clone pointer", kXMPErr_BadParam );
+ if ( options != 0 ) XMP_Throw ( "No options are defined yet", kXMPErr_BadOptions );
+
+ xmpMeta2Ptr->mDOM->Clear();
+ xmpMeta2Ptr->mDOM = mDOM->Clone()->ConvertToMetadata();
+
+} // Clone
+
+
+// -------------------------------------------------------------------------------------------------
+// DeleteProperty
+// --------------
+
+
+void
+XMPMeta2::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;
+ spINode propNode ;
+ XMP_OptionBits options = 0;
+ XMP_Index arrayIndex = 0;
+ if(!XMPUtils::FindCnstNode ( mDOM, expPath, propNode, &options, &arrayIndex ) || !propNode ) {
+
+ return;
+ }
+ if (!propNode) return;
+
+ spINode parentNode = propNode->GetParent();
+
+ // Erase the pointer from the parent's vector, then delete the node and all below it.
+
+ if ( (options & kXMP_PropIsQualifier) ) {
+
+ parentNode->RemoveQualifier( propNode->GetNameSpace()->c_str(), propNode->GetNameSpace()->size(),
+ propNode->GetName()->c_str(), propNode->GetName()->size() );
+
+
+ }
+ else if(parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ parentArrayNode->RemoveNodeAtIndex(arrayIndex);
+
+
+ }
+ else if(parentNode->GetNodeType() == INode::kNTStructure) {
+ spIStructureNode parentStructureNode = parentNode->ConvertToStructureNode();
+ parentStructureNode->RemoveNode( propNode->GetNameSpace()->c_str(), propNode->GetNameSpace()->size(),
+ propNode->GetName()->c_str(), propNode->GetName()->size() );
+ }
+ // delete subtree - needed ?
+ //propNode->Clear();
+
+
+} // DeleteProperty
+
+void
+XMPMeta2::GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const
+{
+ *namePtr = this->mDOM->GetAboutURI()->c_str();
+ *nameLen = static_cast<XMP_StringLen> ( this->mDOM->GetAboutURI()->size() );
+
+} // GetObjectName
+
+
+// -------------------------------------------------------------------------------------------------
+// SetObjectName
+// -------------
+
+void
+XMPMeta2::SetObjectName ( XMP_StringPtr name )
+{
+ VerifyUTF8 (name); // Throws if the string is not legit UTF-8.
+ this->mDOM->SetAboutURI(name, AdobeXMPCommon::npos );
+
+} // SetObjectName
+
+// -------------------------------------------------------------------------------------------------
+// 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
+ChooseIXMPLocalizedText (
+ const spIArrayNode &arrayNode,
+ XMP_OptionBits &options,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ spINode &itemNode )
+{
+ spINode currItem ;
+ const size_t itemLim = arrayNode->ChildCount();
+ size_t itemNum;
+ const XMP_VarString xmlLangQualifierName = "lang";
+
+ // 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(options) ||
+ (!itemLim && XMP_ArrayIsAlternate(options)) ) ) {
+ XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
+ }
+ if ( !itemLim ) {
+
+ return kXMP_CLT_NoValues;
+ }
+
+ for ( itemNum = 1; itemNum <= itemLim; ++itemNum ) {
+ currItem = arrayNode->GetNodeAtIndex(itemNum);
+ if ( currItem->GetNodeType()!= INode::kNTSimple ) {
+ XMP_Throw ( "Alt-text array item is not simple", kXMPErr_BadXPath );
+ }
+ if ( !currItem->HasQualifiers() || !currItem->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), xmlLangQualifierName.c_str(), xmlLangQualifierName.size() ) ) {
+ XMP_Throw ( "Alt-text array item has no language qualifier", kXMPErr_BadXPath );
+ }
+ }
+
+ // Look for an exact match with the specific language.
+ spISimpleNode xmlLangQualifierNode, currItemValue;
+ for ( itemNum = 1; itemNum <= itemLim; ++itemNum ) {
+ currItem = arrayNode->GetNodeAtIndex(itemNum);
+ xmlLangQualifierNode = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode();
+ currItemValue = currItem->ConvertToSimpleNode();
+ if ( !strcmp(xmlLangQualifierNode->GetValue()->c_str(), 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 = 1; itemNum <= itemLim; ++itemNum ) {
+ currItem = arrayNode->GetNodeAtIndex(itemNum);
+ xmlLangQualifierNode = currItem->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(),
+ xmlLangQualifierName.c_str(), xmlLangQualifierName.size() )->ConvertToSimpleNode();
+ XMP_StringPtr currLang = xmlLangQualifierNode->GetValue()->c_str();
+ const size_t currLangSize = xmlLangQualifierNode->GetValue()->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->GetNodeAtIndex(itemNum);
+ xmlLangQualifierNode = currItem->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(),
+ xmlLangQualifierName.c_str(), xmlLangQualifierName.size() )->ConvertToSimpleNode();
+ XMP_StringPtr currLang = xmlLangQualifierNode->GetValue()->c_str();
+ const size_t currLangSize = xmlLangQualifierNode->GetValue()->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 = 1; itemNum <= itemLim; ++itemNum ) {
+ currItem = arrayNode->GetNodeAtIndex(itemNum);
+ xmlLangQualifierNode = currItem->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(),
+ xmlLangQualifierName.c_str(), xmlLangQualifierName.size() )->ConvertToSimpleNode();
+ if ( !XMP_LitMatch(xmlLangQualifierNode->GetValue()->c_str(), "x-default" ) ) {
+ itemNode = currItem;
+ return kXMP_CLT_XDefault;
+ }
+ }
+
+ // Everything failed, choose the first item.
+ itemNode = arrayNode->GetNodeAtIndex(1);
+ return kXMP_CLT_FirstItem;
+
+} // ChooseLocalizedText
+
+
+
+// -------------------------------------------------------------------------------------------------
+// GetLocalizedText
+// ----------------
+
+bool
+XMPMeta2::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
+{
+ // TO DO : options
+ 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 );
+ spINode arrayNode, itemNode;
+ XMP_OptionBits arrayOptions;
+ if(!XMPUtils::FindCnstNode( this->mDOM, arrayPath, arrayNode, &arrayOptions)) return false;
+ XMP_CLTMatch match = ChooseIXMPLocalizedText( arrayNode->ConvertToArrayNode(), arrayOptions, genericLang, specificLang, itemNode );
+ if ( match == kXMP_CLT_NoValues ) return false;
+
+ spISimpleNode qualifierNode = itemNode->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos )->ConvertToSimpleNode();
+ *actualLang = qualifierNode->GetValue()->c_str();
+ *langSize = static_cast<XMP_StringLen>( qualifierNode->GetValue()->size() );
+ spcIUTF8String itemNodeValue = itemNode->ConvertToSimpleNode()->GetValue();
+ *itemValue = itemNodeValue->c_str();
+ *valueSize = static_cast<XMP_StringLen>( itemNodeValue->size() );
+ *options = XMPUtils::GetIXMPOptions(itemNode);
+ return true;
+
+} // GetLocalizedText
+
+// -------------------------------------------------------------------------------------------------
+// DeleteLocalizedText
+// -------------------
+
+
+void
+XMPMeta2::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.
+ spINode destNode, itemNode;
+ spIArrayNode arrayNode;
+ XMP_OptionBits arrayOptions;
+ if(!XMPUtils::FindCnstNode( this->mDOM, arrayPath, destNode, &arrayOptions)) return;
+ arrayNode = destNode->ConvertToArrayNode();
+ size_t arraySize = arrayNode->ChildCount();
+ XMP_CLTMatch match = ChooseIXMPLocalizedText( arrayNode->ConvertToArrayNode(), arrayOptions, genericLang, specificLang, itemNode );
+ spcIUTF8String itemValue = itemNode->ConvertToSimpleNode()->GetValue();
+ if ( match != kXMP_CLT_SpecificMatch ) return;
+
+
+ size_t itemIndex = 1;
+ for ( ; itemIndex <= arraySize; ++itemIndex ) {
+ if ( arrayNode->GetNodeAtIndex(itemIndex) == itemNode ) break;
+ }
+ XMP_Enforce ( itemIndex <= arraySize );
+
+ // Decide if the selected item is x-default or not, find relevant matching item.
+ spISimpleNode qualNode ;
+ bool itemIsXDefault = false;
+
+ if ( itemNode->HasQualifiers() ) {
+ qualNode = itemNode->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos )->ConvertToSimpleNode();
+ if (XMP_LitMatch(qualNode->GetValue()->c_str(), "x-default")) itemIsXDefault = true;
+ }
+
+ if ( itemIsXDefault && (itemIndex != 1) ) { // Enforce the x-default is first policy.
+ auto sp = arrayNode->GetNodeAtIndex( itemIndex );
+ arrayNode->GetNodeAtIndex(1).swap( sp );
+ itemIndex = 1;
+ }
+
+ spINode assocNode;
+ size_t assocIndex = 0;
+ size_t assocIsXDefault = false;
+ if ( itemIsXDefault ) {
+
+ for ( assocIndex = 2; assocIndex <= arraySize; ++assocIndex ) {
+ spISimpleNode indexNode = arrayNode->GetNodeAtIndex( assocIndex )->ConvertToSimpleNode();
+ if ( !strcmp(indexNode->GetValue()->c_str(), itemValue->c_str()) ) {
+ assocNode = arrayNode->GetNodeAtIndex(assocIndex);
+ break;
+ }
+ }
+
+ }
+ else if ( itemIndex > 1 ) {
+
+ spcIUTF8String itemOneValue = arrayNode->GetNodeAtIndex( 1 )->ConvertToSimpleNode()->GetValue();
+ if ( !strcmp(itemOneValue->c_str(), itemValue->c_str()) ) {
+ qualNode = arrayNode->GetNodeAtIndex( 1 )->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos )->ConvertToSimpleNode();
+ if ( XMP_LitMatch(qualNode->GetValue()->c_str(),"x-default") ) {
+ assocNode = arrayNode->GetNodeAtIndex(1);
+ assocIndex = 1;
+ assocIsXDefault = true;
+ }
+ }
+
+ }
+ if ( !assocIndex) {
+ arrayNode->RemoveNodeAtIndex(itemIndex);
+ }
+ else if ( itemIndex < assocIndex ) {
+ arrayNode->RemoveNodeAtIndex(assocIndex);
+ arrayNode->RemoveNodeAtIndex(itemIndex);
+ }
+ else {
+ arrayNode->RemoveNodeAtIndex(itemIndex);
+ arrayNode->RemoveNodeAtIndex(assocIndex);
+ }
+
+} // DeleteLocalizedText
+// -------------------------------------------------------------------------------------------------
+
+// SetLocalizedText
+// ----------------
+
+
+void
+XMPMeta2::SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr _genericLang,
+ XMP_StringPtr _specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+
+ // is new DOM enforcing that first qualifier should be a lang alt
+ 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.
+ spINode destNode;
+ spIArrayNode arrayNode;
+ XMP_OptionBits arrayOptions;
+ if( !XMPUtils::FindCnstNode(this->mDOM, arrayPath, destNode) ) {
+
+ XPathStepInfo lastPathSegment( arrayPath.back());
+ XMP_VarString arrayStep = lastPathSegment.step;
+ XMP_Index insertIndex = 0;
+ if (!XMPUtils::FindNode(this->mDOM, arrayPath, kXMP_CreateNodes, kXMP_PropArrayIsAlternate | kXMP_PropValueIsArray, destNode, &insertIndex)) {
+ XMP_Throw ( "Failure creating array node", kXMPErr_BadXPath );
+ }
+
+ }
+
+ arrayNode = destNode->ConvertToArrayNode();
+ arrayOptions = XMPUtils::GetIXMPOptions(arrayNode);
+
+
+
+ size_t arrayChildCount = arrayNode->ChildCount();
+ if ( !arrayNode ) XMP_Throw ( "Failed to find or create array node", kXMPErr_BadXPath );
+ if ( ! XMP_ArrayIsAltText(arrayOptions) ) {
+ if ( !arrayChildCount && XMP_ArrayIsAlternate(arrayOptions) ) {
+ arrayOptions |= 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;
+ spcISimpleNode firstQualifier;
+ spINode xdItem;
+ bool haveXDefault = false;
+
+ for ( itemNum = 1, itemLim = arrayNode->ChildCount(); itemNum <= itemLim; ++itemNum ) {
+ spINode currItem = arrayNode->GetNodeAtIndex(itemNum);
+
+ XMP_Assert (XMP_PropHasLang(XMPUtils::GetIXMPOptions(currItem)));
+ if(!currItem->HasQualifiers()) {
+ XMP_Throw ( "Language qualifier must be first", kXMPErr_BadXPath );
+ }
+ firstQualifier = currItem->QualifiersIterator()->GetNode()->ConvertToSimpleNode();
+ if (!XMP_LitMatch(firstQualifier->GetName()->c_str(),"lang")) {
+ XMP_Throw ( "Language qualifier must be first", kXMPErr_BadXPath );
+ }
+ if (XMP_LitMatch(firstQualifier->GetValue()->c_str(),"x-default" )) {
+ xdItem = currItem;
+ haveXDefault = true;
+ break;
+ }
+ }
+
+ if ( haveXDefault && (itemNum != 1) ) {
+ //TODO or not to do
+ XMP_Assert ( XMP_LitMatch(firstQualifier->GetValue()->c_str(), "x-default") );
+ spcISimpleNode tempNode = arrayNode->GetNodeAtIndex( itemNum )->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos )->ConvertToSimpleNode();
+
+ firstQualifier.swap(tempNode);
+ }
+
+ spINode itemNode;
+ spcIUTF8String xdValue, itemNodeValue;
+ if(xdItem && xdItem->GetNodeType() == INode::kNTSimple) {
+ xdValue = xdItem->ConvertToSimpleNode()->GetValue();
+ }
+ XMP_CLTMatch match = ChooseIXMPLocalizedText ( arrayNode->ConvertToArrayNode(), arrayOptions, genericLang, specificLang, itemNode);
+ if(itemNode && itemNode->GetNodeType() == INode::kNTSimple) {
+ itemNodeValue = itemNode->ConvertToSimpleNode()->GetValue();
+ }
+ 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.
+ AppendIXMPLangItem ( arrayNode, "x-default", itemValue );
+ haveXDefault = true;
+ if ( ! specificXDefault ) AppendIXMPLangItem ( 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 && haveXDefault && (xdItem != itemNode) && (XMP_LitMatch(xdValue->c_str(), itemNodeValue->c_str())) ) {
+ XMPUtils::SetNode ( xdItem, itemValue, XMPUtils::GetIXMPOptions( xdItem));
+ }
+ XMPUtils::SetNode(itemNode, itemValue,XMPUtils:: GetIXMPOptions(itemNode));
+
+ } else {
+ // Update all items whose values match the old x-default value.
+ XMP_Assert ( xdItem && haveXDefault && (xdItem.get() == itemNode.get()) );
+ for ( itemNum = 1, itemLim = arrayNode->ChildCount(); itemNum <= itemLim; ++itemNum ) {
+ spISimpleNode currItem = arrayNode->GetNodeAtIndex( itemNum )->ConvertToSimpleNode();
+ if ( (currItem.get() == xdItem.get() ) || (strcmp(currItem->GetValue()->c_str(), xdValue->c_str()) )) continue;
+ XMPUtils::SetNode ( currItem, itemValue, XMPUtils::GetIXMPOptions(currItem) );
+ }
+
+ XMPUtils::SetNode( xdItem, itemValue,XMPUtils:: GetIXMPOptions(xdItem));
+ }
+ break;
+
+ case kXMP_CLT_SingleGeneric :
+
+ // Update the generic item, update x-default if it matches the old value.
+ if ( xdItem && haveXDefault && (xdItem != itemNode) && (XMP_LitMatch(xdValue->c_str(),itemNodeValue->c_str()) ) ) {
+ XMPUtils::SetNode ( xdItem, itemValue, XMPUtils::GetIXMPOptions(xdItem) );
+ }
+ XMPUtils::SetNode( itemNode, itemValue,XMPUtils:: GetIXMPOptions(itemNode) ); // ! Do this after the x-default check!
+ break;
+
+ case kXMP_CLT_MultipleGeneric :
+
+ // Create the specific language, ignore x-default.
+ AppendIXMPLangItem ( 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->ChildCount()== 1 ) XMPUtils::SetNode ( xdItem, itemValue, XMPUtils::GetIXMPOptions(xdItem) );
+ AppendIXMPLangItem ( arrayNode, specificLang, itemValue );
+ break;
+
+ case kXMP_CLT_FirstItem :
+
+ // Create the specific language, don't add an x-default item.
+ AppendIXMPLangItem ( 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->ChildCount() == 1) ) {
+ AppendIXMPLangItem ( arrayNode, "x-default", itemValue );
+ }
+
+} // SetLocalizedText
+
+
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpPropertyTree
+// ----------------
+
+// *** Extract the validation code into a separate routine to call on exit in debug builds.
+
+static void
+DumpIXMPPropertyTree ( const spcINode & currNode,
+ int indent,
+ size_t itemIndex,
+ XMP_TextOutputProc outProc,
+ void * refCon )
+{
+ if(!currNode) return;
+ char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
+ XMP_OptionBits options = XMPUtils::GetIXMPOptions(currNode);
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+ XMP_VarString currNameSpace = defaultMap->GetPrefix(currNode->GetNameSpace()->c_str(), currNode->GetNameSpace()->size() )->c_str();
+ XMP_VarString nodeFullName = currNameSpace + ":" + currNode->GetName()->c_str();
+
+ OutProcIndent ( (size_t)indent );
+
+ size_t childCount = 0;
+ if ( itemIndex == 0 ) {
+ if ( options & kXMP_PropIsQualifier ) OutProcNChars ( "? ", 2 );
+ DumpClearString ( nodeFullName, outProc, refCon );
+ }
+ else {
+ OutProcNChars ( "[", 1 );
+ OutProcDecInt ( itemIndex );
+ OutProcNChars ( "]", 1 );
+ }
+
+ if ( ! (options & kXMP_PropCompositeMask) ) {
+ OutProcNChars ( " = \"", 4 );
+ DumpClearString ( currNode->ConvertToSimpleNode()->GetValue()->c_str(), outProc, refCon );
+ OutProcNChars ( "\"", 1 );
+ }
+
+ if ( options != 0 ) {
+ OutProcNChars ( " ", 2 );
+ DumpNodeOptions ( options, outProc, refCon );
+ }
+
+ if ( options & kXMP_PropHasLang ) {
+
+ spcISimpleNode firstQualifier = currNode->QualifiersIterator()->GetNode()->ConvertToSimpleNode();
+ if ( !currNode->HasQualifiers() || !(XMP_LitMatch(firstQualifier->GetName()->c_str(), "lang") ) ) {
+ OutProcLiteral ( " ** bad lang flag **" );
+ }
+ }
+ // *** Check rdf:type also.
+
+ if ( ! (options & kXMP_PropCompositeMask) ) {
+ if(currNode->GetNodeType() == INode::kNTArray) {
+ childCount = currNode->ConvertToArrayNode()->ChildCount();
+ }
+ if(currNode->GetNodeType() == INode::kNTStructure) {
+ childCount = currNode->ConvertToStructureNode()->ChildCount();
+ }
+ if ( childCount ) OutProcLiteral ( " ** bad children **" );
+
+ }
+ else if ( options & kXMP_PropValueIsArray ) {
+ if ( options & kXMP_PropValueIsStruct ) OutProcLiteral ( " ** bad comp flags **" );
+ }
+ else if ( (options & kXMP_PropCompositeMask) != kXMP_PropValueIsStruct ) {
+ OutProcLiteral ( " ** bad comp flags **" );
+ }
+
+ OutProcNewline();
+
+ if( currNode->HasQualifiers() ) {
+ auto qualIter = currNode->QualifiersIterator();
+ for (size_t qualNum = 0 ; qualIter; qualIter = qualIter->Next(), qualNum++ ) {
+ spcINode currQual = qualIter->GetNode();
+ XMP_OptionBits currQualOptions = XMPUtils::GetIXMPOptions(currQual);
+ if ( currQual->GetParent() && currQual->GetParent()->GetParent()!= currNode ) OutProcLiteral ( "** bad parent link => " );
+ if ( XMP_LitMatch(currQual->GetName()->c_str(), kXMP_ArrayItemName ) ) OutProcLiteral ( "** bad qual name => " );
+ if ( ! (currQualOptions & kXMP_PropIsQualifier) ) OutProcLiteral ( "** bad qual flag => " );
+ if ( XMP_LitMatch(currQual->GetName()->c_str(), "lang" )) {
+ if ( (qualNum != 0) || (! (options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " );
+ }
+
+ DumpIXMPPropertyTree ( currQual, indent + 2, 0, outProc, refCon );
+
+ }
+ }
+ spcINodeIterator childIter;
+ if(currNode->GetNodeType() == INode::kNTArray) {
+ childIter = currNode->ConvertToArrayNode()->Iterator();
+ }
+ if(currNode->GetNodeType() == INode::kNTStructure) {
+ childIter = currNode->ConvertToStructureNode()->Iterator();
+ }
+ for (size_t childNum = 0; childIter; childIter = childIter->Next(), childNum++) {
+ spcINode currentChild = childIter->GetNode();
+ XMP_OptionBits currentChildOptions = XMPUtils::GetIXMPOptions( currentChild);
+ if( !currentChild) continue;
+ if ( currentChild->GetParent() != currNode ) OutProcLiteral ( "** bad parent link => " );
+ if ( currentChildOptions & kXMP_PropIsQualifier ) OutProcLiteral ( "** bad qual flag => " );
+
+ if ( options & kXMP_PropValueIsArray ) {
+
+ itemIndex = childNum + 1;
+ if (XMP_LitMatch(currentChild->GetName()->c_str(), kXMP_ArrayItemName) ) OutProcLiteral ( "** bad item name => " );
+ }
+ else {
+
+ itemIndex = 0;
+ if ( XMP_LitMatch(currentChild->GetName()->c_str(), kXMP_ArrayItemName ) ) OutProcLiteral ( "** bad field name => " );
+ }
+
+ DumpIXMPPropertyTree ( currentChild, indent + 1, itemIndex, outProc, refCon );
+
+ }
+
+} // DumpPropertyTree
+
+
+// -------------------------------------------------------------------------------------------------
+// DumpObject
+// ----------
+
+void
+XMPMeta2::DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const
+{
+ // TODO
+ // value of mDOM ?
+
+
+ XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+ OutProcLiteral ( "Dumping XMPMeta object \"" );
+ DumpClearString (mDOM->GetAboutURI()->c_str(), outProc, refCon );
+ OutProcNChars ( "\" ", 3 );
+ DumpNodeOptions ( XMPUtils::GetIXMPOptions(mDOM), outProc, refCon );
+ OutProcNewline();
+
+ // One can't possibly allocate mDOM a value ?!
+ /*
+ if ( ! tree.value.empty() ) {
+ OutProcLiteral ( "** bad root value ** \"" );
+ DumpClearString ( tree.value, outProc, refCon );
+ OutProcNChars ( "\"", 1 );
+ OutProcNewline();
+ }
+ */
+ if ( mDOM->HasQualifiers() ) {
+ OutProcLiteral ( "** bad root qualifiers **" );
+ OutProcNewline();
+ spINodeIterator qualIter = mDOM->QualifiersIterator();
+ for ( ; qualIter; qualIter = qualIter->Next() ) {
+ DumpIXMPPropertyTree ( qualIter->GetNode(), 3, 0, outProc, refCon );
+ }
+ }
+ map<std::string, bool> schemaUsed;
+ if ( mDOM->ChildCount() ) {
+
+ spINodeIterator childIter = mDOM->Iterator();
+ for ( ;childIter; childIter = childIter->Next() ) {
+
+ spINode currSchema = childIter->GetNode();
+ XMP_OptionBits currSchemaOptions = kXMP_SchemaNode;
+ if(!schemaUsed.count(currSchema->GetNameSpace()->c_str())) {
+ OutProcNewline();
+ OutProcIndent ( 1 );
+ XMP_VarString prefix = defaultMap->GetPrefix(currSchema->GetNameSpace()->c_str(), currSchema->GetNameSpace()->size() )->c_str();
+ prefix += ":";
+ DumpClearString ( prefix.c_str(), outProc, refCon );
+ OutProcNChars ( " ", 2 );
+ DumpClearString ( currSchema->GetNameSpace()->c_str(), outProc, refCon );
+ OutProcNChars ( " ", 2 );
+ DumpNodeOptions ( currSchemaOptions, outProc, refCon );
+ OutProcNewline();
+
+ if ( ! (currSchemaOptions & kXMP_SchemaNode) ) {
+ OutProcLiteral ( "** bad schema options **" );
+ OutProcNewline();
+ }
+
+ schemaUsed[currSchema->GetNameSpace()->c_str()] = true;
+ }
+
+ DumpIXMPPropertyTree ( currSchema, 2, 0, outProc, refCon );
+
+ }
+
+ }
+
+} // DumpObject
+
+
+
+// -------------------------------------------------------------------------------------------------
+// SetErrorCallback
+// ----------------
+
+void
+XMPMeta2::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;
+ spParser->GetIDOMParser_I()->SetErrorCallback(&errorCallback);
+
+} // SetErrorCallback
+
+// -------------------------------------------------------------------------------------------------
+// ResetErrorCallbackLimit
+// -----------------------
+
+void
+XMPMeta2::ResetErrorCallbackLimit(XMP_Uns32 limit)
+{
+
+ this->errorCallback.limit = limit;
+ this->errorCallback.notifications = 0;
+ this->errorCallback.topSeverity = kXMPErrSev_Recoverable;
+ spParser->GetIDOMParser_I()->SetErrorCallback(&errorCallback);
+
+} // ResetErrorCallbackLimit
+#endif
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta2.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta2.hpp
new file mode 100644
index 0000000000..bd1aa9ba14
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPMeta2.hpp
@@ -0,0 +1,190 @@
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+#ifndef __XMPMeta2_hpp__
+#define __XMPMeta2_hpp__
+
+
+#include "public/include/XMP_Environment.h"
+#include "public/include/XMP_Const.h"
+#include "XMPCore/source/XMPCore_Impl.hpp"
+#include "source/XMLParserAdapter.hpp"
+#include "XMPCore/source/XMPMeta.hpp"
+#include "XMPCore/XMPCoreFwdDeclarations_I.h"
+
+#ifndef DumpXMLParseTree
+ #define DumpXMLParseTree 0
+#endif
+
+extern XMP_VarString * xdefaultName; // Needed in XMPMeta-Parse.cpp, MoveExplicitAliases.
+
+class XMPIterator;
+class XMPUtils;
+
+class XMPMeta2 : public XMPMeta {
+public:
+
+
+
+
+ // ---------------------------------------------------------------------------------------------
+
+ XMPMeta2();
+
+ virtual ~XMPMeta2() RELEASE_NO_THROW;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual bool
+ GetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr * propValue,
+ XMP_StringLen * valueSize,
+ XMP_OptionBits * options ) const;
+
+ // ---------------------------------------------------------------------------------------------
+
+ virtual void
+ SetProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr propValue,
+ XMP_OptionBits options );
+
+
+ virtual void
+ SetArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ virtual void
+ AppendArrayItem ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits arrayOptions,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ virtual void
+ SetQualifier ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_StringPtr qualNS,
+ XMP_StringPtr qualName,
+ XMP_StringPtr qualValue,
+ XMP_OptionBits options );
+ /*
+ virtual void
+ SetStructField ( XMP_StringPtr schemaNS,
+ XMP_StringPtr structName,
+ XMP_StringPtr fieldNS,
+ XMP_StringPtr fieldName,
+ XMP_StringPtr fieldValue,
+ XMP_OptionBits options );
+
+
+
+
+
+
+ */
+ /*
+
+
+ // ---------------------------------------------------------------------------------------------
+ */
+ virtual 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;
+ virtual void
+ SetLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options );
+
+ virtual void
+ DeleteLocalizedText ( XMP_StringPtr schemaNS,
+ XMP_StringPtr altTextName,
+ XMP_StringPtr genericLang,
+ XMP_StringPtr specificLang);
+ virtual void
+ GetObjectName ( XMP_StringPtr * namePtr,
+ XMP_StringLen * nameLen ) const;
+
+ virtual void
+ SetObjectName ( XMP_StringPtr name );
+
+
+ virtual void
+ ParseFromBuffer ( XMP_StringPtr buffer,
+ XMP_StringLen bufferSize,
+ XMP_OptionBits options );
+ virtual void
+ SerializeToBuffer ( XMP_VarString * rdfString,
+ XMP_OptionBits options,
+ XMP_StringLen padding,
+ XMP_StringPtr newline,
+ XMP_StringPtr indent,
+ XMP_Index baseIndent ) const;
+ virtual void
+ Clone ( XMPMeta * clone, XMP_OptionBits options ) const;
+ virtual bool
+ DoesPropertyExist ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName ) const;
+ virtual void
+ Erase();
+ virtual void
+ Sort();
+ virtual XMP_Index
+ CountArrayItems ( XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName ) const;
+ virtual void
+ DeleteProperty ( XMP_StringPtr schemaNS,
+ XMP_StringPtr propName );
+ virtual void
+ DumpObject ( XMP_TextOutputProc outProc,
+ void * refCon ) const;
+
+ void
+ SetErrorCallback(XMPMeta_ErrorCallbackWrapper wrapperProc,
+ XMPMeta_ErrorCallbackProc clientProc,
+ void * context,
+ XMP_Uns32 limit);
+
+ void
+ ResetErrorCallbackLimit(XMP_Uns32 limit);
+
+
+ // ---------------------------------------------------------------------------------------------
+
+ AdobeXMPCore::spIMetadata mDOM;
+ AdobeXMPCore::spIDOMImplementationRegistry spRegistry;
+ AdobeXMPCore::spIDOMParser spParser;
+
+ friend class XMPIterator;
+ friend class XMPUtils;
+
+private:
+
+ AdobeXMPCommon::spIUTF8String mBuffer;
+ XMPMeta2 ( const XMPMeta2 & )
+ { XMP_Throw ( "Call to hidden constructor", kXMPErr_InternalFailure ); };
+ void operator= ( const XMPMeta2 & )
+ { XMP_Throw ( "Call to hidden operator=", kXMPErr_InternalFailure ); };
+
+ void ProcessXMLTree ( XMP_OptionBits options );
+ bool ProcessXMLBuffer ( XMP_StringPtr buffer, XMP_StringLen xmpSize, bool lastClientCall );
+ void ProcessRDF ( const XML_Node & xmlTree, XMP_OptionBits options );
+
+
+};
+
+#endif
+#endif
\ No newline at end of file
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils-FileInfo.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils-FileInfo.cpp
new file mode 100644
index 0000000000..6c7073f964
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils-FileInfo.cpp
@@ -0,0 +1,1927 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/XMPCoreDefines.h"
+#include "XMPCore/source/XMPUtils.hpp"
+#if ENABLE_CPP_DOM_MODEL
+ #include "source/UnicodeInlines.incl_cpp"
+ #include "source/UnicodeConversions.hpp"
+ #include "source/ExpatAdapter.hpp"
+ #include "third-party/zuid/interfaces/MD5.h"
+ #include "XMPCore/Interfaces/IMetadata_I.h"
+ #include "XMPCore/Interfaces/IArrayNode_I.h"
+ #include "XMPCore/Interfaces/ISimpleNode_I.h"
+ #include "XMPCore/Interfaces/INodeIterator_I.h"
+ #include "XMPCore/Interfaces/IPathSegment_I.h"
+ #include "XMPCore/Interfaces/IPath_I.h"
+ #include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
+ #include "XMPCore/Interfaces/IDOMImplementationRegistry_I.h"
+ #include "XMPCommon/Interfaces/IUTF8String_I.h"
+#endif
+#include <algorithm> // For binary_search.
+
+#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 = static_cast<XMP_Uns32>(*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 ))
+
+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
+// ------------------
+
+
+#if ENABLE_CPP_DOM_MODEL
+// -------------------------------------------------------------------------------------------------
+// CatenateArrayItems_v2
+// ------------------
+
+/* class static */ void
+XMPUtils::CatenateArrayItems_v2(const XMPMeta & ptr,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_VarString * catedStr)
+{
+ using namespace AdobeXMPCore;
+ using namespace AdobeXMPCommon;
+
+ if(sUseNewCoreAPIs) {
+ const XMPMeta2 & xmpObj = dynamic_cast<const XMPMeta2 &>(ptr);
+ 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);
+
+ spINode arrayNode; // ! Move up to avoid gcc complaints.
+ XMP_OptionBits arrayForm = 0, arrayOptions = 0;
+ spcINode currItem;
+
+ // 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);
+
+ XMPUtils::FindCnstNode((xmpObj.mDOM), arrayPath, arrayNode, &arrayOptions);
+
+ if (!arrayNode) return;
+
+ arrayForm = arrayOptions & kXMP_PropCompositeMask;
+ if ((!(arrayForm & kXMP_PropValueIsArray)) || (arrayForm & kXMP_PropArrayIsAlternate)) {
+ XMP_Throw("Named property must be non-alternate array", kXMPErr_BadParam);
+ }
+ size_t arrayChildCount = XMPUtils::GetNodeChildCount(arrayNode);
+ if (!arrayChildCount) 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.
+
+ spcINodeIterator arrayIter = XMPUtils::GetNodeChildIterator(arrayNode);
+
+ if ((XMPUtils::GetIXMPOptions(currItem) & kXMP_PropCompositeMask) != 0) XMP_Throw("Array items must be simple", kXMPErr_BadParam);
+
+ *catedStr = arrayIter->GetNode()->ConvertToSimpleNode()->GetValue()->c_str();
+ ApplyQuotes(catedStr, openQuote, closeQuote, allowCommas);
+
+ //ArrayNodes in the new DOM are homogeneous so need to check types of other items in the arary if the first one is Simple
+ for (arrayIter = arrayIter->Next(); arrayIter; arrayIter = arrayIter->Next()) {
+
+ XMP_VarString tempStr( arrayIter->GetNode()->ConvertToSimpleNode()->GetValue()->c_str());
+ ApplyQuotes(&tempStr, openQuote, closeQuote, allowCommas);
+ *catedStr += separator;
+ *catedStr += tempStr;
+ }
+ }
+ else {
+ return;
+ }
+
+
+} // CatenateArrayItems_v2
+
+#endif
+// -------------------------------------------------------------------------------------------------
+/* 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 )
+{
+
+#if ENABLE_CPP_DOM_MODEL
+
+ if(sUseNewCoreAPIs) {
+
+ dynamic_cast<const XMPMeta2 &>(xmpObj);
+ CatenateArrayItems_v2(xmpObj, schemaNS, arrayName, separator, quotes, options, catedStr);
+ return;
+
+ }
+
+#endif
+
+ 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_v2
+// ------------------
+#if ENABLE_CPP_DOM_MODEL
+/* class static */ void
+XMPUtils::SeparateArrayItems_v2(XMPMeta * xmpObj2,
+XMP_StringPtr schemaNS,
+XMP_StringPtr arrayName,
+XMP_OptionBits options,
+XMP_StringPtr catedStr)
+{
+
+#if ENABLE_CPP_DOM_MODEL
+ using namespace AdobeXMPCore;
+ using namespace AdobeXMPCommon;
+ XMPMeta2 * xmpObj = NULL;
+ if(sUseNewCoreAPIs) {
+ xmpObj = dynamic_cast<XMPMeta2 *> (xmpObj2);
+ }
+
+#endif
+ XMP_Assert((schemaNS != 0) && (arrayName != 0) && (catedStr != 0)); // ! Enforced by wrapper.
+ // TODO - check if the array item name should be arrayname one or karrayitem
+ // TODO - check the find array in case array doesn't already exist
+ XMP_VarString itemValue;
+ size_t itemStart, itemEnd;
+ size_t nextSize, charSize = 0;
+ UniCharKind nextKind, charKind = UCK_normal;
+ UniCodePoint nextChar, uniChar = 0;
+ XMP_OptionBits arrayOptions = 0;
+
+
+ bool preserveCommas = false;
+ if (options & kXMPUtil_AllowCommas) {
+ preserveCommas = true;
+ options ^= kXMPUtil_AllowCommas;
+ }
+
+ options = VerifySetOptions(options, 0);
+ 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);
+ spINode arrayNode;
+ if (XMPUtils::FindCnstNode(xmpObj->mDOM, arrayPath, arrayNode, &arrayOptions)){
+
+ XMP_OptionBits arrayForm = arrayOptions & 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.
+
+ XPathStepInfo lastPathSegment(arrayPath.back());
+ XMP_VarString arrayStep = lastPathSegment.step;
+ //arrayPath.pop_back();
+ spINode destNode;
+ XMP_Index insertIndex = 0;
+ if (!XMPUtils::FindNode(xmpObj->mDOM, arrayPath, kXMP_CreateNodes, options, destNode, &insertIndex, true)) {
+ XMP_Throw("Failure creating array node", kXMPErr_BadXPath);
+ }
+ std::string arrayNameSpace, arrayName;
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+ arrayOptions = options;
+ XMPUtils::GetNameSpaceAndNameFromStepValue(lastPathSegment.step, defaultMap, arrayNameSpace, arrayName);
+ // Need to check Alternate first
+ if (arrayOptions & kXMP_PropArrayIsAlternate) {
+ arrayNode = IArrayNode::CreateAlternativeArrayNode( arrayNameSpace.c_str(), arrayNameSpace.size(), arrayName.c_str(), arrayName.size());
+ }
+ else if (arrayOptions & kXMP_PropArrayIsOrdered) {
+ arrayNode = IArrayNode::CreateOrderedArrayNode( arrayNameSpace.c_str(), arrayNameSpace.size(), arrayName.c_str(), arrayName.size() );
+ }
+ else if (arrayOptions & kXMP_PropArrayIsUnordered) {
+ arrayNode = IArrayNode::CreateUnorderedArrayNode( arrayNameSpace.c_str(), arrayNameSpace.size(), arrayName.c_str(), arrayName.size() );
+ }
+
+ else {
+ XMP_Throw("Failure creating array node", kXMPErr_BadXPath);
+ }
+ if (destNode->GetNodeType() == INode::kNTStructure) {
+
+ destNode->ConvertToStructureNode()->InsertNode(arrayNode);
+ }
+ else if (destNode->GetNodeType() == INode::kNTArray) {
+
+ destNode->ConvertToArrayNode()->AppendNode(arrayNode);
+ }
+ else {
+
+ XMP_Throw("Failure creating array node", kXMPErr_BadXPath);
+ }
+
+ if (!arrayNode) XMP_Throw("Failed to create named array", kXMPErr_BadXPath);
+ }
+
+
+ size_t oldChildCount = XMPUtils::GetNodeChildCount(arrayNode);
+ std::vector<XMP_VarString> oldArrayNodes;
+ std::vector<spINode> qualifiers;
+
+ // used to handle duplicates
+ std::vector<bool> oldArrayNodeSeen(oldChildCount, false);
+ spcINodeIterator oldArrayChildIter = XMPUtils::GetNodeChildIterator(arrayNode);
+
+ for (; oldArrayChildIter; oldArrayChildIter = oldArrayChildIter->Next()) {
+
+ oldArrayNodes.push_back( oldArrayChildIter->GetNode()->ConvertToSimpleNode()->GetValue()->c_str());
+ if (oldArrayChildIter->GetNode()->HasQualifiers()) {
+
+ qualifiers.push_back(oldArrayChildIter->GetNode()->Clone());
+ /*for ( auto it = oldArrayChildIter->GetNode()->QualifiersIterator(); it; it = it->Next() ) {
+ qualifiers.push_back( it->GetNode()->Clone() );
+ }*/
+ }
+ else {
+ qualifiers.push_back(spINode());
+ }
+
+ }
+
+ arrayNode->Clear(true, false);
+ // used to avoid typecasting repeatedly!
+ spIArrayNode tempArrayNode = arrayNode->ConvertToArrayNode();
+
+ size_t endPos = strlen(catedStr);
+
+ itemEnd = 0;
+ while (itemEnd < endPos) {
+
+
+
+ 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) {
+
+
+
+ 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;
+
+ spISimpleNode newItem;
+ for (oldChild = 1; oldChild <= oldChildCount; ++oldChild) {
+ if (!oldArrayNodeSeen[oldChild - 1] && itemValue == oldArrayNodes[oldChild - 1]) break;
+ }
+
+
+ if (oldChild == oldChildCount + 1) {
+ // newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue.c_str(), 0 );
+ newItem = ISimpleNode::CreateSimpleNode(arrayNode->GetNameSpace()->c_str(), arrayNode->GetNameSpace()->size(),
+ kXMP_ArrayItemName, AdobeXMPCommon::npos, itemValue.c_str());
+ }
+ else {
+ newItem = ISimpleNode::CreateSimpleNode(arrayNode->GetNameSpace()->c_str(), arrayNode->GetNameSpace()->size(),
+ kXMP_ArrayItemName, AdobeXMPCommon::npos, oldArrayNodes[oldChild - 1].c_str());
+ if (qualifiers[ oldChild - 1] && qualifiers[ oldChild - 1] ->HasQualifiers() ) {
+
+ for (auto it = qualifiers[oldChild - 1] ->QualifiersIterator(); it; it = it->Next()) {
+
+ newItem->InsertQualifier(it->GetNode()->Clone());
+ }
+ }
+ oldArrayNodeSeen[oldChild - 1] = true; // ! Don't match again, let duplicates be seen.
+ }
+
+ tempArrayNode->AppendNode(newItem);
+
+ } // Loop through all of the returned items.
+
+ // Delete any of the old children that were not kept.
+
+
+} // SeparateArrayItems_v2
+#endif
+
+// -------------------------------------------------------------------------------------------------
+// SeparateArrayItems
+// ------------------
+
+/* class static */ void
+XMPUtils::SeparateArrayItems ( XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr )
+{
+
+#if ENABLE_CPP_DOM_MODEL
+ if (sUseNewCoreAPIs) {
+ SeparateArrayItems_v2(xmpObj, schemaNS, arrayName, options, catedStr);
+ return;
+ }
+#endif
+ 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 )
+{
+
+#if ENABLE_CPP_DOM_MODEL
+ if (sUseNewCoreAPIs) {
+ ApplyTemplate_v2(workingXMP, templateXMP, actions);
+ return;
+ }
+#endif
+
+ 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 )
+{
+
+#if ENABLE_CPP_DOM_MODEL
+ if (sUseNewCoreAPIs) {
+
+ RemoveProperties_v2(xmpObj, schemaNS, propName, options);
+ return;
+ }
+#endif
+
+ 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 )
+{
+
+#if ENABLE_CPP_DOM_MODEL
+ if(sUseNewCoreAPIs) {
+ (void)dynamic_cast<const XMPMeta2 &>(source);
+ return XMPUtils::DuplicateSubtree_v2(source, dest, sourceNS, sourceRoot, destNS, destRoot, options);
+ }
+
+#endif
+
+ 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/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils.cpp
new file mode 100644
index 0000000000..c17ca58637
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils.cpp
@@ -0,0 +1,3741 @@
+// =================================================================================================
+// 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/source/XMPCore_Impl.hpp"
+
+#include "XMPCore/source/XMPUtils.hpp"
+
+#include "XMP_MD5.h"
+
+
+#include <map>
+
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+#include <vector>
+
+#include <stdio.h> // For snprintf.
+#if ENABLE_CPP_DOM_MODEL
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+#include "XMPMeta2.hpp"
+#include "XMPCore/Interfaces/IMetadata_I.h"
+#include "XMPCore/Interfaces/IArrayNode_I.h"
+#include "XMPCore/Interfaces/ISimpleNode_I.h"
+#include "XMPCommon/Interfaces/IUTF8String_I.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap.h"
+#include "XMPCore/Interfaces/INodeIterator.h"
+using namespace AdobeXMPCore;
+using namespace AdobeXMPCommon;
+#endif
+
+#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+/";
+const XMP_VarString xmlNameSpace = "http://www.w3.org/XML/1998/namespace";
+// =================================================================================================
+// Local Utilities
+// ===============
+extern void SplitNameAndValue ( const XMP_VarString & selStep, XMP_VarString * nameStr, XMP_VarString * valueStr );
+
+extern void DumpNodeOptions ( XMP_OptionBits options,XMP_TextOutputProc outProc,void *refCon );
+// -------------------------------------------------------------------------------------------------
+// SetINode
+// --------------
+
+#if ENABLE_CPP_DOM_MODEL
+
+void XMPUtils::SetNode ( const spINode & node , XMP_StringPtr value, XMP_OptionBits options )
+{
+ if (!node) return;
+ //TO DO check UTF-8
+ if ( options & kXMP_DeleteExisting ) {
+ XMP_ClearOption ( options, kXMP_DeleteExisting );
+ node->Clear();
+ }
+ if ( value != 0 ) {
+
+ if ( options & kXMP_PropCompositeMask ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
+ if ( !node ) return;
+ XMP_Assert( node->GetNodeType() == INode::kNTSimple);
+ spISimpleNode simpleNode = node->ConvertToSimpleNode();
+ std::string newValue = value;
+
+ 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_BadUnicode );
+ }
+ }
+
+ }
+ if ( XMP_PropIsQualifier(options) && XMP_LitMatch(node->GetNameSpace()->c_str(), xmlNameSpace.c_str()) && XMP_LitMatch(node->GetName()->c_str(), "lang")) NormalizeLangValue ( &newValue );
+
+ simpleNode->SetValue(newValue.c_str(), newValue.size());
+ }
+ else {
+
+ if((node->GetNodeType() == INode::kNTStructure && (options & kXMP_PropValueIsArray)) || (node->GetNodeType() == INode::kNTArray && (options & kXMP_PropValueIsStruct))) {
+ XMP_Throw ( "Requested and existing composite form mismatch", kXMPErr_BadXPath );
+ }
+ node->Clear();
+
+ }
+
+} // SetINode
+XMP_OptionBits XMPUtils::ConvertNewArrayFormToOldArrayForm (const spcIArrayNode & arrayNode) {
+
+ XMP_OptionBits options = 0;
+ if(!arrayNode) return options;
+ if( arrayNode->GetArrayForm() == IArrayNode::kAFAlternative) return kXMP_PropArrayIsAlternate;
+ if( arrayNode->GetArrayForm() == IArrayNode::kAFOrdered) return kXMP_PropArrayIsOrdered;
+ if( arrayNode->GetArrayForm() == IArrayNode::kAFUnordered) return kXMP_PropArrayIsUnordered;
+ return 0;
+}
+
+spINode XMPUtils::CreateArrayChildNode( const spIArrayNode & arrayNode, XMP_OptionBits options) {
+
+ XMP_VarString nodeNameSpace = arrayNode->GetNameSpace()->c_str(), nodeName = arrayNode->GetName()->c_str();
+ spINode itemNode;
+ size_t arrayChildCount = arrayNode->ChildCount();
+ spINode firstChildNode;
+ if (!arrayChildCount) {
+ itemNode = XMPUtils::CreateTerminalNode(nodeNameSpace.c_str(), nodeName.c_str(), options);
+ return itemNode;
+ }
+ if(arrayChildCount) firstChildNode = arrayNode->GetNodeAtIndex(1);
+ XMP_OptionBits childOptions = 0;
+ if(firstChildNode && firstChildNode->GetNodeType() == INode::kNTArray) {
+ childOptions = ConvertNewArrayFormToOldArrayForm(firstChildNode->ConvertToArrayNode());
+ }
+ if(XMP_PropIsStruct(options) && (!arrayChildCount || firstChildNode->GetNodeType() == INode::kNTStructure ) ) {
+ itemNode = IStructureNode::CreateStructureNode(nodeNameSpace.c_str(), nodeNameSpace.size(), nodeName.c_str(), nodeName.size() );
+ }
+ else if(XMP_PropIsSimple(options) && (!arrayChildCount || firstChildNode->GetNodeType() == INode::kNTSimple ) ) {
+ itemNode = ISimpleNode::CreateSimpleNode(nodeNameSpace.c_str(), nodeNameSpace.size(), nodeName.c_str(), nodeName.size(), "", 0 );
+ }
+ else if((options & kXMP_PropArrayIsAlternate) && (childOptions & kXMP_PropArrayIsAlternate) ) {
+ itemNode = IArrayNode::CreateAlternativeArrayNode( nodeNameSpace.c_str(), nodeNameSpace.size(), nodeName.c_str(), nodeName.size() );
+ }
+ else if((options & kXMP_PropArrayIsOrdered) && (childOptions & kXMP_PropArrayIsOrdered)) {
+ itemNode = IArrayNode::CreateOrderedArrayNode( nodeNameSpace.c_str(), nodeNameSpace.size(), nodeName.c_str(), nodeName.size() );
+ }
+ else if((options & kXMP_PropArrayIsUnordered) && (childOptions & kXMP_PropArrayIsUnordered)) {
+ itemNode = IArrayNode::CreateUnorderedArrayNode( nodeNameSpace.c_str(), nodeNameSpace.size(), nodeName.c_str(), nodeName.size() );
+ }
+ if(!itemNode) XMP_Throw("Array has to be homogeneous", kXMPErr_BadXPath);
+
+ return itemNode;
+
+}
+
+void
+ XMPUtils::DoSetArrayItem ( const spIArrayNode &arrayNode,
+ XMP_Index itemIndex,
+ XMP_StringPtr itemValue,
+ XMP_OptionBits options )
+{
+ XMP_OptionBits itemLoc = options & kXMP_PropArrayLocationMask;
+ XMP_Index arraySize = static_cast<XMP_Index>( arrayNode->ChildCount() );
+ XMP_VarString arrayNameSpace = arrayNode->GetNameSpace()->c_str();
+ XMP_VarString arrayName = arrayNode->GetName()->c_str();
+ 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.
+
+
+
+ spINode itemNode;
+ 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 ) XMP_Throw ( "Can't insert before or after implicit new item", kXMPErr_BadIndex );
+ itemNode = CreateArrayChildNode(arrayNode, options);
+ arrayNode->InsertNodeAtIndex(itemNode, arraySize + 1);
+ }
+ else {
+
+ if ( (itemIndex < 1) || (itemIndex > arraySize) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadIndex );
+
+ if ( itemLoc == 0 ) {
+ itemNode = arrayNode->GetNodeAtIndex( itemIndex )->ConvertToSimpleNode();
+ }
+ else {
+ itemNode = CreateArrayChildNode(arrayNode, options);
+ if ( itemLoc == kXMP_InsertAfterItem ) ++itemIndex;
+ arrayNode->InsertNodeAtIndex (itemNode, itemIndex );
+ }
+
+ }
+ SetNode(itemNode, itemValue, options);
+
+} // DoSetIXMPArrayItem
+
+
+void XMPUtils::SetImplicitNodeInformation( bool & firstImplicitNodeFound,
+ spINode &implicitNodeRoot,
+ spINode &destNode,
+ XMP_Index &implicitNodeIndex,
+ XMP_Index index )
+{
+ if(!firstImplicitNodeFound) {
+ implicitNodeRoot = destNode;
+ firstImplicitNodeFound = true;
+ if( index) {
+ implicitNodeIndex = index;
+ }
+ }
+}
+void XMPUtils::GetNameSpaceAndNameFromStepValue( const std::string & stepStr,
+ const spcINameSpacePrefixMap & defaultMap,
+ std::string &stepNameSpace,
+ std::string &stepName)
+{
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr( 0, colonPos );
+ stepNameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() )->c_str();
+ stepName = stepStr.substr( colonPos + 1);
+}
+
+// =================================================================================================
+// 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.
+
+
+spINode XMPUtils::CreateTerminalNode(const char* nameSpace, const char * name, XMP_OptionBits options) {
+
+ spINode newNode;
+ if(XMP_PropIsSimple(options)) {
+
+ spISimpleNode simpleNode = ISimpleNode::CreateSimpleNode(nameSpace, AdobeXMPCommon::npos, name, AdobeXMPCommon::npos, NULL, 0 );
+ newNode = simpleNode;
+ }
+ if(XMP_PropIsStruct(options)){
+
+ spIStructureNode structNode = IStructureNode::CreateStructureNode(nameSpace, AdobeXMPCommon::npos, name, AdobeXMPCommon::npos);
+ newNode = structNode;
+ }
+ if(XMP_PropIsArray(options)) {
+
+ if ( options & kXMP_PropArrayIsAlternate )
+ newNode = IArrayNode::CreateAlternativeArrayNode( nameSpace, AdobeXMPCommon::npos, name, AdobeXMPCommon::npos );
+ else if(options & kXMP_PropArrayIsOrdered)
+ newNode = IArrayNode::CreateOrderedArrayNode( nameSpace, AdobeXMPCommon::npos, name, AdobeXMPCommon::npos );
+ else
+ newNode = IArrayNode::CreateUnorderedArrayNode( nameSpace, AdobeXMPCommon::npos, name, AdobeXMPCommon::npos );
+ }
+
+ return newNode;
+}
+
+bool XMPUtils::HandleConstAliasStep(const spIMetadata & mDOM,
+ spINode &destNode,
+ const XMP_ExpandedXPath & expandedXPath,
+ XMP_Index *nodeIndex
+ )
+{
+ destNode = mDOM;
+ if (expandedXPath.empty()) XMP_Throw("Empty XPath", kXMPErr_BadXPath);
+ if (!(expandedXPath[kRootPropStep].options & kXMP_StepIsAlias)) {
+
+ return false;
+
+ }
+ else {
+
+ XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find(expandedXPath[kRootPropStep].step);
+ XMP_Assert(aliasPos != sRegisteredAliasMap->end());
+ XMP_VarString namespaceName = aliasPos->second[kSchemaStep].step.c_str();
+ size_t colonPos = aliasPos->second[kRootPropStep].step.find(":");
+ XMP_Assert(colonPos != std::string::npos);
+ XMP_VarString propertyName = aliasPos->second[kRootPropStep].step.substr( colonPos + 1);
+ destNode = mDOM->GetNode( namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
+ if (!destNode) return false;
+ if (aliasPos->second.size() == 2) return true;
+ XMP_Assert(destNode->GetNodeType() == INode::kNTArray);
+ if (aliasPos->second[2].options == kXMP_ArrayIndexStep) {
+
+ XMP_Assert(aliasPos->second[2].step == "[1]");
+ destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
+ INode::eNodeType actualNodeType = destNode->GetNodeType();
+ if (destNode) {
+ if (nodeIndex) *nodeIndex = 1;
+ return true;
+ }
+ return false;
+ }
+ else if (aliasPos->second[2].options == kXMP_QualSelectorStep) {
+ XMP_Assert(aliasPos->second[2].step == "[?xml:lang=\"x-default\"]");
+ spcINodeIterator iter = XMPUtils::GetNodeChildIterator(destNode);
+ XMP_Index index = 1;
+ while (iter) {
+ spcINode node = iter->GetNode();
+ spcINode qualNode = node->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if (qualNode->GetNodeType() == INode::kNTSimple) {
+ if (!strcmp("x-default", qualNode->ConvertToSimpleNode()->GetValue()->c_str())){
+ destNode = AdobeXMPCore_Int::const_pointer_cast<INode>(node);
+ if (nodeIndex) *nodeIndex = index;
+ return true;
+ }
+ }
+ index++;
+ iter =iter->Next();
+ }
+ return false;
+ }
+
+ return false;
+
+ }
+}
+bool XMPUtils::HandleAliasStep(const spIMetadata & mDOM,
+ XMP_ExpandedXPath &expandedXPath,
+ bool createNodes,
+ XMP_OptionBits leafOptions /* = 0 */,
+ spINode &destNode,
+ XMP_Index *nodeIndex,
+ bool ignoreLastStep
+ )
+
+{
+ destNode = mDOM;
+ bool isAliasBeingCreated = expandedXPath.size() == 2;
+ if (expandedXPath.empty()) XMP_Throw("Empty XPath", kXMPErr_BadXPath);
+ if (!(expandedXPath[kRootPropStep].options & kXMP_StepIsAlias)) {
+
+ return false;
+
+ }
+ else {
+
+ XMP_AliasMapPos aliasPos = sRegisteredAliasMap->find(expandedXPath[kRootPropStep].step);
+ XMP_Assert(aliasPos != sRegisteredAliasMap->end());
+ XMP_VarString namespaceName = aliasPos->second[kSchemaStep].step.c_str();
+ size_t colonPos = aliasPos->second[kRootPropStep].step.find(":");
+ XMP_Assert(colonPos != std::string::npos);
+ XMP_VarString propertyName = aliasPos->second[kRootPropStep].step.substr(colonPos + 1);
+ destNode = mDOM->GetNode(namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
+ if (!destNode && !createNodes) return false;
+ if (aliasPos->second.size() == 2) {
+ if (destNode) return true;
+ XMP_OptionBits createOptions = 0;
+ destNode = mDOM;
+ if (isAliasBeingCreated) createOptions = leafOptions;
+ spINode tempNode = CreateTerminalNode(namespaceName.c_str(), propertyName.c_str(), createOptions);
+ if (!tempNode) return false;
+ destNode->ConvertToStructureNode()->AppendNode( tempNode );
+ destNode = tempNode;
+ if (destNode) return true;
+ return false;
+ }
+
+
+ //XMP_Assert(destNode->GetNodeType() == INode::kNTArray);
+ XMP_Assert(aliasPos->second.size() == 3);
+ if (aliasPos->second[2].options == kXMP_ArrayIndexStep) {
+ XMP_Assert(aliasPos->second[2].step == "[1]");
+ destNode = mDOM->GetNode(namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
+ if (!destNode && !createNodes) return false;
+ if (!destNode) {
+ spINode arrayNode = CreateTerminalNode(namespaceName.c_str(), propertyName.c_str(), kXMP_PropArrayIsOrdered | kXMP_PropValueIsArray);
+ mDOM->AppendNode(arrayNode);
+ destNode = arrayNode;
+ }
+
+ if ( destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 ) ) {
+ destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
+ if (nodeIndex) *nodeIndex = 1;
+ return true;
+ }
+ else {
+ spISimpleNode indexNode = ISimpleNode::CreateSimpleNode( namespaceName.c_str(), namespaceName.size(), "[]", AdobeXMPCommon::npos, "", AdobeXMPCommon::npos );
+ destNode->ConvertToArrayNode()->InsertNodeAtIndex( indexNode, 1 );
+ destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
+ return true;
+ }
+ return false;
+ }
+ else if (aliasPos->second[2].options == kXMP_QualSelectorStep) {
+ XMP_Assert(aliasPos->second[2].step == "[?xml:lang=\"x-default\"]");
+ destNode = mDOM->GetNode(namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
+ if (!destNode && !createNodes) return false;
+ spINode arrayNode = CreateTerminalNode(namespaceName.c_str(), propertyName.c_str(), kXMP_PropArrayIsAltText | kXMP_PropValueIsArray);
+ mDOM->AppendNode(arrayNode);
+ destNode = arrayNode;
+ spcINodeIterator iter = XMPUtils::GetNodeChildIterator(destNode);
+ XMP_Index index = 1;
+ while (iter) {
+ spcINode node = iter->GetNode();
+ spcINode qualNode = node->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if (qualNode->GetNodeType() == INode::kNTSimple) {
+ if (!strcmp("x-default", qualNode->ConvertToSimpleNode()->GetValue()->c_str())){
+ destNode = AdobeXMPCore_Int::const_pointer_cast<INode>(node);
+ if (nodeIndex) *nodeIndex = index;
+ return true;
+ }
+ }
+ index++;
+ iter = iter->Next();
+ }
+ spISimpleNode qualifierNode = ISimpleNode::CreateSimpleNode(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos, "x-default" );
+ if ( destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 ) ) {
+ destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
+ if (nodeIndex) *nodeIndex = 1;
+ destNode->InsertQualifier(qualifierNode);
+
+ return true;
+ }
+ else {
+ spISimpleNode indexNode = ISimpleNode::CreateSimpleNode(namespaceName.c_str(), namespaceName.size(), "[]", AdobeXMPCommon::npos );
+ destNode->ConvertToArrayNode()->InsertNodeAtIndex( indexNode, 1 );
+ destNode->InsertQualifier(qualifierNode);
+ destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
+ return true;
+ }
+
+ }
+
+
+
+ }
+ return false;
+}
+bool XMPUtils:: FindNode ( const spIMetadata & mDOM,
+ XMP_ExpandedXPath & expPath,
+ bool createNodes,
+ XMP_OptionBits leafOptions /* = 0 */,
+ spINode &retNode,
+ XMP_Index *nodeIndex ,
+ bool ignoreLastStep
+ )
+{
+
+ // TO DO - Differentiate between failures on last step and steps before that
+ spINode destNode = mDOM;
+ spINode parentDestNode = mDOM;
+ bool firstImplicitNodeFound = false;
+ bool leafIsNew = false;
+ spINode implicitNodeRoot;
+ bool qualifierFlag = false;
+ XMP_Index implicitNodeIndex ; // used in case first implicit node's parent is an array
+ XMP_Assert ( (leafOptions == 0) || createNodes );
+
+ if ( expPath.empty() ) XMP_Throw ( "Empty XPath", kXMPErr_BadXPath );
+
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+ size_t pathStartIdx = 1;
+ if (expPath[kRootPropStep].options & kXMP_StepIsAlias) {
+
+ if (!HandleAliasStep(mDOM, expPath, createNodes, leafOptions, destNode,0, 0 )) return false;
+ pathStartIdx = 2;
+
+ }
+ try{
+ for (size_t i = pathStartIdx, endIndex = (ignoreLastStep) ? expPath.size() - 1 : expPath.size(); i < endIndex; i++) {
+ // split the path into prefix and property name
+ if (!destNode) goto EXIT;
+ XMP_VarString stepStr = expPath[i].step;
+ XMP_VarString prevStep = (i == 0) ? "" : expPath[i - 1].step;
+ spcIUTF8String nameSpace;
+ XMP_VarString stepName;
+
+ switch (expPath[i].options) {
+ case kXMP_StructFieldStep:
+ {
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr(0, colonPos);
+ // get the namespace from the prefix
+ nameSpace = defaultMap->GetNameSpace(prefix.c_str(), prefix.size());
+ stepName = stepStr.substr(colonPos + 1);
+ if (destNode->GetNodeType() == INode::kNTStructure) {
+ spIStructureNode tempNode = destNode->ConvertToStructureNode();
+ parentDestNode = destNode;
+ destNode = tempNode->GetNode(nameSpace->c_str(), nameSpace->size(), stepStr.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if (destNode) continue;
+ if (!createNodes) return false;
+ if (i == (expPath.size() - 1)) {
+
+ spINode simpleInsertNode = CreateTerminalNode(nameSpace->c_str(), stepName.c_str(), leafOptions);
+ tempNode->InsertNode(simpleInsertNode);
+ destNode = simpleInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex);
+
+ }
+ else {
+
+ switch (expPath[i + 1].options) {
+
+ case kXMP_StructFieldStep:
+ {
+ // TODO : Exit and handle deletetion of implicit node
+ // TODO : structInsertNode :
+ spIStructureNode structInsertNode = IStructureNode::CreateStructureNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ spIStructureNode parentStructNode = parentDestNode->ConvertToStructureNode();
+ parentStructNode->InsertNode(structInsertNode);
+ destNode = structInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex);
+
+ }
+ break;
+ case kXMP_FieldSelectorStep:
+ case kXMP_QualSelectorStep:
+ case kXMP_ArrayLastStep:
+ case kXMP_ArrayIndexStep:
+ {
+ // from where will you get arrayform ? which arrayform to set by default?
+ spIArrayNode arrayInsertNode = IArrayNode::CreateOrderedArrayNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ spIStructureNode parentStructNode = parentDestNode->ConvertToStructureNode();
+ parentStructNode->InsertNode(arrayInsertNode);
+ destNode = arrayInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex);
+
+ }
+ break;
+ case kXMP_QualifierStep:
+ {
+ spISimpleNode simpleInsertNode = ISimpleNode::CreateSimpleNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ spIStructureNode parentStructNode = parentDestNode->ConvertToStructureNode();
+ parentStructNode->InsertNode(simpleInsertNode);
+ destNode = simpleInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex);
+
+
+ }
+ default:
+ break;
+ }
+
+ }
+ }
+ else {
+ goto EXIT;
+ }
+ }
+ break;
+ case kXMP_ArrayIndexStep:
+ {
+ // TO DO : type array item
+ // if array not empty -> see type of first array element
+ // else if next is array type , arrayitem is array
+ // if next is struct select type, array item is struct
+ // if next is type qualifier , array item is simple property
+ // TODO : HANDLE EXIT CASE
+ //
+ // we should check if the previous segment is an array segment
+ if (destNode->GetNodeType() != INode::kNTArray) {
+ XMP_Throw("Indexing applied to non-array", kXMPErr_BadXPath);
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+ size_t index = 0;
+ XMP_Assert((stepStr.length() >= 2) && (*(stepStr.begin()) == '[') && (stepStr[stepStr.length() - 1] == ']'));
+ for (size_t chNum = 1, chEnd = stepStr.length() - 1; chNum != chEnd; ++chNum) {
+ XMP_Assert(('0' <= stepStr[chNum]) && (stepStr[chNum] <= '9'));
+ index = (index * 10) + (stepStr[chNum] - '0');
+ }
+ if (index < 1) XMP_Throw("Array index must be larger than one", kXMPErr_BadXPath);
+ if (nodeIndex) *nodeIndex = static_cast<XMP_Index>(index);
+ size_t colonPos = prevStep.find(':');
+ XMP_VarString prefix = prevStep.substr(0, colonPos);
+ nameSpace = defaultMap->GetNameSpace(prefix.c_str(), prefix.size() );
+ stepName = kXMP_ArrayItemName;
+ parentDestNode = destNode;
+ destNode = tempNode->GetNodeAtIndex(index);
+
+ if (destNode) continue;
+ if (!createNodes) return false;
+ spIArrayNode parentArrayNode = parentDestNode->ConvertToArrayNode();
+ if (parentArrayNode->ChildCount() + 1 < index) goto EXIT;
+ if (i == expPath.size() - 1) {
+ // to do if array not empty create of type already existing type
+ /// else create simple node
+ spINode simpleInsertNode = CreateTerminalNode((nameSpace) ? nameSpace->c_str() : kXMP_NS_XMP, stepName.c_str(), leafOptions);
+ parentArrayNode->InsertNodeAtIndex(simpleInsertNode, index);
+ destNode = simpleInsertNode;
+ if (!firstImplicitNodeFound) {
+ firstImplicitNodeFound = true;
+ implicitNodeRoot = destNode;
+ implicitNodeIndex = static_cast<XMP_Index>(index);
+ }
+ }
+ else {
+
+ switch (expPath[i + 1].options) {
+
+ case kXMP_StructFieldStep:
+ {
+ // TODO : Exit and handle deletetion of implicit node
+
+ spIStructureNode structInsertNode = IStructureNode::CreateStructureNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+
+ parentArrayNode->InsertNodeAtIndex(structInsertNode, index);
+ destNode = structInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)index);
+ }
+ break;
+ case kXMP_FieldSelectorStep:
+ case kXMP_QualSelectorStep:
+ case kXMP_ArrayLastStep:
+ case kXMP_ArrayIndexStep:
+ {
+ spIArrayNode arrayInsertNode = IArrayNode::CreateOrderedArrayNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size());
+ parentArrayNode->InsertNodeAtIndex(arrayInsertNode, index);
+ destNode = arrayInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)index);
+ }
+ break;
+ case kXMP_QualifierStep:
+ {
+ spISimpleNode simpleInsertNode = ISimpleNode::CreateSimpleNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ parentArrayNode->InsertNodeAtIndex(simpleInsertNode, index);
+ destNode = simpleInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)index);
+
+ }
+ default:
+ break;
+ }
+
+ }
+
+ }
+ break;
+
+ case kXMP_ArrayLastStep:
+ {
+ // what is the interpretation of last when array is empty ? creating an array item for index 1 if creatNodes is true
+ // rest of the things are same as above case
+ // old implementation has an assertion failing for this case
+ if (destNode->GetNodeType() != INode::kNTArray) {
+ XMP_Throw("Indexing applied to non-array", kXMPErr_BadXPath);
+
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+
+ size_t colonPos = prevStep.find(':');
+ XMP_VarString prefix = prevStep.substr(0, colonPos);
+ nameSpace = defaultMap->GetNameSpace(prefix.c_str(), prefix.size());
+ stepName = prevStep.substr(colonPos + 1);
+ spINode parentNode = destNode;
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ if (parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+ size_t childCount = parentNode->ConvertToArrayNode()->ChildCount();
+ if (nodeIndex) *nodeIndex = (XMP_Index)childCount + 1;
+ if (childCount) {
+ destNode = parentArrayNode->GetNodeAtIndex(childCount);
+ continue;
+ }
+ if (!createNodes) return false;
+ if (i == expPath.size() - 1) {
+
+ spINode simpleInsertNode = CreateTerminalNode(nameSpace->c_str(), stepName.c_str(), leafOptions);
+ parentArrayNode->InsertNodeAtIndex(simpleInsertNode, 1);
+ destNode = simpleInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)childCount + 1);
+ continue;
+ }
+ switch (expPath[i + 1].options) {
+
+ case kXMP_QualifierStep:
+ {
+ spISimpleNode simpleInsertNode = ISimpleNode::CreateSimpleNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size());
+ parentArrayNode->InsertNodeAtIndex(simpleInsertNode, 1);
+ destNode = simpleInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)childCount + 1);
+ continue;
+ }
+ break;
+ case kXMP_ArrayIndexStep:
+ case kXMP_ArrayLastStep:
+ case kXMP_FieldSelectorStep:
+ case kXMP_QualSelectorStep:
+ {
+ spIArrayNode arrayInsertNode = IArrayNode::CreateOrderedArrayNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ parentArrayNode->InsertNodeAtIndex(arrayInsertNode, childCount + 1);
+ destNode = arrayInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)childCount + 1);
+ }
+ break;
+ case kXMP_StructFieldStep:
+ {
+ spIStructureNode structInsertNode = IStructureNode::CreateStructureNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ parentArrayNode->InsertNodeAtIndex(structInsertNode, childCount + 1);
+ destNode = structInsertNode;
+ SetImplicitNodeInformation(firstImplicitNodeFound, implicitNodeRoot, destNode, implicitNodeIndex, (XMP_Index)childCount + 1);
+
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+ }
+
+ }
+ break;
+ case kXMP_QualifierStep:
+ {
+ // if qualifier exists for the parent node, continue
+ // else create qualifier if createnodes is true
+ XMP_Assert(stepStr[0] == '?');
+ stepStr = stepStr.substr(1);
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr(0, colonPos);
+ nameSpace = defaultMap->GetNameSpace(prefix.c_str(),prefix.size());
+ stepName = stepStr.substr(colonPos + 1);
+ qualifierFlag = true;
+ parentDestNode = destNode;
+ destNode = destNode->GetQualifier(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ if (destNode) continue;
+ if (!createNodes) return false;
+ spISimpleNode qualifierNode = ISimpleNode::CreateSimpleNode(nameSpace->c_str(), nameSpace->size(), stepName.c_str(), stepName.size() );
+ parentDestNode->InsertQualifier(qualifierNode);
+ destNode = qualifierNode;
+ }
+
+ break;
+
+ case kXMP_QualSelectorStep:
+ {
+ // TODO - check the old behavior - checked - no implicit nodes except in one case
+ // TODO it is perhaps not required, can be done later
+ // if next path step is array(index/lastinddex/qualselect/fieldselect) - this will be an arraynode
+ // if next path step is a struct, this will be an structnode
+ // if next path step is a qualifier , this will be a simple property
+
+ if (destNode->GetNodeType() != INode::kNTArray) {
+ goto EXIT;
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+ XMP_VarString qualName, qualValue, qualNameSpace;
+ SplitNameAndValue(stepStr, &qualName, &qualValue);
+ spINode parentNode = destNode;
+ size_t colonPos = qualName.find(':');
+ XMP_VarString prefix = qualName.substr(0, colonPos);
+ qualNameSpace = defaultMap->GetNameSpace(prefix.c_str(), prefix.size())->c_str();
+ bool indexFound = false;
+ if (parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ size_t arrayChildCount = parentArrayNode->ChildCount();
+ for (size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+
+ spINode currentArrayItem = parentArrayNode->GetNodeAtIndex(arrayIdx);
+ spINode qualNode = currentArrayItem->GetQualifier(qualNameSpace.c_str(), qualNameSpace.size(), qualName.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if (!qualNode) continue;
+ XMP_VarString currentQualValue = qualNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if (currentQualValue == qualValue) {
+ indexFound = true;
+ destNode = parentArrayNode->GetNodeAtIndex(arrayIdx);
+ break;
+ }
+ }
+
+ }
+ if (!indexFound) {
+ goto EXIT;
+ }
+ }
+ break;
+
+ case kXMP_FieldSelectorStep:
+ {
+ // what if multiple indices match search criterion ?
+ // what if parent node isn't an array- exception or return false ?
+ // same issue what if one or more child nodes aren't structures ?
+ XMP_VarString fieldName, fieldValue, fieldNameSpace;
+ SplitNameAndValue(stepStr, &fieldName, &fieldValue);
+ spINode parentNode = destNode;
+ size_t colonPos = fieldName.find(':');
+ XMP_VarString prefix = fieldName.substr(0, colonPos);
+ fieldNameSpace = defaultMap->GetNameSpace(prefix.c_str(), prefix.size())->c_str();
+ bool indexFound = false;
+ if (parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ size_t arrayChildCount = parentArrayNode->ChildCount();
+ for (size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+
+ spINode currentItem = parentArrayNode->GetNodeAtIndex(arrayIdx);
+
+ if (currentItem->GetNodeType() != INode::kNTStructure) {
+ goto EXIT;
+ }
+
+ spINode fieldNode = currentItem->ConvertToStructureNode()->GetNode(fieldNameSpace.c_str(), fieldNameSpace.size(), fieldName.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if (!fieldNode || fieldNode->GetNodeType() != INode::kNTSimple) continue;
+ XMP_VarString currentFieldValue = fieldNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if (currentFieldValue == fieldValue) {
+ indexFound = true;
+ destNode = parentArrayNode->GetNodeAtIndex(arrayIdx);
+ break;
+ }
+ }
+ }
+ if (!indexFound) {
+ goto EXIT;
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+
+ }
+ }
+ catch (...) {
+ if (firstImplicitNodeFound) {
+
+ spINode parentImplicitNode = implicitNodeRoot->GetParent();
+ if (parentImplicitNode->GetNodeType() == INode::kNTArray) {
+ parentImplicitNode->ConvertToArrayNode()->RemoveNodeAtIndex( implicitNodeIndex );
+ }
+ else if (parentImplicitNode->GetNodeType() == INode::kNTStructure) {
+ parentImplicitNode->ConvertToStructureNode()->RemoveNode(implicitNodeRoot->GetNameSpace()->c_str(), implicitNodeRoot->GetNameSpace()->size(), implicitNodeRoot->GetName()->c_str(), implicitNodeRoot->GetName()->size() );
+ }
+ }
+ throw;
+ }
+
+retNode = destNode;
+return true;
+
+EXIT:
+{
+ //XMP_Assert ( !destNode || (currNode == *currPos) );
+ //XMP_Assert ( (destNode!= 0) || (! createNodes) );
+ if(!destNode) {
+
+ if( firstImplicitNodeFound ) {
+
+ spINode parentImplicitNode = implicitNodeRoot->GetParent();
+ if(parentImplicitNode->GetNodeType() == INode::kNTArray) {
+ parentImplicitNode->ConvertToArrayNode()->RemoveNodeAtIndex( implicitNodeIndex );
+ }
+ else if(parentImplicitNode->GetNodeType()== INode::kNTStructure) {
+ parentImplicitNode->ConvertToStructureNode()->RemoveNode( implicitNodeRoot->GetNameSpace()->c_str(), implicitNodeRoot->GetNameSpace()->size(), implicitNodeRoot->GetName()->c_str(), implicitNodeRoot->GetName()->size() );
+ }
+ }
+ } return false;
+}
+return false;
+} // FindNode
+
+bool XMPUtils::FindCnstNode ( const spIMetadata & mDOM,XMP_ExpandedXPath &expPath , spINode &destNode, XMP_OptionBits *options , XMP_Index * arrayIndex )
+{
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+ destNode = mDOM;
+ bool qualifierFlag = false;
+ size_t pathStartIdx = 1;
+ if (expPath[kRootPropStep].options & kXMP_StepIsAlias) {
+
+ if (!HandleConstAliasStep(mDOM, destNode, expPath, 0)) return false;
+ pathStartIdx = 2;
+
+ }
+ for ( size_t i = pathStartIdx, endIndex = expPath.size(); i < endIndex; i++ ) {
+ // split the path into prefix and property name
+ if(!destNode) return false;
+ XMP_VarString stepStr = expPath[i].step;
+ XMP_VarString prevStep = (i == 0)? "" : expPath[i - 1].step;
+ spcIUTF8String nameSpace ;
+
+ switch( expPath[i].options ) {
+ case kXMP_StructFieldStep:
+ {
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr( 0, colonPos );
+ // get the namespace from the prefix
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ if(destNode->GetNodeType() == INode::kNTStructure) {
+ spIStructureNode tempNode = destNode->ConvertToStructureNode();
+ destNode = tempNode->GetNode(nameSpace->c_str(), nameSpace->size(), stepStr.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ }
+ else {
+ XMP_Throw ( "Named children only allowed for schemas and structs", kXMPErr_BadXPath );
+ }
+ }
+ break;
+ case kXMP_ArrayIndexStep:
+ {
+ // should we check if previous segment is an array segment
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ XMP_Throw ( "Indexes allowed for arrays only", kXMPErr_BadXPath );
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+ XMP_Index index = 0;
+ XMP_Assert ( (stepStr.length() >= 2) && (*( stepStr.begin()) == '[') && (stepStr[stepStr.length()-1] == ']') );
+ for ( size_t chNum = 1,chEnd = stepStr.length() -1 ; chNum != chEnd; ++chNum ) {
+ XMP_Assert ( ('0' <= stepStr[chNum]) && (stepStr[chNum] <= '9') );
+ index = (index * 10) + (stepStr[chNum] - '0');
+ }
+ if ( index < 1) XMP_Throw ( "Array index must be larger than one", kXMPErr_BadXPath );
+ size_t colonPos = prevStep.find(':');
+ XMP_VarString prefix = prevStep.substr( 0, colonPos );
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ destNode = tempNode->GetNodeAtIndex( index);
+ if(arrayIndex) *arrayIndex = index;
+ }
+ break;
+ case kXMP_ArrayLastStep:
+ {
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ XMP_Throw ( "Indexes allowed for arrays only", kXMPErr_BadXPath );
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+
+ size_t colonPos = prevStep.find(':');
+ XMP_VarString prefix = prevStep.substr( 0, colonPos );
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ spINode parentNode = destNode;
+ if(parentNode && parentNode->GetNodeType()== INode::kNTArray) {
+ size_t childCount = parentNode->ConvertToArrayNode()->ChildCount();
+ if(!childCount) {
+ XMP_Throw ( "Array index overflow", kXMPErr_BadXPath );
+ }
+ destNode = tempNode->GetNodeAtIndex(childCount);
+ if(arrayIndex) *arrayIndex = (XMP_Index)childCount;
+ }
+
+ }
+ break;
+ case kXMP_QualifierStep:
+ {
+
+ XMP_Assert(stepStr[0]=='?');
+ stepStr = stepStr.substr(1);
+ size_t colonPos = stepStr.find(':');
+ XMP_VarString prefix = stepStr.substr( 0, colonPos);
+ nameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() );
+ qualifierFlag = true;
+ destNode = destNode->GetQualifier(nameSpace->c_str(), nameSpace->size(), stepStr.c_str() + colonPos + 1, AdobeXMPCommon::npos);
+
+ // spINode node = mDOM->GetNode( path);
+ }
+
+ break;
+
+ case kXMP_QualSelectorStep:
+ {
+ // what if multiple indices match search criterion ?
+ if(destNode->GetNodeType() != INode::kNTArray) {
+ XMP_Throw ( "Indexes allowed for arrays only", kXMPErr_BadXPath );
+ }
+ spIArrayNode tempNode = destNode->ConvertToArrayNode();
+ XMP_VarString qualName, qualValue, qualNameSpace;
+ SplitNameAndValue (stepStr, &qualName, &qualValue );
+ spINode parentNode = destNode;
+ size_t colonPos = qualName.find(':');
+ XMP_VarString prefix = qualName.substr( 0, colonPos);
+ qualNameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() )->c_str();
+ bool indexFound = false;
+ if(parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ size_t arrayChildCount = parentArrayNode->ChildCount();
+ for(size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+
+ spINode currentArrayItem = parentArrayNode->GetNodeAtIndex(arrayIdx);
+ spINode qualNode = currentArrayItem->GetQualifier(qualNameSpace.c_str(), qualNameSpace.size(), qualName.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if(!qualNode) continue;
+ XMP_VarString currentQualValue = qualNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if( currentQualValue == qualValue) {
+ indexFound = true;
+ if(arrayIndex) *arrayIndex = (XMP_Index)arrayIdx;
+ destNode = parentArrayNode->GetNodeAtIndex( arrayIdx);
+ break;
+ }
+ }
+
+ }
+ if(!indexFound) {
+ return false;
+ }
+ }
+ break;
+
+ case kXMP_FieldSelectorStep :
+ {
+ // what if multiple indices match search criterion ?
+ // what if parent node isn't an array- exception or return false ?
+ // same issue what if one or more child nodes aren't structures ?
+ XMP_VarString fieldName, fieldValue, fieldNameSpace;
+ SplitNameAndValue (stepStr, &fieldName, &fieldValue );
+ spINode parentNode = destNode;
+ size_t colonPos = fieldName.find(':');
+ XMP_VarString prefix = fieldName.substr( 0, colonPos);
+ fieldNameSpace = defaultMap->GetNameSpace( prefix.c_str(), prefix.size() )->c_str();
+ bool indexFound = false;
+ if(parentNode && parentNode->GetNodeType() == INode::kNTArray) {
+
+ spIArrayNode parentArrayNode = parentNode->ConvertToArrayNode();
+ size_t arrayChildCount = parentArrayNode->ChildCount();
+ for(size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+
+ spINode currentItem = parentArrayNode->GetNodeAtIndex(arrayIdx);
+
+ if(currentItem->GetNodeType() != INode::kNTStructure) {
+ return false;
+ }
+
+ spINode fieldNode = currentItem->ConvertToStructureNode()->GetNode(fieldNameSpace.c_str(), fieldNameSpace.size(), fieldName.c_str() + colonPos + 1, AdobeXMPCommon::npos );
+ if(!fieldNode || fieldNode->GetNodeType() != INode::kNTSimple) continue;
+ XMP_VarString currentFieldValue = fieldNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if( currentFieldValue == fieldValue) {
+ indexFound = true;
+ if(arrayIndex) *arrayIndex = (XMP_Index)arrayIdx;
+ destNode = parentArrayNode->GetNodeAtIndex( arrayIdx);
+ break;
+ }
+ }
+ }
+ if(!indexFound) {
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+
+ }
+ if(!destNode) return false;
+ if(!options) return true;
+ *options = GetIXMPOptions(destNode);
+ return true;
+}
+
+size_t XMPUtils:: GetNodeChildCount(const spcINode & node){
+ size_t childCount = 0;
+ if( node->GetNodeType() == INode::kNTArray) {
+ childCount = node->ConvertToArrayNode()->ChildCount();
+ }
+ else if (node->GetNodeType() == INode::kNTStructure) {
+ childCount = node->ConvertToStructureNode()->ChildCount();
+ }
+ return childCount;
+
+}
+
+spcINodeIterator XMPUtils::GetNodeChildIterator(const spcINode & node){
+ spcINodeIterator childIter;
+ if( node->GetNodeType() == INode::kNTArray) {
+ childIter = node->ConvertToArrayNode()->Iterator();
+ }
+ else if (node->GetNodeType() == INode::kNTStructure) {
+ childIter = node->ConvertToStructureNode()->Iterator();
+ }
+ return childIter;
+
+}
+
+std::vector<spcINode> XMPUtils:: GetChildVector( const spINode & node) {
+
+ std::vector<spcINode> childNodes;
+ spcINodeIterator childIter = GetNodeChildIterator(node);
+ for(; childIter; childIter = childIter->Next()) {
+ childNodes.push_back(childIter->GetNode());
+ }
+ return childNodes;
+}
+XMP_OptionBits XMPUtils:: GetIXMPOptions( const spcINode & node) {
+
+ XMP_OptionBits options = 0;
+ if(!node) return options;
+ if ( node->HasQualifiers()) {
+ options |= kXMP_PropHasQualifiers;
+ // ( destNode->GetQualifier( "
+ if( node->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos )) {
+ options |= kXMP_PropHasLang;
+ }
+
+ if( node->GetQualifier("http://www.w3.org/1999/02/22-rdf-syntax-ns#", AdobeXMPCommon::npos, "type", AdobeXMPCommon::npos )) {
+ options |= kXMP_PropHasType;
+ }
+ }
+ XMP_VarString snamespace = node->GetNameSpace()->c_str();
+ XMP_VarString sname = node->GetName()->c_str();
+ spcINode parentNode = node->GetParent();
+
+ if (node->IsQualifierNode()){
+ options |= kXMP_PropIsQualifier;
+ }
+
+ if ( node->GetNodeType() == INode::kNTSimple ) {
+
+ if( node->ConvertToSimpleNode()->IsURIType()){
+ options |= kXMP_PropValueIsURI;
+ }
+
+ }
+ else if ( node->GetNodeType() == INode::kNTArray) {
+
+ spcIArrayNode arrayNode = node->ConvertToArrayNode();
+ options |= kXMP_PropValueIsArray;
+
+ switch(arrayNode->GetArrayForm()) {
+
+ case IArrayNode::kAFAlternative:
+ options |= kXMP_PropArrayIsAlternate;options|= kXMP_PropArrayIsOrdered;
+ break;
+
+ case IArrayNode::kAFOrdered:
+ options |= kXMP_PropArrayIsOrdered;
+ break;
+
+ case IArrayNode::kAFUnordered:
+ options |= kXMP_PropArrayIsUnordered;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ bool isAltTextArray = (arrayNode->GetArrayForm() == IArrayNode::kAFAlternative );
+
+ for( size_t arrayIndex = 1; arrayIndex <= arrayNode->ChildCount(); arrayIndex++) {
+ spcINode childNode = arrayNode->GetNodeAtIndex(arrayIndex);
+ if((childNode->GetNodeType() != INode::kNTSimple || !childNode->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos ))) {
+ isAltTextArray = false;
+ break;
+ }
+ }
+ if(isAltTextArray) {
+ options |= kXMP_PropArrayIsAltText;
+ }
+
+ }
+ else if( node->GetNodeType() == INode::kNTStructure && node->GetParent() ) {
+ options |= kXMP_PropValueIsStruct;
+ }
+ return options;
+}
+
+spINode
+XMPUtils::FindChildNode ( const spINode &parent,
+ XMP_StringPtr childName,
+ XMP_StringPtr childNameSpace,
+ bool createNodes,
+ size_t * pos /* = 0 */ )
+{
+ // need to pass childnamespace too
+ spINode childNode;
+ XMP_OptionBits parentOptions = XMPUtils::GetIXMPOptions(parent);
+ if ( ! (parentOptions & (kXMP_SchemaNode | kXMP_PropValueIsStruct)) ) {
+
+ if ( parentOptions & kXMP_PropValueIsArray ) {
+ XMP_Throw ( "Named children not allowed for arrays", kXMPErr_BadXPath );
+ }
+ }
+ spcINodeIterator childIter = XMPUtils::GetNodeChildIterator(parent);
+
+ for (size_t idx = 1 ; childIter; childIter = childIter->Next(), ++idx ) {
+ spcINode currChild = childIter->GetNode();
+
+ if (currChild && XMP_LitMatch(currChild->GetName()->c_str(), childName) && XMP_LitMatch(currChild->GetNameSpace()->c_str(), childNameSpace) ) {
+ childNode = AdobeXMPCore_Int::const_pointer_cast<INode>(currChild);
+ if(pos) *pos = idx;
+ break;
+ }
+ }
+
+ if ( (!childNode) && createNodes ) {
+ childNode = ISimpleNode::CreateSimpleNode(childNameSpace, AdobeXMPCommon::npos, childName, AdobeXMPCommon::npos );
+ parent->ConvertToStructureNode()->InsertNode( childNode );
+ }
+
+ XMP_Assert ( (childNode ) || (! createNodes) );
+ return childNode;
+
+} // FindChildNode
+
+spcIUTF8String XMPUtils::GetNodeValue( const spINode & node) {
+
+
+ if (node && node->GetNodeType() == INode::kNTSimple) {
+ return node->ConvertToSimpleNode()->GetValue();
+ }
+ return spIUTF8String();
+}
+
+
+XMP_Index XMPUtils::LookupFieldSelector_v2(const spIArrayNode & arrayNode, XMP_VarString fieldName, XMP_VarString fieldValue) {
+
+ XMP_Index destIdx = -1;
+ if (arrayNode->GetNodeType() != INode::kNTArray) return destIdx;
+ for (size_t index = 1, indexLim = arrayNode->ChildCount(); index <= indexLim; ++index) {
+
+ spINode childNode = arrayNode->GetNodeAtIndex(index);
+ if (childNode->GetNodeType() != INode::kNTStructure) {
+ XMP_Throw("Field selector must be used on array of struct", kXMPErr_BadXPath);
+ }
+ for (spcINodeIterator childNodeIter = XMPUtils::GetNodeChildIterator(childNode); childNodeIter; childNodeIter = childNodeIter->Next()) {
+ spcINode currentField = childNodeIter->GetNode();
+ if (!XMP_LitMatch(currentField->GetName()->c_str(), fieldName.c_str())) continue;
+ if (currentField->GetNodeType() != INode::kNTSimple) continue;
+ XMP_VarString currentFieldValue = currentField->ConvertToSimpleNode()->GetValue()->c_str();
+ if (currentFieldValue == fieldValue) {
+ return index;
+ }
+ }
+ }
+ return destIdx;
+}
+
+#endif
+
+// -------------------------------------------------------------------------------------------------
+// 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;
+
+}
+
+
+#if ENABLE_CPP_DOM_MODEL
+// -------------------------------------------------------------------------------------------------
+// EstimateSizeForJPEG
+// -------------------
+//
+// Estimate the serialized size for the subtree of an XMP_Node. Support for PackageForJPEG.
+
+static size_t
+EstimateSizeForJPEG(const spINode &xmpNode)
+{
+
+ size_t estSize = 0;
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();
+
+ size_t nameSize = xmpNode->GetName()->size() + 1 ;
+ nameSize += defaultMap->GetPrefix(xmpNode->GetNameSpace()->c_str(), xmpNode->GetNameSpace()->size())->size();
+
+ XMP_OptionBits xmpNodeOptions = XMPUtils::GetIXMPOptions(xmpNode);
+ bool includeName = (xmpNode->GetParent()->GetNodeType() != INode::kNTArray);
+
+ if (XMP_PropIsSimple(xmpNodeOptions)) {
+
+ if (includeName) estSize += (nameSize + 3); // Assume attribute form.
+ estSize += xmpNode->ConvertToSimpleNode()->GetValue()->size();
+ }
+ else if (XMP_PropIsArray(xmpNodeOptions)) {
+
+ // The form of the value portion is: <rdf:Xyz><rdf:li>...</rdf:li>...</rdf:Xyx>
+ if (includeName) estSize += (2 * nameSize + 5);
+ spIArrayNode structNode = xmpNode->ConvertToArrayNode();
+ size_t arraySize = structNode->ChildCount();
+ estSize += 9 + 10; // The rdf:Xyz tags.
+ estSize += arraySize * (8 + 9); // The rdf:li tags.
+
+ for (auto structIter = structNode->Iterator(); structIter; structIter = structIter->Next()) {
+
+ estSize += EstimateSizeForJPEG(structIter->GetNode());
+ }
+
+ }
+ else {
+
+ // The form is: <headTag rdf:parseType="Resource">...fields...</tailTag>
+ if (includeName) estSize += (2 * nameSize + 5);
+ spIStructureNode structNode = xmpNode->ConvertToStructureNode();
+ estSize += 25; // The rdf:parseType="Resource" attribute.
+ size_t fieldCount = structNode->ChildCount();
+
+ for (auto structIter = structNode->Iterator(); structIter; structIter = structIter->Next()) {
+
+ estSize += EstimateSizeForJPEG(structIter->GetNode());
+ }
+
+
+ }
+
+ return estSize;
+
+}
+#endif
+
+// -------------------------------------------------------------------------------------------------
+// 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
+
+
+
+// -------------------------------------------------------------------------------------------------
+// MoveOneProperty
+// ---------------
+#if ENABLE_CPP_DOM_MODEL
+static bool MoveOneProperty(XMPMeta2 & stdXMP, XMPMeta2 * extXMP,
+ XMP_StringPtr schemaURI, XMP_StringPtr propName)
+{
+
+ spINode rootNode = stdXMP.mDOM;
+ if (!rootNode) return false;
+ spINode propNode = rootNode->ConvertToStructureNode()->GetNode(schemaURI, AdobeXMPCommon::npos, propName, AdobeXMPCommon::npos);
+ if (!propNode) return false;
+
+ spINode clonedNode = propNode->Clone();
+
+ spIStructureNode rootNode2 = extXMP->mDOM;
+
+ if (rootNode2->GetNode(schemaURI, AdobeXMPCommon::npos, propName, AdobeXMPCommon::npos )) {
+ rootNode2->RemoveNode(schemaURI, AdobeXMPCommon::npos, propName, AdobeXMPCommon::npos);
+ }
+ rootNode2->AppendNode(clonedNode);
+ rootNode->ConvertToStructureNode()->RemoveNode( schemaURI, AdobeXMPCommon::npos, propName, AdobeXMPCommon::npos );
+ return true;
+} // MoveOneProperty
+#endif
+
+// -------------------------------------------------------------------------------------------------
+// CreateEstimatedSizeMap
+// ----------------------
+
+#ifndef Trace_PackageForJPEG
+ #define Trace_PackageForJPEG 0
+#endif
+
+typedef std::pair < XMP_VarString*, XMP_VarString* > StringPtrPair;
+typedef std::pair < const char *, const char * > StringPtrPair2;
+typedef std::multimap < size_t, StringPtrPair > PropSizeMap;
+typedef std::multimap < size_t, StringPtrPair2 > PropSizeMap2;
+
+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
+
+#if ENABLE_CPP_DOM_MODEL
+static void CreateEstimatedSizeMap(XMPMeta2 & stdXMP, PropSizeMap2 * propSizes)
+{
+#if Trace_PackageForJPEG
+ printf(" Creating top level property map:\n");
+#endif
+
+
+
+ spIStructureNode rootNode = stdXMP.mDOM;
+
+ for (auto rootIter = rootNode->Iterator(); rootIter; rootIter = rootIter->Next()) {
+
+ const spINode & node = rootIter->GetNode();
+ if (!strcmp(node->GetNameSpace()->c_str(), kXMP_NS_XMP_Note) && !strcmp(node->GetName()->c_str(), "HasExtendedXMP")) continue;
+ size_t propSize = EstimateSizeForJPEG(node);
+ StringPtrPair2 namePair(node->GetNameSpace()->c_str(), node->GetName()->c_str());
+ PropSizeMap2::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
+#endif
+
+#if ENABLE_CPP_DOM_MODEL
+// -------------------------------------------------------------------------------------------------
+// MoveLargestProperty
+// -------------------
+
+static size_t MoveLargestProperty(XMPMeta2 & stdXMP, XMPMeta2 * extXMP, PropSizeMap2 & 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
+ PropSizeMap2::iterator lastPos = propSizes.begin();
+ PropSizeMap2::iterator nextPos = lastPos;
+ for (++nextPos; nextPos != propSizes.end(); ++nextPos) lastPos = nextPos;
+#endif
+
+ size_t propSize = lastPos->first;
+ const char * schemaURI = lastPos->second.first;
+ const char * propName = lastPos->second.second;
+
+#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
+#endif
+
+// -------------------------------------------------------------------------------------------------
+// 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 );
+
+ size_t 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 );
+
+ size_t 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 );
+
+ size_t 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 );
+
+ size_t 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 );
+
+ size_t 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 )
+{
+
+#if ENABLE_CPP_DOM_MODEL
+ if(sUseNewCoreAPIs) {
+
+ const XMPMeta2 & orig = dynamic_cast<const XMPMeta2 &>(origXMP);
+ return XMPUtils::PackageForJPEG(orig, stdStr, extStr, digestStr);
+ }
+#endif
+ 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;
+
+ MD5_CTX context;
+ XMP_Uns8 digest [16];
+ MD5Init ( &context );
+ MD5Update ( &context, (XMP_Uns8*)tempStr.c_str(), (XMP_Uns32)tempStr.size() );
+ MD5Final ( digest, &context );
+
+ 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
+
+
+#if ENABLE_CPP_DOM_MODEL
+// -------------------------------------------------------------------------------------------------
+// PackageForJPEG
+// --------------
+
+/* class static */ void
+XMPUtils::PackageForJPEG(const XMPMeta2 & 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;
+ XMPMeta2 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.mDOM = origXMP.mDOM->Clone()->ConvertToMetadata();
+
+
+ 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);
+
+ spIStructureNode currRootNode = stdXMP.mDOM;
+ std::vector<XMP_VarString> nodes;
+ for (auto rootPropIter = currRootNode->Iterator(); rootPropIter; rootPropIter = rootPropIter->Next()) {
+
+ auto rootPropNodeCloned = rootPropIter->GetNode()->Clone();
+ if (strcmp(rootPropNodeCloned->GetNameSpace()->c_str(), kXMP_NS_CameraRaw ) ) continue;
+ extXMP.mDOM->AppendNode(rootPropNodeCloned);
+ nodes.push_back(rootPropNodeCloned->GetName()->c_str());
+ }
+
+ for (size_t childIdx = 0, childLim = nodes.size(); childIdx != childLim; ++childIdx) {
+
+ stdXMP.mDOM->RemoveNode(kXMP_NS_CameraRaw, AdobeXMPCommon::npos, nodes[childIdx].c_str(), nodes[childIdx].size() );
+ }
+
+
+ if (nodes.size() != 0) {
+
+ 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, "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.
+
+ PropSizeMap2 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.mDOM->ChildCount()) {
+
+ // 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;
+
+ MD5_CTX context;
+ XMP_Uns8 digest[16];
+ MD5Init(&context);
+ MD5Update(&context, (XMP_Uns8*)tempStr.c_str(), (XMP_Uns32)tempStr.size());
+ MD5Final(digest, &context);
+
+ 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
+
+#endif
+// -------------------------------------------------------------------------------------------------
+// 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::WhiteSpaceStrPtr = NULL;
+
+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;
+}
+
+#if ENABLE_CPP_DOM_MODEL
+#include "XMPCore/XMPCoreErrorCodes.h"
+
+void XMPUtils::MapXMPErrorToIError( XMP_Int32 xmpErrorCode, IError::eErrorDomain & domain, IError::eErrorCode & code ) {
+
+ switch ( xmpErrorCode ) {
+ case kXMPErr_Unknown:
+ case kXMPErr_TBD:
+ code = kGECUnknownFailure;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_Unavailable:
+ case kXMPErr_Unimplemented:
+ code = kGECNotImplemented;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_BadObject:
+ case kXMPErr_BadParam:
+ case kXMPErr_BadValue:
+ code = kGECParametersNotAsExpected;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_AssertFailure:
+ case kXMPErr_EnforceFailure:
+ code = kGECAssertionFailure;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_InternalFailure:
+ code = kGECInternalFailure;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_Deprecated:
+ code = kGECDeprecatedFunctionCall;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_ExternalFailure:
+ code = kGECExternalFailure;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_UserAbort:
+ case kXMPErr_ProgressAbort:
+ code = kGECUserAbort;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_StdException:
+ code = kGECStandardException;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_UnknownException:
+ code = kGECUnknownExceptionCaught;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_NoMemory:
+ code = kMMECAllocationFailure;
+ domain = IError_base::kEDMemoryManagement;
+ break;
+
+ case kXMPErr_BadSchema:
+ code = kDMECBadSchema;
+ domain = IError_base::kEDDataModel;
+ break;
+
+ case kXMPErr_BadXPath:
+ code = kDMECBadXPath;
+ domain = IError_base::kEDDataModel;
+ break;
+
+ case kXMPErr_BadOptions:
+ code = kDMECBadOptions;
+ domain = IError_base::kEDDataModel;
+ break;
+
+ case kXMPErr_BadIndex:
+ code = kGECIndexOutOfBounds;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_BadIterPosition:
+ code = kDMECBadIterPosition;
+ domain = IError_base::kEDDataModel;
+ break;
+
+ case kXMPErr_BadParse:
+ code = kPECBadXMP;
+ domain = IError_base::kEDParser;
+ break;
+
+ case kXMPErr_BadSerialize:
+ code = kSECSizeExceed;
+ domain = IError_base::kEDSerializer;
+ break;
+
+ case kXMPErr_BadFileFormat:
+ case kXMPErr_NoFileHandler:
+ case kXMPErr_TooLargeForJPEG:
+ case kXMPErr_NoFile:
+ case kXMPErr_FilePermission:
+ case kXMPErr_DiskSpace:
+ case kXMPErr_ReadError:
+ case kXMPErr_WriteError:
+ case kXMPErr_BadBlockFormat:
+ case kXMPErr_FilePathNotAFile:
+ case kXMPErr_RejectedFileExtension:
+ code = kGECNotImplemented;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ case kXMPErr_BadXML:
+ code = kPECBadXML;
+ domain = IError_base::kEDParser;
+ break;
+
+ case kXMPErr_BadRDF:
+ code = kPECBadRDF;
+ domain = IError_base::kEDParser;
+ break;
+
+ case kXMPErr_BadXMP:
+ code = kPECBadXMP;
+ domain = IError_base::kEDParser;
+ break;
+
+ case kXMPErr_EmptyIterator:
+ code = kDMECEmptyIterator;
+ domain = IError_base::kEDDataModel;
+ break;
+
+ case kXMPErr_BadUnicode:
+ code = kDMECBadUnicode;
+ domain = IError_base::kEDDataModel;
+ break;
+
+ case kXMPErr_BadTIFF:
+ case kXMPErr_BadJPEG:
+ case kXMPErr_BadPSD:
+ case kXMPErr_BadPSIR:
+ case kXMPErr_BadIPTC:
+ case kXMPErr_BadMPEG:
+ default:
+ code = kGECNotImplemented;
+ domain = IError_base::kEDGeneral;
+ break;
+
+ }
+}
+
+#endif
+
+// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils.hpp
new file mode 100644
index 0000000000..92c6c987f7
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils.hpp
@@ -0,0 +1,307 @@
+#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 "XMPCore/source/XMPMeta.hpp"
+#include "XMPCore/source/XMPCore_Impl.hpp"
+#include "public/include/client-glue/WXMPUtils.hpp"
+#include "XMPCore/XMPCoreDefines.h"
+
+#if ENABLE_CPP_DOM_MODEL
+#include "XMPCommon/Interfaces/IError.h"
+#include "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCore/source/XMPMeta2.hpp"
+#endif
+
+#include "XMPCore/source/XMPCore_Impl.hpp"
+#include "source/XMLParserAdapter.hpp"
+#include "XMPCore/source/XMPMeta.hpp"
+#include "XMP_MD5.h"
+
+
+
+
+
+// -------------------------------------------------------------------------------------------------
+
+class XMPUtils {
+public:
+
+ static bool
+ Initialize(); // ! For internal use only!
+
+ static void
+ Terminate() RELEASE_NO_THROW; // ! For internal use only!
+
+ // ---------------------------------------------------------------------------------------------
+
+#if ENABLE_CPP_DOM_MODEL
+ static void SetNode(const AdobeXMPCore::spINode & node, XMP_StringPtr value, XMP_OptionBits options);
+ static XMP_OptionBits ConvertNewArrayFormToOldArrayForm(const AdobeXMPCore::spcIArrayNode & arrayNode);
+ static AdobeXMPCore::spINode CreateArrayChildNode(const AdobeXMPCore::spIArrayNode & arrayNode, XMP_OptionBits options);
+ static void DoSetArrayItem(const AdobeXMPCore::spIArrayNode & arrayNode, XMP_Index itemIndex, XMP_StringPtr itemValue, XMP_OptionBits options);
+ static void SetImplicitNodeInformation(bool & firstImplicitNodeFound, AdobeXMPCore::spINode & implicitNodeRoot, AdobeXMPCore::spINode & destNode,
+ XMP_Index & implicitNodeIndex, XMP_Index index = 0);
+ static void GetNameSpaceAndNameFromStepValue(const XMP_VarString & stepStr, const AdobeXMPCore::spcINameSpacePrefixMap & defaultMap,
+ XMP_VarString & stepNameSpace, XMP_VarString & stepName);
+ static bool FindNode(const AdobeXMPCore::spIMetadata & mDOM, XMP_ExpandedXPath & expPath, bool createNodes, XMP_OptionBits leafOptions,
+ AdobeXMPCore::spINode & retNode, XMP_Index * nodeIndex = 0, bool ignoreLastStep = 0);
+ static bool FindCnstNode(const AdobeXMPCore::spIMetadata & mDOM, XMP_ExpandedXPath & expPath, AdobeXMPCore::spINode & destNode, XMP_OptionBits * options = 0,
+ XMP_Index * arrayIndex = 0);
+ static AdobeXMPCore::spINode FindChildNode(const AdobeXMPCore::spINode & parent, XMP_StringPtr childName, XMP_StringPtr childNameSpace, bool createNodes, size_t * pos /* = 0 */);
+ static size_t GetNodeChildCount(const AdobeXMPCore::spcINode & node);
+ static AdobeXMPCore::spcINodeIterator GetNodeChildIterator(const AdobeXMPCore::spcINode & node);
+ static std::vector< AdobeXMPCore::spcINode > GetChildVector(const AdobeXMPCore::spINode & node);
+ static XMP_OptionBits GetIXMPOptions(const AdobeXMPCore::spcINode & node);
+ static bool HandleConstAliasStep(const AdobeXMPCore::spIMetadata & mDOM, AdobeXMPCore::spINode & destNode, const XMP_ExpandedXPath & expandedXPath,
+ XMP_Index * nodeIndex = 0);
+ static bool HandleAliasStep(const AdobeXMPCore::spIMetadata & mDOM, XMP_ExpandedXPath & expandedXPath, bool createNodes, XMP_OptionBits leafOptions,
+ AdobeXMPCore::spINode & destNode, XMP_Index * nodeIndex, bool ignoreLastStep);
+ static AdobeXMPCommon::spcIUTF8String GetNodeValue(const AdobeXMPCore::spINode & node);
+ static XMP_Index LookupFieldSelector_v2(const AdobeXMPCore::spIArrayNode & arrayNode, XMP_VarString fieldName, XMP_VarString fieldValue);
+ static AdobeXMPCore::spINode CreateTerminalNode(const char* nameSpace, const char * name, XMP_OptionBits options);
+
+#endif
+
+
+ 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);
+
+
+#if ENABLE_CPP_DOM_MODEL
+ static void
+ PackageForJPEG(const XMPMeta2 & xmpObj,
+ XMP_VarString * stdStr,
+ XMP_VarString * extStr,
+ XMP_VarString * digestStr);
+#endif
+ 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;
+
+#if ENABLE_CPP_DOM_MODEL
+ static void MapXMPErrorToIError(XMP_Int32 xmpErrorCodes, AdobeXMPCommon::IError::eErrorDomain & domain, AdobeXMPCommon::IError::eErrorCode & code);
+ static bool SerializeExtensionAsJSON(const AdobeXMPCore::spINode & extensionNode, std::string & key, std::string & value);
+ static bool IsExtensionValidForBackwardCompatibility(const AdobeXMPCore::spINode & extensionNode);
+ static bool CreateExtensionNode(const AdobeXMPCore::spIStructureNode & xmpNode, const XMP_VarString & serializedJSON, const XMP_VarString & doubleQuotesStr);
+
+
+ static void
+ CatenateArrayItems_v2(const XMPMeta & xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_StringPtr separator,
+ XMP_StringPtr quotes,
+ XMP_OptionBits options,
+ XMP_VarString * catedStr);
+ static void
+ SeparateArrayItems_v2(XMPMeta * xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr arrayName,
+ XMP_OptionBits options,
+ XMP_StringPtr catedStr);
+
+ static void
+ RemoveProperties_v2(XMPMeta * xmpMetaPtr,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options);
+
+ static void
+ ApplyTemplate_v2(XMPMeta * workingXMP,
+ const XMPMeta & templateXMP,
+ XMP_OptionBits actions);
+
+ static void
+ DuplicateSubtree_v2(const XMPMeta & source,
+ XMPMeta * dest,
+ XMP_StringPtr sourceNS,
+ XMP_StringPtr sourceRoot,
+ XMP_StringPtr destNS,
+ XMP_StringPtr destRoot,
+ XMP_OptionBits options);
+
+#endif
+
+ static bool CreateExtensionNode(XMP_Node ** xmpNode, const XMP_VarString & serializedJSON, const XMP_VarString & doubleQuotesString);
+
+ static bool GetSerializedJSONForExtensionNode(const XMP_Node * xmpNode, XMP_VarString &extensionAsKey, XMP_VarString & serializedJSON);
+
+ static bool IsSuitableForJSONSerialization(const XMP_Node * xmpNode);
+
+}; // XMPUtils
+
+// =================================================================================================
+
+#endif // __XMPUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils2.cpp b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils2.cpp
new file mode 100644
index 0000000000..9d88cd3fdf
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/XMPCore/source/XMPUtils2.cpp
@@ -0,0 +1,921 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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/source/XMPCore_Impl.hpp"
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+
+#include "XMPCore/source/XMPUtils.hpp"
+#include "source/UnicodeInlines.incl_cpp"
+#include "source/UnicodeConversions.hpp"
+#include "source/ExpatAdapter.hpp"
+#include "third-party/zuid/interfaces/MD5.h"
+#include "XMPCore/Interfaces/IMetadata_I.h"
+#include "XMPCore/Interfaces/IArrayNode_I.h"
+#include "XMPCore/Interfaces/ISimpleNode_I.h"
+#include "XMPCore/Interfaces/INodeIterator.h"
+#include "XMPCore/Interfaces/IPathSegment_I.h"
+#include "XMPCore/Interfaces/IPath_I.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
+#include "XMPCore/Interfaces/IDOMImplementationRegistry_I.h"
+
+#include "XMPCommon/Interfaces/IUTF8String_I.h"
+
+const XMP_VarString xmlNameSpace = "http://www.w3.org/XML/1998/namespace";
+extern bool IsInternalProperty(const XMP_VarString & schema, const XMP_VarString & prop);
+extern const char * sListProps[];
+extern const char * sDateProps[];
+
+using namespace AdobeXMPCommon;
+using namespace AdobeXMPCore;
+
+// =================================================================================================
+// CloneSubtree
+// ============
+
+void
+CloneIXMPSubtree(const spcINode & origRoot, const spINode & cloneParent, bool skipEmpty /* = false */)
+{
+ spINode clonedRoot = origRoot->Clone(skipEmpty, true);
+ if (!clonedRoot) return;
+ if (cloneParent->GetNodeType() == INode::kNTArray) {
+ cloneParent->ConvertToArrayNode()->AppendNode( clonedRoot );
+ } else if (cloneParent->GetNodeType() == INode::kNTStructure) {
+ cloneParent->ConvertToStructureNode()->InsertNode( cloneParent );
+ }
+
+} // CloneSubtree
+
+// =================================================================================================
+// LookupLangItem
+// ==============
+//
+// ! Assumes that the language value is already normalized.
+
+XMP_Index
+LookupIXMPLangItem(const spcIArrayNode & arrayNode, XMP_VarString & lang)
+{
+ XMP_OptionBits arrayOptions = XMPUtils::GetIXMPOptions(arrayNode);
+ if (!(arrayOptions & kXMP_PropValueIsArray)) { // *** Check for alt-text?
+ XMP_Throw("Language item must be used on array", kXMPErr_BadXPath);
+ }
+
+ XMP_Index index = 1;
+ XMP_Index itemLim = arrayNode->ChildCount();
+
+ for (; index <= itemLim; ++index) {
+ spcINode currItem = arrayNode->GetNodeAtIndex(index);
+
+ if (!currItem->HasQualifiers()) continue;
+ spcINode langQual = currItem->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if (!langQual) continue;
+ if (langQual->GetNodeType() != INode::kNTSimple) continue;
+ XMP_VarString langQualValue = langQual->ConvertToSimpleNode()->GetValue()->c_str();
+ if (langQualValue == lang) break;
+ }
+
+ if (index == itemLim + 1) index = -1;
+ return index;
+
+} // LookupLangItem
+// =================================================================================================
+
+
+// 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(spcINode leftNode, spcINode rightNode)
+{
+ // Don't compare the names here, we want to allow the outermost roots to have different names.
+ XMP_OptionBits leftNodeOptions = XMPUtils::GetIXMPOptions(leftNode), rightNodeOptions = XMPUtils::GetIXMPOptions(rightNode);
+ if (leftNode->GetNodeType() != rightNode->GetNodeType()) return false;
+ if (leftNode->GetNodeType() == INode::kNTSimple) {
+ if ( strcmp( leftNode->ConvertToSimpleNode()->GetValue()->c_str(), rightNode->ConvertToSimpleNode()->GetValue()->c_str() ) ) {
+ return false;
+ }
+ }
+ if (XMPUtils::GetNodeChildCount(leftNode) != XMPUtils::GetNodeChildCount(rightNode)) return false;
+ if (leftNode->HasQualifiers() != rightNode->HasQualifiers() ) return false;
+ if (leftNode->HasQualifiers()) {
+ for (auto leftQualIter = leftNode->QualifiersIterator(); leftQualIter; leftQualIter = leftQualIter->Next()) {
+ spcINode leftQualNode = leftQualIter->GetNode();
+ spcINode righQualNode = rightNode->GetINode_I()->GetQualifier( leftQualNode->GetNameSpace(), leftQualNode->GetName() );
+ if (!righQualNode || !CompareSubtrees(leftQualNode, righQualNode)){
+ return false;
+ }
+
+ }
+ }
+
+ if (leftNode->GetNodeType() == INode::kNTStructure ) {
+ for ( auto leftChildIter = XMPUtils::GetNodeChildIterator(leftNode); leftChildIter; leftChildIter = leftChildIter->Next()) {
+ spcINode leftChildNode = leftChildIter->GetNode();
+ spcINode rightChildNode = XMPUtils::FindChildNode( AdobeXMPCore_Int::const_pointer_cast<INode>(rightNode), leftChildNode->GetName()->c_str(), leftChildNode->GetNameSpace()->c_str(), false, 0);
+ if (!rightChildNode || !CompareSubtrees(leftChildNode, rightChildNode)) {
+ return false;
+ }
+ }
+ }
+
+
+ else if (leftNodeOptions & kXMP_PropArrayIsAltText) {
+ // The parent node is an alt-text array.
+ auto leftNodeAsArray = leftNode->ConvertToArrayNode();
+ auto rightNodeAsArray = rightNode->ConvertToArrayNode();
+
+ size_t leftNodeChildCount = XMPUtils::GetNodeChildCount(leftNode);
+ for (size_t idx = 1; idx <= leftNodeChildCount; ++idx) {
+ spcINode leftChild = leftNodeAsArray->GetNodeAtIndex(idx);
+ spcINode leftChildFirstQualifier = leftChild->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if (leftChildFirstQualifier) {
+ XMP_VarString leftChildFirstQualifierValue = leftChildFirstQualifier->ConvertToSimpleNode()->GetValue()->c_str();
+ size_t rightIdx = LookupIXMPLangItem( rightNodeAsArray, leftChildFirstQualifierValue );
+ if (rightIdx == -1) {
+ return false;
+ }
+ spcINode rightChild = rightNodeAsArray->GetNodeAtIndex( rightIdx );
+ if (!CompareSubtrees(leftChild, rightChild)) {
+ return false;
+ }
+ }
+
+ }
+
+
+ }
+ else {
+
+ // The parent must be simple or some other (not alt-text) kind of array.
+ XMP_Assert((!(leftNodeOptions & kXMP_PropCompositeMask)) || (leftNodeOptions & kXMP_PropValueIsArray));
+ auto leftNodeAsArray = leftNode->ConvertToArrayNode();
+ auto rightNodeAsArray = rightNode->ConvertToArrayNode();
+
+ size_t leftNodeChildCount = XMPUtils::GetNodeChildCount(leftNode);
+ for (size_t idx = 1; idx <= leftNodeChildCount; ++idx) {
+ spcINode leftChild = leftNodeAsArray->GetNodeAtIndex(idx);
+ spcINode rightChild = rightNodeAsArray->GetNodeAtIndex(idx);
+ if (!CompareSubtrees(leftChild, rightChild)) {
+ return false;
+ }
+ }
+
+ }
+ return true;
+}// CompareSubtrees
+
+// -------------------------------------------------------------------------------------------------
+// MergeArrayItems
+// ---------------
+
+static void
+MergeArrayItems(spINode newArray, spINode mergedArray)
+{
+ XMP_Assert(newArray->GetNodeType() == INode::kNTArray);
+ XMP_Assert(mergedArray->GetNodeType() == INode::kNTArray);
+
+ auto newArrayAsArrayNode = newArray->ConvertToArrayNode();
+ auto mergedArrayAsArrayNode = mergedArray->ConvertToArrayNode();
+
+ for (size_t newNum = 1, newLim = XMPUtils::GetNodeChildCount(newArray); newNum <= newLim; ++newNum) {
+
+ spcINode newItem = newArrayAsArrayNode->GetNodeAtIndex(newNum);
+ size_t mergedNum, mergedLim;
+ for (mergedNum = 1, mergedLim = XMPUtils::GetNodeChildCount(mergedArray) + 1; mergedNum < mergedLim; ++mergedNum) {
+ spcINode mergedItem = mergedArrayAsArrayNode->GetNodeAtIndex(mergedNum);
+ if (CompareSubtrees(newItem, mergedItem)) break;
+ }
+
+ if (mergedNum == mergedLim) CloneIXMPSubtree(newItem, mergedArray, false);
+
+ }
+
+} // MergeArrayItems
+static bool
+ItemValuesMatch(spcINode leftNode, spcINode rightNode)
+{
+ if (!leftNode && !rightNode) return true;
+ if (!leftNode || !rightNode) return false;
+ const XMP_OptionBits leftNodeOptions = XMPUtils::GetIXMPOptions(leftNode);
+ const XMP_OptionBits rightNodeOptions = XMPUtils::GetIXMPOptions(rightNode);
+ const XMP_OptionBits leftForm = leftNodeOptions & kXMP_PropCompositeMask;
+ const XMP_OptionBits rightForm = rightNodeOptions & kXMP_PropCompositeMask;
+
+ if (leftForm != rightForm) return false;
+
+ if (leftForm == 0) {
+
+ // Simple nodes, check the values and xml:lang qualifiers.
+ XMP_VarString leftValue = leftNode->ConvertToSimpleNode()->GetValue()->c_str();
+ XMP_VarString rightValue = rightNode->ConvertToSimpleNode()->GetValue()->c_str();
+ if (leftValue != rightValue) return false;
+ if ((leftNodeOptions & kXMP_PropHasLang) != (rightNodeOptions & kXMP_PropHasLang)) return false;
+ if (leftNodeOptions & kXMP_PropHasLang) {
+ spcINode leftDefaultQualifier = leftNode->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ spcINode rightDefaultQualifier = rightNode->GetQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if (!leftDefaultQualifier && !rightDefaultQualifier) return true;
+ if (!leftDefaultQualifier || !rightDefaultQualifier) return false;
+
+ XMP_VarString leftFirstQualValue = leftDefaultQualifier->ConvertToSimpleNode()->GetValue()->c_str();
+ XMP_VarString rightFirstQualValue = rightDefaultQualifier->ConvertToSimpleNode()->GetValue()->c_str();
+ if (leftFirstQualValue != rightFirstQualValue) {
+ return false;
+ }
+ }
+
+ }
+ else if (leftForm == kXMP_PropValueIsStruct) {
+
+ // Struct nodes, see if all fields match, ignoring order.
+ size_t leftNodeChildCount = XMPUtils::GetNodeChildCount(leftNode);
+ size_t rightNodeChildCount = XMPUtils::GetNodeChildCount(rightNode);
+ if (leftNodeChildCount != rightNodeChildCount) return false;
+
+ auto leftNodeChildIter = XMPUtils::GetNodeChildIterator(leftNode);
+ auto rightNodeChildIter = XMPUtils::GetNodeChildIterator(rightNode);
+ for (; leftNodeChildIter; leftNodeChildIter = leftNodeChildIter->Next(), rightNodeChildIter = rightNodeChildIter->Next()) {
+ spcINode leftField = leftNodeChildIter->GetNode();
+ spINode rightField = XMPUtils::FindChildNode( AdobeXMPCore_Int::const_pointer_cast<INode>(rightNode),
+ leftField->GetNameSpace()->c_str(), leftField->GetName()->c_str(), kXMP_ExistingOnly, 0);
+ if (!rightField || !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);
+ size_t leftNodeChildCount = XMPUtils::GetNodeChildCount(leftNode);
+ size_t rightNodeChildCount = XMPUtils::GetNodeChildCount(rightNode);
+ auto leftNodeAsArrayNode = leftNode->ConvertToArrayNode();
+ auto rightNodeAsArrayNode = rightNode->ConvertToArrayNode();
+ for (size_t leftNum = 1; leftNum <= leftNodeChildCount; ++leftNum) {
+
+ spcINode leftItem = leftNodeAsArrayNode->GetNodeAtIndex(leftNum);
+ bool leftItemFound = false;
+ for (size_t rightNum = 1; rightNum <= rightNodeChildCount; ++rightNum) {
+
+ spcINode rightItem = rightNodeAsArrayNode->GetNodeAtIndex(rightNum);
+
+ if (ItemValuesMatch(leftItem, rightItem)) {
+ leftItemFound = true;
+ break;
+ }
+ }
+ if (!leftItemFound) return false;
+
+ }
+
+ }
+
+ return true; // All of the checks passed.
+
+} // ItemValuesMatch
+
+
+static void
+AppendSubtree(spcINode sourceNode, spINode &destParent,
+const bool mergeCompound, const bool replaceOld, const bool deleteEmpty)
+{
+
+ XMP_VarString sourceName = sourceNode->GetName()->c_str();
+ XMP_VarString sourceNamespace = sourceNode->GetNameSpace()->c_str();
+
+ XMP_VarString destName = destParent->GetName()->c_str();
+ XMP_VarString destNamespace = destParent->GetNameSpace()->c_str();
+ if (sourceName.find("UserComment") != XMP_VarString::npos) {
+ int y = 1;
+ y++;
+ }
+ // Need clone non empty only
+ // to do lang alt append
+ // to do lang alt
+ size_t destPos = 0;
+ spINode destNode = XMPUtils::FindChildNode(destParent, sourceNode->GetName()->c_str(), sourceNode->GetNameSpace()->c_str(), kXMP_ExistingOnly, &destPos);
+
+ bool valueIsEmpty = false;
+ XMP_OptionBits sourceNodeOptions = XMPUtils::GetIXMPOptions(sourceNode);
+
+ if (sourceNode->GetNodeType() == INode::kNTSimple) {
+ valueIsEmpty = sourceNode->ConvertToSimpleNode()->GetValue()->empty();
+ }
+ else {
+
+ valueIsEmpty = XMPUtils::GetNodeChildCount(sourceNode) == 0;
+ }
+
+
+ if (valueIsEmpty) {
+ if (sourceNode && deleteEmpty) {
+ destParent->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( sourceNode->GetNameSpace(), sourceNode->GetName() );
+ }
+ return; // ! Done, empty values are either ignored or cause deletions.
+ }
+
+ if (!destNode) {
+ // The one easy case, the destination does not exist.
+ destNode = sourceNode->Clone(true, true); // TO DO need to skip empty nodes
+ if (!destNode) {
+ if (destParent->GetNodeType() == INode::kNTStructure) {
+ destParent->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( sourceNode->GetNameSpace(), sourceNode->GetName() );
+ }
+ else if (destParent->GetNodeType() == INode::kNTArray) {
+ destParent->ConvertToArrayNode()->RemoveNodeAtIndex( destPos );
+ }
+ return;
+ }
+ if (destParent->GetNodeType() == INode::kNTStructure) {
+ destParent->ConvertToStructureNode()->InsertNode( destNode );
+ }
+ else if (destParent->GetNodeType() == INode::kNTArray) {
+ destParent->ConvertToArrayNode()->InsertNodeAtIndex( destNode, destPos );
+ }
+ // XMP_Assert ( (!destNode) || (! 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));
+
+ XMP_OptionBits sourceForm = XMPUtils::GetIXMPOptions(sourceNode) & kXMP_PropCompositeMask;
+ XMP_OptionBits destForm = XMPUtils::GetIXMPOptions(destNode) & kXMP_PropCompositeMask;
+
+ bool replaceThis = replaceOld; // ! Don't modify replaceOld, it gets passed to inner calls.
+ if (mergeCompound && (!XMP_PropIsSimple(sourceForm))) replaceThis = false;
+
+ if (replaceThis) {
+ if (destNode) {
+ destParent->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( destNode->GetNameSpace(), destNode->GetName() );
+ }
+ destNode = sourceNode->Clone(true, true);
+ if (!destNode) return;
+ if ( destNode->GetParent() != destParent && destParent->GetNodeType() == INode::kNTStructure )
+ destParent->ConvertToStructureNode()->AppendNode( destNode );
+ else if (destNode->GetParent() != destParent && destParent->GetNodeType() == INode::kNTArray) {
+ destParent->ConvertToArrayNode()->InsertNodeAtIndex( destNode, destPos );
+ }
+ if (!XMP_PropIsSimple(XMPUtils::GetIXMPOptions(destNode)) && !XMPUtils::GetNodeChildCount(destNode)) {
+ // 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.
+ if (destParent->GetNodeType() == INode::kNTStructure) {
+ destParent->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( destNode->GetNameSpace(), destNode->GetName() );
+ }
+ else if (destParent->GetNodeType() == INode::kNTArray) {
+ destParent->ConvertToArrayNode()->RemoveNodeAtIndex( destPos );
+ }
+ }
+
+ return;
+
+ }
+
+ // From here on are cases for merging arrays or structs.
+
+ if (XMP_PropIsSimple(sourceForm) || (sourceForm != destForm)) return;
+
+ if (sourceForm == kXMP_PropValueIsStruct) {
+
+ auto sourceChildIter = XMPUtils::GetNodeChildIterator(sourceNode);
+ for (; sourceChildIter; sourceChildIter = sourceChildIter->Next()) {
+ spcINode sourceField = sourceChildIter->GetNode();
+ AppendSubtree(sourceField, destNode, mergeCompound, replaceOld, deleteEmpty);
+ if (deleteEmpty && !XMPUtils::GetNodeChildCount(destNode)) {
+ destParent->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( destNode->GetNameSpace(), destNode->GetName() );
+ }
+ }
+
+
+ }
+ else if (sourceForm & kXMP_PropArrayIsAltText) {
+
+ XMP_Assert(mergeCompound);
+ spcIArrayNode sourceArrayNode = sourceNode->ConvertToArrayNode();
+ for (size_t sourceNum = 1, sourceLim = XMPUtils::GetNodeChildCount(sourceNode); sourceNum <= sourceLim && destNode; ++sourceNum) {
+
+ spcINode sourceItem = sourceArrayNode->GetNodeAtIndex(sourceNum);
+ spcIUTF8String sourceItemValue = sourceItem->ConvertToSimpleNode()->GetValue();
+ if (!sourceItem->HasQualifiers()) continue;
+ spcINode langQualNode = sourceItem->GetQualifier(xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if (!langQualNode || langQualNode->GetNodeType() != INode::kNTSimple) continue;
+ XMP_VarString langValue = langQualNode->ConvertToSimpleNode()->GetValue()->c_str();
+ size_t destIndex = LookupIXMPLangItem( destNode->ConvertToArrayNode(), langValue );
+
+ if (sourceItemValue->empty()) {
+
+ if (deleteEmpty && (destIndex != -1)) {
+ //delete ( destNode->children[destIndex] );
+ //destNode->children.erase ( destNode->children.begin() + destIndex );
+ destNode->ConvertToArrayNode()->RemoveNodeAtIndex(destIndex);
+ if (!XMPUtils::GetNodeChildCount(destNode)) {
+
+ if (destParent->GetNodeType() == INode::kNTStructure) {
+ destParent->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( destNode->GetNameSpace(), destNode->GetName() );
+ }
+ else if (destParent->GetNodeType() == INode::kNTArray) {
+ destParent->ConvertToArrayNode()->RemoveNodeAtIndex( destPos );
+ }
+ }
+ }
+
+ }
+ else {
+
+ if (destIndex != -1) {
+
+ // The source and dest arrays both have this language item.
+
+ if (replaceOld) {
+ auto temp = destNode->ConvertToArrayNode()->GetNodeAtIndex( destIndex );
+ temp->ConvertToSimpleNode()->SetValue(sourceItemValue->c_str(), sourceItemValue->size() );
+ }
+
+ }
+ else {
+
+
+ spcISimpleNode firstQualifier = sourceItem->GetSimpleQualifier( xmlNameSpace.c_str(), xmlNameSpace.size(), "lang", AdobeXMPCommon::npos );
+ if ((!XMP_LitMatch(firstQualifier->GetValue()->c_str(), "x-default")) || !XMPUtils::GetNodeChildCount(destNode)) {
+
+ CloneIXMPSubtree(sourceItem, destNode, true);
+ }
+ else {
+
+ spINode destItem = AdobeXMPCore_Int::ISimpleNode_I::CreateSimpleNode( sourceItem->GetNameSpace(), sourceItem->GetName(), sourceItemValue );
+ destNode->ConvertToArrayNode()->InsertNodeAtIndex(destItem, 1);
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ else if (sourceForm & kXMP_PropValueIsArray) {
+ auto sourceNodeChildIter = XMPUtils::GetNodeChildIterator(sourceNode);
+ for (; sourceNodeChildIter; sourceNodeChildIter = sourceNodeChildIter->Next()) {
+ spcINode sourceItem = sourceNodeChildIter->GetNode();
+
+ spIArrayNode arrayNode = destNode->ConvertToArrayNode();
+ size_t arrayChildCount = arrayNode->ChildCount();
+ size_t foundIndex = arrayChildCount + 1;
+ for (size_t arrayIdx = 1; arrayIdx <= arrayChildCount; arrayIdx++) {
+ spINode destItem = arrayNode->GetNodeAtIndex(arrayIdx);
+ //XMP_VarString destValue = INode_I::AdaptConstNodeTo_I<ISimpleNode, INode::kNTSimple>(destItem)->GetValue_I()->c_str();
+ if (ItemValuesMatch(destItem, sourceItem)) {
+ foundIndex = arrayIdx;
+ break;
+ }
+
+ }
+ if (foundIndex == arrayChildCount + 1) {
+
+ CloneIXMPSubtree(sourceItem, destNode, true);
+
+ }
+
+ }
+
+
+ }
+
+} // AppendSubtree_v2
+
+// -------------------------------------------------------------------------------------------------
+// ApplyTemplate
+// -------------
+
+/* class static */ void
+XMPUtils::ApplyTemplate_v2( XMPMeta * workingXMPBasePtr,
+ const XMPMeta & templateXMPBasePtr,
+ XMP_OptionBits actions)
+{
+ XMPMeta2 * workingXMP = dynamic_cast<XMPMeta2 *>(workingXMPBasePtr);
+ if (!workingXMPBasePtr) return;
+ const XMPMeta2 & templateXMP = dynamic_cast<const XMPMeta2 &> (templateXMPBasePtr);
+ 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);
+
+ auto defaultMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap()->GetINameSpacePrefixMap_I();
+
+ if (doClear) {
+
+ // Visit the top level working properties, delete if not in the template.
+ auto topLevelPropIter = XMPUtils::GetNodeChildIterator(workingXMP->mDOM);
+ std::vector<spcINode> propsToBeDeleted; // needed to avoid problems related with deletion and invalid const iterator
+
+ for (; topLevelPropIter; topLevelPropIter = topLevelPropIter->Next()) {
+ spcINode topLevelProp = topLevelPropIter->GetNode();
+ XMP_VarString currNameSpace = defaultMap->GetPrefix(topLevelProp->GetNameSpace())->c_str();
+ XMP_VarString nodeFullName = currNameSpace + ":" + topLevelProp->GetName()->c_str();
+ if (doAll || !IsInternalProperty(topLevelProp->GetNameSpace()->c_str(), nodeFullName)) {
+ if (!templateXMP.mDOM->GetIStructureNode_I()->GetNode(topLevelProp->GetNameSpace(), topLevelProp->GetName())) {
+ propsToBeDeleted.push_back(topLevelProp);
+ }
+ }
+
+ }
+ for (size_t idx = 0; idx < propsToBeDeleted.size(); idx++) {
+ workingXMP->mDOM->GetIStructureNode_I()->RemoveNode(propsToBeDeleted[idx]->GetNameSpace(), propsToBeDeleted[idx]->GetName());
+ }
+
+ }
+
+ if (doAdd | doReplace) {
+
+ auto templateTopPropIter = XMPUtils::GetNodeChildIterator(templateXMP.mDOM);
+ for (; templateTopPropIter; templateTopPropIter = templateTopPropIter->Next()) {
+ spcINode currentTemplateTopProp = templateTopPropIter->GetNode();
+ XMP_VarString currNameSpace = defaultMap->GetPrefix(currentTemplateTopProp->GetNameSpace())->c_str();
+ XMP_VarString nodeFullName = currNameSpace + ":" + currentTemplateTopProp->GetName()->c_str();
+ XMP_ExpandedXPath expPath;
+ ExpandXPath(currentTemplateTopProp->GetNameSpace()->c_str(), nodeFullName.c_str(), &expPath);
+ spINode destNode;
+ spINode templateXMPRoot = workingXMP->mDOM;
+ if (!currentTemplateTopProp) continue;
+ if (doAll || !IsInternalProperty(currentTemplateTopProp->GetNameSpace()->c_str(), nodeFullName)){
+ AppendSubtree ( currentTemplateTopProp, templateXMPRoot, doAdd, doReplace, deleteEmpty );
+ }
+ }
+ }
+
+
+} // ApplyTemplate_v2
+
+// -------------------------------------------------------------------------------------------------
+// DuplicateSubtree
+// ----------------
+
+
+void CloneContents(spINode sourceNode, spINode &destNode) {
+
+
+ if (sourceNode->GetNodeType() == INode::kNTSimple) {
+
+ spISimpleNode sourceSimpleNode = sourceNode->ConvertToSimpleNode();
+ spISimpleNode destSimpleNode = AdobeXMPCore_Int::ISimpleNode_I::CreateSimpleNode(destNode->GetNameSpace(), destNode->GetName(), sourceSimpleNode->GetValue() );
+ destNode = destSimpleNode;
+ }
+ else if (sourceNode->GetNodeType() == INode::kNTArray)
+ {
+ spIArrayNode arraySourceNode = sourceNode->ConvertToArrayNode();
+ spIArrayNode destArrayNode = AdobeXMPCore_Int::IArrayNode_I::CreateArrayNode(destNode->GetNameSpace(), destNode->GetName(), arraySourceNode->GetArrayForm());
+ destNode = destArrayNode;
+ for (auto childIter = arraySourceNode->Iterator(); childIter; childIter = childIter->Next()) {
+
+ spINode childCloned = childIter->GetNode()->Clone();
+ destArrayNode->AppendNode(childCloned);
+ }
+
+ destNode = destArrayNode;
+
+ }
+ else {
+
+ spIStructureNode arraySourceNode = sourceNode->ConvertToStructureNode();
+
+ spIStructureNode destArrayNode = destNode->ConvertToStructureNode();
+ for (auto childIter = arraySourceNode->Iterator(); childIter; childIter = childIter->Next()) {
+
+ spINode childCloned = childIter->GetNode()->Clone();
+ destArrayNode->AppendNode(childCloned);
+ }
+
+ destNode = destArrayNode;
+
+ }
+
+ if (sourceNode->HasQualifiers()) {
+
+
+ for (auto qualIter = sourceNode->QualifiersIterator(); qualIter; qualIter = qualIter->Next()) {
+
+ spINode clonedQual = qualIter->GetNode()->Clone();
+ destNode->InsertQualifier(clonedQual);
+ }
+ }
+}
+
+/* class static */ void
+XMPUtils::DuplicateSubtree_v2(const XMPMeta & sourceBasePtr,
+XMPMeta * destBasePtr,
+XMP_StringPtr sourceNS,
+XMP_StringPtr sourceRoot,
+XMP_StringPtr destNS,
+XMP_StringPtr destRoot,
+XMP_OptionBits options)
+{
+
+ XMPMeta2 * dest = dynamic_cast<XMPMeta2 *>(destBasePtr);
+
+ if (!dest) return;
+ const XMPMeta2 & source = dynamic_cast<const XMPMeta2 &> (sourceBasePtr);
+
+ IgnoreParam(options);
+ // TODO : Use of testnode == soucenode seems slightly dodgy, verify if it works in null case, simple case, subtree case
+ bool fullSourceTree = false;
+ bool fullDestTree = false;
+
+ XMP_ExpandedXPath sourcePath, destPath;
+
+ spINode sourceNode;
+ spINode destNode;
+
+ 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);
+
+ XMP_OptionBits destOptions = 0;
+ if (!XMPUtils::FindCnstNode(dest->mDOM, destPath, destNode, &destOptions)) {
+ XMP_Throw("Destination must be an existing struct", kXMPErr_BadXPath);
+ }
+ if (!XMP_PropIsStruct(destOptions)) {
+ XMP_Throw("Destination must be an existing struct", kXMPErr_BadXPath);
+ }
+
+ if (XMPUtils::GetNodeChildCount(destNode)) {
+ if (options & kXMP_DeleteExisting) {
+ destNode->Clear();
+ }
+ else {
+ XMP_Throw("Destination must be an empty struct", kXMPErr_BadXPath);
+ }
+ }
+ sourceNode = source.mDOM;
+ CloneContents(sourceNode, destNode);
+
+ }
+ 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);
+ spINode sourceNode;
+ XMP_OptionBits sourceNodeOptions = 0;
+ XMPUtils::FindCnstNode(source.mDOM, srcPath, sourceNode, &sourceNodeOptions);
+
+ if ((!sourceNode) || (!XMP_PropIsStruct(sourceNodeOptions))) {
+ XMP_Throw("Source must be an existing struct", kXMPErr_BadXPath);
+ }
+
+ destNode = dest->mDOM;
+
+ if (XMPUtils::GetNodeChildCount(destNode)) {
+ if (options & kXMP_DeleteExisting) {
+ destNode->Clear();
+ }
+ else {
+ XMP_Throw("Destination tree must be empty", kXMPErr_BadXPath);
+ }
+ }
+
+
+ for (auto sourceChildIter = XMPUtils::GetNodeChildIterator(sourceNode); sourceChildIter; sourceChildIter = sourceChildIter->Next()) {
+
+ spINode copyNode = sourceChildIter->GetNode()->Clone();
+ if (destNode->GetNodeType() == INode::kNTStructure){
+ destNode->ConvertToStructureNode()->AppendNode(copyNode);
+ }
+
+ }
+ }
+ else {
+
+ // Find the root nodes for the source and destination subtrees.
+
+ ExpandXPath(sourceNS, sourceRoot, &sourcePath);
+ ExpandXPath(destNS, destRoot, &destPath);
+ spINode destNodeCopy;
+ if (!XMPUtils::FindCnstNode(source.mDOM, sourcePath, sourceNode)) {
+ XMP_Throw("Can't find source subtree", kXMPErr_BadXPath);
+ }
+ if (XMPUtils::FindCnstNode(dest->mDOM, destPath, destNode)) {
+ XMP_Throw("Destination subtree must not exist", kXMPErr_BadXPath);
+ }
+
+
+ if (!XMPUtils::FindNode(dest->mDOM, destPath, kXMP_CreateNodes, 0, destNode)) { // Now create the dest.
+ 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 (spINode testNode = destNode; testNode; testNode = testNode->GetParent()){
+ if (testNode.get() == sourceNode.get()) {
+
+ XMP_Throw("Destination subtree is within the source subtree", kXMPErr_BadXPath);
+ }
+ }
+ }
+
+ // *** Could use a CloneTree util here and maybe elsewhere.
+ //destNode = sourceNode->Clone();
+
+ if (sourceNode->GetNodeType() == INode::kNTSimple) {
+
+ spISimpleNode sourceSimpleNode = sourceNode->ConvertToSimpleNode();
+ spISimpleNode destSimpleNode = AdobeXMPCore_Int::ISimpleNode_I::CreateSimpleNode(destNode->GetNameSpace(), destNode->GetName(),
+ sourceSimpleNode->GetValue() );
+ destNodeCopy = destSimpleNode;
+ }
+ else if (sourceNode->GetNodeType() == INode::kNTArray)
+ {
+ spIArrayNode arraySourceNode = sourceNode->ConvertToArrayNode();
+ spIArrayNode destArrayNode = AdobeXMPCore_Int::IArrayNode_I::CreateArrayNode(destNode->GetNameSpace(), destNode->GetName(), arraySourceNode->GetArrayForm());
+ destNodeCopy = destArrayNode;
+ for (auto childIter = arraySourceNode->Iterator(); childIter; childIter = childIter->Next()) {
+
+ spINode childCloned = childIter->GetNode()->Clone();
+ destArrayNode->AppendNode(childCloned);
+ }
+
+ destNodeCopy = destArrayNode;
+
+ }
+ else {
+
+ spIStructureNode arraySourceNode = sourceNode->ConvertToStructureNode();
+ spIStructureNode destArrayNode = AdobeXMPCore_Int::IStructureNode_I::CreateStructureNode(destNode->GetNameSpace(), destNode->GetName());
+ destNodeCopy = destArrayNode;
+ for (auto childIter = arraySourceNode->Iterator(); childIter; childIter = childIter->Next()) {
+
+ spINode childCloned = childIter->GetNode()->Clone();
+ destArrayNode->AppendNode(childCloned);
+ }
+
+ destNodeCopy = destArrayNode;
+
+ }
+
+ if (sourceNode->HasQualifiers()) {
+
+
+ for (auto qualIter = sourceNode->QualifiersIterator(); qualIter; qualIter = qualIter->Next()) {
+
+ spINode clonedQual = qualIter->GetNode()->Clone();
+ destNodeCopy->InsertQualifier(clonedQual);
+ }
+ }
+
+ dest->mDOM->ReplaceNode(destNodeCopy);
+ }
+
+} // DuplicateSubtree_v2
+
+// -------------------------------------------------------------------------------------------------
+// RemoveProperties
+// ----------------
+
+/* class static */ void
+XMPUtils::RemoveProperties_v2(XMPMeta * xmpMetaPtr,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
+ XMP_OptionBits options)
+{
+ using namespace AdobeXMPCommon;
+ using namespace AdobeXMPCore;
+ XMPMeta2 * xmpObj = dynamic_cast<XMPMeta2 *> (xmpMetaPtr);
+ if (!xmpObj) {
+ return;
+ }
+ // Handle aliases in remove properties
+ 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_Index propIndex = 0;
+ spINode propNode;
+ if (XMPUtils::FindNode(xmpObj->mDOM, expPath, kXMP_ExistingOnly, kXMP_NoOptions, propNode, &propIndex)) {
+ if (doAll || !IsInternalProperty(expPath[kSchemaStep].step, expPath[kRootPropStep].step)) {
+ spINode parentNode = propNode->GetParent(); // *** Should have XMP_Node::RemoveChild(pos).
+
+ if (parentNode->GetNodeType() == INode::kNTStructure) {
+ parentNode->ConvertToStructureNode()->GetIStructureNode_I()->RemoveNode( propNode->GetNameSpace(), propNode->GetName() );
+ }
+ else if (parentNode->GetNodeType() == INode::kNTArray) {
+ parentNode->ConvertToArrayNode()->RemoveNodeAtIndex(propIndex);
+ }
+ }
+ }
+
+ }
+ else if (*schemaNS != 0) {
+ std::vector<spINode> topLevelNodesToBeDeleted;
+ for (auto topLevelIter = xmpObj->mDOM->Iterator(); topLevelIter; topLevelIter = topLevelIter->Next()) {
+ spINode topLevelProp = topLevelIter->GetNode();
+ if (XMP_LitMatch(topLevelProp->GetNameSpace()->c_str(), schemaNS)) {
+ topLevelNodesToBeDeleted.push_back(topLevelProp);
+ }
+ }
+ for (size_t propIdx = 0; propIdx < topLevelNodesToBeDeleted.size(); ++propIdx) {
+
+ xmpObj->mDOM->GetIStructureNode_I()->RemoveNode(topLevelNodesToBeDeleted[propIdx]->GetNameSpace(), topLevelNodesToBeDeleted[propIdx]->GetName());
+ }
+ if (includeAliases) {
+ // Removing Aliases
+ 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) {
+ spINode destNode;
+ XMP_Index actualPos = 0;
+ size_t colonPos = currAlias->first.find_first_of(":");
+
+ xmpObj->mDOM->RemoveNode( schemaNS, AdobeXMPCommon::npos, currAlias->first.substr( colonPos + 1 ).c_str(), AdobeXMPCommon::npos );
+ /*if (!XMPUtils::FindCnstNode(xmpObj->mDOM, currAlias->second, destNode, 0, &actualPos)) continue;
+ if (!destNode) continue;
+ spINode rootProp = destNode;
+ while (rootProp && rootProp->GetParent() != xmpObj->mDOM) {
+ rootProp = rootProp->GetParent();
+ }
+ if (doAll || !IsInternalProperty(rootProp->GetNameSpace()->c_str(), rootProp->GetName()->c_str())) {
+ spINode parentNode = destNode->GetParent();
+ if (destNode->IsArrayItem()){
+ INode_I::AdaptNodeTo_I<IArrayNode, INode::kNTArray>(parentNode)->RemoveNode_I(actualPos);
+ }
+ else {
+ INode_I::AdaptNodeTo_I<IStructureNode, INode::kNTStructure>(parentNode)->RemoveNode_I(destNode->GetNameSpace()->c_str(), destNode->GetName()->c_str());
+ }
+ }*/
+
+ }
+ }
+
+ }
+
+ }
+ else {
+
+ xmpObj->mDOM->Clear();
+ }
+
+} // RemoveProperties_v2
+#endif
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/build/XMP_BuildInfo.h b/core/libs/dngwriter/extra/xmp_sdk/build/XMP_BuildInfo.h
new file mode 100644
index 0000000000..21a6bb6940
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/build/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) 2016
+#define kXMP_CopyrightStr "Copyright (c) 2016"
+
+#endif /* __XMP_BuildInfo_h__ */
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_BuildInfo.h b/core/libs/dngwriter/extra/xmp_sdk/include/XMP_BuildInfo.h
deleted file mode 100644
index 2b387c86fa..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_BuildInfo.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __XMP_BuildInfo_h__
-#define __XMP_BuildInfo_h__ 1
-
-/* --------------------------------------------------------------------------------------------- */
-/* ** IMPORTANT ** This file must be usable by strict ANSI C compilers. No "//" comments, etc. */
-/* --------------------------------------------------------------------------------------------- */
-
-/*
-// =================================================================================================
-// 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.
-// =================================================================================================
-*/
-
-#define kXMP_Copyright Copyright (c) 2002-2008, Adobe Systems Incorporated
-#define kXMP_CopyrightStr "Copyright (c) 2002-2008, Adobe Systems Incorporated"
-#define kXMP_AdobeIPStr "<AdobeIP#0000425>"
-
-#endif /* __XMP_BuildInfo_h__ */
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPFiles.hpp b/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPFiles.hpp
deleted file mode 100644
index 857f8ae541..0000000000
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPFiles.hpp
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef __WXMPFiles_hpp__
-#define __WXMPFiles_hpp__ 1
-
-// =================================================================================================
-// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-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 "client-glue/WXMP_Common.hpp"
-
-namespace DngXmpSdk {
-
-#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)
-
-// =================================================================================================
-
-#define zXMPFiles_GetVersionInfo_1(versionInfo) \
- WXMPFiles_GetVersionInfo_1 ( versionInfo /* no wResult */ )
-
-#define zXMPFiles_Initialize_1() \
- WXMPFiles_Initialize_1 ( &wResult )
-
-#define zXMPFiles_Initialize_2(options) \
- WXMPFiles_Initialize_2 ( options, &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_OpenFile_1(filePath,format,openFlags) \
- WXMPFiles_OpenFile_1 ( this->xmpFilesRef, filePath, format, openFlags, &wResult )
-
-#define zXMPFiles_CloseFile_1(closeFlags) \
- WXMPFiles_CloseFile_1 ( this->xmpFilesRef, closeFlags, &wResult )
-
-#define zXMPFiles_GetFileInfo_1(filePath,filePathLen,openFlags,format,handlerFlags) \
- WXMPFiles_GetFileInfo_1 ( this->xmpFilesRef, filePath, filePathLen, openFlags, format, handlerFlags, &wResult )
-
-#define zXMPFiles_SetAbortProc_1(abortProc,abortArg) \
- WXMPFiles_SetAbortProc_1 ( this->xmpFilesRef, abortProc, abortArg, &wResult )
-
-#define zXMPFiles_GetXMP_1(xmpRef,xmpPacket,xmpPacketLen,packetInfo) \
- WXMPFiles_GetXMP_1 ( this->xmpFilesRef, xmpRef, xmpPacket, xmpPacketLen, packetInfo, &wResult )
-
-#define zXMPFiles_GetThumbnail_1(tnailInfo) \
- WXMPFiles_GetThumbnail_1 ( this->xmpFilesRef, tnailInfo, &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 )
-
-// =================================================================================================
-
-extern void WXMPFiles_GetVersionInfo_1 ( XMP_VersionInfo * versionInfo );
-
-extern void WXMPFiles_Initialize_1 ( WXMP_Result * result );
-
-extern void WXMPFiles_Initialize_2 ( XMP_OptionBits options, WXMP_Result * result );
-
-extern void WXMPFiles_Terminate_1();
-
-extern void WXMPFiles_CTor_1 ( WXMP_Result * result );
-
-extern void WXMPFiles_UnlockLib_1();
-
-extern void WXMPFiles_UnlockObj_1 ( XMPFilesRef xmpFilesRef );
-
-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_OpenFile_1 ( XMPFilesRef xmpFilesRef,
- XMP_StringPtr filePath,
- XMP_FileFormat format,
- XMP_OptionBits openFlags,
- WXMP_Result * result );
-
-extern void WXMPFiles_CloseFile_1 ( XMPFilesRef xmpFilesRef,
- XMP_OptionBits closeFlags,
- WXMP_Result * result );
-
-extern void WXMPFiles_GetFileInfo_1 ( XMPFilesRef xmpFilesRef,
- XMP_StringPtr * filePath,
- XMP_StringLen * filePathLen,
- XMP_OptionBits * openFlags, // ! Can be null.
- XMP_FileFormat * format, // ! Can be null.
- XMP_OptionBits * handlerFlags, // ! Can be null.
- 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.
- XMP_StringPtr * xmpPacket,
- XMP_StringLen * xmpPacketLen,
- XMP_PacketInfo * packetInfo, // ! Can be null.
- WXMP_Result * result );
-
-extern void WXMPFiles_GetThumbnail_1 ( XMPFilesRef xmpFilesRef,
- XMP_ThumbnailInfo * tnailInfo, // ! Can be null.
- 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 );
-
-// =================================================================================================
-
-#if __cplusplus
-}
-#endif
-
-} //namespace
-
-#endif // __WXMPFiles_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPFiles.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPFiles.hpp
similarity index 59%
rename from core/libs/dngwriter/extra/xmp_sdk/include/TXMPFiles.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPFiles.hpp
index 8789717262..aeecda9c57 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPFiles.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPFiles.hpp
@@ -1,638 +1,854 @@
#ifndef __TXMPFiles_hpp__
-#define __TXMPFiles_hpp__ 1
+#define __TXMPFiles_hpp__ 1
#if ( ! __XMP_hpp__ )
#error "Do not directly include, use XMP.hpp"
#endif
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2007 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 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.
// =================================================================================================
-namespace DngXmpSdk {
+
+#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();
+ 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 only one option is defined, \c kXMPFiles_NoQuickTimeInit. This option
- /// prevents calling the QuickTime initialization on Windows, which can be slow. The MOV file
- /// handler on Windows uses Apple's QuickTime SDK for the actual file I/O.
+ /// 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 );
+ 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();
+ 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();
+ 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 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_OpenCacheTNail
/// \li \c #kXMPFiles_OpenStrictly
/// \li \c #kXMPFiles_OpenUseSmartHandler
/// \li \c #kXMPFiles_OpenUsePacketScanning
/// \li \c #kXMPFiles_OpenLimitedScanning
- /// \li \c #kXMPFiles_OpenInBackground
///
/// @return The new \c TXMPFiles object.
TXMPFiles ( XMP_StringPtr filePath,
- XMP_FileFormat format = kXMP_UnknownFile,
- XMP_OptionBits openFlags = 0 );
+ 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.
+ /// 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 );
+ 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 );
+ 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_ReturnsTNail - File handler returns native thumbnail information.
/// \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 );
+ 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.
///
- /// \c CheckFileFormat tries to determine the format of a file, returning an XMP_FileFormat value.
- /// It uses the same logic as \c OpenFile will use to select a smart handler.
+ /// 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, otherwise \c kXMP_UnknownFile.
+ /// @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.
///
- /// \c CheckPackageFormat tries to determine the format of a "package" given the name of the top
- /// level folder, returning an 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.
+ /// 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. The path is not the same as would be passed
- /// to \c OpenFile. For example the path passed to \c CheckPackageFormat might be ".../MyMovie",
- /// while the path passed to \c OpenFile would be ".../MyMovie/SomeClip".
+ /// @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 a smart handler would be selected, otherwise \c kXMP_UnknownFile.
-
+ /// @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 handler supports native thumbnails and \c #kXMPFiles_OpenCacheTNail
- /// is passed, the native thumbnail is cached.
+ /// 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_OpenCacheTNail - Cache thumbnail if possible, GetThumbnail will be called.
/// \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
+ /// 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 );
+ 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.
+ /// 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 );
+ 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 );
+ 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 );
+ 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 GetThumbnail() retrieves the native thumbnail from an open file.
- ///
- /// Use this function to obtain native thumbnail information, if the associated file handler
- /// supports that and the thumbnail was cached by the call to \c OpenFile(); that is, the
- /// \c #kXMPFiles_OpenCacheTNail option flag was set. The return value reports whether a thumbnail
- /// is present in the file.
- ///
- /// The returned thumbnail information can be incomplete, depending on the file format, the file
- /// handler's capabilities, and the specific file content.
- ///
- /// \li The \c #XMP_ThumbnailInfo::fullWidth, \c fullHeight, and \c fullOrientation fields are
- /// only meaningful for image files. They are not meaningful for multi-page files such as PDF
- /// or InDesign, for dynamic audio or video files, and so on. The field values are zero if not
- /// meaningful or not determined.
- /// \li The \c #XMP_ThumbnailInfo::tnailImage and \c #XMP_ThumbnailInfo::tnailSize fields
- /// might be zero even if a recognized thumbnail is present.
- ///
- /// Being recognized means only that the handler has determined that the file does contain a
- /// native thumbnail. The thumbnail data might be of a format that the file handler cannot
- /// return as a single contiguous block of thumbnail data. For example, for a TIFF uncompressed
- /// thumbnail, the handler might not have logic to gather the various disjoint pieces of the
- /// thumbnail from the overall TIFF stream.
- ///
- /// @param tnailInfo [out] Optional. A buffer in which to return information about a recognized
- /// native thumbnail, and related information about the primary image if appropriate. Can be
- /// null if the information is not desired.
- ///
- /// @return True if a recognized native thumbnail is present and the thumbnail was cached by the
- /// call to \c OpenFile(); that is, the \c #kXMPFiles_OpenCacheTNail option flag was set. Can
- /// return true even if the function cannot retrieve the actual thumbnail image.
-
- bool GetThumbnail ( XMP_ThumbnailInfo * tnailInfo );
+ 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.
+ /// 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.
- ///
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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.
+ /// 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;
-}; // class TXMPFiles
+ XMPFilesRef xmpFilesRef;
-} //namespace
+ // 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/core/libs/dngwriter/extra/xmp_sdk/include/TXMPIterator.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPIterator.hpp
similarity index 97%
rename from core/libs/dngwriter/extra/xmp_sdk/include/TXMPIterator.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPIterator.hpp
index 32e515f196..603db687c1 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPIterator.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPIterator.hpp
@@ -1,239 +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-2007 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_IterIncludeAliases - Include aliases as part of the iteration. Since aliases are
-/// not actual nodes the default iteration does not visit them.
/// \li \c #kXMP_IterOmitQualifiers - Do not visit the qualifiers of a node.
// =================================================================================================
#include "client-glue/WXMPIterator.hpp"
-namespace DngXmpSdk {
-
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.
-}; // class TXMPIterator
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
-} //namespace
+}; // class TXMPIterator
// =================================================================================================
#endif // __TXMPIterator_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPMeta.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPMeta.hpp
similarity index 90%
rename from core/libs/dngwriter/extra/xmp_sdk/include/TXMPMeta.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPMeta.hpp
index 6695d38926..5a3e576f94 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPMeta.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPMeta.hpp
@@ -1,1817 +1,1756 @@
#ifndef __TXMPMeta_hpp__
#define __TXMPMeta_hpp__ 1
#if ( ! __XMP_hpp__ )
#error "Do not directly include, use XMP.hpp"
#endif
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+ #include "XMPCore/XMPCoreFwdDeclarations.h"
+#endif
+
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2008 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.
+/// 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.
// =================================================================================================
-namespace DngXmpSdk {
-
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 );
- // ---------------------------------------------------------------------------------------------
- /// @brief \c DumpAliases() sends the list of registered aliases and corresponding actuals 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 DumpAliases ( 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 );
/// @}
- // ---------------------------------------------------------------------------------------------
- /// \name Alias functions
- /// @{
- ///
- /// Aliases in XMP serve the same purpose as Windows file shortcuts, Mac OS file aliases, or
- /// UNIX file symbolic links. The aliases are multiple names for the same property. One
- /// distinction of XMP aliases is that they are ordered. An alias name points to an actual name;
- /// the primary significance of the actual name is that it is the preferred name for output,
- /// generally the most widely recognized name.
- ///
- /// XMP restricts the names that can be aliased. The alias must be a top-level property name,
- /// not a field within a structure or an element within an array. The actual can be a top-level
- /// property name, the first element within a top-level array, or the default element in an
- /// alt-text array. This does not mean the alias can only be a simple property; you can alias a
- /// top-level structure or array to an identical top-level structure or array, or to the first
- /// item of an array of structures.
-
- // ---------------------------------------------------------------------------------------------
- /// @brief \c RegisterAlias() associates an alias name with an actual name.
- ///
- /// Defines an alias mapping from one namespace/property to another. Both property names must be
- /// simple names. An alias can be a direct mapping, where the alias and actual have the same
- /// data type. It is also possible to map a simple alias to an item in an array. This can either
- /// be to the first item in the array, or to the 'x-default' item in an alt-text array. Multiple
- /// alias names can map to the same actual, as long as the forms match. It is a no-op to
- /// reregister an alias in an identical fashion.
- ///
- /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
- ///
- /// @param aliasNS The namespace URI for the alias. Must not be null or the empty string.
- ///
- /// @param aliasProp The name of the alias. Must be a simple name, not null or the empty string
- /// and not a general path expression.
- ///
- /// @param actualNS The namespace URI for the actual. Must not be null or the empty string.
- ///
- /// @param actualProp The name of the actual. Must be a simple name, not null or the empty string
- /// and not a general path expression.
- ///
- /// @param arrayForm Provides the array form for simple aliases to an array item. This is needed
- /// to know what kind of array to create if set for the first time via the simple alias. Pass
- /// \c #kXMP_NoOptions, the default value, for all direct aliases regardless of whether the actual
- /// data type is an array or not. One of these constants:
- ///
- /// \li \c #kXMP_NoOptions - This is a direct mapping. The actual data type does not matter.
- /// \li \c #kXMP_PropValueIsArray - The actual is an unordered array, the alias is to the
- /// first element of the array.
- /// \li \c #kXMP_PropArrayIsOrdered - The actual is an ordered array, the alias is to the
- /// first element of the array.
- /// \li \c #kXMP_PropArrayIsAlternate - The actual is an alternate array, the alias is to the
- /// first element of the array.
- /// \li \c #kXMP_PropArrayIsAltText - The actual is an alternate text array, the alias is to
- /// the 'x-default' element of the array. */
-
- static void RegisterAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr actualNS,
- XMP_StringPtr actualProp,
- XMP_OptionBits arrayForm = kXMP_NoOptions );
-
- // ---------------------------------------------------------------------------------------------
- /// @brief \c ResolveAlias() reports whether a name is an alias, and what it is aliased to.
- ///
- /// Output strings are not written until return, so you can use this to
- /// "reduce" a path to the base form as follows:
- /// <pre>
- /// isAlias = SXMPMeta::ResolveAlias ( ns.c_str(), path.c_str(), &ns, &path, 0 );
- /// </pre>
- /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
- ///
- /// @param aliasNS The namespace URI for the alias. Must not be null or the empty string.
- ///
- /// @param aliasProp The name of the alias. Can be an arbitrary path expression path, must not
- /// null or the empty string.
- ///
- /// @param actualNS [out] A string object in which to return the namespace URI for the actual.
- /// Not modified if the given name is not an alias. Can be null if the namespace URI is not wanted.
- ///
- /// @param actualProp [out] A string object in which to return the path of the actual.
- /// Not modified if the given name is not an alias. Can be null if the actual's path is not wanted.
- ///
- /// @param arrayForm [out] A string object in which to return the array form of the actual. This
- /// is 0 (\c #kXMP_NoOptions) if the alias and actual forms match, otherwise it is the options
- /// passed to \c TXMPMeta::RegisterAlias(). Not modified if the given name is not an alias. Can
- /// be null if the actual's array form is not wanted.
- ///
- /// @return True if the provided name is an alias.
-
- static bool ResolveAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- tStringObj * actualNS,
- tStringObj * actualProp,
- XMP_OptionBits * arrayForm );
-
- // ---------------------------------------------------------------------------------------------
- /// @brief \c DeleteAlias() deletes an alias.
- ///
- /// This deletes only the registration of the alias, it does not delete the actual property.
- /// It deletes any view of the property through the alias name.
- ///
- /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
- ///
- /// @param aliasNS The namespace URI for the alias. Must not be null or the empty string.
- ///
- /// @param aliasProp The name of the alias. Must be a simple name, not null or the empty string
- /// and not a general path expression. It is not an error to provide
- /// a name that has not been registered as an alias.
-
- static void DeleteAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp );
-
- // ---------------------------------------------------------------------------------------------
- /// @brief \c RegisterStandardAliases() registers all of the built-in aliases for a standard namespace.
- ///
- /// The built-in aliases are documented in the XMP Specification. This function registers the
- /// aliases in the given namespace; that is, it creates the aliases from this namespace to
- /// actuals in other namespaces.
- ///
- /// This function is static; make the call directly from the concrete class (\c SXMPMeta).
- ///
- /// @param schemaNS The namespace URI for the aliases. Must not be null or the empty string.
-
- static void RegisterStandardAliases ( XMP_StringPtr schemaNS );
-
- /// @}
-
// =============================================================================================
// 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. Can be null or the empty string if the first component of the \c propName path
- /// contains a namespace prefix.
+ /// 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,
- long * propValue,
+ 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,
- long long * propValue,
+ 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,
- long propValue,
+ 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,
- long long propValue,
+ 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_WriteAliasComments - Include XML comments for aliases.
/// \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_WriteAliasComments - Include XML comments for aliases.
/// \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 functions \c DumpNamespaces() and \c DumpAliases()
+ /// @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
-}; // class TXMPMeta
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
-} //namespace
+}; // class TXMPMeta
#endif // __TXMPMeta_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPUtils.hpp
similarity index 88%
rename from core/libs/dngwriter/extra/xmp_sdk/include/TXMPUtils.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPUtils.hpp
index 7e2127ef64..79ade07a24 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/TXMPUtils.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/TXMPUtils.hpp
@@ -1,968 +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-2008 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
// =================================================================================================
-namespace DngXmpSdk {
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.
+ /// 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.
+ /// 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. If the
- /// time zone is already UTC, the value is not modified.
+ /// 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.
- /// If the time zone is already the local zone, the value is not modified.
+ /// 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 AppendProperties() adds or moves properties from one XMP object to another.
- ///
- /// The default operation is to append only external properties that do not already exist in the
- /// destination. Option flags allow you to add internal properties, and to merge values of
- /// properties that exist in both the source and destination.
- ///
- /// \li \c #kXMPUtil_DoAllProperties: Operate on all top-level properties, external and
- /// internal. You can use this flag together with \c #kXMPUtil_ReplaceOldValues to replace the
- /// values of existing top-level properties.
- ///
- /// \li \c #kXMPUtil_ReplaceOldValues: Propogate all top-level properties from the source to
- /// the destination, replacing any existing values. The values of properties in the
- /// destination that are not in the source are not modified.<br>
- /// The keep-or-replace-old notion also applies within structs and arrays. Top-level
- /// properties are added to the destination if they do not already exist. If they do exist but
- /// differ in form (simple/struct/array) then the destination is not modified. If the forms
- /// match, simple properties are left unchanged, while structs and arrays are merged.<br>
- /// Do not use this option when the processing is more complicated. <<than what??>>
- ///
- /// \li \c #kXMPUtil_DeleteEmptyValues: An empty value in the source XMP causes the
- /// corresponding destination property to be deleted. By default, empty values are treated in
- /// the same way as non-empty values. An empty value is a simple empty string, an array with
- /// no items,or a struct with no fields. Qualifiers are ignored.
- ///
- /// The detailed behavior is defined by the following pseudo-code:
- ///
- /// <pre>
- /// AppendProperties ( sourceXMP, destXMP, options ):
- /// doAll = options & kXMPUtil_DoAllProperties
- /// replaceOld = options & kXMPUtil_ReplaceOldValues
- /// deleteEmpty = options & kXMPUtil_DeleteEmptyValues
- /// for all source schema (top level namespaces):
- /// for all top level properties in sourceSchema:
- /// if doAll or prop is external:
- /// AppendSubtree ( sourceNode, destSchema, replaceOld, deleteEmpty )
- ///
- /// AppendSubtree ( sourceNode, destParent, replaceOld, deleteEmpty ):
- /// if deleteEmpty and source value is empty:
- /// delete the corresponding child from destParent
- /// else if sourceNode not in destParent (by name):
- /// copy sourceNode's subtree to destParent
- /// else if replaceOld:
- /// delete subtree from destParent
- /// copy sourceNode's subtree to destParent
- /// else: // (Already exists in dest and not replacing, merge structs and arrays)
- /// if sourceNode and destNode forms differ:
- /// return, leave the destNode alone
- /// else if form is a struct:
- /// for each field in sourceNode:
- /// AppendSubtree ( sourceNode.field, destNode, replaceOld )
- /// else if form is an alt-text array:
- /// copy new items by xml:lang value into the destination
- /// else if form is an array:
- /// copy new items by value into the destination, ignoring order and duplicates
- /// </pre>
- ///
- /// Array item checking is n-squared; this can be time-intensive if the replace-old options 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 source The source XMP object.
- ///
- /// @param dest The destination XMP object.
- ///
- /// @param options Option flags to control the copying. A logical OR of these bit-flag constants:
- /// \li \c kXMPUtil_DoAllProperties - Operate on internal properties in addition to external properties.
- /// \li \c kXMPUtil_ReplaceOldValues - Replace the values of existing properties.
- /// \li \c kXMPUtil_DeleteEmptyValues - Delete properties if the new value is empty.
-
- static void AppendProperties ( const TXMPMeta<tStringObj> & source,
- TXMPMeta<tStringObj> * dest,
- 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:
-}; // class TXMPUtils
+ static void SetClientString ( void * clientPtr, XMP_StringPtr valuePtr, XMP_StringLen valueLen );
-} //namespace
+}; // class TXMPUtils
// =================================================================================================
#endif // __TXMPUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/XMP.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP.hpp
similarity index 97%
rename from core/libs/dngwriter/extra/xmp_sdk/include/XMP.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/XMP.hpp
index 277a00cc7c..8ec39eb9b0 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/XMP.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP.hpp
@@ -1,102 +1,98 @@
#ifndef __XMP_hpp__
#define __XMP_hpp__ 1
// =================================================================================================
-// Copyright 2002-2007 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.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"
-namespace DngXmpSdk {
typedef class TXMPMeta <TXMP_STRING_TYPE> SXMPMeta; // For client convenience.
typedef class TXMPIterator <TXMP_STRING_TYPE> SXMPIterator;
typedef class TXMPUtils <TXMP_STRING_TYPE> SXMPUtils;
-} //namespace
#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.
-namespace DngXmpSdk {
typedef class TXMPFiles <TXMP_STRING_TYPE> SXMPFiles;
-} //namespace
#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/core/libs/dngwriter/extra/xmp_sdk/include/XMP.incl_cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP.incl_cpp
similarity index 94%
rename from core/libs/dngwriter/extra/xmp_sdk/include/XMP.incl_cpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/XMP.incl_cpp
index 612505b889..fe2a6fa229 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/XMP.incl_cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP.incl_cpp
@@ -1,71 +1,69 @@
#ifndef __XMP_incl_cpp__
#define __XMP_incl_cpp__ 1
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2007 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"
-namespace DngXmpSdk {
template class TXMPMeta <TXMP_STRING_TYPE>;
template class TXMPIterator <TXMP_STRING_TYPE>;
template class TXMPUtils <TXMP_STRING_TYPE>;
-} //namespace
#if XMP_INCLUDE_XMPFILES
#include "client-glue/TXMPFiles.incl_cpp"
-namespace DngXmpSdk {
template class TXMPFiles <TXMP_STRING_TYPE>;
-} //namespace
- #endif
+ #endif
#endif
#if XMP_WinBuild
#pragma warning ( pop )
#endif
#endif // __XMP_incl_cpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h
new file mode 100644
index 0000000000..e7ba7c64d0
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h
@@ -0,0 +1,225 @@
+//!
+//! @file IConfigurable.h
+//!
+
+#ifndef IConfigurable_h__
+#define IConfigurable_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Interface that allows to attach various key-value parameters to the underlying object.
+ //!
+ //! \details Key is an unsigned 64-bit integer value which can be a char buffer of eight characters also.
+ //! \note For all value types except user data ( const void * ) or char buffer ( const char * ) a copy is made
+ //! and is stored, so the scope is maintained internally. But for user data ( const void * ) or char buffer
+ //! ( const char * ) its clients responsibility to make sure these pointers remain valid through out the life
+ //! span of the object or objects derived from it.
+ //!
+ class XMP_PUBLIC IConfigurable
+ {
+ public:
+
+ //!
+ //! @brief Indicates various types of parameter values.
+ //!
+ typedef enum {
+ //!< Data type is none.
+ kDTNone = 0,
+ //!< Data type is boolean.
+ kDTBool = 1 << 0,
+ //!< Data type is unsigned 64 bit integer.
+ kDTUint64 = 1 << 1,
+ //!< Data type is signed 64 bit integer.
+ kDTInt64 = 1 << 2,
+ //!< Data type is character.
+ kDTChar = 1 << 3,
+ //!< Data type is double.
+ kDTDouble = 1 << 4,
+ //!< Data type is char buffer.
+ kDTConstCharBuffer = 1 << 5,
+ //!< Data type is user data ( pointer to const void ).
+ kDTConstVoidPtr = 1 << 6,
+
+ //!< Maximum value this enum can hold.
+ kDTAll = 0xFFFFFFFF
+ } eDataType;
+
+ //!
+ //! @{
+ //! @brief Add/Change a value of a parameter.
+ //! \param[in] key An unsigned 64 bit integer value indicating the key.
+ //! \param[in] value New value of the parameter.
+ //! \attention Error is thrown in case
+ //! - the previous type of value associated with key is of different type.
+ //! - the type of value associated with key is not as expected.
+ //!
+ virtual void APICALL SetParameter( const uint64 & key, bool value ) = 0;
+ virtual void APICALL SetParameter( const uint64 & key, uint64 value ) = 0;
+ virtual void APICALL SetParameter( const uint64 & key, int64 value ) = 0;
+ virtual void APICALL SetParameter( const uint64 & key, double value ) = 0;
+ virtual void APICALL SetParameter( const uint64 & key, char value ) = 0;
+ virtual void APICALL SetParameter( const uint64 & key, const char * value ) = 0;
+ virtual void APICALL SetParameter( const uint64 & key, const void * value ) = 0;
+ //! @}
+
+ //!
+ //! @brief Removes a particular parameter if present.
+ //! \param[in] key An unsigned 64 bit integer value indicating the key.
+ //! \return True in case key was present and is deleted.
+ //! \attention Error is thrown in case
+ //! - key is a must have for the underlying object.
+ //!
+ virtual bool APICALL RemoveParameter( const uint64 & key ) = 0;
+
+ //!
+ //! @{
+ //! @brief Get the value of a parameter if present.
+ //! \param[in] key An unsigned 64 bit integer value indicating the key.
+ //! \param[out] value The value of the parameter.
+ //! \return false if no such parameter is present, otherwise true.
+ //! \attention Error is thrown in case the type of the parameter is not
+ //! the one client is asking for.
+ //!
+ virtual bool APICALL GetParameter( const uint64 & key, bool & value ) const = 0;
+ virtual bool APICALL GetParameter( const uint64 & key, uint64 & value ) const = 0;
+ virtual bool APICALL GetParameter( const uint64 & key, int64 & value ) const = 0;
+ virtual bool APICALL GetParameter( const uint64 & key, double & value ) const = 0;
+ virtual bool APICALL GetParameter( const uint64 & key, char & value ) const = 0;
+ virtual bool APICALL GetParameter( const uint64 & key, const char * & value ) const = 0;
+ virtual bool APICALL GetParameter( const uint64 & key, const void * & value ) const = 0;
+ //! @}
+
+ //!
+ //! @brief Get all the keys of the parameters associated with the object.
+ //! \details Provide a std::vector containing the keys of all the parameters associated with the object.
+ //! \return A std::vector of unsigned 64 bit integers.
+ //!
+ virtual std::vector< uint64 > APICALL GetAllParameters() const = 0;
+
+ //!
+ //! @brief Get the number of parameters associated with the object.
+ //!
+ virtual sizet APICALL Size() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Get the value type of a particular parameter.
+ //! \param[in] key An unsigned 64 bit integer value indicating the key.
+ //! \return A value of type eDataType indicating the type of value the parameter is supposed to hold.
+ //! \note return kDTNone in case no such key is associated with the object.
+ //!
+ virtual eDataType APICALL GetDataType( const uint64 & key ) const = 0;
+
+ //!
+ //! @brief Utility function to convert character buffer ( maximum of 8 characters ) to uint64 representation.
+ //! \param[in] key A pointer to const char buffer, maximum characters used are 8 provided there is no
+ //! null character present in the buffer between 1st to 8 characters, otherwise characters upto NULL
+ //! character (excluding NULL) are read.
+ //! \return A 64-bit unsigned integer representing the first 8 characters of the character buffer.
+ //! \note Return 0 in case key is NULL.
+ //!
+ static uint64 ConvertCharBufferToUint64( const char * key ) {
+ uint64 keyAsuint64 = 0;
+ if ( key ) {
+ for ( int i = 0; i < 8 && key[ i ] != '\0'; i++ ) {
+ keyAsuint64 = keyAsuint64 << 8;
+ keyAsuint64 += ( unsigned char ) key[ i ];
+ }
+ }
+ return keyAsuint64;
+ }
+
+ //!
+ //! @brief A union data type to store all kind of values.
+ //!
+ union CombinedDataValue {
+ bool boolValue;
+ uint32 uint32Value;
+ uint64 uint64Value;
+ int64 int64Value;
+ double doubleValue;
+ char charValue;
+ const char * constCharPtrValue;
+ const void * constVoidPtrValue;
+ };
+
+ protected:
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ // all safe functions
+ virtual void APICALL setParameter( const uint64 & key, uint32 dataType, const CombinedDataValue & dataValue, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL removeParameter( const uint64 & key, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL getParameter( const uint64 & key, uint32 dataType, CombinedDataValue & value, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual void APICALL getAllParameters( uint64 * array, sizet count ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL getDataType( const uint64 & key, pcIError_base & error ) const __NOTHROW__ = 0;
+ //! \endcond
+
+ protected:
+ //!
+ //! protected Virtual Destructor
+ //!
+ virtual ~IConfigurable() __NOTHROW__ {};
+
+ friend class IConfigurableProxy;
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ };
+
+//! \cond XMP_INTERNAL_DOCUMENTATION
+#if !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+
+ class IConfigurableProxy
+ : public virtual IConfigurable {
+ public:
+ IConfigurableProxy( pIConfigurable configurable );
+ virtual void APICALL SetParameter( const uint64 & key, bool value );
+ virtual void APICALL SetParameter( const uint64 & key, uint64 value );
+ virtual void APICALL SetParameter( const uint64 & key, int64 value );
+ virtual void APICALL SetParameter( const uint64 & key, double value );
+ virtual void APICALL SetParameter( const uint64 & key, char value );
+ virtual void APICALL SetParameter( const uint64 & key, const char * value );
+ virtual void APICALL SetParameter( const uint64 & key, const void * value );
+ virtual void APICALL setParameter( const uint64 & key, uint32 dataType, const CombinedDataValue & dataValue, pcIError_base & error ) __NOTHROW__;
+
+ virtual bool APICALL RemoveParameter( const uint64 & key );
+ virtual uint32 APICALL removeParameter( const uint64 & key, pcIError_base & error ) __NOTHROW__;
+
+ virtual bool APICALL GetParameter( const uint64 & key, bool & value ) const;
+ virtual bool APICALL GetParameter( const uint64 & key, uint64 & value ) const;
+ virtual bool APICALL GetParameter( const uint64 & key, int64 & value ) const;
+ virtual bool APICALL GetParameter( const uint64 & key, double & value ) const;
+ virtual bool APICALL GetParameter( const uint64 & key, char & value ) const;
+ virtual bool APICALL GetParameter( const uint64 & key, const char * & value ) const;
+ virtual bool APICALL GetParameter( const uint64 & key, const void * & value ) const;
+ virtual uint32 APICALL getParameter( const uint64 & key, uint32 dataType, CombinedDataValue & value, pcIError_base & error ) const __NOTHROW__;
+
+ virtual std::vector< uint64 > APICALL GetAllParameters() const;
+ virtual void APICALL getAllParameters( uint64 * array, sizet count ) const __NOTHROW__;
+
+ virtual sizet APICALL Size() const __NOTHROW__;
+
+ virtual eDataType APICALL GetDataType( const uint64 & key ) const;
+ virtual uint32 APICALL getDataType( const uint64 & key, pcIError_base & error ) const __NOTHROW__;
+
+ protected:
+ pIConfigurable mConfigurableRawPtr;
+ };
+
+#endif // !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+//! \endcond
+
+}
+
+#endif // IConfigurable_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h
new file mode 100644
index 0000000000..4b5f86f27c
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h
@@ -0,0 +1,71 @@
+#ifndef __ISharedObject_h__
+#define __ISharedObject_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Interface that serves as the base interface of all the externally exposed interfaces.
+ //! \details This allows all interfaces to be used as shared pointers so as to reduce the burden of
+ //! scope management from the client or library code. It makes the heap allocated object to be self manged in
+ //! in terms of memory and life. This provides functions so as to inform the actual object when a shared pointer
+ //! is created or destroyed and appropriately release the memory during the last call to Release.
+ //! \attention Supports Multi-threading at object level through use of Atomic Variables.
+ //! \note Any interface which inherits from this needs to make sure that its destructor is declared protected
+ //! so that unknowingly also client of this object cannot call delete on the object.
+ //!
+
+ class XMP_PUBLIC ISharedObject {
+ public:
+
+ //!
+ //! @brief Called by the clients of the object to indicate that he has acquired the shared ownership of the object.
+ //!
+ virtual void APICALL Acquire() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Called by the clients of the object to indicate he has released his shared ownership of the object.
+ //! If this being the last client than this function should call Destroy to delete and release the memory.
+ //!
+ virtual void APICALL Release() const __NOTHROW__ = 0;
+
+ //! @{
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ //! Return the pointer to the internal Shared Object interface
+ //! \return either a const or non const pointer to internal ISharedObject_I interface.
+ virtual AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCommon_Int::pcISharedObject_I GetISharedObject_I() const __NOTHROW__ {
+ return const_cast< ISharedObject * >( this )->GetISharedObject_I();
+ }
+ //! \endcond
+ //! @}
+
+ protected:
+
+ //!
+ //! protected virtual destructor.
+ //!
+ virtual ~ISharedObject() __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+
+ REQ_FRIEND_CLASS_DECLARATION();
+ };
+
+ inline ISharedObject::~ISharedObject() __NOTHROW__ { }
+
+};
+
+#endif // __ISharedObject_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IThreadSafe.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IThreadSafe.h
new file mode 100644
index 0000000000..b0ed4b5458
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IThreadSafe.h
@@ -0,0 +1,75 @@
+//! @file IThreadSafe.h
+#ifndef IThreadSafe_h__
+#define IThreadSafe_h__ 1
+
+//
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Interface that serves as the base interface for all the externally exposed interfaces which needs to provide client configurable thread safety.
+ //!
+ //! \attention In case client has disabled thread safety at the module level these functions will
+ //! have no use.
+ //! \note By default all the objects created are not thread safe.
+ //!
+ class XMP_PUBLIC IThreadSafe
+ {
+ public:
+
+ //!
+ //! @brief Enables the thread safety on an object.
+ //! @details After calling this function the object can be used across multiple threads.
+ //!
+ virtual void APICALL EnableThreadSafety() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Disables the thread safety on an object.
+ //! @details After calling this function the object should not be used across multiple threads.
+ //!
+ virtual void APICALL DisableThreadSafety() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Informs whether object can be used across multiple threads or not.
+ //! \returns bool value; true in case object can be used across multiple threads, false
+ //! otherwise.
+ //!
+ virtual bool APICALL IsThreadSafe() const = 0;
+
+ //! @{
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ //! @brief Return the pointer to the internal Thread Safe interface
+ //! \return either a const or non const pointer to internal IThreadSafe_I interface.
+ virtual AdobeXMPCommon_Int::pIThreadSafe_I APICALL GetIThreadSafe_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCommon_Int::pcIThreadSafe_I GetIThreadSafe_I() const __NOTHROW__ {
+ return const_cast< IThreadSafe * >( this )->GetIThreadSafe_I();
+ }
+ //! \endcond
+ //! @}
+
+ protected:
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ //! @brief all safe functions
+ virtual uint32 APICALL isThreadSafe() const __NOTHROW__ = 0;
+ //! \endcond
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ };
+
+}
+#endif // IThreadSafe_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IVersionable.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IVersionable.h
new file mode 100644
index 0000000000..ec6074778a
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/BaseInterfaces/IVersionable.h
@@ -0,0 +1,71 @@
+#ifndef IVersionable_h__
+#define IVersionable_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Interface that serves as the base interface for all the externally exposed interfaces
+ //! which needs to provide evolving versions of the interface.
+ //! @details Provide pointer to interface requested by client.
+ //! Requirements on the class type
+ //! -# Need to implement a function GetInterfaceID() returning a unique id for the
+ //! interface. Only required to be implemented in first version of the interface.
+ //! -# Need to implement a function GetVersionNumber() returning the version of the
+ //! interface. Required to implemented by each version of the interface.
+ //!
+
+ class XMP_PUBLIC IVersionable {
+ public:
+
+ //!
+ //! @brief Get the raw pointer to an interface object implementing the requested version.
+ //! \return a raw pointer to an interface object implementing the requested version.
+ //! \attention In case a particular version number is not supported than an error is
+ //! thrown.
+ //!
+ template< typename requestedInterface >
+ XMP_PRIVATE requestedInterface * GetInterfacePointer() {
+ pvoid ptr = GetInterfacePointer( requestedInterface::GetInterfaceID(),
+ requestedInterface::GetInterfaceVersion() );
+ return static_cast< requestedInterface * >( ptr );
+ }
+
+ //!
+ //! @brief Get the raw pointer to a const interface object implementing the requested version.
+ //! \return a raw pointer to a const interface object implementing the requested version.
+ //! \attention In case a particular version number is not supported than an error is
+ //! thrown.
+ //!
+ template< typename requestedInterface >
+ XMP_PRIVATE const requestedInterface * GetInterfacePointer() const {
+ return const_cast< IVersionable * >( this )->GetInterfacePointer< requestedInterface >();
+ }
+
+ protected:
+ virtual ~IVersionable() {}
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) = 0;
+ // all safe functions
+ virtual pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ = 0;
+ //! \endcond
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ };
+
+}
+
+#endif // IVersionable_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IConfigurationManager.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IConfigurationManager.h
new file mode 100644
index 0000000000..5581749cda
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IConfigurationManager.h
@@ -0,0 +1,167 @@
+//! @file IConfigurationManager.h
+
+#ifndef IConfigurationManager_h__
+#define IConfigurationManager_h__ 1
+
+//
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+#include "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! @class IConfigurationManager_v1
+ //! \brief Version1 of the interface that represents configuration settings controllable by the client.
+ //! \details Provides functions through which client can plug in its own memory allocators, error notifiers.
+ //! \attention Not Thread Safe as this functionality is generally used at the initialization phase.
+ //!
+ class XMP_PUBLIC IConfigurationManager_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Allows the client to plug in its own memory allocation procedures which will be used to allocate/deallocate memory from the heap.
+ //!
+ //! \param[in] memoryAllocator A pointer to an object of type AdobeXMPCommon::IMemoryAllocator.
+ //! NULL pointer will switch to default allocator built in the library.
+ //! \return A value of bool type; true means successful and false otherwise.
+ //!
+ virtual bool APICALL RegisterMemoryAllocator( pIMemoryAllocator memoryAllocator ) = 0;
+
+ //!
+ //! @brief Allows the client to plug in its own error notification procedures which will be used to
+ //! inform client about various warnings and errors.
+ //! \param[in] clientErrorNotifier A pointer to an object of type AdobeXMPCommon::IErrorNotifier. NULL
+ //! pointer means client no longer wants to be notified of any warnings or errors.
+ //! \return a value of bool type; true means successful and false otherwise.
+ //!
+ virtual bool APICALL RegisterErrorNotifier( pIErrorNotifier_base clientErrorNotifier ) = 0;
+
+ //!
+ //! @brief Allows the client to disable the support for multi threading inside the library.
+ //! By default library supports multi-threading.
+ //! \return A value of bool type; true means successful and false otherwise.
+ //!
+ virtual bool APICALL DisableMultiThreading() = 0;
+
+ //!
+ //! @brief Returns whether library supports multi threading or not
+ //! \return A value of bool type; true means it supports multi threading and false otherwise.
+ //!
+ virtual bool APICALL IsMultiThreaded() const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IConfigurationManager interface.
+ //!
+ virtual pIConfigurationManager APICALL GetActualIConfigurationManager() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIConfigurationManager GetActualIConfigurationManager() const __NOTHROW__ {
+ return const_cast< IConfigurationManager_v1 * >( this )->GetActualIConfigurationManager();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Convert raw pointer to shared pointer.
+ //! @detail The raw pointer is of version 1 interface where as the returned shared pointer depends on the version client is interested in.
+ //!
+ //! \return Shared pointer to const or non constant IConfigurationManager interface.
+ //!
+ XMP_PRIVATE static spIConfigurationManager MakeShared( pIConfigurationManager_base ptr );
+ XMP_PRIVATE static spcIConfigurationManager MakeShared( pcIConfigurationManager_base ptr ) {
+ return MakeShared( const_cast< pIConfigurationManager_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Return the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIConfigurationManagerID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ virtual ~IConfigurationManager_v1() __NOTHROW__ {}
+
+ protected:
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL registerMemoryAllocator( pIMemoryAllocator_base memoryAllocator, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL registerErrorNotifier( pIErrorNotifier_base clientErrorNotifier, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL disableMultiThreading( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL isMultiThreaded( pcIError_base & error ) const __NOTHROW__ = 0;
+ //! \endcond
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+ };
+}
+
+
+#if !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+
+namespace AdobeXMPCommon {
+ class IConfigurationManagerProxy
+ : public virtual IConfigurationManager
+ {
+ private:
+ pIConfigurationManager mRawPtr;
+
+ public:
+ IConfigurationManagerProxy( pIConfigurationManager ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IConfigurationManagerProxy() __NOTHROW__ { mRawPtr->Release(); }
+ pIConfigurationManager APICALL GetActualIConfigurationManager() __NOTHROW__ { return mRawPtr; }
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ { return mRawPtr->GetISharedObject_I(); }
+
+ void APICALL Acquire() const __NOTHROW__;
+ void APICALL Release() const __NOTHROW__;
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion );
+ virtual bool APICALL RegisterMemoryAllocator( pIMemoryAllocator memoryAllocator );
+ virtual bool APICALL RegisterErrorNotifier( pIErrorNotifier_base clientErrorNotifier );
+ virtual bool APICALL DisableMultiThreading();
+ virtual bool APICALL IsMultiThreaded() const;
+
+ protected:
+ virtual uint32 APICALL registerMemoryAllocator( pIMemoryAllocator_base memoryAllocator, pcIError_base & error ) __NOTHROW__;
+ virtual uint32 APICALL registerErrorNotifier( pIErrorNotifier_base clientErrorNotifier, pcIError_base & error ) __NOTHROW__;
+ virtual uint32 APICALL disableMultiThreading( pcIError_base & error ) __NOTHROW__;
+ virtual uint32 APICALL isMultiThreaded( pcIError_base & error ) const __NOTHROW__;
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__;
+ };
+
+}
+
+#endif // BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_LIB
+
+#endif // IConfigurationManager_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IError.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IError.h
new file mode 100644
index 0000000000..15955ba64b
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IError.h
@@ -0,0 +1,377 @@
+//! @file IError.h
+#ifndef __IError_h__
+#define __IError_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+#include "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! @brief Version1 of the interface that represents an error/warning encountered during processing.
+ //! \details Provides all the functions to get required information regarding error scenario.
+ //! \attention Do Not support Multi-threading at object level.
+ //! \attention Multi-threading not required since clients will only be provided const objects.
+ //!
+ class XMP_PUBLIC IError_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+ //!
+ //! @brief Indicates various types of errors.
+ //!
+ typedef enum {
+ //! No severity, not to be used.
+ kESNone = 0,
+
+ //! Recovery is possible, client can choose to ignore and let library continue with the best possible way.
+ kESWarning = 1 << 0,
+
+ //! Recovery is not possible, an exception of type pcIError_base will be thrown aborting the API call.
+ kESOperationFatal = 1 << 1,
+
+ //! Recovery is not possible, an exception of type pcIError_base will be thrown, client should abort the process.
+ kESProcessFatal = 1 << 2,
+
+ // Add new severities here
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kESMaxValue = 1 << 31,
+
+ //! Union of all severities
+ kESAll = kAllBits,
+ } eErrorSeverity;
+
+
+ //!
+ //! @brief Indicates various types of error domains.
+ //!
+ typedef enum {
+ //! No Domain
+ kEDNone = 0,
+
+ //! Indicates error related to general conditions.
+ kEDGeneral = 1,
+
+ //! Indicates error related to memory allocation-deallocation conditions.
+ kEDMemoryManagement = 2,
+
+ //! Indicates error related to configurable APIs.
+ kEDConfigurable = 3,
+
+ //! Indicates error releated to multithreading.
+ kEDMultiThreading = 4,
+
+ //! Indicates error related to XMP Data Model Management.
+ kEDDataModel = 100,
+
+ //! Indicates error related to XMP Parsing.
+ kEDParser = 101,
+
+ //! Indicates error related to XMP Serializing.
+ kEDSerializer = 102,
+
+
+ //! Indicates error related to dealing with XMP in various file formats.
+ kEDXMPFiles = 200,
+
+
+ //! Indicates error related to Conflict Identification.
+ kEDConflictIdentification = 400,
+
+ //! Indicates error related to Conflict Resolution.
+ kEDConflictResolution = 500,
+
+ //! Indicates error related to 3 Way Merge.
+ kEDThreeWayMerge = 600,
+
+ //! Indicates error related to Generic Strategy Database
+ kEDGenericStrategyDatabase = 601,
+
+ //! Indicates error related to Asset Management.
+ kEDAssetManagement = 10000,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kEDMaxValue = kMaxEnumValue
+ } eErrorDomain;
+
+ typedef uint32 eErrorCode;
+
+ //!
+ //! @brief Get the error code.
+ //! \return An object of type #eErrorCode indicating the error code.
+ //!
+ virtual eErrorCode APICALL GetCode() const = 0;
+
+ //!
+ //! @brief Get the error domain.
+ //! \return An object of type #eErrorDomain indicating the error domain.
+ //!
+ virtual eErrorDomain APICALL GetDomain() const = 0;
+
+ //!
+ //! @brief Get the error severity.
+ //! \return An object of type #eErrorSeverity indicating the severity of error.
+ //!
+ virtual eErrorSeverity APICALL GetSeverity() const = 0;
+
+ //!
+ //! @brief Get the error message.
+ //! \details Error message contains a 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.
+ //! \return A shared pointer to const AdobeXMPCommon::IUTF8String object containing message string.
+ //!
+ virtual spcIUTF8String APICALL GetMessage() const = 0;
+
+ //!
+ //! @brief Get the location of the error origin.
+ //! \return A shared pointer to const AdobeXMPCommon::IUTF8String object containing location as like file name
+ //! and line number.
+ //! \note For debugging use only.
+ //!
+ virtual spcIUTF8String APICALL GetLocation() const = 0;
+
+ //!
+ //! @brief Get the value of a parameter at a particular index.
+ //! \details Based on each error condition various parameters are stored along with the error object. Clients can
+ //! one by one get access to each parameter that can be later used for debugging.
+ //! \param[in] index A value of \#AdobeXMPCommon::sizet indicating the index of the parameter client is
+ //! interested in retrieving.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String object containing some string.
+ //! \attention Throws \#AdobeXMPCommon::pcIError_base in case index is out of bounds.
+ //! \note For debugging use only.
+ //!
+ virtual spcIUTF8String APICALL GetParameter( sizet index ) const = 0;
+
+ //!
+ //! @brief Get the count of parameters.
+ //! \return An object of type \#AdobeXMPCommon::sizet containing the count of paramaters associated with the error object.
+ //!
+ virtual sizet APICALL GetParametersCount() const __NOTHROW__ = 0;
+
+ //!
+ //! @{
+ //! @brief Get the next error in the chain.
+ //! \return A pointer to const/non-const \#AdobeXMPCommon::IError object which is the next error in the chain.
+ //! \note Return an invalid shared pointer in case it is the last error object in the chain.
+ //!
+ virtual spIError APICALL GetNextError() = 0;
+
+ XMP_PRIVATE spcIError GetNextError() const {
+ return const_cast< IError_v1 * >( this )->GetNextError();
+ }
+ //! @}
+
+ //!
+ //! @brief Set the next error in the chain.
+ //! \param[in] error A pointer to \#AdobeXMP::IError object which will be the next error in the chain.
+ //! \return A pointer to \#AdobeXMPCommon::IError object which is the current next error in the chain.
+ //! \note Return an invalid pointer in case there is no current next error in the chain.
+ //!
+ virtual spIError APICALL SetNextError( const spIError & error ) = 0;
+
+ //!
+ //! @brief Set the error message.
+ //! \param[in] message Pointer to a constant char buffer containing message. It can be null terminated or not.
+ //! NULL pointer will be treated as empty message string.
+ //! \param[in] len A value of \#AdobeXMPCommon::sizet indicating the length in case message is not null
+ //! terminated. In case message is null terminated it can be set to its default value ( npos ).
+ //!
+ virtual void APICALL SetMessage( const char * message, sizet len = npos ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Set the location of origin of error.
+ //! \param[in] fileName Pointer to a null terminated char buffer containing the file name from which the error
+ //! originated. NULL pointer will be treated as empty fileName.
+ //! \param[in] lineNumber A value of \#AdobeXMPCommon::sizet indicating the line in source file from which the error
+ //! originated.
+ //!
+ virtual void APICALL SetLocation( const char * fileName, sizet lineNumber ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a parameter to the list of parameters.
+ //! \param[in] parameter Pointer to a constant char buffer containing parameter. It can be null terminated or not.
+ //! NULL pointer will be treated as empty message string.
+ //! \param[in] len A value of AdobeXMPCommon::sizet indicating the length in case parameter is not null
+ //! terminated. In case parameter is null terminated it can be set to its default value ( npos ).
+ //!
+ virtual void APICALL AppendParameter( const char * parameter, sizet len = npos ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends an address as a string to the list of parameters.
+ //! \param[in] addressParameter A value of void * type containing the address of the location to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( void * addressParameter ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a 32 bit unsigned integer value as a string to the list of parameters.
+ //! \param[in] integerValue A value of AdobeXMPCommon::uint32 type containing the integral value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( const uint32 & integerValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a 64 bit unsigned integer value as a string to the list of parameters.
+ //! \param[in] integerValue A value of AdobeXMPCommon::uint64 type containing the integral value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( const uint64 & integerValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a 32 bit integer value as a string to the list of parameters.
+ //! \param[in] integerValue A value of AdobeXMPCommon::int32 type containing the integral value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( const int32 & integerValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a 64 bit integer value as a string to the list of parameters.
+ //! \param[in] integerValue A value of AdobeXMPCommon::uint64 type containing the integral value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( const int64 & integerValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a floating value as a string to the list of parameters.
+ //! \param[in] floatValue A value of float type containing the floating value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( const float & floatValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a double floating value as a string to the list of parameters.
+ //! \param[in] doubleValue A value of double type containing the floating value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( const double & doubleValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Appends a boolean value as a string to the list of parameters.
+ //! \param[in] booleanValue A value of bool type containing the boolean value to be used as parameter.
+ //!
+ virtual void APICALL AppendParameter( bool booleanValue ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates an error object.
+ //! \param[in] objFactory A pointer to IObjectFactory object.
+ //! \param[in] errDomain A value of #eErrorDomain indicating the error domain.
+ //! \param[in] errCode A value of #eErrorCode indicating the error code.
+ //! \param[in] errSeverity A value of #eErrorSeverity indicating the severity of the error.
+ //! \return A shared pointer to an object of IError_v1.
+ //!
+ static spIError CreateError( pIObjectFactory objFactory, eErrorDomain errDomain,
+ eErrorCode errCode, eErrorSeverity errSeverity );
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ //! @{
+ //! @brief Return the actual raw pointer from the pointer available to client, which can be of a proxy class.
+ //! \return Either a const or non const pointer to IError interface.
+ //!
+ virtual pIError APICALL GetActualIError() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIError GetActualIError() const __NOTHROW__ {
+ return const_cast< IError_v1 * >( this )->GetActualIError();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Convert raw pointer to shared pointer.
+ //! @details The raw pointer is of version 1 interface where as the returned shared pointer depends on the version client who is interested in.
+ //!
+ //! \return Shared pointer to const or non constant IError interface.
+ //!
+ XMP_PRIVATE static spIError MakeShared( pIError_base ptr );
+ XMP_PRIVATE static spcIError MakeShared( pcIError_base ptr ) {
+ return MakeShared( const_cast< pIError_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIErrorID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IError_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL getCode( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL getDomain( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL getSeverity( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getMessage( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getLocation( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getParameter( sizet index, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pIError_base APICALL getNextError( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIError_base APICALL setNextError( pIError_base nextError, pcIError_base & error ) __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+ };
+
+ //!
+ //! @brief A function pointer to report back errors and warnings to the library encountered during the serialization operation.
+ //! @details Based on the error condition library can return 0 or non zero to indicate that a particular warning can be ignored
+ //! and operation can continue.
+ //! \param[in] errorDomain An unsigned 32 bit integer indicating the domain of the error.
+ //! \param[in] errorCode An unsigned 32 bit integer indicating the code of the error.
+ //! \param[in] errorSeverity An unsigned 32 bit integer indicating the severity of the error.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return non zero value indicating that process can continue ignoring the warning, otherwise return 0 to indicate it should stop immediately.
+ //!
+ typedef uint32( *ReportErrorAndContinueABISafeProc )( uint32 errorDomain, uint32 errorCode, uint32 errorSeverity, const char * message, pcIError_base & error );
+
+ //!
+ //! @brief A Function object used by the client to report back and warnings to the library encountered during the serialization operation.
+ //! @details Based on the error condition library can return 0 or non zero to indicate that a particular warning can be ignored
+ //! and operation can continue.
+ //!
+ class ReportErrorAndContinueFunctor {
+ public:
+ ReportErrorAndContinueFunctor( ReportErrorAndContinueABISafeProc safeProc )
+ : mSafeProc( safeProc ) {}
+
+ //!
+ //! \param[in] errorDomain A value of \#IError_v1::eErrorDomain indicating the domain of the error.
+ //! \param[in] errorCode A value of \#IError_v1::eErrorCode indicating the code of the error.
+ //! \param[in] errorSeverity A value of \#IError_v1::eErrorSeverity indicating the severity of the error.
+ //! \param[in] message Pointer to a constant char buffer containing message.
+ //! \return true value indicating that process can continue ignoring the warning, otherwise return false to indicate it should stop immediately.
+ //!
+ bool operator()( IError_v1::eErrorDomain errorDomain, IError_v1::eErrorCode errorCode, IError_v1::eErrorSeverity errorSeverity, const char * message ) {
+ pcIError_base error( NULL );
+ auto retValue = mSafeProc( static_cast< uint32 >( errorDomain ), static_cast< uint32 >( errorCode ), static_cast< uint32 >( errorSeverity ), message, error );
+ if ( error )
+ throw IError_v1::MakeShared( error );
+ return retValue != 0 ? true : false;
+ }
+
+ protected:
+ ReportErrorAndContinueABISafeProc mSafeProc;
+ };
+
+
+}
+
+#endif // __IError_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IErrorNotifier.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IErrorNotifier.h
new file mode 100644
index 0000000000..7d17721a6c
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IErrorNotifier.h
@@ -0,0 +1,51 @@
+#ifndef IErrorNotifier_h__
+#define IErrorNotifier_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Version1 of the interface that represents an interface to be implemented by client
+ //! in case he is interested in getting notifications with respect to errors/warnings encountered
+ //! by library.
+ //! \details In case client is interested in error notifications he can implement this interface
+ //! and register the same with the \#AdobeXMPCommon::IConfigurationManager. For every warning or error
+ //! encountered the NotifyError function will be called by the library. In case of warnings ( indicated
+ //! by the severity of the error ) the client has the option to continue ignoring the warning by returning
+ //! true else he can return false and the warning will be thrown aborting the current operation.
+ //!
+ class XMP_PUBLIC IErrorNotifier_v1
+ {
+ public:
+ //!
+ //! @brief Called by the library to notify the client about the warning/error.
+ //! \param[in] error const pointer to a \#AdobeXMPCommon::IError. Client can use the information
+ //! in the error to decide what should be the future course of action.
+ //! \return A value of bool type that will indicate the future course of action.
+ //!
+ virtual bool APICALL Notify( const spcIError & error ) = 0;
+
+ protected:
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL notify( pcIError_base error, uint32 & exceptionThrown ) __NOTHROW__;
+ //! \endcond
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+ };
+}
+
+#endif // IErrorNotifier_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IMemoryAllocator.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IMemoryAllocator.h
new file mode 100644
index 0000000000..c2cdef3fb7
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IMemoryAllocator.h
@@ -0,0 +1,64 @@
+#ifndef IMemoryAllocator_h__
+#define IMemoryAllocator_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+#include "XMPCommon/XMPCommonFwdDeclarations.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Version1 of the interface that represents an interface to be implemented by client in case
+ //! he is interested in controlling the memory allocation and deallocation on the heap.
+ //! \details In case client is interested in controlling the memory allocation and deallocation on
+ //! the heap he can implement this interface and register the same with the
+ //! \#AdobeXMPCommon::IConfigurationManager. For every request of memory allocation or deallocation on
+ //! the heap corresponding function will be called by the library.
+ //! \attention Support for Multi threading is under clients hand.
+ //!
+ class XMP_PUBLIC IMemoryAllocator_v1
+ {
+ public:
+ //!
+ //! @brief Called by the library whenever it needs some space on the heap.
+ //! \param[in] size A value of type \#AdobeXMPCommon::sizet indicating the number of bytes
+ //! required by the library on the heap.
+ //! \return A pointer to memory location on the heap.
+ //!
+ virtual void * APICALL allocate( sizet size ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Called by the library whenever there is no further need for a previously allocated space on the heap.
+ //! \param[in] ptr A pointer to a memory location which is no longer needed.
+ //!
+ virtual void APICALL deallocate( void * ptr ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Called by the library whenever it needs to expand or contract some space already allocated on
+ //! the heap, preserving the contents.
+ //! \param[in] ptr A pointer to a memory location which was previously allocated on the heap.
+ //! \param[in] size A value of type \#AdobeXMPCommon::sizet indicating the new number of bytes
+ //! required by the library on the heap.
+ //! \return A pointer to memory location on the heap which is of new size and previous contents are
+ //! preserved.
+ //!
+ virtual void * APICALL reallocate( void * ptr, sizet size ) __NOTHROW__ = 0;
+
+ protected:
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ };
+};
+
+#endif // IMemoryAllocator_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IObjectFactory.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IObjectFactory.h
new file mode 100644
index 0000000000..0dd86b98b7
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IObjectFactory.h
@@ -0,0 +1,90 @@
+#ifndef IObjectFactory_h__
+#define IObjectFactory_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCommon/XMPCommonFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! \brief Version1 of a interface that represents a factory to create various artifacts defined within
+ //! AdobeXMPCommon namespace.
+ //! @details Provides all the functions to create instances of various artifacts defined with AdobeXMPCommon namespace. This
+ //! is the interface through which clients of the library actually get access to all other interfaces.
+ //!
+
+ class XMP_PUBLIC IObjectFactory_v1
+ : public IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Creates an IUTF8String object.
+ //! \param[in] buf pointer to a constant char buffer containing content. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length in case buf is not null
+ //! terminated. In case buf is null terminated it can be set to npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \attention The returned pointer is allocated on heap by the module so client is responsible for its release.
+ //! They should call Release once they no longer need this object.
+ //!
+ virtual pIUTF8String_base APICALL CreateUTF8String( const char * buf, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates an IError object.
+ //! \param[in] domain An unsigned 32 bit integer value representing the error domain.
+ //! \param[in] code An unsigned 32 bit integer value representing the error code.
+ //! \param[in] severity An unsigned 32 bit integer value representing the severity of the error.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \attention The returned pointer is allocated on heap by the module so client is responsible for its release.
+ //! They should call Release once they no longer need this object.
+ //!
+ virtual pIError_base APICALL CreateError( uint32 domain, uint32 code, uint32 severity, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @{
+ //! @details Convert raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned returned pointer depends on the version client is interested in.
+ //! \return Raw pointer to const or non constant IObjectFactory interface.
+ //!
+ XMP_PRIVATE static pIObjectFactory MakeObjectFactory( pIObjectFactory_base ptr ) {
+ return IObjectFactory::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IObjectFactory >() : ptr;
+ }
+ XMP_PRIVATE static pcIObjectFactory MakeObjectFactory( pcIObjectFactory_base ptr ) {
+ return MakeObjectFactory( const_cast< pIObjectFactory_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIObjectFactoryID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+
+ virtual ~IObjectFactory_v1() __NOTHROW__ {};
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ };
+
+}
+
+#endif // IObjectFactory_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IUTF8String.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IUTF8String.h
new file mode 100644
index 0000000000..e1cc517dca
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Interfaces/IUTF8String.h
@@ -0,0 +1,504 @@
+#ifndef __IUTF8String_h__
+#define __IUTF8String_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCommon {
+ using AdobeXMPCommon::npos;
+
+ //!
+ //! @brief Version1 of the interface that represents an UTF8String.
+ //! @details Provides all the functions to access properties of the string object, appends or assigns content
+ //! to the existing string objects and clones existing string objects.
+ //!
+ class XMP_PUBLIC IUTF8String_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+ //!
+ //! @brief Appends more content into the existing string object through a pointer to char buffer.
+ //! \param[in] buf pointer to a constant char buffer containing new content. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length in case buf is not null
+ //! terminated. In case buf is null terminated it can be set to npos.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //!
+ virtual spIUTF8String APICALL append( const char * buf, sizet count ) = 0;
+
+ //!
+ //! @brief Appends the contents of another string into the existing string.
+ //! \param[in] src Shared pointer to const \#AdobeXMPCommon::IUTF8String whose contents will be
+ //! appended to existing content in the object. Invalid shared pointer will be treated as empty string.
+ //! \param[in] srcPos A value of \#AdobeXMPCommon::sizet indicating the position of the first character
+ //! in src that is inserted into the object as a substring.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length of the substring to be copied
+ //! (if the string is shorter, as many characters as possible are copied). A value of npos indicates all
+ //! characters until the end of src.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \attention Error is thrown in case
+ //! - srcPos is greater than length of src.
+ //!
+ virtual spIUTF8String APICALL append( const spcIUTF8String & src, sizet srcPos = 0, sizet count = npos ) = 0;
+
+ //!
+ //! @brief Overwrites new string content into the existing string object through a pointer to char buffer.
+ //! \param[in] buf pointer to a constant char buffer containing new content. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length in case buf is not null
+ //! terminated. In case buf is null terminated it can be set to npos.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //!
+ virtual spIUTF8String APICALL assign( const char * buf, sizet count ) = 0;
+
+ //!
+ //! @brief Overwrites the contents with contents of another string.
+ //! \param[in] src shared pointer to const \#AdobeXMPCommon::IUTF8String whose contents will
+ //! overwrite existing content in the object. Invalid shared pointer will be treated as empty string.
+ //! \param[in] srcPos A value of \#AdobeXMPCommon::sizet indicating the position of the first character
+ //! in src that is inserted into the object as a substring.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length of the substring to be copied.
+ //! A value of npos indicates all characters until the end of src. If this is greater than the available
+ //! characters in the substring then copying is limited to the number of available characters.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \attention Error is thrown in case
+ //! - srcPos is greater than length of src.
+ //!
+ virtual spIUTF8String APICALL assign( const spcIUTF8String & src, sizet srcPos = 0, sizet count = npos ) = 0;
+
+ //!
+ //! @brief Inserts additional characters into the string right before the character indicated by pos.
+ //! \param[in] pos Insertion point: The new contents are inserted before the character at position pos.
+ //! \param[in] buf pointer to a constant char buffer containing new content. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length in case buf is not null
+ //! terminated. In case buf is null terminated it can be set to npos.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \\attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ virtual spIUTF8String APICALL insert( sizet pos, const char * buf, sizet count ) = 0;
+
+ //!
+ //! @brief Inserts additional characters into the string right before the character indicated by pos.
+ //! \param[in] pos Insertion point: The new contents are inserted before the character at position pos.
+ //! \param[in] src shared pointer to const \#AdobeXMPCommon::IUTF8String whose contents will
+ //! be copied and pushed into the object. Invalid shared pointer will be treated as empty string.
+ //! \param[in] srcPos A value of \#AdobeXMPCommon::sizet indicating the position of the first character
+ //! in src that is inserted into the object as a substring.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length of the substring to be copied
+ //! (if the string is shorter, as many characters as possible are copied). A value of npos indicates all
+ //! characters until the end of src. If this is greater than the available characters in the substring
+ //! then copying is limited to the number of available characters.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \attention Error is thrown in case
+ //! - srcPos is greater than length of src.
+ //! - pos is greater than the object's length.
+ //!
+ virtual spIUTF8String APICALL insert( sizet pos, const spcIUTF8String & src, sizet srcPos = 0, sizet count = npos ) = 0;
+
+ //!
+ //! @brief Erases part of the string, reducing its length.
+ //! \param[in] pos Position of the first character to be erased.
+ //! If this is greater than the string length, nothing is erased.
+ //! \param[in] count Number of characters to erase (if the string is shorter, as many characters as
+ //! possible are erased). A value of npos indicates all characters until the end of the string.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ virtual spIUTF8String APICALL erase( sizet pos = 0, sizet count = npos ) = 0;
+
+ //!
+ //! @brief Resizes the string to the length of n characters.
+ //! /param[in] n New string length, expressed in number of characters.
+ //! \note If n is smaller than the current string length, the current value is shortened
+ //! to its first size character, removing the characters beyond the nth. If n is greater than the
+ //! current string length, the current content is extended by inserting at the end as many NULL
+ //! characters as needed to reach a size of n.
+ //! \attention Error is thrown in case
+ //! - n is greater than max_size
+ //! - allocation fails
+ //!
+ virtual void APICALL resize( sizet n ) = 0 ;
+
+ //!
+ //! @brief Replace portion of string.
+ //! \param[in] pos Position of the first character to be replaced.
+ //! \param[in] count Number of characters to replace (if the string is shorter, as many characters as possible
+ //! are replaced). A value of npos indicates all characters until the end of the string.
+ //! \param[in] buf pointer to a constant char buffer containing new content. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] srcCount A value of \#AdobeXMPCommon::sizet indicating the length in case buf is not null
+ //! terminated. In case buf is null terminated it can be set to npos.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ virtual spIUTF8String APICALL replace( sizet pos, sizet count, const char * buf, sizet srcCount ) = 0;
+
+ //!
+ //! @brief Replace portion of string.
+ //! \param[in] pos Position of the first character to be replaced.
+ //! \param[in] count Number of characters to replace (if the string is shorter, as many characters as possible
+ //! are replaced). A value of npos indicates all characters until the end of the string.
+ //! \param[in] src Shared pointer to const \#AdobeXMPCommon::IUTF8String whose contents will
+ //! be copied and pushed into the object. Invalid shared pointer will be treated as empty string.
+ //! \param[in] srcPos Position of the first character in str that is copied to the object as replacement.
+ //! \param[in] srcCount Length of the substring to be copied (if the string is shorter, as many characters
+ //! as possible are copied). A value of npos indicates all characters until the end of str.
+ //! \return The shared pointer to itself of type \#AdobeXMPCommon::IUTF8String.
+ //! \attention Error is thrown in case
+ //! - srcPos is greater than length of src.
+ //! - pos is greater than the object's length.
+ //!
+ virtual spIUTF8String APICALL replace( sizet pos, sizet count, const spcIUTF8String & src, sizet srcPos = 0, sizet srcCount = npos ) = 0;
+
+ //!
+ //! @brief Copy sequence of characters from string.
+ //! @details Copies a substring of the current value of the string object into the array. This substring
+ //! contains the len characters that start at position pos.
+ //! \param[in,out] buf Pointer to an array of characters. The array shall contain enough storage for the copied
+ //! characters.
+ //! \param[in] len Number of characters to copy (if the string is shorter, as many characters as possible are
+ //! copied).
+ //! \param[in] pos Position of the first character to be copied.
+ //! \return The number of characters copied to the array. This may be equal to count or to size() - pos.
+ //! \note The function does not append a null character at the end of the copied content.
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ virtual sizet APICALL copy( char * buf, sizet len, sizet pos = 0 ) const = 0;
+
+ //!
+ //! @brief Find content in string.
+ //! @details Searches the string for the first occurrence of the sequence specified by its arguments. When pos
+ //! is specified, the search only includes characters at or after position pos, ignoring any possible
+ //! occurrences that include characters before pos.
+ //! \param[in] buf pointer to a constant char buffer containing content to be matched. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] pos Position of the first character in the string to be considered in the search.
+ //! If this is greater than the string length, the function never finds matches.
+ //! \return The position of the first character of the first match. If no matches were found, the function
+ //! returns npos.
+ //!
+ sizet find( const char * buf, sizet pos = 0 ) const {
+ return find( buf, pos, npos );
+ }
+
+ //!
+ //! @brief Find content in string.
+ //! @details Searches the string for the first occurrence of the sequence specified by its arguments. When pos
+ //! is specified, the search only includes characters at or after position pos, ignoring any possible
+ //! occurrences that include characters before pos.
+ //! \param[in] buf pointer to a constant char buffer containing content to be matched. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] pos Position of the first character in the string to be considered in the search.
+ //! If this is greater than the string length, the function never finds matches.
+ //! \param[in] count Length of sequence of characters to match.
+ //! \return The position of the first character of the first match. If no matches were found, the function
+ //! returns npos.
+ //!
+ virtual sizet APICALL find( const char * buf, sizet pos, sizet count ) const = 0;
+
+
+ //
+ //! @brief Find content in string.
+ //! @details Searches the string for the first occurrence of the sequence specified by its arguments. When pos
+ //! is specified, the search only includes characters at or after position pos, ignoring any possible
+ //! occurrences that include characters before pos.
+ //! \param[in] src shared pointer to const \#AdobeXMPCommon::IUTF8String containing content to be matched. Invalid
+ //! shared pointer will be treated as empty string.
+ //! \param[in] pos Position of the first character in the string to be considered in the search.
+ //! If this is greater than the string length, the function never finds matches.
+ //! \param[in] count Length of sequence of characters to match.
+ //! \return The position of the first character of the first match. If no matches were found, the function
+ //! returns npos.
+ //!
+ virtual sizet APICALL find( const spcIUTF8String & src, sizet pos = 0, sizet count = npos ) const = 0;
+
+ //!
+ // @{
+ //! @brief Find last occurrence of content in string.
+ //! @details Searches the string for the last occurrence of the sequence specified by its arguments. When pos
+ //! is specified, the search only includes sequences of characters that begin at or before position pos,
+ //! ignoring any possible match beginning after pos.
+ //! \param[in] buf pointer to a constant char buffer containing content to be matched. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] pos Position of the last character in the string to be considered as the beginning of a match.
+ //! Any value greater or equal than the string length (including npos) means that the entire string is
+ //! searched.
+ //! \return The position of the fist character of the last match. If no matches were found, the function
+ //! returns npos.
+ //!
+ sizet rfind( const char * buf, sizet pos = npos ) const {
+ return rfind( buf, pos, npos );
+ }
+ virtual sizet APICALL rfind( const char * buf, sizet pos, sizet count ) const = 0;
+ //@}
+ //!
+
+ //!
+ //! @brief Find last occurrence of content in string.
+ //! @details Searches the string for the last occurrence of the sequence specified by its arguments. When pos
+ //! is specified, the search only includes sequences of characters that begin at or before position pos,
+ //! ignoring any possible match beginning after pos.
+ //! \param[in] src shared pointer to const \#AdobeXMPCommon::IUTF8String containing content to be matched. Invalid
+ //! shared pointer will be treated as empty string.
+ //! \param[in] pos Position of the last character in the string to be considered as the beginning of a match.
+ //! Any value greater or equal than the string length (including npos) means that the entire string is
+ //! searched.
+ //! \param[in] count Length of sequence of characters to match.
+ //! \return The position of the fist character of the last match. If no matches were found, the function
+ //! returns npos.
+ //!
+ virtual sizet APICALL rfind( const spcIUTF8String & src, sizet pos = npos, sizet count = npos ) const = 0;
+
+ //!
+ //! @{
+ //! @brief Compare strings.
+ //! @details Compares the value of the string object (or a substring) to the sequence of characters specified by its
+ //! arguments.
+ //! \param[in] buf pointer to a constant char buffer containing content to be compared. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //!
+ //! \return Returns a signed integral indicating the relation between the strings
+ //! | value | relation between compared string and comparing string |
+ //! | :---: | :-----------------------------------------------------|
+ //! | 0 | They compare equal |
+ //! | <0 | Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter. |
+ //! | >0 | Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer. |
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ int32 compare( const char * buf ) const {
+ return compare( 0, size(), buf, npos );
+ }
+ //! @brief Compare strings.
+ //! @details Compares the value of the string object (or a substring) to the sequence of characters specified by its
+ //! arguments.
+ //! \param[in] buf pointer to a constant char buffer containing content to be compared. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] pos Position of the first character in the compared string. If this is greater than the string
+ //! length, it is treated as empty string.
+ //! \param[in] len Length of compared string (if the string is shorter, as many characters as possible).
+ //! A value of npos indicates all characters until the end of the string.
+ //!
+ //! \return Returns a signed integral indicating the relation between the strings
+ //! | value | relation between compared string and comparing string |
+ //! | :---: | :-----------------------------------------------------|
+ //! | 0 | They compare equal |
+ //! | <0 | Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter. |
+ //! | >0 | Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer. |
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ int32 compare( sizet pos, sizet len, const char * buf ) const {
+ return compare( pos, len, buf, npos );
+ }
+ //!@brief Compare strings.
+ //! @details Compares the value of the string object (or a substring) to the sequence of characters specified by its
+ //! arguments.
+ //! \param[in] buf pointer to a constant char buffer containing content to be compared. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] pos Position of the first character in the compared string. If this is greater than the string
+ //! length, it is treated as empty string.
+ //! \param[in] len Length of compared string (if the string is shorter, as many characters as possible).
+ //! A value of npos indicates all characters until the end of the string.
+ //! \param[in] count Number of characters to compare.
+ //!
+ //! \return Returns a signed integral indicating the relation between the strings
+ //! | value | relation between compared string and comparing string |
+ //! | :---: | :-----------------------------------------------------|
+ //! | 0 | They compare equal |
+ //! | <0 | Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter. |
+ //! | >0 | Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer. |
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //!
+ virtual int32 APICALL compare( sizet pos, sizet len, const char * buf, sizet count ) const = 0;
+
+
+ //!
+ //! @brief Compare strings.
+ //! @details Compares the value of the string object (or a substring) to the contents of an string or substring object
+ //! specified by its arguments.
+ //! \param[in] str shared pointer to const \#AdobeXMPCommon::IUTF8String containing content to be compared.
+ //! Invalid shared pointer will be treated as empty string.
+ //! \return Returns a signed integral indicating the relation between the strings
+ //! | value | relation between compared string and comparing string |
+ //! | :---: | :-----------------------------------------------------|
+ //! | 0 | They compare equal |
+ //! | <0 | Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter. |
+ //! | >0 | Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer. |
+ //! \attention Error is thrown in case
+ //! - strPos is greater than length of str.
+ //! - pos is greater than the object's length.
+ //!
+ int32 compare( const spcIUTF8String & str ) const {
+ return compare( 0, size(), str, 0, str->size() );
+ }
+ //!
+ //! @brief Compare strings.
+ //! @details Compares the value of the string object (or a substring) to the contents of an string or substring object
+ //! specified by its arguments.
+ //! \param[in] pos Position of the first character in the compared string.
+ //! \param[in] len Length of compared string (if the string is shorter, as many characters as possible).
+ //! A value of npos indicates all characters until the end of the string.
+ //! \param[in] str shared pointer to const \#AdobeXMPCommon::IUTF8String containing content to be compared.
+ //! Invalid shared pointer will be treated as empty string.
+ //! \param[in] strPos Position of the first character in the comparing string.
+ //! \param[in] strLen Length of comparing string (if the string is shorter, as many characters as possible).
+ //!
+ //! \return Returns a signed integral indicating the relation between the strings
+ //! | value | relation between compared string and comparing string |
+ //! | :---: | :-----------------------------------------------------|
+ //! | 0 | They compare equal |
+ //! | <0 | Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter. |
+ //! | >0 | Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer. |
+ //! \attention Error is thrown in case
+ //! - strPos is greater than length of str.
+ //! - pos is greater than the object's length.
+ //!
+ virtual int32 APICALL compare( sizet pos, sizet len, const spcIUTF8String & str, sizet strPos = 0, sizet strLen = npos ) const = 0;
+
+ //!
+ //! @brief Returns a new string object which contains a sub string of the actual string object.
+ //! \param[in] pos Position of the first character to be copied. If this is greater than the string length, then
+ //! nothing is copied.
+ //! \param[in] count Number of characters to copy (if the string is shorter, as many characters as possible are
+ //! copied).
+ //! \return A shared pointer to AdobeXMPCommon::IUTF8String which is exact replica of the current object.
+ //! \attention Error is thrown in case
+ //! - pos is greater than the object's length.
+ //! - allocation fails
+ //!
+ virtual spIUTF8String APICALL substr( sizet pos = 0, sizet count = npos ) const = 0;
+
+ //!
+ //! @brief Indicates whether the string object is empty or not.
+ //! \return A value of type bool; true in case the contents of the string object is empty.
+ //!
+ virtual bool APICALL empty() const = 0;
+
+ //!
+ //! @brief Provides access to the actual location where contents of string are stored.
+ //! \return A pointer to a buffer of const chars containing the contents of the string object.
+ //!
+ virtual const char * APICALL c_str() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Clears the contents of the string object.
+ //!
+ virtual void APICALL clear() __NOTHROW__ = 0;
+
+ //!
+ //! @brief Indicates the number of bytes used by the contents of the string object.
+ //! \return An object of type \#AdobeXMPCommon::sizet containing the number of bytes used to store the contents fo the string object.
+ //!
+ virtual sizet APICALL size() const __NOTHROW__ = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IUTF8String interface.
+ //!
+ virtual pIUTF8String APICALL GetActualIUTF8String() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIUTF8String GetActualIUTF8String() const __NOTHROW__ {
+ return const_cast< IUTF8String_v1 * >( this )->GetActualIUTF8String();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Convert raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIUTF8String MakeShared( pIUTF8String_base ptr );
+ XMP_PRIVATE static spcIUTF8String MakeShared( pcIUTF8String_base ptr ) {
+ return MakeShared( const_cast< pIUTF8String_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIUTF8StringID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // static factory functions
+
+ //!
+ //! @brief Creates an empty IUTF8String object.
+ //! \param[in] objFactory A pointer to \#AdobeXMPCommon::IObjectFactory object.
+ //! \return A shared pointer to an empty IUTF8String object
+ //!
+ XMP_PRIVATE static spIUTF8String CreateUTF8String( pIObjectFactory objFactory );
+
+ //!
+ //! @brief Creates an IUTF8String object whose initial contents are copied from a char buffer.
+ //! \param[in] objFactory A pointer to \#AdobeXMPCommon::IObjectFactory object.
+ //! \param[in] buf pointer to a constant char buffer containing content. It can be null
+ //! terminated or not. NULL pointer will be treated as empty string.
+ //! \param[in] count A value of \#AdobeXMPCommon::sizet indicating the length in case buf is not null
+ //! terminated. In case buf is null terminated it can be set to npos.
+ //! \return A shared pointer to a newly created \#AdobeXMPCommon::IUTF8String object
+ //!
+ XMP_PRIVATE static spIUTF8String CreateUTF8String( pIObjectFactory objFactory, const char * buf, sizet count );
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IUTF8String_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pIUTF8String_base APICALL assign( const char * buffer, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL assign( pcIUTF8String_base str, sizet srcPos, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL append( const char * buffer, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL append( pcIUTF8String_base str, sizet srcPos, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL insert( sizet pos, const char * buf, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL insert( sizet pos, pcIUTF8String_base src, sizet srcPos, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL erase( sizet pos, sizet count, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL resize( sizet n, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL replace( sizet pos, sizet count, const char * buf, sizet srcCount, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL replace( sizet pos, sizet count, pcIUTF8String_base src, sizet srcPos, sizet srcCount, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual sizet APICALL copy( char * buf, sizet len, sizet pos, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual sizet APICALL find( const char * buf, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual sizet APICALL find( pcIUTF8String_base src, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual sizet APICALL rfind( const char * buf, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual sizet APICALL rfind( pcIUTF8String_base src, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual int32 APICALL compare( sizet pos, sizet len, const char * buf, sizet count, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual int32 APICALL compare( sizet pos, sizet len, pcIUTF8String_base str, sizet strPos, sizet strLen, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL substr( sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL empty( pcIError_base & error ) const __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+ };
+}
+
+#endif // __IUTF8String_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Utilities/TWrapperFunctions.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Utilities/TWrapperFunctions.h
new file mode 100644
index 0000000000..41af71ec53
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Utilities/TWrapperFunctions.h
@@ -0,0 +1,252 @@
+#ifndef TWrapperFunctions_h__
+#define TWrapperFunctions_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/Interfaces/IError.h"
+
+#if SUPPORT_VARIADIC_TEMPLATES
+//! \cond XMP_INTERNAL_DOCUMENTATION
+namespace AdobeXMPCommon {
+
+ //!
+ //! @{
+ //! template functions taking care of all the functions where return types of client exposed function as well as
+ //! DLL/library safe function are void.
+ //! \details It calls the underlying DLL/library safe function and in case any error is reported back through
+ //! pointer, it throws the error to the upper functions to handle.
+ //! \param[in] ptr non const pointer to an object of className itself ( most probably this pointer ).
+ //! \param[in] Func function pointer to non const member function of className accepting 0 or n number of variables
+ //! anad a reference to a pointer to const #AdobeXMPCommon::IError_base object and returning void.
+ //! \param[in] Vs n number of variables of varying/same type.
+ //! \note These takes care of non const functions.
+ //!
+ template < typename className >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( pcIError_base & ) )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename ... Ts >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( Ts ..., pcIError_base & ), Ts ... Vs )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( Vs ..., error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! template functions taking care of all the functions where return types of client exposed function as well as
+ //! DLL/library safe function are void.
+ //! \details It calls the underlying DLL/library safe function and in case any error is reported back through
+ //! pointer, it throws the error to the upper functions to handle.
+ //! \param[in] ptr const pointer to a const object of className itself ( most probably this pointer ).
+ //! \param[in] Func function pointer to const member function of className accepting 0 or n number of variables
+ //! and a reference to a pointer to const #AdobeXMPCommon::IError_base object and returning void.
+ //! \param[in] Vs n number of variables of varying/same type.
+ //! \note These takes care of const functions.
+ //!
+ template < typename className >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( pcIError_base & ) const )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className, typename ... Ts >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( Ts ..., pcIError_base & ) const, Ts ... Vs )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( Vs ..., error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! template functions taking care of all the functions where return types of client exposed function as well as
+ //! DLL/library safe function are nor void type neither shared pointers.
+ //! \details It calls the underlying DLL/library safe function and in case any error is reported back through
+ //! pointer, it throws the error to the upper function to handle.
+ //! \param[in] ptr non const pointer to an object of className itself ( most probably this pointer ).
+ //! \param[in] Func function pointer to non const member function of className accepting 0 or n number of variables
+ //! and a reference to a pointer to const #AdobeXMPCommon::IError_base object and returning value of type internalReturnType.
+ //! \param[in] Vs n number of variables of varying/same type.
+ //! These take care of non const functions.
+ //!
+ template < typename className, typename returnType, typename internalReturnType >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType ( APICALL className::*Func )( pcIError_base & ) )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename ... Ts >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType ( APICALL className::*Func )( Ts ..., pcIError_base & ), Ts ... Vs )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( Vs ..., error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! template functions taking care of all the functions where return types of client exposed function as well as
+ //! DLL/library safe function are nor void type neither shared pointers.
+ //! \details It calls the underlying DLL/library safe function and in case any error is reported back through
+ //! pointer, it throws the error to the upper function to handle.
+ //! \param[in] ptr const pointer to a const object of className itself ( most probably this pointer ).
+ //! \param[in] Func function pointer to const member function of className accepting 0 or n number of variables
+ //! and a reference to a pointer to const #AdobeXMPCommon::IError_base object and returning value of type internalReturnType.
+ //! \param[in] Vs n number of variables of varying/same type.
+ //! These take care of const functions.
+ //!
+ template < typename className, typename returnType, typename internalReturnType >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( pcIError_base & ) const )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename ... Ts >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( Ts ..., pcIError_base & ) const, Ts ... Vs )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( Vs ..., error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! template functions taking care of all the functions where return types of client exposed function is a
+ //! shared pointer.
+ //! \details It calls the underlying DLL/library safe function and in case any error is reported back through
+ //! pointer, it throws the error to the upper function to handle.
+ //! \param[in] ptr non const pointer to an object of className itself ( most probably this pointer ).
+ //! \param[in] Func function pointer to non const member function of className accepting 0 or n number of variables
+ //! and a reference to a pointer to const #AdobeXMPCommon::IError_base object and returning internalReturnType.
+ //! \param[in] Vs n number of variables of varying/same type.
+ //! These take care of non const functions.
+ //!
+ template < typename className, typename internalReturnType, typename sharedPointerType >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType ( APICALL className::*Func )( pcIError_base & ) )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename ... Ts >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType ( APICALL className::*Func )( Ts ..., pcIError_base & ), Ts ... Vs )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( Vs ..., error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! template functions taking care of all the functions where return types of client exposed function is a
+ //! shared pointer.
+ //! \details It calls the underlying DLL/library safe function and in case any error is reported back through
+ //! pointer, it throws the error to the upper function to handle.
+ //! \param[in] ptr const pointer to a const object of className itself ( most probably this pointer ).
+ //! \param[in] Func function pointer to const member function of className accepting 0 or n number of variables
+ //! and a reference to a pointer to const #AdobeXMPCommon::IError_base object and returning internalReturnType.
+ //! \param[in] Vs n number of variables of varying/same type.
+ //! These take care of const functions.
+ //!
+ template < typename className, typename internalReturnType, typename sharedPointerType >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( pcIError_base & ) const )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename ... Ts >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( Ts ..., pcIError_base & ) const, Ts ... Vs )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( Vs ..., error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+ //!
+ //! @}
+}
+
+//! \endcond
+#else
+ #include "XMPCommon/Utilities/TWrapperFunctions2.h"
+#endif
+#endif // TWrapperFunctions_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Utilities/TWrapperFunctions2.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Utilities/TWrapperFunctions2.h
new file mode 100644
index 0000000000..a6dc4a61a3
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/Utilities/TWrapperFunctions2.h
@@ -0,0 +1,554 @@
+#ifndef TWrapperFunctions2_h__
+#define TWrapperFunctions2_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+//! \cond XMP_INTERNAL_DOCUMENTATION
+namespace AdobeXMPCommon {
+ template < typename className >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( pcIError_base & ) )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename t1 >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( t1, pcIError_base & ), t1 v1 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename t1, typename t2 >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( t1, t2, pcIError_base & ), t1 v1, t2 v2 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename t1, typename t2, typename t3 >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, pcIError_base & ), t1 v1, t2 v2, t3 v3 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename t1, typename t2, typename t3, typename t4 >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, t4, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, v4, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename t1, typename t2, typename t3, typename t4, typename t5 >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, t4, t5, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4, t5 v5 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template< typename className, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6 >
+ void CallSafeFunctionReturningVoid( className * ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( pcIError_base & ) const )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className, typename t1 >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( t1, pcIError_base & ) const, t1 v1 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className, typename t1, typename t2 >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( t1, t2, pcIError_base & ) const, t1 v1, t2 v2 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className, typename t1, typename t2, typename t3 >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, pcIError_base & ) const, t1 v1, t2 v2, t3 v3 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className, typename t1, typename t2, typename t3, typename t4 >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, t4, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, v4, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+ template < typename className, typename t1, typename t2, typename t3, typename t4, typename t5 >
+ void CallConstSafeFunctionReturningVoid( const className * const ptr,
+ void ( APICALL className::*Func )( t1, t2, t3, t4, t5, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5 )
+ {
+ pcIError_base error( NULL );
+ ( ptr->*Func )( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ }
+
+
+ template < typename className, typename returnType, typename internalReturnType >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType ( APICALL className::*Func )( pcIError_base & ) )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1 >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType ( APICALL className::*Func )( t1, pcIError_base & ), t1 v1 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2 >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, pcIError_base & ), t1 v1, t2 v2 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3 >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, pcIError_base & ), t1 v1, t2 v2, t3 v3 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4 >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4, typename t5 >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, t5, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4, t5 v5 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ // Fixing AML build on mac
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6 >
+ returnType CallSafeFunction( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, v5, v6, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( pcIError_base & ) const )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, pcIError_base & ) const, t1 v1 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, pcIError_base & ) const, t1 v1, t2 v2 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, t3, pcIError_base & ) const, t1 v1, t2 v2, t3 v3 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, v3, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, t3, t4, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, v3, v4, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4, typename t5 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, t3, t4, t5, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ //Fixing AML build on mac
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, v3, v4, v5, v6, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, t7, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6, t7 v7 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, v3, v4, v5, v6, v7, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+
+ template < typename className, typename returnType, typename internalReturnType, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8, typename t9 >
+ returnType CallConstSafeFunction( const className * const ptr,
+ internalReturnType ( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, t7, t8, t9, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6, t7 v7, t8 v8, t9 v9 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = (ptr->*Func)( v1, v2, v3, v4, v5, v6, v7, v8, v9, error );
+ if ( error ) throw IError::MakeShared( error );
+ #if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4800 )
+ #endif
+ return static_cast< returnType >( returnValue );
+ #if XMP_WinBuild
+ #pragma warning( pop )
+ #endif
+ }
+
+
+
+ template < typename className, typename internalReturnType, typename sharedPointerType >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( pcIError_base & ) )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1 >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, pcIError_base & ), t1 v1 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2 >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, pcIError_base & ), t1 v1, t2 v2 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3 >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, pcIError_base & ), t1 v1, t2 v2, t3 v3 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3, typename t4 >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3, typename t4, typename t5 >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, t5, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4, t5 v5 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6 >
+ shared_ptr< sharedPointerType > CallSafeFunctionReturningPointer( className * ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, pcIError_base & ), t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, v5, v6, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( pcIError_base & ) const )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1 >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( t1, pcIError_base & ) const, t1 v1 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2 >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, pcIError_base & ) const, t1 v1, t2 v2 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3 >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, pcIError_base & ) const, t1 v1, t2 v2, t3 v3 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3, typename t4 >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3, typename t4, typename t5 >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, t5, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, v5, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+
+ template < typename className, typename internalReturnType, typename sharedPointerType, typename t1, typename t2, typename t3, typename t4, typename t5, typename t6 >
+ shared_ptr< sharedPointerType > CallConstSafeFunctionReturningPointer( const className * const ptr,
+ internalReturnType( APICALL className::*Func )( t1, t2, t3, t4, t5, t6, pcIError_base & ) const, t1 v1, t2 v2, t3 v3, t4 v4, t5 v5, t6 v6 )
+ {
+ pcIError_base error( NULL );
+ internalReturnType returnValue = ( ptr->*Func )( v1, v2, v3, v4, v5, v6, error );
+ if ( error ) throw IError::MakeShared( error );
+ return sharedPointerType::MakeShared( returnValue );
+ }
+}
+//! \endcond
+#endif // TWrapperFunctions2_h__
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonDefines.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonDefines.h
new file mode 100644
index 0000000000..d63de3559e
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonDefines.h
@@ -0,0 +1,166 @@
+#ifndef __XMPCommonDefines_h__
+#define __XMPCommonDefines_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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_CommonDefines.h - Common Defines across all the XMP Components
+// ================================================================
+//
+// This header defines common definitions to be used across all the XMP Components.
+//
+// =================================================================================================
+
+// =================================================================================================
+// All Platform Settings
+// ===========================
+#include "XMP_Environment.h"
+#if !XMP_WinBuild
+ #include <ciso646>
+#endif
+ // =================================================================================================
+ // Macintosh Specific Settings
+ // ===========================
+ #if XMP_MacBuild
+ #define SUPPORT_STD_ATOMIC_IMPLEMENTATION 0
+ #ifdef _LIBCPP_VERSION
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 0
+ #define SUPPORT_SHARED_POINTERS_IN_STD 1
+ #else
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 1
+ #define SUPPORT_SHARED_POINTERS_IN_STD 0
+ #endif
+ #define SUPPORT_SHARED_POINTERS_WITH_ALLOCATORS 0
+ #define BAD_EXCEPTION_SUPPORT_STRINGS 0
+ #define VECTOR_SUPPORT_CONST_ITERATOR_FUNCTIONS 0
+ #define SUPPORT_VARIADIC_TEMPLATES 0
+ #endif
+
+ // =================================================================================================
+ // IOS Specific Settings
+ // ===========================
+ #if XMP_iOSBuild
+ #define SUPPORT_STD_ATOMIC_IMPLEMENTATION 0
+ #ifdef _LIBCPP_VERSION
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 0
+ #define SUPPORT_SHARED_POINTERS_IN_STD 1
+ #else
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 1
+ #define SUPPORT_SHARED_POINTERS_IN_STD 0
+ #endif
+ #define SUPPORT_SHARED_POINTERS_WITH_ALLOCATORS 0
+ #define BAD_EXCEPTION_SUPPORT_STRINGS 0
+ #define VECTOR_SUPPORT_CONST_ITERATOR_FUNCTIONS 0
+ #define SUPPORT_VARIADIC_TEMPLATES 0
+ #endif
+
+ // =================================================================================================
+ // Windows Specific Settings
+ // =========================
+ #if XMP_WinBuild
+ #define SUPPORT_SHARED_POINTERS_WITH_ALLOCATORS 1
+ #if _MSC_VER <= 1600
+ #define SUPPORT_STD_ATOMIC_IMPLEMENTATION 0
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 1
+ #define SUPPORT_SHARED_POINTERS_IN_STD 0
+ #else
+ #define SUPPORT_STD_ATOMIC_IMPLEMENTATION 1
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 0
+ #define SUPPORT_SHARED_POINTERS_IN_STD 1
+ #endif
+ #define BAD_EXCEPTION_SUPPORT_STRINGS 1
+ #define VECTOR_SUPPORT_CONST_ITERATOR_FUNCTIONS 1
+ #endif
+
+ // =================================================================================================
+ // UNIX Specific Settings
+ // ======================
+ #if XMP_UNIXBuild
+ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+ #if GCC_VERSION >= 40800
+ #define SUPPORT_STD_ATOMIC_IMPLEMENTATION 1
+ #else
+ #define REQ_FRIEND_CLASS_DECLARATION() template<typename _Ptr, std::_Lock_policy _Lp> friend class std::_Sp_counted_ptr;
+ #define SUPPORT_STD_ATOMIC_IMPLEMENTATION 0
+ #endif
+
+ #define SUPPORT_SHARED_POINTERS_IN_TR1 0
+ #define SUPPORT_SHARED_POINTERS_IN_STD 1
+ #define SUPPORT_SHARED_POINTERS_WITH_ALLOCATORS 0
+ #define BAD_EXCEPTION_SUPPORT_STRINGS 0
+ #define VECTOR_SUPPORT_CONST_ITERATOR_FUNCTIONS 1
+ #define SUPPORT_DYNAMIC_CAST_OPTIMIZATION 0
+ #define SUPPORT_VARIADIC_TEMPLATES 0
+ #endif
+
+ #ifndef SUPPORT_VARIADIC_TEMPLATES
+ #define SUPPORT_VARIADIC_TEMPLATES 1
+ #endif
+
+ #ifndef REQ_FRIEND_CLASS_DECLARATION
+ #define REQ_FRIEND_CLASS_DECLARATION()
+ #endif
+
+ #define JOIN_CLASSNAME_WITH_VERSION_NUMBER_INT(x,y) x ## _v ## y
+ #define JOIN_CLASSNAME_WITH_VERSION_NUMBER(x,y) JOIN_CLASSNAME_WITH_VERSION_NUMBER_INT(x,y)
+ #define BASE_CLASS(classNameWithoutVersionNumber, versionNumber) JOIN_CLASSNAME_WITH_VERSION_NUMBER(classNameWithoutVersionNumber, versionNumber)
+ #define EXPAND_MACRO(X) X
+ #define QUOTEME2(X) #X
+ #define QUOTEME(X) QUOTEME2(X)
+
+ #define __NOTHROW__ throw()
+
+ #if SOURCE_COMPILING_XMP_ALL || SOURCE_COMPILING_XMPCORE_LIB || SOURCE_COMPILING_XMPCOMPAREANDMERGE_LIB || SOURCE_COMPILING_XMPEXTENSIONS_LIB
+ #define SOURCE_COMPILING_XMPCOMMON_LIB 1
+ #else
+ #define SOURCE_COMPILING_XMPCOMMON_LIB 0
+ #endif
+
+ #ifndef BUILDING_XMPCOMMON_LIB
+ #define BUILDING_XMPCOMMON_LIB 0
+ #endif
+
+ #if BUILDING_XMPCOMMON_LIB
+ #if !BUILDING_XMPCOMMON_AS_STATIC && !BUILDING_XMPCOMMON_AS_DYNAMIC
+ #error "Define either BUILDING_XMPCOMMON_AS_STATIC as 1 or BUILDING_XMPCOMMON_AS_DYNAMIC as 1"
+ #endif
+ #endif
+
+ #ifndef __XMP_Const_h__
+ #include "XMP_Const.h"
+ #endif
+
+ namespace AdobeXMPCommon {
+
+ typedef XMP_Int64 int64;
+ typedef XMP_Uns64 uint64;
+ typedef XMP_Int32 int32;
+ typedef XMP_Uns32 uint32;
+ #if !XMP_64
+ typedef uint32 sizet;
+ #else
+ typedef uint64 sizet;
+ #endif
+
+ const sizet kMaxSize ( ( sizet ) -1 );
+ const sizet npos ( kMaxSize );
+
+ // force an enum type to be represented in 32 bits
+ static const uint32 kMaxEnumValue ( Max_XMP_Uns32 );
+ static const uint32 kAllBits ( 0xFFFFFFFF );
+
+ // unique ids for the interfaces defined in the namespace
+ static const uint64 kIErrorID ( 0x6e4572726f722020 /* nError */ );
+ static const uint64 kIUTF8StringID ( 0x6e55544638537472 /* nUTF8Str */ );
+ static const uint64 kIObjectFactoryID ( 0x6e4f626a46616374 /* nObjFact */ );
+ static const uint64 kIErrorNotifierID ( 0x6e4572724e6f7466 /* nErrNotf */ );
+ static const uint64 kIConfigurationManagerID ( 0x6e436f6e664d6772 /* nConfMgr */ );
+ } // namespace AdobeXMPCommon
+
+#endif // __XMPCommonDefines_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonErrorCodes.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonErrorCodes.h
new file mode 100644
index 0000000000..22997dabbd
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonErrorCodes.h
@@ -0,0 +1,114 @@
+#ifndef XMPCommonErrorCodes_h__
+#define XMPCommonErrorCodes_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/XMPCommonDefines.h"
+
+namespace AdobeXMPCommon {
+
+ //!
+ //! @brief Indicates various types of error codes within General Domain.
+ //!
+ typedef enum {
+ //! Indicates no error
+ kGECNone = 0,
+
+ //! Indicates that parameters passed to function are not as expected.
+ kGECParametersNotAsExpected = 1,
+
+ //! Indicates that version expected by client is not available in the library.
+ kGECVersionUnavailable = 2,
+
+ //! Indicates that some assertion has failed.
+ kGECAssertionFailure = 3,
+
+ //! Indicates logic failure.
+ kGECLogicalError = 4,
+
+ //! Indicates index provided is out of bounds.
+ kGECIndexOutOfBounds = 5,
+
+ //! Indicates an internal failure.
+ kGECInternalFailure = 6,
+
+ //! Indicates a call to deprecated function.
+ kGECDeprecatedFunctionCall = 7,
+
+ //! Indicates an external failure.
+ kGECExternalFailure = 8,
+
+ //! Indicates an unknown failure.
+ kGECUnknownFailure = 9,
+
+ //! Indicates an error due to User Abort.
+ kGECUserAbort = 10,
+
+ //! Indicates a particular interface is not available.
+ kGECInterfaceUnavailable = 11,
+
+ //! Indicates that client code has thrown some exception.
+ kGECClientThrownExceptionCaught = 100,
+
+ //! Indicates that standard exception has occurred.
+ kGECStandardException = 101,
+
+ //! Indicates that some unknown exception has occurred.
+ kGECUnknownExceptionCaught = 200,
+
+ //! Indicates that functionality is not yet implemented.
+ kGECNotImplemented = 10000,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kGECMaxValue = kMaxEnumValue
+ } eGeneralErrorCode;
+
+ //!
+ //! @brief Indicates various types of error codes within Memory Management domain.
+ //!
+ typedef enum {
+ //! Indicates no error
+ kMMECNone = 0,
+
+ //! Indicates that allocation has failed.
+ kMMECAllocationFailure = 1,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kMMECMaxValue = kMaxEnumValue
+ } eMemoryManagementErrorCode;
+
+ //!
+ //! @brief Indicates various types of error codes within Configurable domain.
+ //!
+ typedef enum {
+ //! Indicates no error.
+ kCECNone = 0,
+
+ //! Indicates that key is not supported by the object.
+ kCECKeyNotSupported = 1,
+
+ //! Indicates different type of value provided than the one supported for a key.
+ kCECValueTypeNotSupported = 2,
+
+ //! Indicates that different value type is previously stored for a key.
+ kCECPreviousTypeDifferent = 3,
+
+ //! Indicates the type of value stored for a key is different than what client is asking for.
+ kCECValueTypeMismatch = 4,
+
+ //! Indicates an invalid value is provided.
+ kCECValueNotSupported = 5,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kCECodeMaxValue = 0xFFFFFFFF
+ } eConfigurableErrorCode;
+}
+
+#endif // XMPCommonErrorCodes_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonFwdDeclarations.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonFwdDeclarations.h
new file mode 100644
index 0000000000..dce21ec97d
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonFwdDeclarations.h
@@ -0,0 +1,158 @@
+#ifndef __XMPCommonFwdDeclarations_h__
+#define __XMPCommonFwdDeclarations_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/XMPCommonDefines.h"
+#include "XMPCommon/XMPCommonLatestInterfaceVersions.h"
+#include <vector>
+
+#if SUPPORT_SHARED_POINTERS_IN_STD
+ #include <memory>
+ #include <functional>
+#elif SUPPORT_SHARED_POINTERS_IN_TR1
+ #if XMP_WinBuild
+ #include <memory>
+ #else
+ #include <tr1/memory>
+ #include <tr1/functional>
+ #endif
+#else
+ #error "location of shared pointer stuff is unknown"
+#endif
+
+namespace AdobeXMPCommon {
+
+ #if SUPPORT_SHARED_POINTERS_IN_STD
+ using std::shared_ptr;
+ using std::enable_shared_from_this;
+ using std::mem_fn;
+ #elif SUPPORT_SHARED_POINTERS_IN_TR1
+ using std::tr1::shared_ptr;
+ using std::tr1::enable_shared_from_this;
+ using std::tr1::mem_fn;
+ #endif
+
+ // void
+ typedef void * pvoid;
+ typedef const void * pcvoid;
+ typedef shared_ptr< void > spvoid;
+ typedef shared_ptr< const void * > spcvoid;
+
+ // IObjectFactory
+ class IObjectFactory_v1;
+ typedef IObjectFactory_v1 IObjectFactory_base;
+ typedef IObjectFactory_v1 * pIObjectFactory_base;
+ typedef const IObjectFactory_v1 * pcIObjectFactory_base;
+ typedef BASE_CLASS( IObjectFactory, IOBJECTFACTORY_VERSION ) IObjectFactory;
+ typedef IObjectFactory * pIObjectFactory;
+ typedef const IObjectFactory * pcIObjectFactory;
+
+ // IError
+ class IError_v1;
+ typedef IError_v1 IError_base;
+ typedef IError_v1 * pIError_base;
+ typedef const IError_v1 * pcIError_base;
+ typedef BASE_CLASS( IError, IERROR_VERSION ) IError;
+ typedef IError * pIError;
+ typedef const IError * pcIError;
+ typedef shared_ptr< IError > spIError;
+ typedef shared_ptr< const IError > spcIError;
+
+ // IUTF8String
+ class IUTF8String_v1;
+ typedef IUTF8String_v1 IUTF8String_base;
+ typedef IUTF8String_v1 * pIUTF8String_base;
+ typedef const IUTF8String_v1 * pcIUTF8String_base;
+ typedef BASE_CLASS( IUTF8String, IUTF8STRING_VERSION ) IUTF8String;
+ typedef IUTF8String * pIUTF8String;
+ typedef const IUTF8String * pcIUTF8String;
+ typedef shared_ptr< IUTF8String > spIUTF8String;
+ typedef shared_ptr< const IUTF8String > spcIUTF8String;
+
+ // IMemoryAllocator
+ class IMemoryAllocator_v1;
+ typedef IMemoryAllocator_v1 IMemoryAllocator_base;
+ typedef IMemoryAllocator_v1 * pIMemoryAllocator_base;
+ typedef const IMemoryAllocator_v1 * pcIMemoryAllocator_base;
+ typedef BASE_CLASS( IMemoryAllocator, IMEMORYALLOCATOR_VERSION ) IMemoryAllocator;
+ typedef IMemoryAllocator * pIMemoryAllocator;
+ typedef const IMemoryAllocator * pcIMemoryAllocator;
+ typedef shared_ptr< IMemoryAllocator > spIMemoryAllocator;
+ typedef shared_ptr< const IMemoryAllocator > spcIMemoryAllocator;
+
+ // IErrorNotifier
+ class IErrorNotifier_v1;
+ typedef IErrorNotifier_v1 IErrorNotifier_base;
+ typedef IErrorNotifier_v1 * pIErrorNotifier_base;
+ typedef const IErrorNotifier_v1 * pcIErrorNotifier_base;
+ typedef BASE_CLASS( IErrorNotifier, IERRORNOTIFIER_VERSION ) IErrorNotifier;
+ typedef IErrorNotifier * pIErrorNotifier;
+ typedef const IErrorNotifier * pcIErrorNotifier;
+ typedef shared_ptr< IErrorNotifier > spIErrorNotifier;
+ typedef shared_ptr< const IErrorNotifier > spcIErrorNotifier;
+
+ // IConfigurationManager
+ class IConfigurationManager_v1;
+ typedef IConfigurationManager_v1 IConfigurationManager_base;
+ typedef IConfigurationManager_v1 * pIConfigurationManager_base;
+ typedef const IConfigurationManager_v1 * pcIConfigurationManager_base;
+ typedef BASE_CLASS( IConfigurationManager, ICONFIGURATIONMANAGER_VERSION ) IConfigurationManager;
+ typedef IConfigurationManager * pIConfigurationManager;
+ typedef const IConfigurationManager * pcIConfigurationManager;
+ typedef shared_ptr< IConfigurationManager > spIConfigurationManager;
+ typedef shared_ptr< const IConfigurationManager > spcIConfigurationManager;
+
+ // IConfigurable
+ class IConfigurable;
+ typedef IConfigurable * pIConfigurable;
+ typedef const IConfigurable * pcIConfigurable;
+
+ // typedefs for vectors and their corresponding shared pointers.
+ typedef std::vector< spIUTF8String > IUTF8Strings;
+ typedef std::vector< spcIUTF8String > cIUTF8Strings;
+ typedef shared_ptr< IUTF8Strings > spIUTF8Strings;
+ typedef shared_ptr< cIUTF8Strings > spcIUTF8Strings;
+ typedef shared_ptr< const IUTF8Strings > spIUTF8Strings_const;
+ typedef shared_ptr< const cIUTF8Strings > spcIUTF8Strings_const;
+
+ //!
+ //! @brief A function pointer to get the memory allocated from the library.
+ //! \param[in] size a value indicating the number of bytes to be allocated.
+ //! \return a pointer to memory allocated by the library.
+ //! \note NULL value is returned in case memory allocation fails.
+ //!
+ typedef void * ( *MemAllocateProc )( sizet sz );
+ void * MemAllocate( sizet size ) __NOTHROW__;
+
+ //!
+ //! @brief A function pointer to get the memory freed from the library.
+ //! \param[in] ptr address of the memory location to be freed.
+ //!
+ typedef void( *MemReleaseProc )( void * ptr );
+ void MemRelease( void * ptr ) __NOTHROW__;
+
+} // namespace AdobeXMPCommon
+
+namespace AdobeXMPCommon_Int {
+
+ // ISharedObject_I
+ class ISharedObject_I;
+ typedef ISharedObject_I * pISharedObject_I;
+ typedef const ISharedObject_I * pcISharedObject_I;
+
+ // IThreadSafe_I
+ class IThreadSafe_I;
+ typedef IThreadSafe_I * pIThreadSafe_I;
+ typedef const IThreadSafe_I * pcIThreadSafe_I;
+
+}
+
+#endif // __XMPCommonFwdDeclarations_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonLatestInterfaceVersions.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonLatestInterfaceVersions.h
new file mode 100644
index 0000000000..d7f5add6c2
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/XMPCommonLatestInterfaceVersions.h
@@ -0,0 +1,51 @@
+#ifndef XMPCommonLatestInterfaceVersions_h__
+#define XMPCommonLatestInterfaceVersions_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+//!
+//!@brief Macro to include a client file through with client can control the interface versions he wants to stick with
+//!if not the latest ones.
+//!
+#if !SOURCE_COMPILING_XMPCOMMON_LIB
+ #ifdef XMPCOMMON_CLIENT_VERSION_NUMBER_FILE
+ #include QUOTEME(XMPCOMMON_CLIENT_VERSION_NUMBER_FILE)
+ #endif
+#endif
+
+#ifndef IOBJECTFACTORY_VERSION
+ #define IOBJECTFACTORY_VERSION 1
+#endif
+
+#ifndef IERROR_VERSION
+ #define IERROR_VERSION 1
+#endif
+
+#ifndef IUTF8STRING_VERSION
+ #define IUTF8STRING_VERSION 1
+#endif
+
+#ifndef IMEMORYALLOCATOR_VERSION
+ #define IMEMORYALLOCATOR_VERSION 1
+#endif
+
+#ifndef IERRORNOTIFIER_VERSION
+ #define IERRORNOTIFIER_VERSION 1
+#endif
+
+#ifndef ICONFIGURATIONMANAGER_VERSION
+ #define ICONFIGURATIONMANAGER_VERSION 1
+#endif
+
+#ifndef ICONFIGURABLE_VERSION
+ #define ICONFIGURABLE_VERSION 1
+#endif
+
+#endif // XMPCommonLatestInterfaceVersions_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IConfigurable.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IConfigurable.cpp
new file mode 100644
index 0000000000..fb8e2f3a88
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IConfigurable.cpp
@@ -0,0 +1,204 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h"
+
+#if !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include <assert.h>
+
+namespace AdobeXMPCommon {
+
+ IConfigurableProxy::IConfigurableProxy( pIConfigurable configurable )
+ : mConfigurableRawPtr( configurable ) { }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, bool value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.uint32Value = value ? 1 : 0;
+ CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTBool ), combinedValue
+ );
+ }
+
+ void APICALL IConfigurableProxy::setParameter( const uint64 & key, uint32 dataType, const CombinedDataValue & dataValue, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mConfigurableRawPtr->setParameter( key, dataType, dataValue, error );
+ }
+
+ bool APICALL IConfigurableProxy::RemoveParameter( const uint64 & key ) {
+ return CallSafeFunction< IConfigurable, bool, uint32, const uint64 & >(
+ mConfigurableRawPtr, &IConfigurable::removeParameter, key );
+ }
+
+ uint32 APICALL IConfigurableProxy::removeParameter( const uint64 & key, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mConfigurableRawPtr->removeParameter( key, error );
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, bool & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTBool ), combinedValue
+ );
+ value = combinedValue.uint32Value != 0 ? 1 : 0;
+ return returnValue;
+ }
+
+ uint32 APICALL IConfigurableProxy::getParameter( const uint64 & key, uint32 dataType, CombinedDataValue & value, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mConfigurableRawPtr->getParameter( key, dataType, value, error );
+ }
+
+ std::vector< uint64 > APICALL IConfigurableProxy::GetAllParameters() const {
+ sizet nElements = mConfigurableRawPtr->Size();
+ std::vector< uint64 > vec( nElements );
+ if ( nElements > 0 )
+ mConfigurableRawPtr->getAllParameters( vec.data(), nElements );
+ return vec;
+ }
+
+ void APICALL IConfigurableProxy::getAllParameters( uint64 * array, sizet count ) const __NOTHROW__ {
+ assert( false );
+ return mConfigurableRawPtr->getAllParameters( array, count );
+ }
+
+ sizet APICALL IConfigurableProxy::Size() const __NOTHROW__ {
+ return mConfigurableRawPtr->Size();
+ }
+
+ IConfigurable::eDataType APICALL IConfigurableProxy::GetDataType( const uint64 & key ) const {
+ return CallConstSafeFunction< IConfigurable, eDataType, uint32, const uint64 & >(
+ mConfigurableRawPtr, &IConfigurable::getDataType, key );
+ }
+
+ uint32 APICALL IConfigurableProxy::getDataType( const uint64 & key, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mConfigurableRawPtr->getDataType( key, error );
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, const void * & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTConstVoidPtr ), combinedValue
+ );
+ value = combinedValue.constVoidPtrValue;
+ return returnValue;
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, const char * & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTConstCharBuffer ), combinedValue
+ );
+ value = combinedValue.constCharPtrValue;
+ return returnValue;
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, char & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTChar ), combinedValue
+ );
+ value = combinedValue.charValue;
+ return returnValue;
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, double & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTDouble ), combinedValue
+ );
+ value = combinedValue.doubleValue;
+ return returnValue;
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, int64 & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTInt64 ), combinedValue
+ );
+ value = combinedValue.int64Value;
+ return returnValue;
+ }
+
+ bool APICALL IConfigurableProxy::GetParameter( const uint64 & key, uint64 & value ) const {
+ CombinedDataValue combinedValue;
+ bool returnValue = CallConstSafeFunction< IConfigurable, bool, uint32, const uint64 &, uint32, CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::getParameter, key, static_cast< uint32 >( IConfigurable::kDTUint64 ), combinedValue
+ );
+ value = combinedValue.uint64Value;
+ return returnValue;
+ }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, const void * value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.constVoidPtrValue= value;
+ return CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTConstVoidPtr ), combinedValue
+ );
+ }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, const char * value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.constCharPtrValue = value;
+ return CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTConstCharBuffer ), combinedValue
+ );
+ }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, char value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.charValue = value;
+ return CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTChar ), combinedValue
+ );
+ }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, double value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.doubleValue = value;
+ return CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTDouble ), combinedValue
+ );
+ }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, int64 value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.int64Value = value;
+ return CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTInt64 ), combinedValue
+ );
+ }
+
+ void APICALL IConfigurableProxy::SetParameter( const uint64 & key, uint64 value ) {
+ CombinedDataValue combinedValue;
+ combinedValue.uint64Value = value;
+ return CallSafeFunctionReturningVoid< IConfigurable, const uint64 &, uint32, const CombinedDataValue &
+ >(
+ mConfigurableRawPtr, &IConfigurable::setParameter, key, static_cast< uint32 >( IConfigurable::kDTUint64 ), combinedValue
+ );
+ }
+
+}
+
+#endif // !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IConfigurationManager.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IConfigurationManager.cpp
new file mode 100644
index 0000000000..0cfdab1d6b
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IConfigurationManager.cpp
@@ -0,0 +1,92 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 FRIEND_CLASS_DECLARATION() friend class IConfigurationManagerProxy;
+
+#include "XMPCommon/Interfaces/IConfigurationManager.h"
+
+#if !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IError.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCommon {
+
+ void APICALL IConfigurationManagerProxy::Acquire() const __NOTHROW__ {
+ assert( false );
+ }
+
+ void APICALL IConfigurationManagerProxy::Release() const __NOTHROW__ {
+ assert( false );
+ }
+
+ pvoid APICALL IConfigurationManagerProxy::getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ pvoid APICALL IConfigurationManagerProxy::GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return AdobeXMPCommon::CallSafeFunction<
+ IVersionable, pvoid, pvoid, uint64, uint32
+ >( mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ uint32 APICALL IConfigurationManagerProxy::registerMemoryAllocator( pIMemoryAllocator_base memoryAllocator, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->registerMemoryAllocator( memoryAllocator, error );
+ }
+
+ bool APICALL IConfigurationManagerProxy::RegisterMemoryAllocator( pIMemoryAllocator memoryAllocator ) {
+ return CallSafeFunction< IConfigurationManager, bool, uint32, pIMemoryAllocator_base >(
+ mRawPtr, &IConfigurationManager::registerMemoryAllocator, memoryAllocator );
+ }
+
+ uint32 APICALL IConfigurationManagerProxy::registerErrorNotifier( pIErrorNotifier_base clientErrorNotifier, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->registerErrorNotifier( clientErrorNotifier, error );
+ }
+
+ bool APICALL IConfigurationManagerProxy::RegisterErrorNotifier( pIErrorNotifier_base clientErrorNotifier ) {
+ return CallSafeFunction< IConfigurationManager, bool, uint32, pIErrorNotifier_base >(
+ mRawPtr, &IConfigurationManager::registerErrorNotifier, clientErrorNotifier );
+ }
+
+ uint32 APICALL IConfigurationManagerProxy::disableMultiThreading( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->disableMultiThreading( error );
+ }
+
+ bool APICALL IConfigurationManagerProxy::DisableMultiThreading() {
+ return CallSafeFunction< IConfigurationManager, bool, uint32 >(
+ mRawPtr, &IConfigurationManager::disableMultiThreading );
+ }
+
+ uint32 APICALL IConfigurationManagerProxy::isMultiThreaded( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isMultiThreaded( error );
+ }
+
+ bool APICALL IConfigurationManagerProxy::IsMultiThreaded() const {
+ return CallConstSafeFunction< IConfigurationManager, bool, uint32 >(
+ mRawPtr, &IConfigurationManager::isMultiThreaded );
+ }
+
+ spIConfigurationManager IConfigurationManager_v1::MakeShared( pIConfigurationManager_base ptr ) {
+ if ( !ptr ) return spIConfigurationManager();
+ pIConfigurationManager p = IConfigurationManager::GetInterfaceVersion() > 1 ?
+ ptr->GetInterfacePointer< IConfigurationManager >() : ptr;
+ return shared_ptr< IConfigurationManager >( new IConfigurationManagerProxy( p ) );
+ }
+
+}
+
+#endif // !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_LIB
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IError.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IError.cpp
new file mode 100644
index 0000000000..8f763d385e
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IError.cpp
@@ -0,0 +1,207 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 FRIEND_CLASS_DECLARATION() friend class IErrorProxy;
+
+#include "XMPCommon/Interfaces/IError.h"
+
+#if !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCommon/Interfaces/IObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCommon {
+ class IErrorProxy
+ : public virtual IError
+ {
+ private:
+ pIError mRawPtr;
+
+ public:
+ IErrorProxy( pIError ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IErrorProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIError APICALL GetActualIError() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction<
+ IVersionable, pvoid, pvoid, uint64, uint32
+ >( mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ eErrorCode APICALL GetCode() const {
+ return CallConstSafeFunction< IError, eErrorCode, uint32 >(
+ mRawPtr, &IError::getCode );
+ }
+
+ uint32 APICALL getCode( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getCode( error );
+ }
+
+ eErrorDomain APICALL GetDomain() const {
+ return CallConstSafeFunction< IError, eErrorDomain, uint32 >(
+ mRawPtr, &IError::getDomain );
+ }
+
+ uint32 APICALL getDomain( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getDomain( error );
+ }
+
+ eErrorSeverity APICALL GetSeverity() const {
+ return CallConstSafeFunction< IError, eErrorSeverity, uint32 >(
+ mRawPtr, &IError::getSeverity );
+ }
+
+ uint32 APICALL getSeverity( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getSeverity( error );
+ }
+
+ spcIUTF8String APICALL GetMessage() const {
+ return CallConstSafeFunctionReturningPointer< IError, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &IError::getMessage );
+ }
+
+ pcIUTF8String_base APICALL getMessage( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getMessage( error );
+ }
+
+ spcIUTF8String APICALL GetLocation() const {
+ return CallConstSafeFunctionReturningPointer< IError, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &IError::getLocation );
+ }
+
+ pcIUTF8String_base APICALL getLocation( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getLocation( error );
+ }
+
+ spcIUTF8String APICALL GetParameter( sizet index ) const {
+ return CallConstSafeFunctionReturningPointer< IError, pcIUTF8String_base, const IUTF8String, sizet >(
+ mRawPtr, &IError::getParameter, index );
+ }
+
+ pcIUTF8String_base APICALL getParameter( sizet index, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getParameter( index, error );
+ }
+
+ sizet APICALL GetParametersCount() const __NOTHROW__ {
+ return mRawPtr->GetParametersCount();
+ }
+
+ spIError APICALL GetNextError() {
+ pcIError_base error( NULL );
+ pIError_base ptr = mRawPtr->getNextError( error );
+ if ( error ) throw MakeShared( error );
+ return MakeShared( ptr );
+ }
+
+ pIError_base APICALL getNextError( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNextError( error );
+ }
+
+ spIError APICALL SetNextError( const spIError & nextError ) {
+ pcIError_base error( NULL );
+ pIError_base ptr = mRawPtr->setNextError( nextError ? nextError->GetActualIError() : NULL, error );
+ if ( error ) throw MakeShared( error );
+ return MakeShared( ptr );
+ }
+
+ pIError_base APICALL setNextError( pIError_base nextError, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->setNextError( nextError, error );
+ }
+
+ void APICALL SetMessage( const char * message, sizet len ) __NOTHROW__ {
+ mRawPtr->SetMessage( message, len );
+ }
+
+ void APICALL SetLocation( const char * fileName, sizet lineNumber ) __NOTHROW__ {
+ mRawPtr->SetLocation( fileName, lineNumber );
+ }
+
+ void APICALL AppendParameter( const char * parameter, sizet len ) __NOTHROW__ {
+ mRawPtr->AppendParameter( parameter, len );
+ }
+
+ void APICALL AppendParameter( void * addressParameter ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( addressParameter );
+ }
+
+ void APICALL AppendParameter( const uint32 & integerValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( integerValue );
+ }
+
+ void APICALL AppendParameter( const uint64 & integerValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( integerValue );
+ }
+
+ void APICALL AppendParameter( const int32 & integerValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( integerValue );
+ }
+
+ void APICALL AppendParameter( const int64 & integerValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( integerValue );
+ }
+
+ void APICALL AppendParameter( const float & floatValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( floatValue );
+ }
+
+ void APICALL AppendParameter( const double & doubleValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( doubleValue );
+ }
+
+ void APICALL AppendParameter( bool booleanValue ) __NOTHROW__ {
+ return mRawPtr->AppendParameter( booleanValue );
+ }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ };
+
+ spIError IError_v1::CreateError( pIObjectFactory objFactory, eErrorDomain errDomain, eErrorCode errCode, eErrorSeverity errSeverity ) {
+ pIError_base temp = CallSafeFunction< IObjectFactory_base, pIError_base, pIError_base, uint32, uint32, uint32 >(
+ objFactory, &IObjectFactory_base::CreateError, static_cast< uint32 >( errDomain ),
+ static_cast< uint32 >( errCode ), static_cast< uint32 >( errSeverity ) );
+ return MakeShared( temp );
+ }
+
+ spIError IError_v1::MakeShared( pIError_base ptr ) {
+ if ( !ptr ) return spIError();
+ pIError p = IError::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer<IError>() : ptr;
+ return shared_ptr< IError >( new IErrorProxy( p ) );
+ }
+}
+
+#endif // !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IErrorNotifier.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IErrorNotifier.cpp
new file mode 100644
index 0000000000..acc8486e49
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IErrorNotifier.cpp
@@ -0,0 +1,26 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCommon/Interfaces/IErrorNotifier.h"
+#include "XMPCommon/Interfaces/IError.h"
+
+namespace AdobeXMPCommon {
+ uint32 APICALL IErrorNotifier_v1::notify( pcIError_base error, uint32 & exceptionThrown ) __NOTHROW__ {
+ exceptionThrown = 0;
+ bool retValue( false );
+ try {
+ retValue = Notify( IError::MakeShared( error ) );
+ } catch ( ... ) {
+ exceptionThrown = 1;
+ }
+ return retValue ? 1 : 0;
+ }
+
+}
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IUTF8String.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IUTF8String.cpp
new file mode 100644
index 0000000000..5f24b0e249
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCommon/source/IUTF8String.cpp
@@ -0,0 +1,299 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 FRIEND_CLASS_DECLARATION() friend class IUTF8StringProxy;
+
+#include "XMPCommon/Interfaces/IUTF8String.h"
+
+#if !BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCommon {
+
+ class IUTF8StringProxy
+ : public virtual IUTF8String
+ , public enable_shared_from_this< IUTF8StringProxy >
+ {
+ private:
+ pIUTF8String mRawPtr;
+
+ public:
+ IUTF8StringProxy( pIUTF8String ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IUTF8StringProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIUTF8String APICALL GetActualIUTF8String() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ spIUTF8String APICALL append( const char * buf, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, const char *, sizet >(
+ mRawPtr, &IUTF8String::append, buf, count )->Release();
+ return shared_from_this();
+ }
+
+ spIUTF8String APICALL append( const spcIUTF8String & src, sizet srcPos, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::append, src ? src->GetActualIUTF8String() : NULL, srcPos, count )->Release();
+ return shared_from_this();
+ }
+
+ pIUTF8String_base APICALL append( const char * buffer, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->append( buffer, count, error );
+ return this;
+ }
+
+ pIUTF8String_base APICALL append( pcIUTF8String_base str, sizet srcPos, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->append( str, srcPos, count, error );
+ return this;
+ }
+
+ spIUTF8String APICALL assign( const char * buf, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, const char *, sizet >(
+ mRawPtr, &IUTF8String::assign, buf, count )->Release();
+ return shared_from_this();
+ }
+
+ spIUTF8String APICALL assign( const spcIUTF8String & src, sizet srcPos, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::assign, src ? src->GetActualIUTF8String() : NULL, srcPos, count )->Release();
+ return shared_from_this();
+ }
+
+ pIUTF8String_base APICALL assign( const char * buffer, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->assign( buffer, count, error );
+ return this;
+ }
+
+ pIUTF8String_base APICALL assign( pcIUTF8String_base str, sizet srcPos, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->assign( str, srcPos, count, error );
+ return this;
+ }
+
+ spIUTF8String APICALL insert( sizet pos, const char * buf, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, sizet, const char *, sizet >(
+ mRawPtr, &IUTF8String::insert, pos, buf, count )->Release();
+ return shared_from_this();
+ }
+
+ spIUTF8String APICALL insert( sizet pos, const spcIUTF8String & src, sizet srcPos, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, sizet, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::insert, pos, src ? src->GetActualIUTF8String() : NULL, srcPos, count )->Release();
+ return shared_from_this();
+ }
+
+ pIUTF8String_base APICALL insert( sizet pos, const char * buf, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->insert( pos, buf, count, error );
+ return this;
+ }
+
+ pIUTF8String_base APICALL insert( sizet pos, pcIUTF8String_base src, sizet srcPos, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->insert( pos, src, srcPos, count, error );
+ return this;
+ }
+
+ spIUTF8String APICALL erase( sizet pos, sizet count ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::erase, pos, count )->Release();
+ return shared_from_this();
+ }
+
+ pIUTF8String_base APICALL erase( sizet pos, sizet count, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->erase( pos, count, error );
+ return this;
+ }
+
+ void APICALL resize( sizet n ) {
+ CallSafeFunctionReturningVoid< IUTF8String, sizet >(
+ mRawPtr, &IUTF8String::resize, n );
+ }
+
+ virtual void APICALL resize( sizet n, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->resize( n, error );
+ }
+
+ spIUTF8String APICALL replace( sizet pos, sizet count, const char * buf, sizet srcCount ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, sizet, sizet, const char *, sizet >(
+ mRawPtr, &IUTF8String::replace, pos, count, buf, srcCount )->Release();
+ return shared_from_this();
+ }
+
+ spIUTF8String APICALL replace( sizet pos, sizet count, const spcIUTF8String & src, sizet srcPos, sizet srcCount ) {
+ CallSafeFunction< IUTF8String, pIUTF8String_base, pIUTF8String_base, sizet, sizet, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::replace, pos, count, src ? src->GetActualIUTF8String() : NULL, srcPos, srcCount )->Release();
+ return shared_from_this();
+ }
+
+ pIUTF8String_base APICALL replace( sizet pos, sizet count, const char * buf, sizet srcCount, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->replace( pos, count, buf, srcCount, error );
+ return this;
+ }
+
+ pIUTF8String_base APICALL replace( sizet pos, sizet count, pcIUTF8String_base src, sizet srcPos, sizet srcCount, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ mRawPtr->replace( pos, count, src, srcPos, srcCount, error );
+ return this;
+ }
+
+ sizet APICALL copy( char * buf, sizet len, sizet pos ) const {
+ return CallConstSafeFunction< IUTF8String, sizet, sizet, char *, sizet, sizet >(
+ mRawPtr, &IUTF8String::copy, buf, len, pos );
+ }
+
+ sizet APICALL copy( char * buf, sizet len, sizet pos, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->copy( buf, len, pos, error );
+ }
+
+ sizet APICALL find( const char * buf, sizet pos, sizet count ) const {
+ return CallConstSafeFunction< IUTF8String, sizet, sizet, const char *, sizet, sizet >(
+ mRawPtr, &IUTF8String::find, buf, pos, count );
+ }
+
+ sizet APICALL find( const spcIUTF8String & src, sizet pos, sizet count ) const {
+ return CallConstSafeFunction< IUTF8String, sizet, sizet, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::find, src ? src->GetActualIUTF8String() : NULL, pos, count );
+ }
+
+ sizet APICALL find( const char * buf, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->find( buf, pos, count, error );
+ }
+
+ sizet APICALL find( pcIUTF8String_base src, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->find( src, pos, count, error );
+ }
+
+ sizet APICALL rfind( const char * buf, sizet pos, sizet count ) const {
+ return CallConstSafeFunction< IUTF8String, sizet, sizet, const char *, sizet, sizet >(
+ mRawPtr, &IUTF8String::rfind, buf, pos, count );
+ }
+
+ sizet APICALL rfind( const spcIUTF8String & src, sizet pos, sizet count ) const {
+ return CallConstSafeFunction< IUTF8String, sizet, sizet, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::rfind, src ? src->GetActualIUTF8String() : NULL, pos, count );
+ }
+
+ sizet APICALL rfind( const char * buf, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->rfind( buf, pos, count, error );
+ }
+
+ sizet APICALL rfind( pcIUTF8String_base src, sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->rfind( src, pos, count, error );
+ }
+
+ int32 APICALL compare( sizet pos, sizet len, const char * buf, sizet count ) const {
+ return CallConstSafeFunction< IUTF8String, int32, int32, sizet, sizet, const char *, sizet >(
+ mRawPtr, &IUTF8String::compare, pos, len, buf, count );
+ }
+
+ int32 APICALL compare( sizet pos, sizet len, const spcIUTF8String & str, sizet strPos, sizet strLen ) const {
+ return CallConstSafeFunction< IUTF8String, int32, int32, sizet, sizet, pcIUTF8String_base, sizet, sizet >(
+ mRawPtr, &IUTF8String::compare, pos, len, str ? str->GetActualIUTF8String() : NULL, strPos, strLen );
+ }
+
+ int32 APICALL compare( sizet pos, sizet len, const char * buf, sizet count, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->compare( pos, len, buf, count, error );
+ }
+
+ int32 APICALL compare( sizet pos, sizet len, pcIUTF8String_base str, sizet strPos, sizet strLen, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->compare( pos, len, str, strPos, strLen, error );
+ }
+
+ spIUTF8String APICALL substr( sizet pos, sizet count ) const {
+ return CallConstSafeFunctionReturningPointer< IUTF8String, pIUTF8String_base, IUTF8String, sizet, sizet >(
+ mRawPtr, &IUTF8String::substr, pos, count );
+ }
+
+ pIUTF8String_base APICALL substr( sizet pos, sizet count, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->substr( pos, count, error );
+ }
+
+ bool APICALL empty() const {
+ return CallConstSafeFunction< IUTF8String, bool, uint32 >(
+ mRawPtr, &IUTF8String::empty );
+ }
+
+ uint32 APICALL empty( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->empty();
+ }
+
+ const char * APICALL c_str() const __NOTHROW__ {
+ return mRawPtr->c_str();
+ }
+
+ void APICALL clear() __NOTHROW__ {
+ mRawPtr->clear();
+ }
+
+ sizet APICALL size() const __NOTHROW__ {
+ return mRawPtr->size();
+ }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ };
+
+ spIUTF8String IUTF8String_v1::MakeShared( pIUTF8String_base ptr ) {
+ if ( !ptr ) return spIUTF8String();
+ pIUTF8String p = IUTF8String::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IUTF8String >() : ptr;
+ return shared_ptr< IUTF8StringProxy >( new IUTF8StringProxy( p ) );
+ }
+
+ spIUTF8String IUTF8String_v1::CreateUTF8String( pIObjectFactory objFactory ) {
+ return CallSafeFunctionReturningPointer< IObjectFactory, pIUTF8String_base, IUTF8String, const char *, sizet >(
+ objFactory, &IObjectFactory::CreateUTF8String, NULL, ( sizet ) 0 );
+ }
+
+ spIUTF8String IUTF8String_v1::CreateUTF8String( pIObjectFactory objFactory, const char * buf, sizet count ) {
+ return CallSafeFunctionReturningPointer< IObjectFactory, pIUTF8String_base, IUTF8String, const char *, sizet >(
+ objFactory, &IObjectFactory::CreateUTF8String, buf, count );
+ }
+
+}
+
+#endif // BUILDING_XMPCOMMON_LIB && !SOURCE_COMPILING_XMP_ALL
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IArrayNode.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IArrayNode.h
new file mode 100644
index 0000000000..dd189763d4
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IArrayNode.h
@@ -0,0 +1,303 @@
+#ifndef __IArrayNode_h__
+#define __IArrayNode_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/Interfaces/ICompositeNode.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that represents an Array Node of XMP DOM.
+ //! \details Provides all the functions to get and set various properties of the array node.
+ //! \attention Support multi threading through locks but can be enabled/disabled by the client. By default
+ //! every object created does not support multi-threading.
+ //! \note The index of the array is 1-based.
+ //!
+ class XMP_PUBLIC IArrayNode_v1
+ : public virtual ICompositeNode_v1
+ {
+ public:
+
+ //!
+ //! @brief Indicates different kinds of array forms possible in XMP i.e, unordered, ordered and alternative.
+ //!
+ typedef enum {
+ //! unknown array form, should be used as invalid value.
+ kAFNone = 0,
+
+ //! Array contains entries which are unordered.
+ kAFUnordered = 1 << 0,
+
+ //! Array contains entries which are ordered.
+ kAFOrdered = 1 << 1,
+
+ //! Array contains entries which are ordered plus default value should be the top one.
+ kAFAlternative = 1 << 2,
+
+ //! Maximum value this enum can hold, should be treated as invalid value
+ kAFAll = kAllBits
+ } eArrayForm;
+
+ //!
+ //! @brief Get the type of array.
+ //! \return a value of type #eArrayForm indicating the type of array.
+ //!
+ virtual eArrayForm APICALL GetArrayForm() const = 0;
+
+ //!
+ //! @brief Get the type of child nodes.
+ //! \return a value of type #eNodeType indicating the type of child nodes array can hold.
+ //! \note An empty array will return \#INode_v1::kNTAll indicating that right now it can hold any type of node.
+ //!
+ virtual eNodeType APICALL GetChildNodeType() const = 0;
+
+ //!
+ //! @{
+ //! @brief Get the node at the specified index.
+ //! \param[in] index an object of type \#sizet indicating the index of the node client who is interested in.
+ //! \return A shared pointer to const or non const \#INode object containing node.
+ //! \note In case no node exists at the given index an invalid shared pointer is returned.
+ //! \note The index of an array is 1-based.
+ //!
+ virtual spINode APICALL GetNodeAtIndex( sizet index ) = 0;
+ XMP_PRIVATE spcINode GetNodeAtIndex( sizet index ) const {
+ return const_cast< IArrayNode_v1 * >( this )->GetNodeAtIndex( index );
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get the node at the specified index as simple node, if possible.
+ //! \param[in] index An object of type \#sizet indicating the index of the node client is interested in.
+ //! \return A shared pointer to const or non const \#ISimpleNode object containing node.
+ //! \note In case no node exists at the given index an invalid shared pointer is returned.
+ //! \note The index of an array is 1-based.
+ //! \attention Error is thrown in case
+ //! - a child exists at the given index but is not a simple node.
+ //!
+ XMP_PRIVATE spcISimpleNode GetSimpleNodeAtIndex( sizet index ) const {
+ auto node = GetNodeAtIndex( index );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spcISimpleNode();
+ }
+
+ XMP_PRIVATE spISimpleNode GetSimpleNodeAtIndex( sizet index ) {
+ auto node = GetNodeAtIndex( index );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spISimpleNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get the node at the specified index as structure node, if possible.
+ //! \param[in] index An object of type \#sizet indicating the index of the node client is interested in.
+ //! \return A shared pointer to const or non const \#IStructureNode object containing node.
+ //! \note In case no node exists at the given index an invalid shared pointer is returned.
+ //! \note The index of an array is 1-based.
+ //! \attention Error is thrown in case
+ //! - a child exists at the given index but is not a structure node.
+ //!
+ XMP_PRIVATE spcIStructureNode GetStructureNodeAtIndex( sizet index ) const {
+ auto node = GetNodeAtIndex( index );
+ if ( node ) return node->ConvertToStructureNode();
+ return spcIStructureNode();
+ }
+
+ XMP_PRIVATE spIStructureNode GetStructureNodeAtIndex( sizet index ) {
+ auto node = GetNodeAtIndex( index );
+ if ( node ) return node->ConvertToStructureNode();
+ return spIStructureNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get the node at the specified index as an array node, if possible.
+ //! \param[in] index an object of type \#sizet indicating the index of the node client is interested in.
+ //! \return a shared pointer to const or non const \#IArrayNode object containing node.
+ //! \note In case no node exists at the given index an invalid shared pointer is returned.
+ //! \note The index of an array is 1-based.
+ //! \attention Error is thrown in case
+ //! - a child exists at the given index but is not an array node.
+ //!
+ XMP_PRIVATE spcIArrayNode GetArrayNodeAtIndex( sizet index ) const {
+ auto node = GetNodeAtIndex( index );
+ if ( node ) return node->ConvertToArrayNode();
+ return spcIArrayNode();
+ }
+
+ XMP_PRIVATE spIArrayNode GetArrayNodeAtIndex( sizet index ) {
+ auto node = GetNodeAtIndex( index );
+ if ( node ) return node->ConvertToArrayNode();
+ return spIArrayNode();
+ }
+ //! @}
+
+ //!
+ //! @brief Inserts a given node at the specified index.
+ //! \param[in] node Shared pointer to an object of \#INode containing the node to be inserted at the specified index.
+ //! \param[in] index An object of type sizet indicating the index where the node should
+ //! be inserted.
+ //! \note The index of an array is 1-based.
+ //! \attention Error is thrown in following cases:
+ //! -# given node is invalid.
+ //! -# type of given node is not same as other child items of the array node.
+ //! -# given node is already a child of some other node.
+ //! -# given index is less than 1 or greater than current child count + 1.
+ //!
+ virtual void APICALL InsertNodeAtIndex( const spINode & node, sizet index ) = 0;
+
+ //!
+ //! @brief Replaces an existing node with the given node at the specified index.
+ //! \param[in] node Shared pointer to an object of \#INode containing the node to be inserted at the specified index.
+ //! \param[in] index An object of type \#sizet indicating the index from where the node should be replaced.
+ //! \return A shared pointer to the node replaced with the new node.
+ //! \note The index of an array is 1-based.
+ //! \attention Error is thrown in following cases:
+ //! -# Given node is invalid.
+ //! -# Type of given node is not same as other child items of the array node.
+ //! -# Given node is already a child of some other node.
+ //! -# Given index is less than 1 or greater than current child count.
+ //! -# No node exists at the requested index.
+ //!
+ virtual spINode APICALL ReplaceNodeAtIndex( const spINode & node, sizet index ) = 0;
+
+ //!
+ //! @brief Remove the node at the specified index.
+ //! \param[in] index An object of type \#sizet indicating the index from where the node should be removed.
+ //! \note The index of an array is 1-based.
+ //! \return A shared pointer to \#INode object containing node which is removed from the tree.
+ //! \note In case no node exists at the given index an invalid shared pointer is returned.
+ //!
+ virtual spINode APICALL RemoveNodeAtIndex( sizet index ) = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IArrayNode interface.
+ //!
+ virtual pIArrayNode APICALL GetActualIArrayNode() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIArrayNode GetActualIArrayNode() const __NOTHROW__ {
+ return const_cast< IArrayNode_v1 * >( this )->GetActualIArrayNode();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Return the pointer to internal interfaces.
+ //! \return either a const or non const pointer to IArrayNode_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIArrayNode_I APICALL GetIArrayNode_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIArrayNode_I GetIArrayNode_I() const __NOTHROW__ {
+ return const_cast< IArrayNode_v1 * >( this )->GetIArrayNode_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer.
+ //! @details The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIArrayNode MakeShared( pIArrayNode_base ptr );
+ XMP_PRIVATE static spcIArrayNode MakeShared( pcIArrayNode_base ptr ) {
+ return MakeShared( const_cast< pIArrayNode_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! return The unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIArrayNodeID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // Factories to create the array node
+
+ //!
+ //! @brief Creates an unordered array node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the array node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated, set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the array node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to a \#IArrayNode object.
+ //! \attention Error is thrown in the following cases:
+ //! -# nameSpace is NULL or its contents are empty.
+ //! -# name is NULL or its contents are empty.
+ //!
+ XMP_PRIVATE static spIArrayNode CreateUnorderedArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ //!
+ //! @brief Creates an ordered array node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the array node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the array node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to a \#IArrayNode object.
+ //! \attention Error is thrown in the following cases:
+ //! -# nameSpace is NULL or its contents are empty.
+ //! -# name is NULL or its contents are empty.
+ //!
+ XMP_PRIVATE static spIArrayNode CreateOrderedArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ //!
+ //! @brief Creates an alternative array node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the array node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the array node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to a \#IArrayNode object.
+ //! \attention Error is thrown in the following cases:
+ //! -# nameSpace is NULL or its contents are empty.
+ //! -# name is NULL or its contents are empty.
+ //!
+ XMP_PRIVATE static spIArrayNode CreateAlternativeArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IArrayNode_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL getArrayForm( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL getChildNodeType( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINode_base APICALL getNodeAtIndex( sizet index, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL insertNodeAtIndex( pINode_base node, sizet index, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL replaceNodeAtIndex( pINode_base node, sizet index, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL removeNodeAtIndex( sizet index, pcIError_base & error ) __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // __IArrayNode_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IClientDOMParser.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IClientDOMParser.h
new file mode 100644
index 0000000000..ff27e00416
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IClientDOMParser.h
@@ -0,0 +1,88 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/IError.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h"
+#include "XMPCore/XMPCoreErrorCodes.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version 1 of the interface that supports parsing by the client supplied parser of the XMP Data Model.
+ //! @details Provides functions to parse the XMP Data Model.
+ //! Thread safety is controllable by the client.
+ //!
+ class XMP_PUBLIC IClientDOMParser_v1
+ {
+ public:
+
+ //!
+ //! @brief Parse the contents present in the buffer taking into account the configuration parameters.
+ //! \param[in] buffer Pointer to a constant char buffer containing serialized XMP Data Model.
+ //! \param[in] bufferLength Number of characters in buffer. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] configurationParameters An object of type \#AdobeXMPCommon::IConfigurable containing all the configuration parameters requested by client
+ //! to be taken care of while parsing.
+ //! \param[in] proc A function pointer to be used by the parse operation to report back any encountered errors/warnings.
+ //! \return A shared pointer to \#INode object containing all the parsed XMP Data Model.
+ //!
+ virtual spINode APICALL Parse( const char * buffer, sizet bufferLength, pcIConfigurable configurationParameters, ReportErrorAndContinueFunctor proc ) = 0;
+
+ //!
+ //! @brief Indicates whether object supports case sensitive keys or not.
+ //! \return True in case object supports case sensitive keys, false otherwise.
+ //! \note Default implementation makes keys case insensitive.
+ //!
+ virtual bool APICALL AreKeysCaseSensitive() const { return false; }
+
+ //!
+ //! @brief Initialize the default configuration parameters.
+ //! @details The object needs to fill the default configuration parameters supported by it.
+ //! \param[in] configurationParameters an empty object of type \#AdobeXMPCommon::IConfigurable.
+ //! \note default implementation does not fill anything in the configuration parameters.
+ //!
+ virtual void APICALL Initialize( pIConfigurable configurationParameters ) {};
+
+ //!
+ //! @brief Validate the data type and value for a parameter.
+ //! \param[in] key An unsigned 64 bit integer value indicating the key.
+ //! \param[in] dataType A value of type \#AdobeXMPCommon::IConfigurable::eDataType indicating the type of value the parameter holds.
+ //! \param[in] dataValue A value of \#AdobeXMPCommon::IConfigurable::CombinedDataValue indicating the value the parameter holds.
+ //! \return An error code in case there is something wrong with the combination, otherwise returns \ p0-\#AdobeXMPCommon::eCECNone.
+ //! \note Default implementation validates all the keys + dataTypes + dataValue combinations.
+ //!
+ virtual eConfigurableErrorCode APICALL Validate( const uint64 & key, IConfigurable::eDataType dataType, const IConfigurable::CombinedDataValue & dataValue ) {
+ return kCECNone;
+ }
+
+ //!
+ //! @brief Called by the library when the object is no longer required by it and client can free up the resources or memory associated with the object.
+ //!
+ virtual void APICALL Release() const __NOTHROW__ = 0;
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IClientDOMParser_v1() {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pINode_base APICALL parse( const char * buffer, sizet bufferLength, pcIConfigurable configurationParameters, ReportErrorAndContinueABISafeProc proc, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__;
+ virtual uint32 APICALL areKeysCaseSensitive( pcIError_base & error, uint32 & unknownExceptionCaught ) const __NOTHROW__;
+ virtual void APICALL initialize( pIConfigurable configurationParameters, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__;
+ virtual uint32 APICALL validate( const uint64 & key, uint32 dataType, const IConfigurable::CombinedDataValue & dataValue, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IClientDOMSerializer.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IClientDOMSerializer.h
new file mode 100644
index 0000000000..06558cdfd3
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IClientDOMSerializer.h
@@ -0,0 +1,94 @@
+#ifndef IClientDOMSerializer_h__
+#define IClientDOMSerializer_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/IError.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h"
+#include "XMPCommon/XMPCommonErrorCodes.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version 1 of the interface that supports serializing by the client supplied serializer of the XMP Data Model.
+ //! @details Provides functions to serialize the XMP Data Model.
+ //! Thread safety is controllable by the client.
+ //!
+ class XMP_PUBLIC IClientDOMSerializer_v1
+ {
+ public:
+
+ //!
+ //! @brief Serialize the XMP Data Model taking into account the configuration parameters.
+ //! \param[in] node The node to be serialized.
+ //! \param[in] nameSpacePrefixMap An object of type \#INameSpacePrefixMap which contains preferred prefixes for namespaces.
+ //! \param[in] configurationParameters An object of type #AdobeXMPCommon::IConfigurable containing all the configuration parameters requested by client
+ //! to be taken care of while serializing.
+ //! \param[in] functor A function object to be used by the serializing operation to report back any encountered errors/warnings.
+ //! \param[out] string A shared pointer to an IUTF8String object which should be filled with the serialized form of XMP Data Model.
+ //!
+ virtual void APICALL Serialize( const spINode & node, const spcINameSpacePrefixMap & nameSpacePrefixMap, pcIConfigurable configurationParameters,
+ ReportErrorAndContinueFunctor functor, const spIUTF8String & string ) = 0;
+
+ //!
+ //! @brief Indicates whether object supports case sensitive keys or not.
+ //! \return True in case object supports case sensitive keys, false otherwise.
+ //! \note Default implementation makes keys case insensitive.
+ //!
+ virtual bool APICALL AreKeysCaseSensitive() const { return false; }
+
+ //!
+ //! @brief Initializes the default configuration parameters.
+ //! The object needs to fill the default configuration parameters supported by it.
+ //! \param[in] configurationParameters An empty object of type #AdobeXMPCommon::IConfigurable.
+ //! \note Default implementation does not fill anything in the configuration parameters.
+ //!
+ virtual void APICALL Initialize( pIConfigurable configurationParameters ) {};
+
+ //!
+ //! @brief Validate the data type and value for a parameter.
+ //! \param[in] key An unsigned 64 bit integer value indicating the key.
+ //! \param[in] dataType A value of type #AdobeXMPCommon::IConfigurable::eDataType indicating the type of value the parameter holds.
+ //! \param[in] dataValue A value of \#AdobeXMPCommon::IConfigurable::CombinedDataValue indicating the value the parameter holds.
+ //! \return An error code in case there is something wrong with the combination, otherwise returns \#AdobeXMPCommon::eCECNone.
+ //! \note Default implementation validates all the keys + dataTypes + dataValue combinations.
+ //!
+ virtual eConfigurableErrorCode APICALL Validate( const uint64 & key, IConfigurable::eDataType dataType, const IConfigurable::CombinedDataValue & dataValue ) {
+ return kCECNone;
+ }
+
+ //!
+ //! @brief Called by the library when the object is no longer required by it and client can free up the resources or memory associated with the object.
+ //!
+ virtual void APICALL Release() const __NOTHROW__ = 0;
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IClientDOMSerializer_v1() {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual void APICALL serialize( pINode_base node, pcINameSpacePrefixMap_base nameSpacePrefixMap, pcIConfigurable configurationParameters, ReportErrorAndContinueABISafeProc proc, pIUTF8String_base string, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__;
+ virtual uint32 APICALL areKeysCaseSensitive( pcIError_base & error, uint32 & unknownExceptionCaught ) const __NOTHROW__;
+ virtual void APICALL initialize( pIConfigurable configurationParameters, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__;
+ virtual uint32 APICALL validate( const uint64 & key, uint32 dataType, const IConfigurable::CombinedDataValue & dataValue, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // IClientDOMSerializer_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICompositeNode.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICompositeNode.h
new file mode 100644
index 0000000000..4754ed5551
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICompositeNode.h
@@ -0,0 +1,331 @@
+#ifndef __ICompositeNode_h__
+#define __ICompositeNode_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/Interfaces/INode.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that serves as a base interface to all composite types of nodes
+ //! in the XMP DOM ( like Arrays and Structures ).
+ //! \details Provides all the functions to get various properties of the composite node.
+ //! \attention Support multi threading through locks but can be enabled/disabled by the client. By default
+ //! every object created does not support multi-threading.
+ //!
+ class XMP_PUBLIC ICompositeNode_v1
+ : public virtual INode_v1
+ {
+ public:
+
+ //!
+ //! @brief Get the node type specified by the path relative to the composite node.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path
+ //! from the node to the node client is interested in.
+ //! \return The type of the node.
+ //! \note In case no node exists at the given path a value \#eNodeType::kNTNone is returned.
+ //!
+ virtual eNodeType APICALL GetNodeTypeAtPath( const spcIPath & path ) const = 0;
+
+ //!
+ //! @{
+ //! @brief Get the node specified by the path relative to the composite node.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path
+ //! from the node to the node client is interested in.
+ //! \return A shared pointer to either a const or non const \#AdobeXMPCore::INode object containing node.
+ //! \note In case no node exists at the given path an invalid shared pointer is returned.
+ //!
+ XMP_PRIVATE spcINode GetNodeAtPath( const spcIPath & path ) const {
+ return const_cast< ICompositeNode_v1 * >( this )->GetNodeAtPath( path );
+ }
+ virtual spINode APICALL GetNodeAtPath( const spcIPath & path ) = 0;
+ //! @}
+
+ //!
+ //! @brief Appends a given node as the child of the node.
+ //! @details In case of array node it is appended at the last
+ //! and in case of structure node qualified name of the node to be inserted determines its position.
+ //! \param[in] node Shared pointer to an object of \#AdobeXMPCore::INode containing the node to be
+ //! appended as the last child.
+ //! \note This operation is not currently implemented for the ICompositeNode interface.
+ //! \attention Error is thrown in following cases:
+ //! -# provided node is invalid.
+ //! -# type of given node is not same as other child items of the array node.
+ //! -# given node is already a child of some other node.
+ //! -# composite node already has a child node with the same qualified name in case of structure node.
+ //!
+ virtual void APICALL AppendNode( const spINode & node ) = 0;
+
+ //!
+ //! @brief Inserts a given node at the path relative to the composite node.
+ //! \param[in] node Shared pointer to an object of \#AdobeXMPCore::INode containing the node to be
+ //! inserted at the specified relative path.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path.
+ //! \note All the hierarchy of nodes is created if not present.
+ //! \note This operation is not currently implemented for the ICompositeNode interface.
+ //! \attention Error is thrown in following cases:
+ //! -# given node is invalid.
+ //! -# type of given node is not same as other child items of the array node.
+ //! -# given node is already a child of some other node.
+ //! -# given path is invalid or logically incorrect.
+ //! -# type of given node is not suitable for the destination location.
+ //! -# a node already exists at the specified path.
+ //!
+ virtual void APICALL InsertNodeAtPath( const spINode & node, const spcIPath & path ) = 0;
+
+ //!
+ //! @brief Replaces an existing node with the given node at the path relative to the composite node..
+ //! \param[in] node Shared pointer to an object of \#AdobeXMPCore::INode.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path.
+ //! \return a Shared pointer to the node being replaced.
+ //! \note This operation is not currently implemented for the ICompositeNode interface.
+ //! \attention Error is thrown in following cases:
+ //! -# given node is invalid.
+ //! -# type of given node is not same as other child items of the array node.
+ //! -# given node is already a child of some other node.
+ //! -# given index is less than 1 or greater than current child count.
+ //! -# type of given node is not suitable for the destination location.
+ //! -# no node exists at the specified path.
+ //!
+ virtual spINode APICALL ReplaceNodeAtPath( const spINode & node, const spcIPath & path ) = 0;
+
+ //!
+ //! @brief Removes the node specified by the path relative to the composite node.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path
+ //! from the node to the node client is interested in.
+ //! \return A shared pointer to \#AdobeXMPCore::INode object containing node which is removed from the tree.
+ //! \note In case no node exists at the given path an invalid shared pointer is returned.
+ //!
+ virtual spINode APICALL RemoveNodeAtPath( const spcIPath & path ) = 0;
+
+ //!
+ //! @{
+ //! @brief Get an iterator object to iterate over all the child nodes of the composite node.
+ //! \return a shared pointer to a const or non const \#INodeIterator object.
+ //!
+ virtual spINodeIterator APICALL Iterator() = 0;
+ XMP_PRIVATE spcINodeIterator Iterator() const {
+ return const_cast< ICompositeNode_v1 * >( this )->Iterator();
+ }
+ // @}
+
+ //!
+ //! @brief Get the count of child nodes of the composite node.
+ //! \return an object of type \#AdobeXMPCommon::sizet containing the count of children of the node.
+ //!
+ virtual sizet APICALL ChildCount() const __NOTHROW__ = 0;
+
+ // Wrapper non virtual functions
+
+ //!
+ //! @{
+ //! @brief Get a simple node specified by the path relative to the node.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path
+ //! from the node to the node client is interested in.
+ //! \return A shared pointer to const or non const \#ISimpleNode object containing node.
+ //! \note In case no node exists at the given path an invalid shared pointer is returned.
+ //! \attention Error is thrown in case
+ //! - a node exists at the given path but is not a simple node.
+ //!
+ XMP_PRIVATE spcISimpleNode GetSimpleNodeAtPath( const spcIPath & path ) const {
+ auto node = GetNodeAtPath( path );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spcISimpleNode();
+ }
+
+ XMP_PRIVATE spISimpleNode GetSimpleNodeAtPath( const spcIPath & path ) {
+ auto node = GetNodeAtPath( path );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spISimpleNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get a structure node specified by the path relative to the node.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path
+ //! from the node to the node client is interested in.
+ //! \return A shared pointer to const or non const \#IStructureNode object containing node.
+ //! \note In case no node exists at the given path an invalid shared pointer is returned.
+ //! \attention Error is thrown in case
+ //! - a node exists at the given path but is not a structure node.
+ //!
+ XMP_PRIVATE spcIStructureNode GetStructureNodeAtPath( const spcIPath & path ) const {
+ auto node = GetNodeAtPath( path );
+ if ( node ) return node->ConvertToStructureNode();
+ return spcIStructureNode();
+ }
+
+ XMP_PRIVATE spIStructureNode GetStructureNodeAtPath( const spcIPath & path ) {
+ auto node = GetNodeAtPath( path );
+ if ( node ) return node->ConvertToStructureNode();
+ return spIStructureNode();
+ }
+ // !@}
+
+ //!
+ //! @{
+ //! @brief Get an array node specified by the path relative to the node.
+ //! \param[in] path Shared pointer to a const \#AdobeXMPCore::IPath object containing the relative path
+ //! from the node to the node client is interested in.
+ //! \return A shared pointer to const or non const \#IArrayNode object containing node.
+ //! \note In case no node exists at the given path an invalid shared pointer is returned.
+ //! \attention Error is thrown in case
+ //! - a node exists at the given path but is not an array node.
+ //!
+ XMP_PRIVATE spcIArrayNode GetArrayNodeAtPath( const spcIPath & path ) const {
+ auto node = GetNodeAtPath( path );
+ if ( node ) return node->ConvertToArrayNode();
+ return spcIArrayNode();
+ }
+
+ XMP_PRIVATE spIArrayNode GetArrayNodeAtPath( const spcIPath & path ) {
+ auto node = GetNodeAtPath( path );
+ if ( node ) return node->ConvertToArrayNode();
+ return spIArrayNode();
+ }
+ // !@}
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to ICompositeNode interface.
+ //!
+ virtual pICompositeNode APICALL GetActualICompositeNode() __NOTHROW__ = 0;
+ XMP_PRIVATE pcICompositeNode GetActualICompositeNode() const __NOTHROW__ {
+ return const_cast< ICompositeNode_v1 * >( this )->GetActualICompositeNode();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to ICompositeNode_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pICompositeNode_I APICALL GetICompositeNode_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcICompositeNode_I GetICompositeNode_I() const __NOTHROW__ {
+ return const_cast< ICompositeNode_v1 * >( this )->GetICompositeNode_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer.
+ //! @details The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spICompositeNode MakeShared( pICompositeNode_base ptr );
+ XMP_PRIVATE static spcICompositeNode MakeShared( pcICompositeNode_base ptr ) {
+ return const_cast< ICompositeNode_v1 * >( ptr )->MakeShared( ptr );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kICompositeNodeID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~ICompositeNode_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL getNodeTypeAtPath( pcIPath_base path, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINode_base APICALL getNodeAtPath( pcIPath_base path, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL appendNode( pINode_base node, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL insertNodeAtPath( pINode_base node, pcIPath_base path, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL replaceNodeAtPath( pINode_base node, pcIPath_base path, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL removeNodeAtPath( pcIPath_base path, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINodeIterator_base APICALL iterator( pcIError_base & error ) __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+//! \cond XMP_INTERNAL_DOCUMENTATION
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class ICompositeNodeProxy
+ : public virtual ICompositeNode
+ , public virtual INodeProxy
+ {
+ private:
+ pICompositeNode mRawPtr;
+
+ public:
+ ICompositeNodeProxy( pICompositeNode ptr );
+ ~ICompositeNodeProxy() __NOTHROW__ ;
+
+ pICompositeNode APICALL GetActualICompositeNode() __NOTHROW__;
+ AdobeXMPCore_Int::pICompositeNode_I APICALL GetICompositeNode_I() __NOTHROW__;
+
+ virtual eNodeType APICALL GetNodeTypeAtPath( const spcIPath & path ) const;
+ virtual spINode APICALL GetNodeAtPath( const spcIPath & path );
+ virtual void APICALL AppendNode( const spINode & node );
+ virtual void APICALL InsertNodeAtPath( const spINode & node, const spcIPath & path );
+ virtual spINode APICALL ReplaceNodeAtPath( const spINode & node, const spcIPath & path );
+ virtual spINode APICALL RemoveNodeAtPath( const spcIPath & path );
+ virtual spINodeIterator APICALL Iterator();
+ virtual sizet APICALL ChildCount() const __NOTHROW__;
+
+ protected:
+ virtual uint32 APICALL getNodeTypeAtPath( pcIPath_base path, pcIError_base & error ) const __NOTHROW__;
+ virtual pINode_base APICALL getNodeAtPath( pcIPath_base path, pcIError_base & error ) __NOTHROW__;
+ virtual void APICALL appendNode( pINode_base node, pcIError_base & error ) __NOTHROW__;
+ virtual void APICALL insertNodeAtPath( pINode_base node, pcIPath_base path, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL replaceNodeAtPath( pINode_base node, pcIPath_base path, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL removeNodeAtPath( pcIPath_base path, pcIError_base & error ) __NOTHROW__;
+ virtual pINodeIterator_base APICALL iterator( pcIError_base & error ) __NOTHROW__;
+
+ };
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+}
+
+#endif // BUILDING_XMPCORE_LIB
+//! \endcond
+
+#endif // __ICompositeNode_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICoreConfigurationManager.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICoreConfigurationManager.h
new file mode 100644
index 0000000000..98b09a006f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICoreConfigurationManager.h
@@ -0,0 +1,107 @@
+#ifndef ICoreConfigurationManager_h__
+#define ICoreConfigurationManager_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/IConfigurationManager.h"
+
+namespace AdobeXMPCore {
+ //!
+ //! @brief Version1 of the interface that represents configuration settings controllable by the client.
+ //! \details Provides functions through which client can plug in its own memory allocators, error notifiers.
+ //! \attention Not Thread Safe as this functionality is generally used at the initialization phase.
+ //!
+ class XMP_PUBLIC ICoreConfigurationManager_v1
+ : public virtual IConfigurationManager_v1
+ {
+ public:
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to ICoreConfigurationManager interface.
+ //!
+ virtual pICoreConfigurationManager APICALL GetActualICoreConfigurationManager() __NOTHROW__ = 0;
+ XMP_PRIVATE pcICoreConfigurationManager GetActualICoreConfigurationManager() const __NOTHROW__ {
+ return const_cast< ICoreConfigurationManager_v1 * >( this )->GetActualICoreConfigurationManager();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to ICoreConfigurationManager_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pICoreConfigurationManager_I APICALL GetICoreConfigurationManager_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcICoreConfigurationManager_I GetICoreConfigurationManager_I() const __NOTHROW__ {
+ return const_cast< ICoreConfigurationManager_v1 * >( this )->GetICoreConfigurationManager_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spICoreConfigurationManager MakeShared( pICoreConfigurationManager_base ptr );
+ XMP_PRIVATE static spcICoreConfigurationManager MakeShared( pcICoreConfigurationManager_base ptr ) {
+ return MakeShared( const_cast< pICoreConfigurationManager_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Return the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kICoreConfigurationManagerID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // static factory functions
+
+ //!
+ //! @brief Get the configuration manager object associated with XMPCore library..
+ //! \return A shared pointer to an object of \#ICoreConfigurationManager.
+ //!
+ XMP_PRIVATE static spICoreConfigurationManager GetCoreConfigurationManager();
+
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~ICoreConfigurationManager_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+#endif // ICoreConfigurationManager_h__
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICoreObjectFactory.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICoreObjectFactory.h
new file mode 100644
index 0000000000..234a6856ed
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ICoreObjectFactory.h
@@ -0,0 +1,264 @@
+#ifndef ICoreObjectFactory_h__
+#define ICoreObjectFactory_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/IObjectFactory.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version1 of a interface that represents a factory to create various artifacts of XMP DOM like array,
+ //! structure, path etc.
+ //!
+ //! @details Provides all the functions to create instances of various artifacts of XMP DOM and return them as shared pointers
+ //! to the clients. This is the interface through which clients of the library actually get access to all other interfaces.
+ //!
+
+ class XMP_PUBLIC ICoreObjectFactory_v1
+ : public virtual IObjectFactory_v1
+ {
+ public:
+
+ //!
+ //! @brief Creates an empty name space prefix map.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to an empty \#INameSpacePrefixMap_v1 object.
+ //!
+ virtual pINameSpacePrefixMap_base APICALL CreateNameSpacePrefixMap( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Provides the default mapping of prefix string and nameSpace strings used by XMPCore.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to const \#INameSpacePrefixMap_v1 object containing all the mappings used as default by the XMPCore.
+ //!
+ virtual pcINameSpacePrefixMap_base APICALL GetDefaultNameSpacePrefixMap( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates a normal property path segment.These are essentially all properties (simple, struct and arrays).
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the property.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to const \#IPathSegment_v1.
+ //!
+ virtual pcIPathSegment_base APICALL CreatePropertyPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates an array index path segment that denotes a specific element of an array.
+ //! @details Such segments do not have an own name and inherits the namespace from the Array property itself.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] index An object of type \#AdobeXMP::sizet containting the index of the array element.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to const \#IPathSegment_v1.
+ //! \attention Throws \#AdobeXMP::pcIError in case
+ //! - pointers to const char buffers are NULL,
+ //! - their content is empty.
+ //!
+ virtual pcIPathSegment_base APICALL CreateArrayIndexPathSegment( const char * nameSpace, sizet nameSpaceLength, sizet index, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates a Qualifier path segment, which behaves like a normal property
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the property.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to const \#IPathSegment_v1.
+ //!
+ virtual pcIPathSegment_base APICALL CreateQualifierPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates a path segment that selects a specific qualifier by its value.
+ //! For example a specific language in a alternative array of languages.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the property.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] value Pointer to a constant char buffer containing value of the language (xml:lang)
+ //! \param[in] valueLength Number of characters in value. In case value is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to const \#IPathSegment_v1.
+ //!
+ virtual pcIPathSegment_base APICALL CreateQualifierSelectorPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name,
+ sizet nameLength, const char * value, sizet valueLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates an empty IPath object.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to an empty \#IPath_v1 object
+ //!
+ virtual pIPath_base APICALL CreatePath( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates a path from a char buffer which contains the serialized path.
+ //! \param[in] path Pointer to a const char buffer containing serialized form of the path.
+ //! \param[in] pathLength Number of characters in the path. In case path in null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] map A pointer to a const \#IXMPNameSpacePrefixMap_v1 object which will contain the mapping for nameSpaces to prefixes.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to a \#IPath_v1 object.
+ //!
+ virtual pIPath_base APICALL ParsePath( const char * path, sizet pathLength, pcINameSpacePrefixMap_base map, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates a simple property node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the simple node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the simple node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] value Pointer to a constant char buffer containing value of the simple node.
+ //! \param[in] valueLength Number of characters in value. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to a \#ISimpleNode_v1 object.
+ //!
+ virtual pISimpleNode_base APICALL CreateSimpleNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength,
+ const char * value, sizet valueLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates an array node which is not part of any metadata document.
+ //! \param[in] arrayForm A value indicating the array type
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the array node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the array node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to a \#IArrayNode_v1 object.
+ //!
+ virtual pIArrayNode_base APICALL CreateArrayNode( uint32 arrayForm, const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates a structure node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the structure node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the structure node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to a \#IStructureNode_v1 object.
+ virtual pIStructureNode_base APICALL CreateStructureNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Creates an empty IMetadata object.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return a pointer to an empty \#IMetadata_v1 object.
+ //!
+ virtual pIMetadata_base APICALL CreateMetadata( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Provides the reference to the database of Serializers and Parsers available with the library.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return a pointer to \#IDOMImplementationRegistry_base object containing all the entries for serailizers and parsers.
+ //!
+ virtual pIDOMImplementationRegistry_base APICALL GetDOMImplementationRegistry( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Provides access to the configuration manager of the library.
+ //! \param[out] error A reference to a pointer to const IError object which will be filled with the error object in case of any error.
+ //! \return A pointer to \#ICoreConfigurationManager_base object.
+ //!
+ virtual pICoreConfigurationManager_base APICALL GetCoreConfigurationManager( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to ICoreObjectFactory interface.
+ //!
+ virtual pICoreObjectFactory APICALL GetActualICoreObjectFactory() __NOTHROW__ = 0;
+ XMP_PRIVATE pcICoreObjectFactory GetActualICoreObjectFactory() const __NOTHROW__ {
+ return const_cast< ICoreObjectFactory_v1 * >( this )->GetActualICoreObjectFactory();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to ICoreObjectFactory_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pICoreObjectFactory_I APICALL GetICoreObjectFactory_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcICoreObjectFactory_I GetICoreObjectFactory_I() const __NOTHROW__ {
+ return const_cast< ICoreObjectFactory_v1 * >( this )->GetICoreObjectFactory_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to base version to pointer to client interested version.
+ //! @details The raw pointer is of version 1 interface where as the returned pointer depends on the version client is interested in.
+ //! \return Pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static pICoreObjectFactory MakeCoreObjectFactory( pICoreObjectFactory_base ptr );
+ XMP_PRIVATE static pcICoreObjectFactory MakeCoreObjectFactory( pcICoreObjectFactory_base ptr ) {
+ return MakeCoreObjectFactory( const_cast< pcICoreObjectFactory_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kICoreObjectFactoryID; }
+
+ //!
+ //! @brief returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ //!
+ //! @brief Gets an object of ICoreObjectFactory.
+ //! \return A pointer to an ICoreObjectFactory object.
+ //!
+ XMP_PRIVATE static pICoreObjectFactory GetCoreObjectFactory();
+
+ //!
+ //! @{
+ //! @brief Sets up the core object factory.
+ //! \param[in] coreObjectFactory A pointer to an \#ICoreObjectFactory_v1 object.
+ //! \note coreObjectFactory is an optional parameter and only required for clients who don't directly link with the library
+ //! but want to use its functionality.
+ //!
+ #if LINKING_XMPCORE_LIB
+ XMP_PRIVATE static void SetupCoreObjectFactory();
+ #else
+ XMP_PRIVATE static void SetupCoreObjectFactory( pICoreObjectFactory_base coreObjectFactory );
+ #endif
+ //! @}
+
+ //!
+ //! @brief Destroy everything related to core object factory.
+ //!
+ XMP_PRIVATE static void DestroyCoreObjectFactory();
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~ICoreObjectFactory_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+#endif // ICoreObjectFactory_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMImplementationRegistry.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMImplementationRegistry.h
new file mode 100644
index 0000000000..7a732bddc8
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMImplementationRegistry.h
@@ -0,0 +1,150 @@
+#ifndef IDOMImplementationRegistry_h__
+#define IDOMImplementationRegistry_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that serves as a database/registry of all the parsers and
+ //! serializers available with the XMPCore library.
+ //! \details Provides all the functions to
+ //! -# get registered serializers and parsers from the database.
+ //! -# add client defined serializers and parsers to the database.
+ //! \attention Support multi threading if library is configured to support multi-threading by default.
+ //! \note By default following keys are registered by default with the database by the library:
+ //! -# rdf
+ //!
+ class XMP_PUBLIC IDOMImplementationRegistry_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Gets a parser corresponding to the key and returns to the client for usage.
+ //! \param[in] key Pointer to a const NULL terminated char buffer containing key of the parser in the database.
+ //! \return A shared pointer to a \#IDOMParser object.
+ //! \note In case the key is not present in the database an invalid shared pointer will be returned.
+ //! \note key is case sensitive.
+ //!
+ virtual spIDOMParser APICALL GetParser( const char * key ) const = 0;
+
+ //!
+ //! @brief Gets a serializer corresponding to the key and returns to the client for usage.
+ //! \param[in] key Pointer to a const NULL terminated char buffer containing key of the serializer in the database.
+ //! \return A shared pointer to a \#IDOMSerializer object.
+ //! \note In case the key is not present in the database an invalid shared pointer will be returned.
+ //! \note key is case sensitive.
+ //!
+ virtual spIDOMSerializer APICALL GetSerializer( const char * key ) const = 0;
+
+ //!
+ //! @brief Registers a parser with the database along with the key.
+ //! \param[in] key Pointer to a const NULL terminated char buffer containing key of the parser to be used while registering.
+ //! \param[in] parser A pointer to \#IClientDOMParser object to be registered with the database
+ //! \return True in case parser is successfully registered, false otherwise like in case key is already registered.
+ //!
+ virtual bool APICALL RegisterParser( const char * key, pIClientDOMParser_base parser ) = 0;
+
+ //!
+ //! @brief Registers a serializer with the database along with the key.
+ //! \param[in] key Pointer to a const NULL terminated char buffer containing key of the serializer to be used while registering.
+ //! \param[in] serializer A pointer to \#IClientDOMSerializer object to be registered with the database.
+ //! \return True in case serializer is successfully registered, false otherwise like in case key is already registered.
+ //!
+ virtual bool APICALL RegisterSerializer( const char * key, pIClientDOMSerializer_base serializer ) = 0;
+
+ //!
+ //! @brief Provides the reference to the database of Serializers and Parsers available with the library.
+ //! \return A shared pointer to \#IDOMImplementationRegistry object containing all the entries for serailizers and parsers.
+ //!
+ XMP_PRIVATE static spIDOMImplementationRegistry GetDOMImplementationRegistry();
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IDOMImplementationRegistry interface.
+ //!
+ virtual pIDOMImplementationRegistry APICALL GetActualIDOMImplementationRegistry() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIDOMImplementationRegistry GetActualIDOMImplementationRegistry() const __NOTHROW__ {
+ return const_cast< IDOMImplementationRegistry_v1 * >( this )->GetActualIDOMImplementationRegistry();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IDOMImplementationRegistry_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIDOMImplementationRegistry_I APICALL GetIDOMImplementationRegistry_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIDOMImplementationRegistry_I GetIDOMImplementationRegistry_I() const __NOTHROW__ {
+ return const_cast< IDOMImplementationRegistry_v1 * >( this )->GetIDOMImplementationRegistry_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIDOMImplementationRegistry MakeShared( pIDOMImplementationRegistry_base ptr );
+ XMP_PRIVATE static spcIDOMImplementationRegistry MakeShared( pcIDOMImplementationRegistry_base ptr ) {
+ return MakeShared( const_cast< pIDOMImplementationRegistry_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIDOMImplementationRegistryID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IDOMImplementationRegistry_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pIDOMParser_base APICALL getParser( const char * key, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pIDOMSerializer_base APICALL getSerializer( const char * key, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL registerParser( const char * key, pIClientDOMParser_base parser, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL registerSerializer( const char * key, pIClientDOMSerializer_base serializer, pcIError_base & error ) __NOTHROW__= 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // IDOMImplementationRegistry_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMParser.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMParser.h
new file mode 100644
index 0000000000..b33ff1779c
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMParser.h
@@ -0,0 +1,181 @@
+#ifndef IDOMParser_h__
+#define IDOMParser_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version 1 of the interface that supports parsing of the XMP Data Model.
+ //! @details Provides all functions to parse the buffer as well as to configure the parser.
+ //!
+ class XMP_PUBLIC IDOMParser_v1
+ : public virtual IConfigurable
+ , public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Indicates various types of operations possible while parsing with some node as the context.
+ //!
+ typedef enum {
+ //! @brief Append all the nodes parsed from the buffer as the child of the context node.
+ //! \attention Error is thrown in case
+ //! - Context Node is invalid.
+ //! - Context Node is not array or structure node.
+ //! - Context Node is a structure node but a child node with the same qualified name is already present.
+ //! - Context Node is an array node but the type of any parsed node is not same as that of other existing nodes in the array.
+ //!
+ kATAppendAsChildren = 0,
+
+ //! @brief Replaces the children of the context node with nodes parsed from the buffer.
+ //! \attention Error is thrown in case
+ //! - Context Node is invalid.
+ //! - Context Node is not array or structure node.
+ //! - Context Node is a structure node but a child node with the same qualified name is not already present.
+ //! - Context Node is an array node but the type of all parsed nodes are not same.
+ //!
+ kATReplaceChildren = 1,
+
+ //! @brief Either append all the nodes parsed from the buffer as the child/children of the context node.
+ //! \attention Error is thrown in case
+ //! - Context Node is invalid.
+ //! - Context Node is not array or structure node.
+ //! - Context Node is an array node but the type of all parsed nodes are not same.
+ //! - If a structure node is the parsed node, it is appended if it already not present, otherwise it is replaced.
+ //! - If an array node is the parsed node, it is appended if it already not present, otherwise it is removed.
+ kATAppendOrReplaceChildren = 2,
+
+ //! @brief Treats all the parsed nodes as the siblings of the context node and place them before the context node, if possible.
+ //! \attention Error is thrown in case
+ //! - Context Node is invalid.
+ //! - parent of the Context Node is not an array node.
+ //! - The type of any parsed nodes is not same as that of other existing nodes in the array.
+ kATInsertBefore = 3,
+
+ //! @brief Treats all the parsed nodes as the siblings of the context node and place them after the context node, if possible.
+ //! \attention Error is thrown in case
+ //! - Context Node is invalid.
+ //! - parent of the Context Node is not an array node.
+ //! - The type of any parsed nodes is not same as that of other existing nodes in the array.
+ kATInsertAfter = 4,
+
+ //! @brief Replaces the context node and insert the node parsed from the buffer in its place.
+ //! \attention Error is thrown in case
+ //! - type of node returned after parsing in not of type which is compatible with the Context Node.
+ kATReplace = 5,
+ } eActionType;
+
+ //!
+ //! @brief Parses the buffer contents and creates an XMP DOM node.
+ //! \param[in] buffer Pointer to a constant char buffer containing serialized XMP Data Model.
+ //! \param[in] bufferLength Number of characters in buffer. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to an object of \#IMetadata containing all the information parsed from the buffer.
+ //!
+ virtual spIMetadata APICALL Parse( const char * buffer, sizet bufferLength ) = 0;
+
+ //!
+ //! @brief Parse the buffer contents and populate the provided node .
+ //! \param[in] buffer Pointer to a constant char buffer containing serialized XMP Data Model.
+ //! \param[in] bufferLength Number of characters in buffer. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] actionType Value indicating how the parsed content and context node should be used.
+ //! \param[in,out] node The context node to be used base on the actionType.
+ //!
+ virtual void APICALL ParseWithSpecificAction( const char * buffer, sizet bufferLength, eActionType actionType, spINode & node ) = 0;
+
+ //!
+ //! @brief Virtual copy constructor.
+ //! @details Creates an exact replica of the object.
+ //! \return A shared pointer to an object of \#IDOMParser which is the exact replica of the current serializer.
+ //!
+ virtual spIDOMParser APICALL Clone() const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IDOMParser interface.
+ //!
+ virtual pIDOMParser APICALL GetActualIDOMParser() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIDOMParser GetActualIDOMParser() const __NOTHROW__ {
+ return const_cast< IDOMParser_v1 * >( this )->GetActualIDOMParser();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IDOMParser_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIDOMParser_I APICALL GetIDOMParser_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIDOMParser_I GetIDOMParser_I() const __NOTHROW__ {
+ return const_cast< IDOMParser_v1 * >( this )->GetIDOMParser_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer.
+ //! @details The raw pointer is of version 1 interface where as the returned shared pointer depends on the version client is interested in.
+ //!
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIDOMParser MakeShared( pIDOMParser_base ptr );
+ XMP_PRIVATE static spcIDOMParser MakeShared( pcIDOMParser_base ptr ) {
+ return MakeShared( const_cast< pIDOMParser_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! return The unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIDOMParserID; }
+
+ //!
+ //! return The version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IDOMParser_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pIMetadata_base APICALL parse( const char * buffer, sizet bufferLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL parseWithSpecificAction( const char * buffer, sizet bufferLength, uint32 actionType, pINode_base node, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIDOMParser_base APICALL clone( pcIError_base & error ) const __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // IDOMParser_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMSerializer.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMSerializer.h
new file mode 100644
index 0000000000..fe4d9fc43c
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IDOMSerializer.h
@@ -0,0 +1,120 @@
+#ifndef IDOMSerializer_h__
+#define IDOMSerializer_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IConfigurable.h"
+
+namespace AdobeXMPCore {
+ //!
+ //! @brief Version1 of the interface that represents an object that can serialize an XMP Data Model to a buffer.
+ //! Provides the functions to serialize the XMP Data Model.
+ //!
+ class XMP_PUBLIC IDOMSerializer_v1
+ : public virtual IConfigurable
+ , public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Serializes the given XMP Node into an IUTF8String object.
+ //! \param[in] node An object of type \#INode which needs to be serialized.
+ //! \param[in] nameSpacePrefixMap An object of type \#INameSpacePrefixMap which contains preferred prefixes for namespaces.
+ //! \return An object of \#AdobeXMPCommon::IUTF8String type containing the serialized form of the node.
+ //!
+ virtual spIUTF8String APICALL Serialize( const spINode & node, const spcINameSpacePrefixMap & nameSpacePrefixMap = spcINameSpacePrefixMap() ) = 0;
+
+ //!
+ //! @brief Virtual copy constructor.
+ //! Creates an exact replica of the object.
+ //! \return A shared pointer to an object of \#IDOMSerializer which is the exact replica of the current serializer.
+ //!
+ virtual spIDOMSerializer APICALL Clone() const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IDOMSerializer interface.
+ //!
+ virtual pIDOMSerializer APICALL GetActualIDOMSerializer() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIDOMSerializer GetActualIDOMSerializer() const __NOTHROW__ {
+ return const_cast< IDOMSerializer_v1 * >( this )->GetActualIDOMSerializer();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IDOMSerializer_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIDOMSerializer_I APICALL GetIDOMSerializer_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIDOMSerializer_I GetIDOMSerializer_I() const __NOTHROW__ {
+ return const_cast< IDOMSerializer_v1 * >( this )->GetIDOMSerializer_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIDOMSerializer MakeShared( pIDOMSerializer_base ptr );
+ XMP_PRIVATE static spcIDOMSerializer MakeShared( pcIDOMSerializer_base ptr ) {
+ return MakeShared( const_cast< pIDOMSerializer_base >( ptr ) );
+ }
+
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIDOMSerializerID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IDOMSerializer_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pIUTF8String_base APICALL serialize( pINode_base node, pcINameSpacePrefixMap_base map, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIDOMSerializer_base APICALL clone( pcIError_base & error ) const __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // IDOMSerializer_h__
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IMetadata.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IMetadata.h
new file mode 100644
index 0000000000..74015a6f24
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IMetadata.h
@@ -0,0 +1,145 @@
+#ifndef __IMetadata_h__
+#define __IMetadata_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/Interfaces/IStructureNode.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that represents the whole xmp metadata for an asset.
+ //! @details Provides all the functions to add or remove nodes to and from metadata.
+ //! \attention Support multi threading through locks but can be enabled/disabled by the client. By default
+ //! every object created does not support multi-threading.
+ //!
+
+ class XMP_PUBLIC IMetadata_v1
+ : public virtual IStructureNode_v1
+ {
+ public:
+ //!
+
+ //! @brief Gets the about URI string for the XMP metadata.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String object containing URI string.
+ //! \note By default this is an empty string.
+ //!
+ virtual spcIUTF8String APICALL GetAboutURI() const = 0;
+
+ //!
+ //! @brief Sets the about URI string for the XMP metadata.
+ //! \param[in] uri Pointer to a constant char buffer containing uri string.
+ //! \param[in] uriLength Number of characters in uri. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //!
+ virtual void APICALL SetAboutURI( const char * uri, sizet uriLength ) __NOTHROW__ = 0;
+
+ //!
+ //! @brief Enables support for a particular feature.
+ //! \param[in] key A const char buffer containing key for the feature.
+ //! \param[in] keyLength Number of characters in key.
+ //! \note Following keys are supported:
+ //! - alias Enable support for aliases on the metadata object.
+ //!
+ virtual void APICALL EnableFeature( const char * key, sizet keyLength ) const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Disables support for a particular feature.
+ //! \param[in] key A const char buffer containing key for the feature.
+ //! \param[in] keyLength Number of characters in key.
+ //!
+ virtual void APICALL DisableFeature( const char * key, sizet keyLength ) const __NOTHROW__ = 0;
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IMetadata interface.
+ //!
+ virtual pIMetadata APICALL GetActualIMetadata() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIMetadata GetActualIMetadata() const __NOTHROW__ {
+ return const_cast< IMetadata_v1 * >( this )->GetActualIMetadata();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IMetadata_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIMetadata_I APICALL GetIMetadata_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIMetadata_I GetIMetadata_I() const __NOTHROW__ {
+ return const_cast< IMetadata_v1 * >( this )->GetIMetadata_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIMetadata MakeShared( pIMetadata_base ptr );
+ XMP_PRIVATE static spcIMetadata MakeShared( pcIMetadata_base ptr ) {
+ return MakeShared( const_cast< pIMetadata_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIMetadataID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // static factory functions
+
+ //!
+ //! @brief Creates an empty IMetadata object.
+ //! \return A shared pointer to an empty \#IMetadata object.
+ //!
+ XMP_PRIVATE static spIMetadata CreateMetadata();
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IMetadata_v1() __NOTHROW__ {}
+
+ //! Hiding some functions from derived classes
+ using INode_v1::GetParent;
+ using INode_v1::GetNameSpace;
+ using INode_v1::SetNameSpace;
+ using INode_v1::GetName;
+ using INode_v1::SetName;
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pcIUTF8String_base APICALL getAboutURI( pcIError_base & error ) const __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // __IMetadata_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INameSpacePrefixMap.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INameSpacePrefixMap.h
new file mode 100644
index 0000000000..9aa606a2aa
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INameSpacePrefixMap.h
@@ -0,0 +1,236 @@
+#ifndef INameSpacePrefixMap_h__
+#define INameSpacePrefixMap_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IThreadSafe.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that represents map where each entry consists of prefix string
+ //! as the key and corresponding nameSpace string as its value.
+ //! \details Provides all the functions to get/set the entries inside the map.
+ //! \attention Supports Multi-threading at object level through locks.
+ //!
+ class XMP_PUBLIC INameSpacePrefixMap_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ , public virtual IThreadSafe
+ {
+ public:
+
+ //!
+ //! @brief Adds a new pair of prefix string and its corresponding nameSpace string or replace an existing entry.
+ //! \param[in] prefix Pointer to a constant char buffer containing prefix string.
+ //! \param[in] prefixLength Number of characters in prefix. In case prefix is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing nameSpace string.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A bool type object containing true in case operation was successful, false otherwise.
+ //! \note Raises warning in case of
+ //! - prefix or nameSpace are null pointers
+ //! - prefixLength or nameSpaceLength is 0.
+ //!
+ virtual bool APICALL Insert( const char * prefix, sizet prefixLength, const char * nameSpace, sizet nameSpaceLength ) = 0;
+
+ //!
+ //! @brief Finds the prefix string in the map and removes an entry corresponding to it in the map.
+ //! \param[in] prefix Pointer to a const char buffer containing prefix string.
+ //! \param[in] prefixLength Number of characters in prefix. In case prefix is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A bool type object containing true in case entry was found and then deleted from the map, false otherwise.
+ //! \note Raises warning in case of
+ //! - prefix is null pointer, or
+ //! - prefixLength is 0.
+ //! \attention Throws AdobeXMPCommon::pcIError in case of failure in removing or searching process.
+ //!
+ virtual bool APICALL RemovePrefix( const char * prefix, sizet prefixLength ) = 0;
+
+ //!
+ //! @brief Finds the nameSpace string in the map and removes an entry corresponding to it in the map.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing nameSpace string.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A bool type object containing true in case entry was found and then deleted from the map, false otherwise.
+ //! \note Raises warning in case of
+ //! - nameSpace is null pointer, or
+ //! - nameSpaceLength is 0.
+ //! \attention Throws AdobeXMPCommon::pcIError in case of failure in removing or searching process.
+ //!
+ virtual bool APICALL RemoveNameSpace( const char * nameSpace, sizet nameSpaceLength ) = 0;
+
+ //!
+ //! @brief Checks for the existence of a particular prefix in the map.
+ //! \param[in] prefix Pointer to a const char buffer containing prefix string.
+ //! \param[in] prefixLength Number of characters in prefix. In case prefix is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A bool type object containing true in case there is an entry present corresponding to the prefix string, otherwise false.
+ //! \note Raises warning in case of
+ //! - prefix is null pointer, or
+ //! - prefixLength is 0.
+ //!
+ virtual bool APICALL IsPrefixPresent( const char * prefix, sizet prefixLength ) const = 0;
+
+ //!
+ //! @brief Checks for the existence of a particular nameSpace in the map.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing nameSpace string.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A bool type object containing true in case there is an entry present corresponding to the nameSpace string, otherwise false.
+ //! \note Raises warning in case of
+ //! - nameSpace is null pointer, or
+ //! - nameSpaceLength is 0.
+ //!
+ virtual bool APICALL IsNameSpacePresent( const char * nameSpace, sizet nameSpaceLength ) const = 0;
+
+ //!
+ //! @brief Gets the nameSpace string corresponding to the prefix string.
+ //! \param[in] prefix Pointer to a const char buffer containing prefix string.
+ //! \param[in] prefixLength Number of characters in prefix. In case prefix is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String object containing nameSpace string corresponding to
+ //! prefix string if a mapping exists, otherwise invalid shared pointer is returned.
+ //! \note Raises warning in case of
+ //! - prefix is null pointer, or
+ //! - prefixLength is 0.
+ //!
+ virtual spcIUTF8String APICALL GetNameSpace( const char * prefix, sizet prefixLength ) const = 0;
+
+ //!
+ //! @brief Get the prefix string corresponding to the nameSpace string.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing nameSpace string.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String object containing prefix string corresponding to
+ //! nameSpace string if a mapping exists, otherwise invalid shared pointer is returned.
+ //! \note Raises warning in case of
+ //! - nameSpace is null pointer, or
+ //! - nameSpaceLength is 0.
+ //!
+ virtual spcIUTF8String APICALL GetPrefix( const char * nameSpace, sizet nameSpaceLength ) const = 0;
+
+ //!
+ //! @brief To get the total number of entries in the map.
+ //! \return An object of type \#AdobeXMPCommon::sizet containing the count of entries in the map.
+ //!
+ virtual sizet APICALL Size() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief To check whether the map is empty or not.
+ //! \return True in case map is empty; false otherwise.
+ //!
+ bool IsEmpty() const __NOTHROW__;
+
+ //!
+ //! @brief Clear all the entries in the map.
+ //!
+ virtual void APICALL Clear() __NOTHROW__ = 0;
+
+ //!
+ //! \brief Virtual Copy Constructor.
+ //! \details Makes an another object which is exact replica of the existing object.
+ // \return A shared pointer to INameSpacePrefixMap which is exact replica of the current object.
+ //!
+ virtual spINameSpacePrefixMap APICALL Clone() const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to INameSpacePrefixMap interface.
+ //!
+ virtual pINameSpacePrefixMap APICALL GetActualINameSpacePrefixMap() __NOTHROW__ = 0;
+ XMP_PRIVATE pcINameSpacePrefixMap GetActualINameSpacePrefixMap() const __NOTHROW__ {
+ return const_cast< INameSpacePrefixMap_v1 * >( this )->GetActualINameSpacePrefixMap();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to INameSpacePrefixMap_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pINameSpacePrefixMap_I APICALL GetINameSpacePrefixMap_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcINameSpacePrefixMap_I GetINameSpacePrefixMap_I() const __NOTHROW__ {
+ return const_cast< INameSpacePrefixMap_v1 * >( this )->GetINameSpacePrefixMap_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spINameSpacePrefixMap MakeShared( pINameSpacePrefixMap_base ptr );
+ XMP_PRIVATE static spcINameSpacePrefixMap MakeShared( pcINameSpacePrefixMap_base ptr ) {
+ return MakeShared( const_cast< pINameSpacePrefixMap_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kINameSpacePrefixMapID; }
+
+ //!
+ //! @brief returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+
+ //! \endcond
+
+
+ // static factory functions
+
+ //!
+ //! @brief Provides the default mapping of prefix string and nameSpace strings used by XMPCore.
+ //! \return A shared pointer to const INameSpacePrefixMap object containing all the mappings used
+ //! as default by the XMPCore.
+ //!
+ XMP_PRIVATE static spcINameSpacePrefixMap GetDefaultNameSpacePrefixMap();
+
+ //!
+ //! @brief Creates an empty namespace - prefix map and returns it to the client as a shared pointer.
+ //! \return A shared pointer to an empty INameSpacePrefixMap object.
+ //!
+ XMP_PRIVATE static spINameSpacePrefixMap CreateNameSpacePrefixMap();
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~INameSpacePrefixMap_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ const uint32 kPrefixIsParameter = 0;
+ const uint32 kNameSpaceIsParameter = 1;
+
+ virtual uint32 APICALL insert( const char * prefix, sizet prefixLength, const char * nameSpace, sizet nameSpaceLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL remove( uint32 keyType, const char * key, sizet keyLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL isPresent( uint32 keyType, const char * key, sizet keyLength, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL get( uint32 keyType, const char * key, sizet keyLength, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINameSpacePrefixMap_base APICALL clone( pcIError_base & error ) const __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // INameSpacePrefixMap_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INode.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INode.h
new file mode 100644
index 0000000000..59b64bb469
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INode.h
@@ -0,0 +1,582 @@
+#ifndef __INode_h__
+#define __INode_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IThreadSafe.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that serves as a base interface to all types of nodes in the XMP DOM.
+ //! \details Provides all the functions to get various properties of the node.
+ //! \attention Support multi threading through locks but can be enabled/disabled by the client. By default
+ //! every object created does not support multi-threading.
+ //!
+ class XMP_PUBLIC INode_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ , public virtual IThreadSafe
+ {
+ public:
+
+ //!
+ //! @brief Indicates various types of node available in XMP Data Model like simple, array and structure.
+ //!
+ typedef enum {
+ //! Indicates none, to be used as invalid type.
+ kNTNone = 0,
+
+ //! XMP Node is of Simple Node type (key value pair).
+ kNTSimple = 1,
+
+ //! XMP Node is of Array type. Indexing start from 1.
+ kNTArray = 1 << 1,
+
+ //! XMP Node is of structure type.
+ kNTStructure = 1 << 2,
+
+ //! XMP Node of any type
+ kNTAll = kAllBits
+ } eNodeType;
+
+ //!
+ //! @brief Gets the node type of the node.
+ //! \return An object of type \#eNodeType indicating the type of the node.
+ //!
+ virtual eNodeType APICALL GetNodeType() const = 0;
+
+ //!
+ //! @brief Gets the node type of the node's parent.
+ //! \return An object of type \#eNodeType indicating the type of the node.
+ //! \note \#eNodeType::kNTNone is returned in case node has no parent.
+ //!
+ virtual eNodeType APICALL GetParentNodeType() const = 0;
+
+ //!
+ //! @{
+ //! @brief Gets the parent node of the node.
+ //! \return Either a const or non const pointer to INode interface.
+ //! \return A shared pointer to either a const or non const \#AdobeXMPCore::INode representing the parent of the node.
+ //! \note Returns an invalid shared pointer in case the node is a root node or it is not part of tree.
+ //!
+ XMP_PRIVATE spcINode GetParent() const {
+ return const_cast< INode_v1 * >( this )->GetParent();
+ }
+ virtual spINode APICALL GetParent() = 0;
+ //!
+ //! @}
+
+ //!
+ //! @brief Changes the local name of the node.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \attention Error can be thrown in case
+ //! - name is NULL pointer or its contents are empty
+ //! - name is not valid XML property name.
+ //! - Sibling with the same combination of name and nameSpace is present.
+ //!
+ virtual void APICALL SetName( const char * name, sizet nameLength ) = 0;
+
+ //!
+ //! @brief Gets the local name of the node.
+ //! \return a shared pointer to const \#AdobeXMPCommon::IUTF8String representing the name of the node.
+ //!
+ virtual spcIUTF8String APICALL GetName() const = 0;
+
+ //!
+ //! @brief Changes the name space of the node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \attention Error can be thrown in case
+ //! - nameSpace is NULL pointer or its contents are empty
+ //! - Sibling with the same combination of name and nameSpace is present.
+ //!
+ virtual void APICALL SetNameSpace( const char * nameSpace, sizet nameSpaceLength ) = 0;
+
+ //!
+ //! @brief Gets the name space of the node.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String representing the name space of the node.
+ //!
+ virtual spcIUTF8String APICALL GetNameSpace() const = 0;
+
+ //!
+ //! @brief Gets the path of the node from the root of the metadata.
+ //! \return A shared pointer to \#AdobeXMPCore::IPath representing the path of the node.
+ //!
+ virtual spIPath APICALL GetPath() const = 0;
+
+ //!
+ //! @brief Gets the count of the qualifiers attached with the node
+ //! \return An object of type \#AdobeXMPCommon::sizet containing the count of qualifiers attached with the node.
+ //!
+ virtual sizet APICALL QualifiersCount() const __NOTHROW__ = 0;
+
+ //!
+ //! @{
+ //! Get an iterator object to iterate over all the qualifier nodes attached to the composite node.
+ //! \return A shared pointer to a const or non const \#INodeIterator object.
+ //!
+ XMP_PRIVATE spcINodeIterator QualifiersIterator() const {
+ return const_cast< INode_v1 * >( this )->QualifiersIterator();
+ }
+ virtual spINodeIterator APICALL QualifiersIterator() = 0;
+ //! @}
+
+ //!
+ //! @brief Gets the type of the node's qualifier having specified namespace and name.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the qualifier node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the qualifier node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return An object of type \#eNodeType indicating the type of the node's qualifier.
+ //! \note In case no qualifier exists with the specified nameSpace and name combination then an \#eNodeType::kNTNode is returned.
+ //!
+ virtual eNodeType APICALL GetQualifierNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const = 0;
+
+ //!
+ //! @{
+ //! @brief Gets the qualifier of the node having specified namespace and name.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the qualifier node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the qualifier node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to either a const or const qualifier node.
+ //! \note In case no qualifier exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //!
+ XMP_PRIVATE spcINode GetQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ return const_cast< INode_v1 * >( this )->GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ }
+ virtual spINode APICALL GetQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) = 0;
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get the node's qualifier having specified name space and name as simple node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the qualifier node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the qualifier node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const or non const \#ISimpleNode object containing qualifier.
+ //! \note In case no qualifier exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //! \attention Error is thrown in case
+ //! - a qualifier exists with the specified nameSpace and name combination but is not a simple node.
+ //!
+ XMP_PRIVATE spcISimpleNode GetSimpleQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ auto node = GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spcISimpleNode();
+ }
+
+ XMP_PRIVATE spISimpleNode GetSimpleQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ auto node = GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spISimpleNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get the node's qualifier having specified name space and name as structure node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the qualifier node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the qualifier node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const or non const \#IStructureNode object containing qualifier.
+ //! \note In case no qualifier exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //! \attention Error is thrown in case
+ //! - a qualifier exists with the specified nameSpace and name combination but is not a structure node.
+ //!
+ XMP_PRIVATE spcIStructureNode GetStructureQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ auto node = GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToStructureNode();
+ return spcIStructureNode();
+ }
+
+ XMP_PRIVATE spIStructureNode GetStructureQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ auto node = GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToStructureNode();
+ return spIStructureNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Get the node's qualifier having specified name space and name as an array node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the qualifier node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the qualifier node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const or non const \#ISimpleNode object containing qualifier.
+ //! \note In case no qualifier exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //! \attention Error is thrown in case
+ //! - a qualifier exists with the specified nameSpace and name combination but is not an array node.
+ //!
+ XMP_PRIVATE spcIArrayNode GetArrayQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ auto node = GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToArrayNode();
+ return spcIArrayNode();
+ }
+
+ XMP_PRIVATE spIArrayNode GetArrayQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ auto node = GetQualifier( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToArrayNode();
+ return spIArrayNode();
+ }
+ //! @}
+
+ //!
+ //! @brief Inserts a given qualifier node.
+ //! \param[in] node Shared pointer to an object of \#AdobeXMPCore::INode representing the qualifier node to be inserted.
+ //! \attention Error is thrown in following cases:
+ //! - given qualifier node is invalid.
+ //! - given qualifier node is already a child of some other node.
+ //! - there exists a qualifier node with the same nameSpace and name combination.
+ //! - parent or any ancestor node is a qualifier node.
+ //!
+ virtual void APICALL InsertQualifier( const spINode & node ) = 0;
+
+ //!
+ //! @brief Replaces a given qualifier node.
+ //! \param[in] node Shared pointer to an object of \#AdobeXMPCore::INode representing the qualifier node to be inserted.
+ //! \return A shared pointer to a qualifier node which is being replaced.
+ //! \attention Error is thrown in following cases:
+ //! -# given qualifier node is invalid.
+ //! -# given qualifier node is already a child of some other node.
+ //! -# there exists no qualifier node with the same nameSpace and name combination.
+ //! \note Warning is raised in case the type of the old existing node is not same as that of new node.
+ //!
+ virtual spINode APICALL ReplaceQualifier( const spINode & node ) = 0;
+
+ //!
+ //! @brief Removes the qualifier node with the specified nameSpace and name.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the qualifier node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the qualifier node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to \#AdobeXMPCore::INode object representing qualifier node which is removed from the node.
+ //! \note In case no qualifier node exists at the given index an invalid shared pointer is returned.
+ //!
+ virtual spINode APICALL RemoveQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) = 0;
+
+ //!
+ //! @brief Indicates whether the node is a direct child of an array node.
+ //! \return A bool value; true in case the node is a direct child of an array node, false otherwise.
+ //!
+ virtual bool APICALL IsArrayItem() const = 0;
+
+ //!
+ //! @brief Indicates whether the node is a qualifier node.
+ //! \return A bool value; true in case the node is a qualifier node, false otherwise.
+ //!
+ virtual bool APICALL IsQualifierNode() const = 0;
+
+ //!
+ //! @brief Returns the index of the node in case it is an array item.
+ //! \return The index of the node, in case it is an array item, otherwise returns 0.
+ //!
+ virtual sizet APICALL GetIndex() const = 0;
+
+ //!
+ //! @brief Indicates whether the node has any qualifiers associated with it.
+ //! \return A bool value; true in case the node has any qualifier associated with it, false otherwise.
+ //!
+ virtual bool APICALL HasQualifiers() const = 0;
+
+ //!
+ //! @brief Returns whether the node has any content or not.
+ //! return A bool value indicating the presence of contents in the node apart from qualifiers.
+ //!
+ virtual bool APICALL HasContent() const = 0;
+
+ //!
+ //! @brief Returns whether the node is empty.
+ //! return A bool value indicating whether the contents and qualifiers of a node are empty.
+ //!
+ virtual bool APICALL IsEmpty() const = 0;
+
+ //!
+ //! @brief Returns the status about any change done to the node or its children or qualifiers.
+ //! returns a bool value indicating whether some changes have been performed on the node or its children or qualifiers.
+ //! for a simple node, true will be returned in scenarios like when the node's value or qualifiers are modified.
+ //! for an array node or a structure node, true will be returned in scenarios like when the node's children or the node's qualifiers are modified.
+ //!
+ virtual bool APICALL HasChanged() const = 0;
+
+ //!
+ //! @brief Acknowledges that changes for the node and its children and qualifiers have been taken care of.
+ //! for a simple node, changes that will be acknowledged in scenarios like when the node's value or node's qualifiers were modified.
+ //! for an array node or a structure node, changes will be acknowledged in scenarios like when the node's children were or the node's qualifiers were modified.
+ //!
+ virtual void APICALL AcknowledgeChanges() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Clear the contents of the node.
+ //! \param[in] contents A bool value controlling whether contents of the node should be cleared or not.
+ //! \param[in] qualifiers A bool value controlling whether qualifiers of the node should be cleared or not.
+ //!
+ virtual void APICALL Clear( bool contents = true, bool qualifiers = true ) = 0;
+
+ //!
+ //! @{
+ //! @brief Converts Node to a simple node, if possible.
+ //! \return Shared pointer to const or non const ISimpleNode object. An empty simple node is thrown in case actual node is not a simple node.
+ //!
+ XMP_PRIVATE spcISimpleNode ConvertToSimpleNode() const {
+ return const_cast< INode_v1 * >( this )->ConvertToSimpleNode();
+ }
+ virtual spISimpleNode APICALL ConvertToSimpleNode() = 0;
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts Node to a structure node type, if possible.
+ //! \return Shared pointer to const or non const IStructureNode object. An empty structure node is thrown in case actual node is not a structure node.
+ //!
+ XMP_PRIVATE spcIStructureNode ConvertToStructureNode() const {
+ return const_cast< INode_v1 * >( this )->ConvertToStructureNode();
+ }
+ virtual spIStructureNode APICALL ConvertToStructureNode() = 0;
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts Node to an array node type, if possible.
+ //! \return Shared pointer to const or non const IArrayNode object. An empty array node is thrown in case actual node is not an array node.
+ //!
+ XMP_PRIVATE spcIArrayNode ConvertToArrayNode() const {
+ return const_cast< INode_v1 * >( this )->ConvertToArrayNode();
+ }
+ virtual spIArrayNode APICALL ConvertToArrayNode() = 0;
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts Node to a metadata node type, if possible.
+ //! \return Shared pointer to const or non const IMetadata object. An empty metadata node is thrown in case actual node is not a metadata node.
+ //!
+ XMP_PRIVATE spcIMetadata ConvertToMetadata() const {
+ return const_cast< INode_v1 * >( this )->ConvertToMetadata();
+ }
+ virtual spIMetadata APICALL ConvertToMetadata() = 0;
+ //! @}
+
+ //!
+ //! @brief Virtual copy constructor
+ //! @details Clones the node creating an exact replica of the node which is not part of any metadata tree.
+ //! \param[in] ignoreEmptyNodes A bool value controlling whether to clone empty nodes or not.
+ //! \param[in] ignoreNodesWithOnlyQualifiers A bool value controlling whether presence of only qualifiers should mark
+ //! node as non empty.
+ //! \return A shared pointer to newly created replica of the node.
+ //!
+ virtual spINode APICALL Clone( bool ignoreEmptyNodes = false, bool ignoreNodesWithOnlyQualifiers = false ) const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to INode interface.
+ //!
+ virtual pINode APICALL GetActualINode() __NOTHROW__ = 0;
+
+ XMP_PRIVATE pcINode GetActualINode() const __NOTHROW__ {
+ return const_cast< INode_v1 * >( this )->GetActualINode();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to INode_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pINode_I APICALL GetINode_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcINode_I GetINode_I() const __NOTHROW__ {
+ return const_cast< INode_v1 * >( this )->GetINode_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spINode MakeShared( pINode_base ptr );
+ XMP_PRIVATE static spcINode MakeShared( pcINode_base ptr ) {
+ return MakeShared( const_cast< pINode_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kINodeID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~INode_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL getParentNodeType( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINode_base APICALL getParent( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL setName( const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getName( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual void APICALL setNameSpace( const char * nameSpace, sizet nameSpaceLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getNameSpace( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pIPath_base APICALL getPath( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINodeIterator_base APICALL qualifiersIterator( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL getQualifierNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINode_base APICALL getQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL insertQualifier( pINode_base base, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL replaceQualifier( pINode_base node, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL removeQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL getNodeType( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL isArrayItem( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL isQualifierNode( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual sizet APICALL getIndex( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL hasQualifiers( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL hasContent( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL isEmpty( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL hasChanged( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual void APICALL clear( uint32 contents, uint32 qualifiers, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL clone( uint32 igoreEmptyNodes, uint32 ignoreNodesWithOnlyQualifiers, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pISimpleNode_base APICALL convertToSimpleNode( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIStructureNode_base APICALL convertToStructureNode( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIArrayNode_base APICALL convertToArrayNode( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIMetadata_base APICALL convertToMetadata( pcIError_base & error ) __NOTHROW__ = 0;
+
+ //! @}
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+//! \cond XMP_INTERNAL_DOCUMENTATION
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+ namespace AdobeXMPCore {
+
+ class INodeProxy
+ : public virtual INode
+ {
+ private:
+ pINode mRawPtr;
+
+ public:
+ INodeProxy( pINode ptr );
+ ~INodeProxy() __NOTHROW__ ;
+
+ pINode APICALL GetActualINode() __NOTHROW__;
+ void APICALL Acquire() const __NOTHROW__;
+ void APICALL Release() const __NOTHROW__;
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__;
+ AdobeXMPCore_Int::pINode_I APICALL GetINode_I() __NOTHROW__;
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion );
+
+ virtual eNodeType APICALL GetParentNodeType() const;
+ virtual spINode APICALL GetParent();
+ virtual void APICALL SetName( const char * name, sizet nameLength );
+ virtual spcIUTF8String APICALL GetName() const;
+ virtual void APICALL SetNameSpace( const char * nameSpace, sizet nameSpaceLength );
+ virtual spcIUTF8String APICALL GetNameSpace() const;
+ virtual spIPath APICALL GetPath() const;
+ virtual sizet APICALL QualifiersCount() const __NOTHROW__;
+ virtual spINodeIterator APICALL QualifiersIterator();
+ virtual eNodeType APICALL GetQualifierNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const;
+ virtual spINode APICALL GetQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+ virtual void APICALL InsertQualifier( const spINode & node );
+ virtual spINode APICALL ReplaceQualifier( const spINode & node );
+ virtual spINode APICALL RemoveQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+ virtual eNodeType APICALL GetNodeType() const;
+ virtual bool APICALL IsArrayItem() const;
+ virtual bool APICALL IsQualifierNode() const;
+ virtual sizet APICALL GetIndex() const;
+ virtual bool APICALL HasQualifiers() const;
+ virtual bool APICALL HasContent() const;
+ virtual bool APICALL IsEmpty() const;
+ virtual bool APICALL HasChanged() const;
+ virtual void APICALL AcknowledgeChanges() const __NOTHROW__;
+ virtual void APICALL Clear( bool contents, bool qualifiers );
+ virtual spINode APICALL Clone( bool ignoreEmptyNodes, bool ignoreNodesWithOnlyQualifiers ) const;
+ virtual void APICALL EnableThreadSafety() const __NOTHROW__;
+ virtual void APICALL DisableThreadSafety() const __NOTHROW__;
+ virtual bool APICALL IsThreadSafe() const;
+ virtual AdobeXMPCommon_Int::pIThreadSafe_I APICALL GetIThreadSafe_I() __NOTHROW__;
+ virtual spISimpleNode APICALL ConvertToSimpleNode();
+ virtual spIStructureNode APICALL ConvertToStructureNode();
+ virtual spIArrayNode APICALL ConvertToArrayNode();
+ virtual spIMetadata APICALL ConvertToMetadata();
+
+ protected:
+ virtual pINode_base APICALL getParent( pcIError_base & error ) __NOTHROW__;
+ virtual void APICALL setName( const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__;
+ virtual pcIUTF8String_base APICALL getName( pcIError_base & error ) const __NOTHROW__;
+ virtual void APICALL setNameSpace( const char * nameSpace, sizet nameSpaceLength, pcIError_base & error ) __NOTHROW__;
+ virtual pcIUTF8String_base APICALL getNameSpace( pcIError_base & error ) const __NOTHROW__;
+ virtual pIPath_base APICALL getPath( pcIError_base & error ) const __NOTHROW__;
+ virtual pINodeIterator_base APICALL qualifiersIterator( pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL getQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__;
+ virtual void APICALL insertQualifier( pINode_base base, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL replaceQualifier( pINode_base node, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL removeQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__;
+ virtual uint32 APICALL getNodeType( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL isArrayItem( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL isQualifierNode( pcIError_base & error ) const __NOTHROW__;
+ virtual sizet APICALL getIndex( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL hasQualifiers( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL hasContent( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL isEmpty( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL hasChanged( pcIError_base & error ) const __NOTHROW__;
+ virtual void APICALL clear( uint32 contents, uint32 qualifiers, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL clone( uint32 igoreEmptyNodes, uint32 ignoreNodesWithOnlyQualifiers, pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL isThreadSafe() const __NOTHROW__;
+ virtual pISimpleNode_base APICALL convertToSimpleNode( pcIError_base & error ) __NOTHROW__;
+ virtual pIStructureNode_base APICALL convertToStructureNode( pcIError_base & error ) __NOTHROW__;
+ virtual pIArrayNode_base APICALL convertToArrayNode( pcIError_base & error ) __NOTHROW__;
+ virtual pIMetadata_base APICALL convertToMetadata( pcIError_base & error ) __NOTHROW__;
+ virtual uint32 APICALL getParentNodeType( pcIError_base & error ) const __NOTHROW__;
+ virtual uint32 APICALL getQualifierNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) const __NOTHROW__;
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__;
+ };
+
+}
+#endif // !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+//! \endcond
+
+#endif // __INode_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INodeIterator.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INodeIterator.h
new file mode 100644
index 0000000000..93bb194d44
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/INodeIterator.h
@@ -0,0 +1,193 @@
+#ifndef __INodeIterator_h__
+#define __INodeIterator_h__ 1
+
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCore/Interfaces/INode.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Interface that represents an iterator over the mutable children of a XMP DOM Node.
+ //! \note Iterators are valid as long as their are no changes performed on the node. In case there are some
+ //! changes performed on the node then the behavior is undefined.
+ //!
+ class XMP_PUBLIC INodeIterator_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Gets the type of the node currently pointed by the iterator.
+ //! \return A value of type \#INode_v1::eNodeType indicating the type of the node currently pointed by the iterator.
+ //!
+ virtual INode_v1::eNodeType APICALL GetNodeType() const = 0;
+
+ //!
+ //! @{
+ //! @brief Gets the node currently pointed by the iterator.
+ //! \return A shared pointer to a const or non const object of type \#INode.
+ //! \note In case iterator has gone beyond its limit, an invalid shared pointer is returned
+ //!
+ virtual spINode APICALL GetNode() = 0;
+ XMP_PRIVATE spcINode APICALL GetNode() const {
+ return const_cast< INodeIterator * >( this )->GetNode();
+ };
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Gets the iterator's currently pointed node as simple node, if possible.
+ //! \return A shared pointer to a const or non const object of type \#ISimpleNode.
+ //! \attention Error is thrown in case
+ //! - iterator's currently pointed node is valid but is not a simple node.
+ //! \note In case iterator has gone beyond its limit, an invalid shared pointer is returned.
+ //!
+ XMP_PRIVATE spISimpleNode GetSimpleNode() {
+ auto node = GetNode();
+ if ( node ) return node->ConvertToSimpleNode();
+ return spISimpleNode();
+ }
+
+ XMP_PRIVATE spcISimpleNode GetSimpleNode() const {
+ return const_cast< INodeIterator * >( this )->GetSimpleNode();
+ }
+ //! @}
+
+ //!
+ //! @brief Gets the iterator's currently pointed node as structure node, if possible.
+ //! \return A shared pointer to a const or non const object of type \#IStructureNode.
+ //! \attention Error is thrown in case
+ //! - iterator's currently pointed node is valid but is not a structure node.
+ //! \note In case iterator has gone beyond its limit, an invalid shared pointer is returned.
+ //!
+ XMP_PRIVATE spIStructureNode GetStructureNode() {
+ auto node = GetNode();
+ if ( node ) return node->ConvertToStructureNode();
+ return spIStructureNode();
+ }
+
+ XMP_PRIVATE spcIStructureNode GetStructureNode() const {
+ return const_cast< INodeIterator * >( this )->GetStructureNode();
+ }
+ //! @}
+
+ //!
+ //! @brief Gets the iterator's currently pointed node as an array node, if possible.
+ //! \return A shared pointer to a const or non const object of type \#IArrayNode.
+ //! \attention Error is thrown in case
+ //! - iterator's currently pointed node is valid but is not an array node.
+ //! \note In case iterator has gone beyond its limit, an invalid shared pointer is returned.
+ //!
+ XMP_PRIVATE spIArrayNode GetArrayNode() {
+ auto node = GetNode();
+ if ( node ) return node->ConvertToArrayNode();
+ return spIArrayNode();
+ }
+
+ XMP_PRIVATE spcIArrayNode GetArrayNode() const {
+ return const_cast< INodeIterator * >( this )->GetArrayNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Advances iterator by one position.
+ //! \return A shared pointer to a const or non object of type \#INodeIterator.
+ //! \note Returned shared pointer is invalid in case the current node is the last one.
+ //!
+ virtual spINodeIterator APICALL Next() = 0;
+ XMP_PRIVATE spcINodeIterator APICALL Next() const {
+ return const_cast< INodeIterator * >( this )->Next();
+ }
+ //! @}
+
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to INodeIterator interface.
+ //!
+ virtual pINodeIterator APICALL GetActualINodeIterator() __NOTHROW__ = 0;
+ XMP_PRIVATE pcINodeIterator GetActualINodeIterator() const __NOTHROW__ {
+ return const_cast< INodeIterator * >( this )->GetActualINodeIterator();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to INodeIterator_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pINodeIterator_I APICALL GetINodeIterator_I() __NOTHROW__ = 0;
+ XMP_PRIVATE AdobeXMPCore_Int::pcINodeIterator_I GetINodeIterator_I() const __NOTHROW__ {
+ return const_cast< INodeIterator * >( this )->GetINodeIterator_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spINodeIterator MakeShared( pINodeIterator ptr );
+ XMP_PRIVATE static spcINodeIterator MakeShared( pcINodeIterator ptr ) {
+ return MakeShared( const_cast< pINodeIterator >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @}
+
+ //!
+ //! return the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kINodeIteratorID; }
+
+ //!
+ //! return the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~INodeIterator_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL getNodeType( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINode_base APICALL getNode( pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINodeIterator_base APICALL next( pcIError_base & error ) __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // __INodeIterator_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IPath.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IPath.h
new file mode 100644
index 0000000000..7f55853654
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IPath.h
@@ -0,0 +1,212 @@
+#ifndef __IPath_h__
+#define __IPath_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version1 of the interface that provides an easy iterative description of a specific path into the XMP tree.
+ //! @details Path consists of multiple path segments in an order and each \#IPathSegment represents one segment
+ //! of the path into the XMP tree.
+ //! Provides all the functions to create path and get the various properties of a path.
+ //! \attention Do not support multi-threading.
+ //! \note Index in the path are 1-based.
+ //!
+ class XMP_PUBLIC IPath_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief Registers a map of namespace and prefix with the object.
+ //! This map will be used during serialization and parsing.
+ //! \param[in] map A shared pointer of an object \#AdobeXMPCore::INameSpacePrefixMap.
+ //! \return A shared pointer to the const map registered previously with the object.
+ //!
+ virtual spcINameSpacePrefixMap APICALL RegisterNameSpacePrefixMap( const spcINameSpacePrefixMap & map ) = 0;
+
+ //!
+ //! @brief Serializes the IPath object to a utf8 string representation. This will produce either a long form of the path using
+ //! the full namespace strings or short form of the path using the prefix for the namespace.
+ //! \param[in] map A shared pointer to a const \#AdobeXMPCore::INameSpacePrefixMap object which can contain the
+ //! mapping for nameSpaces to prefixes. They will take precedence over the map registered with the object.
+ //! \return A shard pointer to \#AdobeXMPCommon::IUTF8String object containing serialized form of path.
+ //! \note In case map is not a valid shared pointer all the mappings will be picked from the map registered with the object.
+ //! If neither a map is registered nor it is provided in the arguments then it will serialize to long form of the path.
+ //! \attention Error will be thrown in case
+ //! - no prefix exists for a namespace used in the path.
+ //!
+ virtual spIUTF8String APICALL Serialize( const spcINameSpacePrefixMap & map = spcINameSpacePrefixMap() ) const = 0;
+
+ //!
+ //! @brief Appends a path segment to the path.
+ //! \param[in] segment A shared pointer to a const \#AdobeXMPCore::IPathSegment object.
+ //! \attention Error is thrown in case
+ //! - segment is not a valid shared pointer.
+ //!
+ virtual void APICALL AppendPathSegment( const spcIPathSegment & segment ) = 0;
+
+ //!
+ //! @brief Removes a path segment from the path.
+ //! \param[in] index Indicates the index of the path segment to be removed.
+ //! \returns A shared pointer to the const path segment removed.
+ //! \attention Error is thrown in case
+ //! - index is out of bounds.
+ //!
+ virtual spcIPathSegment APICALL RemovePathSegment( sizet index ) = 0;
+
+ //!
+ //! @brief Gets the path segment at a particular index in the path
+ //! \param[in] index Indicates the index for the path segment in the path.
+ //! \return A shared pointer to a const path segment.
+ //! \attention Error is thrown in case
+ //! -index is out of bounds.
+ //!
+ virtual spcIPathSegment APICALL GetPathSegment( sizet index ) const = 0;
+
+ //!
+ //! @brief Gets the number of the path segments in the path.
+ //! \return The count of the path segments in the path.
+ //!
+ virtual sizet APICALL Size() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief To check whether path is empty or not.
+ //! \returns A bool object indicating true in case the path is empty (no path segment)
+ //!
+ XMP_PRIVATE bool IsEmpty() const {
+ return Size() == 0;
+ }
+
+ //!
+ //! @brief Clears the path by removing all the path segments from it
+ //!
+ virtual void APICALL Clear() __NOTHROW__ = 0;
+
+ //!
+ //! @brief Gets a new path having a selected range of path segments
+ //! \param[in] startingIndex Indicates the starting index of the path segment to be part of the returned path object. Default value is 1.
+ //! \param[in] countOfSegments Indicates the count of the path segments to be part of the returned path object starting from startingIndex.
+ //! Default value is \#AdobeXMPCommon::kMaxSize.
+ //! \note In case countOfSegments is more than the number of segments available in the path object starting from the starting index
+ //! then internally it is truncated to the number of path segments available.
+ //! \attention Error is thrown in case
+ //! - startingIndex is more than the count of segments in the object.
+ //!
+ virtual spIPath APICALL Clone( sizet startingIndex = 1, sizet countOfSegments = kMaxSize ) const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IPath interface.
+ //!
+ virtual pIPath APICALL GetActualIPath() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIPath GetActualIPath() const __NOTHROW__ {
+ return const_cast< IPath_v1 * >( this )->GetActualIPath();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IPath_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIPath_I APICALL GetIPath_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIPath_I GetIPath_I() const __NOTHROW__ {
+ return const_cast< IPath_v1 * >( this )->GetIPath_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIPath MakeShared( pIPath_base ptr );
+ XMP_PRIVATE static spcIPath MakeShared( pcIPath_base ptr ) {
+ return MakeShared( const_cast< pIPath_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIPathID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // static factory functions
+
+ //!
+ //! @brief Creates an empty IPath object.
+ //! \return a shared pointer to an empty IPath object
+ //!
+ XMP_PRIVATE static spIPath CreatePath();
+
+ //!
+ //! @brief Creates a path from a char buffer which contains the serialized path.
+ //! \param[in] path Pointer to a const char buffer containing serialized form of the path.
+ //! \param[in] pathLength Number of characters in the path. In case path in null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] map A shared pointer to a const \#AdobeXMPCore::IXMPNameSpacePrefixMap object which will contain the
+ //! mapping from nameSpaces to prefixes.
+ //! \return A shared pointer to a \#AdobeXMPCore::IPath object.
+ //! \note In case the serializedPath is NULL or the contents are empty then it will result in an empty path.
+ //! \note This operation is currently not implemented for the IPath interface.
+ //! \attention Error is thrown in case
+ //! - no mapping exists for a prefix to name space.
+ //! - path contains invalid data.
+ //!
+ XMP_PRIVATE static spIPath ParsePath( const char * path, sizet pathLength, const spcINameSpacePrefixMap & map );
+
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IPath_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pcINameSpacePrefixMap_base APICALL registerNameSpacePrefixMap( pcINameSpacePrefixMap_base map, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pIUTF8String_base APICALL serialize( pcINameSpacePrefixMap_base map, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual void APICALL appendPathSegment( pcIPathSegment_base segment, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pcIPathSegment_base APICALL removePathSegment( sizet index, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pcIPathSegment_base APICALL getPathSegment( sizet index, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pIPath_base APICALL clone( sizet startingIndex, sizet countOfSegemetns, pcIError_base & error ) const __NOTHROW__ = 0;
+
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // __IPath_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IPathSegment.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IPathSegment.h
new file mode 100644
index 0000000000..9dd9ac972f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IPathSegment.h
@@ -0,0 +1,225 @@
+#ifndef __IPathSegment_h__
+#define __IPathSegment_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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 "XMPCore/XMPCoreFwdDeclarations.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/ISharedObject.h"
+#include "XMPCommon/Interfaces/BaseInterfaces/IVersionable.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version1 of the interface that represents one segment in a path to a node into the XMP tree.
+ //! @details Provides all the functions to access properties of the path segment and factory functions
+ //! to create various kinds of path segments.
+ //! \attention Not thread safe and not required as only read only access is provided to client.
+ //!
+ class XMP_PUBLIC IPathSegment_v1
+ : public virtual ISharedObject
+ , public virtual IVersionable
+ {
+ public:
+
+ //!
+ //! @brief This enumeration represents the types of a path segment.
+ //!
+ typedef enum {
+ //! None type
+ kPSTNone = 0,
+
+ //! Any property that consists of namespace and a localName
+ kPSTProperty = 1,
+
+ //! An array index which does not have a namespace or localName itself
+ kPSTArrayIndex = 1 << 1,
+
+ //! A qualifier of a property, also consists of namespace and localName
+ kPSTQualifier = 1 << 2,
+
+ //! Selects a specific qualifier by its value (e.g. specific language)
+ kPSTQualifierSelector = 1 << 3,
+
+ //! Represents all property types
+ kPSTAll = kAllBits
+ } ePathSegmentType;
+
+ //!
+ //! @brief Gets the name space of the path segment.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String object representing namespace of the path segment.
+ //!
+ virtual spcIUTF8String APICALL GetNameSpace() const = 0;
+
+ //!
+ //! @brief Gets the name of the path segment.
+ //! \return A shared pointer to const \#AdobeXMPCommon::IUTF8String object containing name of the path segment. In case
+ //! path segment has no name space, an invalid shared pointer is returned.
+ //!
+ virtual spcIUTF8String APICALL GetName() const = 0;
+
+ //!
+ //! @brief Gets the type of the path segment.
+ //! \return An object of type \#ePathSegmentType representing type of the path segment.
+ //!
+ virtual ePathSegmentType APICALL GetType() const = 0;
+
+ //!
+ //! @brief Gets the index of the array type path segment.
+ //! \return An objet of type \#AdobeXMPCommon::sizet object representing index of the array type path segment. In case
+ //! path segment is not of type kPSTArrayIndex, it returns \#AdobeXMPCommon::kMaxSize.
+ //!
+ virtual sizet APICALL GetIndex() const __NOTHROW__ = 0;
+
+ //!
+ //! @brief Gets the value of the qualifier type path segment.
+ //! \return A shared pointer to const \#AdobeXMP::IUTF8String object representing value of the qualifier type path segment.
+ //! In case path segment is not of type kPSTQualifier an invalid shared pointer is returned.
+ //!
+ virtual spcIUTF8String APICALL GetValue() const = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IPathSegment interface.
+ //!
+ virtual pIPathSegment APICALL GetActualIPathSegment() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIPathSegment GetActualIPathSegment() const __NOTHROW__ {
+ return const_cast< IPathSegment_v1 * >( this )->GetActualIPathSegment();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IPathSegment_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIPathSegment_I APICALL GetIPathSegment_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIPathSegment_I GetIPathSegment_I() const __NOTHROW__ {
+ return const_cast< IPathSegment_v1 * >( this )->GetIPathSegment_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer.
+ //! @details The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIPathSegment MakeShared( pIPathSegment_base ptr );
+ XMP_PRIVATE static spcIPathSegment MakeShared( pcIPathSegment_base ptr ) {
+ return MakeShared( const_cast< pIPathSegment_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIPathSegmentID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // static factory functions
+
+ // Factories to create the specific segments
+
+ //!
+ //! @brief Creates a normal property path segment.These are essentially all properties (simple, struct and arrays).
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the property.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const \#IPathSegment.
+ //! \attention Throws \#AdobeXMPCommon::pcIError in case
+ //! - pointers to const char buffers are NULL,
+ //! - their content is empty.
+ //!
+ XMP_PRIVATE static spcIPathSegment CreatePropertyPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ //!
+ //! @brief Creates an array index path segment that denotes a specific element of an array.
+ //! @details Such segments do not have an own name and inherits the namespace from the Array property itself.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] index An object of type \#AdobeXMP::sizet containting the index of the array element.
+ //! \return A shared pointer to const \#IPathSegment.
+ //! \attention Throws \#AdobeXMP::pcIError in case
+ //! - pointers to const char buffers are NULL,
+ //! - their content is empty.
+ //!
+ //!
+ XMP_PRIVATE static spcIPathSegment CreateArrayIndexPathSegment( const char * nameSpace, sizet nameSpaceLength, sizet index );
+
+ //!
+ //! @brief Creates a Qualifier path segment, which behaves like a normal property
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the property.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const \#IPathSegment.
+ //! \attention Throws \#AdobeXMPCommon::pcIError in case
+ //! - pointers to const char buffers are NULL,
+ //! - their content is empty.
+ //!
+ XMP_PRIVATE static spcIPathSegment CreateQualifierPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ //!
+ //! @brief Creates a path segment that selects a specific qualifier by its value.
+ //! For example a specific language in a alternative array of languages.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the property.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the property.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \param[in] value Pointer to a constant char buffer containing value of the language (xml:lang)
+ //! \param[in] valueLength Number of characters in value. In case value is null terminated set it to \#AdobeXMPCommon::npos.
+ //! \return A shared pointer to const \#IPathSegment.
+ //! \attention Throws #AdobeXMPCommon::pcIError in case
+ //! - pointers to const char buffers are NULL,
+ //! - their content is empty.
+ //!
+ XMP_PRIVATE static spcIPathSegment CreateQualifierSelectorPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name,
+ sizet nameLength, const char * value, sizet valueLength );
+
+
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IPathSegment_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pcIUTF8String_base APICALL getNameSpace( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getName( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual uint32 APICALL getType( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pcIUTF8String_base APICALL getValue( pcIError_base & error ) const __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // __IPathSegment_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ISimpleNode.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ISimpleNode.h
new file mode 100644
index 0000000000..8d154d3469
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/ISimpleNode.h
@@ -0,0 +1,150 @@
+#ifndef __ISimpleNode_h__
+#define __ISimpleNode_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/Interfaces/INode.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! \brief Version1 of the interface that represents a Simple Property Node of XMP DOM.
+ //! \details Provides all the functions to get and set various properties of the simple node.
+ //! \attention Support multi threading through locks but can be enabled/disabled by the client. By default
+ //! every object created does not support multi-threading.
+ //!
+ class XMP_PUBLIC ISimpleNode_v1
+ : public virtual INode_v1
+ {
+ public:
+
+ //!
+ //! @brief Gets the value of the simple property node.
+ //! \return A shared pointer to const AdobeXMPCommon::IUTF8String object containing value string
+ //! of the simple property node.
+ //!
+ virtual spcIUTF8String APICALL GetValue() const = 0;
+
+ //!
+ //! @brief Changes the value string of the simple property node.
+ //! \param[in] value Pointer to a constant char buffer containing value of the simple node.
+ //! \param[in] valueLength Number of characters in value. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \note In case the value is null pointer or its contents are empty than the value is set to empty string.
+ //!
+ virtual void APICALL SetValue( const char * value, sizet valueLength ) = 0;
+
+ //!
+ //! @brief Indicates whether the simple property node is of URI type.
+ //! \return A bool value; true in case the simple node is of URI type, false otherwise.
+ //!
+ virtual bool APICALL IsURIType() const = 0;
+
+ //!
+ //! @brief Controls whether the type of simple property node should be of IsURI type or not.
+ //! \param[in] isURI A bool value controlling the IsURI type of the simple property node
+ //!
+ virtual void APICALL SetURIType( bool isURI ) = 0;
+
+ // Factories to create the simple node
+
+ //!
+ //! @brief Creates a simple property node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the simple node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the simple node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] value Pointer to a constant char buffer containing value of the simple node.
+ //! \param[in] valueLength Number of characters in value. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to a AdobeXMPCore::ISimpleNode object.
+ //! \attention Error is thrown in case
+ //! - nameSpace or name are NULL pointers, or
+ //! - their contents are empty.
+ //! \note In case the value is a null pointer or its contents are empty than the value is set to empty string.
+ //!
+ XMP_PRIVATE static spISimpleNode CreateSimpleNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength,
+ const char * value = NULL, sizet valueLength = AdobeXMPCommon::npos );
+
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to ISimpleNode interface.
+ //!
+ virtual pISimpleNode APICALL GetActualISimpleNode() __NOTHROW__ = 0;
+ XMP_PRIVATE pcISimpleNode GetActualISimpleNode() const __NOTHROW__ {
+ return const_cast< ISimpleNode_v1 * >( this )->GetActualISimpleNode();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to ISimpleNode_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pISimpleNode_I APICALL GetISimpleNode_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcISimpleNode_I GetISimpleNode_I() const __NOTHROW__ {
+ return const_cast< ISimpleNode_v1 * >( this )->GetISimpleNode_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spISimpleNode MakeShared( pISimpleNode_base ptr );
+ XMP_PRIVATE static spcISimpleNode MakeShared( pcISimpleNode_base ptr ) {
+ return MakeShared( const_cast< pISimpleNode_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kISimpleNodeID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~ISimpleNode_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual pcIUTF8String_base APICALL getValue( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual void APICALL setValue( const char * value, sizet valueLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual uint32 APICALL isURIType( pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual void APICALL setURIType( uint32 isURI, pcIError_base & error ) __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+#endif // __ISimpleNode_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IStructureNode.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IStructureNode.h
new file mode 100644
index 0000000000..5df1f08209
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/Interfaces/IStructureNode.h
@@ -0,0 +1,306 @@
+#ifndef IStructureNode_h__
+#define IStructureNode_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/Interfaces/ICompositeNode.h"
+
+namespace AdobeXMPCore {
+
+ //!
+ //! @brief Version1 of the interface that represents a structure Node of XMP DOM.
+ //! \details Provides all the functions to get and set various properties of the structure node.
+ //! \attention Support multi threading through locks but can be enabled/disabled by the client. By default
+ //! every object created does not support multi-threading.
+ //!
+ class XMP_PUBLIC IStructureNode_v1
+ : public virtual ICompositeNode_v1
+ {
+ public:
+
+ //!
+ //! @brief Gets the type of the node's child having specified namespace and name.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the child node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the child node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return An object of type #eNodeType indicating the type of the node's child.
+ //! \note In case no child exists with the specified nameSpace and name combination then an eNodeType::kNTNone is returned.
+ //!
+ virtual eNodeType APICALL GetChildNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const = 0;
+
+
+ //!
+ //! @{
+ //! @brief Gets the child of the node having specified namespace and name.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the child node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the child node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to either a const or const child node.
+ //! \note In case no child exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //!
+ XMP_PRIVATE spcINode GetNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ return const_cast< IStructureNode_v1 * >( this )->GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ }
+ virtual spINode APICALL GetNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) = 0;
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Gets the node's child having specified name space and name as simple node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the child node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the child node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to const or non const ISimpleNode object containing child.
+ //! \note In case no child exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //! \attention Error is thrown in case
+ //! - a child exists with the specified nameSpace and name combination but is not a simple node.
+ //!
+ XMP_PRIVATE spcISimpleNode GetSimpleNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ auto node = GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spcISimpleNode();
+ }
+
+ XMP_PRIVATE spISimpleNode GetSimpleNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ auto node = GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToSimpleNode();
+ return spISimpleNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Gets the node's child having specified name space and name as structure node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the child node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the child node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to const or non const IStructureNode object containing child.
+ //! \note In case no child exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //! \attention Error is thrown in case
+ //! - a child exists with the specified nameSpace and name combination but is not a structure node.
+ //!
+ XMP_PRIVATE spcIStructureNode GetStructureNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ auto node = GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToStructureNode();
+ return spcIStructureNode();
+ }
+
+ XMP_PRIVATE spIStructureNode GetStructureNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ auto node = GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToStructureNode();
+ return spIStructureNode();
+ }
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Gets the node's child having specified name space and name as an array node.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the child node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the child node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to const or non const ISimpleNode object containing child.
+ //! \note In case no child exists with the specified nameSpace and name combination then an invalid shared pointer
+ //! is returned.
+ //! \attention Error is thrown in case
+ //! - a child exists with the specified nameSpace and name combination but is not an array node.
+ //!
+ XMP_PRIVATE spcIArrayNode GetArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ auto node = GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToArrayNode();
+ return spcIArrayNode();
+ }
+
+ XMP_PRIVATE spIArrayNode GetArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ auto node = GetNode( nameSpace, nameSpaceLength, name, nameLength );
+ if ( node ) return node->ConvertToArrayNode();
+ return spIArrayNode();
+ }
+ //! @}
+
+ //!
+ //! @brief Inserts a given node.
+ //! \param[in] node Shared pointer to an object of AdobeXMPCore::INode containing the node to be inserted.
+ //! \attention Error is thrown in following cases:
+ //! -# given node is invalid.
+ //! -# given node is already a child of some other node.
+ //! -# there exists a node with the same nameSpace and name combination.
+ //!
+ virtual void APICALL InsertNode( const spINode & node ) = 0;
+
+ //!
+ //! @brief Replaces a given node.
+ //! \param[in] node Shared pointer to an object of AdobeXMPCore::INode.
+ //! \return A shared pointer to the node being replaced.
+ //! \attention Error is thrown in following cases:
+ //! -# given node is invalid.
+ //! -# given node is already a child of some other node.
+ //! -# there exists no node with the same nameSpace and name combination.
+ //! \note Type of the old existing node may/may not be same as that of new node.
+ //!
+ virtual spINode APICALL ReplaceNode( const spINode & node ) = 0;
+
+ //!
+ //! @brief Removes the node with the specified nameSpace and name.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the child node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the child node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to AdobeXMPCore::INode object containing node which is removed from the tree.
+ //! \note In case no node exists with the given nameSpace and name combination an invalid shared pointer is returned.
+ //!
+ virtual spINode APICALL RemoveNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) = 0;
+
+ //!
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+
+ //!
+ //! @{
+ //! @brief Returns the actual raw pointer from the shared pointer, which can be a shared pointer of a proxy class.
+ //! \return Either a const or non const pointer to IStructureNode interface.
+ //!
+ virtual pIStructureNode APICALL GetActualIStructureNode() __NOTHROW__ = 0;
+ XMP_PRIVATE pcIStructureNode GetActualIStructureNode() const __NOTHROW__ {
+ return const_cast< IStructureNode_v1 * >( this )->GetActualIStructureNode();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Returns the pointer to internal interfaces.
+ //! \return Either a const or non const pointer to IStructureNode_I interface.
+ //!
+ virtual AdobeXMPCore_Int::pIStructureNode_I APICALL GetIStructureNode_I() __NOTHROW__ = 0;
+
+ XMP_PRIVATE AdobeXMPCore_Int::pcIStructureNode_I GetIStructureNode_I() const __NOTHROW__ {
+ return const_cast< IStructureNode_v1 * >( this )->GetIStructureNode_I();
+ }
+ //!
+ //! @}
+
+ //!
+ //! @{
+ //! @brief Converts raw pointer to shared pointer. The raw pointer is of version 1 interface
+ //! where as the returned shared pointer depends on the version client is interested in.
+ //! \return Shared pointer to const or non constant interface.
+ //!
+ XMP_PRIVATE static spIStructureNode MakeShared( pIStructureNode_base ptr );
+ XMP_PRIVATE static spcIStructureNode MakeShared( pcIStructureNode_base ptr ) {
+ return MakeShared( const_cast< pIStructureNode_base >( ptr ) );
+ }
+ //!
+ //! @}
+
+ //!
+ //! @brief Returns the unique ID assigned to the interface.
+ //! \return 64 bit unsigned integer representing the unique ID assigned to the interface.
+ //!
+ XMP_PRIVATE static uint64 GetInterfaceID() { return kIStructureNodeID; }
+
+ //!
+ //! @brief Returns the version of the interface.
+ //! \return 32 bit unsigned integer representing the version of the interface.
+ //!
+ XMP_PRIVATE static uint32 GetInterfaceVersion() { return 1; }
+ //! \endcond
+
+ // Factories to create the structure node
+
+ //!
+ //! @brief Creates a structure node which is not part of any metadata document.
+ //! \param[in] nameSpace Pointer to a constant char buffer containing name space URI of the structure node.
+ //! \param[in] nameSpaceLength Number of characters in nameSpace. In case nameSpace is null terminated set it to AdobeXMPCommon::npos.
+ //! \param[in] name Pointer to a constant char buffer containing local name of the structure node.
+ //! \param[in] nameLength Number of characters in name. In case name is null terminated set it to AdobeXMPCommon::npos.
+ //! \return A shared pointer to a AdobeXMPCore::IStructureNode object.
+ //! \attention Error is thrown in the following cases:
+ //! -# nameSpace is NULL or its contents are empty.
+ //! -# name is NULL or its contents are empty.
+ //!
+ XMP_PRIVATE static spIStructureNode CreateStructureNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ protected:
+ //!
+ //! Destructor
+ //!
+ virtual ~IStructureNode_v1() __NOTHROW__ {}
+
+ //! \cond XMP_INTERNAL_DOCUMENTATION
+ virtual uint32 APICALL getChildNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) const __NOTHROW__ = 0;
+ virtual pINode_base APICALL getNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual void APICALL insertNode( pINode_base node, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL replaceNode( pINode_base node, pcIError_base & error ) __NOTHROW__ = 0;
+ virtual pINode_base APICALL removeNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ = 0;
+
+ #ifdef FRIEND_CLASS_DECLARATION
+ FRIEND_CLASS_DECLARATION();
+ #endif
+ REQ_FRIEND_CLASS_DECLARATION();
+ //! \endcond
+
+ };
+}
+
+//! \cond XMP_INTERNAL_DOCUMENTATION
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class IStructureNodeProxy
+ : public virtual IStructureNode
+ , public virtual ICompositeNodeProxy
+ {
+ private:
+ pIStructureNode mRawPtr;
+
+ public:
+ IStructureNodeProxy( pIStructureNode ptr );
+ ~IStructureNodeProxy() __NOTHROW__ ;
+
+ AdobeXMPCore_Int::pIStructureNode_I APICALL GetIStructureNode_I() __NOTHROW__;
+ virtual pIStructureNode APICALL GetActualIStructureNode() __NOTHROW__;
+
+ virtual eNodeType APICALL GetChildNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const;
+ virtual spINode APICALL GetNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+ virtual void APICALL InsertNode( const spINode & node );
+ virtual spINode APICALL ReplaceNode( const spINode & node );
+ virtual spINode APICALL RemoveNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength );
+
+ protected:
+ virtual uint32 APICALL getChildNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) const __NOTHROW__;
+ virtual pINode_base APICALL getNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__;
+ virtual void APICALL insertNode( pINode_base node, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL replaceNode( pINode_base node, pcIError_base & error ) __NOTHROW__;
+ virtual pINode_base APICALL removeNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__;
+ };
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+}
+
+#endif // BUILDING_XMPCORE_LIB
+//! \endcond
+
+#endif // IStructureNode_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreDefines.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreDefines.h
new file mode 100644
index 0000000000..fbe9af42f0
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreDefines.h
@@ -0,0 +1,86 @@
+#ifndef XMPCoreDefines_h__
+#define XMPCoreDefines_h__ 1
+
+// =================================================================================================
+// Copyright 2014 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.
+// =================================================================================================
+
+// =================================================================================================
+// XMPCoreDefines.h - Common Defines for XMP Core component
+// ================================================================
+//
+// This header defines common definitions to be used in XMP Core component.
+//
+// =================================================================================================
+
+// =================================================================================================
+// All Platform Settings
+// ===========================
+#include "XMPCommon/XMPCommonDefines.h"
+
+#ifndef ENABLE_CPP_DOM_MODEL
+// =================================================================================================
+// Macintosh Specific Settings
+// ===========================
+#if XMP_MacBuild
+ #define ENABLE_CPP_DOM_MODEL 0
+#endif
+
+// =================================================================================================
+// IOS Specific Settings
+// ===========================
+#if XMP_iOSBuild
+ #define ENABLE_CPP_DOM_MODEL 0
+#endif
+
+// =================================================================================================
+// Windows Specific Settings
+// =========================
+#if XMP_WinBuild
+ #define ENABLE_CPP_DOM_MODEL 0
+#endif
+
+// =================================================================================================
+// UNIX Specific Settings
+// ======================
+#if XMP_UNIXBuild
+#define ENABLE_CPP_DOM_MODEL 0
+#endif
+#endif // ENABLE_CPP_DOM_MODEL
+
+#ifndef ENABLE_CPP_DOM_MODEL
+ #define ENABLE_CPP_DOM_MODEL 0
+#endif
+
+#if ENABLE_CPP_DOM_MODEL
+
+ #if SOURCE_COMPILING_XMP_ALL
+ #define SOURCE_COMPILING_XMPCORE_LIB 1
+ #endif
+
+ #ifndef SOURCE_COMPILING_XMPCORE_LIB
+ #define SOURCE_COMPILING_XMPCORE_LIB 0
+ #endif
+
+ #ifndef BUILDING_XMPCORE_LIB
+ #define BUILDING_XMPCORE_LIB 0
+ #endif
+
+ #if BUILDING_XMPCORE_LIB
+ #if !BUILDING_XMPCORE_AS_STATIC && !BUILDING_XMPCORE_AS_DYNAMIC
+ #error "Define either BUILDING_XMPCORE_AS_STATIC as 1 or BUILDING_XMPCORE_AS_DYNAMIC as 1"
+ #endif
+ #endif
+
+ #ifndef LINKING_XMPCORE_LIB
+ #define LINKING_XMPCORE_LIB 1
+ #endif
+
+ namespace AdobeXMPCore {};
+#endif // ENABLE_CPP_DOM_MODEL
+
+#endif // XMPCoreDefines_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreErrorCodes.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreErrorCodes.h
new file mode 100644
index 0000000000..63c2f5570a
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreErrorCodes.h
@@ -0,0 +1,116 @@
+#ifndef XMPCoreErrorCodes_h__
+#define XMPCoreErrorCodes_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/XMPCoreDefines.h"
+#include "XMPCommon/XMPCommonErrorCodes.h"
+
+namespace AdobeXMPCore {
+
+ typedef enum {
+ //! Indicates no error.
+ kDMECNone = 0,
+
+ //! Indicates that IXMPNameSpacePrefixMap has an entry missing.
+ kDMECNameSpacePrefixMapEntryMissing = 1,
+
+ //! Indicates that a different type of node is present than one user is expecting
+ kDMECDifferentNodeTypePresent = 2,
+
+ //! Indicates that node is already a child of another parent.
+ kDMECNodeAlreadyAChild = 3,
+
+ //! Indicates a node with the same qualified name or index already exists.
+ kDMECNodeAlreadyExists = 4,
+
+ //! Indicates no such node exists.
+ kDMECNoSuchNodeExists = 5,
+
+ //! Indicates current array element type is not same as that of other child items
+ kDMECArrayItemTypeDifferent = 6,
+
+ //! Indicates invalid path segment inside a path.
+ kDMECInvalidPathSegment = 7,
+
+ //! Indicates Bad schema parameter
+ kDMECBadSchema = 101,
+
+ //! Indicates Bad XPath parameter
+ kDMECBadXPath = 102,
+
+ //! Indicates Bad options parameter
+ kDMECBadOptions = 103,
+
+ //! Indicates Bad iteration position
+ kDMECBadIterPosition = 104,
+
+ //! Indicates Unicode error
+ kDMECBadUnicode = 105,
+
+ //! Indicates XMP format error
+ kDMECValidationError = 106,
+
+ //! Indicates Empty iterator
+ kDMECEmptyIterator = 107,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kDMECMaxValue = kMaxEnumValue
+ } eDataModelErrorCode;
+
+ //!
+ //! @brief Indicates various errors encountered during parsing.
+ //!
+ typedef enum {
+ //! Indicates no error.
+ kPECNone = 0,
+
+ //! Indicates XML parsing error.
+ kPECBadXML = 1,
+
+ //! RDF format error
+ kPECBadRDF = 2,
+
+ //! XMP format error
+ kPECBadXMP = 3,
+
+ //! Context Node is invalid
+ kPECInvalidContextNode = 4,
+
+ //! Context Node is not a composite node
+ kPECContextNodeIsNonComposite = 5,
+
+ //! Parent of Context Node is not an array node
+ kPECContextNodeParentIsNonArray = 6,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kPECMaxValue = kMaxEnumValue
+ } eParserErrorCode;
+
+ //!
+ //! @brief Indicates various errors encountered during serialization.
+ //!
+ typedef enum {
+ //! Indicates no error.
+ kSECNone = 0,
+
+ //! Indicates serialization failed to achieve size requirement.
+ kSECSizeExceed = 1,
+
+ //! Indicates un registered namespace encountered during serialization.
+ kSECUnRegisteredNameSpace = 2,
+
+ //! Maximum value this enum can hold, should be treated as invalid value.
+ kSECMaxValue = kMaxEnumValue
+
+ } eSerializerErrorCode;
+}
+
+#endif // XMPCoreErrorCodes_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreFwdDeclarations.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreFwdDeclarations.h
new file mode 100644
index 0000000000..65a38cc465
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreFwdDeclarations.h
@@ -0,0 +1,308 @@
+#ifndef XMPCoreFwdDeclarations_h__
+#define XMPCoreFwdDeclarations_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2014 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 "XMPCore/XMPCoreDefines.h"
+#include "XMPCommon/XMPCommonFwdDeclarations.h"
+#include "XMPCore/XMPCoreLatestInterfaceVersions.h"
+
+namespace AdobeXMPCore {
+ using namespace AdobeXMPCommon;
+
+ // INameSpacePrefixMap
+ class INameSpacePrefixMap_v1;
+ typedef INameSpacePrefixMap_v1 INameSpacePrefixMap_base;
+ typedef INameSpacePrefixMap_v1 * pINameSpacePrefixMap_base;
+ typedef const INameSpacePrefixMap_v1 * pcINameSpacePrefixMap_base;
+ typedef BASE_CLASS( INameSpacePrefixMap, INAMESPACEPREFIXMAP_VERSION ) INameSpacePrefixMap;
+ typedef INameSpacePrefixMap * pINameSpacePrefixMap;
+ typedef const INameSpacePrefixMap * pcINameSpacePrefixMap;
+ typedef shared_ptr< INameSpacePrefixMap > spINameSpacePrefixMap;
+ typedef shared_ptr< const INameSpacePrefixMap > spcINameSpacePrefixMap;
+ static const uint64 kINameSpacePrefixMapID ( 0x634e5350724d6170 /* cNSPrMap */ );
+
+ // IPathSegment
+ class IPathSegment_v1;
+ typedef IPathSegment_v1 IPathSegment_base;
+ typedef IPathSegment_v1 * pIPathSegment_base;
+ typedef const IPathSegment_v1 * pcIPathSegment_base;
+ typedef BASE_CLASS( IPathSegment, IPATHSEGMENT_VERSION ) IPathSegment;
+ typedef IPathSegment * pIPathSegment;
+ typedef const IPathSegment * pcIPathSegment;
+ typedef shared_ptr< IPathSegment > spIPathSegment;
+ typedef shared_ptr< const IPathSegment > spcIPathSegment;
+ static const uint64 kIPathSegmentID ( 0x6350617468536567 /* cPathSeg */ );
+
+ // IPath
+ class IPath_v1;
+ typedef IPath_v1 IPath_base;
+ typedef IPath_v1 * pIPath_base;
+ typedef const IPath_v1 * pcIPath_base;
+ typedef BASE_CLASS( IPath, IPATH_VERSION ) IPath;
+ typedef IPath * pIPath;
+ typedef const IPath * pcIPath;
+ typedef shared_ptr< IPath > spIPath;
+ typedef shared_ptr< const IPath > spcIPath;
+ static const uint64 kIPathID ( 0x6350617468202020 /* cPath */ );
+
+ // INode
+ class INode_v1;
+ typedef INode_v1 INode_base;
+ typedef INode_v1 * pINode_base;
+ typedef const INode_v1 * pcINode_base;
+ typedef BASE_CLASS( INode, INODE_VERSION ) INode;
+ typedef INode * pINode;
+ typedef const INode * pcINode;
+ typedef shared_ptr< INode > spINode;
+ typedef shared_ptr< const INode > spcINode;
+ static const uint64 kINodeID ( 0x634e6f6465202020 /* cNode */ );
+
+ // ISimpleNode
+ class ISimpleNode_v1;
+ typedef ISimpleNode_v1 ISimpleNode_base;
+ typedef ISimpleNode_v1 * pISimpleNode_base;
+ typedef const ISimpleNode_v1 * pcISimpleNode_base;
+ typedef BASE_CLASS( ISimpleNode, ISIMPLENODE_VERSION ) ISimpleNode;
+ typedef ISimpleNode * pISimpleNode;
+ typedef const ISimpleNode * pcISimpleNode;
+ typedef shared_ptr< ISimpleNode > spISimpleNode;
+ typedef shared_ptr< const ISimpleNode > spcISimpleNode;
+ static const uint64 kISimpleNodeID ( 0x63536d6c4e6f6465 /* cSmlNode */ );
+
+ // ICompositeNode
+ class ICompositeNode_v1;
+ typedef ICompositeNode_v1 ICompositeNode_base;
+ typedef ICompositeNode_v1 * pICompositeNode_base;
+ typedef const ICompositeNode_v1 * pcICompositeNode_base;
+ typedef BASE_CLASS( ICompositeNode, ICOMPOSITENODE_VERSION ) ICompositeNode;
+ typedef ICompositeNode * pICompositeNode;
+ typedef const ICompositeNode * pcICompositeNode;
+ typedef shared_ptr< ICompositeNode > spICompositeNode;
+ typedef shared_ptr< const ICompositeNode > spcICompositeNode;
+ static const uint64 kICompositeNodeID ( 0x63436d704e6f6465 /* cCmpNode */ );
+
+ // IStructureNode
+ class IStructureNode_v1;
+ typedef IStructureNode_v1 IStructureNode_base;
+ typedef IStructureNode_v1 * pIStructureNode_base;
+ typedef const IStructureNode_v1 * pcIStructureNode_base;
+ typedef BASE_CLASS( IStructureNode, ISTRUCTURENODE_VERSION ) IStructureNode;
+ typedef IStructureNode * pIStructureNode;
+ typedef const IStructureNode * pcIStructureNode;
+ typedef shared_ptr< IStructureNode > spIStructureNode;
+ typedef shared_ptr< const IStructureNode > spcIStructureNode;
+ static const uint64 kIStructureNodeID ( 0x635374724e6f6465 /* cStrNode */ );
+
+ // IArrayNode
+ class IArrayNode_v1;
+ typedef IArrayNode_v1 IArrayNode_base;
+ typedef IArrayNode_v1 * pIArrayNode_base;
+ typedef const IArrayNode_v1 * pcIArrayNode_base;
+ typedef BASE_CLASS( IArrayNode, IARRAYNODE_VERSION ) IArrayNode;
+ typedef IArrayNode * pIArrayNode;
+ typedef const IArrayNode * pcIArrayNode;
+ typedef shared_ptr< IArrayNode > spIArrayNode;
+ typedef shared_ptr< const IArrayNode > spcIArrayNode;
+ static const uint64 kIArrayNodeID ( 0x634172724e6f6465 /* cArrNode */ );
+
+ // INodeIterator
+ class INodeIterator_v1;
+ typedef INodeIterator_v1 INodeIterator_base;
+ typedef INodeIterator_v1 * pINodeIterator_base;
+ typedef const INodeIterator_v1 * pcINodeIterator_base;
+ typedef BASE_CLASS(INodeIterator, INODEITERATOR_VERSION) INodeIterator;
+ typedef INodeIterator * pINodeIterator;
+ typedef const INodeIterator * pcINodeIterator;
+ typedef shared_ptr< INodeIterator > spINodeIterator;
+ typedef shared_ptr< const INodeIterator > spcINodeIterator;
+ static const uint64 kINodeIteratorID (0x634e6f6465497420 /* cNodeIt */);
+
+ // IMetadata
+ class IMetadata_v1;
+ typedef IMetadata_v1 IMetadata_base;
+ typedef IMetadata_v1 * pIMetadata_base;
+ typedef const IMetadata_v1 * pcIMetadata_base;
+ typedef BASE_CLASS( IMetadata, IMETADATA_VERSION ) IMetadata;
+ typedef IMetadata * pIMetadata;
+ typedef const IMetadata * pcIMetadata;
+ typedef shared_ptr< IMetadata > spIMetadata;
+ typedef shared_ptr< const IMetadata > spcIMetadata;
+ static const uint64 kIMetadataID ( 0x634d657461646174 /* cMetadat */ );
+
+ // IClientDOMParser
+ class IClientDOMParser_v1;
+ typedef IClientDOMParser_v1 IClientDOMParser_base;
+ typedef IClientDOMParser_v1 * pIClientDOMParser_base;
+ typedef const IClientDOMParser_v1 * pcIClientDOMParser_base;
+ typedef BASE_CLASS( IClientDOMParser, ICLIENTDOMPARSER_VERSION ) IClientDOMParser;
+ typedef IClientDOMParser * pIClientDOMParser;
+ typedef const IClientDOMParser * pcIClientDOMParser;
+
+ // IClientDOMSerializer
+ class IClientDOMSerializer_v1;
+ typedef IClientDOMSerializer_v1 IClientDOMSerializer_base;
+ typedef IClientDOMSerializer_v1 * pIClientDOMSerializer_base;
+ typedef const IClientDOMSerializer_v1 * pcIClientDOMSerializer_base;
+ typedef BASE_CLASS( IClientDOMSerializer, ICLIENTDOMSERIALIZER_VERSION ) IClientDOMSerializer;
+ typedef IClientDOMSerializer * pIClientDOMSerializer;
+ typedef const IClientDOMSerializer * pcIClientDOMSerializer;
+
+ // IDOMParser
+ class IDOMParser_v1;
+ typedef IDOMParser_v1 IDOMParser_base;
+ typedef IDOMParser_v1 * pIDOMParser_base;
+ typedef const IDOMParser_v1 * pcIDOMParser_base;
+ typedef BASE_CLASS( IDOMParser, IDOMPARSER_VERSION ) IDOMParser;
+ typedef IDOMParser * pIDOMParser;
+ typedef const IDOMParser * pcIDOMParser;
+ typedef shared_ptr< IDOMParser > spIDOMParser;
+ typedef shared_ptr< const IDOMParser > spcIDOMParser;
+ static const uint64 kIDOMParserID ( 0x63444f4d50727372 /* cDOMPrsr */ );
+
+ // IDOMSerializer
+ class IDOMSerializer_v1;
+ typedef IDOMSerializer_v1 IDOMSerializer_base;
+ typedef IDOMSerializer_v1 * pIDOMSerializer_base;
+ typedef const IDOMSerializer_v1 * pcIDOMSerializer_base;
+ typedef BASE_CLASS( IDOMSerializer, IDOMSERIALIZER_VERSION ) IDOMSerializer;
+ typedef IDOMSerializer * pIDOMSerializer;
+ typedef const IDOMSerializer * pcIDOMSerializer;
+ typedef shared_ptr< IDOMSerializer > spIDOMSerializer;
+ typedef shared_ptr< const IDOMSerializer > spcIDOMSerializer;
+ static const uint64 kIDOMSerializerID ( 0x63444f4d53726c7a /* cDOMSrlz */ );
+
+ // IDOMImplementationRegistry
+ class IDOMImplementationRegistry_v1;
+ typedef IDOMImplementationRegistry_v1 IDOMImplementationRegistry_base;
+ typedef IDOMImplementationRegistry_v1 * pIDOMImplementationRegistry_base;
+ typedef const IDOMImplementationRegistry_v1 * pcIDOMImplementationRegistry_base;
+ typedef BASE_CLASS( IDOMImplementationRegistry, IDOMIMPLEMENTATIONREGISTRY_VERSION) IDOMImplementationRegistry;
+ typedef IDOMImplementationRegistry * pIDOMImplementationRegistry;
+ typedef const IDOMImplementationRegistry * pcIDOMImplementationRegistry;
+ typedef shared_ptr< IDOMImplementationRegistry > spIDOMImplementationRegistry;
+ typedef shared_ptr< const IDOMImplementationRegistry > spcIDOMImplementationRegistry;
+ static const uint64 kIDOMImplementationRegistryID ( 0x63444f4d52677374 /* cDOMRgst */ );
+
+ // ICoreObjectFactory
+ class ICoreObjectFactory_v1;
+ typedef ICoreObjectFactory_v1 ICoreObjectFactory_base;
+ typedef ICoreObjectFactory_v1 * pICoreObjectFactory_base;
+ typedef const ICoreObjectFactory_v1 * pcICoreObjectFactory_base;
+ typedef BASE_CLASS( ICoreObjectFactory, ICOREOBJECTFACTORY_VERSION ) ICoreObjectFactory;
+ typedef ICoreObjectFactory * pICoreObjectFactory;
+ typedef const ICoreObjectFactory * pcICoreObjectFactory;
+ static const uint64 kICoreObjectFactoryID ( 0x634f626a46616374 /* cObjFact */ );
+
+ // ICoreConfigurationManager
+ class ICoreConfigurationManager_v1;
+ typedef ICoreConfigurationManager_v1 ICoreConfigurationManager_base;
+ typedef ICoreConfigurationManager_v1 * pICoreConfigurationManager_base;
+ typedef const ICoreConfigurationManager_v1 * pcICoreConfigurationManager_base;
+ typedef BASE_CLASS( ICoreConfigurationManager, ICORECONFIGURATIONMANAGER_VERSION ) ICoreConfigurationManager;
+ typedef ICoreConfigurationManager * pICoreConfigurationManager;
+ typedef const ICoreConfigurationManager * pcICoreConfigurationManager;
+ typedef shared_ptr< ICoreConfigurationManager > spICoreConfigurationManager;
+ typedef shared_ptr< const ICoreConfigurationManager > spcICoreConfigurationManager;
+ static const uint64 kICoreConfigurationManagerID ( 0x63436f6e664d6772 /* cConfMgr */ );
+
+}
+
+namespace AdobeXMPCore_Int {
+
+ // INameSpacePrefixMap_I
+ class INameSpacePrefixMap_I;
+ typedef INameSpacePrefixMap_I * pINameSpacePrefixMap_I;
+ typedef const INameSpacePrefixMap_I * pcINameSpacePrefixMap_I;
+
+ // IPathSegment_I
+ class IPathSegment_I;
+ typedef IPathSegment_I * pIPathSegment_I;
+ typedef const IPathSegment_I * pcIPathSegment_I;
+
+ // IPath_I
+ class IPath_I;
+ typedef IPath_I * pIPath_I;
+ typedef const IPath_I * pcIPath_I;
+
+ // INode_I
+ class INode_I;
+ typedef INode_I * pINode_I;
+ typedef const INode_I * pcINode_I;
+
+ // ISimpleNode_I
+ class ISimpleNode_I;
+ typedef ISimpleNode_I * pISimpleNode_I;
+ typedef const ISimpleNode_I * pcISimpleNode_I;
+
+ // ICompositeNode_I
+ class ICompositeNode_I;
+ typedef ICompositeNode_I * pICompositeNode_I;
+ typedef const ICompositeNode_I * pcICompositeNode_I;
+
+ // IStructureNode_I
+ class IStructureNode_I;
+ typedef IStructureNode_I * pIStructureNode_I;
+ typedef const IStructureNode_I * pcIStructureNode_I;
+
+ // IArrayNode_I
+ class IArrayNode_I;
+ typedef IArrayNode_I * pIArrayNode_I;
+ typedef const IArrayNode_I * pcIArrayNode_I;
+
+ // INodeIterator_I
+ class INodeIterator_I;
+ typedef INodeIterator_I * pINodeIterator_I;
+ typedef const INodeIterator_I * pcINodeIterator_I;
+
+ // IMetadata_I
+ class IMetadata_I;
+ typedef IMetadata_I * pIMetadata_I;
+ typedef const IMetadata_I * pcIMetadata_I;
+
+ // IClientDOMParser_I
+ class IClientDOMParser_I;
+ typedef IClientDOMParser_I * pIClientDOMParser_I;
+ typedef const IClientDOMParser_I * pcIClientDOMParser_I;
+
+ // IClientDOMSerializer_I
+ class IClientDOMSerializer_I;
+ typedef IClientDOMSerializer_I * pIClientDOMSerializer_I;
+ typedef const IClientDOMSerializer_I * pcIClientDOMSerializer_I;
+
+ // IDOMParser_I
+ class IDOMParser_I;
+ typedef IDOMParser_I * pIDOMParser_I;
+ typedef const IDOMParser_I * pcIDOMParser_I;
+
+ // IDOMSerializer_I
+ class IDOMSerializer_I;
+ typedef IDOMSerializer_I * pIDOMSerializer_I;
+ typedef const IDOMSerializer_I * pcIDOMSerializer_I;
+
+ // IDOMImplementationRegistry_I
+ class IDOMImplementationRegistry_I;
+ typedef IDOMImplementationRegistry_I * pIDOMImplementationRegistry_I;
+ typedef const IDOMImplementationRegistry_I * pcIDOMImplementationRegistry_I;
+
+ // ICoreObjectFactory_I
+ class ICoreObjectFactory_I;
+ typedef ICoreObjectFactory_I * pICoreObjectFactory_I;
+ typedef const ICoreObjectFactory_I * pcICoreObjectFactory_I;
+
+ // ICoreConfigurationManager_I
+ class ICoreConfigurationManager_I;
+ typedef ICoreConfigurationManager_I * pICoreConfigurationManager_I;
+ typedef const ICoreConfigurationManager_I * pcICoreConfigurationManager_I;
+}
+
+#endif // XMPCoreFwdDeclarations_h__
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreLatestInterfaceVersions.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreLatestInterfaceVersions.h
new file mode 100644
index 0000000000..b5b54bfde3
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/XMPCoreLatestInterfaceVersions.h
@@ -0,0 +1,92 @@
+#ifndef XMPCoreLatestInterfaceVersions_h__
+#define XMPCoreLatestInterfaceVersions_h__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+//!
+//! @brief Macro to include a client file through with client can control the interface versions he wants to stick with
+//! if not the latest ones.
+//!
+#if !SOURCE_COMPILING_XMPCORE_LIB
+ #ifdef XMPCORE_CLIENT_VERSION_NUMBER_FILE
+ #include QUOTEME(XMPCORE_CLIENT_VERSION_NUMBER_FILE)
+ #endif
+#endif
+
+#ifndef INAMESPACEPREFIXMAP_VERSION
+ #define INAMESPACEPREFIXMAP_VERSION 1
+#endif
+
+#ifndef IPATHSEGMENT_VERSION
+ #define IPATHSEGMENT_VERSION 1
+#endif
+
+#ifndef IPATH_VERSION
+ #define IPATH_VERSION 1
+#endif
+
+#ifndef INODE_VERSION
+ #define INODE_VERSION 1
+#endif
+
+#ifndef INODEITERATOR_VERSION
+ #define INODEITERATOR_VERSION 1
+#endif
+
+#ifndef ISIMPLENODE_VERSION
+ #define ISIMPLENODE_VERSION 1
+#endif
+
+#ifndef ICOMPOSITENODE_VERSION
+ #define ICOMPOSITENODE_VERSION 1
+#endif
+
+#ifndef ISTRUCTURENODE_VERSION
+ #define ISTRUCTURENODE_VERSION 1
+#endif
+
+#ifndef IARRAYNODE_VERSION
+ #define IARRAYNODE_VERSION 1
+#endif
+
+#ifndef IMETADATA_VERSION
+ #define IMETADATA_VERSION 1
+#endif
+
+#ifndef ICLIENTDOMPARSER_VERSION
+ #define ICLIENTDOMPARSER_VERSION 1
+#endif
+
+#ifndef ICLIENTDOMSERIALIZER_VERSION
+ #define ICLIENTDOMSERIALIZER_VERSION 1
+#endif
+
+#ifndef IDOMPARSER_VERSION
+ #define IDOMPARSER_VERSION 1
+#endif
+
+#ifndef IDOMSERIALIZER_VERSION
+ #define IDOMSERIALIZER_VERSION 1
+#endif
+
+#ifndef IDOMIMPLEMENTATIONREGISTRY_VERSION
+ #define IDOMIMPLEMENTATIONREGISTRY_VERSION 1
+#endif
+
+#ifndef ICOREOBJECTFACTORY_VERSION
+ #define ICOREOBJECTFACTORY_VERSION 1
+#endif
+
+#ifndef ICORECONFIGURATIONMANAGER_VERSION
+ #define ICORECONFIGURATIONMANAGER_VERSION 1
+#endif
+
+#endif // XMPCoreLatestInterfaceVersions_h__
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IArrayNode.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IArrayNode.cpp
new file mode 100644
index 0000000000..12fd0da5b6
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IArrayNode.cpp
@@ -0,0 +1,163 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IArrayNodeProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IArrayNodeProxy;
+
+#include "XMPCore/Interfaces/IArrayNode.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class IArrayNodeProxy
+ : public virtual IArrayNode
+ , public virtual ICompositeNodeProxy
+ {
+ private:
+ pIArrayNode mRawPtr;
+
+ public:
+ IArrayNodeProxy( pIArrayNode ptr )
+ : mRawPtr( ptr )
+ , ICompositeNodeProxy( ptr )
+ , INodeProxy( ptr ) {}
+
+ ~IArrayNodeProxy() __NOTHROW__ {}
+
+ pIArrayNode APICALL GetActualIArrayNode() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIArrayNode_I APICALL GetIArrayNode_I() __NOTHROW__ {
+ return mRawPtr->GetIArrayNode_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual eArrayForm APICALL GetArrayForm() const {
+ return CallConstSafeFunction< IArrayNode_v1, eArrayForm, uint32 >(
+ mRawPtr, &IArrayNode_v1::getArrayForm );
+ }
+
+ virtual eNodeType APICALL GetChildNodeType() const {
+ return CallConstSafeFunction< IArrayNode_v1, eNodeType, uint32 >(
+ mRawPtr, &IArrayNode_v1::getChildNodeType );
+ }
+
+ virtual spINode APICALL GetNodeAtIndex( sizet index ) {
+ return CallSafeFunctionReturningPointer< IArrayNode_v1, pINode_base, INode, sizet >(
+ mRawPtr, &IArrayNode_v1::getNodeAtIndex, index );
+ }
+
+ virtual void APICALL InsertNodeAtIndex( const spINode & node, sizet index ) {
+ return CallSafeFunctionReturningVoid< IArrayNode_v1, pINode_base, sizet >(
+ mRawPtr, &IArrayNode_v1::insertNodeAtIndex, node ? node->GetActualINode() : NULL, index );
+ }
+
+ virtual spINode APICALL RemoveNodeAtIndex( sizet index ) {
+ return CallSafeFunctionReturningPointer< IArrayNode_v1, pINode_base, INode, sizet >(
+ mRawPtr, &IArrayNode_v1::removeNodeAtIndex, index );
+ }
+
+ virtual spINode APICALL ReplaceNodeAtIndex( const spINode & node, sizet index ) {
+ return CallSafeFunctionReturningPointer< IArrayNode_v1, pINode_base, INode, pINode_base, sizet >(
+ mRawPtr, &IArrayNode_v1::replaceNodeAtIndex, node ? node->GetActualINode() :NULL, index );
+ }
+
+ virtual uint32 APICALL getArrayForm( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getArrayForm( error );
+ }
+
+ virtual pINode_base APICALL getNodeAtIndex( sizet index, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNodeAtIndex( index, error );
+ }
+
+ virtual void APICALL insertNodeAtIndex( pINode_base node, sizet index, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->insertNodeAtIndex( node, index, error );
+ }
+
+ virtual pINode_base APICALL removeNodeAtIndex( sizet index, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->removeNodeAtIndex( index, error );
+ }
+
+ virtual pINode_base APICALL replaceNodeAtIndex( pINode_base node, sizet index, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->replaceNodeAtIndex( node, index, error );
+ }
+
+ virtual uint32 APICALL getChildNodeType( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getChildNodeType( error );
+ }
+
+ };
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+ spIArrayNode IArrayNode_v1::MakeShared( pIArrayNode_base ptr ) {
+ if ( !ptr ) return spIArrayNode();
+ pIArrayNode p = IArrayNode::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IArrayNode >() : ptr;
+ return shared_ptr< IArrayNode >( new IArrayNodeProxy( p ) );
+ }
+
+ spIArrayNode IArrayNode_v1::CreateUnorderedArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIArrayNode_base, IArrayNode, uint32, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateArrayNode, static_cast< uint32 >( IArrayNode::kAFUnordered ),
+ nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ spIArrayNode IArrayNode_v1::CreateOrderedArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIArrayNode_base, IArrayNode, uint32, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateArrayNode, static_cast< uint32 >( IArrayNode::kAFOrdered ),
+ nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ spIArrayNode IArrayNode_v1::CreateAlternativeArrayNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIArrayNode_base, IArrayNode, uint32, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateArrayNode, static_cast< uint32 >( IArrayNode::kAFAlternative ),
+ nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IClientDOMParser.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IClientDOMParser.cpp
new file mode 100644
index 0000000000..c4767826b5
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IClientDOMParser.cpp
@@ -0,0 +1,76 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/Interfaces/IClientDOMParser.h"
+#include "XMPCore/Interfaces/INode.h"
+
+#if 1//!BUILDING_XMPCORE_LIB
+namespace AdobeXMPCore {
+
+ pINode_base APICALL IClientDOMParser_v1::parse( const char * buffer, sizet bufferLength, pcIConfigurable configurationParameters, ReportErrorAndContinueABISafeProc proc, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ auto node = Parse( buffer, bufferLength, configurationParameters, proc );
+ if ( node ) {
+ node->Acquire();
+ return node->GetActualINode();
+ }
+ return NULL;
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ return NULL;
+ }
+
+ uint32 APICALL IClientDOMParser_v1::areKeysCaseSensitive( pcIError_base & error, uint32 & unknownExceptionCaught ) const __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ return AreKeysCaseSensitive() ? 1 : 0;
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ return 0;
+ }
+
+ void APICALL IClientDOMParser_v1::initialize( pIConfigurable configurationParameters, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ Initialize( configurationParameters );
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ }
+
+ uint32 APICALL IClientDOMParser_v1::validate( const uint64 & key, uint32 dataType, const IConfigurable::CombinedDataValue & dataValue, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ return static_cast< uint32 >( Validate( key, static_cast< IConfigurable::eDataType >( dataType ), dataValue ) );
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ return 0;
+ }
+}
+#endif // !BUILDING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IClientDOMSerializer.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IClientDOMSerializer.cpp
new file mode 100644
index 0000000000..f1f9f52614
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IClientDOMSerializer.cpp
@@ -0,0 +1,73 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/Interfaces/IClientDOMSerializer.h"
+#include "XMPCore/Interfaces/INode.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap.h"
+
+#if !BUILDING_XMPCORE_LIB
+namespace AdobeXMPCore {
+
+ void APICALL IClientDOMSerializer_v1::serialize( pINode_base node, pcINameSpacePrefixMap_base map, pcIConfigurable configurationParameters, ReportErrorAndContinueABISafeProc proc, pIUTF8String_base string, pcIError_base & error, uint32 & unknownErrorThrown ) __NOTHROW__ {
+ unknownErrorThrown = 0;
+ error = NULL;
+ try {
+ Serialize( INode::MakeShared( node ), INameSpacePrefixMap::MakeShared( map ), configurationParameters, proc, IUTF8String::MakeShared( string ) );
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownErrorThrown = 1;
+ }
+ }
+
+ uint32 APICALL IClientDOMSerializer_v1::areKeysCaseSensitive( pcIError_base & error, uint32 & unknownExceptionCaught ) const __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ return AreKeysCaseSensitive() ? 1 : 0;
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ return 0;
+ }
+
+ void APICALL IClientDOMSerializer_v1::initialize( pIConfigurable configurationParameters, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ Initialize( configurationParameters );
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ }
+
+ uint32 APICALL IClientDOMSerializer_v1::validate( const uint64 & key, uint32 dataType, const IConfigurable::CombinedDataValue & dataValue, pcIError_base & error, uint32 & unknownExceptionCaught ) __NOTHROW__ {
+ unknownExceptionCaught = 0;
+ error = NULL;
+ try {
+ return static_cast< uint32 >( Validate( key, static_cast< IConfigurable::eDataType >( dataType ), dataValue ) );
+ } catch ( spcIError err ) {
+ error = err->GetActualIError();
+ error->Acquire();
+ } catch ( ... ) {
+ unknownExceptionCaught = 1;
+ }
+ return 0;
+ }
+
+}
+#endif // !BUILDING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICompositeNode.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICompositeNode.cpp
new file mode 100644
index 0000000000..603501b0fc
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICompositeNode.cpp
@@ -0,0 +1,121 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class ICompositeNodeProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::ICompositeNodeProxy;
+
+#include "XMPCore/Interfaces/ICompositeNode.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include <assert.h>
+#include "XMPCore/Interfaces/IPath.h"
+#include "XMPCore/Interfaces/INodeIterator.h"
+
+namespace AdobeXMPCore {
+ ICompositeNodeProxy::ICompositeNodeProxy( pICompositeNode ptr )
+ : mRawPtr( ptr )
+ , INodeProxy( ptr ) {}
+
+ ICompositeNodeProxy::~ICompositeNodeProxy() __NOTHROW__ {}
+
+ pICompositeNode APICALL ICompositeNodeProxy::GetActualICompositeNode() __NOTHROW__ { return mRawPtr; }
+
+ AdobeXMPCore_Int::pICompositeNode_I APICALL ICompositeNodeProxy::GetICompositeNode_I() __NOTHROW__ {
+ return mRawPtr->GetICompositeNode_I();
+ }
+
+ INode_v1::eNodeType APICALL ICompositeNodeProxy::GetNodeTypeAtPath( const spcIPath & path ) const {
+ return CallConstSafeFunction< ICompositeNode_v1, eNodeType, uint32, pcIPath_base >(
+ mRawPtr, &ICompositeNode_v1::getNodeTypeAtPath, path ? path->GetActualIPath() : NULL );
+ }
+
+ spINode APICALL ICompositeNodeProxy::GetNodeAtPath( const spcIPath & path ) {
+ return CallSafeFunctionReturningPointer< ICompositeNode_v1, pINode_base, INode, pcIPath_base >(
+ mRawPtr, &ICompositeNode_v1::getNodeAtPath, path ? path->GetActualIPath() : NULL );
+ }
+
+ void APICALL ICompositeNodeProxy::AppendNode( const spINode & node ) {
+ return CallSafeFunctionReturningVoid< ICompositeNode_v1, pINode_base >(
+ mRawPtr, &ICompositeNode_v1::appendNode, node ? node->GetActualINode() : NULL );
+ }
+
+ void APICALL ICompositeNodeProxy::InsertNodeAtPath( const spINode & node, const spcIPath & path ) {
+ return CallSafeFunctionReturningVoid< ICompositeNode_v1, pINode_base, pcIPath_base >(
+ mRawPtr, &ICompositeNode_v1::insertNodeAtPath, node ? node->GetActualINode() : NULL, path ? path->GetActualIPath() : NULL );
+ }
+
+ spINode APICALL ICompositeNodeProxy::ReplaceNodeAtPath( const spINode & node, const spcIPath & path ) {
+ return CallSafeFunctionReturningPointer< ICompositeNode_v1, pINode_base, INode, pINode_base, pcIPath_base >(
+ mRawPtr, &ICompositeNode_v1::replaceNodeAtPath, node ? node->GetActualINode() : NULL, path ? path->GetActualIPath() : NULL );
+ }
+
+ spINode APICALL ICompositeNodeProxy::RemoveNodeAtPath( const spcIPath & path ) {
+ return CallSafeFunctionReturningPointer< ICompositeNode_v1, pINode_base, INode, pcIPath_base >(
+ mRawPtr, &ICompositeNode_v1::removeNodeAtPath, path ? path->GetActualIPath() : NULL );
+ }
+
+ spINodeIterator APICALL ICompositeNodeProxy::Iterator() {
+ return CallSafeFunctionReturningPointer< ICompositeNode_v1, pINodeIterator_base, INodeIterator >(
+ mRawPtr, &ICompositeNode_v1::iterator );
+ }
+
+ sizet APICALL ICompositeNodeProxy::ChildCount() const __NOTHROW__ {
+ return mRawPtr->ChildCount();
+ }
+
+ uint32 APICALL ICompositeNodeProxy::getNodeTypeAtPath( pcIPath_base path, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNodeTypeAtPath( path, error );
+ }
+
+ pINode_base APICALL ICompositeNodeProxy::getNodeAtPath( pcIPath_base path, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNodeAtPath( path, error );
+ }
+
+ void APICALL ICompositeNodeProxy::appendNode( pINode_base node, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->appendNode( node, error );
+ }
+
+ void APICALL ICompositeNodeProxy::insertNodeAtPath( pINode_base node, pcIPath_base path, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->insertNodeAtPath( node, path, error );
+ }
+
+ pINode_base APICALL ICompositeNodeProxy::replaceNodeAtPath( pINode_base node, pcIPath_base path, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->replaceNodeAtPath( node, path, error );
+ }
+
+ pINode_base APICALL ICompositeNodeProxy::removeNodeAtPath( pcIPath_base path, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->removeNodeAtPath( path, error );
+ }
+
+ pINodeIterator_base APICALL ICompositeNodeProxy::iterator( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->iterator( error );
+ }
+
+ spICompositeNode ICompositeNode_v1::MakeShared( pICompositeNode_base ptr ) {
+ if ( !ptr ) return spICompositeNode();
+ pICompositeNode p = ICompositeNode::GetInterfaceVersion() > 1 ?
+ ptr->GetInterfacePointer< ICompositeNode >() : ptr;
+ return shared_ptr< ICompositeNode >( new ICompositeNodeProxy( p ) );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICoreConfigurationManager.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICoreConfigurationManager.cpp
new file mode 100644
index 0000000000..af4f74c1ff
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICoreConfigurationManager.cpp
@@ -0,0 +1,88 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class ICoreConfigurationManagerProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::ICoreConfigurationManagerProxy;
+
+#include "XMPCore/Interfaces/ICoreConfigurationManager.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class ICoreConfigurationManagerProxy
+ : public virtual ICoreConfigurationManager
+ , public virtual IConfigurationManagerProxy
+ {
+ private:
+ pICoreConfigurationManager mRawPtr;
+
+ public:
+ ICoreConfigurationManagerProxy( pICoreConfigurationManager ptr )
+ : IConfigurationManagerProxy( ptr )
+ , mRawPtr( ptr ) {}
+
+ ~ICoreConfigurationManagerProxy() __NOTHROW__ {}
+
+ pICoreConfigurationManager APICALL GetActualICoreConfigurationManager() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pICoreConfigurationManager_I APICALL GetICoreConfigurationManager_I() __NOTHROW__ {
+ return mRawPtr->GetICoreConfigurationManager_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ };
+
+ spICoreConfigurationManager ICoreConfigurationManager_v1::MakeShared( pICoreConfigurationManager_base ptr ) {
+ if ( !ptr ) return spICoreConfigurationManager();
+ pICoreConfigurationManager p = ICoreConfigurationManager::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< ICoreConfigurationManager >() : ptr;
+ return shared_ptr< ICoreConfigurationManager >( new ICoreConfigurationManagerProxy( p ) );
+ }
+
+ spICoreConfigurationManager ICoreConfigurationManager_v1::GetCoreConfigurationManager() {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pICoreConfigurationManager_base, ICoreConfigurationManager >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::GetCoreConfigurationManager );
+ }
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+}
+
+#endif // !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICoreObjectFactory.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICoreObjectFactory.cpp
new file mode 100644
index 0000000000..b7e12e83fd
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ICoreObjectFactory.cpp
@@ -0,0 +1,83 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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 "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include <assert.h>
+
+#if LINKING_XMPCORE_LIB
+ extern "C" AdobeXMPCore::pICoreObjectFactory_base WXMPMeta_GetXMPDOMFactoryInstance_1();
+#endif
+
+namespace AdobeXMPCore {
+
+ pICoreObjectFactory ICoreObjectFactory_v1::MakeCoreObjectFactory( pICoreObjectFactory_base ptr ) {
+ if ( ICoreObjectFactory::GetInterfaceVersion() == 1 )
+ return ptr;
+ else
+ return ptr->GetInterfacePointer< ICoreObjectFactory >();
+ }
+
+#if LINKING_XMPCORE_LIB
+ static pICoreObjectFactory ManageCoreObjectFactory( bool destroy = false ) {
+ static pICoreObjectFactory sCoreObjectFactoryPtr( NULL );
+ if ( destroy && sCoreObjectFactoryPtr ) {
+ sCoreObjectFactoryPtr = NULL;
+ return sCoreObjectFactoryPtr;
+ }
+
+ if ( !sCoreObjectFactoryPtr ) {
+ if ( ICoreObjectFactory::GetInterfaceVersion() != 1 )
+ sCoreObjectFactoryPtr = WXMPMeta_GetXMPDOMFactoryInstance_1()->GetInterfacePointer< ICoreObjectFactory >();
+ else
+ sCoreObjectFactoryPtr = WXMPMeta_GetXMPDOMFactoryInstance_1();
+ }
+ return sCoreObjectFactoryPtr;
+ }
+
+
+ void ICoreObjectFactory_v1::SetupCoreObjectFactory() {
+ ManageCoreObjectFactory();
+ }
+#else
+ static pICoreObjectFactory ManageCoreObjectFactory( bool destroy = false, pICoreObjectFactory_base coreObjectFactory = NULL ) {
+ static pICoreObjectFactory sCoreObjectFactoryPtr( NULL );
+ if ( destroy && sCoreObjectFactoryPtr ) {
+ sCoreObjectFactoryPtr = NULL;
+ return sCoreObjectFactoryPtr;
+ }
+
+ if ( !sCoreObjectFactoryPtr && coreObjectFactory ) {
+ if ( ICoreObjectFactory::GetInterfaceVersion() != 1 )
+ sCoreObjectFactoryPtr = coreObjectFactory->GetInterfacePointer< ICoreObjectFactory >();
+ else
+ sCoreObjectFactoryPtr = coreObjectFactory;
+ }
+ return sCoreObjectFactoryPtr;
+ }
+
+ void ICoreObjectFactory_v1::SetupCoreObjectFactory( pICoreObjectFactory_base coreObjectFactory ) {
+ ManageCoreObjectFactory( false, coreObjectFactory );
+ }
+#endif
+
+ pICoreObjectFactory ICoreObjectFactory_v1::GetCoreObjectFactory() {
+ return ManageCoreObjectFactory();
+ }
+
+ void ICoreObjectFactory_v1::DestroyCoreObjectFactory() {
+ ManageCoreObjectFactory( true );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMImplementationRegistry.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMImplementationRegistry.cpp
new file mode 100644
index 0000000000..35934e23e1
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMImplementationRegistry.cpp
@@ -0,0 +1,122 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IDOMImplementationRegistryProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IDOMImplementationRegistryProxy;
+
+#include "XMPCore/Interfaces/IDOMImplementationRegistry.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include <assert.h>
+#include "XMPCore/Interfaces/IDOMParser.h"
+#include "XMPCore/Interfaces/IDOMSerializer.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+namespace AdobeXMPCore {
+
+ class IDOMImplementationRegistryProxy
+ : public virtual IDOMImplementationRegistry
+ {
+ private:
+ pIDOMImplementationRegistry mRawPtr;
+
+ public:
+ IDOMImplementationRegistryProxy( pIDOMImplementationRegistry ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IDOMImplementationRegistryProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIDOMImplementationRegistry APICALL GetActualIDOMImplementationRegistry() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIDOMImplementationRegistry_I APICALL GetIDOMImplementationRegistry_I() __NOTHROW__ {
+ return mRawPtr->GetIDOMImplementationRegistry_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spIDOMParser APICALL GetParser( const char * key ) const {
+ return CallConstSafeFunctionReturningPointer< IDOMImplementationRegistry, pIDOMParser_base, IDOMParser, const char * >(
+ mRawPtr, &IDOMImplementationRegistry::getParser, key );
+ }
+
+ virtual spIDOMSerializer APICALL GetSerializer( const char * key ) const {
+ return CallConstSafeFunctionReturningPointer< IDOMImplementationRegistry, pIDOMSerializer_base, IDOMSerializer, const char * >(
+ mRawPtr, &IDOMImplementationRegistry::getSerializer, key );
+ }
+
+ virtual bool APICALL RegisterParser( const char * key, pIClientDOMParser_base parser ) {
+ return CallSafeFunction< IDOMImplementationRegistry, bool, uint32, const char *, pIClientDOMParser_base >(
+ mRawPtr, &IDOMImplementationRegistry::registerParser, key, parser );
+ }
+
+ virtual bool APICALL RegisterSerializer( const char * key, pIClientDOMSerializer_base serializer ) {
+ return CallSafeFunction< IDOMImplementationRegistry, bool, uint32, const char *, pIClientDOMSerializer_base >(
+ mRawPtr, &IDOMImplementationRegistry::registerSerializer, key, serializer );
+ }
+
+ virtual pIDOMParser_base APICALL getParser( const char * key, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getParser( key, error );
+ }
+
+ virtual pIDOMSerializer_base APICALL getSerializer( const char * key, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getSerializer( key, error );
+ }
+
+ virtual uint32 APICALL registerParser( const char * key, pIClientDOMParser_base parser, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->registerParser( key, parser, error );
+ }
+
+ virtual uint32 APICALL registerSerializer( const char * key, pIClientDOMSerializer_base serializer, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->registerSerializer( key, serializer, error );
+ }
+
+ };
+
+ spIDOMImplementationRegistry IDOMImplementationRegistry_v1::GetDOMImplementationRegistry() {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIDOMImplementationRegistry_base, IDOMImplementationRegistry >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::GetDOMImplementationRegistry );
+ }
+
+ spIDOMImplementationRegistry IDOMImplementationRegistry_v1::MakeShared( pIDOMImplementationRegistry_base ptr ) {
+ if ( !ptr ) return spIDOMImplementationRegistry();
+ pIDOMImplementationRegistry p = IDOMImplementationRegistry::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IDOMImplementationRegistry >() : ptr;
+ return shared_ptr< IDOMImplementationRegistry >( new IDOMImplementationRegistryProxy( p ) );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMParser.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMParser.cpp
new file mode 100644
index 0000000000..a077a5c854
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMParser.cpp
@@ -0,0 +1,116 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IDOMParserProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IDOMParserProxy;
+
+#include "XMPCore/Interfaces/IDOMParser.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include <assert.h>
+#include "XMPCore/Interfaces/IMetadata.h"
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class IDOMParserProxy
+ : public virtual IDOMParser
+ , public virtual IConfigurableProxy
+ {
+ private:
+ pIDOMParser mRawPtr;
+
+ public:
+ IDOMParserProxy( pIDOMParser ptr )
+ : IConfigurableProxy( ptr )
+ , mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IDOMParserProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIDOMParser APICALL GetActualIDOMParser() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIDOMParser_I APICALL GetIDOMParser_I() __NOTHROW__ {
+ return mRawPtr->GetIDOMParser_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spIDOMParser APICALL Clone() const {
+ return CallConstSafeFunctionReturningPointer< IDOMParser, pIDOMParser_base, IDOMParser >(
+ mRawPtr, &IDOMParser::clone );
+ }
+
+ virtual spIMetadata APICALL Parse( const char * buffer, sizet bufferLength ) {
+ return CallSafeFunctionReturningPointer< IDOMParser, pIMetadata_base, IMetadata, const char *, sizet >(
+ mRawPtr, &IDOMParser::parse, buffer, bufferLength );
+ }
+
+ virtual void APICALL ParseWithSpecificAction( const char * buffer, sizet bufferLength, eActionType actionType, spINode & node ) {
+ return CallSafeFunctionReturningVoid< IDOMParser, const char *, sizet, uint32, pINode_base >(
+ mRawPtr, &IDOMParser::parseWithSpecificAction, buffer, bufferLength, static_cast< uint32 >( actionType ), node ? node->GetActualINode() : NULL );
+ }
+
+ virtual pIDOMParser_base APICALL clone( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->clone( error );
+ }
+
+ virtual pIMetadata_base APICALL parse( const char * buffer, sizet bufferLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->parse( buffer, bufferLength, error );
+ }
+
+ virtual void APICALL parseWithSpecificAction( const char * buffer, sizet bufferLength, uint32 actionType, pINode_base node, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->parseWithSpecificAction( buffer, bufferLength, actionType, node, error );
+ }
+
+ };
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+ spIDOMParser IDOMParser_v1::MakeShared( pIDOMParser_base ptr ) {
+ if ( !ptr ) return spIDOMParser();
+ pIDOMParser p = IDOMParser::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IDOMParser >() : ptr;
+ return shared_ptr< IDOMParser >( new IDOMParserProxy( p ) );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMSerializer.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMSerializer.cpp
new file mode 100644
index 0000000000..481477a72a
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IDOMSerializer.cpp
@@ -0,0 +1,109 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IDOMSerializerProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IDOMSerializerProxy;
+
+#include "XMPCore/Interfaces/IDOMSerializer.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCore/Interfaces/INode.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class IDOMSerializerProxy
+ : public virtual IDOMSerializer
+ , public virtual IConfigurableProxy
+ {
+ private:
+ pIDOMSerializer mRawPtr;
+
+ public:
+ IDOMSerializerProxy( pIDOMSerializer ptr )
+ : IConfigurableProxy( ptr )
+ , mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IDOMSerializerProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIDOMSerializer APICALL GetActualIDOMSerializer() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIDOMSerializer_I APICALL GetIDOMSerializer_I() __NOTHROW__ {
+ return mRawPtr->GetIDOMSerializer_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spIDOMSerializer APICALL Clone() const {
+ return CallConstSafeFunctionReturningPointer< IDOMSerializer, pIDOMSerializer_base, IDOMSerializer >(
+ mRawPtr, &IDOMSerializer_v1::clone );
+ }
+
+ virtual spIUTF8String APICALL Serialize( const spINode & node, const spcINameSpacePrefixMap & map ) {
+ return CallSafeFunctionReturningPointer< IDOMSerializer, pIUTF8String_base, IUTF8String, pINode_base, pcINameSpacePrefixMap_base >(
+ mRawPtr, &IDOMSerializer_v1::serialize, node ? node->GetActualINode() : NULL , map ? map->GetActualINameSpacePrefixMap() : NULL );
+ }
+
+ virtual pIDOMSerializer_base APICALL clone( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->clone( error );
+ }
+
+ virtual pIUTF8String_base APICALL serialize( pINode_base node, pcINameSpacePrefixMap_base map, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->serialize( node, map, error );
+ }
+
+ };
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+ spIDOMSerializer IDOMSerializer_v1::MakeShared( pIDOMSerializer_base ptr ) {
+ if ( !ptr ) return spIDOMSerializer();
+ pIDOMSerializer p = ptr->GetInterfacePointer< IDOMSerializer >();
+ return shared_ptr< IDOMSerializer >( new IDOMSerializerProxy( p ) );
+ }
+
+}
+
+#endif // !BUILDING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IMetadata.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IMetadata.cpp
new file mode 100644
index 0000000000..9b4eef5e85
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IMetadata.cpp
@@ -0,0 +1,113 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IMetadataProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IMetadataProxy;
+
+#include "XMPCore/Interfaces/IMetadata.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class IMetadataProxy
+ : public virtual IMetadata
+ , public virtual IStructureNodeProxy
+ {
+ private:
+ pIMetadata mRawPtr;
+
+ public:
+ IMetadataProxy( pIMetadata ptr )
+ : mRawPtr( ptr )
+ , IStructureNodeProxy( ptr )
+ , ICompositeNodeProxy( ptr )
+ , INodeProxy( ptr ) {}
+
+ ~IMetadataProxy() __NOTHROW__ {}
+
+ pIMetadata APICALL GetActualIMetadata() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIMetadata_I APICALL GetIMetadata_I() __NOTHROW__ {
+ return mRawPtr->GetIMetadata_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spcIUTF8String APICALL GetAboutURI() const {
+ return CallConstSafeFunctionReturningPointer< IMetadata_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &IMetadata_v1::getAboutURI );
+ }
+
+ virtual void APICALL SetAboutURI( const char * uri, sizet uriLength ) __NOTHROW__ {
+ mRawPtr->SetAboutURI( uri, uriLength );
+ }
+
+ virtual pcIUTF8String_base APICALL getAboutURI( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getAboutURI( error );
+ }
+
+ virtual void APICALL EnableFeature( const char * key, sizet keyLength ) const __NOTHROW__ {
+ return mRawPtr->EnableFeature( key, keyLength );
+ }
+
+ virtual void APICALL DisableFeature( const char * key, sizet keyLength ) const __NOTHROW__ {
+ return mRawPtr->DisableFeature( key, keyLength );
+ }
+ };
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+
+ spIMetadata IMetadata_v1::MakeShared( pIMetadata_base ptr ) {
+ if ( !ptr ) return spIMetadata();
+ pIMetadata p = IMetadata::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IMetadata >() : ptr;
+ return shared_ptr< IMetadata >( new IMetadataProxy( p ) );
+ }
+
+ spIMetadata IMetadata_v1::CreateMetadata() {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIMetadata, IMetadata >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateMetadata );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INameSpacePrefixMap.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INameSpacePrefixMap.cpp
new file mode 100644
index 0000000000..8dee5b7bb8
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INameSpacePrefixMap.cpp
@@ -0,0 +1,187 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class INameSpacePrefixMapProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::INameSpacePrefixMapProxy;
+
+#include "XMPCore/Interfaces/INameSpacePrefixMap.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+
+ bool INameSpacePrefixMap::IsEmpty() const __NOTHROW__{
+ return this->Size() == 0;
+ }
+
+ class INameSpacePrefixMapProxy
+ : public virtual INameSpacePrefixMap
+ {
+ private:
+ pINameSpacePrefixMap mRawPtr;
+
+ public:
+ INameSpacePrefixMapProxy( pINameSpacePrefixMap ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~INameSpacePrefixMapProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pINameSpacePrefixMap APICALL GetActualINameSpacePrefixMap() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pINameSpacePrefixMap_I APICALL GetINameSpacePrefixMap_I() __NOTHROW__ {
+ return mRawPtr->GetINameSpacePrefixMap_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual bool APICALL Insert( const char * prefix, sizet prefixLength, const char * nameSpace, sizet nameSpaceLength ) {
+ return CallSafeFunction< INameSpacePrefixMap_v1, bool, uint32, const char *, sizet, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::insert, prefix, prefixLength, nameSpace, nameSpaceLength );
+ }
+
+ virtual uint32 APICALL insert( const char * prefix, sizet prefixLength, const char * nameSpace, sizet nameSpaceLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->insert( prefix, prefixLength, nameSpace, nameSpaceLength, error );
+ }
+
+ virtual bool APICALL RemovePrefix( const char * prefix, sizet prefixLength ) {
+ return CallSafeFunction< INameSpacePrefixMap_v1, bool, uint32, uint32, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::remove, kPrefixIsParameter, prefix, prefixLength );
+ }
+
+ virtual bool APICALL RemoveNameSpace( const char * nameSpace, sizet nameSpaceLength ) {
+ return CallSafeFunction< INameSpacePrefixMap_v1, bool, uint32, uint32, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::remove, kNameSpaceIsParameter, nameSpace, nameSpaceLength );
+ }
+
+ virtual bool APICALL IsPrefixPresent( const char * prefix, sizet prefixLength ) const {
+ return CallConstSafeFunction< INameSpacePrefixMap_v1, bool, uint32, uint32, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::isPresent, kPrefixIsParameter, prefix, prefixLength );
+ }
+
+ virtual bool APICALL IsNameSpacePresent( const char * nameSpace, sizet nameSpaceLength ) const {
+ return CallConstSafeFunction< INameSpacePrefixMap_v1, bool, uint32, uint32, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::isPresent, kNameSpaceIsParameter, nameSpace, nameSpaceLength );
+ }
+
+ virtual spcIUTF8String APICALL GetNameSpace( const char * prefix, sizet prefixLength ) const {
+ return CallConstSafeFunctionReturningPointer< INameSpacePrefixMap_v1, pcIUTF8String_base, const IUTF8String, uint32, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::get, kPrefixIsParameter, prefix, prefixLength );
+ }
+
+ virtual spcIUTF8String APICALL GetPrefix( const char * nameSpace, sizet nameSpaceLength ) const {
+ return CallConstSafeFunctionReturningPointer< INameSpacePrefixMap_v1, pcIUTF8String_base, const IUTF8String, uint32, const char *, sizet >(
+ mRawPtr, &INameSpacePrefixMap_v1::get, kNameSpaceIsParameter, nameSpace, nameSpaceLength );
+ }
+
+ virtual sizet APICALL Size() const __NOTHROW__ {
+ return mRawPtr->Size();
+ }
+
+ virtual void APICALL Clear() __NOTHROW__ {
+ return mRawPtr->Clear();
+ }
+
+ virtual spINameSpacePrefixMap APICALL Clone() const {
+ return CallConstSafeFunctionReturningPointer< INameSpacePrefixMap_v1, pINameSpacePrefixMap_base, INameSpacePrefixMap >(
+ mRawPtr, &INameSpacePrefixMap_v1::clone );
+ }
+
+ virtual pINameSpacePrefixMap_base APICALL clone( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->clone( error );
+ }
+
+ virtual uint32 APICALL remove( uint32 keyType, const char * key, sizet keyLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->remove( keyType, key, keyLength, error );
+ }
+
+ virtual uint32 APICALL isPresent( uint32 keyType, const char * key, sizet keyLength, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isPresent( keyType, key, keyLength, error );
+ }
+
+ virtual pcIUTF8String_base APICALL get( uint32 keyType, const char * key, sizet keyLength, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->get( keyType, key, keyLength, error );
+ }
+
+ virtual void APICALL EnableThreadSafety() const __NOTHROW__ {
+ return mRawPtr->EnableThreadSafety();
+ }
+
+ virtual void APICALL DisableThreadSafety() const __NOTHROW__ {
+ return mRawPtr->DisableThreadSafety();
+ }
+
+ virtual bool APICALL IsThreadSafe() const {
+ return mRawPtr->isThreadSafe() != 0;
+ }
+
+ virtual uint32 APICALL isThreadSafe( ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isThreadSafe();
+ }
+
+ virtual AdobeXMPCommon_Int::pIThreadSafe_I APICALL GetIThreadSafe_I() __NOTHROW__ override {
+ return mRawPtr->GetIThreadSafe_I();
+ }
+
+ };
+
+ spINameSpacePrefixMap INameSpacePrefixMap_v1::MakeShared( pINameSpacePrefixMap_base ptr ) {
+ if ( !ptr ) return spINameSpacePrefixMap();
+ pINameSpacePrefixMap p = INameSpacePrefixMap::GetInterfaceVersion() > 1 ?
+ ptr->GetInterfacePointer< INameSpacePrefixMap >() : ptr;
+ return shared_ptr< INameSpacePrefixMap >( new INameSpacePrefixMapProxy( p ) );
+ }
+
+ spINameSpacePrefixMap INameSpacePrefixMap_v1::CreateNameSpacePrefixMap() {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pINameSpacePrefixMap_base, INameSpacePrefixMap >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateNameSpacePrefixMap );
+ }
+
+ spcINameSpacePrefixMap INameSpacePrefixMap_v1::GetDefaultNameSpacePrefixMap() {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pcINameSpacePrefixMap_base, const INameSpacePrefixMap >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::GetDefaultNameSpacePrefixMap );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INode.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INode.cpp
new file mode 100644
index 0000000000..9d0126c0e1
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INode.cpp
@@ -0,0 +1,377 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class INodeProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::INodeProxy;
+
+#include "XMPCore/Interfaces/INode.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCore/Interfaces/IPath.h"
+#include "XMPCore/Interfaces/ISimpleNode.h"
+#include "XMPCore/Interfaces/INodeIterator.h"
+#include "XMPCore/Interfaces/IArrayNode.h"
+#include "XMPCore/Interfaces/IMetadata.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+ INodeProxy::INodeProxy( pINode ptr ) : mRawPtr( ptr ) {
+ mRawPtr->Acquire();
+ }
+
+ INodeProxy::~INodeProxy() __NOTHROW__ {
+ mRawPtr->Release();
+ }
+
+ pINode APICALL INodeProxy::GetActualINode() __NOTHROW__ {
+ return mRawPtr;
+ }
+
+ void APICALL INodeProxy::Acquire() const __NOTHROW__ {
+ assert( false );
+ }
+
+ void APICALL INodeProxy::Release() const __NOTHROW__ {
+ assert( false );
+ }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL INodeProxy::GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pINode_I APICALL INodeProxy::GetINode_I() __NOTHROW__ {
+ return mRawPtr->GetINode_I();
+ }
+
+ pvoid APICALL INodeProxy::getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ spINode APICALL INodeProxy::GetParent() {
+ return CallSafeFunctionReturningPointer< INode_v1, pINode_base, INode >(
+ mRawPtr, &INode_v1::getParent );
+ }
+
+ void APICALL INodeProxy::SetName( const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningVoid< INode_v1, const char *, sizet >(
+ mRawPtr, &INode_v1::setName, name, nameLength );
+ }
+
+ spcIUTF8String APICALL INodeProxy::GetName() const {
+ return CallConstSafeFunctionReturningPointer< INode_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &INode_v1::getName );
+ }
+
+ void APICALL INodeProxy::SetNameSpace( const char * nameSpace, sizet nameSpaceLength ) {
+ return CallSafeFunctionReturningVoid< INode_v1, const char *, sizet >(
+ mRawPtr, &INode_v1::setNameSpace, nameSpace, nameSpaceLength );
+
+ }
+
+ spcIUTF8String APICALL INodeProxy::GetNameSpace() const {
+ return CallConstSafeFunctionReturningPointer< INode_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &INode_v1::getNameSpace );
+ }
+
+ spIPath APICALL INodeProxy::GetPath() const {
+ return CallConstSafeFunctionReturningPointer< INode_v1, pIPath_base, IPath >(
+ mRawPtr, &INode_v1::getPath );
+ }
+
+ sizet APICALL INodeProxy::QualifiersCount() const __NOTHROW__ {
+ return mRawPtr->QualifiersCount();
+ }
+
+ spINodeIterator APICALL INodeProxy::QualifiersIterator() {
+ return CallSafeFunctionReturningPointer< INode_v1, pINodeIterator_base, INodeIterator >(
+ mRawPtr, &INode_v1::qualifiersIterator );
+ }
+
+ spINode APICALL INodeProxy::GetQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< INode_v1, pINode_base, INode, const char *, sizet, const char *, sizet >(
+ mRawPtr, &INode_v1::getQualifier, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ void APICALL INodeProxy::InsertQualifier( const spINode & node ) {
+ return CallSafeFunctionReturningVoid< INode_v1, pINode_base >(
+ mRawPtr, &INode_v1::insertQualifier, node ? node->GetActualINode() : NULL );
+ }
+
+ spINode APICALL INodeProxy::ReplaceQualifier( const spINode & node ) {
+ return CallSafeFunctionReturningPointer< INode_v1, pINode_base, INode, pINode_base >(
+ mRawPtr, &INode_v1::replaceQualifier, node ? node->GetActualINode() : NULL );
+ }
+
+ spINode APICALL INodeProxy::RemoveQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< INode_v1, pINode_base, INode, const char *, sizet, const char *, sizet >(
+ mRawPtr, &INode_v1::removeQualifier, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ INode_v1::eNodeType APICALL INodeProxy::GetNodeType() const {
+ return CallConstSafeFunction< INode_v1, eNodeType, uint32 >(
+ mRawPtr, &INode_v1::getNodeType );
+ }
+
+ bool APICALL INodeProxy::IsArrayItem() const {
+ return CallConstSafeFunction< INode_v1, bool, uint32 >(
+ mRawPtr, &INode_v1::isArrayItem );
+ }
+
+ bool APICALL INodeProxy::IsQualifierNode() const {
+ return CallConstSafeFunction< INode_v1, bool, uint32 >(
+ mRawPtr, &INode_v1::isQualifierNode );
+ }
+
+ sizet APICALL INodeProxy::GetIndex() const {
+ return CallConstSafeFunction< INode_v1, sizet, sizet >(
+ mRawPtr, &INode_v1::getIndex );
+ }
+
+ bool APICALL INodeProxy::HasQualifiers() const {
+ return CallConstSafeFunction< INode_v1, bool, uint32 >(
+ mRawPtr, &INode_v1::hasQualifiers );
+ }
+
+ bool APICALL INodeProxy::HasContent() const {
+ return CallConstSafeFunction< INode_v1, bool, uint32 >(
+ mRawPtr, &INode_v1::hasContent );
+ }
+
+ bool APICALL INodeProxy::IsEmpty() const {
+ return CallConstSafeFunction< INode_v1, bool, uint32 >(
+ mRawPtr, &INode_v1::isEmpty );
+ }
+
+ bool APICALL INodeProxy::HasChanged() const {
+ return CallConstSafeFunction< INode_v1, bool, uint32 >(
+ mRawPtr, &INode_v1::hasChanged );
+ }
+
+ void APICALL INodeProxy::AcknowledgeChanges() const __NOTHROW__ {
+ return mRawPtr->AcknowledgeChanges( );
+ }
+
+ void APICALL INodeProxy::Clear( bool contents, bool qualifiers ) {
+ return CallSafeFunctionReturningVoid< INode_v1, uint32, uint32 >(
+ mRawPtr, &INode_v1::clear, static_cast< uint32 >( contents ), static_cast< uint32 >( qualifiers ) );
+ }
+
+ spINode APICALL INodeProxy::Clone( bool ignoreEmptyNodes, bool ignoreNodesWithOnlyQualifiers ) const {
+ return CallConstSafeFunctionReturningPointer< INode_v1, pINode_base, INode, uint32, uint32 >(
+ mRawPtr, &INode_v1::clone, static_cast< uint32 >( ignoreEmptyNodes ), static_cast< uint32 >( ignoreNodesWithOnlyQualifiers ) );
+ }
+
+ pINode_base APICALL INodeProxy::getParent( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getParent( error );
+ }
+
+ void APICALL INodeProxy::setName( const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->setName( name, nameLength, error );
+ }
+
+ AdobeXMPCommon::pcIUTF8String_base APICALL INodeProxy::getName( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getName( error );
+ }
+
+ void APICALL INodeProxy::setNameSpace( const char * nameSpace, sizet nameSpaceLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->setNameSpace( nameSpace, nameSpaceLength, error );
+ }
+
+ pcIUTF8String_base APICALL INodeProxy::getNameSpace( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNameSpace( error );
+ }
+
+ pIPath_base APICALL INodeProxy::getPath( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getPath( error );
+ }
+
+ pINodeIterator_base APICALL INodeProxy::qualifiersIterator( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->qualifiersIterator( error );
+ }
+
+ pINode_base APICALL INodeProxy::getQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getQualifier( nameSpace, nameSpaceLength, name, nameLength, error );
+ }
+
+ void APICALL INodeProxy::insertQualifier( pINode_base base, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->insertQualifier( base, error );
+ }
+
+ pINode_base APICALL INodeProxy::replaceQualifier( pINode_base node, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->replaceQualifier( node, error );
+ }
+
+ pINode_base APICALL INodeProxy::removeQualifier( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->removeQualifier( nameSpace, nameSpaceLength, name, nameLength, error );
+ }
+
+ uint32 APICALL INodeProxy::getNodeType( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNodeType( error );
+ }
+
+ uint32 APICALL INodeProxy::isArrayItem( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isArrayItem( error );
+ }
+
+ uint32 APICALL INodeProxy::isQualifierNode( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isQualifierNode( error );
+ }
+
+ sizet APICALL INodeProxy::getIndex( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getIndex( error );
+ }
+
+ uint32 APICALL INodeProxy::hasQualifiers( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->hasQualifiers( error );
+ }
+
+ uint32 APICALL INodeProxy::hasContent( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->hasContent( error );
+ }
+
+ uint32 APICALL INodeProxy::isEmpty( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isEmpty( error );
+ }
+
+ uint32 APICALL INodeProxy::hasChanged( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->hasChanged( error );
+ }
+
+ void APICALL INodeProxy::clear( uint32 contents, uint32 qualifiers, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->clear( contents, qualifiers, error );
+ }
+
+ pINode_base APICALL INodeProxy::clone( uint32 igoreEmptyNodes, uint32 ignoreNodesWithOnlyQualifiers, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->clone( igoreEmptyNodes, ignoreNodesWithOnlyQualifiers, error );
+ }
+
+ void APICALL INodeProxy::EnableThreadSafety() const __NOTHROW__ {
+ return mRawPtr->EnableThreadSafety( );
+ }
+
+ void APICALL INodeProxy::DisableThreadSafety() const __NOTHROW__ {
+ return mRawPtr->DisableThreadSafety( );
+ }
+
+ bool APICALL INodeProxy::IsThreadSafe() const {
+ return mRawPtr->isThreadSafe() != 0;
+ }
+
+ uint32 APICALL INodeProxy::isThreadSafe() const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isThreadSafe();
+ }
+
+ spISimpleNode APICALL INodeProxy::ConvertToSimpleNode() {
+ return CallSafeFunctionReturningPointer< INode_v1, pISimpleNode_base, ISimpleNode >(
+ mRawPtr, &INode_v1::convertToSimpleNode );
+ }
+
+ spIStructureNode APICALL INodeProxy::ConvertToStructureNode() {
+ return CallSafeFunctionReturningPointer< INode_v1, pIStructureNode_base, IStructureNode >(
+ mRawPtr, &INode_v1::convertToStructureNode );
+ }
+
+ spIArrayNode APICALL INodeProxy::ConvertToArrayNode() {
+ return CallSafeFunctionReturningPointer< INode_v1, pIArrayNode_base, IArrayNode >(
+ mRawPtr, &INode_v1::convertToArrayNode );
+ }
+
+ spIMetadata APICALL INodeProxy::ConvertToMetadata() {
+ return CallSafeFunctionReturningPointer< INode_v1, pIMetadata_base, IMetadata >(
+ mRawPtr, &INode_v1::convertToMetadata );
+ }
+
+ pISimpleNode_base APICALL INodeProxy::convertToSimpleNode( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->convertToSimpleNode( error );
+ }
+
+ pIStructureNode_base APICALL INodeProxy::convertToStructureNode( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->convertToStructureNode( error ); }
+
+ pIArrayNode_base APICALL INodeProxy::convertToArrayNode( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->convertToArrayNode( error );
+ }
+
+ pIMetadata_base APICALL INodeProxy::convertToMetadata( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->convertToMetadata( error );
+ }
+
+ uint32 APICALL INodeProxy::getParentNodeType( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getParentNodeType( error );
+ }
+
+ uint32 APICALL INodeProxy::getQualifierNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getQualifierNodeType( nameSpace, nameSpaceLength, name, nameLength, error );
+ }
+
+ INode_v1::eNodeType APICALL INodeProxy::GetParentNodeType() const {
+ return CallConstSafeFunction< INode_v1, eNodeType, uint32 >(
+ mRawPtr, &INode_v1::getParentNodeType );
+ }
+
+ INode_v1::eNodeType APICALL INodeProxy::GetQualifierNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ return CallConstSafeFunction< INode_v1, eNodeType, uint32, const char *, sizet, const char *, sizet >(
+ mRawPtr, &INode_v1::getQualifierNodeType, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ AdobeXMPCommon_Int::pIThreadSafe_I APICALL INodeProxy::GetIThreadSafe_I() __NOTHROW__ {
+ return mRawPtr->GetIThreadSafe_I( );
+ }
+
+ pvoid APICALL INodeProxy::GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ spINode INode_v1::MakeShared( pINode_base ptr ) {
+ if ( !ptr ) return spINode();
+ pINode p = INode::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< INode >() : ptr;
+ return shared_ptr< INode >( new INodeProxy( p ) );
+ }
+
+}
+
+#endif // !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INodeIterator.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INodeIterator.cpp
new file mode 100644
index 0000000000..f2f43a36be
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/INodeIterator.cpp
@@ -0,0 +1,105 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class INodeIteratorProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::INodeIteratorProxy;
+
+#include "XMPCore/Interfaces/INodeIterator.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+ class INodeIteratorProxy
+ : public virtual INodeIterator
+ {
+ private:
+ pINodeIterator mRawPtr;
+
+ public:
+ INodeIteratorProxy( pINodeIterator ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~INodeIteratorProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pINodeIterator APICALL GetActualINodeIterator() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pINodeIterator_I APICALL GetINodeIterator_I() __NOTHROW__ {
+ return mRawPtr->GetINodeIterator_I();
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spINode APICALL GetNode() {
+ return CallSafeFunctionReturningPointer< INodeIterator_v1, pINode_base, INode >(
+ mRawPtr, &INodeIterator_v1::getNode );
+ }
+
+ virtual INode_v1::eNodeType APICALL GetNodeType() const {
+ return CallConstSafeFunction< INodeIterator_v1, INode_v1::eNodeType, uint32 >(
+ mRawPtr, &INodeIterator_v1::getNodeType );
+ }
+
+ virtual spINodeIterator APICALL Next() {
+ return CallSafeFunctionReturningPointer< INodeIterator_v1, pINodeIterator, INodeIterator >(
+ mRawPtr, &INodeIterator_v1::next );
+ }
+
+ virtual uint32 APICALL getNodeType( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNodeType( error );
+ }
+
+ virtual pINode_base APICALL getNode( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNode( error );
+ }
+
+ virtual pINodeIterator_base APICALL next( pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->next( error );
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ };
+
+ spINodeIterator INodeIterator_v1::MakeShared( pINodeIterator_base ptr ) {
+ if ( !ptr ) return spINodeIterator();
+ //return shared_ptr< INodeIterator >( new INodeIteratorProxy( ptr ) );
+ pINodeIterator p = INodeIterator::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< INodeIterator >() : ptr;
+ return shared_ptr< INodeIterator >( new INodeIteratorProxy( p ) );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IPath.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IPath.cpp
new file mode 100644
index 0000000000..f0b99c3a99
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IPath.cpp
@@ -0,0 +1,157 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IPathProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IPathProxy;
+
+#include "XMPCore/Interfaces/IPath.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCore/Interfaces/INameSpacePrefixMap.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCore/Interfaces/IPathSegment.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+ class IPathProxy
+ : public virtual IPath
+ {
+ private:
+ pIPath mRawPtr;
+
+ public:
+ IPathProxy( pIPath ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IPathProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIPath APICALL GetActualIPath() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIPath_I APICALL GetIPath_I() __NOTHROW__ {
+ return mRawPtr->GetIPath_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spcINameSpacePrefixMap APICALL RegisterNameSpacePrefixMap( const spcINameSpacePrefixMap & map ) {
+ return CallSafeFunctionReturningPointer< IPath_v1, pcINameSpacePrefixMap_base, const INameSpacePrefixMap, pcINameSpacePrefixMap_base >(
+ mRawPtr, &IPath_v1::registerNameSpacePrefixMap, map ? map->GetActualINameSpacePrefixMap() : NULL );
+ }
+
+ virtual pcINameSpacePrefixMap_base APICALL registerNameSpacePrefixMap( pcINameSpacePrefixMap_base map, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->registerNameSpacePrefixMap( map, error );
+ }
+
+ virtual spIUTF8String APICALL Serialize( const spcINameSpacePrefixMap & map ) const {
+ return CallConstSafeFunctionReturningPointer< IPath_v1, pIUTF8String_base, IUTF8String, pcINameSpacePrefixMap_base >(
+ mRawPtr, &IPath_v1::serialize, map ? map->GetActualINameSpacePrefixMap() : NULL );
+ }
+
+ virtual pIUTF8String_base APICALL serialize( pcINameSpacePrefixMap_base map, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->serialize( map, error );
+ }
+
+ virtual void APICALL AppendPathSegment( const spcIPathSegment & segment ) {
+ return CallSafeFunctionReturningVoid< IPath_v1, pcIPathSegment_base >(
+ mRawPtr, &IPath_v1::appendPathSegment, segment ? segment->GetActualIPathSegment() : NULL );
+ }
+
+ virtual void APICALL appendPathSegment( pcIPathSegment_base segment, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->appendPathSegment( segment, error );
+ }
+
+ virtual spcIPathSegment APICALL RemovePathSegment( sizet index ) {
+ return CallSafeFunctionReturningPointer< IPath_v1, pcIPathSegment_base, const IPathSegment, sizet >(
+ mRawPtr, &IPath_v1::removePathSegment, index );
+ }
+
+ virtual pcIPathSegment_base APICALL removePathSegment( sizet index, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->removePathSegment( index, error );
+ }
+
+ virtual spcIPathSegment APICALL GetPathSegment( sizet index ) const {
+ return CallConstSafeFunctionReturningPointer< IPath_v1, pcIPathSegment_base, const IPathSegment, sizet >(
+ mRawPtr, &IPath_v1::getPathSegment, index );
+ }
+
+ virtual pcIPathSegment_base APICALL getPathSegment( sizet index, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getPathSegment( index, error );
+ }
+
+ virtual sizet APICALL Size() const __NOTHROW__ {
+ return mRawPtr->Size( );
+ }
+
+ virtual void APICALL Clear() __NOTHROW__ {
+ return mRawPtr->Clear( );
+ }
+
+ virtual spIPath APICALL Clone( sizet startingIndex, sizet countOfSegments ) const {
+ return CallConstSafeFunctionReturningPointer< IPath_v1, pIPath_base, IPath, sizet, sizet >(
+ mRawPtr, &IPath_v1::clone, startingIndex, countOfSegments );
+ }
+
+ virtual pIPath_base APICALL clone( sizet startingIndex, sizet countOfSegemetns, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->clone( startingIndex, countOfSegemetns, error );
+ }
+
+ };
+
+ spIPath IPath_v1::MakeShared( pIPath_base ptr ) {
+ if ( !ptr ) return spIPath();
+ pIPath p = IPath::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IPath >() : ptr;
+ return shared_ptr< IPath >( new IPathProxy( p ) );
+ }
+
+ spIPath IPath_v1::CreatePath() {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIPath_base, IPath >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreatePath );
+ }
+
+ spIPath IPath_v1::ParsePath( const char * path, sizet pathLength, const spcINameSpacePrefixMap & map ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIPath_base, IPath, const char *, sizet, pcINameSpacePrefixMap_base >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::ParsePath, path, pathLength, map ? map->GetActualINameSpacePrefixMap() : NULL );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IPathSegment.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IPathSegment.cpp
new file mode 100644
index 0000000000..42284922ce
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IPathSegment.cpp
@@ -0,0 +1,146 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IPathSegmentProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IPathSegmentProxy;
+
+#include "XMPCore/Interfaces/IPathSegment.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCommon/Interfaces/IError.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+ class IPathSegmentProxy
+ : public virtual IPathSegment
+ {
+ private:
+ pIPathSegment mRawPtr;
+
+ public:
+ IPathSegmentProxy( pIPathSegment ptr )
+ : mRawPtr( ptr )
+ {
+ mRawPtr->Acquire();
+ }
+
+ ~IPathSegmentProxy() __NOTHROW__ { mRawPtr->Release(); }
+
+ pIPathSegment APICALL GetActualIPathSegment() __NOTHROW__ { return mRawPtr; }
+
+ void APICALL Acquire() const __NOTHROW__ { assert( false ); }
+
+ void APICALL Release() const __NOTHROW__ { assert( false ); }
+
+ AdobeXMPCommon_Int::pISharedObject_I APICALL GetISharedObject_I() __NOTHROW__ {
+ return mRawPtr->GetISharedObject_I();
+ }
+
+ AdobeXMPCore_Int::pIPathSegment_I APICALL GetIPathSegment_I() __NOTHROW__ {
+ return mRawPtr->GetIPathSegment_I();
+ }
+
+ pvoid APICALL GetInterfacePointer( uint64 interfaceID, uint32 interfaceVersion ) {
+ return CallSafeFunction< IVersionable, pvoid, pvoid, uint64, uint32 >(
+ mRawPtr, &IVersionable::getInterfacePointer, interfaceID, interfaceVersion );
+ }
+
+ pvoid APICALL getInterfacePointer( uint64 interfaceID, uint32 interfaceVersion, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getInterfacePointer( interfaceID, interfaceVersion, error );
+ }
+
+ virtual spcIUTF8String APICALL GetNameSpace() const {
+ return CallConstSafeFunctionReturningPointer< IPathSegment_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &IPathSegment_v1::getNameSpace );
+ }
+
+ virtual pcIUTF8String_base APICALL getNameSpace( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNameSpace( error );
+ }
+
+ virtual spcIUTF8String APICALL GetName() const {
+ return CallConstSafeFunctionReturningPointer< IPathSegment_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &IPathSegment_v1::getName );
+ }
+
+ virtual pcIUTF8String_base APICALL getName( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getName( error );
+ }
+
+ virtual ePathSegmentType APICALL GetType() const {
+ return CallConstSafeFunction< IPathSegment_v1, ePathSegmentType, uint32 >(
+ mRawPtr, &IPathSegment_v1::getType );
+ }
+
+ virtual uint32 APICALL getType( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getType( error );
+ }
+
+ virtual sizet APICALL GetIndex() const __NOTHROW__ {
+ return mRawPtr->GetIndex();
+ }
+
+ virtual spcIUTF8String APICALL GetValue() const {
+ return CallConstSafeFunctionReturningPointer< IPathSegment_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &IPathSegment_v1::getValue );
+ }
+
+ virtual pcIUTF8String_base APICALL getValue( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getValue( error );
+ }
+
+ };
+
+ spIPathSegment IPathSegment_v1::MakeShared( pIPathSegment_base ptr ) {
+ if ( !ptr ) return spIPathSegment();
+ pIPathSegment p = IPathSegment::GetInterfaceVersion() > 1 ?
+ ptr->GetInterfacePointer< IPathSegment >() : ptr;
+ return shared_ptr< IPathSegment >( new IPathSegmentProxy( p ) );
+ }
+
+ spcIPathSegment IPathSegment_v1::CreatePropertyPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pcIPathSegment_base, const IPathSegment, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreatePropertyPathSegment, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ spcIPathSegment IPathSegment_v1::CreateArrayIndexPathSegment( const char * nameSpace, sizet nameSpaceLength, sizet index ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pcIPathSegment_base, const IPathSegment, const char *, sizet, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateArrayIndexPathSegment, nameSpace, nameSpaceLength, index );
+ }
+
+ spcIPathSegment IPathSegment_v1::CreateQualifierPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pcIPathSegment_base, const IPathSegment, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateQualifierPathSegment, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ spcIPathSegment IPathSegment_v1::CreateQualifierSelectorPathSegment( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength,
+ const char * value, sizet valueLength )
+ {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pcIPathSegment_base, const IPathSegment, const char *, sizet, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateQualifierSelectorPathSegment, nameSpace, nameSpaceLength, name, nameLength, value, valueLength );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ISimpleNode.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ISimpleNode.cpp
new file mode 100644
index 0000000000..170192f129
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/ISimpleNode.cpp
@@ -0,0 +1,111 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class ISimpleNodeProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::ISimpleNodeProxy;
+
+#include "XMPCore/Interfaces/ISimpleNode.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCommon/Interfaces/IUTF8String.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+#if XMP_WinBuild
+ #pragma warning( push )
+ #pragma warning( disable : 4250 )
+#endif
+
+ class ISimpleNodeProxy
+ : public virtual ISimpleNode
+ , public virtual INodeProxy
+ {
+ private:
+ pISimpleNode mRawPtr;
+
+ public:
+ ISimpleNodeProxy( pISimpleNode ptr )
+ : mRawPtr( ptr )
+ , INodeProxy( ptr ) {}
+
+ ~ISimpleNodeProxy() __NOTHROW__ {}
+
+ pISimpleNode APICALL GetActualISimpleNode() __NOTHROW__ { return mRawPtr; }
+
+ AdobeXMPCore_Int::pISimpleNode_I APICALL GetISimpleNode_I() __NOTHROW__ {
+ return mRawPtr->GetISimpleNode_I();
+ }
+
+ virtual spcIUTF8String APICALL GetValue() const {
+ return CallConstSafeFunctionReturningPointer< ISimpleNode_v1, pcIUTF8String_base, const IUTF8String >(
+ mRawPtr, &ISimpleNode_v1::getValue );
+ }
+
+ virtual void APICALL SetValue( const char * value, sizet valueLength ) {
+ return CallSafeFunctionReturningVoid< ISimpleNode_v1, const char *, sizet >(
+ mRawPtr, &ISimpleNode_v1::setValue, value, valueLength );
+ }
+
+ virtual bool APICALL IsURIType() const {
+ return CallConstSafeFunction< ISimpleNode_v1, bool, uint32 >(
+ mRawPtr, &ISimpleNode_v1::isURIType );
+ }
+
+ virtual void APICALL SetURIType( bool isURI ) {
+ return CallSafeFunctionReturningVoid< ISimpleNode_v1, uint32 >(
+ mRawPtr, &ISimpleNode_v1::setURIType, isURI ? 1 : 0 );
+ }
+
+ virtual pcIUTF8String_base APICALL getValue( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getValue( error );
+ }
+
+ virtual void APICALL setValue( const char * value, sizet valueLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->setValue( value, valueLength, error );
+ }
+
+ virtual uint32 APICALL isURIType( pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->isURIType( error );
+ }
+
+ virtual void APICALL setURIType( uint32 isURI, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->setURIType( isURI, error );
+ }
+
+ };
+
+ spISimpleNode ISimpleNode_v1::CreateSimpleNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, const char * value, sizet valueLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pISimpleNode_base, ISimpleNode, const char *, sizet, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateSimpleNode, nameSpace, nameSpaceLength, name, nameLength, value, valueLength );
+ }
+
+ spISimpleNode ISimpleNode_v1::MakeShared( pISimpleNode_base ptr ) {
+ if ( !ptr ) return spISimpleNode();
+ pISimpleNode p = ISimpleNode::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< ISimpleNode >() : ptr;
+ return shared_ptr< ISimpleNode >( new ISimpleNodeProxy( p ) );
+ }
+
+#if XMP_WinBuild
+ #pragma warning( pop )
+#endif
+}
+
+#endif // !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IStructureNode.cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IStructureNode.cpp
new file mode 100644
index 0000000000..32aa76d18f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMPCore/source/IStructureNode.cpp
@@ -0,0 +1,104 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2015 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.
+// =================================================================================================
+
+namespace AdobeXMPCore {
+ class IStructureNodeProxy;
+}
+
+#define FRIEND_CLASS_DECLARATION() friend class AdobeXMPCore::IStructureNodeProxy;
+
+#include "XMPCore/Interfaces/IStructureNode.h"
+
+#if !BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
+
+#include "XMPCommon/Utilities/TWrapperFunctions.h"
+#include "XMPCore/Interfaces/ICoreObjectFactory.h"
+#include <assert.h>
+
+namespace AdobeXMPCore {
+
+
+ IStructureNodeProxy::IStructureNodeProxy( pIStructureNode ptr ) : mRawPtr( ptr )
+ , ICompositeNodeProxy( ptr )
+ , INodeProxy( ptr ) { }
+
+ IStructureNodeProxy::~IStructureNodeProxy() __NOTHROW__ { }
+
+ AdobeXMPCore_Int::pIStructureNode_I APICALL IStructureNodeProxy::GetIStructureNode_I() __NOTHROW__ {
+ return mRawPtr->GetIStructureNode_I();
+ }
+
+ INode_v1::eNodeType APICALL IStructureNodeProxy::GetChildNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) const {
+ return CallConstSafeFunction< IStructureNode_v1, eNodeType, uint32, const char *, sizet, const char *, sizet >(
+ mRawPtr, &IStructureNode_v1::getChildNodeType, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ spINode APICALL IStructureNodeProxy::GetNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< IStructureNode_v1, pINode_base, INode, const char *, sizet, const char *, sizet >(
+ mRawPtr, &IStructureNode_v1::getNode, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ void APICALL IStructureNodeProxy::InsertNode( const spINode & node ) {
+ return CallSafeFunctionReturningVoid< IStructureNode_v1, pINode_base >(
+ mRawPtr, &IStructureNode_v1::insertNode, node ? node->GetActualINode() : NULL );
+ }
+
+ spINode APICALL IStructureNodeProxy::ReplaceNode( const spINode & node ) {
+ return CallSafeFunctionReturningPointer< IStructureNode_v1, pINode_base, INode, pINode_base >(
+ mRawPtr, &IStructureNode_v1::replaceNode, node ? node->GetActualINode() : NULL );
+ }
+
+ spINode APICALL IStructureNodeProxy::RemoveNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< IStructureNode_v1, pINode_base, INode, const char *, sizet, const char *, sizet >(
+ mRawPtr, &IStructureNode_v1::removeNode, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+ uint32 APICALL IStructureNodeProxy::getChildNodeType( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) const __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getChildNodeType( nameSpace, nameSpaceLength, name, nameLength, error );
+ }
+
+ pINode_base APICALL IStructureNodeProxy::getNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->getNode( nameSpace, nameSpaceLength, name, nameLength, error );
+ }
+
+ void APICALL IStructureNodeProxy::insertNode( pINode_base node, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->insertNode( node, error );
+ }
+
+ pINode_base APICALL IStructureNodeProxy::replaceNode( pINode_base node, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->replaceNode( node, error );
+ }
+
+ pINode_base APICALL IStructureNodeProxy::removeNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength, pcIError_base & error ) __NOTHROW__ {
+ assert( false );
+ return mRawPtr->removeNode( nameSpace, nameSpaceLength, name, nameLength, error );
+ }
+
+ pIStructureNode APICALL IStructureNodeProxy::GetActualIStructureNode() __NOTHROW__ {
+ return mRawPtr;
+ }
+
+ spIStructureNode IStructureNode_v1::MakeShared( pIStructureNode_base ptr ) {
+ if ( !ptr ) return spIStructureNode();
+ pIStructureNode p = IStructureNode::GetInterfaceVersion() > 1 ? ptr->GetInterfacePointer< IStructureNode >() : ptr;
+ return shared_ptr< IStructureNode >( new IStructureNodeProxy( p ) );
+ }
+
+ spIStructureNode IStructureNode_v1::CreateStructureNode( const char * nameSpace, sizet nameSpaceLength, const char * name, sizet nameLength ) {
+ return CallSafeFunctionReturningPointer< ICoreObjectFactory, pIStructureNode_base, IStructureNode, const char *, sizet, const char *, sizet >(
+ ICoreObjectFactory::GetCoreObjectFactory(), &ICoreObjectFactory::CreateStructureNode, nameSpace, nameSpaceLength, name, nameLength );
+ }
+
+}
+
+#endif // BUILDING_XMPCORE_LIB && !SOURCE_COMPILING_XMPCORE_LIB
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_Const.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Const.h
similarity index 70%
rename from core/libs/dngwriter/extra/xmp_sdk/include/XMP_Const.h
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Const.h
index 863722f345..144baec19f 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_Const.h
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Const.h
@@ -1,1334 +1,1569 @@
#ifndef __XMP_Const_h__
#define __XMP_Const_h__ 1
// =================================================================================================
-// Copyright 2002-2008 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 "XMP_Environment.h"
- #include <stddef.h>
+ #include <stddef.h>
-#if XMP_MacBuild // ! No stdint.h on Windows and some UNIXes.
+#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
-namespace DngXmpSdk {
+#ifndef XMP_MARKER_EXTENSIBILITY_BACKWARD_COMPATIBILITY
+ #define XMP_MARKER_EXTENSIBILITY_BACKWARD_COMPATIBILITY 1
+#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
+#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;
-#else
+#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;
-/// 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().
+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 );
+
+
+/// @brief 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
+/// @brief 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
+/// @brief 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
+/// @brief 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 &
+/// \brief The type for a collection of 32 flag bits.
+/// @details 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 arithmetic plus, '+'.
+/// 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).
+///@brief Type for yes/no/maybe answers. The values are picked to allow Boolean-like usage. The yes
+///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_Int32 tzSign;
+ 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_iXML "http://ns.adobe.com/ixml/1.0/"
#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_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.
+/// @brief 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:
+/// @brief Option bit flags for the \c TXMPMeta property setting functions.
+/// @details 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().
+/// @brief 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().
+/// @brief 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,
- /// Show aliases as XML comments.
- kXMP_WriteAliasComments = 0x0400UL,
-
/// Omit all formatting whitespace.
kXMP_OmitAllFormatting = 0x0800UL,
/// Omit the x:xmpmeta element surrounding the rdf:RDF element.
- kXMP_OmitXMPMetaElement = 0x1000UL,
+ 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.
+/// @brief 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,
- /// Include aliases, default is just actual properties.
- kXMP_IterIncludeAliases = 0x0800UL,
-
/// Omit all qualifiers.
kXMP_IterOmitQualifiers = 0x1000UL
};
-/// Option bit flags for \c TXMPIterator::Skip().
+/// @brief 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:
+
+/// @brief Option bit flags for \c TXMPUtils::CatenateArrayItems() and \c TXMPUtils::SeparateArrayItems().
+/// @details 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::RemoveProperties() and \c TXMPUtils::AppendProperties().
+/// @brief 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
+
+};
+
+/// @brief 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
// ================================
-/// File format constants for use with XMPFiles.
+/// @brief Seek mode constants for use with XMP_IO and inside XMPFiles library code.
+enum SeekMode { kXMP_SeekFromStart, kXMP_SeekFromCurrent, kXMP_SeekFromEnd };
+
+/// @brief 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: 'AVCU', a collection not really a single file
+ kXMP_AVCUltraFile = 0x41564355UL,
/// Public file format constant: 'HTML'
kXMP_HTMLFile = 0x48544D4CUL,
/// Public file format constant: 'XML '
kXMP_XMLFile = 0x584D4C20UL,
/// Public file format constant: 'text'
kXMP_TextFile = 0x74657874UL,
+ /// Public file format constant: 'SVG '
+ kXMP_SVGFile = 0x53564720UL,
// -------------------------------
// 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
+/// @brief 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.
+/// @brief 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
+/// @brief 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
+/// @brief Version of the XMP_PacketInfo type
enum {
/// Version of the XMP_PacketInfo type
kXMP_PacketInfoVersion = 3
};
// -------------------------------------------------------------------------------------------------
-/// Values for \c XMP_ThumbnailInfo::tnailFormat.
+/// @brief Option bit flags for \c TXMPFiles::Initialize().
enum {
- /// The thumbnail data has an unknown format.
- kXMP_UnknownTNail = 0,
- /// The thumbnail data is a JPEG stream, presumably compressed.
- kXMP_JPEGTNail = 1,
- /// The thumbnail data is a TIFF stream, presumably uncompressed.
- kXMP_TIFFTNail = 2,
- /// The thumbnail data is in the format of Photoshop Image Resource 1036.
- kXMP_PShopTNail = 3
+ /// 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
};
-/// Thumbnail descriptor
-struct XMP_ThumbnailInfo {
-
- /// The format of the containing file.
- XMP_FileFormat fileFormat;
- /// Full image size in pixels.
- XMP_Uns32 fullWidth, fullHeight;
- /// Thumbnail image size in pixels.
- XMP_Uns32 tnailWidth, tnailHeight;
- /// Orientation of full image and thumbnail, as defined by Exif for tag 274.
-
- XMP_Uns16 fullOrientation, tnailOrientation;
- /// Raw image data from the host file, valid for life of the owning \c XMPFiles object. Do not modify!
- const XMP_Uns8 * tnailImage;
- /// The size in bytes of the thumbnail image data.
- XMP_Uns32 tnailSize;
- /// The format of the thumbnail image data.
- XMP_Uns8 tnailFormat;
-
- /// Padding to make the struct's size be a multiple 4.
- XMP_Uns8 pad1, pad2, pad3;
-
- /// Default constructor.
- XMP_ThumbnailInfo() : fileFormat(kXMP_UnknownFile), fullWidth(0), fullHeight(0),
- tnailWidth(0), tnailHeight(0), fullOrientation(0), tnailOrientation(0),
- tnailImage(0), tnailSize(0), tnailFormat(kXMP_UnknownTNail) {};
-
-};
-
-/// Version of the XMP_ThumbnailInfo type
-enum {
- /// Version of the XMP_ThumbnailInfo type
- kXMP_ThumbnailInfoVersion = 1
-};
-
-// -------------------------------------------------------------------------------------------------
-
-/// Option bit flags for \c TXMPFiles::Initialize().
-enum {
- /// Do not initialize QuickTime, the client will.
- kXMPFiles_NoQuickTimeInit = 0x0001
-};
-
-/// Option bit flags for \c TXMPFiles::GetFormatInfo().
+/// @brief 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,
- /// File handler returns native thumbnail.
- kXMPFiles_ReturnsTNail = 0x00000080,
-
/// 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
+ 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().
+/// @brief 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,
- /// Cache thumbnail if possible, \c TXMPFiles::GetThumbnail() will be called.
- kXMPFiles_OpenCacheTNail = 0x00000008,
-
- /// Be strict about locating XMP and reconciling with other forms.
+ /// 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,
- /// Set if calling from background thread.
- kXMPFiles_OpenInBackground = 0x10000000
+ /// When updating a file, spend the effort necessary to optimize file layout.
+ kXMPFiles_OptimizeFileLayout = 0x00000200
};
-// A note about kXMPFiles_OpenInBackground. The XMPFiles handler for .mov files currently uses
-// QuickTime. On Macintosh, calls to Enter/ExitMovies versus Enter/ExitMoviesOnThread must be made.
-// This option is used to signal background use so that the .mov handler can behave appropriately.
-
-/// Option bit flags for \c TXMPFiles::CloseFile().
+/// @brief Option bit flags for \c TXMPFiles::CloseFile().
enum {
/// Write into a temporary file and swap for crash safety.
kXMPFiles_UpdateSafely = 0x0001
};
+
// =================================================================================================
-// Exception codes
-// ===============
+// Error notification and Exceptions
+// =================================
-/// \name Errors Exception handling
+/// \name Error notification and Exceptions
/// @{
///
-/// XMP Tookit errors result in throwing an \c XMP_Error exception. Any exception thrown within the
-/// XMP Toolkit is caught in the toolkit and rethrown as an \c XMP_Error.
+/// @details 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;
+
+/// @brief 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
+};
+
+// -------------------------------------------------------------------------------------------------
+/// @brief 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 );
+
+// -------------------------------------------------------------------------------------------------
+/// @brief 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) {};
+ 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;
};
-/// Exception code constants
+/// @brief XMP_Error exception code constants
enum {
- // --------------------
- // Generic error codes.
+ // --------------------
+ /// 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
+ /// 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,
+/// @brief 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
+/// @brief The signature of a client-defined callback for text output from XMP Toolkit debugging
+/// operations.
+/// @details 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
+/// @brief 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 ); // Used by .
+typedef bool (* XMP_AbortProc) ( void * arg );
+
+// -------------------------------------------------------------------------------------------------
+/// @brief 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
-} //namespace
-
-#endif // __XMP_Const_h__
+#include <vector>
+#endif // __XMP_Const_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_Environment.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Environment.h
similarity index 56%
rename from core/libs/dngwriter/extra/xmp_sdk/include/XMP_Environment.h
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Environment.h
index a315f889df..4a88b0b908 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_Environment.h
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Environment.h
@@ -1,121 +1,192 @@
#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-2007 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.
// =================================================================================================
// =================================================================================================
// Determine the Platform
// ======================
-// One of MAC_ENV, WIN_ENV, or UNIX_ENV must be defined by the client. Since some other code
+// One of MAC_ENV, WIN_ENV, UNIX_ENV or IOS_ENV must be defined by the client. Since some other code
// requires these to be defined without values, they are only used here to define XMP-specific
// macros with 0 or 1 values.
// ! Tempting though it might be to have a standard macro for big or little endian, there seems to
// ! be no decent way to do that on our own in UNIX. Forcing it on the client isn't acceptable.
#if defined ( MAC_ENV )
#if 0 // ! maybe someday - ! MAC_ENV
#error "MAC_ENV must be defined so that \"#if MAC_ENV\" is true"
#endif
-
- #if defined ( WIN_ENV ) || defined ( UNIX_ENV )
- #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, or UNIX_ENV"
+
+ #if defined ( WIN_ENV ) || defined ( UNIX_ENV ) || defined ( IOS_ENV )
+ #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, UNIX_ENV or IOS_ENV"
#endif
#define XMP_MacBuild 1
#define XMP_WinBuild 0
#define XMP_UNIXBuild 0
+ #define XMP_iOSBuild 0
#elif defined ( WIN_ENV )
#if 0 // ! maybe someday - ! WIN_ENV
#error "WIN_ENV must be defined so that \"#if WIN_ENV\" is true"
#endif
-
- #if defined ( UNIX_ENV )
- #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, or UNIX_ENV"
+
+ #if defined ( MAC_ENV ) || defined ( UNIX_ENV ) || defined ( IOS_ENV )
+ #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, UNIX_ENV or IOS_ENV"
#endif
#define XMP_MacBuild 0
#define XMP_WinBuild 1
#define XMP_UNIXBuild 0
+ #define XMP_iOSBuild 0
#elif defined ( UNIX_ENV )
#if 0 // ! maybe someday - ! UNIX_ENV
#error "UNIX_ENV must be defined so that \"#if UNIX_ENV\" is true"
#endif
+
+ #if defined ( MAC_ENV ) || defined ( WIN_ENV ) || defined ( IOS_ENV )
+ #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, UNIX_ENV or IOS_ENV"
+ #endif
#define XMP_MacBuild 0
#define XMP_WinBuild 0
#define XMP_UNIXBuild 1
+ #define XMP_iOSBuild 0
+
+#elif defined ( IOS_ENV )
+
+ #if 0 // ! maybe someday - ! IOS_ENV
+ #error "IOS_ENV must be defined so that \"#if IOS_ENV\" is true"
+ #endif
+
+ #if defined ( MAC_ENV ) || defined ( WIN_ENV ) || defined ( UNIX_ENV )
+ #error "XMP environment error - must define only one of MAC_ENV, WIN_ENV, UNIX_ENV or IOS_ENV"
+ #endif
+
+ #define XMP_MacBuild 0
+ #define XMP_WinBuild 0
+ #define XMP_UNIXBuild 0
+ #define XMP_iOSBuild 1
#else
- #error "XMP environment error - must define one of MAC_ENV, WIN_ENV, or UNIX_ENV"
+ #error "XMP environment error - must define one of MAC_ENV, WIN_ENV, UNIX_ENV or IOS_ENV"
#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
+ #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")))
+ #define APICALL
+#endif
// =================================================================================================
// Windows Specific Settings
// =========================
+#if (XMP_WinBuild)
+ #define XMP_HELPER_DLL_IMPORT
+ #define XMP_HELPER_DLL_EXPORT
+ #define XMP_HELPER_DLL_PRIVATE
+ #define APICALL __stdcall
+#endif
// =================================================================================================
// UNIX Specific Settings
// ======================
+#if (XMP_UNIXBuild)
+ #define XMP_HELPER_DLL_IMPORT
+ #define XMP_HELPER_DLL_EXPORT __attribute__ ((visibility ("default")))
+ #define XMP_HELPER_DLL_PRIVATE __attribute__ ((visibility ("hidden")))
+ #define APICALL
+#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")))
+ #define APICALL
+#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__
+#endif // __XMP_Environment_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_IO.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_IO.hpp
new file mode 100644
index 0000000000..d485392cac
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/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/core/libs/dngwriter/extra/xmp_sdk/include/XMP_Version.h b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Version.h
similarity index 81%
rename from core/libs/dngwriter/extra/xmp_sdk/include/XMP_Version.h
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Version.h
index 0c842d06d5..23d16b7c58 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/XMP_Version.h
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/XMP_Version.h
@@ -1,45 +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-2008 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.
// =================================================================================================
*/
/* ============================================================================================= */
/**
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 XMP_API_VERSION_MAJOR 4
-#define XMP_API_VERSION_MINOR 4
-#define XMP_API_VERSION_MICRO 0
+#define XMPCORE_API_VERSION_MAJOR 5
+#define XMPCORE_API_VERSION_MINOR 6
+#define XMPCORE_API_VERSION_MICRO 0
-#define XMP_API_VERSION 4.4
-#define XMP_API_VERSION_STRING "4.4.0"
+#define XMPCORE_API_VERSION 5.6.0
+#define XMPCORE_API_VERSION_STRING "5.6.0"
+
+#define XMPFILES_API_VERSION_MAJOR 5
+#define XMPFILES_API_VERSION_MINOR 7
+#define XMPFILES_API_VERSION_MICRO 0
+
+#define XMPFILES_API_VERSION 5.7.0
+#define XMPFILES_API_VERSION_STRING "5.7.0"
/* ============================================================================================= */
#endif /* __XMP_Version_h__ */
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPFiles.incl_cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPFiles.incl_cpp
similarity index 65%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPFiles.incl_cpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPFiles.incl_cpp
index dffcb5efef..eb198871d0 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPFiles.incl_cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPFiles.incl_cpp
@@ -1,369 +1,484 @@
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2007 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"
-namespace DngXmpSdk {
+#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_2 ( 0 ) );
+ 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_2 ( 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 */ )
+ 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 */ )
+ 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 */ )
+CloseFile ( XMP_OptionBits closeFlags /* = 0 */ )
{
WrapCheckVoid ( zXMPFiles_CloseFile_1 ( closeFlags ) );
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPFiles,bool)::
GetFileInfo ( tStringObj * filePath /* = 0 */,
- XMP_OptionBits * openFlags /* =0 */,
+ XMP_OptionBits * openFlags /* = 0 */,
XMP_FileFormat * format /* = 0 */,
- XMP_OptionBits * handlerFlags /* =0 */ )
+ XMP_OptionBits * handlerFlags /* = 0 */ )
{
- XMP_StringPtr pathStr;
- XMP_StringLen pathLen;
-
- WrapCheckBool ( isOpen, zXMPFiles_GetFileInfo_1 ( &pathStr, &pathLen, openFlags, format, handlerFlags ) );
- if ( isOpen ) {
- if ( filePath != 0 ) filePath->assign ( pathStr, pathLen );
- WXMPFiles_UnlockObj_1 ( this->xmpFilesRef );
- }
+ 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 */ )
+ XMP_PacketInfo * packetInfo /* = 0 */ )
{
- XMP_StringPtr xmpStr;
- XMP_StringLen xmpLen;
-
XMPMetaRef xmpRef = 0;
if ( xmpObj != 0 ) {
- SXMPUtils::RemoveProperties ( xmpObj, 0, 0, kXMPUtil_DoAllProperties );
- // *** Need an SXMPMeta::Clear method:
+ SXMPUtils::RemoveProperties ( xmpObj, 0, 0, kXMPUtil_DoAllProperties ); // *** Need an SXMPMeta::Clear method:
xmpRef = xmpObj->GetInternalRef();
}
-
- WrapCheckBool ( hasXMP, zXMPFiles_GetXMP_1 ( xmpRef, &xmpStr, &xmpLen, packetInfo ) );
- if ( hasXMP ) {
- if ( xmpPacket != 0 ) xmpPacket->assign ( xmpStr, xmpLen );
- WXMPFiles_UnlockObj_1 ( this->xmpFilesRef );
- }
- return hasXMP;
-}
-// -------------------------------------------------------------------------------------------------
-
-XMP_MethodIntro(TXMPFiles,bool)::
-GetThumbnail ( XMP_ThumbnailInfo * tnailInfo )
-{
- WrapCheckBool ( hasTNail, zXMPFiles_GetThumbnail_1 ( tnailInfo ) );
- return hasTNail;
+ 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() );
}
-} //namespace
+// =================================================================================================
+
+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/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPIterator.incl_cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPIterator.incl_cpp
similarity index 92%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPIterator.incl_cpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPIterator.incl_cpp
index 7738b78a35..0b39d013e8 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPIterator.incl_cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPIterator.incl_cpp
@@ -1,230 +1,223 @@
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2007 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"
-namespace DngXmpSdk {
-
// =================================================================================================
// 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 */ )
{
- XMP_StringPtr schemaPtr = 0;
- XMP_StringLen schemaLen = 0;
- XMP_StringPtr pathPtr = 0;
- XMP_StringLen pathLen = 0;
- XMP_StringPtr valuePtr = 0;
- XMP_StringLen valueLen = 0;
- WrapCheckBool ( found, zXMPIterator_Next_1 ( &schemaPtr, &schemaLen, &pathPtr, &pathLen, &valuePtr, &valueLen, options ) );
- if ( found ) {
- if ( schemaNS != 0 ) schemaNS->assign ( schemaPtr, schemaLen );
- if ( propPath != 0 ) propPath->assign ( pathPtr, pathLen );
- if ( propValue != 0 ) propValue->assign ( valuePtr, valueLen );
- WXMPUtils_UnlockIter_1 ( this->iterRef, 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 ) );
}
-} //namespace
-
// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPMeta.incl_cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPMeta.incl_cpp
similarity index 85%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPMeta.incl_cpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPMeta.incl_cpp
index 899adee186..7f67a3a14f 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPMeta.incl_cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPMeta.incl_cpp
@@ -1,945 +1,917 @@
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2008 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"
-namespace DngXmpSdk {
+
+#include "XMPCore/XMPCoreDefines.h"
+#if ENABLE_CPP_DOM_MODEL
+ #include "XMPCore/Interfaces/IMetadata.h"
+ #include "XMPCore/Interfaces/ICoreObjectFactory.h"
+#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_CPP_DOM_MODEL
+ AdobeXMPCore::ICoreObjectFactory::SetupCoreObjectFactory();
+ #endif
+
return ok;
+
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPMeta,void)::
Terminate()
{
+
+ #if ENABLE_CPP_DOM_MODEL
+ AdobeXMPCore::ICoreObjectFactory::DestroyCoreObjectFactory();
+ #endif
+
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,XMP_Status)::
-DumpAliases ( XMP_TextOutputProc outProc,
- void * refCon )
-{
- TOPW_Info info ( outProc, refCon );
- WrapCheckStatus ( status, zXMPMeta_DumpAliases_1 ( TextOutputProcWrapper, &info ) );
- return status;
-}
-
-// -------------------------------------------------------------------------------------------------
-
XMP_MethodIntro(TXMPMeta,bool)::
RegisterNamespace ( XMP_StringPtr namespaceURI,
XMP_StringPtr suggestedPrefix,
tStringObj * registeredPrefix )
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( prefixMatch, zXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, &resultPtr, &resultLen ) );
- if ( registeredPrefix != 0 ) registeredPrefix->assign ( resultPtr, resultLen );
- WXMPMeta_Unlock_1 ( 0 );
+ WrapCheckBool ( prefixMatch, zXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, registeredPrefix, SetClientString ) );
return prefixMatch;
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPMeta,bool)::
GetNamespacePrefix ( XMP_StringPtr namespaceURI,
tStringObj * namespacePrefix )
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( found, zXMPMeta_GetNamespacePrefix_1 ( namespaceURI, &resultPtr, &resultLen ) );
- if ( found ) {
- if ( namespacePrefix != 0 ) namespacePrefix->assign ( resultPtr, resultLen );
- WXMPMeta_Unlock_1 ( 0 );
- }
+ WrapCheckBool ( found, zXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, SetClientString ) );
return found;
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPMeta,bool)::
GetNamespaceURI ( XMP_StringPtr namespacePrefix,
tStringObj * namespaceURI )
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( found, zXMPMeta_GetNamespaceURI_1 ( namespacePrefix, &resultPtr, &resultLen ) );
- if ( found ) {
- if ( namespaceURI != 0 ) namespaceURI->assign ( resultPtr, resultLen );
- WXMPMeta_Unlock_1 ( 0 );
- }
+ WrapCheckBool ( found, zXMPMeta_GetNamespaceURI_1 ( namespacePrefix, namespaceURI, SetClientString ) );
return found;
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPMeta,void)::
DeleteNamespace ( XMP_StringPtr namespaceURI )
{
WrapCheckVoid ( zXMPMeta_DeleteNamespace_1 ( namespaceURI ) );
}
-// -------------------------------------------------------------------------------------------------
-
-XMP_MethodIntro(TXMPMeta,void)::
-RegisterAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr actualNS,
- XMP_StringPtr actualProp,
- XMP_OptionBits arrayForm )
-{
- WrapCheckVoid ( zXMPMeta_RegisterAlias_1 ( aliasNS, aliasProp, actualNS, actualProp, arrayForm ) );
-}
-
-// -------------------------------------------------------------------------------------------------
-
-XMP_MethodIntro(TXMPMeta,bool)::
-ResolveAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- tStringObj * actualNS,
- tStringObj * actualProp,
- XMP_OptionBits * arrayForm )
-{
- XMP_StringPtr nsPtr = 0;
- XMP_StringLen nsLen = 0;
- XMP_StringPtr propPtr = 0;
- XMP_StringLen propLen = 0;
- WrapCheckBool ( found, zXMPMeta_ResolveAlias_1 ( aliasNS, aliasProp, &nsPtr, &nsLen, &propPtr, &propLen, arrayForm ) );
- if ( found ) {
- if ( actualNS != 0 ) actualNS->assign ( nsPtr, nsLen );
- if ( actualProp != 0 ) actualProp->assign ( propPtr, propLen );
- WXMPMeta_Unlock_1 ( 0 );
- }
- return found;
-}
-
-// -------------------------------------------------------------------------------------------------
-
-XMP_MethodIntro(TXMPMeta,void)::
-DeleteAlias ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp )
-{
- WrapCheckVoid ( zXMPMeta_DeleteAlias_1 ( aliasNS, aliasProp ) );
-}
-
-// -------------------------------------------------------------------------------------------------
-
-XMP_MethodIntro(TXMPMeta,void)::
-RegisterStandardAliases ( XMP_StringPtr schemaNS )
-{
- WrapCheckVoid ( zXMPMeta_RegisterStandardAliases_1 ( schemaNS ) );
-}
-
// =================================================================================================
// Basic property manipulation functions
// =====================================
XMP_MethodIntro(TXMPMeta,bool)::
GetProperty ( XMP_StringPtr schemaNS,
XMP_StringPtr propName,
tStringObj * propValue,
XMP_OptionBits * options ) const
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( found, zXMPMeta_GetProperty_1 ( schemaNS, propName, &resultPtr, &resultLen, options ) );
- if ( found ) {
- if ( propValue != 0 ) propValue->assign ( resultPtr, resultLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
- }
+ 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
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( found, zXMPMeta_GetArrayItem_1 ( schemaNS, arrayName, itemIndex, &resultPtr, &resultLen, options ) );
- if ( found ) {
- if ( itemValue != 0 ) itemValue->assign ( resultPtr, resultLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
- }
+ 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
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( found, zXMPMeta_GetStructField_1 ( schemaNS, structName, fieldNS, fieldName, &resultPtr, &resultLen, options ) );
- if ( found ) {
- if ( fieldValue != 0 ) fieldValue->assign ( resultPtr, resultLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
- }
+ 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
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckBool ( found, zXMPMeta_GetQualifier_1 ( schemaNS, propName, qualNS, qualName, &resultPtr, &resultLen, options ) );
- if ( found ) {
- if ( qualValue != 0 ) qualValue->assign ( resultPtr, resultLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
- }
+ 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
{
- XMP_StringPtr langPtr = 0;
- XMP_StringLen langLen = 0;
- XMP_StringPtr itemPtr = 0;
- XMP_StringLen itemLen = 0;
WrapCheckBool ( found, zXMPMeta_GetLocalizedText_1 ( schemaNS, altTextName, genericLang, specificLang,
- &langPtr, &langLen, &itemPtr, &itemLen, options ) );
- if ( found ) {
- if ( actualLang != 0 ) actualLang->assign ( langPtr, langLen );
- if ( itemValue != 0 ) itemValue->assign ( itemPtr, itemLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, kXMP_NoOptions );
- }
+ 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,
- long * propValue,
+ XMP_Int32 * propValue,
XMP_OptionBits * options ) const
{
- XMP_Int32 abiValue;
- WrapCheckBool ( found, zXMPMeta_GetProperty_Int_1 ( schemaNS, propName, &abiValue, options ) );
- if ( found && (propValue != 0) ) *propValue = abiValue;
+ WrapCheckBool ( found, zXMPMeta_GetProperty_Int_1 ( schemaNS, propName, propValue, options ) );
return found;
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPMeta,bool)::
GetProperty_Int64 ( XMP_StringPtr schemaNS,
XMP_StringPtr propName,
- long long * propValue,
+ XMP_Int64 * propValue,
XMP_OptionBits * options ) const
{
- XMP_Int64 abiValue;
- WrapCheckBool ( found, zXMPMeta_GetProperty_Int64_1 ( schemaNS, propName, &abiValue, options ) );
- if ( found && (propValue != 0) ) *propValue = abiValue;
+ 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,
- long propValue,
+ 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,
- long long propValue,
+ 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 * name ) const
+GetObjectName ( tStringObj * nameStr ) const
{
- XMP_StringPtr namePtr = 0;
- XMP_StringLen nameLen = 0;
- WrapCheckVoid ( zXMPMeta_GetObjectName_1 ( &namePtr, &nameLen ) );
- if ( name != 0 ) name->assign ( namePtr, nameLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+ 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
{
- XMP_StringPtr resultPtr = 0;
- XMP_StringLen resultLen = 0;
- WrapCheckVoid ( zXMPMeta_SerializeToBuffer_1 ( &resultPtr, &resultLen, options, padding, newline, indent, baseIndent ) );
- if ( pktString != 0 ) pktString->assign ( resultPtr, resultLen );
- WXMPMeta_UnlockObject_1 ( this->xmpRef, 0 );
+ 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 );
}
// -------------------------------------------------------------------------------------------------
-} //namespace
+// -------------------------------------------------------------------------------------------------
+
+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/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPUtils.incl_cpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPUtils.incl_cpp
similarity index 80%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPUtils.incl_cpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPUtils.incl_cpp
index bcf4a30597..2cd5baeeda 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/TXMPUtils.incl_cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/TXMPUtils.incl_cpp
@@ -1,497 +1,445 @@
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2002-2008 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"
-namespace DngXmpSdk {
-
// =================================================================================================
// 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 )
{
- XMP_StringPtr pathPtr = 0;
- XMP_StringLen pathLen = 0;
- WrapCheckVoid ( zXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, &pathPtr, &pathLen ) );
- if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr pathPtr = 0;
- XMP_StringLen pathLen = 0;
- WrapCheckVoid ( zXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, &pathPtr, &pathLen ) );
- if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr pathPtr = 0;
- XMP_StringLen pathLen = 0;
- WrapCheckVoid ( zXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, &pathPtr, &pathLen ) );
- if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr pathPtr = 0;
- XMP_StringLen pathLen = 0;
- WrapCheckVoid ( zXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, &pathPtr, &pathLen ) );
- if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr pathPtr = 0;
- XMP_StringLen pathLen = 0;
- WrapCheckVoid ( zXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue,
- &pathPtr, &pathLen ) );
- if ( fullPath != 0 ) fullPath->assign ( pathPtr, pathLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr strPtr = 0;
- XMP_StringLen strLen = 0;
- WrapCheckVoid ( zXMPUtils_ConvertFromBool_1 ( binValue, &strPtr, &strLen ) );
- if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
- WXMPUtils_Unlock_1 ( 0 );
+ WrapCheckVoid ( zXMPUtils_ConvertFromBool_1 ( binValue, strValue, SetClientString ) );
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPUtils,void)::
ConvertFromInt ( long binValue,
XMP_StringPtr format,
tStringObj * strValue )
{
- XMP_StringPtr strPtr = 0;
- XMP_StringLen strLen = 0;
- WrapCheckVoid ( zXMPUtils_ConvertFromInt_1 ( binValue, format, &strPtr, &strLen ) );
- if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
- WXMPUtils_Unlock_1 ( 0 );
+ #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 )
{
- XMP_StringPtr strPtr = 0;
- XMP_StringLen strLen = 0;
- WrapCheckVoid ( zXMPUtils_ConvertFromInt64_1 ( binValue, format, &strPtr, &strLen ) );
- if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
- WXMPUtils_Unlock_1 ( 0 );
+ WrapCheckVoid ( zXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, SetClientString ) );
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPUtils,void)::
ConvertFromFloat ( double binValue,
XMP_StringPtr format,
tStringObj * strValue )
{
- XMP_StringPtr strPtr = 0;
- XMP_StringLen strLen = 0;
- WrapCheckVoid ( zXMPUtils_ConvertFromFloat_1 ( binValue, format, &strPtr, &strLen ) );
- if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
- WXMPUtils_Unlock_1 ( 0 );
+ WrapCheckVoid ( zXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, SetClientString ) );
}
// -------------------------------------------------------------------------------------------------
XMP_MethodIntro(TXMPUtils,void)::
ConvertFromDate ( const XMP_DateTime & binValue,
tStringObj * strValue )
{
- XMP_StringPtr strPtr = 0;
- XMP_StringLen strLen = 0;
- WrapCheckVoid ( zXMPUtils_ConvertFromDate_1 ( binValue, &strPtr, &strLen ) );
- if ( strValue != 0 ) strValue->assign ( strPtr, strLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr encPtr = 0;
- XMP_StringLen encLen = 0;
- WrapCheckVoid ( zXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, &encPtr, &encLen ) );
- if ( encodedStr != 0 ) encodedStr->assign ( encPtr, encLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr rawPtr = 0;
- XMP_StringLen rawLen = 0;
- WrapCheckVoid ( zXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, &rawPtr, &rawLen ) );
- if ( rawStr != 0 ) rawStr->assign ( rawPtr, rawLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr stdStr = 0;
- XMP_StringLen stdLen = 0;
- XMP_StringPtr extStr = 0;
- XMP_StringLen extLen = 0;
- XMP_StringPtr digestStr = 0;
- XMP_StringLen digestLen = 0;
- WrapCheckVoid ( zXMPUtils_PackageForJPEG_1 ( xmpObj.GetInternalRef(),
- &stdStr, &stdLen, &extStr, &extLen, &digestStr, &digestLen ) );
- if ( standardXMP != 0 ) standardXMP->assign ( stdStr, stdLen );
- if ( extendedXMP != 0 ) extendedXMP->assign ( extStr, extLen );
- if ( extendedDigest != 0 ) extendedDigest->assign ( digestStr, digestLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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 )
{
- XMP_StringPtr catedPtr = 0;
- XMP_StringLen catedLen = 0;
WrapCheckVoid ( zXMPUtils_CatenateArrayItems_1 ( xmpObj.GetInternalRef(), schemaNS, arrayName,
- separator, quotes, options, &catedPtr, &catedLen ) );
- if ( catedStr != 0 ) catedStr->assign ( catedPtr, catedLen );
- WXMPUtils_Unlock_1 ( 0 );
+ 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)::
-AppendProperties ( const TXMPMeta<tStringObj> & source,
- TXMPMeta<tStringObj> * dest,
- XMP_OptionBits options /* = 0 */ )
-{
- if ( dest == 0 ) throw XMP_Error ( kXMPErr_BadParam, "Null output SXMPMeta pointer" );
- WrapCheckVoid ( zXMPUtils_AppendProperties_1 ( source.GetInternalRef(), dest->GetInternalRef(), 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 ) );
}
// =================================================================================================
-} //namespace
-
// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPFiles.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPFiles.hpp
new file mode 100644
index 0000000000..2f8bb9abae
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/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.hpp
+/// \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/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPIterator.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPIterator.hpp
similarity index 63%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPIterator.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPIterator.hpp
index db7a27a4c9..e40a1d46ff 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPIterator.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPIterator.hpp
@@ -1,87 +1,74 @@
#if ! __WXMPIterator_hpp__
#define __WXMPIterator_hpp__ 1
// =================================================================================================
-// Copyright 2002-2007 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"
-namespace DngXmpSdk {
-
#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,nsSize,propPath,pathSize,propValue,valueSize,options) \
- WXMPIterator_Next_1 ( this->iterRef, schemaNS, nsSize, propPath, pathSize, propValue, valueSize, 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
-WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
+XMP_PUBLIC WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS,
XMP_StringPtr propName,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef );
-
-extern void
-WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef );
+XMP_PUBLIC WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef );
extern void
-WXMPIterator_Unlock_1 ( XMP_OptionBits options );
+XMP_PUBLIC WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef );
extern void
-WXMPIterator_Next_1 ( XMPIteratorRef iterRef,
- XMP_StringPtr * schemaNS,
- XMP_StringLen * nsSize,
- XMP_StringPtr * propPath,
- XMP_StringLen * pathSize,
- XMP_StringPtr * propValue,
- XMP_StringLen * valueSize,
+XMP_PUBLIC WXMPIterator_Next_1 ( XMPIteratorRef iterRef,
+ void * schemaNS,
+ void * propPath,
+ void * propValue,
XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
extern void
-WXMPIterator_Skip_1 ( XMPIteratorRef iterRef,
+XMP_PUBLIC WXMPIterator_Skip_1 ( XMPIteratorRef iterRef,
XMP_OptionBits options,
WXMP_Result * wResult );
-extern void
-WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef,
- XMP_OptionBits options );
-
// =================================================================================================
#if __cplusplus
} /* extern "C" */
#endif
-} //namespace
-
#endif // __WXMPIterator_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPMeta.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPMeta.hpp
similarity index 68%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPMeta.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPMeta.hpp
index 79b3b59834..af5a11e8c0 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPMeta.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPMeta.hpp
@@ -1,628 +1,635 @@
#if ! __WXMPMeta_hpp__
#define __WXMPMeta_hpp__ 1
// =================================================================================================
-// Copyright 2002-2008 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"
-namespace DngXmpSdk {
-
#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_DumpAliases_1(outProc,refCon) \
- WXMPMeta_DumpAliases_1 ( outProc, refCon, &wResult )
-
-#define zXMPMeta_RegisterNamespace_1(namespaceURI,suggestedPrefix,registeredPrefix,prefixSize) \
- WXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize, &wResult )
+#define zXMPMeta_Use_CPP_DOM_APIs_1(useNewCoreAPIs) \
+ WXMPMeta_Use_CPP_DOM_APIs_1( useNewCoreAPIs, &wResult )
+#define zXMPMeta_RegisterNamespace_1(namespaceURI,suggestedPrefix,actualPrefix,SetClientString) \
+ WXMPMeta_RegisterNamespace_1 ( namespaceURI, suggestedPrefix, actualPrefix, SetClientString, &wResult )
-#define zXMPMeta_GetNamespacePrefix_1(namespaceURI,namespacePrefix,prefixSize) \
- WXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, prefixSize, &wResult )
+#define zXMPMeta_GetNamespacePrefix_1(namespaceURI,namespacePrefix,SetClientString) \
+ WXMPMeta_GetNamespacePrefix_1 ( namespaceURI, namespacePrefix, SetClientString, &wResult )
-#define zXMPMeta_GetNamespaceURI_1(namespacePrefix,namespaceURI,uriSize) \
- WXMPMeta_GetNamespaceURI_1 ( namespacePrefix, namespaceURI, uriSize, &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_RegisterAlias_1(aliasNS,aliasProp,actualNS,actualProp,arrayForm) \
- WXMPMeta_RegisterAlias_1 ( aliasNS, aliasProp, actualNS, actualProp, arrayForm, &wResult )
-
-#define zXMPMeta_ResolveAlias_1(aliasNS,aliasProp,actualNS,nsSize,actualProp,propSize,arrayForm) \
- WXMPMeta_ResolveAlias_1 ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm, &wResult )
+#define zXMPMeta_GetIXMPMetadata_1() \
+ WXMPMeta_GetIXMPMetadata_1( this->xmpRef, &wResult )
-#define zXMPMeta_DeleteAlias_1(aliasNS,aliasProp) \
- WXMPMeta_DeleteAlias_1 ( aliasNS, aliasProp, &wResult )
+#define zXMPMeta_GetProperty_1(schemaNS,propName,propValue,options,SetClientString) \
+ WXMPMeta_GetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, options, SetClientString, &wResult )
-#define zXMPMeta_RegisterStandardAliases_1(schemaNS) \
- WXMPMeta_RegisterStandardAliases_1 ( schemaNS, &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_GetProperty_1(schemaNS,propName,propValue,valueSize,options) \
- WXMPMeta_GetProperty_1 ( this->xmpRef, schemaNS, propName, propValue, valueSize, options, &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_GetArrayItem_1(schemaNS,arrayName,itemIndex,itemValue,valueSize,options) \
- WXMPMeta_GetArrayItem_1 ( this->xmpRef, schemaNS, arrayName, itemIndex, itemValue, valueSize, options, &wResult )
-
-#define zXMPMeta_GetStructField_1(schemaNS,structName,fieldNS,fieldName,fieldValue,valueSize,options) \
- WXMPMeta_GetStructField_1 ( this->xmpRef, schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options, &wResult )
-
-#define zXMPMeta_GetQualifier_1(schemaNS,propName,qualNS,qualName,qualValue,valueSize,options) \
- WXMPMeta_GetQualifier_1 ( this->xmpRef, schemaNS, propName, qualNS, qualName, qualValue, valueSize, options, &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,actualLang,langSize,itemValue,valueSize,options) \
- WXMPMeta_GetLocalizedText_1 ( this->xmpRef, schemaNS, altTextName, genericLang, specificLang, actualLang, langSize, itemValue, valueSize, options, &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(namePtr,nameLen) \
- WXMPMeta_GetObjectName_1 ( this->xmpRef, namePtr, nameLen, &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,pktSize,options,padding,newline,indent,baseIndent) \
- WXMPMeta_SerializeToBuffer_1 ( this->xmpRef, pktString, pktSize, options, padding, newline, indent, baseIndent, &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
-WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info );
+XMP_PUBLIC WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info );
extern void
-WXMPMeta_Initialize_1 ( WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_Initialize_1 ( WXMP_Result * wResult );
extern void
-WXMPMeta_Terminate_1();
-
-extern void
-WXMPMeta_Unlock_1 ( XMP_OptionBits options );
+XMP_PUBLIC WXMPMeta_Terminate_1();
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_CTor_1 ( WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_CTor_1 ( WXMP_Result * wResult );
extern void
-WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef );
+XMP_PUBLIC WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef );
extern void
-WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef );
+XMP_PUBLIC WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult );
extern void
-WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
+XMP_PUBLIC WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
+XMP_PUBLIC WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc,
void * refCon,
WXMP_Result * wResult );
extern void
-WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc,
- void * refCon,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_Use_CPP_DOM_APIs_1( XMP_Bool useNewCoreAPIs,
+ WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
- XMP_StringPtr suggestedPrefix,
- XMP_StringPtr * registeredPrefix,
- XMP_StringLen * prefixSize,
- WXMP_Result * wResult );
-
-extern void
-WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
- XMP_StringPtr * namespacePrefix,
- XMP_StringLen * prefixSize,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI,
+ XMP_StringPtr suggestedPrefix,
+ void * actualPrefix,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
- XMP_StringPtr * namespaceURI,
- XMP_StringLen * uriSize,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI,
+ void * namespacePrefix,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
+XMP_PUBLIC WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix,
+ void * namespaceURI,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
-// -------------------------------------------------------------------------------------------------
-
-extern void
-WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr actualNS,
- XMP_StringPtr actualProp,
- XMP_OptionBits arrayForm,
- WXMP_Result * wResult );
-
-extern void
-WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- XMP_StringPtr * actualNS,
- XMP_StringLen * nsSize,
- XMP_StringPtr * actualProp,
- XMP_StringLen * propSize,
- XMP_OptionBits * arrayForm,
- WXMP_Result * wResult );
-
extern void
-WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS,
- XMP_StringPtr aliasProp,
- WXMP_Result * wResult );
-
-extern void
-WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI,
+ WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef,
- XMP_OptionBits options );
+XMP_PUBLIC WXMPMeta_GetIXMPMetadata_1(XMPMetaRef xmpObjRef,
+WXMP_Result * wResult );
-// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
- XMP_StringPtr * propValue,
- XMP_StringLen * valueSize,
+ void * propValue,
XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_Index itemIndex,
- XMP_StringPtr * itemValue,
- XMP_StringLen * valueSize,
+ void * itemValue,
XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr structName,
XMP_StringPtr fieldNS,
XMP_StringPtr fieldName,
- XMP_StringPtr * fieldValue,
- XMP_StringLen * valueSize,
+ void * fieldValue,
XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
XMP_StringPtr qualNS,
XMP_StringPtr qualName,
- XMP_StringPtr * qualValue,
- XMP_StringLen * valueSize,
+ void * qualValue,
XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult ) /* const */ ;
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
XMP_StringPtr propValue,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
WXMP_Result * wResult );
extern void
-WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_Index itemIndex,
WXMP_Result * wResult );
extern void
-WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr structName,
XMP_StringPtr fieldNS,
XMP_StringPtr fieldName,
WXMP_Result * wResult );
extern void
-WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
XMP_StringPtr qualNS,
XMP_StringPtr qualName,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_Index itemIndex,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr altTextName,
XMP_StringPtr genericLang,
XMP_StringPtr specificLang,
- XMP_StringPtr * actualLang,
- XMP_StringLen * langSize,
- XMP_StringPtr * itemValue,
- XMP_StringLen * valueSize,
+ void * clientLang,
+ void * clientValue,
XMP_OptionBits * options,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr propName,
double propValue,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef,
+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
-WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr * namePtr,
- XMP_StringLen * nameLen,
- WXMP_Result * wResult ) /* const */ ;
+XMP_PUBLIC WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef,
+ void * objName,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef,
XMP_StringPtr name,
WXMP_Result * wResult );
extern void
-WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPMeta_Sort_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_Sort_1 ( XMPMetaRef xmpRef,
WXMP_Result * wResult );
extern void
-WXMPMeta_Erase_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_Erase_1 ( XMPMetaRef xmpRef,
WXMP_Result * wResult );
extern void
-WXMPMeta_Clone_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_Clone_1 ( XMPMetaRef xmpRef,
XMP_OptionBits options,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef,
XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
WXMP_Result * wResult ) /* const */ ;
extern void
-WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef,
XMP_TextOutputProc outProc,
void * refCon,
WXMP_Result * wResult ) /* const */ ;
// -------------------------------------------------------------------------------------------------
extern void
-WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef,
+XMP_PUBLIC WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef,
XMP_StringPtr buffer,
XMP_StringLen bufferSize,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef,
- XMP_StringPtr * pktString,
- XMP_StringLen * pktSize,
- XMP_OptionBits options,
- XMP_StringLen padding,
- XMP_StringPtr newline,
- XMP_StringPtr indent,
- XMP_Index baseIndent,
- WXMP_Result * wResult ) /* const */ ;
+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
-} //namespace
-
#endif // __WXMPMeta_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPUtils.hpp
similarity index 51%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPUtils.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPUtils.hpp
index 69387ce36e..b785357d34 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMPUtils.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMPUtils.hpp
@@ -1,326 +1,314 @@
#if ! __WXMPUtils_hpp__
#define __WXMPUtils_hpp__ 1
// =================================================================================================
-// Copyright 2002-2008 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"
-
-namespace DngXmpSdk {
-
#if __cplusplus
extern "C" {
#endif
// =================================================================================================
-#define zXMPUtils_ComposeArrayItemPath_1(schemaNS,arrayName,itemIndex,fullPath,pathSize) \
- WXMPUtils_ComposeArrayItemPath_1 ( schemaNS, arrayName, itemIndex, fullPath, pathSize, &wResult );
+#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,fullPath,pathSize) \
- WXMPUtils_ComposeStructFieldPath_1 ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize, &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,fullPath,pathSize) \
- WXMPUtils_ComposeQualifierPath_1 ( schemaNS, propName, qualNS, qualName, fullPath, pathSize, &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,fullPath,pathSize) \
- WXMPUtils_ComposeLangSelector_1 ( schemaNS, arrayName, langName, fullPath, pathSize, &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,fullPath,pathSize) \
- WXMPUtils_ComposeFieldSelector_1 ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize, &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,strSize) \
- WXMPUtils_ConvertFromBool_1 ( binValue, strValue, strSize, &wResult );
+#define zXMPUtils_ConvertFromBool_1(binValue,strValue,SetClientString) \
+ WXMPUtils_ConvertFromBool_1 ( binValue, strValue, SetClientString, &wResult );
-#define zXMPUtils_ConvertFromInt_1(binValue,format,strValue,strSize) \
- WXMPUtils_ConvertFromInt_1 ( binValue, format, strValue, strSize, &wResult );
+#define zXMPUtils_ConvertFromInt_1(binValue,format,strValue,SetClientString) \
+ WXMPUtils_ConvertFromInt_1 ( binValue, format, strValue, SetClientString, &wResult );
-#define zXMPUtils_ConvertFromInt64_1(binValue,format,strValue,strSize) \
- WXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, strSize, &wResult );
+#define zXMPUtils_ConvertFromInt64_1(binValue,format,strValue,SetClientString) \
+ WXMPUtils_ConvertFromInt64_1 ( binValue, format, strValue, SetClientString, &wResult );
-#define zXMPUtils_ConvertFromFloat_1(binValue,format,strValue,strSize) \
- WXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, strSize, &wResult );
+#define zXMPUtils_ConvertFromFloat_1(binValue,format,strValue,SetClientString) \
+ WXMPUtils_ConvertFromFloat_1 ( binValue, format, strValue, SetClientString, &wResult );
-#define zXMPUtils_ConvertFromDate_1(binValue,strValue,strSize) \
- WXMPUtils_ConvertFromDate_1 ( binValue, strValue, strSize, &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,encodedLen) \
- WXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, encodedStr, encodedLen, &wResult );
+#define zXMPUtils_EncodeToBase64_1(rawStr,rawLen,encodedStr,SetClientString) \
+ WXMPUtils_EncodeToBase64_1 ( rawStr, rawLen, encodedStr, SetClientString, &wResult );
-#define zXMPUtils_DecodeFromBase64_1(encodedStr,encodedLen,rawStr,rawLen) \
- WXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, rawStr, rawLen, &wResult );
+#define zXMPUtils_DecodeFromBase64_1(encodedStr,encodedLen,rawStr,SetClientString) \
+ WXMPUtils_DecodeFromBase64_1 ( encodedStr, encodedLen, rawStr, SetClientString, &wResult );
-#define zXMPUtils_PackageForJPEG_1(xmpObj,stdStr,stdLen,extStr,extLen,digestStr,digestLen) \
- WXMPUtils_PackageForJPEG_1 ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen, &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,catedPtr,catedLen) \
- WXMPUtils_CatenateArrayItems_1 ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedPtr, catedLen, &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_AppendProperties_1(source,dest,options) \
- WXMPUtils_AppendProperties_1 ( source, dest, 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
-WXMPUtils_Unlock_1 ( XMP_OptionBits options );
-
-// -------------------------------------------------------------------------------------------------
-
-extern void
-WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
+XMP_PUBLIC WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_Index itemIndex,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
+ void * itemPath,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
extern void
-WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
+XMP_PUBLIC WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS,
XMP_StringPtr structName,
XMP_StringPtr fieldNS,
XMP_StringPtr fieldName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
+ void * fieldPath,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
extern void
-WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
+XMP_PUBLIC WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS,
XMP_StringPtr propName,
XMP_StringPtr qualNS,
XMP_StringPtr qualName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
+ void * qualPath,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
extern void
-WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
+XMP_PUBLIC WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_StringPtr langName,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
+ void * selPath,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
extern void
-WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
+XMP_PUBLIC WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_StringPtr fieldNS,
XMP_StringPtr fieldName,
XMP_StringPtr fieldValue,
- XMP_StringPtr * fullPath,
- XMP_StringLen * pathSize,
+ void * selPath,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertFromFloat_1 ( double binValue,
- XMP_StringPtr format,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_ConvertFromFloat_1 ( double binValue,
+ XMP_StringPtr format,
+ void * strValue,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
- XMP_StringPtr * strValue,
- XMP_StringLen * strSize,
+XMP_PUBLIC WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue,
+ void * strValue,
+ SetClientStringProc SetClientString,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
+XMP_PUBLIC WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue,
WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
+XMP_PUBLIC WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue,
WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
+XMP_PUBLIC WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue,
WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
+XMP_PUBLIC WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue,
WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
+XMP_PUBLIC WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue,
XMP_DateTime * binValue,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
+XMP_PUBLIC WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time,
WXMP_Result * wResult );
extern void
-WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
+XMP_PUBLIC WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time,
WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
+XMP_PUBLIC WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time,
WXMP_Result * wResult );
extern void
-WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
+XMP_PUBLIC WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time,
WXMP_Result * wResult );
extern void
-WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
+XMP_PUBLIC WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left,
const XMP_DateTime & right,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
- XMP_StringLen rawLen,
- XMP_StringPtr * encodedStr,
- XMP_StringLen * encodedLen,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr,
+ XMP_StringLen rawLen,
+ void * encodedStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
- XMP_StringLen encodedLen,
- XMP_StringPtr * rawStr,
- XMP_StringLen * rawLen,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr,
+ XMP_StringLen encodedLen,
+ void * rawStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPUtils_PackageForJPEG_1 ( XMPMetaRef xmpObj,
- XMP_StringPtr * stdStr,
- XMP_StringLen * stdLen,
- XMP_StringPtr * extStr,
- XMP_StringLen * extLen,
- XMP_StringPtr * digestStr,
- XMP_StringLen * digestLen,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_PackageForJPEG_1 ( XMPMetaRef xmpObj,
+ void * stdStr,
+ void * extStr,
+ void * digestStr,
+ SetClientStringProc SetClientString,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef fullXMP,
+XMP_PUBLIC WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef fullXMP,
XMPMetaRef extendedXMP,
WXMP_Result * wResult );
// -------------------------------------------------------------------------------------------------
extern void
-WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef xmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr arrayName,
- XMP_StringPtr separator,
- XMP_StringPtr quotes,
- XMP_OptionBits options,
- XMP_StringPtr * catedStr,
- XMP_StringLen * catedLen,
- WXMP_Result * wResult );
+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
-WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef xmpObj,
+XMP_PUBLIC WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef xmpObj,
XMP_StringPtr schemaNS,
XMP_StringPtr arrayName,
XMP_OptionBits options,
XMP_StringPtr catedStr,
WXMP_Result * wResult );
extern void
-WXMPUtils_RemoveProperties_1 ( XMPMetaRef xmpObj,
- XMP_StringPtr schemaNS,
- XMP_StringPtr propName,
- XMP_OptionBits options,
- WXMP_Result * wResult );
+XMP_PUBLIC WXMPUtils_ApplyTemplate_1 ( XMPMetaRef workingXMP,
+ XMPMetaRef templateXMP,
+ XMP_OptionBits options,
+ WXMP_Result * wResult );
extern void
-WXMPUtils_AppendProperties_1 ( XMPMetaRef source,
- XMPMetaRef dest,
+XMP_PUBLIC WXMPUtils_RemoveProperties_1 ( XMPMetaRef xmpObj,
+ XMP_StringPtr schemaNS,
+ XMP_StringPtr propName,
XMP_OptionBits options,
WXMP_Result * wResult );
extern void
-WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef source,
+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
-} //namespace
-
#endif // __WXMPUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMP_Common.hpp b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMP_Common.hpp
similarity index 72%
rename from core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMP_Common.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMP_Common.hpp
index 1741c7d5f4..2fea14923e 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/include/client-glue/WXMP_Common.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/public/include/client-glue/WXMP_Common.hpp
@@ -1,127 +1,132 @@
#if ! __WXMP_Common_hpp__
#define __WXMP_Common_hpp__ 1
-namespace DngXmpSdk {
-
// =================================================================================================
-// Copyright 2002-2007 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.
// =================================================================================================
#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) {};
+ 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 TraceXMPCalls
- #define TraceXMPCalls 0
+#ifndef XMP_TraceClientCalls
+ #define XMP_TraceClientCalls 0
+ #define XMP_TraceClientCallsToFile 0
#endif
-#if ! TraceXMPCalls
+#if ! XMP_TraceClientCalls
#define InvokeCheck(WCallProto) \
WXMP_Result wResult; \
WCallProto; \
PropagateException ( wResult )
#else
- #define InvokeCheck(WCallProto) \
- WXMP_Result wResult; \
- fprintf ( stderr, "WXMP calling: %s\n", #WCallProto ); fflush ( stderr ); \
- WCallProto; \
- if ( wResult.errMessage == 0 ) { \
- fprintf ( stderr, "WXMP back, no error\n" ); fflush ( stderr ); \
- } else { \
- fprintf ( stderr, "WXMP back, error: %s\n", wResult.errMessage ); fflush ( stderr ); \
- } \
+ 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)
+ 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 WrapCheckNewMetadata(result,WCallProto) \
+ InvokeCheck(WCallProto); \
+ void * result = 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" */
+} // extern "C"
#endif
-} //namespace
-
#endif // __WXMP_Common_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/Endian.h b/core/libs/dngwriter/extra/xmp_sdk/source/Endian.h
new file mode 100644
index 0000000000..9df508d6d7
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/Endian.h
@@ -0,0 +1,101 @@
+/**************************************************************************
+*
+* 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.
+*
+**************************************************************************/
+
+#ifndef _Endian_h_
+#define _Endian_h_ 1
+
+#include "public/include/XMP_Environment.h" // ! This must be the first include.
+#include "public/include/XMP_Const.h"
+#include "source/EndianUtils.hpp"
+
+class IEndian
+{
+public:
+ virtual ~IEndian() {};
+
+ virtual XMP_Uns16 getUns16 ( const void* value ) const = 0;
+ virtual XMP_Uns32 getUns32 ( const void* value ) const = 0;
+ virtual XMP_Uns64 getUns64 ( const void* value ) const = 0;
+ virtual float getFloat ( const void* value ) const = 0;
+ virtual double getDouble ( const void* value ) const = 0;
+
+ virtual void putUns16 ( XMP_Uns16 value, void* dest ) const = 0;
+ virtual void putUns32 ( XMP_Uns32 value, void* dest ) const = 0;
+ virtual void putUns64 ( XMP_Uns64 value, void* dest ) const = 0;
+ virtual void putFloat ( float value, void* dest ) const = 0;
+ virtual void putDouble ( double value, void* dest ) const = 0;
+};
+
+
+class LittleEndian : public IEndian
+{
+private:
+ // Private Constructors / operators to prevent direkt creation
+ LittleEndian() {};
+ LittleEndian( const LittleEndian& ) {};
+ LittleEndian& operator=( const LittleEndian& ) { return *this; };
+
+public:
+ // Singleton Factory
+ static const LittleEndian& getInstance()
+ {
+ // Singleton instance (on Stack)
+ static LittleEndian instance;
+
+ return instance;
+ }
+
+ virtual XMP_Uns16 getUns16 ( const void* value ) const { return GetUns16LE( value ); }
+ virtual XMP_Uns32 getUns32 ( const void* value ) const { return GetUns32LE( value ); }
+ virtual XMP_Uns64 getUns64 ( const void* value ) const { return GetUns64LE( value ); }
+ virtual float getFloat ( const void* value ) const { return GetFloatLE( value ); }
+ virtual double getDouble ( const void* value ) const { return GetDoubleLE( value ); }
+
+ virtual void putUns16 ( XMP_Uns16 value, void* dest ) const { PutUns16LE( value, dest ); }
+ virtual void putUns32 ( XMP_Uns32 value, void* dest ) const { PutUns32LE( value, dest ); }
+ virtual void putUns64 ( XMP_Uns64 value, void* dest ) const { PutUns64LE( value, dest ); }
+ virtual void putFloat ( float value, void* dest ) const { PutFloatLE( value, dest ); }
+ virtual void putDouble ( double value, void* dest ) const { PutDoubleLE( value, dest ); }
+}; // LittleEndian
+
+
+class BigEndian : public IEndian
+{
+private:
+ // Private Constructors / operators to prevent direkt creation
+ BigEndian() {};
+ BigEndian( const BigEndian& ) {};
+ BigEndian& operator=( const BigEndian& ) { return *this; };
+
+public:
+ // Singleton Factory
+ static const BigEndian& getInstance()
+ {
+ // Singleton instance (on Stack)
+ static BigEndian instance;
+
+ return instance;
+ }
+
+ virtual XMP_Uns16 getUns16 ( const void* value ) const { return GetUns16BE( value ); }
+ virtual XMP_Uns32 getUns32 ( const void* value ) const { return GetUns32BE( value ); }
+ virtual XMP_Uns64 getUns64 ( const void* value ) const { return GetUns64BE( value ); }
+ virtual float getFloat ( const void* value ) const { return GetFloatBE( value ); }
+ virtual double getDouble ( const void* value ) const { return GetDoubleBE( value ); }
+
+ virtual void putUns16 ( XMP_Uns16 value, void* dest ) const { PutUns16BE( value, dest ); }
+ virtual void putUns32 ( XMP_Uns32 value, void* dest ) const { PutUns32BE( value, dest ); }
+ virtual void putUns64 ( XMP_Uns64 value, void* dest ) const { PutUns64BE( value, dest ); }
+ virtual void putFloat ( float value, void* dest ) const { PutFloatBE( value, dest ); }
+ virtual void putDouble ( double value, void* dest ) const { PutDoubleBE( value, dest ); }
+}; // BigEndian
+
+#endif
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/EndianUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/EndianUtils.hpp
similarity index 71%
rename from core/libs/dngwriter/extra/xmp_sdk/common/EndianUtils.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/EndianUtils.hpp
index df65a80ba5..1ad23d68e1 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/EndianUtils.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/EndianUtils.hpp
@@ -1,422 +1,470 @@
#ifndef __EndianUtils_hpp__
#define __EndianUtils_hpp__ 1
// =================================================================================================
// ADOBE SYSTEMS INCORPORATED
-// Copyright 2006-2007 Adobe Systems Incorporated
+// 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.
// =================================================================================================
-#include "XMP_Environment.h" // ! This must be the first include.
-#include "XMP_Const.h"
+#include "public/include/XMP_Environment.h" // ! This must be the first include.
+#include "public/include/XMP_Const.h"
+
+#if SUNOS_SPARC || SUNOS || XMP_IOS_ARM
+#include "string.h"
+#endif //SUNOS_SPARC || SUNOS || XMP_IOS_ARM
// *** These should be in a more common location. The Unicode conversions of XMPCore have similar utils.
// *** May want to improve with PowerPC swapping load/store, or SSE instructions.
// =================================================================================================
-namespace DngXmpSdk {
+
#define kLittleEndianHost (! kBigEndianHost)
#if XMP_WinBuild
#pragma warning ( disable : 4127 ) // conditional expression is constant
#define kBigEndianHost 0
-#elif XMP_MacBuild
+#elif XMP_MacBuild | XMP_iOSBuild
#if __BIG_ENDIAN__
#define kBigEndianHost 1
#elif __LITTLE_ENDIAN__
#define kBigEndianHost 0
#else
#error "Neither __BIG_ENDIAN__ nor __LITTLE_ENDIAN__ is set"
#endif
#elif XMP_UNIXBuild
#ifndef kBigEndianHost // Typically in the makefile for generic UNIX.
#if __GNUC__ && (__i386__ || __x86_64__)
#define kBigEndianHost 0
+ #elif __GNUC__ && (__sparc__)
+ #define kBigEndianHost 1
+ #define kLittleEndianHost 0
#else
#error "Must define kBigEndianHost as 0 or 1 in the makefile."
#endif
#endif
#else
#error "Unknown build environment"
#endif
// =================================================================================================
typedef XMP_Uns16 (*GetUns16_Proc) ( const void* addr );
typedef XMP_Uns32 (*GetUns32_Proc) ( const void* addr );
typedef XMP_Uns64 (*GetUns64_Proc) ( const void* addr );
typedef float (*GetFloat_Proc) ( const void* addr );
typedef double (*GetDouble_Proc) ( const void* addr );
typedef XMP_Uns16 (*MakeUns16_Proc) ( XMP_Uns16 value );
typedef XMP_Uns32 (*MakeUns32_Proc) ( XMP_Uns32 value );
typedef XMP_Uns64 (*MakeUns64_Proc) ( XMP_Uns64 value );
typedef float (*MakeFloat_Proc) ( float value );
typedef double (*MakeDouble_Proc) ( double value );
typedef void (*PutUns16_Proc) ( XMP_Uns16 value, void* addr );
typedef void (*PutUns32_Proc) ( XMP_Uns32 value, void* addr );
typedef void (*PutUns64_Proc) ( XMP_Uns64 value, void* addr );
typedef void (*PutFloat_Proc) ( float value, void* addr );
typedef void (*PutDouble_Proc) ( double value, void* addr );
// =================================================================================================
+#if SUNOS_SPARC || SUNOS || XMP_IOS_ARM
+ #define DefineAndGetValue(type,addr) type value = 0; memcpy ( &value, addr, sizeof(type) )
+ #define DefineAndSetValue(type,addr) memcpy(addr, &value, sizeof(type))
+ #define DefineFlipAndSet(type,x,addr) type temp; memcpy(&temp, addr, sizeof(type)); temp = Flip##x(temp); memcpy(addr, &temp, sizeof(type))
+#else
+ #define DefineAndGetValue(type,addr) type value = *((type*)addr)
+ #define DefineAndSetValue(type,addr) *((type*)addr) = value
+ #define DefineFlipAndSet(type,x,addr) type* uPtr = (type*) addr; *uPtr = Flip##x ( *uPtr )
+#endif //#if SUNOS_SPARC || SUNOS || XMP_IOS_ARM
+
+// -------------------------------------------------------------------------------------------------
+
static inline XMP_Uns16 Flip2 ( XMP_Uns16 value )
{
value = ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
return value;
}
// -------------------------------------------------------------------------------------------------
static inline void Flip2 ( void * addr )
{
- XMP_Uns16 * u16Ptr = (XMP_Uns16*) addr;
- *u16Ptr = Flip2 ( *u16Ptr );
+ DefineFlipAndSet ( XMP_Uns16, 2, addr );
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns32 Flip4 ( XMP_Uns32 value )
{
value = ((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) |
((value >> 8) & 0x0000FF00) | ((value >> 24) & 0x000000FF);
return value;
}
// -------------------------------------------------------------------------------------------------
static inline void Flip4 ( void * addr )
{
- XMP_Uns32 * u32Ptr = (XMP_Uns32*) addr;
- *u32Ptr = Flip4 ( *u32Ptr );
+ DefineFlipAndSet ( XMP_Uns32, 4, addr );
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns64 Flip8 ( XMP_Uns64 value )
{
XMP_Uns32 oldLow = (XMP_Uns32)(value);
XMP_Uns32 oldHigh = (XMP_Uns32)(value >> 32);
return (((XMP_Uns64)Flip4(oldLow)) << 32) | ((XMP_Uns64)Flip4(oldHigh));
}
// -------------------------------------------------------------------------------------------------
static inline void Flip8 ( void * addr )
{
- XMP_Uns64 * u64Ptr = (XMP_Uns64*) addr;
- *u64Ptr = Flip8 ( *u64Ptr );
+ DefineFlipAndSet ( XMP_Uns64, 8, addr );
}
// =================================================================================================
-static inline XMP_Uns16
-GetUns16BE ( const void * addr )
+static inline XMP_Uns16 GetUns16BE ( const void * addr )
{
- XMP_Uns16 value = *((XMP_Uns16*)addr);
+ DefineAndGetValue ( XMP_Uns16, addr );
if ( kLittleEndianHost ) value = Flip2 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
-static inline XMP_Uns16
-GetUns16LE ( const void * addr )
+static inline XMP_Uns16 GetUns16LE ( const void * addr )
{
- XMP_Uns16 value = *((XMP_Uns16*)addr);
+ DefineAndGetValue ( XMP_Uns16, addr );
if ( kBigEndianHost ) value = Flip2 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
-static inline XMP_Uns32
-GetUns32BE ( const void * addr )
+static inline XMP_Uns16 GetUns16AsIs ( const void * addr )
{
- XMP_Uns32 value = *((XMP_Uns32*)addr);
+ DefineAndGetValue ( XMP_Uns16, addr );
+ return value; // Use this to avoid SPARC failure to handle unaligned loads and stores.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns32 GetUns32BE ( const void * addr )
+{
+ DefineAndGetValue ( XMP_Uns32, addr );
if ( kLittleEndianHost ) value = Flip4 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
-static inline XMP_Uns32
-GetUns32LE ( const void * addr )
+static inline XMP_Uns32 GetUns32LE ( const void * addr )
{
- XMP_Uns32 value = *((XMP_Uns32*)addr);
+ DefineAndGetValue ( XMP_Uns32, addr );
if ( kBigEndianHost ) value = Flip4 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
-static inline XMP_Uns64
-GetUns64BE ( const void * addr )
+static inline XMP_Uns32 GetUns32AsIs ( const void * addr )
{
- XMP_Uns64 value = *((XMP_Uns64*)addr);
+ DefineAndGetValue ( XMP_Uns32, addr );
+ return value; // Use this to avoid SPARC failure to handle unaligned loads and stores.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline XMP_Uns64 GetUns64BE ( const void * addr )
+{
+ DefineAndGetValue ( XMP_Uns64, addr );
if ( kLittleEndianHost ) value = Flip8 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
-static inline XMP_Uns64
-GetUns64LE ( const void * addr )
+static inline XMP_Uns64 GetUns64LE ( const void * addr )
{
- XMP_Uns64 value = *((XMP_Uns64*)addr);
+ DefineAndGetValue ( XMP_Uns64, addr );
if ( kBigEndianHost ) value = Flip8 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
+static inline XMP_Uns64 GetUns64AsIs ( const void * addr )
+{
+ DefineAndGetValue ( XMP_Uns64, addr );
+ return value; // Use this to avoid SPARC failure to handle unaligned loads and stores.
+}
+
+// -------------------------------------------------------------------------------------------------
+
static inline float
GetFloatBE ( const void * addr )
{
XMP_Uns32 value = *((XMP_Uns32*)addr);
if ( kLittleEndianHost ) value = Flip4 ( value );
return *((float*)&value);
}
// -------------------------------------------------------------------------------------------------
static inline float
GetFloatLE ( const void * addr )
{
XMP_Uns32 value = *((XMP_Uns32*)addr);
if ( kBigEndianHost ) value = Flip4 ( value );
return *((float*)&value);
}
// -------------------------------------------------------------------------------------------------
static inline double
GetDoubleBE ( const void * addr )
{
XMP_Uns64 value = *((XMP_Uns64*)addr);
if ( kLittleEndianHost ) value = Flip8 ( value );
return *((double*)&value);
}
// -------------------------------------------------------------------------------------------------
static inline double
GetDoubleLE ( const void * addr )
{
XMP_Uns64 value = *((XMP_Uns64*)addr);
if ( kBigEndianHost ) value = Flip8 ( value );
return *((double*)&value);
}
// =================================================================================================
static inline XMP_Uns16
MakeUns16BE ( XMP_Uns16 value )
{
if ( kLittleEndianHost ) value = Flip2 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns16
MakeUns16LE ( XMP_Uns16 value )
{
if ( kBigEndianHost ) value = Flip2 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns32
MakeUns32BE ( XMP_Uns32 value )
{
if ( kLittleEndianHost ) value = Flip4 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns32
MakeUns32LE ( XMP_Uns32 value )
{
if ( kBigEndianHost ) value = Flip4 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns64
MakeUns64BE ( XMP_Uns64 value )
{
if ( kLittleEndianHost ) value = Flip8 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
static inline XMP_Uns64
MakeUns64LE ( XMP_Uns64 value )
{
if ( kBigEndianHost ) value = Flip8 ( value );
return value;
}
// -------------------------------------------------------------------------------------------------
static inline float
MakeFloatBE ( float value )
{
if ( kLittleEndianHost ) {
XMP_Uns32* intPtr = (XMP_Uns32*) &value;
*intPtr = Flip4 ( *intPtr );
}
return value;
}
// -------------------------------------------------------------------------------------------------
static inline float
MakeFloatLE ( float value )
{
if ( kBigEndianHost ) {
XMP_Uns32* intPtr = (XMP_Uns32*) &value;
*intPtr = Flip4 ( *intPtr );
}
return value;
}
// -------------------------------------------------------------------------------------------------
static inline double
MakeDoubleBE ( double value )
{
if ( kLittleEndianHost ) {
XMP_Uns64* intPtr = (XMP_Uns64*) &value;
*intPtr = Flip8 ( *intPtr );
}
return value;
}
// -------------------------------------------------------------------------------------------------
static inline double
MakeDoubleLE ( double value )
{
if ( kBigEndianHost ) {
XMP_Uns64* intPtr = (XMP_Uns64*) &value;
*intPtr = Flip8 ( *intPtr );
}
return value;
}
// =================================================================================================
-static inline void
-PutUns16BE ( XMP_Uns16 value, void * addr )
+static inline void PutUns16BE ( XMP_Uns16 value, void * addr )
{
if ( kLittleEndianHost ) value = Flip2 ( value );
- *((XMP_Uns16*)addr) = value;
+ DefineAndSetValue ( XMP_Uns16, addr );
}
// -------------------------------------------------------------------------------------------------
-static inline void
-PutUns16LE ( XMP_Uns16 value, void * addr )
+static inline void PutUns16LE ( XMP_Uns16 value, void * addr )
{
if ( kBigEndianHost ) value = Flip2 ( value );
- *((XMP_Uns16*)addr) = value;
+ DefineAndSetValue ( XMP_Uns16, addr );
}
// -------------------------------------------------------------------------------------------------
-static inline void
-PutUns32BE ( XMP_Uns32 value, void * addr )
+static inline void PutUns16AsIs ( XMP_Uns16 value, void * addr )
+{
+ DefineAndSetValue ( XMP_Uns16, addr ); // Use this to avoid SPARC failure to handle unaligned loads and stores.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void PutUns32BE ( XMP_Uns32 value, void * addr )
{
if ( kLittleEndianHost ) value = Flip4 ( value );
- *((XMP_Uns32*)addr) = value;
+ DefineAndSetValue ( XMP_Uns32, addr );
}
// -------------------------------------------------------------------------------------------------
-static inline void
-PutUns32LE ( XMP_Uns32 value, void * addr )
+static inline void PutUns32LE ( XMP_Uns32 value, void * addr )
{
if ( kBigEndianHost ) value = Flip4 ( value );
- *((XMP_Uns32*)addr) = value;
+ DefineAndSetValue ( XMP_Uns32, addr );
}
// -------------------------------------------------------------------------------------------------
-static inline void
-PutUns64BE ( XMP_Uns64 value, void * addr )
+static inline void PutUns32AsIs ( XMP_Uns32 value, void * addr )
+{
+ DefineAndSetValue ( XMP_Uns32, addr ); // Use this to avoid SPARC failure to handle unaligned loads and stores.
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void PutUns64BE ( XMP_Uns64 value, void * addr )
{
if ( kLittleEndianHost ) value = Flip8 ( value );
- *((XMP_Uns64*)addr) = value;
+ DefineAndSetValue ( XMP_Uns64, addr );
}
// -------------------------------------------------------------------------------------------------
-static inline void
-PutUns64LE ( XMP_Uns64 value, void * addr )
+static inline void PutUns64LE ( XMP_Uns64 value, void * addr )
{
if ( kBigEndianHost ) value = Flip8 ( value );
- *((XMP_Uns64*)addr) = value;
+ DefineAndSetValue ( XMP_Uns64, addr );
+}
+
+// -------------------------------------------------------------------------------------------------
+
+static inline void PutUns64AsIs ( XMP_Uns64 value, void * addr )
+{
+ DefineAndSetValue ( XMP_Uns64, addr ); // Use this to avoid SPARC failure to handle unaligned loads and stores.
}
// -------------------------------------------------------------------------------------------------
static inline void
PutFloatBE ( float value, void * addr )
{
if ( kLittleEndianHost ) {
XMP_Uns32* intPtr = (XMP_Uns32*) &value;
*intPtr = Flip4 ( *intPtr );
}
*((float*)addr) = value;
}
// -------------------------------------------------------------------------------------------------
static inline void
PutFloatLE ( float value, void * addr )
{
if ( kBigEndianHost ) {
XMP_Uns32* intPtr = (XMP_Uns32*) &value;
*intPtr = Flip4 ( *intPtr );
}
*((float*)addr) = value;
}
// -------------------------------------------------------------------------------------------------
static inline void
PutDoubleBE ( double value, void * addr )
{
if ( kLittleEndianHost ) {
XMP_Uns64* intPtr = (XMP_Uns64*) &value;
*intPtr = Flip8 ( *intPtr );
}
*((double*)addr) = value;
}
// -------------------------------------------------------------------------------------------------
static inline void
PutDoubleLE ( double value, void * addr )
{
if ( kBigEndianHost ) {
XMP_Uns64* intPtr = (XMP_Uns64*) &value;
*intPtr = Flip8 ( *intPtr );
}
*((double*)addr) = value;
}
// =================================================================================================
-} //namespace
#endif // __EndianUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/ExpatAdapter.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/ExpatAdapter.hpp
similarity index 56%
rename from core/libs/dngwriter/extra/xmp_sdk/common/ExpatAdapter.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/ExpatAdapter.hpp
index 3884acee27..2f3a73211c 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/ExpatAdapter.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/ExpatAdapter.hpp
@@ -1,52 +1,59 @@
#ifndef __ExpatAdapter_hpp__
#define __ExpatAdapter_hpp__
// =================================================================================================
-// Copyright 2005-2008 Adobe Systems Incorporated
+// 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 "XMP_Environment.h" // ! Must be the first #include!
-#include "XMLParserAdapter.hpp"
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "source/XMLParserAdapter.hpp"
// =================================================================================================
// Derived XML parser adapter for Expat.
// =================================================================================================
-struct XML_ParserStruct; // ! Hack to avoid exposing expat.h to all clients.
-typedef struct XML_ParserStruct *XML_Parser;
#ifndef BanAllEntityUsage
- #define BanAllEntityUsage 0
+ #define BanAllEntityUsage 0
#endif
-namespace DngXmpSdk {
-
+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;
-
- #if BanAllEntityUsage
- bool isAborted;
- #endif
-
- #if XMP_DebugBuild
- size_t elemNesting;
- #endif
-
- ExpatAdapter();
- virtual ~ExpatAdapter();
-
- void ParseBuffer ( const void * buffer, size_t length, bool last = true );
+ 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_NewExpatAdapter();
+extern "C" ExpatAdapter *
+XMP_PUBLIC XMP_NewExpatAdapter ( bool useGlobalNamespaces );
// =================================================================================================
-} //namespace
+
#endif // __ExpatAdapter_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO-POSIX.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO-POSIX.cpp
new file mode 100644
index 0000000000..5f71a28b0e
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO-POSIX.cpp
@@ -0,0 +1,560 @@
+// =================================================================================================
+// 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 "public/include/XMP_Environment.h" // ! This must be the first include.
+
+#include "source/Host_IO.hpp"
+#include "source/XMP_LibUtils.hpp"
+
+#include <cstring>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if (SUNOS_SPARC || SUNOS_X86 || XMP_IOS_ARM)
+ #include <limits.h>
+#endif
+
+// =================================================================================================
+// Host_IO implementations for POSIX
+// =================================
+
+#if (! XMP_MacBuild) & (! XMP_UNIXBuild) & (! XMP_iOSBuild)
+ #error "This is the POSIX implementation of Host_IO for Mac, iOS and general UNIX."
+#endif
+
+// =================================================================================================
+// ====================================== File operations ======================================
+// =================================================================================================
+
+// Make sure off_t is 64 bits and signed.
+static char check_off_t_size [ (sizeof(off_t) == 8) ? 1 : -1 ];
+// *** No std::numeric_limits? static char check_off_t_sign [ std::numeric_limits<off_t>::is_signed ? -1 : 1 ];
+
+static bool HaveWriteAccess( const std::string & path );
+
+// =================================================================================================
+// Host_IO::Exists
+// ===============
+
+bool Host_IO::Exists ( const char* filePath )
+{
+ struct stat info;
+ int err = stat ( filePath, &info );
+ return (err == 0);
+}
+
+// =================================================================================================
+// Host_IO::Writable
+// ===============
+bool Host_IO::Writable( const char * path, bool checkCreationPossible )
+{
+ if ( Exists( path ) )
+ {
+ switch ( GetFileMode( path ) )
+ {
+ case kFMode_IsFile:
+ case kFMode_IsFolder:
+ return HaveWriteAccess( path );
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+ else if ( checkCreationPossible )
+ {
+ // get the parent path
+ std::string utf8Path(path);
+ size_t pos = utf8Path.find_last_of('/');
+ if (pos != std::string::npos)
+ {
+ if (pos == 0)
+ utf8Path = utf8Path.substr(0, 1);
+ else
+ utf8Path = utf8Path.substr(0, pos);
+ }
+ else
+ {
+ utf8Path = ".";
+ }
+ return Host_IO::Writable( utf8Path.c_str(), checkCreationPossible );
+ }
+ else
+ return true;
+
+}
+
+// =================================================================================================
+// Host_IO::Create
+// ===============
+
+bool Host_IO::Create ( const char* filePath )
+{
+ if ( Host_IO::Exists ( filePath ) ) {
+ if ( Host_IO::GetFileMode ( filePath ) == kFMode_IsFile ) return false;
+ XMP_Throw ( "Host_IO::Create, path exists but is not a file", kXMPErr_InternalFailure );
+ }
+
+ mode_t mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ int refNum = open ( filePath, (O_CREAT | O_EXCL | O_RDWR), mode ); // *** Include O_EXLOCK?
+ if ( refNum == -1 ) XMP_Throw ( "Host_IO::Create, cannot create file", kXMPErr_InternalFailure );
+ close ( refNum );
+ return true;
+
+} // Host_IO::Create
+
+// =================================================================================================
+// ConvertPosixDateTime
+// ====================
+
+static void ConvertPosixDateTime ( const time_t & osTime, XMP_DateTime * xmpTime )
+{
+ struct tm posixUTC;
+ gmtime_r ( &osTime, &posixUTC );
+
+ xmpTime->year = posixUTC.tm_year + 1900;
+ xmpTime->month = posixUTC.tm_mon + 1;
+ xmpTime->day = posixUTC.tm_mday;
+ xmpTime->hasDate = true;
+
+ xmpTime->hour = posixUTC.tm_hour;
+ xmpTime->minute = posixUTC.tm_min;
+ xmpTime->second = posixUTC.tm_sec;
+ xmpTime->nanoSecond = 0; // The time_t resolution is only to seconds.
+ xmpTime->hasTime = true;
+
+ xmpTime->tzSign = kXMP_TimeIsUTC;
+ xmpTime->tzHour = 0;
+ xmpTime->tzMinute = 0;
+ xmpTime->hasTimeZone = true;
+
+} // ConvertPosixDateTime
+
+// =================================================================================================
+// Host_IO::GetModifyDate
+// ======================
+
+bool Host_IO::GetModifyDate ( const char* filePath, XMP_DateTime* modifyDate )
+{
+ struct stat info;
+ int err = stat ( filePath, &info );
+ if ( err != 0 ) return false;
+ if ( (! S_ISREG(info.st_mode)) && (! S_ISDIR(info.st_mode)) ) return false;
+
+ if ( modifyDate != 0 ) ConvertPosixDateTime ( info.st_mtime, modifyDate );
+ return true;
+
+} // Host_IO::GetModifyDate
+
+// =================================================================================================
+// ConjureDerivedPath
+// ==================
+
+static std::string ConjureDerivedPath ( const char* basePath )
+{
+ std::string tempPath = basePath;
+ tempPath += "._nn_";
+ char * indexPart = (char*) tempPath.c_str() + strlen(basePath) + 2;
+
+ for ( char ten = '0'; ten <= '9' ; ++ten ) {
+ indexPart[0] = ten;
+ for ( char one = '0'; one <= '9' ; ++one ) {
+ indexPart[1] = one;
+ if ( ! Host_IO::Exists ( tempPath.c_str() ) ) return tempPath;
+ }
+ }
+
+ return "";
+
+} // ConjureDerivedPath
+
+// =================================================================================================
+// Host_IO::CreateTemp
+// ===================
+
+std::string Host_IO::CreateTemp ( const char* sourcePath )
+{
+ std::string tempPath = ConjureDerivedPath ( sourcePath );
+ if ( tempPath.empty() ) XMP_Throw ( "Host_IO::CreateTemp, cannot create temp file path", kXMPErr_InternalFailure );
+ XMP_Assert ( ! Host_IO::Exists ( tempPath.c_str() ) );
+
+ Host_IO::Create ( tempPath.c_str() );
+ return tempPath;
+
+} // Host_IO::CreateTemp
+
+// =================================================================================================
+// Host_IO::Open
+// =============
+//
+// Returns Host_IO::noFileRef (0) if the file does not exist, throws for other errors.
+
+Host_IO::FileRef Host_IO::Open ( const char* filePath, bool readOnly )
+{
+ int flags = (readOnly ? O_RDONLY : O_RDWR); // *** Include O_EXLOCK?
+
+ int refNum = open ( filePath, flags, ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ) );
+ if ( refNum == -1 ) {
+ int osCode = errno; // Capture ASAP and once, might not be thread safe.
+ if ( osCode == ENOENT ) {
+ return Host_IO::noFileRef;
+ } else if ( osCode == EACCES ) {
+ XMP_Throw ( "Host_IO::Open, file permission error", kXMPErr_FilePermission );
+ } else {
+ XMP_Throw ( "Host_IO::Open, other failure", kXMPErr_ExternalFailure );
+ }
+ }
+
+ if ( ! readOnly ) {
+ // A root user might be able to open a write-protected file w/o complaint.
+ struct stat info;
+ if ( fstat ( refNum, &info ) == -1 ) XMP_Throw ( "Host_IO::Open, fstat failed.", kXMPErr_ExternalFailure );
+ if ( 0 == (info.st_mode & S_IWUSR) ) XMP_Throw ( "Host_IO::Open, file permission error", kXMPErr_FilePermission );
+ }
+
+ return refNum;
+
+} // Host_IO::Open
+
+// =================================================================================================
+// Host_IO::Close
+// ==============
+
+void Host_IO::Close ( Host_IO::FileRef refNum )
+{
+ if ( refNum == Host_IO::noFileRef ) return;
+
+ int err = close ( refNum );
+ if ( err != 0 ) XMP_Throw ( "Host_IO::Close, close failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::Close
+
+// =================================================================================================
+// Host_IO::SwapData
+// =================
+
+void Host_IO::SwapData ( const char* sourcePath, const char* destPath )
+{
+ // For lack of a better approach, do a 3-way rename.
+
+ std::string thirdPath = ConjureDerivedPath ( sourcePath );
+ if ( thirdPath.empty() ) XMP_Throw ( "Cannot create temp file path", kXMPErr_InternalFailure );
+ XMP_Assert ( ! Host_IO::Exists ( thirdPath.c_str() ) );
+
+ Host_IO::Rename ( sourcePath, thirdPath.c_str() );
+
+ try {
+ Host_IO::Rename ( destPath, sourcePath );
+ } catch ( ... ) {
+ Host_IO::Rename ( thirdPath.c_str(), sourcePath );
+ throw;
+ }
+
+ try {
+ Host_IO::Rename ( thirdPath.c_str(), destPath );
+ } catch ( ... ) {
+ Host_IO::Rename ( sourcePath, destPath );
+ Host_IO::Rename ( thirdPath.c_str(), sourcePath );
+ throw;
+ }
+
+} // Host_IO::SwapData
+
+// =================================================================================================
+// Host_IO::Rename
+// ===============
+
+void Host_IO::Rename ( const char* oldPath, const char* newPath )
+{
+ if ( Host_IO::Exists ( newPath ) ) XMP_Throw ( "Host_IO::Rename, new path exists", kXMPErr_InternalFailure );
+ int err = rename ( oldPath, newPath );
+ if ( err != 0 ) XMP_Throw ( "Host_IO::Rename, rename failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::Rename
+
+// =================================================================================================
+// Host_IO::Delete
+// ===============
+
+void Host_IO::Delete ( const char* filePath )
+{
+ int err;
+
+ switch ( Host_IO::GetFileMode ( filePath ) ) {
+
+ case Host_IO::kFMode_DoesNotExist :
+ return;
+
+ case Host_IO::kFMode_IsFile :
+ err = unlink ( filePath );
+ if ( err != 0 ) XMP_Throw ( "Host_IO::Delete, unlink failure", kXMPErr_ExternalFailure );
+ return;
+
+ case Host_IO::kFMode_IsFolder :
+ err = rmdir ( filePath );
+ if ( err != 0 ) XMP_Throw ( "Host_IO::Delete, rmdir failure", kXMPErr_ExternalFailure );
+ return;
+
+ case Host_IO::kFMode_IsOther :
+ XMP_Throw ( "Host_IO::Delete, can't delete 'other' file", kXMPErr_ExternalFailure );
+
+ }
+
+} // Host_IO::Delete
+
+// =================================================================================================
+// Host_IO::Seek
+// =============
+
+XMP_Int64 Host_IO::Seek ( Host_IO::FileRef refNum, XMP_Int64 offset, SeekMode mode )
+{
+ int posMode;
+ switch ( mode ) {
+ case kXMP_SeekFromStart :
+ posMode = SEEK_SET;
+ break;
+ case kXMP_SeekFromCurrent :
+ posMode = SEEK_CUR;
+ break;
+ case kXMP_SeekFromEnd :
+ posMode = SEEK_END;
+ break;
+ default :
+ XMP_Throw ( "Host_IO::Seek, Invalid seek mode", kXMPErr_InternalFailure );
+ break;
+ }
+
+ XMP_Int64 newPos = (XMP_Int64) lseek ( refNum, offset, mode );
+ if ( newPos == -1 ) XMP_Throw ( "Host_IO::Seek, lseek failure", kXMPErr_ExternalFailure );
+
+ return newPos;
+
+} // Host_IO::Seek
+
+// =================================================================================================
+// Host_IO::Read
+// =============
+
+#define TwoGB (XMP_Uns32)(2*1024*1024*1024UL)
+
+XMP_Uns32 Host_IO::Read ( Host_IO::FileRef refNum, void * buffer, XMP_Uns32 count )
+{
+ if ( count >= TwoGB ) XMP_Throw ( "Host_IO::Read, request too large", kXMPErr_EnforceFailure );
+
+ ssize_t bytesRead = read ( refNum, buffer, count );
+ if ( bytesRead == -1 ) XMP_Throw ( "Host_IO::Read, read failure", kXMPErr_ReadError );
+
+ return static_cast<XMP_Uns32>( bytesRead );
+
+} // Host_IO::Read
+
+// =================================================================================================
+// Host_IO::Write
+// ==============
+
+void Host_IO::Write ( Host_IO::FileRef refNum, const void * buffer, XMP_Uns32 count )
+{
+ if ( count >= TwoGB ) XMP_Throw ( "Host_IO::Write, request too large", kXMPErr_EnforceFailure );
+
+ ssize_t bytesWritten = write ( refNum, buffer, count );
+ if ( bytesWritten != (ssize_t)count ) {
+ int osCode = errno; // Capture ASAP and once, might not be thread safe.
+ if ( errno == ENOSPC ) {
+ XMP_Throw ( "Host_IO::Write, disk full", kXMPErr_DiskSpace );
+ } else {
+ XMP_Throw ( "Host_IO::Write, write failure", kXMPErr_WriteError );
+ }
+ }
+
+} // Host_IO::Write
+
+// =================================================================================================
+// Host_IO::Length
+// ===============
+
+XMP_Int64 Host_IO::Length ( Host_IO::FileRef refNum )
+{
+ off_t currPos = lseek ( refNum, 0, kXMP_SeekFromCurrent );
+ off_t length = lseek ( refNum, 0, kXMP_SeekFromEnd );
+ if ( (currPos == -1) || (length == -1) ) XMP_Throw ( "Host_IO::Length, lseek failure", kXMPErr_ExternalFailure );
+ (void) lseek ( refNum, currPos, kXMP_SeekFromStart );
+
+ return length;
+
+} // Host_IO::Length
+
+// =================================================================================================
+// Host_IO::SetEOF
+// ===============
+
+void Host_IO::SetEOF ( Host_IO::FileRef refNum, XMP_Int64 length )
+{
+ int err = ftruncate ( refNum, length );
+ if ( err != 0 ) XMP_Throw ( "Host_IO::SetEOF, ftruncate failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::SetEOF
+
+// =================================================================================================
+// ===================================== Folder operations =====================================
+// =================================================================================================
+
+// =================================================================================================
+// Host_IO::GetFileMode
+// ====================
+
+Host_IO::FileMode Host_IO::GetFileMode ( const char * path )
+{
+ struct stat fileInfo;
+
+ int err = stat ( path, &fileInfo );
+ if ( err != 0 ) return kFMode_DoesNotExist; // ! Any failure turns into does-not-exist.
+
+ // ! The target of a symlink is properly recognized, not the symlink itself. A Mac alias is
+ // ! seen as a file, we would need extra code to recognize it and find the target.
+
+ if ( S_ISREG ( fileInfo.st_mode ) ) return kFMode_IsFile;
+ if ( S_ISDIR ( fileInfo.st_mode ) ) return kFMode_IsFolder;
+ return kFMode_IsOther;
+
+} // Host_IO::GetFileMode
+
+// =================================================================================================
+// Host_IO::GetChildMode
+// =====================
+
+Host_IO::FileMode Host_IO::GetChildMode ( const char * parentPath, const char * childName )
+{
+ std::string fullPath = parentPath;
+ char lastChar = fullPath[fullPath.length() -1];
+ if ( lastChar != '/' )
+ fullPath += '/';
+ fullPath += childName;
+
+ return GetFileMode ( fullPath.c_str() );
+
+} // Host_IO::GetChildMode
+
+// =================================================================================================
+// Host_IO::OpenFolder
+// ===================
+
+Host_IO::FolderRef Host_IO::OpenFolder ( const char* folderPath )
+{
+ switch ( Host_IO::GetFileMode ( folderPath ) ) {
+
+ case Host_IO::kFMode_IsFolder :
+ {
+ Host_IO::FolderRef folder = opendir ( folderPath );
+ if ( folder == noFolderRef ) XMP_Throw ( "Host_IO::OpenFolder, opendir failed", kXMPErr_ExternalFailure );
+ return folder;
+ }
+
+ case Host_IO::kFMode_DoesNotExist :
+ return Host_IO::noFolderRef;
+
+ default :
+ XMP_Throw ( "Host_IO::OpenFolder, path is not a folder", kXMPErr_ExternalFailure );
+
+ }
+
+ XMP_Throw ( "Host_IO::OpenFolder, should not get here", kXMPErr_InternalFailure );
+
+} // Host_IO::OpenFolder
+
+// =================================================================================================
+// Host_IO::CloseFolder
+// ====================
+
+void Host_IO::CloseFolder ( Host_IO::FolderRef folder )
+{
+ if ( folder == noFolderRef ) return;
+
+ int err = closedir ( folder );
+ if ( err != 0 ) XMP_Throw ( "Host_IO::CloseFolder, closedir failed", kXMPErr_ExternalFailure );
+
+} // Host_IO::CloseFolder
+
+// =================================================================================================
+// Host_IO::GetNextChild
+// =====================
+
+#if (SUNOS_SPARC || SUNOS_X86 || XMP_IOS_ARM)
+ class SafeMalloc {
+ public:
+ void* pointer;
+ void* GetPointer() { return this->pointer; };
+ SafeMalloc ( size_t size ) { this->pointer = malloc ( size ); };
+ ~SafeMalloc() { if ( this->pointer != 0 ) free ( this->pointer ); };
+ private:
+ SafeMalloc() : pointer(0) {}; // Hidden on purpose.
+ };
+#endif
+
+bool Host_IO::GetNextChild ( Host_IO::FolderRef folder, std::string* childName )
+{
+ struct dirent * result;
+
+ if ( folder == Host_IO::noFolderRef ) return false;
+
+ #if ! (SUNOS_SPARC || SUNOS_X86 || XMP_IOS_ARM)
+ struct dirent _childInfo;
+ struct dirent* childInfo = &_childInfo;
+ #else
+ SafeMalloc sm ( offsetof ( struct dirent, d_name ) + PATH_MAX + 1 );
+ struct dirent* childInfo = (struct dirent *) sm.GetPointer();
+ if ( childInfo == 0 ) XMP_Throw ( "Can't allocate SunOS OR IOS childInfo", kXMPErr_NoMemory );
+ #endif
+
+ while ( true ) {
+ // Ignore all children with names starting in '.'. This covers ., .., .DS_Store, etc.
+ // ! On AIX readdir_r returns 9 instead of 0 for normal termination.
+ int err = readdir_r ( folder, childInfo, &result ); // ! Use the thread-safe form.
+ if ( err == 9 ) return false; // Tolerable should some other UNIX return 9.
+ if ( err != 0 ) XMP_Throw ( "Host_IO::GetNextChild, readdir_r failed", kXMPErr_ExternalFailure );
+ if ( result == 0 ) return false;
+ if ( childInfo->d_name[0] != '.' ) break;
+ }
+
+ if ( childName != 0 ) *childName = childInfo->d_name;
+ return true;
+
+} // Host_IO::GetNextChild
+
+// =================================================================================================
+// Writable
+// =====================
+
+static bool HaveWriteAccess( const std::string & path )
+{
+ return ( access(path.c_str(), W_OK) == 0 );
+}
+
+std::string Host_IO::GetCasePreservedName(const std::string& inputPath)
+{
+ char* systemPath=NULL;
+ if ( Host_IO::Exists ( inputPath.c_str() ) )
+ {
+ systemPath=realpath( inputPath.c_str() , NULL );
+ if ( systemPath != NULL )
+ {
+ std::string fullPath(systemPath);
+ free(systemPath);
+ return fullPath;
+ }
+ }
+ return std::string("");
+}
+// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO-Win.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO-Win.cpp
new file mode 100644
index 0000000000..71551afb34
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO-Win.cpp
@@ -0,0 +1,819 @@
+// =================================================================================================
+// 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 "public/include/XMP_Environment.h" // ! This must be the first include.
+
+#include "source/Host_IO.hpp"
+#include "source/XMP_LibUtils.hpp"
+#include "source/XIO.hpp"
+#include "source/UnicodeConversions.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+// =================================================================================================
+// Host_IO implementations for Windows
+// ===================================
+
+#if ! XMP_WinBuild
+ #error "This is the Windows implementation of Host_IO."
+#endif
+
+static bool IsLongPath ( const std::string& path );
+static bool IsNetworkPath ( const std::string& path );
+static bool IsRelativePath ( const std::string& path );
+static bool GetWidePath ( const char* path, std::string & widePath );
+static std::string & CorrectSlashes ( std::string & path );
+
+static bool Exists ( const std::string & widePath );
+static Host_IO::FileRef Open ( const std::string & widePath, bool readOnly );
+static Host_IO::FileRef OpenWithWriteShare ( const std::string & widePath, bool readOnly );
+static Host_IO::FileMode GetFileMode ( const std::string & widePath );
+
+// =================================================================================================
+// File operations
+// =================================================================================================
+
+// =================================================================================================
+// Host_IO::Exists
+// ===============
+
+bool Host_IO::Exists ( const char* filePath )
+{
+ std::string wideName;
+ if ( GetWidePath(filePath, wideName) ) {
+ return ::Exists(wideName);
+ }
+ return false;
+}
+
+// =================================================================================================
+// Host_IO::Writable
+// ===============
+bool Host_IO::Writable( const char * path, bool checkCreationPossible )
+{
+ std::string widePath;
+ if ( ! GetWidePath(path, widePath) || widePath.length() == 0)
+ XMP_Throw ( "Host_IO::Writable, cannot convert path", kXMPErr_ExternalFailure );
+
+ if ( ::Exists( widePath ) )
+ {
+ switch ( ::GetFileMode( widePath ) )
+ {
+ case kFMode_IsFile:
+ // open the file in write mode but with file_share_read | file_share_write
+ try
+ {
+ Host_IO::FileRef fileRef = Host_IO::noFileRef;
+ fileRef = ::OpenWithWriteShare( widePath, false );
+ if ( fileRef == Host_IO::noFileRef )
+ return false;// can not open in write mode.
+ Host_IO::Close ( fileRef );
+ return true;
+ }
+ catch ( ... )
+ {
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+ else if ( checkCreationPossible )
+ {
+ // file doesn't exist. Let's check if we can create it temporarily.
+ bool created = false;
+ try
+ {
+ created = Host_IO::Create ( path );
+ if ( created )
+ Host_IO::Delete ( path );
+ }
+ catch ( ... )
+ {
+ return false;
+ }
+ return created;
+ }
+ else
+ return true;
+}
+
+// =================================================================================================
+// Host_IO::Create
+// ===============
+
+bool Host_IO::Create ( const char* filePath )
+{
+ std::string wideName;
+ if ( !GetWidePath ( filePath, wideName ) || wideName.length() == 0 )
+ XMP_Throw ( "Host_IO::Create, cannot convert path", kXMPErr_ExternalFailure );
+
+ if ( ::Exists ( wideName ) ) {
+ if ( ::GetFileMode ( wideName ) == kFMode_IsFile ) return false;
+ XMP_Throw ( "Host_IO::Create, path exists but is not a file", kXMPErr_InternalFailure );
+ }
+
+ Host_IO::FileRef fileHandle;
+ fileHandle = CreateFileW ( (LPCWSTR)wideName.data(), (GENERIC_READ | GENERIC_WRITE), 0, 0, CREATE_ALWAYS,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( fileHandle == INVALID_HANDLE_VALUE ) XMP_Throw ( "Host_IO::Create, cannot create file", kXMPErr_InternalFailure );;
+
+ CloseHandle ( fileHandle );
+ return true;
+} // Host_IO::Create
+
+// =================================================================================================
+// FillXMPTime
+// ===========
+
+static void FillXMPTime ( const SYSTEMTIME & winTime, XMP_DateTime * xmpTime )
+{
+
+ // Ignore the fractional seconds for consistency with UNIX and to avoid false newness even on
+ // Windows. Some other sources of time only resolve to seconds, we don't want 25.3 looking
+ // newer than 25.
+
+ xmpTime->year = winTime.wYear;
+ xmpTime->month = winTime.wMonth;
+ xmpTime->day = winTime.wDay;
+ xmpTime->hasDate = true;
+
+ xmpTime->hour = winTime.wHour;
+ xmpTime->minute = winTime.wMinute;
+ xmpTime->second = winTime.wSecond;
+ xmpTime->nanoSecond = 0; // See note above; winTime.wMilliseconds * 1000*1000;
+ xmpTime->hasTime = true;
+
+ xmpTime->tzSign = kXMP_TimeIsUTC;
+ xmpTime->tzHour = 0;
+ xmpTime->tzMinute = 0;
+ xmpTime->hasTimeZone = true;
+
+}
+
+// =================================================================================================
+// Host_IO::GetModifyDate
+// ======================
+
+bool Host_IO::GetModifyDate ( const char* filePath, XMP_DateTime * modifyDate )
+{
+ BOOL ok;
+ Host_IO::FileRef fileHandle;
+
+ try { // Host_IO::Open should not throw - fix after CS6.
+ fileHandle = Host_IO::Open ( filePath, Host_IO::openReadOnly );
+ if ( fileHandle == Host_IO::noFileRef ) return false;
+ } catch ( ... ) {
+ return false;
+ }
+
+ FILETIME binTime;
+ ok = GetFileTime ( fileHandle, 0, 0, &binTime );
+ Host_IO::Close ( fileHandle );
+ if ( ! ok ) return false;
+
+ SYSTEMTIME utcTime;
+ ok = FileTimeToSystemTime ( &binTime, &utcTime );
+ if ( ! ok ) return false;
+
+ FillXMPTime ( utcTime, modifyDate );
+ return true;
+
+} // Host_IO::GetModifyDate
+
+// =================================================================================================
+// ConjureDerivedPath
+// ==================
+
+static std::string ConjureDerivedPath ( const char* basePath )
+{
+ std::string tempPath = basePath;
+ tempPath += "._nn_";
+ char * indexPart = (char*) tempPath.c_str() + strlen(basePath) + 2;
+
+ for ( char ten = '0'; ten <= '9' ; ++ten ) {
+ indexPart[0] = ten;
+ for ( char one = '0'; one <= '9' ; ++one ) {
+ indexPart[1] = one;
+ if ( ! Host_IO::Exists ( tempPath.c_str() ) ) return tempPath;
+ }
+ }
+
+ return "";
+
+} // ConjureDerivedPath
+
+// =================================================================================================
+// Host_IO::CreateTemp
+// ===================
+
+std::string Host_IO::CreateTemp ( const char* sourcePath )
+{
+ std::string tempPath = ConjureDerivedPath ( sourcePath );
+ if ( tempPath.empty() ) XMP_Throw ( "Host_IO::CreateTemp, cannot create temp file path", kXMPErr_InternalFailure );
+ XMP_Assert ( ! Host_IO::Exists ( tempPath.c_str() ) );
+
+ Host_IO::Create ( tempPath.c_str() );
+ return tempPath;
+
+} // Host_IO::CreateTemp
+
+// =================================================================================================
+// Host_IO::Open
+// =============
+//
+// Returns Host_IO::noFileRef (0) if the file does not exist, throws for other errors.
+
+Host_IO::FileRef Host_IO::Open ( const char* filePath, bool readOnly )
+{
+ std::string wideName;
+ if ( !GetWidePath ( filePath, wideName ) || wideName.length() == 0 )
+ XMP_Throw ( "Host_IO::Open, GetWidePath failure", kXMPErr_ExternalFailure );
+
+ return ::Open( wideName, readOnly );
+
+} // Host_IO::Open
+
+// =================================================================================================
+// Host_IO::Close
+// ==============
+
+void Host_IO::Close ( Host_IO::FileRef fileHandle )
+{
+ if ( fileHandle == Host_IO::noFileRef ) return;
+
+ BOOL ok = CloseHandle ( fileHandle );
+ if ( ! ok ) XMP_Throw ( "Host_IO::Close, CloseHandle failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::Close
+
+// =================================================================================================
+// Host_IO::SwapData
+// =================
+
+void Host_IO::SwapData ( const char* sourcePath, const char* destPath )
+{
+
+ // For lack of a better approach, do a 3-way rename.
+
+ std::string thirdPath = ConjureDerivedPath ( sourcePath );
+ if ( thirdPath.empty() ) XMP_Throw ( "Cannot create temp file path", kXMPErr_InternalFailure );
+ XMP_Assert ( ! Host_IO::Exists ( thirdPath.c_str() ) );
+
+ Host_IO::Rename ( sourcePath, thirdPath.c_str() );
+
+ try {
+ Host_IO::Rename ( destPath, sourcePath );
+ } catch ( ... ) {
+ Host_IO::Rename ( thirdPath.c_str(), sourcePath );
+ throw;
+ }
+
+ try {
+ Host_IO::Rename ( thirdPath.c_str(), destPath );
+ } catch ( ... ) {
+ Host_IO::Rename ( sourcePath, destPath );
+ Host_IO::Rename ( thirdPath.c_str(), sourcePath );
+ throw;
+ }
+
+} // Host_IO::SwapData
+
+// =================================================================================================
+// Host_IO::Rename
+// ===============
+
+void Host_IO::Rename ( const char* oldPath, const char* newPath )
+{
+ std::string wideOldPath, wideNewPath;
+ if ( !GetWidePath ( oldPath, wideOldPath ) || wideOldPath.length() == 0 )
+ XMP_Throw ( "Host_IO::Rename, GetWidePath failure", kXMPErr_ExternalFailure );
+
+ if ( !GetWidePath ( newPath, wideNewPath ) || wideNewPath.length() == 0 )
+ XMP_Throw ( "Host_IO::Rename, GetWidePath failure", kXMPErr_ExternalFailure );
+
+ if ( ::Exists ( wideNewPath ) ) XMP_Throw ( "Host_IO::Rename, new path exists", kXMPErr_InternalFailure );
+
+
+
+ BOOL ok = MoveFileW ( (LPCWSTR)wideOldPath.data(), (LPCWSTR)wideNewPath.data() );
+ if ( ! ok ) XMP_Throw ( "Host_IO::Rename, MoveFileW failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::Rename
+
+// =================================================================================================
+// Host_IO::Delete
+// ===============
+
+void Host_IO::Delete ( const char* filePath )
+{
+ std::string wideName;
+ if ( !GetWidePath ( filePath, wideName ) || wideName.length() == 0 )
+ XMP_Throw ( "Host_IO::Delete, GetWidePath failure", kXMPErr_ExternalFailure );
+
+ if ( !::Exists ( wideName ) ) return;
+
+
+
+ BOOL ok = DeleteFileW ( (LPCWSTR)wideName.data() );
+ if ( ! ok ) {
+ DWORD errCode = GetLastError();
+ if ( errCode != ERROR_FILE_NOT_FOUND ) {
+ XMP_Throw ( "Host_IO::Delete, DeleteFileW failure", kXMPErr_ExternalFailure );
+ }
+ }
+
+} // Host_IO::Delete
+
+// =================================================================================================
+// Host_IO::Seek
+// =============
+
+XMP_Int64 Host_IO::Seek ( Host_IO::FileRef fileHandle, XMP_Int64 offset, SeekMode mode )
+{
+ DWORD method;
+ switch ( mode ) {
+ case kXMP_SeekFromStart :
+ method = FILE_BEGIN;
+ break;
+ case kXMP_SeekFromCurrent :
+ method = FILE_CURRENT;
+ break;
+ case kXMP_SeekFromEnd :
+ method = FILE_END;
+ break;
+ default :
+ XMP_Throw ( "Invalid seek mode", kXMPErr_InternalFailure );
+ break;
+ }
+
+ LARGE_INTEGER seekOffset, newPos;
+ seekOffset.QuadPart = offset;
+
+ BOOL ok = SetFilePointerEx ( fileHandle, seekOffset, &newPos, method );
+ if ( ! ok ) XMP_Throw ( "Host_IO::Seek, SetFilePointerEx failure", kXMPErr_ExternalFailure );
+
+ return newPos.QuadPart;
+
+} // Host_IO::Seek
+
+// =================================================================================================
+// Host_IO::Read
+// =============
+
+#define TwoGB (XMP_Uns32)(2*1024*1024*1024UL)
+
+XMP_Uns32 Host_IO::Read ( Host_IO::FileRef fileHandle, void * buffer, XMP_Uns32 count )
+{
+ if ( count >= TwoGB ) XMP_Throw ( "Host_IO::Read, request too large", kXMPErr_EnforceFailure );
+
+ DWORD bytesRead;
+ BOOL ok = ReadFile ( fileHandle, buffer, count, &bytesRead, 0 );
+ if ( ! ok ) XMP_Throw ( "Host_IO::Read, ReadFile failure", kXMPErr_ReadError );
+
+ return bytesRead;
+
+} // Host_IO::Read
+
+// =================================================================================================
+// Host_IO::Write
+// ==============
+
+void Host_IO::Write ( Host_IO::FileRef fileHandle, const void * buffer, XMP_Uns32 count )
+{
+ if ( count >= TwoGB ) XMP_Throw ( "Host_IO::Write, request too large", kXMPErr_EnforceFailure );
+
+ DWORD bytesWritten;
+ BOOL ok = WriteFile ( fileHandle, buffer, count, &bytesWritten, 0 );
+ if ( (! ok) || (bytesWritten != count) ) {
+ DWORD osCode = GetLastError();
+ if ( osCode == ERROR_DISK_FULL ) {
+ XMP_Throw ( "Host_IO::Write, disk full", kXMPErr_DiskSpace );
+ } else {
+ XMP_Throw ( "Host_IO::Write, WriteFile failure", kXMPErr_WriteError );
+ }
+ }
+
+} // Host_IO::Write
+
+// =================================================================================================
+// Host_IO::Length
+// ===============
+
+XMP_Int64 Host_IO::Length ( Host_IO::FileRef fileHandle )
+{
+ LARGE_INTEGER length;
+ BOOL ok = GetFileSizeEx ( fileHandle, &length );
+ if ( ! ok ) XMP_Throw ( "Host_IO::Length, GetFileSizeEx failure", kXMPErr_ExternalFailure );
+
+ return length.QuadPart;
+
+} // Host_IO::Length
+
+// =================================================================================================
+// Host_IO::SetEOF
+// ===============
+
+void Host_IO::SetEOF ( Host_IO::FileRef fileHandle, XMP_Int64 length )
+{
+ LARGE_INTEGER winLength;
+ winLength.QuadPart = length;
+
+ BOOL ok = SetFilePointerEx ( fileHandle, winLength, 0, FILE_BEGIN );
+ if ( ! ok ) XMP_Throw ( "Host_IO::SetEOF, SetFilePointerEx failure", kXMPErr_ExternalFailure );
+ ok = SetEndOfFile ( fileHandle );
+ if ( ! ok ) XMP_Throw ( "Host_IO::SetEOF, SetEndOfFile failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::SetEOF
+
+// =================================================================================================
+// Folder operations
+// =================================================================================================
+
+// =================================================================================================
+// Host_IO::GetFileMode
+// ====================
+
+static DWORD kOtherAttrs = (FILE_ATTRIBUTE_DEVICE);
+
+Host_IO::FileMode Host_IO::GetFileMode ( const char * path )
+{
+ std::string utf16; // GetFileAttributes wants native UTF-16.
+ if ( !GetWidePath ( path, utf16 ) )
+ XMP_Throw ( "Host_IO::GetFileMode, GetWidePath failure", kXMPErr_ExternalFailure );
+
+ return ::GetFileMode( utf16 );
+} // Host_IO::GetFileMode
+
+// =================================================================================================
+// Host_IO::GetChildMode
+// =====================
+
+Host_IO::FileMode Host_IO::GetChildMode ( const char * parentPath, const char * childName )
+{
+ std::string fullPath = parentPath;
+ char lastChar = fullPath[fullPath.length() - 1];
+ if ( lastChar != '\\' && lastChar != '/' )
+ fullPath += '\\';
+ fullPath += childName;
+
+ return GetFileMode ( fullPath.c_str() );
+
+} // Host_IO::GetChildMode
+
+// =================================================================================================
+// Host_IO::OpenFolder
+// ===================
+
+Host_IO::FolderRef Host_IO::OpenFolder ( const char* folderPath )
+{
+ switch ( Host_IO::GetFileMode ( folderPath ) ) {
+
+ case Host_IO::kFMode_IsFolder :
+ {
+ WIN32_FIND_DATAW childInfo;
+ std::string findPath = folderPath;
+ // Looking for all children of that folder, add * as search criteria
+ findPath += findPath[findPath.length() - 1] == '\\' ? "*" : "\\*";
+
+ std::string utf16; // FindFirstFile wants native UTF-16.
+ if ( !GetWidePath ( findPath.c_str(), utf16 ) )
+ XMP_Throw ( "Host_IO::OpenFolder, GetWidePath failure", kXMPErr_ExternalFailure );
+ Host_IO::FolderRef folder = FindFirstFileW ( (LPCWSTR) utf16.c_str(), &childInfo );
+ if ( folder == noFolderRef ) XMP_Throw ( "Host_IO::OpenFolder - FindFirstFileW failed", kXMPErr_ExternalFailure );
+ // The first child should be ".", which we want to ignore anyway.
+ XMP_Assert ( (folder == noFolderRef) || (childInfo.cFileName[0] == '.') );
+
+ return folder;
+ }
+
+ case Host_IO::kFMode_DoesNotExist :
+ return Host_IO::noFolderRef;
+
+ default :
+ XMP_Throw ( "Host_IO::OpenFolder, path is not a folder", kXMPErr_ExternalFailure );
+
+ }
+
+ XMP_Throw ( "Host_IO::OpenFolder, should not get here", kXMPErr_InternalFailure );
+
+} // Host_IO::OpenFolder
+
+// =================================================================================================
+// Host_IO::CloseFolder
+// ====================
+
+void Host_IO::CloseFolder ( Host_IO::FolderRef folder )
+{
+ if ( folder == noFolderRef ) return;
+
+ BOOL ok = FindClose ( folder );
+ if ( ! ok ) XMP_Throw ( "Host_IO::CloseFolder, FindClose failure", kXMPErr_ExternalFailure );
+
+} // Host_IO::CloseFolder
+
+// =================================================================================================
+// Host_IO::GetNextChild
+// =====================
+
+bool Host_IO::GetNextChild ( Host_IO::FolderRef folder, std::string* childName )
+{
+ bool found;
+ WIN32_FIND_DATAW childInfo;
+
+ if ( folder == Host_IO::noFolderRef ) return false;
+
+ do { // Ignore all children with names starting in '.'. This covers ., .., .DS_Store, etc.
+ found = (bool) FindNextFile ( folder, &childInfo );
+ } while ( found && (childInfo.cFileName[0] == '.') );
+ if ( ! found ) return false;
+
+ if ( childName != 0 ) {
+ size_t len16 = 0; // The cFileName field is native UTF-16.
+ while ( childInfo.cFileName[len16] != 0 ) ++len16;
+ FromUTF16Native ( (UTF16Unit*)childInfo.cFileName, len16, childName );
+ }
+
+ return true;
+
+} // Host_IO::GetNextChild
+
+// =================================================================================================
+// IsLongPath
+// =====================
+
+bool IsLongPath ( const std::string& path ) {
+ if ( path.find ( "\\\\?\\" ) == 0 ) return true;
+ return false;
+}
+
+// =================================================================================================
+// IsNetworkPath
+// =====================
+
+bool IsNetworkPath ( const std::string& path ) {
+ if ( path.find ( "\\\\" ) == 0 ) return true;
+ return false;
+}
+
+// =================================================================================================
+// IsRelativePath
+// =====================
+
+bool IsRelativePath ( const std::string& path ) {
+ if ( path.length() > 2) {
+ char driveLetter = path[0];
+ if ( ( driveLetter >= 'a' && driveLetter <= 'z' ) || ( driveLetter >= 'A' && driveLetter <= 'Z' ) ) {
+ if (path[1] == ':' && path[2] == '\\' ) {
+ if ( path.find(".\\") == std::string::npos )
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// =================================================================================================
+// GetWidePath
+// =====================
+
+bool GetWidePath( const char* path, std::string & widePath ) {
+ std::string utfPath ( path );
+ CorrectSlashes ( utfPath);
+
+ if ( !IsLongPath ( utfPath ) ) {
+ if ( IsNetworkPath ( utfPath ) ) {
+ utfPath = "\\\\?\\UNC\\" + utfPath.substr ( 2 );
+ } else if ( IsRelativePath ( utfPath ) ) {
+ //don't do anything
+ } else { // absolute path
+ utfPath = "\\\\?\\" + utfPath;
+ }
+ }
+
+ widePath.clear();
+ const size_t maxLen = MultiByteToWideChar ( CP_UTF8, 0, utfPath.c_str(), -1, (LPWSTR)0, (int)0 );
+
+ widePath.reserve ( maxLen * sizeof (WCHAR) );
+ widePath.assign ( maxLen * sizeof (WCHAR) , '\0' );
+ int wideLen = MultiByteToWideChar ( CP_UTF8, 0, utfPath.c_str(), -1, (LPWSTR)widePath.data(), (int)maxLen );
+ if ( wideLen == 0 ) return false;
+ return true;
+}
+
+// =================================================================================================
+// CorrectSlashes
+// =====================
+
+std::string & CorrectSlashes ( std::string & path ) {
+ size_t idx = 0;
+
+ while( (idx = path.find_first_of('/',idx)) != std::string::npos )
+ path.replace( idx, 1, "\\" );
+ return path;
+}
+
+bool Exists ( const std::string & widePath )
+{
+ DWORD attrs = GetFileAttributesW ( (LPCWSTR)widePath.data() );
+ return ( attrs != INVALID_FILE_ATTRIBUTES);
+}
+
+
+Host_IO::FileMode GetFileMode ( const std::string & widePath )
+{
+ // ! A shortcut is seen as a file, we would need extra code to recognize it and find the target.
+ DWORD fileAttrs = GetFileAttributesW ( (LPCWSTR) widePath.c_str() );
+ if ( fileAttrs == INVALID_FILE_ATTRIBUTES ) return Host_IO::kFMode_DoesNotExist; // ! Any failure turns into does-not-exist.
+
+ if ( fileAttrs & FILE_ATTRIBUTE_DIRECTORY ) return Host_IO::kFMode_IsFolder;
+ if ( fileAttrs & kOtherAttrs ) return Host_IO::kFMode_IsOther;
+ return Host_IO::kFMode_IsFile;
+
+}
+
+Host_IO::FileRef Open ( const std::string & widePath, bool readOnly )
+{
+ DWORD access = GENERIC_READ; // Assume read mode.
+ DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ if ( ! readOnly ) {
+ access |= GENERIC_WRITE;
+ share = 0;
+ }
+
+ Host_IO::FileRef fileHandle;
+ fileHandle = CreateFileW ( (LPCWSTR)widePath.data(), access, share, 0, OPEN_EXISTING,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( fileHandle == INVALID_HANDLE_VALUE ) {
+ DWORD osCode = GetLastError();
+ if ( (osCode == ERROR_FILE_NOT_FOUND) || (osCode == ERROR_PATH_NOT_FOUND) || (osCode == ERROR_FILE_OFFLINE) ) {
+ return Host_IO::noFileRef;
+ } else if ( osCode == ERROR_ACCESS_DENIED ) {
+ XMP_Throw ( "Open, file permission error", kXMPErr_FilePermission );
+ } else {
+ XMP_Throw ( "Open, other failure", kXMPErr_ExternalFailure );
+ }
+ }
+
+ return fileHandle;
+}
+
+Host_IO::FileRef OpenWithWriteShare ( const std::string & widePath, bool readOnly )
+{
+ DWORD access = GENERIC_READ; // Assume read mode.
+ DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ if ( ! readOnly ) {
+ access |= GENERIC_WRITE;
+ }
+
+ Host_IO::FileRef fileHandle;
+ fileHandle = CreateFileW ( (LPCWSTR)widePath.data(), access, share, 0, OPEN_EXISTING,
+ (FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS), 0 );
+ if ( fileHandle == INVALID_HANDLE_VALUE ) {
+ DWORD osCode = GetLastError();
+ if ( (osCode == ERROR_FILE_NOT_FOUND) || (osCode == ERROR_PATH_NOT_FOUND) || (osCode == ERROR_FILE_OFFLINE) ) {
+ return Host_IO::noFileRef;
+ } else if ( osCode == ERROR_ACCESS_DENIED ) {
+ XMP_Throw ( "Open, file permission error", kXMPErr_FilePermission );
+ } else {
+ XMP_Throw ( "Open, other failure", kXMPErr_ExternalFailure );
+ }
+ }
+
+ return fileHandle;
+}
+
+static std::string ConstructPreservedPath( const std::string& inputPath )
+{
+ DWORD allocate_size,retValue;
+ std::string longpathname="\\\\?\\";
+ std::string networkpathsuffix="UNC\\";
+ std::string pathSep="\\";
+ std::string casePreservedPath,systempath,widePath,leafname;
+
+ if ( ! Host_IO::Exists( inputPath.c_str() ) )
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, Invalid Path-Doesn't Exist", kXMPErr_ExternalFailure );
+ std::string utfPath ( inputPath );
+ CorrectSlashes ( utfPath);
+
+ size_t pos = 0;
+ bool isNetworkPath=false;
+ int skipServerAndShareName=0;
+ if ( ! longpathname.compare ( utfPath.substr ( 0, longpathname.length() ) ) )
+ {
+ pos = longpathname.length() ;
+ if ( ! networkpathsuffix.compare ( utfPath.substr ( pos, networkpathsuffix.length() ) ))
+ {
+ pos += networkpathsuffix.length() ;
+ isNetworkPath=true;
+ }
+ casePreservedPath = utfPath.substr ( 0 , pos ) ;
+ }
+ else
+ {
+ isNetworkPath=IsNetworkPath(utfPath);
+ if (isNetworkPath){ pos =2;casePreservedPath="\\\\";}
+ }
+ if (isNetworkPath) skipServerAndShareName=2;
+ bool loopvar=true;
+ while(loopvar)
+ {
+ size_t newpos = utfPath.find_first_of( pathSep, pos );
+ if ( newpos == std::string::npos )
+ {
+ newpos = utfPath.length();
+ loopvar= false;
+ }
+ WIN32_FIND_DATAW fileInfo;
+ HANDLE searchNext;
+ leafname=utfPath.substr(pos,newpos-pos );
+ skipServerAndShareName=(skipServerAndShareName<0)?0:skipServerAndShareName;
+ if (!( leafname=="" || leafname=="." || leafname==".." || leafname[newpos-pos-1]==':' || skipServerAndShareName-- ) )
+ {
+ std::string partialPath=utfPath.substr(0,newpos);
+ if ( ! GetWidePath(partialPath.c_str(), widePath) || widePath.length() == 0)
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+ searchNext = ::FindFirstFileW ( (LPCWSTR) widePath.c_str(), &fileInfo );
+ if( searchNext == INVALID_HANDLE_VALUE || ! ::FindClose(searchNext) )
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+
+ allocate_size=::WideCharToMultiByte(CP_UTF8,0,fileInfo.cFileName,-1,NULL,0,NULL,NULL);
+ leafname.reserve(allocate_size);
+ leafname.assign ( allocate_size , 0 );
+ retValue=::WideCharToMultiByte(CP_UTF8,0,fileInfo.cFileName,-1,(LPSTR)leafname.data(),leafname.length(),NULL,NULL);
+ if ( ! retValue )
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+ }
+ casePreservedPath += leafname.c_str() ;
+ if (loopvar)
+ casePreservedPath+=pathSep;
+ pos=newpos+1;
+ }
+ return casePreservedPath.c_str();
+}
+static bool ContainsNonASCIICodePoints( const std::string & value )
+{
+ size_t vallen=value.length();
+ for (size_t index=0;index<vallen;index++)
+ {
+ if ((unsigned char)value[index]>127)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+// =================================================================================================
+// Host_IO::GetCasePreservedName
+// =============================
+std::string Host_IO::GetCasePreservedName( const std::string& inputPath )
+{
+ if ( ! ContainsNonASCIICodePoints( inputPath ) )
+ {
+ DWORD allocate_size,retValue;
+ std::string widePath,systempath,longPathName,shortPathName;
+ if ( ! GetWidePath(inputPath.c_str(), widePath) || widePath.length() == 0)
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+
+ allocate_size = ::GetShortPathNameW((LPCWSTR)(widePath.c_str()),NULL,0);
+ shortPathName.reserve ( allocate_size* sizeof(TCHAR) );
+ shortPathName.assign ( allocate_size* sizeof(TCHAR) , 0 );
+ retValue = ::GetShortPathNameW( ( LPCWSTR)(widePath.c_str()),(LPWSTR)shortPathName.data(),allocate_size);
+ if ( ! retValue )
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+
+ allocate_size = ::GetLongPathNameW((LPCWSTR)(shortPathName.c_str()),NULL,0);
+ longPathName.reserve ( allocate_size* sizeof(TCHAR) );
+ longPathName.assign ( allocate_size* sizeof(TCHAR) , 0 );
+ retValue = ::GetLongPathNameW( ( LPCWSTR)(shortPathName.c_str()),(LPWSTR)longPathName.data(),allocate_size);
+ if ( ! retValue )
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+
+ allocate_size=::WideCharToMultiByte(CP_UTF8,0,(LPWSTR)&longPathName[0],-1,NULL,0,NULL,NULL);
+ systempath.reserve(allocate_size+1);
+ systempath.assign ( allocate_size+1 , 0 );
+ retValue=::WideCharToMultiByte(CP_UTF8,0,(LPWSTR)&longPathName[0],-1,(LPSTR)systempath.data(),systempath.size(),NULL,NULL);
+ if ( ! retValue )
+ XMP_Throw ( "Host_IO::GetCasePresevedLeafName, cannot convert path", kXMPErr_ExternalFailure );
+
+ return systempath.c_str();
+ }
+ else
+ {
+ return ConstructPreservedPath( inputPath );
+ }
+}
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO.hpp
new file mode 100644
index 0000000000..74f051597b
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/Host_IO.hpp
@@ -0,0 +1,190 @@
+#ifndef __Host_IO_hpp__
+#define __Host_IO_hpp__ 1
+
+// =================================================================================================
+// 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 "public/include/XMP_Environment.h" // ! This must be the first include.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include <string>
+
+#if XMP_WinBuild
+ #include <Windows.h>
+#elif XMP_MacBuild
+ #include <CoreServices/CoreServices.h>
+ #include <dirent.h> // Mac uses the POSIX folder functions.
+#elif XMP_UNIXBuild | XMP_iOSBuild
+ #include <dirent.h>
+#else
+ #error "Unknown host platform."
+#endif
+
+// =================================================================================================
+// Host_IO is a collection of minimal convenient wrappers for host I/O services. It is intentionally
+// a namespace and not a class. No state is kept here, these are just wrappers that provide a common
+// internal API for basic I/O services that differ from host to host.
+
+namespace Host_IO {
+
+ // =============================================================================================
+ // File operations
+ // ===============
+ //
+ // ! The file operations should only be used in the implementation of XMPFiles_IO.
+ //
+ // Exists - Returns true if the path exists, whether as a file, folder, or anything else. Never
+ // throws an exception.
+ //
+ // Writable - Returns true
+ // a. In case checkCreationPossible is false check for existence and writable permissions.
+ // b. In case checkCreationPossible is true and path is not existence, check permissions of parent folder.
+ //
+ // Create - Create a file if possible, return true if successful. Return false if the file
+ // already exists. Throw an XMP_Error exception if the file cannot be created or if the path
+ // already exists but is not a file.
+ //
+ // GetModifyDate - Return the file system modification date. Returns false if the file or folder
+ // does not exist.
+ //
+ // CreateTemp - Create a (presumably) temporary file related to some other file. The source
+ // file path is passed in, a derived name is selected in the same folder. The source file need
+ // not exist, but all folders in the path must exist. The derived name is guaranteed to not
+ // already exist. A limited number of attempts are made to select a derived name. Returns the
+ // temporary file path if successful. Throws an XMP_Error exception if no derived name is found
+ // of if the temporary file cannot be created.
+ //
+ // Open - Open a file for read-only or read-write access. Returns the host-specific FileRef if
+ // successful, returns noFileRef if the path does not exist. Throws an XMP_Error exception for
+ // other errors.
+ //
+ // Close - Close a file. Does nothing if the FileRef is noFileRef. Throws an XMP_Error
+ // exception for any errors.
+ //
+ // SwapData - Swap the contents of two files. Both should be closed. Used as part of safe-save
+ // operations. On Mac, also swaps all non-data forks. Ideally just the contents should be
+ // swapped, but a 3-way rename will be used instead of reading and writing the contents. Uses a
+ // host file-swap service if available, even if that swaps more than the contents. Throws an
+ // XMP_Error exception for any errors.
+ //
+ // Rename - Rename a file or folder. The new path must not exist. Throws an XMP_Error exception
+ // for any errors.
+ //
+ // Delete - Deletes a file or folder. Does nothing if the path does not exist. Throws an
+ // XMP_Error exception for any errors.
+ //
+ // Seek - Change the I/O position of an open file, returning the new absolute offset. Uses the
+ // native host behavior for seeking beyond EOF. Throws an XMP_Error exception for any errors.
+ //
+ // Read - Read into a buffer returning the number of bytes read. Requests are limited to less
+ // than 2GB in case the host uses an SInt32 count. Throws an XMP_Error exception for errors.
+ // Reaching EOF or being at EOF is not an error.
+ //
+ // Write - Write from a buffer. Requests are limited to less than 2GB in case the host uses an
+ // SInt32 count. Throws an XMP_Error exception for any errors.
+ //
+ // Length - Returns the length of an open file in bytes. The I/O position is not changed.
+ // Throws an XMP_Error exception for any errors.
+ //
+ // SetEOF - Sets a new EOF offset. The I/O position may be changed. Throws an XMP_Error
+ // exception for any errors.
+
+ #if XMP_WinBuild
+ typedef HANDLE FileRef;
+ static const FileRef noFileRef = INVALID_HANDLE_VALUE;
+ #elif XMP_MacBuild
+ typedef FSIORefNum FileRef;
+ static const FileRef noFileRef = -1;
+ #elif XMP_UNIXBuild | XMP_iOSBuild
+ typedef int FileRef;
+ static const FileRef noFileRef = -1;
+ #endif
+
+ bool Exists ( const char* filePath );
+ bool Writable ( const char* path, bool checkCreationPossible = false);
+ bool Create ( const char* filePath ); // Returns true if file exists or was created.
+
+ std::string GetCasePreservedName(const std::string& inputPath);
+
+ bool GetModifyDate ( const char* filePath, XMP_DateTime* modifyDate );
+
+ std::string CreateTemp ( const char* sourcePath );
+
+ enum { openReadOnly = true, openReadWrite = false };
+
+ FileRef Open ( const char* filePath, bool readOnly );
+ void Close ( FileRef file );
+
+ void SwapData ( const char* sourcePath, const char* destPath );
+ void Rename ( const char* oldPath, const char* newPath );
+ void Delete ( const char* filePath );
+
+ XMP_Int64 Seek ( FileRef file, XMP_Int64 offset, SeekMode mode );
+ XMP_Uns32 Read ( FileRef file, void* buffer, XMP_Uns32 count );
+ void Write ( FileRef file, const void* buffer, XMP_Uns32 count );
+ XMP_Int64 Length ( FileRef file );
+ void SetEOF ( FileRef file, XMP_Int64 length );
+
+ inline XMP_Int64 Offset ( FileRef file ) { return Host_IO::Seek ( file, 0, kXMP_SeekFromCurrent ); };
+ inline XMP_Int64 Rewind ( FileRef file ) { return Host_IO::Seek ( file, 0, kXMP_SeekFromStart ); }; // Always returns 0.
+ inline XMP_Int64 ToEOF ( FileRef file ) { return Host_IO::Seek ( file, 0, kXMP_SeekFromEnd ); };
+
+ // =============================================================================================
+ // Folder operations
+ // =================
+ //
+ // ! The folder operations may be used anywhere.
+ //
+ // GetFileMode - Returns an enum telling if a path names a file, folder, other, or nothing.
+ // Never throws an exception.
+ //
+ // GetChildMode - Same as GetFileMode, but has separate parent path and child name parameters.
+ //
+ // OpenFolder - Initializes the iteration of a folder.
+ //
+ // CloseFolder - Terminates the iteration of a folder.
+ //
+ // GetNextChild - Steps an iteration of a folder. Returns false at the end. Otherwise returns
+ // true and the local name of the next child. All names starting with '.' are skipped.
+ //
+ // AutoFolder - A utility class to make sure a folder iteration is terminated at scope exit.
+
+ enum { kFMode_DoesNotExist, kFMode_IsFile, kFMode_IsFolder, kFMode_IsOther };
+ typedef XMP_Uns8 FileMode;
+
+ FileMode GetFileMode ( const char * path );
+ FileMode GetChildMode ( const char * parentPath, const char * childName );
+
+ #if XMP_WinBuild
+ typedef HANDLE FolderRef;
+ static const FolderRef noFolderRef = INVALID_HANDLE_VALUE;
+ #elif XMP_MacBuild
+ typedef DIR* FolderRef;
+ static const FolderRef noFolderRef = 0;
+ #elif XMP_UNIXBuild | XMP_iOSBuild
+ typedef DIR* FolderRef;
+ static const FolderRef noFolderRef = 0;
+ #endif
+
+ FolderRef OpenFolder ( const char* folderPath );
+ void CloseFolder ( FolderRef folder );
+ bool GetNextChild ( FolderRef folder, std::string* childName );
+
+ class AutoFolder { // Used to make sure folder is closed at scope exit.
+ public:
+ FolderRef folder;
+ AutoFolder() : folder(noFolderRef) {};
+ ~AutoFolder() { this->Close(); };
+ void Close() { CloseFolder ( this->folder ); this->folder = noFolderRef; };
+ };
+
+};
+
+#endif // __Host_IO_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/IOUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/IOUtils.cpp
new file mode 100644
index 0000000000..726aaf6f96
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/IOUtils.cpp
@@ -0,0 +1,118 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2013 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 "source/IOUtils.hpp"
+#include "source/Host_IO.hpp"
+
+#include <algorithm>
+
+// =================================================================================================
+// ListAllChildren
+// =================================================================================================
+
+static void ListAllChildren( XMP_StringPtr folderPath, XMP_StringVector & list, XMP_Bool listFolders, XMP_Bool listFiles, XMP_Bool sortList )
+{
+ try
+ {
+ Host_IO::AutoFolder af;
+ af.folder = Host_IO::OpenFolder ( folderPath );
+ if ( af.folder != Host_IO::noFolderRef )
+ {
+ std::string resourceName;
+
+ while ( Host_IO::GetNextChild ( af.folder, &resourceName ) == true )
+ {
+
+ XMP_Bool addPath = false;
+ if ( listFolders && listFiles ) {
+ addPath = true;
+ }
+ else if ( listFolders )
+ {
+ if ( Host_IO::GetChildMode ( folderPath, resourceName.c_str() ) == Host_IO::kFMode_IsFolder )
+ addPath = true;
+ }
+ else if ( listFiles )
+ {
+ if ( Host_IO::GetChildMode ( folderPath, resourceName.c_str() ) == Host_IO::kFMode_IsFile )
+ addPath = true;
+ }
+
+ if ( addPath )
+ list.push_back ( resourceName );
+ }
+ }
+ } catch ( XMP_Error & ) {
+ // do nothing
+ }
+ if ( sortList )
+ std::sort ( list.begin(), list.end() );
+}
+
+
+// =================================================================================================
+// GetMatchingChildren
+// =================================================================================================
+
+void IOUtils::GetMatchingChildren ( XMP_StringVector & matchingChildList, const XMP_VarString & rootPath,
+ const XMP_StringVector & regExStringVec, XMP_Bool includeFolders, XMP_Bool includeFiles, XMP_Bool prefixRootPath )
+{
+ try
+ {
+ XMP_StringVector listOfAllResources;
+ ListAllChildren (rootPath.c_str(), listOfAllResources, includeFolders, includeFiles, true);
+
+ XMP_Bool matchRequired = !regExStringVec.empty();
+ if ( matchRequired )
+ {
+ size_t childCount = listOfAllResources.size();
+ for ( size_t index = 0; index < childCount; index++ )
+ {
+ XMP_Bool match = false;
+ size_t regExpCount = regExStringVec.size();
+ for ( size_t index2 = 0; index2 < regExpCount; index2++ )
+ {
+ XMP_RegExp regexObj ( regExStringVec[index2].c_str() );
+ match = regexObj.Match ( listOfAllResources[index].c_str() );
+
+ if ( match )
+ {
+ if ( prefixRootPath )
+ {
+ std::string fullPath = rootPath;
+ if (fullPath[fullPath.length() - 1] != kDirChar )
+ fullPath += kDirChar;
+ fullPath += listOfAllResources[index];
+ matchingChildList.push_back ( fullPath );
+ }
+ else
+ matchingChildList.push_back ( listOfAllResources[index] );
+ break;
+ }
+ }
+ }
+ }
+ } catch ( XMP_Error & ) {
+ // do nothing
+ }
+} // GetMatchingChildren
+
+// =================================================================================================
+// GetMatchingChildren
+// =================================================================================================
+
+void IOUtils::GetMatchingChildren ( XMP_StringVector & matchingChildList, const XMP_VarString & rootPath,
+ const XMP_VarString & regExpStr, XMP_Bool includeFolders, XMP_Bool includeFiles, XMP_Bool prefixRootPath )
+{
+ XMP_StringVector regExpStringVec;
+ regExpStringVec.push_back ( regExpStr );
+ return GetMatchingChildren ( matchingChildList, rootPath, regExpStringVec, includeFolders, includeFiles, prefixRootPath );
+} // GetMatchingChildren
+
+// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/IOUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/IOUtils.hpp
new file mode 100644
index 0000000000..fd4542b890
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/IOUtils.hpp
@@ -0,0 +1,31 @@
+#ifndef __IOUtils_hpp__
+#define __IOUtils_hpp__ 1
+
+// =================================================================================================
+// Copyright 2013 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 "source/XMP_LibUtils.hpp"
+
+//Helper class for common IO function
+class IOUtils
+{
+public:
+ // Returns the list of folders or files matching particular string format in the given Directory
+ static void GetMatchingChildren ( XMP_StringVector & matchingChildList, const XMP_VarString & rootPath,
+ const XMP_StringVector & regExStringVec, XMP_Bool includeFolders, XMP_Bool includeFiles, XMP_Bool prefixRootPath );
+
+ // Returns the list of folders or files matching particular string format in the given Directory
+ static void GetMatchingChildren ( XMP_StringVector & matchingChildList, const XMP_VarString & rootPath,
+ const XMP_VarString & regExpStr, XMP_Bool includeFolders, XMP_Bool includeFiles, XMP_Bool prefixRootPath );
+};
+
+#endif // __IOUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/PerfUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/PerfUtils.cpp
new file mode 100644
index 0000000000..6cf8b3101d
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/PerfUtils.cpp
@@ -0,0 +1,147 @@
+// =================================================================================================
+// 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.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h"
+#include "public/include/XMP_Const.h"
+
+#include "source/PerfUtils.hpp"
+
+#include <stdio.h>
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4996 ) // '...' was declared deprecated
+#endif
+
+// =================================================================================================
+// =================================================================================================
+
+#if XMP_WinBuild
+
+#pragma warning ( disable : 4800 ) // forcing bool to 0/1
+
+const char * PerfUtils::GetTimerInfo()
+{
+ LARGE_INTEGER freq;
+ static char msgBuffer[1000];
+
+ bool ok = (bool) QueryPerformanceFrequency ( &freq );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_ExternalFailure, "Failure from QueryPerformanceFrequency" );
+
+ if ( freq.HighPart != 0 ) {
+ return "Windows PerfUtils measures finer than nanoseconds, using the QueryPerformanceCounter() timer";
+ }
+
+ double rate = 1.0 / (double)freq.LowPart;
+ _snprintf ( msgBuffer, sizeof(msgBuffer),
+ "Windows PerfUtils measures %e second, using the QueryPerformanceCounter() timer", rate );
+ return msgBuffer;
+
+} // PerfUtils::GetTimerInfo
+
+// ------------------------------------------------------------------------------------------------
+
+PerfUtils::MomentValue PerfUtils::NoteThisMoment()
+{
+ LARGE_INTEGER now;
+
+ bool ok = (bool) QueryPerformanceCounter ( &now );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_ExternalFailure, "Failure from QueryPerformanceCounter" );
+ return now.QuadPart;
+
+} // PerfUtils::NoteThisMoment
+
+// ------------------------------------------------------------------------------------------------
+
+double PerfUtils::GetElapsedSeconds ( PerfUtils::MomentValue start, PerfUtils::MomentValue finish )
+{
+ LARGE_INTEGER freq;
+
+ bool ok = (bool) QueryPerformanceFrequency ( &freq );
+ if ( ! ok ) throw XMP_Error ( kXMPErr_ExternalFailure, "Failure from QueryPerformanceFrequency" );
+
+ const double scale = (double)freq.QuadPart;
+
+ const double elapsed = (double)(finish - start) / scale;
+ return elapsed;
+
+} // PerfUtils::GetElapsedSeconds
+
+#endif
+
+// =================================================================================================
+
+#if XMP_UNIXBuild
+
+const char * PerfUtils::GetTimerInfo()
+{
+ return "UNIX PerfUtils measures nano seconds, using the POSIX clock_gettime() timer";
+} // PerfUtils::GetTimerInfo
+
+// ------------------------------------------------------------------------------------------------
+
+PerfUtils::MomentValue PerfUtils::NoteThisMoment()
+{
+ MomentValue moment = kZeroMoment;
+ if ( clock_gettime( CLOCK_MONOTONIC, &moment ) != 0 )
+ throw XMP_Error( kXMPErr_ExternalFailure, "Failure from clock_gettime" );
+ return moment;
+} // PerfUtils::NoteThisMoment
+
+// ------------------------------------------------------------------------------------------------
+
+double PerfUtils::GetElapsedSeconds ( PerfUtils::MomentValue start, PerfUtils::MomentValue finish )
+{
+ double startInSeconds = start.tv_sec + start.tv_nsec / 1000000000.0;
+ double finishInSeconds = finish.tv_sec + finish.tv_nsec / 1000000000.0;
+ return finishInSeconds - startInSeconds;
+} // PerfUtils::GetElapsedSeconds
+
+#endif
+
+// =================================================================================================
+
+#if XMP_MacBuild | XMP_iOSBuild
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+
+const char * PerfUtils::GetTimerInfo()
+{
+ return "Mac PerfUtils measures nano seconds, using the mach_absolute_time() timer";
+} // PerfUtils::GetTimerInfo
+
+// ------------------------------------------------------------------------------------------------
+
+PerfUtils::MomentValue PerfUtils::NoteThisMoment()
+{
+ return mach_absolute_time();
+} // PerfUtils::NoteThisMoment
+
+// ------------------------------------------------------------------------------------------------
+
+double PerfUtils::GetElapsedSeconds ( PerfUtils::MomentValue start, PerfUtils::MomentValue finish )
+{
+ static mach_timebase_info_data_t sTimebaseInfo;
+ static double sConversionFactor = 0.0;
+ // If this is the first time we've run, get the timebase.
+ // We can use denom == 0 to indicate that sTimebaseInfo is
+ // uninitialized because it makes no sense to have a zero
+ // denominator is a fraction.
+
+ if ( sTimebaseInfo.denom == 0 ) {
+ mach_timebase_info(&sTimebaseInfo);
+ sConversionFactor = ((double)sTimebaseInfo.denom / (double)sTimebaseInfo.numer);
+ sConversionFactor /= 1000000000.0;
+ }
+
+ return ( finish - start ) * sConversionFactor;
+} // PerfUtils::GetElapsedSeconds
+
+#endif
+
+
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/PerfUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/PerfUtils.hpp
new file mode 100644
index 0000000000..4bf9831bd7
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/PerfUtils.hpp
@@ -0,0 +1,44 @@
+#ifndef __PerfUtils_hpp__
+#define __PerfUtils_hpp__ 1
+
+// =================================================================================================
+// 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.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h"
+
+#if XMP_MacBuild
+ #include <CoreServices/CoreServices.h>
+#elif XMP_WinBuild
+ #include <Windows.h>
+#elif XMP_UNIXBuild | XMP_iOSBuild
+ #include <time.h>
+#endif
+
+namespace PerfUtils {
+
+ #if XMP_WinBuild
+// typedef LARGE_INTEGER MomentValue;
+ typedef LONGLONG MomentValue;
+ static const MomentValue kZeroMoment = 0;
+ #elif XMP_UNIXBuild
+ typedef struct timespec MomentValue;
+ static const MomentValue kZeroMoment = {0, 0};
+ #elif XMP_iOSBuild | XMP_MacBuild
+ typedef uint64_t MomentValue;
+ static const MomentValue kZeroMoment = 0;
+ #endif
+
+ const char * GetTimerInfo();
+
+ MomentValue NoteThisMoment();
+
+ double GetElapsedSeconds ( MomentValue start, MomentValue finish );
+
+}; // PerfUtils
+
+#endif // __PerfUtils_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/SafeStringAPIs.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/SafeStringAPIs.cpp
new file mode 100644
index 0000000000..0e7b2246c6
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/SafeStringAPIs.cpp
@@ -0,0 +1,633 @@
+/*************************************************************************
+*
+* ADOBE CONFIDENTIAL
+* ___________________
+*
+* Copyright 2010 Adobe Systems Incorporated
+* All Rights Reserved.
+*
+* NOTICE: All information contained herein is, and remains
+* the property of Adobe Systems Incorporated and its suppliers,
+* if any. The intellectual and technical concepts contained
+* herein are proprietary to Adobe Systems Incorporated and its
+* suppliers and are protected by trade secret or copyright law.
+* Dissemination of this information or reproduction of this material
+* is strictly forbidden unless prior written permission is obtained
+* from Adobe Systems Incorporated.
+**************************************************************************/
+
+#include <stddef.h> /* Include standard ANSI C stuff: size_t, NULL etc */
+#include <string.h> /* memmove etc. defined here */
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdarg.h>
+
+#include <assert.h>
+#include <limits.h>
+#include "SafeStringAPIs.h"
+
+/*
+ Safe String Functions
+*/
+
+CONDITIONAL_STATIC size_t strnlen_safe(const char *s, size_t maxSize)
+{
+ if (s)
+ {
+ size_t n;
+ for (n = 0; n < maxSize && *s; n++, s++)
+ ;
+ return n;
+ }
+ else{
+ return 0;
+ }
+}
+
+CONDITIONAL_STATIC SafeInt32 strcpy_safe(char *dest, size_t size, const char *src)
+{
+
+ if (dest && src && size > 0)
+ {
+ char* p = dest;
+ size_t available = size;
+ while((*p++ = *src++) != '\0' && --available > 0)
+ {
+ }
+ if(available == 0)
+ {
+ *(--p) = '\0';
+ //Buffer overflow. return ERROR_SAFE_BUFFER_OVERFLOW
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ else
+ return 0;
+ }
+ else{
+ if(dest)
+ *dest = '\0';
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+
+}
+
+CONDITIONAL_STATIC SafeInt32 strncpy_safe(char *dest, size_t size, const char *src, size_t n)
+{
+ if(n == 0 && dest == NULL && size == 0)
+ return 0;
+ if(dest && src && size > 0)
+ {
+ if(n == 0)
+ {
+ *dest = '\0';
+ return 0;
+ }
+ char* p = dest;
+ size_t available = size;
+ while((*p++ = *src++) != '\0' && --available > 0 && --n > 0)
+ {
+ }
+ if(n == 0)
+ *p = '\0';
+ if(available == 0)
+ {
+ *(--p) = '\0';
+ //Buffer overflow. Returns ERROR_SAFE_BUFFER_OVERFLOW
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+
+ return 0;
+ }
+ else{
+ if(dest)
+ *dest = '\0';
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+}
+
+CONDITIONAL_STATIC SafeInt32 strcat_safe(char *s1, size_t s1max, const char *s2)
+{
+ if(s1 == NULL && s1max == 0)
+ return 0;
+ if(s1 && s2 && s1max > 0)
+ {
+ size_t available = s1max;
+ char* dest = s1;
+ while(available > 0 && *dest != '\0')
+ {
+ dest++;
+ available--;
+ }
+ if(available == 0)
+ {
+ *s1 = '\0';
+ //Destination not null terminated. Empty destination and return ERROR_SAFE_INVALID_PARAM
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+ while((*dest++ = *s2++) != '\0' && --available > 0)
+ {
+ }
+ if(available == 0)
+ {
+ //Truncate at buffer overflow attempt. Return ERROR_SAFE_BUFFER_OVERFLOW.
+ *(--dest) = '\0';
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ return 0;
+ }
+ else{
+ if(s1)
+ *s1 = '\0';
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+}
+
+CONDITIONAL_STATIC SafeInt32 strncat_safe(char *s1, size_t s1max, const char *s2, size_t n)
+{
+ if(n == 0 && s1 == NULL && s1max == 0)
+ return 0;
+ if(s1 && s2 && s1max > 0)
+ {
+ char* dest = s1;
+ size_t available = s1max;
+
+ while(available > 0 && *dest != '\0')
+ {
+ dest++;
+ available--;
+ }
+ if(available == 0)
+ {
+ *s1 = '\0';
+ //Destination not null terminated. Empty destination and return ERROR_SAFE_INVALID_PARAM
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+ while(n > 0 && (*dest++ = *s2++)!= '\0' && --available > 0)
+ {
+ n--;
+ }
+ if(n == 0)
+ {
+ *dest = '\0';
+ }
+ if(available == 0)
+ {
+ //Truncate. Return ERROR_SAFE_BUFFER_OVERFLOW
+ *(--dest) = '\0';
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ return 0;
+ }
+ else{
+ if(s1)
+ *s1 = '\0';
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+}
+
+CONDITIONAL_STATIC char *strchr_safe(const char *s, size_t maxSize, char c)
+{
+ if(s == NULL) return NULL;
+ for (; maxSize > 0 && *s != '\0'; s++, maxSize--)
+ {
+ if (*s == (const char)c)
+ {
+ return (char *)s;
+ }
+ }
+
+ if (maxSize > 0 && (const char)c == *s)
+ {
+ return (char *)s;
+ }
+
+ return NULL;
+}
+
+CONDITIONAL_STATIC char * strtok_safe(char* strToken, size_t maxSize, const char *strDelimit, char **context)
+{
+ if(maxSize == 0)
+ {
+ return NULL;
+ }
+
+ if(strToken)
+ {
+ strToken[maxSize - 1] = '\0';
+ }
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return strtok_s(strToken, strDelimit, context);
+#else
+ if( !strDelimit || !context || ( !( *context) && ( !strToken)))
+ {
+ return NULL;
+ }
+
+ if( !strToken)
+ {
+ // We got NULL input, so we get our last position from context.
+ strToken = *context;
+ }
+ /* pass all characters that are present in the delimiter string */
+ while(*strToken && strchr_safe(strDelimit, (size_t)-1, *strToken))
+ ++strToken;
+
+ if(*strToken){
+ /* This is where the next piece of string starts */
+ char *start = strToken;
+ /* Set the context pointer to the first byte after start */
+ *context = start + 1;
+ while(**context && !strchr_safe(strDelimit, (size_t)-1, **context))
+ ++*context;
+
+ if(**context){
+ //The end is not a null byte
+ **context = '\0'; /* Null terminate it */
+ ++*context; /* Advance the last pointer to beyond the null byte. */
+ }
+ return start;
+ }
+
+ // No remaining tokens. Set the context pointer to the original terminating null
+ // of strToken and return null.
+ *context = strToken;
+ return NULL;
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 vprintf_safe(const char* format, va_list argp)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return vprintf_s(format, argp);
+#else
+ if(format)
+ {
+ return vprintf(format, argp);
+ }
+ else
+ {
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 vsprintf_safe(char* buffer, size_t size, const char* format, va_list argp)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return vsprintf_s(buffer, size, format, argp);
+#else
+ if(buffer && format && size > 0)
+ {
+ SafeInt32 count = static_cast<SafeInt32>(size);
+ if(count > INT_MAX)
+ count = INT_MAX;
+ SafeInt32 numBytes = vsnprintf(buffer, count, format, argp);
+ if(numBytes >= count)
+ {
+ /* If number of bytes written is greater than count, the buffer is too small,
+ vsnprintf truncates the buffer and null terminates it.*/
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ return numBytes;
+ }
+ else
+ {
+ if(buffer)
+ *buffer = '\0';
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 vsnprintf_safe(char *buffer, size_t size, size_t count, const char* format, va_list argp)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return vsnprintf_s(buffer, size, count, format, argp);
+#else
+ if(count == 0 && buffer == NULL && size == 0)
+ return 0; //allowed
+ if(buffer && format && size > 0)
+ {
+ if(count == 0)
+ {
+ *buffer = '\0';
+ return 0;
+ }
+ SafeInt32 n = (count + 1) < size ? (count + 1) : size; //MIN(count+1, size);
+ SafeInt32 numBytes = vsnprintf(buffer, n, format, argp);
+ if(numBytes >= static_cast<SafeInt32>(size) && count >= size)
+ {
+ //Truncate here. Return ERROR_SAFE_BUFFER_OVERFLOW.
+ buffer[n-1] = '\0';
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ buffer[n-1] = '\0';
+ return numBytes;
+ }
+ else
+ {
+ if(buffer)
+ *buffer = '\0';
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 vwprintf_safe(const wchar_t *format, va_list argp)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return vwprintf_s(format, argp);
+#else
+ if(format)
+ {
+ return vwprintf(format, argp);
+ }
+ else
+ {
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 sprintf_safe(char *buffer, size_t size, const char *format, ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vsprintf_safe(buffer, size, format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+CONDITIONAL_STATIC SafeInt32 printf_safe(const char *format, ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vprintf_safe(format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+CONDITIONAL_STATIC SafeInt32 snprintf_safe(char* buffer, size_t size, size_t count, const char *format, ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vsnprintf_safe(buffer, size, count, format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+CONDITIONAL_STATIC SafeInt32 wprintf_safe(const wchar_t *format, ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vwprintf_safe(format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+
+CONDITIONAL_STATIC SafeInt32 splitpath_safe(const char* path, char* drive, size_t driveSize, char* dir,
+ size_t dirSize, char* fname, size_t fnameSize, char* ext, size_t extSize)
+{
+ return _splitpath_s(path, drive, driveSize, dir, dirSize, fname, fnameSize, ext, extSize);
+}
+
+CONDITIONAL_STATIC SafeInt32 makepath_safe(char* path, size_t size, const char* drive, const char* dir,
+ const char* fname, const char* ext)
+{
+ return _makepath_s(path, size, drive, dir, fname, ext);
+}
+
+#endif
+
+#if !(defined(_WIN32) || defined(_WIN64)) || !defined __STDC_WANT_SECURE_LIB__
+
+static char *reverse_string_safe(char *str, size_t size)
+{
+ size_t head = 0;
+ size_t tail = strnlen_safe(str, size) - 1;
+ while (head < tail)
+ {
+ char temp = str[head];
+ str[head] = str[tail];
+ str[tail] = temp;
+ head++;
+ tail--;
+ }
+ return str;
+}
+
+
+static SafeInt32 _xtox_safe(unsigned long val, char *buf, size_t size, int radix, int isNeg)
+{
+ if(!buf)
+ {
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+ if(radix < 2 || radix > 36)
+ {
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+ size_t len;
+ unsigned long num;
+ if(isNeg)
+ num = (unsigned long)(-(long)val);
+ else
+ num = val;
+ for(len = 2; num; num/= radix) len++; /* quick log_base */
+
+ if(size <= 0 || size < len)
+ {
+ buf[0]='\0';
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ /* parameters are valid */
+
+ int strIndex = 0;
+ if(isNeg)
+ val = (unsigned long)(-(long)val);
+
+
+ do
+ {
+ unsigned curDigit = (unsigned) val % radix;
+ if(curDigit > 9)
+ buf[strIndex++] = curDigit + 'a' - 10;
+ else
+ buf[strIndex++] = curDigit + '0';
+
+ val /= radix;
+ }while(val);
+
+ if(isNeg)
+ buf[strIndex++] = '-';
+ buf[strIndex++] = 0;
+
+ /* Now reverse the string */
+ reverse_string_safe(buf, size);
+ return 0;
+}
+
+static SafeInt32 _x64tox_safe(SafeUns64 val, char *buf, size_t size, int radix, int isNeg)
+{
+ if(!buf)
+ {
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+ if(radix < 2 || radix > 36)
+ {
+ return ERROR_SAFE_INVALID_PARAM;
+ }
+ size_t len;
+ SafeUns64 num = 0;
+ if(isNeg)
+ num = (SafeUns64)(-(SafeInt64)val);
+ else
+ num = val;
+ for(len = 2; num; num/= radix) len++; /* quick log_base */
+
+ if(size <= 0 || size < len)
+ {
+ buf[0]='\0';
+ return ERROR_SAFE_BUFFER_OVERFLOW;
+ }
+ /* parameters are valid */
+
+ int strIndex = 0;
+ if(isNeg)
+ val = (SafeUns64)(-(SafeInt64)val);
+
+ do
+ {
+ unsigned curDigit = (unsigned) val % radix;
+ if(curDigit > 9)
+ buf[strIndex++] = curDigit + 'a' - 10;
+ else
+ buf[strIndex++] = curDigit + '0';
+
+ val /= radix;
+ }while(val);
+
+ if(isNeg)
+ buf[strIndex++] = '-';
+ buf[strIndex++] = 0;
+
+ /* Now reverse the string */
+ reverse_string_safe(buf, size);
+ return 0;
+}
+#endif
+
+
+CONDITIONAL_STATIC SafeInt32 _itoa_safe(int val, char* buf, size_t size, int radix)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return _itoa_s(val, buf, size, radix);
+#else
+ if(radix == 10 && val < 0)
+ return _xtox_safe((unsigned long)val, buf, size, radix, 1);
+ else
+ return _xtox_safe((unsigned long)(unsigned int)val, buf, size, radix, 0);
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 _ltoa_safe(long val, char *buf, size_t size, int radix)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return _ltoa_s(val, buf, size, radix);
+#else
+ return _xtox_safe((unsigned long)val, buf, size, radix, (radix == 10 && val < 0));
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 _ultoa_safe(unsigned long val, char *buf, size_t size, int radix)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return _ultoa_s(val, buf, size, radix);
+#else
+ return _xtox_safe(val, buf, size, radix, 0);
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 _i64toa_safe(SafeInt64 val, char* buf, size_t size, int radix)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return _i64toa_s(val, buf, size, radix);
+#else
+ return _x64tox_safe((SafeUns64)val, buf, size, radix, (radix == 10 && val <0 ));
+#endif
+}
+
+CONDITIONAL_STATIC SafeInt32 _ui64toa_safe(SafeUns64 val, char* buf, size_t size, int radix)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return _ui64toa_s(val, buf, size, radix);
+#else
+ return _x64tox_safe(val, buf, size, radix, 0);
+#endif
+}
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+CONDITIONAL_STATIC SafeInt32 _itow_safe(int val, wchar_t *buf, size_t size, int radix)
+{
+ return _itow_s(val, buf, size, radix);
+}
+
+CONDITIONAL_STATIC SafeInt32 _i64tow_safe(SafeInt64 val, wchar_t *buf, size_t size, int radix)
+{
+ return _i64tow_s(val, buf, size, radix);
+}
+
+CONDITIONAL_STATIC SafeInt32 _ui64tow_safe(SafeUns64 val, wchar_t *buf, size_t size, int radix)
+{
+ return _ui64tow_s(val, buf, size, radix);
+}
+
+CONDITIONAL_STATIC SafeInt32 _ltow_safe(long val, wchar_t *str, size_t size, int radix)
+{
+ return _ltow_s(val, str, size, radix);
+}
+
+CONDITIONAL_STATIC SafeInt32 _ultow_safe(unsigned long val, wchar_t *str, size_t size, int radix)
+{
+ return _ultow_s(val, str, size, radix);
+}
+#endif
+
+CONDITIONAL_STATIC char * gets_safe(char* buffer, size_t size)
+{
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+ return gets_s(buffer, size);
+#else
+ if(buffer && size > 0)
+ {
+ char* pointer = buffer;
+ char ch;
+ size_t count = size;
+ ch = (char)getchar();
+ while(ch != (char)EOF && ch != '\n')
+ {
+ if(count > 0)
+ {
+ count--;
+ *pointer++ = ch;
+ }
+ ch = (char)getchar();
+ }
+ if(count == 0)
+ {
+ *buffer = '\0';
+ }
+ else
+ *pointer = '\0';
+ return buffer;
+ }
+ else
+ {
+ return NULL;
+ }
+#endif
+}
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/SafeStringAPIs.h b/core/libs/dngwriter/extra/xmp_sdk/source/SafeStringAPIs.h
new file mode 100644
index 0000000000..705aeb3d2f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/SafeStringAPIs.h
@@ -0,0 +1,650 @@
+/*************************************************************************
+*
+* ADOBE CONFIDENTIAL
+* ___________________
+*
+* Copyright 2010 Adobe Systems Incorporated
+* All Rights Reserved.
+*
+* NOTICE: All information contained herein is, and remains
+* the property of Adobe Systems Incorporated and its suppliers,
+* if any. The intellectual and technical concepts contained
+* herein are proprietary to Adobe Systems Incorporated and its
+* suppliers and are protected by trade secret or copyright law.
+* Dissemination of this information or reproduction of this material
+* is strictly forbidden unless prior written permission is obtained
+* from Adobe Systems Incorporated.
+**************************************************************************/
+
+//Safe String APIs Version 1.0
+
+#ifndef _H_SafeAPIs
+#define _H_SafeAPIs
+
+#include <stddef.h> /* Include standard ANSI C stuff: size_t, NULL etc */
+#include <stdarg.h>
+#include "SuppressSAL.h"
+#include "SafeTypes.h"
+
+/*
+ OVERVIEW:
+ --------
+ This file contains APIs that will map unsafe/banned string functions to their safe equivalents.
+ The objective is to make minimal change at the actual call site.
+
+ There are two sets of APIs in this file.
+ APIs in first set should be invoked for dynamic array buffers, and pointers to buffers.
+ APIs in second set should be invoked for static array buffers.
+
+ Note: Any of the following functions which take more than one argument does not verify whether
+ the buffers provided to them are not overlapping. It currently expects that they do not overlap.
+*/
+
+#define ERROR_SAFE_INVALID_PARAM -1 //Error for invalid parameters passed to the APIs
+#define ERROR_SAFE_BUFFER_OVERFLOW -2 //Error for buffer overflow that could happen on completing the operation
+
+/*
+ NOTE:
+ Defining STATIC_SAFE_API macro prior to #include "SafeMemoryAPIs.h" shall make all
+ the functions defined in SafeMemoryAPIs.h to be static. This macro is intended to
+ be used ONLY in those .c or .cpp files which needs the definition of the SafeMemoryAPIs
+ in the local scope. This macro will help avoiding the linker error due to the redefined
+ symbols from SafeMemoryAPIs.
+ If STATIC_SAFE_API is defined, the warnings for unreferenced local functions will be removed.
+*/
+
+#ifdef STATIC_SAFE_API
+ #if (defined(_WIN32) || defined(_WIN64))
+ #pragma warning( disable : 4505 )
+ #elif defined(__GNUC__)
+ #pragma GCC system_header
+ #endif
+#endif
+
+#ifdef STATIC_SAFE_API
+ #define CONDITIONAL_STATIC static
+#else
+ #define CONDITIONAL_STATIC
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif
+
+//String functions
+
+/* strnlen_safe
+Safe version of strlen. To replace strlen.
+It returns the number of characters in the string (excluding the terminating null).
+If there is no null terminator within the first maxSize bytes of the string then maxSize is returned
+to indicate the error condition; null-terminated strings have lengths strictly less than maxSize.
+
+ex:
+ strnlen_safe("abcd", 5) & strnlen_safe("abcd", 4) will return 4.
+
+ Please use the following replacements for the other Windows-only strnlen APIS.
+ Unsafe/Deprecated | New Safe API
+ _mbslen | _mbsnlen_s
+ wcslen | Don't use it.
+*/
+_Check_return_ CONDITIONAL_STATIC size_t strnlen_safe(_In_z_count_(maxSize) const char *s,
+ _In_ size_t maxSize);
+
+/* strcpy_safe
+Safe version of strcpy. This should be used in place of strcpy, _tcscpy or strcpy.
+size - The max number of characters (in bytes) that are to be copied into the destination including the null terminator.
+Ensures no buffer overflow and ensures null-terminated strings.
+
+RETURNS: Zero if all the characters including the null terminator was copied successfully, negative otherwise.
+
+Note, that the string will be truncated to fit into the buffer.
+
+ex: char buffer[5];
+ strcpy_safe(buffer, 5, "abcde"); -- will make buffer = "abcd" and return ERROR_SAFE_BUFFER_OVERFLOW
+
+ strcpy_safe(buffer, 5, "abc"); -- safe. will execute normally.
+
+ Please use the following replacements for the other Windows-only strcpy APIS.
+ Unsafe/Deprecated | New Safe API
+ lstrcpy | StringCchCopy
+ lstrcpyA | StringCchCopyA
+ lstrcpyW | StringCchCopyW
+ _mbscpy | _mbscpy_s
+ wcscpy | Don't use it.
+*/
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 strcpy_safe(_Out_z_cap_(size) char *dest,
+ _In_ size_t size,
+ _In_z_ const char *src);
+
+/*
+strncpy_safe - To replace strncpy, strncpy and strlcpy
+RETURNS: Zero if successful, negative if unsuccessful.
+A zero return value implies that all of the requested characters from the string pointed to by src fit
+within the array pointed to by dest and that the result in dest is null terminated.
+
+NOTE: n is the number of characters to be copied excluding the NULL terminator.
+
+Also, if the length of the source string is greater than the buffer size, the source string will be truncated to fit
+the buffer.
+
+ex: char buffer[5];
+ strncpy_safe(buffer, 5, "abcde", 5); -- will safely truncate the source string and null terminate buffer.
+ The contents of buffer = "abcd". However,
+ this will return ERROR_SAFE_BUFFER_OVERFLOW.
+
+ strncpy_safe(buffer, 5, "abc", 3); -- contents of buffer = "abc" and return 0.
+*/
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 strncpy_safe(_Out_z_cap_(size) char *dest,
+ _In_ size_t size,
+ _In_z_ const char *src,
+ _In_ size_t n);
+
+/*strcat_safe - Safe version of strcat. To replace strcat.
+Ensures there is no buffer overflow and that the resultant string is null-terminated.
+NOTE: The second argument is the total size of the buffer and not the remaining size
+s1 is the destination to which atmost s1max characters of s2 are appended.
+
+RETURNS: Zero if successful, negative if unsuccessful.
+A zero return value implies that all of the requested characters from the string pointed
+to by s2 were appended to the string pointed to by s1 and that the result in s1 is null terminated.
+ex: char a[10];
+ a= "abcde" and buffer = "abc"
+
+ strcat_safe(a, 10, buffer); -- safe. a will now be "abcdeabc"
+
+ strcat_safe(a, 10, buffer); -- buffer overflow detected. Truncated a = 'abcdeabca'.
+ ERROR_SAFE_BUFFER_OVERFLOW will be returned.
+
+ Please use the following replacements for the other Windows-only strcat APIS.
+ Unsafe/Deprecated | New Safe API
+ lstrcat | StringCchCat
+ lstrcatA | StringCchCatA
+ lstrcatW | StringCchCatW
+ _mbscat | _mbscat_s
+ wcscat | Don't use it.
+*/
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 strcat_safe( _Inout_z_cap_( s1max ) char *s1,
+ _In_ size_t s1max,
+ _In_z_ const char *s2);
+
+/*strncat_safe - Safe version of strncat. To replace strncat and strlcat.
+Ensures there is no buffer overflow and that the resultant string is null-terminated.
+NOTE: The second argument is the total size of the buffer and not the remaining size
+s1 is the destination to which the first n characters of of s2 are appended.
+RETURNS: Zero if successful, an error code if unsuccessful.
+A zero return value implies that all the requested characters from the string pointed to by
+s2 were appended to the string pointed to by s1 and that the result in s1 is null terminated.
+
+ex: a[10].
+ a = "abcde" and buf = "abc".
+ strncat_safe(a, 10, buf, 5) -- will be successful since the length
+ of the src buffer is only 3. The contents
+ of a = "abcdeabc"
+ But, strncat_safe(a, 10, "abcde", 5) --- will set <a> to null and return ERROR_SAFE_BUFFER_OVERFLOW.
+ Again, with a = "abcde"
+ strncat_safe(a, 10, "abcde", 3) -- will be safe. And a = "abcdeabc".
+
+ Please use the following replacements for the other Windows-only strncat APIS.
+ Unsafe/Deprecated | New Safe API
+ lstrncat | StringCchCatN
+ lstrcatnA | StringCchCatNA
+ lstrcatnW | StringCchCatNW
+ _mbsncat | _mbsncat_s
+ wcsncat | Don't use it.
+*/
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 strncat_safe(_Inout_z_cap_(s1max) char *s1,
+ _In_ size_t s1max,
+ _In_z_ const char *s2,
+ _In_ size_t n);
+
+_Check_return_ CONDITIONAL_STATIC char *strchr_safe(_In_z_count_(maxSize) const char *s,
+ _In_ size_t maxSize,
+ _In_ char c);
+
+/* strtok_safe - Safe version of strtok. To replace strtok.
+ strToken: String containing token or tokens.
+ maxSize: The max number of characters (in bytes) that can be present in strToken including the null terminator.
+ strDelimit: Set of delimiter characters.
+ context: Used to store position information between calls to strtok_safe
+
+ Note: The caller function has to see that strToken passed at the first call
+ should be NULL terminated, without which buffer overflow can occur
+
+ Example:
+ static char str1[] = "?a???b,,,#c";
+ static char str2[] = "\t \t";
+ char *t, *ptr1, *ptr2;
+ t = strtok_safe(str1, sizeof(str1), "?", &ptr1);
+ t = strtok_safe(NULL, sizeof(str2), ",", &ptr1);
+
+ will print
+
+ Please use the following replacements for the other Windows-only strtok APIS.
+ Unsafe/Deprecated New Safe API
+ _mbstok _mbstok_s
+ wcstok Don't use it.
+*/
+_Check_return_ CONDITIONAL_STATIC char * strtok_safe(_Inout_opt_z_cap_(maxSize) char* strToken,
+ _In_ size_t maxSize,
+ _In_z_ const char *strDelimit,
+ _Inout_ _Deref_prepost_opt_z_ char **context);
+
+//- Variable argument functions
+/* vprintf_safe: Safe replacement for vprintf. However, for non-Windows platforms,
+ it does not validate format string and hence it is strongly
+ advised not to pass untrusted strings as the format argument.*/
+
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 vprintf_safe(_In_z_ _Printf_format_string_ const char* format,
+ va_list argp);
+
+/* vsprintf: Safe replacement for vsprintf. Avoids buffer overrun and ensures buffer is null-terminated.
+ However, for non-Windows platforms, it does not validate format string and hence it is strongly
+ advised not to pass untrusted strings as the format argument.*/
+CONDITIONAL_STATIC SafeInt32 vsprintf_safe(_Out_z_cap_(size) char* buffer,
+ _In_ size_t size,
+ _In_z_ _Printf_format_string_ const char* format,
+ va_list argp);
+/* vsnprintf_safe */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 vsnprintf_safe(_Out_z_cap_(size) char *buffer,
+ _In_ size_t size,
+ _In_ size_t count,
+ _In_z_ _Printf_format_string_ const char* format,
+ va_list argp);
+
+/* vwprintf_safe: Safe replacement for vwprintf. However, for non-Windows platforms,
+ it does not validate format string and hence it is strongly
+ advised not to pass untrusted strings as the format argument.*/
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 vwprintf_safe(_In_z_ _Printf_format_string_ const wchar_t *format,
+ va_list argp);
+
+// printf functions
+
+/* sprintf_safe. Safe replacement of sprintf. Safer version of sprintf.
+Returns the number of characters written into the buffer including the null terminator, or an error code.
+NOTE: We are still not using a completely safe version of sprintf on non-Windows platforms. The format string is not
+validated here. Format string could be used maliciously.
+But, with the below implementation, we will prevent buffer overruns on all platforms and give us runtime
+checks on Win that we use sprintf correctly.
+
+*/
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 sprintf_safe(_Out_z_cap_(size) char *buffer,
+ _In_ size_t size,
+ _In_z_ _Printf_format_string_ const char *format,
+ ...);
+
+/* printf_safe - Safe version of printf on Windows. Replaces printf. Still UNSAFE on MAC and Unix.
+NOTE: This is UNSAFE to use in Non-Debug mode on any platform other than Windows.
+Please avoid using printf on these platforms or ensure that the format string is not user defined. */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 printf_safe(_In_z_ _Printf_format_string_ const char *format,
+ ...);
+
+/* snprintf_safe: Safe replacement for snprintf. Prevents buffer overrun and ensures buffer is null-terminated.
+For non-Windows platforms, this can still be misused by passing an invalid format string.
+This routine does not validate format string for non-Windows platforms and hence it is strongly
+advised not to pass untrusted strings as the format argument.*/
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 snprintf_safe(_Out_z_cap_(size) char* buffer,
+ _In_ size_t size,
+ _In_ size_t count,
+ _In_z_ _Printf_format_string_ const char *format,
+ ...);
+
+/* wprintf_safe - Safe version of wprintf on Windows. Still UNSAFE on MAC and Unix.
+NOTE: This is UNSAFE to be used in Non-Debug mode on any platform other than Windows.
+Please avoid using printf on these platforms or ensure that the format string is not user defined. */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 wprintf_safe(_In_z_ _Printf_format_string_ const wchar_t *format,
+ ...);
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+
+//splitpath and makepath
+
+/* splitpath_safe - Safe replacement for _splitpath
+ makepath_safe - Safe replacement for _makepath
+These are Windows only routines and are not applicable to Mac and unix platforms.
+RETURN: zero if successful, an error code on failure.
+If any of the buffers is too short to hold the result, these functions clear all the
+buffers to empty strings and return a non-zero error code. */
+
+/*
+ If any of drive, dir, fname, or ext is NULL the corresponding size parameter must be zero.
+ See corresponding documentation in MSDN for _splitpath_s.
+ */
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 splitpath_safe(_In_z_ const char* path,
+ _Out_opt_z_cap_(driveSize) char* drive,
+ _In_ size_t driveSize,
+ _Out_opt_z_cap_(dirSize) char* dir,
+ _In_ size_t dirSize,
+ _Out_opt_z_cap_(fnameSize) char* fname,
+ _In_ size_t fnameSize,
+ _Out_opt_z_cap_(extSize) char* ext,
+ _In_ size_t extSize);
+
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 makepath_safe(_Out_z_cap_(size) char* path,
+ _In_ size_t size,
+ _In_opt_z_ const char* drive,
+ _In_opt_z_ const char* dir,
+ _In_opt_z_ const char* fname,
+ _In_opt_z_ const char* ext);
+
+#endif
+
+/* The following are safe replacements for numeric conversion APIs which are not ANSI C.
+ size is the size of the buffer. It should be large enough to accommodate the resultant string.
+ For radix 2, (sizeof(int)*8 + 1), i.e. one character for each bit + 1 Null character.
+
+ _itoa_safe - Replacement for itoa and _itoa.
+ Returns: Zero if succesful, an error code on failure.*/
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 _itoa_safe(_In_ int val,
+ _Out_z_cap_(size) char* buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _ltoa_safe - Replacement for ltoa and _ltoa */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 _ltoa_safe(_In_ long val,
+ _Out_z_cap_(size) char *buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _ultoa_safe - Replacement for ultoa and _ultoa */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 _ultoa_safe(_In_ unsigned long val,
+ _Out_z_cap_(size) char *buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _i64toa_safe - Replacement for i64toa and _i64toa */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 _i64toa_safe(_In_ SafeInt64 val,
+ _Out_z_cap_(size) char* buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _ui64toa_safe - Replacement for ui64toa and _ui64toa */
+_Check_return_opt_ CONDITIONAL_STATIC SafeInt32 _ui64toa_safe(_In_ SafeUns64 val,
+ _Out_z_cap_(size) char* buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+/* Win APIs only. Preferable don't use them */
+
+/* _itow_safe - Replacement for itow and _itow */
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 _itow_safe(_In_ int val,
+ _Out_z_cap_(size) wchar_t *buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _i64tow_safe - Replacement for i64tow and _i64tow */
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 _i64tow_safe(_In_ SafeInt64 val,
+ _Out_z_cap_(size) wchar_t *buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _ui64tow_safe - Replacement for ui64tow and _ui64tow */
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 _ui64tow_safe(_In_ SafeUns64 val,
+ _Out_z_cap_(size) wchar_t *buf,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _ltow_safe - Replacement for ltow and _ltow */
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 _ltow_safe(_In_ long val,
+ _Out_z_cap_(size) wchar_t *str,
+ _In_ size_t size,
+ _In_ int radix);
+
+/* _ultow_safe - Replacement for ultow and _ultow */
+_Check_return_wat_ CONDITIONAL_STATIC SafeInt32 _ultow_safe(_In_ unsigned long val,
+ _Out_z_cap_(size) wchar_t *str,
+ _In_ size_t size,
+ _In_ int radix);
+#endif
+
+/* gets_safe - to replace gets.
+
+ example: char line[21]; // room for 20 chars + '\0'
+ gets_safe( line, 21 );
+
+ If more than 20 chars are entered, this will set line to NULL.
+
+ NOTE: This routine relies entirely on the user to provide the appropriate size. It has no way of finding out
+ if the buffer is actually smaller than the provided size.
+ Hence, please make sure you provide the right size.
+
+ For eg: char line[5];
+ gets_safe(line, 6);
+
+ will end up reading 6 characters from stdin and overwrite the buffer.
+*/
+_Check_return_wat_ CONDITIONAL_STATIC char * gets_safe( _Out_z_cap_(size) char* buffer,
+ _In_ size_t size);
+
+#if __cplusplus
+}
+#endif
+
+#if __cplusplus // This guard is needed to avoid the templates getting included into C files.
+
+/*
+Methods which will be called for static array buffers.
+Here we will invoke safe version of APIs.
+*/
+
+/*
+char buffer based APIs
+*/
+
+template<size_t _Size>
+_Check_return_ inline SafeUns32 strnlen_safe(const char (&s)[_Size])
+{
+ return strnlen_safe(s, _Size);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 strcpy_safe(char (&dest)[_Size],
+ _In_z_ const char *src)
+{
+ return strcpy_safe(dest, _Size, src);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 strncpy_safe(char (&dest)[_Size],
+ _In_z_ const char *src,
+ _In_ size_t n)
+{
+ return strncpy_safe(dest, _Size, src, n);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 strcat_safe(char (&dest)[_Size],
+ _In_z_ const char *s2)
+{
+ return strcat_safe(dest, _Size, s2);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 strncat_safe(char (&dest)[_Size],
+ _In_z_ const char *s2,
+ _In_ size_t n)
+{
+ return strncat_safe(dest, _Size, s2, n);
+}
+
+template<size_t _Size>
+_Check_return_ inline char *strchr_safe(const char (&s)[_Size],
+ _In_ char c)
+{
+ return strchr_safe(s, _Size, c);
+}
+
+template<size_t _Size>
+inline SafeInt32 vsprintf_safe(char (&buffer)[_Size],
+ _In_z_ _Printf_format_string_ const char* format,
+ va_list argp)
+{
+ return vsprintf_safe(buffer, _Size, format, argp);
+}
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 vsnprintf_safe(char (&buffer)[_Size],
+ _In_ size_t count,
+ _In_z_ _Printf_format_string_ const char* format,
+ ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vsnprintf_safe(buffer, _Size, count, format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+template<size_t _Size>
+inline SafeInt32 sprintf_safe(char (&buffer)[_Size],
+ _In_z_ _Printf_format_string_ const char *format,
+ ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vsprintf_safe(buffer, _Size, format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 snprintf_safe(char (&buffer)[_Size],
+ _In_ size_t count,
+ _In_z_ _Printf_format_string_ const char *format,
+ ...)
+{
+ va_list argp;
+ va_start(argp, format);
+ SafeInt32 numBytes = vsnprintf_safe(buffer, _Size, count, format, argp);
+ va_end(argp);
+ return numBytes;
+}
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+
+template<size_t _DriveSize, size_t _DirSize, size_t _FNameSize, size_t _ExtSize>
+_Check_return_wat_ inline SafeInt32 splitpath_safe(_In_z_ const char* path,
+ char (&drive)[_DriveSize],
+ char (&dir)[_DirSize],
+ char (&fname)[_FNameSize],
+ char (&ext)[_ExtSize])
+
+{
+ return splitpath_safe(path, drive, _DriveSize, dir, _DirSize, fname, _FNameSize, ext, _ExtSize);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 makepath_safe(char (&path)[_Size],
+ _In_opt_z_ const char* drive,
+ _In_opt_z_ const char* dir,
+ _In_opt_z_ const char* fname,
+ _In_opt_z_ const char* ext)
+{
+ return makepath_safe(path, _Size, drive, dir, fname, ext);
+}
+
+#endif
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 _itoa_safe(_In_ int val,
+ char (&buf)[_Size],
+ _In_ int radix)
+{
+ return _itoa_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 _ltoa_safe(_In_ long val,
+ char (&buf)[_Size],
+ _In_ int radix)
+{
+ return _ltoa_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 _ultoa_safe(_In_ unsigned long val,
+ char (&buf)[_Size],
+ _In_ int radix)
+{
+ return _ultoa_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 _i64toa_safe(_In_ SafeInt64 val,
+ char (&buf)[_Size],
+ _In_ int radix)
+{
+ return _i64toa_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_opt_ inline SafeInt32 _ui64toa_safe(_In_ SafeUns64 val,
+ char (&buf)[_Size],
+ _In_ int radix)
+{
+ return _ui64toa_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+inline char * gets_safe( char (&buffer)[_Size])
+{
+ return gets_safe(buffer, _Size);
+}
+
+/*
+for wchar_t based buffers
+*/
+#if (defined(_WIN32) || defined(_WIN64)) && defined __STDC_WANT_SECURE_LIB__
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 _itow_safe(_In_ int val,
+ wchar_t (&buf)[_Size],
+ _In_ int radix)
+{
+ return _itow_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 _i64tow_safe(_In_ SafeInt64 val,
+ wchar_t (&buf)[_Size],
+ _In_ int radix)
+{
+ return _i64tow_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 _ui64tow_safe(_In_ SafeUns64 val,
+ wchar_t (&buf)[_Size],
+ _In_ int radix)
+{
+ return _ui64tow_safe(val, buf, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 _ltow_safe(_In_ long val,
+ wchar_t (&str)[_Size],
+ _In_ int radix)
+{
+ return _ltow_safe(val, str, _Size, radix);
+}
+
+template<size_t _Size>
+_Check_return_wat_ inline SafeInt32 _ultow_safe(_In_ unsigned long val,
+ wchar_t (&str)[_Size],
+ _In_ int radix)
+{
+ return _ultow_safe(val, str, _Size, radix);
+}
+
+#endif
+
+#endif // __cplusplus
+
+/*
+The definition of SafeStringAPIs functions are included if STATIC_SAFE_API is defined.
+*/
+#ifdef STATIC_SAFE_API
+#include "SafeStringAPIs.cpp"
+#endif
+
+#endif //End _H_SafeAPIs
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/SafeTypes.h b/core/libs/dngwriter/extra/xmp_sdk/source/SafeTypes.h
new file mode 100644
index 0000000000..01a6a9dcb8
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/SafeTypes.h
@@ -0,0 +1,187 @@
+/*************************************************************************
+*
+* ADOBE CONFIDENTIAL
+* ___________________
+*
+* Copyright 2010 Adobe Systems Incorporated
+* All Rights Reserved.
+*
+* NOTICE: All information contained herein is, and remains
+* the property of Adobe Systems Incorporated and its suppliers,
+* if any. The intellectual and technical concepts contained
+* herein are proprietary to Adobe Systems Incorporated and its
+* suppliers and are protected by trade secret or copyright law.
+* Dissemination of this information or reproduction of this material
+* is strictly forbidden unless prior written permission is obtained
+* from Adobe Systems Incorporated.
+**************************************************************************/
+
+
+//SafeTypes Version 1.0
+
+#ifndef _H_SafeTypes
+#define _H_SafeTypes
+
+#include <stddef.h> /* Include standard ANSI C stuff: size_t, NULL etc */
+
+/* Integer types
+
+ The following chart shows signed and unsigned integer types.
+
+ +------------+------+--------------+--------------+
+ | Typedef | Bits | Max Value | Min Value |
+ +------------+------+--------------+--------------+
+ | SafeInt8 | 8 | SafeMAXInt8 | SafeMINInt8 |
+ +------------+------+--------------+--------------+
+ | SafeUns8 | 8 | SafeMAXUns8 | SafeMINUns8 |
+ +------------+------+--------------+--------------+
+ | SafeInt16 | 16 | SafeMAXInt16 | SafeMINInt16 |
+ +------------+------+--------------+--------------+
+ | SafeUns16 | 16 | SafeMAXUns16 | SafeMINUns16 |
+ +------------+------+--------------+--------------+
+ | SafeInt32 | 32 | SafeMAXInt32 | SafeMINInt32 |
+ +------------+------+--------------+--------------+
+ | SafeUns32 | 32 | SafeMAXUns32 | SafeMINUns32 |
+ +------------+------+--------------+--------------+
+ | SafeInt64 | 64 | SafeMAXInt64 | SafeMINInt64 |
+ +------------+------+--------------+--------------+
+ | SafeUns64 | 64 | SafeMAXUns64 | SafeMINUns64 |
+ +------------+------+--------------+--------------+
+
+*/
+
+/* If application / component specific types are to be used, define SAFE_INT_TYPES as 0.
+ Note that such specialized types have to be defined as SafeTypes in the following section.
+ */
+
+#ifndef SAFE_INT_TYPES
+#define SAFE_INT_TYPES 1 // Define it as 0, if component specific types are to be used.
+#endif
+
+#if SAFE_INT_TYPES
+
+/* Application / component specific definition for safe integer types goes here.
+ Here is a sample usage:
+ */
+
+#define SafeInt8 XMP_Int8
+#define SafeUns8 XMP_Uns8
+#define SafeInt16 XMP_Int16
+#define SafeUns16 XMP_Uns16
+#define SafeInt32 XMP_Int32
+#define SafeUns32 XMP_Uns32
+#define SafeInt64 XMP_Int64
+#define SafeUns64 XMP_Uns64
+
+/* Application / component specific definition for SafeMathThrow and SafeMathException goes here.
+ Here we use MyException as an example.
+*/
+/*
+** For XMP, there no math function which cause exception, so can be leave no
+*/
+
+#ifdef __cplusplus
+
+#include "XMP_Const.h"
+
+//#define SafeMathThrow throw
+//#define SafeMathException XMP_Error( "Math overflow exception" )
+
+#endif
+
+
+#else
+/* If the Safe Types are not derived from any specialized types,
+ they will be derived from the platform specific types.
+ */
+
+#ifdef _MSC_VER /* Windows VisualC */
+
+typedef __int8 SafeInt8;
+typedef unsigned __int8 SafeUns8;
+typedef __int16 SafeInt16;
+typedef unsigned __int16 SafeUns16;
+typedef __int32 SafeInt32;
+typedef unsigned __int32 SafeUns32;
+typedef __int64 SafeInt64;
+typedef unsigned __int64 SafeUns64;
+
+#else
+
+#include <inttypes.h>
+
+typedef int8_t SafeInt8;
+typedef uint8_t SafeUns8;
+typedef int16_t SafeInt16;
+typedef uint16_t SafeUns16;
+typedef int32_t SafeInt32;
+typedef uint32_t SafeUns32;
+typedef int64_t SafeInt64;
+typedef uint64_t SafeUns64;
+
+#endif /* Windows VisualC */
+
+/* If SafeMathThrow and SafeMathException are not derived from any specialized definitions,
+ the std exceptions will be used
+ */
+
+#ifdef __cplusplus
+
+#include <stdexcept>
+
+#define SafeMathThrow throw
+#define SafeMathException std::overflow_error("Math overflow exception")
+
+#endif
+
+#endif
+
+/* Warning:
+ In case of signed char, the Microsoft VC++ compiler shows a strange behavior. By default, it type cast the "signed char" to "signed int"
+ during function call.
+
+ So you must type cast the "signed char" to "char" or "__int8" (on MS VC++ Compiler) in function calls.
+ It works fine on Linux and MAC.
+
+*/
+#define SafeMAXInt8 127
+#define SafeMINInt8 (-SafeMAXInt8 - 1) // please read above notes
+#define SafeMAXUns8 255
+#define SafeMINUns8 0
+
+#define SafeMAXInt16 32767
+#define SafeMINInt16 (-SafeMAXInt16 - 1) // please read above notes
+#define SafeMAXUns16 65535U
+#define SafeMINUns16 0
+
+#define SafeMAXInt32 2147483647L
+#define SafeMINInt32 (-SafeMAXInt32 - 1) // please read above notes
+#define SafeMAXUns32 4294967295UL
+#define SafeMINUns32 0
+
+#define SafeMAXInt32LL 2147483647LL
+#define SafeMINInt32LL (-SafeMAXInt32LL - 1) // please read above notes
+#define SafeMAXUns32LL 4294967295ULL
+#define SafeMINUns32LL 0
+
+#define SafeMAXInt64 9223372036854775807LL
+#define SafeMINInt64 (-SafeMAXInt64 - 1) // please read above notes
+#define SafeMAXUns64 18446744073709551615ULL
+#define SafeMINUns64 0
+
+// values for quick and dirty check of unsigned 64 bit overflow.
+// They represent SafeMAXUns64 +- 4096 to assure that our
+// tests account for precision loss in conversion to doubles
+// with a 53 bit mantissa.
+
+#define kSafeBigDouble 18446744073709547519.0
+#define kTooBigDouble 18446744073709555711.0
+#define kSafeSmallDouble -18446744073709547519.0
+#define kTooSmallDouble -18446744073709555711.0
+
+#define kSafeBigSignedDouble 9223372036854771711.0
+#define kTooBigSignedDouble 9223372036854779903.0
+#define kSafeSmallSignedDouble -9223372036854771712.0
+#define kTooSmallSignedDouble -9223372036854779904.0
+
+#endif //_H_SafeTypes
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/SuppressSAL.h b/core/libs/dngwriter/extra/xmp_sdk/source/SuppressSAL.h
new file mode 100644
index 0000000000..0d75c72d34
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/SuppressSAL.h
@@ -0,0 +1,614 @@
+/*************************************************************************
+*
+* ADOBE CONFIDENTIAL
+* ___________________
+*
+* Copyright 2010 Adobe Systems Incorporated
+* All Rights Reserved.
+*
+* NOTICE: All information contained herein is, and remains
+* the property of Adobe Systems Incorporated and its suppliers,
+* if any. The intellectual and technical concepts contained
+* herein are proprietary to Adobe Systems Incorporated and its
+* suppliers and are protected by trade secret or copyright law.
+* Dissemination of this information or reproduction of this material
+* is strictly forbidden unless prior written permission is obtained
+* from Adobe Systems Incorporated.
+**************************************************************************/
+
+//SuppressSAL.h Version 1.0
+
+/*
+ * This file defines the Standard Annotation Language(SAL) symbols as empty, for non-windows platform.
+ * This file should be included in multi-platform code which uses SAL, to avoid build breaks
+ * on non-windows platform.
+ */
+
+#ifndef _H_SuppressSAL
+#define _H_SuppressSAL
+
+#if !defined(_WIN32) && !defined(_WIN64) /* The following definition is applicable only for non-windows platform */
+
+#define _In_
+#define _In_opt_
+
+#define _In_z_
+#define _In_opt_z_
+
+#define _In_count_(size)
+#define _In_opt_count_(size)
+#define _In_bytecount_(size)
+#define _In_opt_bytecount_(size)
+
+#define _In_count_c_(size)
+#define _In_opt_count_c_(size)
+#define _In_bytecount_c_(size)
+#define _In_opt_bytecount_c_(size)
+
+#define _In_z_count_(size)
+#define _In_opt_z_count_(size)
+#define _In_z_bytecount_(size)
+#define _In_opt_z_bytecount_(size)
+
+#define _In_z_count_c_(size)
+#define _In_opt_z_count_c_(size)
+#define _In_z_bytecount_c_(size)
+#define _In_opt_z_bytecount_c_(size)
+
+#define _In_ptrdiff_count_(size)
+#define _In_opt_ptrdiff_count_(size)
+
+#define _In_count_x_(size)
+#define _In_opt_count_x_(size)
+#define _In_bytecount_x_(size)
+#define _In_opt_bytecount_x_(size)
+
+#define _Out_
+#define _Out_opt_
+
+#define _Out_cap_(size)
+#define _Out_opt_cap_(size)
+#define _Out_bytecap_(size)
+#define _Out_opt_bytecap_(size)
+
+#define _Out_cap_c_(size)
+#define _Out_opt_cap_c_(size)
+#define _Out_bytecap_c_(size)
+#define _Out_opt_bytecap_c_(size)
+
+#define _Out_cap_m_(mult,size)
+#define _Out_opt_cap_m_(mult,size)
+#define _Out_z_cap_m_(mult,size)
+#define _Out_opt_z_cap_m_(mult,size)
+
+#define _Out_ptrdiff_cap_(size)
+#define _Out_opt_ptrdiff_cap_(size)
+
+#define _Out_cap_x_(size)
+#define _Out_opt_cap_x_(size)
+#define _Out_bytecap_x_(size)
+#define _Out_opt_bytecap_x_(size)
+
+#define _Out_z_cap_(size)
+#define _Out_opt_z_cap_(size)
+#define _Out_z_bytecap_(size)
+#define _Out_opt_z_bytecap_(size)
+
+#define _Out_z_cap_c_(size)
+#define _Out_opt_z_cap_c_(size)
+#define _Out_z_bytecap_c_(size)
+#define _Out_opt_z_bytecap_c_(size)
+
+#define _Out_z_cap_x_(size)
+#define _Out_opt_z_cap_x_(size)
+#define _Out_z_bytecap_x_(size)
+#define _Out_opt_z_bytecap_x_(size)
+
+#define _Out_cap_post_count_(cap,count)
+#define _Out_opt_cap_post_count_(cap,count)
+#define _Out_bytecap_post_bytecount_(cap,count)
+#define _Out_opt_bytecap_post_bytecount_(cap,count)
+
+#define _Out_z_cap_post_count_(cap,count)
+#define _Out_opt_z_cap_post_count_(cap,count)
+#define _Out_z_bytecap_post_bytecount_(cap,count)
+#define _Out_opt_z_bytecap_post_bytecount_(cap,count)
+
+#define _Out_capcount_(capcount)
+#define _Out_opt_capcount_(capcount)
+#define _Out_bytecapcount_(capcount)
+#define _Out_opt_bytecapcount_(capcount)
+
+#define _Out_capcount_x_(capcount)
+#define _Out_opt_capcount_x_(capcount)
+#define _Out_bytecapcount_x_(capcount)
+#define _Out_opt_bytecapcount_x_(capcount)
+
+#define _Out_z_capcount_(capcount)
+#define _Out_opt_z_capcount_(capcount)
+#define _Out_z_bytecapcount_(capcount)
+#define _Out_opt_z_bytecapcount_(capcount)
+
+#define _Inout_
+#define _Inout_opt_
+
+#define _Inout_z_
+#define _Inout_opt_z_
+
+#define _Inout_count_(size)
+#define _Inout_opt_count_(size)
+#define _Inout_bytecount_(size)
+#define _Inout_opt_bytecount_(size)
+
+#define _Inout_count_c_(size)
+#define _Inout_opt_count_c_(size)
+#define _Inout_bytecount_c_(size)
+#define _Inout_opt_bytecount_c_(size)
+
+#define _Inout_z_count_(size)
+#define _Inout_opt_z_count_(size)
+#define _Inout_z_bytecount_(size)
+#define _Inout_opt_z_bytecount_(size)
+
+#define _Inout_z_count_c_(size)
+#define _Inout_opt_z_count_c_(size)
+#define _Inout_z_bytecount_c_(size)
+#define _Inout_opt_z_bytecount_c_(size)
+
+#define _Inout_ptrdiff_count_(size)
+#define _Inout_opt_ptrdiff_count_(size)
+
+#define _Inout_count_x_(size)
+#define _Inout_opt_count_x_(size)
+#define _Inout_bytecount_x_(size)
+#define _Inout_opt_bytecount_x_(size)
+
+#define _Inout_cap_(size)
+#define _Inout_opt_cap_(size)
+#define _Inout_bytecap_(size)
+#define _Inout_opt_bytecap_(size)
+
+#define _Inout_cap_c_(size)
+#define _Inout_opt_cap_c_(size)
+#define _Inout_bytecap_c_(size)
+#define _Inout_opt_bytecap_c_(size)
+
+#define _Inout_cap_x_(size)
+#define _Inout_opt_cap_x_(size)
+#define _Inout_bytecap_x_(size)
+#define _Inout_opt_bytecap_x_(size)
+
+#define _Inout_z_cap_(size)
+#define _Inout_opt_z_cap_(size)
+#define _Inout_z_bytecap_(size)
+#define _Inout_opt_z_bytecap_(size)
+
+#define _Inout_z_cap_c_(size)
+#define _Inout_opt_z_cap_c_(size)
+#define _Inout_z_bytecap_c_(size)
+#define _Inout_opt_z_bytecap_c_(size)
+
+#define _Inout_z_cap_x_(size)
+#define _Inout_opt_z_cap_x_(size)
+#define _Inout_z_bytecap_x_(size)
+#define _Inout_opt_z_bytecap_x_(size)
+
+#define _Ret_
+#define _Ret_opt_
+
+#define _Deref_out_
+#define _Deref_out_opt_
+#define _Deref_opt_out_
+#define _Deref_opt_out_opt_
+
+#define _Deref_out_z_
+#define _Deref_out_opt_z_
+#define _Deref_opt_out_z_
+#define _Deref_opt_out_opt_z_
+
+#define _Check_return_
+#define _Check_return_opt_
+#define _Check_return_wat_
+
+#define _Printf_format_string_
+#define _Scanf_format_string_
+#define _Scanf_s_format_string_
+
+#define _Success_(expr)
+
+#define _In_bound_
+#define _Out_bound_
+#define _Ret_bound_
+#define _Deref_in_bound_
+#define _Deref_out_bound_
+#define _Deref_inout_bound_
+#define _Deref_ret_bound_
+
+#define _In_range_(lb,ub)
+#define _Out_range_(lb,ub)
+#define _Ret_range_(lb,ub)
+#define _Deref_in_range_(lb,ub)
+#define _Deref_out_range_(lb,ub)
+#define _Deref_ret_range_(lb,ub)
+
+#define _Pre_z_
+#define _Pre_opt_z_
+
+#define _Pre_cap_(size)
+#define _Pre_opt_cap_(size)
+#define _Pre_bytecap_(size)
+#define _Pre_opt_bytecap_(size)
+
+#define _Pre_cap_c_(size)
+#define _Pre_opt_cap_c_(size)
+#define _Pre_bytecap_c_(size)
+#define _Pre_opt_bytecap_c_(size)
+
+#define _Pre_cap_m_(mult,size)
+#define _Pre_opt_cap_m_(mult,size)
+
+#define _Pre_cap_for_(param)
+#define _Pre_opt_cap_for_(param)
+
+#define _Pre_cap_x_(size)
+#define _Pre_opt_cap_x_(size)
+#define _Pre_bytecap_x_(size)
+#define _Pre_opt_bytecap_x_(size)
+
+#define _Pre_ptrdiff_cap_(ptr)
+#define _Pre_opt_ptrdiff_cap_(ptr)
+
+#define _Pre_z_cap_(size)
+#define _Pre_opt_z_cap_(size)
+#define _Pre_z_bytecap_(size)
+#define _Pre_opt_z_bytecap_(size)
+
+#define _Pre_z_cap_c_(size)
+#define _Pre_opt_z_cap_c_(size)
+#define _Pre_z_bytecap_c_(size)
+#define _Pre_opt_z_bytecap_c_(size)
+
+#define _Pre_z_cap_x_(size)
+#define _Pre_opt_z_cap_x_(size)
+#define _Pre_z_bytecap_x_(size)
+#define _Pre_opt_z_bytecap_x_(size)
+
+#define _Pre_valid_cap_(size)
+#define _Pre_opt_valid_cap_(size)
+#define _Pre_valid_bytecap_(size)
+#define _Pre_opt_valid_bytecap_(size)
+
+#define _Pre_valid_cap_c_(size)
+#define _Pre_opt_valid_cap_c_(size)
+#define _Pre_valid_bytecap_c_(size)
+#define _Pre_opt_valid_bytecap_c_(size)
+
+#define _Pre_valid_cap_x_(size)
+#define _Pre_opt_valid_cap_x_(size)
+#define _Pre_valid_bytecap_x_(size)
+#define _Pre_opt_valid_bytecap_x_(size)
+
+#define _Pre_count_(size)
+#define _Pre_opt_count_(size)
+#define _Pre_bytecount_(size)
+#define _Pre_opt_bytecount_(size)
+
+#define _Pre_count_c_(size)
+#define _Pre_opt_count_c_(size)
+#define _Pre_bytecount_c_(size)
+#define _Pre_opt_bytecount_c_(size)
+
+#define _Pre_count_x_(size)
+#define _Pre_opt_count_x_(size)
+#define _Pre_bytecount_x_(size)
+#define _Pre_opt_bytecount_x_(size)
+
+#define _Pre_ptrdiff_count_(ptr)
+#define _Pre_opt_ptrdiff_count_(ptr)
+
+#define _Pre_valid_
+#define _Pre_opt_valid_
+
+#define _Pre_invalid_
+
+#define _Pre_notnull_
+#define _Pre_maybenull_
+#define _Pre_null_
+
+#define _Pre_readonly_
+#define _Pre_writeonly_
+
+#define _Post_z_
+
+#define _Post_maybez_
+
+#define _Post_cap_(size)
+#define _Post_bytecap_(size)
+
+#define _Post_count_(size)
+#define _Post_bytecount_(size)
+#define _Post_count_c_(size)
+#define _Post_bytecount_c_(size)
+#define _Post_count_x_(size)
+#define _Post_bytecount_x_(size)
+
+#define _Post_z_count_(size)
+#define _Post_z_bytecount_(size)
+#define _Post_z_count_c_(size)
+#define _Post_z_bytecount_c_(size)
+#define _Post_z_count_x_(size)
+#define _Post_z_bytecount_x_(size)
+
+#define _Post_valid_
+#define _Post_invalid_
+
+#define _Post_notnull_
+
+#define _Ret_z_
+#define _Ret_opt_z_
+
+#define _Ret_cap_(size)
+#define _Ret_opt_cap_(size)
+#define _Ret_bytecap_(size)
+#define _Ret_opt_bytecap_(size)
+
+#define _Ret_cap_c_(size)
+#define _Ret_opt_cap_c_(size)
+#define _Ret_bytecap_c_(size)
+#define _Ret_opt_bytecap_c_(size)
+
+#define _Ret_cap_x_(size)
+#define _Ret_opt_cap_x_(size)
+#define _Ret_bytecap_x_(size)
+#define _Ret_opt_bytecap_x_(size)
+
+#define _Ret_z_cap_(size)
+#define _Ret_opt_z_cap_(size)
+#define _Ret_z_bytecap_(size)
+#define _Ret_opt_z_bytecap_(size)
+
+#define _Ret_count_(size)
+#define _Ret_opt_count_(size)
+#define _Ret_bytecount_(size)
+#define _Ret_opt_bytecount_(size)
+
+#define _Ret_count_c_(size)
+#define _Ret_opt_count_c_(size)
+#define _Ret_bytecount_c_(size)
+#define _Ret_opt_bytecount_c_(size)
+
+#define _Ret_count_x_(size)
+#define _Ret_opt_count_x_(size)
+#define _Ret_bytecount_x_(size)
+#define _Ret_opt_bytecount_x_(size)
+
+#define _Ret_z_count_(size)
+#define _Ret_opt_z_count_(size)
+#define _Ret_z_bytecount_(size)
+#define _Ret_opt_z_bytecount_(size)
+
+#define _Ret_valid_
+#define _Ret_opt_valid_
+
+#define _Ret_notnull_
+#define _Ret_maybenull_
+#define _Ret_null_
+
+#define _Deref_pre_z_
+#define _Deref_pre_opt_z_
+
+#define _Deref_pre_cap_(size)
+#define _Deref_pre_opt_cap_(size)
+#define _Deref_pre_bytecap_(size)
+#define _Deref_pre_opt_bytecap_(size)
+
+#define _Deref_pre_cap_c_(size)
+#define _Deref_pre_opt_cap_c_(size)
+#define _Deref_pre_bytecap_c_(size)
+#define _Deref_pre_opt_bytecap_c_(size)
+
+#define _Deref_pre_cap_x_(size)
+#define _Deref_pre_opt_cap_x_(size)
+#define _Deref_pre_bytecap_x_(size)
+#define _Deref_pre_opt_bytecap_x_(size)
+
+#define _Deref_pre_z_cap_(size)
+#define _Deref_pre_opt_z_cap_(size)
+#define _Deref_pre_z_bytecap_(size)
+#define _Deref_pre_opt_z_bytecap_(size)
+
+#define _Deref_pre_z_cap_c_(size)
+#define _Deref_pre_opt_z_cap_c_(size)
+#define _Deref_pre_z_bytecap_c_(size)
+#define _Deref_pre_opt_z_bytecap_c_(size)
+
+#define _Deref_pre_z_cap_x_(size)
+#define _Deref_pre_opt_z_cap_x_(size)
+#define _Deref_pre_z_bytecap_x_(size)
+#define _Deref_pre_opt_z_bytecap_x_(size)
+
+#define _Deref_pre_valid_cap_(size)
+#define _Deref_pre_opt_valid_cap_(size)
+#define _Deref_pre_valid_bytecap_(size)
+#define _Deref_pre_opt_valid_bytecap_(size)
+
+#define _Deref_pre_valid_cap_c_(size)
+#define _Deref_pre_opt_valid_cap_c_(size)
+#define _Deref_pre_valid_bytecap_c_(size)
+#define _Deref_pre_opt_valid_bytecap_c_(size)
+
+#define _Deref_pre_valid_cap_x_(size)
+#define _Deref_pre_opt_valid_cap_x_(size)
+#define _Deref_pre_valid_bytecap_x_(size)
+#define _Deref_pre_opt_valid_bytecap_x_(size)
+
+#define _Deref_pre_count_(size)
+#define _Deref_pre_opt_count_(size)
+#define _Deref_pre_bytecount_(size)
+#define _Deref_pre_opt_bytecount_(size)
+
+#define _Deref_pre_count_c_(size)
+#define _Deref_pre_opt_count_c_(size)
+#define _Deref_pre_bytecount_c_(size)
+#define _Deref_pre_opt_bytecount_c_(size)
+
+#define _Deref_pre_count_x_(size)
+#define _Deref_pre_opt_count_x_(size)
+#define _Deref_pre_bytecount_x_(size)
+#define _Deref_pre_opt_bytecount_x_(size)
+
+#define _Deref_pre_valid_
+#define _Deref_pre_opt_valid_
+#define _Deref_pre_invalid_
+
+#define _Deref_pre_notnull_
+#define _Deref_pre_maybenull_
+#define _Deref_pre_null_
+
+#define _Deref_pre_readonly_
+#define _Deref_pre_writeonly_
+
+#define _Deref_post_z_
+#define _Deref_post_opt_z_
+
+#define _Deref_post_cap_(size)
+#define _Deref_post_opt_cap_(size)
+#define _Deref_post_bytecap_(size)
+#define _Deref_post_opt_bytecap_(size)
+
+#define _Deref_post_cap_c_(size)
+#define _Deref_post_opt_cap_c_(size)
+#define _Deref_post_bytecap_c_(size)
+#define _Deref_post_opt_bytecap_c_(size)
+
+#define _Deref_post_cap_x_(size)
+#define _Deref_post_opt_cap_x_(size)
+#define _Deref_post_bytecap_x_(size)
+#define _Deref_post_opt_bytecap_x_(size)
+
+#define _Deref_post_z_cap_(size)
+#define _Deref_post_opt_z_cap_(size)
+#define _Deref_post_z_bytecap_(size)
+#define _Deref_post_opt_z_bytecap_(size)
+
+#define _Deref_post_z_cap_c_(size)
+#define _Deref_post_opt_z_cap_c_(size)
+#define _Deref_post_z_bytecap_c_(size)
+#define _Deref_post_opt_z_bytecap_c_(size)
+
+#define _Deref_post_z_cap_x_(size)
+#define _Deref_post_opt_z_cap_x_(size)
+#define _Deref_post_z_bytecap_x_(size)
+#define _Deref_post_opt_z_bytecap_x_(size)
+
+#define _Deref_post_valid_cap_(size)
+#define _Deref_post_opt_valid_cap_(size)
+#define _Deref_post_valid_bytecap_(size)
+#define _Deref_post_opt_valid_bytecap_(size)
+
+#define _Deref_post_valid_cap_c_(size)
+#define _Deref_post_opt_valid_cap_c_(size)
+#define _Deref_post_valid_bytecap_c_(size)
+#define _Deref_post_opt_valid_bytecap_c_(size)
+
+#define _Deref_post_valid_cap_x_(size)
+#define _Deref_post_opt_valid_cap_x_(size)
+#define _Deref_post_valid_bytecap_x_(size)
+#define _Deref_post_opt_valid_bytecap_x_(size)
+
+#define _Deref_post_count_(size)
+#define _Deref_post_opt_count_(size)
+#define _Deref_post_bytecount_(size)
+#define _Deref_post_opt_bytecount_(size)
+
+#define _Deref_post_count_c_(size)
+#define _Deref_post_opt_count_c_(size)
+#define _Deref_post_bytecount_c_(size)
+#define _Deref_post_opt_bytecount_c_(size)
+
+#define _Deref_post_count_x_(size)
+#define _Deref_post_opt_count_x_(size)
+#define _Deref_post_bytecount_x_(size)
+#define _Deref_post_opt_bytecount_x_(size)
+
+#define _Deref_post_valid_
+#define _Deref_post_opt_valid_
+
+#define _Deref_post_notnull_
+#define _Deref_post_maybenull_
+#define _Deref_post_null_
+
+#define _Deref_ret_z_
+#define _Deref_ret_opt_z_
+
+#define _Deref2_pre_readonly_
+
+#define _Prepost_z_
+#define _Prepost_opt_z_
+
+#define _Prepost_count_(size)
+#define _Prepost_opt_count_(size)
+#define _Prepost_bytecount_(size)
+#define _Prepost_opt_bytecount_(size)
+#define _Prepost_count_c_(size)
+#define _Prepost_opt_count_c_(size)
+#define _Prepost_bytecount_c_(size)
+#define _Prepost_opt_bytecount_c_(size)
+#define _Prepost_count_x_(size)
+#define _Prepost_opt_count_x_(size)
+#define _Prepost_bytecount_x_(size)
+#define _Prepost_opt_bytecount_x_(size)
+
+#define _Prepost_valid_
+#define _Prepost_opt_valid_
+
+#define _Deref_prepost_z_
+#define _Deref_prepost_opt_z_
+
+#define _Deref_prepost_cap_(size)
+#define _Deref_prepost_opt_cap_(size)
+#define _Deref_prepost_bytecap_(size)
+#define _Deref_prepost_opt_bytecap_(size)
+
+#define _Deref_prepost_cap_x_(size)
+#define _Deref_prepost_opt_cap_x_(size)
+#define _Deref_prepost_bytecap_x_(size)
+#define _Deref_prepost_opt_bytecap_x_(size)
+
+#define _Deref_prepost_z_cap_(size)
+#define _Deref_prepost_opt_z_cap_(size)
+#define _Deref_prepost_z_bytecap_(size)
+#define _Deref_prepost_opt_z_bytecap_(size)
+
+#define _Deref_prepost_valid_cap_(size)
+#define _Deref_prepost_opt_valid_cap_(size)
+#define _Deref_prepost_valid_bytecap_(size)
+#define _Deref_prepost_opt_valid_bytecap_(size)
+
+#define _Deref_prepost_valid_cap_x_(size)
+#define _Deref_prepost_opt_valid_cap_x_(size)
+#define _Deref_prepost_valid_bytecap_x_(size)
+#define _Deref_prepost_opt_valid_bytecap_x_(size)
+
+#define _Deref_prepost_count_(size)
+#define _Deref_prepost_opt_count_(size)
+#define _Deref_prepost_bytecount_(size)
+#define _Deref_prepost_opt_bytecount_(size)
+
+#define _Deref_prepost_count_x_(size)
+#define _Deref_prepost_opt_count_x_(size)
+#define _Deref_prepost_bytecount_x_(size)
+#define _Deref_prepost_opt_bytecount_x_(size)
+
+#define _Deref_prepost_valid_
+#define _Deref_prepost_opt_valid_
+
+#define _Deref_out_z_cap_c_(size)
+#define _Deref_inout_z_cap_c_(size)
+#define _Deref_out_z_bytecap_c_(size)
+#define _Deref_inout_z_bytecap_c_(size)
+#define _Deref_inout_z_
+
+#endif
+
+#endif //_H_SuppressSAL
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/UnicodeConversions.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/UnicodeConversions.cpp
similarity index 96%
rename from core/libs/dngwriter/extra/xmp_sdk/common/UnicodeConversions.cpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/UnicodeConversions.cpp
index 5013fd2d71..39e4413e2e 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/UnicodeConversions.cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/UnicodeConversions.cpp
@@ -1,1667 +1,1654 @@
// =================================================================================================
-// Copyright 2004-2007 Adobe Systems Incorporated
+// 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 "XMP_Const.h"
+#include "public/include/XMP_Const.h"
-#if UnicodeTestBuild
- #include <cassert>
- #include <stdexcept>
- #define UC_Assert assert
- #define UC_Throw(m,k) throw std::logic_error ( m )
-#else
- #define UC_Assert(cond) /* Nothing for now, should be XMP_Assert. */
- #define UC_Throw(msg,id) throw XMP_Error ( id, msg )
-#endif
+#define UC_Assert(cond) /* Nothing for now, should be XMP_Assert. */
+#define UC_Throw(msg,id) throw XMP_Error ( id, msg )
-#include "UnicodeConversions.hpp"
+#include "source/UnicodeConversions.hpp"
+
+#if SUNOS_SPARC || XMP_IOS_ARM
+ #include "string.h"
+#endif
using namespace std;
-namespace DngXmpSdk {
// =================================================================================================
// *** 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) );
+ 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 XMP_MacBuild && __MWERKS__
-
- #define UTF16InSwap(inPtr) UTF16Unit ( __lhbrx ( (void*)(inPtr), 0 ) )
- #define UTF32InSwap(inPtr) UTF32Unit ( __lwbrx ( (void*)(inPtr), 0 ) )
-
- #define UTF16OutSwap(outPtr,value) __sthbrx ( value, (void*)(outPtr), 0 )
- #define UTF32OutSwap(outPtr,value) __stwbrx ( value, (void*)(outPtr), 0 )
-
+#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 UTF16Unit * inPtr )
- {
- UTF16Unit inUnit = *inPtr;
- return (inUnit << 8) | (inUnit >> 8);
- }
-
- static inline UTF32Unit UTF32InSwap ( const UTF32Unit * inPtr )
- {
- UTF32Unit inUnit = *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 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 UTF32OutSwap ( UTF32Unit * outPtr, const UTF32Unit value )
- {
- UTF32Unit outUnit = (value << 24) | ((value << 8) & 0x00FF0000) | ((value >> 8) & 0x0000FF00) | (value >> 24);
- *outPtr = outUnit;
- }
+static inline void UTF16OutSwap ( UTF16Unit * outPtr, const UTF16Unit value )
+{
+ UTF16Unit outUnit = (value << 8) | (value >> 8);
+ *outPtr = outUnit;
+}
-#endif
+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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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 );
+ if ( writeCount == 0 ) UC_Throw ( "Incomplete Unicode at end of string", kXMPErr_BadUnicode );
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.
- if ( utf8Len == 0 ) goto Done;
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 efficient way to count the bytes.
+
+ #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:
+
+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:
+
+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) );
+ UC_Assert ( (utf16Out != 0) && (utf16Written != 0) );
if ( utf16Len == 0 ) goto Done;
if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP.
-InBMP:
+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) );
+ UC_Assert ( (utf16Out != 0) && (utf16Written != 0) );
if ( utf16Len == 0 ) goto Done;
if ( cpIn >= 0xD800 ) goto CheckSurrogate; // ! Force linear execution path for the BMP.
-InBMP:
+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
-} //namespace
// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/UnicodeConversions.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/UnicodeConversions.hpp
similarity index 93%
rename from core/libs/dngwriter/extra/xmp_sdk/common/UnicodeConversions.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/UnicodeConversions.hpp
index e040cbc07e..f09437c9bb 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/UnicodeConversions.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/UnicodeConversions.hpp
@@ -1,121 +1,115 @@
#ifndef __UnicodeConversions_h__
#define __UnicodeConversions_h__
// =================================================================================================
-// Copyright 2004-2007 Adobe Systems Incorporated
+// 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>
// =================================================================================================
-namespace DngXmpSdk {
-#if UnicodeTestBuild
- typedef unsigned char UTF8Unit;
- typedef unsigned short UTF16Unit;
- typedef unsigned long UTF32Unit;
-#else
- typedef XMP_Uns8 UTF8Unit;
- typedef XMP_Uns16 UTF16Unit;
- typedef XMP_Uns32 UTF32Unit;
-#endif
+
+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?
+// *** 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();
// =================================================================================================
-} //namespace
+
#endif // __UnicodeConversions_h__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/UnicodeInlines.incl_cpp b/core/libs/dngwriter/extra/xmp_sdk/source/UnicodeInlines.incl_cpp
similarity index 97%
rename from core/libs/dngwriter/extra/xmp_sdk/common/UnicodeInlines.incl_cpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/UnicodeInlines.incl_cpp
index 7f4489b115..829132a5a1 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/UnicodeInlines.incl_cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/UnicodeInlines.incl_cpp
@@ -1,131 +1,129 @@
#ifndef __UnicodeInlines_incl_cpp__
#define __UnicodeInlines_incl_cpp__
// =================================================================================================
-// Copyright 2002-2007 Adobe Systems Incorporated
+// 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"
+#include "source/UnicodeConversions.hpp"
-namespace DngXmpSdk {
// =================================================================================================
// 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
// =================================================================================================
-} // namespace DngXmpSdk
#endif // __UnicodeInlines_incl_cpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/XIO.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/XIO.cpp
new file mode 100644
index 0000000000..d05180e2c8
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XIO.cpp
@@ -0,0 +1,238 @@
+// =================================================================================================
+// 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 "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "source/XIO.hpp"
+#include "source/XMP_LibUtils.hpp"
+#include "source/UnicodeConversions.hpp"
+
+#if XMP_WinBuild
+ #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
+#endif
+
+// =================================================================================================
+
+static inline void MakeLowerCase ( std::string * str )
+{
+ for ( size_t i = 0, limit = str->size(); i < limit; ++i ) {
+ char ch = (*str)[i];
+ if ( ('A' <= ch) && (ch <= 'Z') ) (*str)[i] += 0x20;
+ }
+}
+
+// =================================================================================================
+// XIO::SplitLeafName
+// ==================
+
+void XIO::SplitLeafName ( std::string * path, std::string * leafName )
+{
+ size_t dirPos = path->size();
+ // Return if path is empty or just the slash
+ if ( dirPos == 0 || (dirPos == 1 && (*path)[dirPos-1] == kDirChar) )
+ {
+ leafName->erase();
+ path->erase();
+ return;
+ }
+
+ // Remove trailing slashes
+ --dirPos;
+#if XMP_WinBuild
+ if ( (*path)[dirPos] == '/' ) (*path)[dirPos] = kDirChar; // Tolerate both '\' and '/'.
+#endif
+ if ( (*path)[dirPos] == kDirChar )
+ {
+ path->erase(dirPos);
+ }
+
+ // Search next slash
+ for ( --dirPos; dirPos > 0; --dirPos ) {
+ #if XMP_WinBuild
+ if ( (*path)[dirPos] == '/' ) (*path)[dirPos] = kDirChar; // Tolerate both '\' and '/'.
+ #endif
+ if ( (*path)[dirPos] == kDirChar ) break;
+ }
+
+ if ( (*path)[dirPos] == kDirChar ) {
+ leafName->assign ( &(*path)[dirPos+1] );
+ path->erase ( dirPos );
+ } else if ( dirPos == 0 ) {
+ leafName->erase();
+ leafName->swap ( *path );
+ }
+
+} // XIO::SplitLeafName
+
+// =================================================================================================
+// XIO::SplitFileExtension
+// =======================
+//
+// ! Must only be called after using SplitLeafName!
+
+void XIO::SplitFileExtension ( std::string * leafName, std::string * fileExt , bool lowercase )
+{
+
+ fileExt->erase();
+
+ size_t extPos = leafName->size();
+ if ( extPos == 0 ) return;
+
+ for ( --extPos; extPos > 0; --extPos ) if ( (*leafName)[extPos] == '.' ) break;
+
+ if ( (*leafName)[extPos] == '.' ) {
+ fileExt->assign ( &((*leafName)[extPos+1]) );
+ if (lowercase) MakeLowerCase ( fileExt );
+ leafName->erase ( extPos );
+ }
+
+} // XIO::SplitFileExtension
+
+// =================================================================================================
+// XIO::ReplaceTextFile
+// ====================
+//
+// Replace the contents of a text file in a manner that preserves the meaning of the old content if
+// a disk full error occurs. This can mean appended spaces appear in the old content.
+
+void XIO::ReplaceTextFile ( XMP_IO* textFile, const std::string & newContent, bool doSafeUpdate )
+{
+ XMP_Int64 newContentSize = (XMP_Int64)newContent.size();
+ XMP_Enforce ( newContentSize <= (XMP_Int64)0xFFFFFFFFULL ); // Make sure it fits in UInt32 for Write.
+
+ if ( doSafeUpdate ) {
+
+ // Safe updates are no problem, the old content is untouched if the temp file write fails.
+
+ XMP_IO* tempFile = textFile->DeriveTemp();
+ tempFile->Write ( newContent.data(), (XMP_Uns32)newContentSize );
+ textFile->AbsorbTemp();
+
+ } else {
+
+ // We're overwriting the existing file. Make sure it is big enough, write the new content,
+ // then truncate if necessary.
+
+ XMP_Int64 oldContentSize = textFile->Length();
+
+ if ( oldContentSize < newContentSize ) {
+ size_t spaceCount = (size_t) (newContentSize - oldContentSize); // AUDIT: newContentSize fits in UInt32.
+ std::string spaces;
+ spaces.assign ( spaceCount, ' ' );
+ textFile->ToEOF();
+ textFile->Write ( spaces.data(), (XMP_Uns32)spaceCount );
+ }
+
+ XMP_Assert ( newContentSize <= textFile->Length() );
+ textFile->Rewind();
+ textFile->Write ( newContent.data(), (XMP_Uns32)newContentSize );
+
+ if ( oldContentSize > newContentSize ) textFile->Truncate ( newContentSize );
+
+ }
+
+} // XIO::ReplaceTextFile
+
+// =================================================================================================
+// XIO::Copy
+// =========
+
+void XIO::Copy ( XMP_IO* sourceFile, XMP_IO* destFile, XMP_Int64 length,
+ XMP_AbortProc abortProc /* = 0 */, void* abortArg /* = 0 */ )
+{
+ const bool checkAbort = (abortProc != 0);
+ XMP_Uns8 buffer [64*1024];
+
+ while ( length > 0 ) {
+
+ if ( checkAbort && abortProc(abortArg) ) {
+ XMP_Throw ( "XIO::Copy, user abort", kXMPErr_UserAbort );
+ }
+
+ XMP_Int32 ioCount = sizeof(buffer);
+ if ( length < ioCount ) ioCount = (XMP_Int32)length;
+
+ sourceFile->Read ( buffer, ioCount, XMP_IO::kReadAll );
+ destFile->Write ( buffer, ioCount );
+ length -= ioCount;
+
+ }
+
+} // XIO::Copy
+
+// =================================================================================================
+// XIO::Move
+// =========
+
+// allows to move data within a file (just pass in the same file handle as srcFile and dstFile)
+// shadow effects (stumbling over just-written data) are avoided.
+//
+// * however can also be used to move data between two files *
+// (having both option is handy for flexible use in update()/re-write() handler routines)
+
+void XIO::Move ( XMP_IO* srcFile, XMP_Int64 srcOffset,
+ XMP_IO* dstFile, XMP_Int64 dstOffset,
+ XMP_Int64 length, XMP_AbortProc abortProc /* = 0 */, void * abortArg /* = 0 */ )
+{
+ enum { kBufferLen = 64*1024 };
+ XMP_Uns8 buffer [kBufferLen];
+
+ const bool checkAbort = (abortProc != 0);
+
+ if ( srcOffset > dstOffset ) { // avoiding shadow effects
+
+ // move down -> shift lowest packet first !
+
+ while ( length > 0 ) {
+
+ if ( checkAbort && abortProc(abortArg) ) XMP_Throw ( "XIO::Move - User abort", kXMPErr_UserAbort );
+ XMP_Int32 ioCount = kBufferLen;
+ if ( length < kBufferLen ) ioCount = (XMP_Int32)length; //smartly avoids 32/64 bit issues
+
+ srcFile->Seek ( srcOffset, kXMP_SeekFromStart );
+ srcFile->ReadAll ( buffer, ioCount );
+ dstFile->Seek ( dstOffset, kXMP_SeekFromStart );
+ dstFile->Write ( buffer, ioCount );
+ length -= ioCount;
+
+ srcOffset += ioCount;
+ dstOffset += ioCount;
+
+ }
+
+ } else { // move up -> shift highest packet first
+
+ srcOffset += length; //move to end
+ dstOffset += length;
+
+ while ( length > 0 ) {
+
+ if ( checkAbort && abortProc(abortArg) ) XMP_Throw ( "XIO::Move - User abort", kXMPErr_UserAbort );
+ XMP_Int32 ioCount = kBufferLen;
+ if ( length < kBufferLen ) ioCount = (XMP_Int32)length; //smartly avoids 32/64 bit issues
+
+ srcOffset -= ioCount;
+ dstOffset -= ioCount;
+
+ srcFile->Seek ( srcOffset, kXMP_SeekFromStart );
+ srcFile->ReadAll ( buffer, ioCount );
+ dstFile->Seek ( dstOffset, kXMP_SeekFromStart );
+ dstFile->Write ( buffer, ioCount );
+ length -= ioCount;
+
+ }
+
+ }
+
+} // XIO::Move
+
+// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/XIO.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/XIO.hpp
new file mode 100644
index 0000000000..3a8d3b9507
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XIO.hpp
@@ -0,0 +1,388 @@
+#ifndef __XIO_hpp__
+#define __XIO_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 "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "source/Host_IO.hpp"
+#include "source/EndianUtils.hpp"
+
+#include <string>
+
+// =================================================================================================
+// Support for I/O
+// ===============
+
+namespace XIO {
+
+ // =============================================================================================
+ // Internal utilities layered on top of the abstract XMP_IO and XMPFiles_IO classes.
+ // =================================================================================
+
+ void SplitLeafName ( std::string * path, std::string * leafName );
+ void SplitFileExtension ( std::string * path, std::string * fileExt , bool lowercase=true);
+
+ void ReplaceTextFile ( XMP_IO* textFile, const std::string & newContent, bool doSafeUpdate );
+
+ extern void Copy ( XMP_IO* sourceFile, XMP_IO* destFile, XMP_Int64 length,
+ XMP_AbortProc abortProc = 0, void* abortArg = 0 );
+
+ extern void Move ( XMP_IO* sourceFile, XMP_Int64 sourceOffset,
+ XMP_IO* destFile, XMP_Int64 destOffset,
+ XMP_Int64 length, XMP_AbortProc abortProc = 0, void* abortArg = 0 );
+
+ static inline bool CheckFileSpace ( XMP_IO* file, XMP_Int64 length )
+ {
+ XMP_Int64 remaining = file->Length() - file->Offset();
+ return (length <= remaining);
+ }
+
+ // *** Need to absorb more of the utilities like FolderInfo, GetFileMode.
+
+ // =============================================================================================
+ // Inline utilities for endian-oriented reads and writes of numerbers.
+ // ===================================================================
+
+ // -------------------------------------
+ // Unsigned forms that do the real work.
+
+ static inline XMP_Uns8 ReadUns8 ( XMP_IO* file )
+ {
+ XMP_Uns8 value;
+ file->ReadAll ( &value, 1 );
+ return value;
+ }
+
+ static inline XMP_Uns16 ReadUns16_BE ( XMP_IO* file )
+ {
+ XMP_Uns16 value;
+ file->ReadAll ( &value, 2 );
+ return MakeUns16BE ( value );
+ }
+
+ static inline XMP_Uns16 ReadUns16_LE ( XMP_IO* file )
+ {
+ XMP_Uns16 value;
+ file->ReadAll ( &value, 2 );
+ return MakeUns16LE ( value );
+ }
+
+ static inline XMP_Uns32 ReadUns32_BE ( XMP_IO* file )
+ {
+ XMP_Uns32 value;
+ file->ReadAll ( &value, 4 );
+ return MakeUns32BE ( value );
+ }
+
+ static inline XMP_Uns32 ReadUns32_LE ( XMP_IO* file )
+ {
+ XMP_Uns32 value;
+ file->ReadAll ( &value, 4 );
+ return MakeUns32LE ( value );
+ }
+
+ static inline XMP_Uns64 ReadUns64_BE ( XMP_IO* file )
+ {
+ XMP_Uns64 value;
+ file->ReadAll ( &value, 8 );
+ return MakeUns64BE ( value );
+ }
+
+ static inline XMP_Uns64 ReadUns64_LE ( XMP_IO* file )
+ {
+ XMP_Uns64 value;
+ file->ReadAll ( &value, 8 );
+ return MakeUns64LE ( value );
+ }
+
+ static inline XMP_Uns8 PeekUns8 ( XMP_IO* file )
+ {
+ XMP_Uns8 value = XIO::ReadUns8 ( file );
+ file->Seek ( -1, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline XMP_Uns16 PeekUns16_BE ( XMP_IO* file )
+ {
+ XMP_Uns16 value = XIO::ReadUns16_BE ( file );
+ file->Seek ( -2, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline XMP_Uns16 PeekUns16_LE ( XMP_IO* file )
+ {
+ XMP_Uns16 value = XIO::ReadUns16_LE ( file );
+ file->Seek ( -2, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline XMP_Uns32 PeekUns32_BE ( XMP_IO* file )
+ {
+ XMP_Uns32 value = XIO::ReadUns32_BE ( file );
+ file->Seek ( -4, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline XMP_Uns32 PeekUns32_LE ( XMP_IO* file )
+ {
+ XMP_Uns32 value = XIO::ReadUns32_LE ( file );
+ file->Seek ( -4, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline XMP_Uns64 PeekUns64_BE ( XMP_IO* file )
+ {
+ XMP_Uns64 value = XIO::ReadUns64_BE ( file );
+ file->Seek ( -8, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline XMP_Uns64 PeekUns64_LE ( XMP_IO* file )
+ {
+ XMP_Uns64 value = XIO::ReadUns64_LE ( file );
+ file->Seek ( -8, kXMP_SeekFromCurrent );
+ return value;
+ }
+
+ static inline void WriteUns8 ( XMP_IO* file, XMP_Uns8 value )
+ {
+ file->Write ( &value, 1 );
+ }
+
+ static inline void WriteUns16_BE ( XMP_IO* file, XMP_Uns16 value )
+ {
+ XMP_Uns16 v = MakeUns16BE ( value );
+ file->Write ( &v, 2 );
+ }
+
+ static inline void WriteUns16_LE ( XMP_IO* file, XMP_Uns16 value )
+ {
+ XMP_Uns16 v = MakeUns16LE ( value );
+ file->Write ( &v, 2 );
+ }
+
+ static inline void WriteUns32_BE ( XMP_IO* file, XMP_Uns32 value )
+ {
+ XMP_Uns32 v = MakeUns32BE ( value );
+ file->Write ( &v, 4 );
+ }
+
+ static inline void WriteUns32_LE ( XMP_IO* file, XMP_Uns32 value )
+ {
+ XMP_Uns32 v = MakeUns32LE ( value );
+ file->Write ( &v, 4 );
+ }
+
+ static inline void WriteUns64_BE ( XMP_IO* file, XMP_Uns64 value )
+ {
+ XMP_Uns64 v = MakeUns64BE ( value );
+ file->Write ( &v, 8 );
+ }
+
+ static inline void WriteUns64_LE ( XMP_IO* file, XMP_Uns64 value )
+ {
+ XMP_Uns64 v = MakeUns64LE ( value );
+ file->Write ( &v, 8 );
+ }
+
+ // ------------------------------------------------------------------
+ // Signed forms that just cast to unsigned and use the unsigned call.
+
+ static inline XMP_Int8 ReadInt8 ( XMP_IO* file )
+ {
+ return (XMP_Int8) XIO::ReadUns8 ( file );
+ }
+
+ static inline XMP_Int16 ReadInt16_BE ( XMP_IO* file )
+ {
+ return (XMP_Int16) XIO::ReadUns16_BE ( file );
+ }
+
+ static inline XMP_Int16 ReadInt16_LE ( XMP_IO* file )
+ {
+ return (XMP_Int16) XIO::ReadUns16_LE ( file );
+ }
+
+ static inline XMP_Int32 ReadInt32_BE ( XMP_IO* file )
+ {
+ return (XMP_Int32) XIO::ReadUns32_BE ( file );
+ }
+
+ static inline XMP_Int32 ReadInt32_LE ( XMP_IO* file )
+ {
+ return (XMP_Int32) XIO::ReadUns32_LE ( file );
+ }
+
+ static inline XMP_Int64 ReadInt64_BE ( XMP_IO* file )
+ {
+ return (XMP_Int64) XIO::ReadUns64_BE ( file );
+ }
+
+ static inline XMP_Int64 ReadInt64_LE ( XMP_IO* file )
+ {
+ return (XMP_Int64) XIO::ReadUns64_LE ( file );
+ }
+
+ static inline XMP_Int8 PeekInt8 ( XMP_IO* file )
+ {
+ return (XMP_Int8) XIO::PeekUns8 ( file );
+ }
+
+ static inline XMP_Int16 PeekInt16_BE ( XMP_IO* file )
+ {
+ return (XMP_Int16) XIO::PeekUns16_BE ( file );
+ }
+
+ static inline XMP_Int16 PeekInt16_LE ( XMP_IO* file )
+ {
+ return (XMP_Int16) XIO::PeekUns16_LE ( file );
+ }
+
+ static inline XMP_Int32 PeekInt32_BE ( XMP_IO* file )
+ {
+ return (XMP_Int32) XIO::PeekUns32_BE ( file );
+ }
+
+ static inline XMP_Int32 PeekInt32_LE ( XMP_IO* file )
+ {
+ return (XMP_Int32) XIO::PeekUns32_LE ( file );
+ }
+
+ static inline XMP_Int64 PeekInt64_BE ( XMP_IO* file )
+ {
+ return (XMP_Int64) XIO::PeekUns64_BE ( file );
+ }
+
+ static inline XMP_Int64 PeekInt64_LE ( XMP_IO* file )
+ {
+ return (XMP_Int64) XIO::PeekUns64_LE ( file );
+ }
+
+ static inline void WriteInt8 ( XMP_IO* file, XMP_Int8 value )
+ {
+ XIO::WriteUns8 ( file, (XMP_Uns8)value );
+ }
+
+ static inline void WriteInt16_BE ( XMP_IO* file, XMP_Int16 value )
+ {
+ XIO::WriteUns16_BE ( file, (XMP_Uns16)value );
+ }
+
+ static inline void WriteInt16_LE ( XMP_IO* file, XMP_Int16 value )
+ {
+ XIO::WriteUns16_LE ( file, (XMP_Uns16)value );
+ }
+
+ static inline void WriteInt32_BE ( XMP_IO* file, XMP_Int32 value )
+ {
+ XIO::WriteUns32_BE ( file, (XMP_Uns32)value );
+ }
+
+ static inline void WriteInt32_LE ( XMP_IO* file, XMP_Int32 value )
+ {
+ XIO::WriteUns32_LE ( file, (XMP_Uns32)value );
+ }
+
+ static inline void WriteInt64_BE ( XMP_IO* file, XMP_Int64 value )
+ {
+ XIO::WriteUns64_BE ( file, (XMP_Uns64)value );
+ }
+
+ static inline void WriteInt64_LE ( XMP_IO* file, XMP_Int64 value )
+ {
+ XIO::WriteUns64_LE ( file, (XMP_Uns64)value );
+ }
+
+};
+
+// =================================================================================================
+
+// **********************************************************************************************
+// I/O buffer used in JPEG, PSD, and TIFF handlers. Discredited, a mistake, do not use elsewhere.
+// **********************************************************************************************
+
+// -------------------------------------------------------------------------------------------------
+// CheckFileSpace and RefillBuffer
+// -------------------------------
+//
+// There is always a problem in file scanning of managing what you want to check against what is
+// available in a buffer, trying to keep the logic understandable and minimize data movement. The
+// CheckFileSpace and RefillBuffer functions are used here for a standard scanning model.
+//
+// The format scanning routines have an outer, "infinite" loop that looks for file markers. There
+// is a local (on stack) buffer, a pointer to the current position in the buffer, and a pointer for
+// the end of the buffer. The end pointer is just past the end of the buffer, "bufPtr == bufLimit"
+// means you are out of data. The outer loop ends when the necessary markers are found or we reach
+// the end of the file.
+//
+// The filePos is the file offset of the start of the current buffer. This is maintained so that
+// we can tell where the packet is in the file, part of the info returned to the client.
+//
+// At each check CheckFileSpace is used to make sure there is enough data in the buffer for the
+// check to be made. It refills the buffer if necessary, preserving the unprocessed data, setting
+// bufPtr and bufLimit appropriately. If we are too close to the end of the file to make the check
+// a failure status is returned.
+
+enum { kIOBufferSize = 128*1024 };
+
+struct IOBuffer {
+ XMP_Int64 filePos;
+ XMP_Uns8* ptr;
+ XMP_Uns8* limit;
+ size_t len;
+ XMP_Uns8 data [kIOBufferSize];
+ IOBuffer() : filePos(0), ptr(&data[0]), limit(ptr), len(0) {};
+};
+
+static inline void FillBuffer ( XMP_IO* fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
+{
+ ioBuf->filePos = fileRef->Seek ( fileOffset, kXMP_SeekFromStart );
+ if ( ioBuf->filePos != fileOffset ) {
+ throw XMP_Error ( kXMPErr_ExternalFailure, "Seek failure in FillBuffer" );
+ }
+ ioBuf->len = fileRef->Read ( &ioBuf->data[0], kIOBufferSize );
+ ioBuf->ptr = &ioBuf->data[0];
+ ioBuf->limit = ioBuf->ptr + ioBuf->len;
+}
+
+static inline void MoveToOffset ( XMP_IO* fileRef, XMP_Int64 fileOffset, IOBuffer* ioBuf )
+{
+ if ( (ioBuf->filePos <= fileOffset) && (fileOffset < (XMP_Int64)(ioBuf->filePos + ioBuf->len)) ) {
+ size_t bufOffset = (size_t)(fileOffset - ioBuf->filePos);
+ ioBuf->ptr = &ioBuf->data[bufOffset];
+ } else {
+ FillBuffer ( fileRef, fileOffset, ioBuf );
+ }
+}
+
+static inline void RefillBuffer ( XMP_IO* fileRef, IOBuffer* ioBuf )
+{
+ // Refill including part of the current data, seek back to the new buffer origin and read.
+ ioBuf->filePos += (ioBuf->ptr - &ioBuf->data[0]); // ! Increment before the read.
+ size_t bufTail = ioBuf->limit - ioBuf->ptr; // We'll re-read the tail portion of the buffer.
+ if ( bufTail > 0 ) ioBuf->filePos = fileRef->Seek ( -((XMP_Int64)bufTail), kXMP_SeekFromCurrent );
+ ioBuf->len = fileRef->Read ( &ioBuf->data[0], kIOBufferSize );
+ ioBuf->ptr = &ioBuf->data[0];
+ ioBuf->limit = ioBuf->ptr + ioBuf->len;
+}
+
+static inline bool CheckFileSpace ( XMP_IO* fileRef, IOBuffer* ioBuf, size_t neededLen )
+{
+ if ( size_t(ioBuf->limit - ioBuf->ptr) < size_t(neededLen) ) { // ! Avoid VS.Net compare warnings.
+ RefillBuffer ( fileRef, ioBuf );
+ }
+ return (size_t(ioBuf->limit - ioBuf->ptr) >= size_t(neededLen));
+}
+
+#endif // __XIO_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/XMLParserAdapter.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMLParserAdapter.hpp
similarity index 86%
rename from core/libs/dngwriter/extra/xmp_sdk/common/XMLParserAdapter.hpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/XMLParserAdapter.hpp
index a2f03b5a7c..b337cb6fe6 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/XMLParserAdapter.hpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMLParserAdapter.hpp
@@ -1,141 +1,155 @@
#ifndef __XMLParserAdapter_hpp__
#define __XMLParserAdapter_hpp__
// =================================================================================================
-// Copyright 2005-2007 Adobe Systems Incorporated
+// 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 "XMP_Environment.h" // ! Must be the first #include!
-#include "XMP_Const.h"
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "public/include/XMP_Const.h"
+
+#include "source/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.
-namespace DngXmpSdk {
+
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)
+ 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
};
// =================================================================================================
-} //namespace
#endif // __XMLParserAdapter_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/common/XML_Node.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/XML_Node.cpp
similarity index 95%
rename from core/libs/dngwriter/extra/xmp_sdk/common/XML_Node.cpp
rename to core/libs/dngwriter/extra/xmp_sdk/source/XML_Node.cpp
index a19a8dc1f0..c71c312841 100644
--- a/core/libs/dngwriter/extra/xmp_sdk/common/XML_Node.cpp
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XML_Node.cpp
@@ -1,463 +1,473 @@
// =================================================================================================
-// Copyright 2005-2007 Adobe Systems Incorporated
+// 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 "XMP_Environment.h" // ! Must be the first #include!
-#include "XMLParserAdapter.hpp"
+#include "public/include/XMP_Environment.h" // ! Must be the first #include!
+#include "source/XMLParserAdapter.hpp"
#include <map>
#include <cstring>
#include <cstdio>
-namespace DngXmpSdk {
// ! 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", node->nsPrefixLen );
+ 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
-} //namespace
// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/XMPFiles_IO.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMPFiles_IO.cpp
new file mode 100644
index 0000000000..3d3c45ef78
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMPFiles_IO.cpp
@@ -0,0 +1,388 @@
+ // =================================================================================================
+// 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 "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "source/XMP_LibUtils.hpp"
+#include "source/XMPFiles_IO.hpp"
+#include "source/XIO.hpp"
+
+
+#define EMPTY_FILE_PATH ""
+#define XMP_FILESIO_STATIC_START try { /* int a;*/
+#define XMP_FILESIO_STATIC_END1(errorCallbackPtr, filePath, severity) \
+ /*a = 1;*/ \
+ } catch ( XMP_Error & error ) { \
+ if ( (errorCallbackPtr) != NULL ) (errorCallbackPtr)->NotifyClient ( (severity), error, (filePath) ); \
+ else throw; \
+ }
+#define XMP_FILESIO_START try { /*int b;*/
+#define XMP_FILESIO_END1(severity) \
+ /*b = 1;*/ \
+ } catch ( XMP_Error & error ) { \
+ if ( errorCallback != NULL ) errorCallback->NotifyClient ( (severity), error, filePath.c_str() ); \
+ else throw; \
+ }
+#define XMP_FILESIO_END2(filePath, severity) \
+ /* b = 1;*/ \
+ } catch ( XMP_Error & error ) { \
+ if ( errorCallback != NULL ) errorCallback->NotifyClient ( (severity), error, (filePath) ); \
+ else throw; \
+ }
+#define XMP_FILESIO_STATIC_NOTIFY_ERROR(errorCallbackPtr, filePath, severity, error) \
+ if ( (errorCallbackPtr) != NULL ) errorCallbackPtr->NotifyClient ( (severity), (error), (filePath) );
+#define XMP_FILESIO_NOTIFY_ERROR(filePath, severity, error) \
+ XMP_FILESIO_STATIC_NOTIFY_ERROR(errorCallback, (filePath), (severity), (error))
+
+
+// =================================================================================================
+// XMPFiles_IO::New_XMPFiles_IO
+// ============================
+
+/* class static */
+XMPFiles_IO * XMPFiles_IO::New_XMPFiles_IO (
+ const char * filePath,
+ bool readOnly,
+ GenericErrorCallback * _errorCallback,
+ XMP_ProgressTracker * _progressTracker )
+{
+ XMP_FILESIO_STATIC_START
+ Host_IO::FileRef hostFile = Host_IO::noFileRef;
+
+ switch ( Host_IO::GetFileMode ( filePath ) ) {
+ case Host_IO::kFMode_IsFile:
+ hostFile = Host_IO::Open ( filePath, readOnly );
+ break;
+ case Host_IO::kFMode_DoesNotExist:
+ break;
+ default:
+ XMP_Throw ( "New_XMPFiles_IO, path must be a file or not exist", kXMPErr_FilePathNotAFile );
+ }
+ if ( hostFile == Host_IO::noFileRef ) {
+ XMP_Error error (kXMPErr_NoFile, "New_XMPFiles_IO, file does not exist");
+ XMP_FILESIO_STATIC_NOTIFY_ERROR ( _errorCallback, filePath, kXMPErrSev_Recoverable, error );
+ return 0;
+ }
+
+ Host_IO::Rewind ( hostFile ); // Make sure offset really is 0.
+
+ XMPFiles_IO * newFile = new XMPFiles_IO ( hostFile, filePath, readOnly, _errorCallback, _progressTracker );
+ return newFile;
+ XMP_FILESIO_STATIC_END1 ( _errorCallback, filePath, kXMPErrSev_FileFatal )
+ return NULL;
+
+} // XMPFiles_IO::New_XMPFiles_IO
+
+// =================================================================================================
+// XMPFiles_IO::XMPFiles_IO
+// ========================
+
+XMPFiles_IO::XMPFiles_IO (
+ Host_IO::FileRef hostFile,
+ const char * _filePath,
+ bool _readOnly,
+ GenericErrorCallback * _errorCallback,
+ XMP_ProgressTracker * _progressTracker )
+ : readOnly(_readOnly)
+ , filePath(_filePath)
+ , fileRef(hostFile)
+ , currOffset(0)
+ , isTemp(false)
+ , derivedTemp(0)
+ , errorCallback(_errorCallback)
+ , progressTracker(_progressTracker)
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+
+ this->currLength = Host_IO::Length ( this->fileRef );
+ XMP_FILESIO_END2 ( _filePath, kXMPErrSev_FileFatal )
+} // XMPFiles_IO::XMPFiles_IO
+
+// =================================================================================================
+// XMPFiles_IO::~XMPFiles_IO
+// =========================
+
+XMPFiles_IO::~XMPFiles_IO()
+{
+ try {
+ XMP_FILESIO_START
+ if ( this->derivedTemp != 0 ) this->DeleteTemp();
+ if ( this->fileRef != Host_IO::noFileRef ) Host_IO::Close ( this->fileRef );
+ if ( this->isTemp && (! this->filePath.empty()) ) Host_IO::Delete ( this->filePath.c_str() );
+ XMP_FILESIO_END1 ( kXMPErrSev_Recoverable )
+ } catch ( ... ) {
+ // All of the above is fail-safe cleanup, ignore problems.
+ }
+} // XMPFiles_IO::~XMPFiles_IO
+
+// =================================================================================================
+// XMPFiles_IO::operator=
+// ======================
+
+void XMPFiles_IO::operator = ( const XMP_IO& in )
+{
+ XMP_FILESIO_START
+ XMP_Throw ( "No assignment for XMPFiles_IO", kXMPErr_InternalFailure );
+ XMP_FILESIO_END1 ( kXMPErrSev_OperationFatal )
+
+}; // XMPFiles_IO::operator=
+
+// =================================================================================================
+// XMPFiles_IO::Read
+// =================
+
+XMP_Uns32 XMPFiles_IO::Read ( void * buffer, XMP_Uns32 count, bool readAll /* = false */ )
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+ XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
+ XMP_Assert ( this->currOffset <= this->currLength );
+
+ if ( count > (this->currLength - this->currOffset) ) {
+ if ( readAll ) XMP_Throw ( "XMPFiles_IO::Read, not enough data", kXMPErr_EnforceFailure );
+ count = (XMP_Uns32) (this->currLength - this->currOffset);
+ }
+
+ XMP_Uns32 amountRead = Host_IO::Read ( this->fileRef, buffer, count );
+ XMP_Enforce ( amountRead == count );
+
+ this->currOffset += amountRead;
+ return amountRead;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+ return 0;
+
+} // XMPFiles_IO::Read
+
+// =================================================================================================
+// XMPFiles_IO::Write
+// ==================
+
+void XMPFiles_IO::Write ( const void * buffer, XMP_Uns32 count )
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+ XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
+ XMP_Assert ( this->currOffset <= this->currLength );
+
+ try {
+ if ( this->readOnly )
+ XMP_Throw ( "New_XMPFiles_IO, write not permitted on read only file", kXMPErr_FilePermission );
+ Host_IO::Write ( this->fileRef, buffer, count );
+ if ( this->progressTracker != 0 ) this->progressTracker->AddWorkDone ( (float) count );
+ } catch ( ... ) {
+ try {
+ // we should try to maintain the state as best as possible
+ // but no exception should escape from this backup plan.
+ // Make sure the internal state reflects partial writes.
+ this->currOffset = Host_IO::Offset ( this->fileRef );
+ this->currLength = Host_IO::Length ( this->fileRef );
+ } catch ( ... ) {
+ // don't do anything
+ }
+ throw;
+ }
+
+ this->currOffset += count;
+ if ( this->currOffset > this->currLength ) this->currLength = this->currOffset;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+
+} // XMPFiles_IO::Write
+
+// =================================================================================================
+// XMPFiles_IO::Seek
+// =================
+
+XMP_Int64 XMPFiles_IO::Seek ( XMP_Int64 offset, SeekMode mode )
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+ XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
+
+ XMP_Int64 newOffset = offset;
+ if ( mode == kXMP_SeekFromCurrent ) {
+ newOffset += this->currOffset;
+ } else if ( mode == kXMP_SeekFromEnd ) {
+ newOffset += this->currLength;
+ }
+ XMP_Enforce ( newOffset >= 0 );
+
+ if ( newOffset <= this->currLength ) {
+ this->currOffset = Host_IO::Seek ( this->fileRef, offset, mode );
+ } else if ( this->readOnly ) {
+ XMP_Throw ( "XMPFiles_IO::Seek, read-only seek beyond EOF", kXMPErr_EnforceFailure );
+ } else {
+ Host_IO::SetEOF ( this->fileRef, newOffset ); // Extend a file open for writing.
+ this->currLength = newOffset;
+ this->currOffset = Host_IO::Seek ( this->fileRef, 0, kXMP_SeekFromEnd );
+ }
+
+ XMP_Assert ( this->currOffset == newOffset );
+ return this->currOffset;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal );
+ return -1;
+
+} // XMPFiles_IO::Seek
+
+// =================================================================================================
+// XMPFiles_IO::Length
+// ===================
+
+XMP_Int64 XMPFiles_IO::Length()
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+ XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+ return this->currLength;
+
+} // XMPFiles_IO::Length
+
+// =================================================================================================
+// XMPFiles_IO::Truncate
+// =====================
+
+void XMPFiles_IO::Truncate ( XMP_Int64 length )
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+ XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_Assert ( this->currLength == Host_IO::Length ( this->fileRef ) );
+
+ if ( this->readOnly )
+ XMP_Throw ( "New_XMPFiles_IO, truncate not permitted on read only file", kXMPErr_FilePermission );
+
+ XMP_Enforce ( length <= this->currLength );
+ Host_IO::SetEOF ( this->fileRef, length );
+
+ this->currLength = length;
+ if ( this->currOffset > this->currLength ) this->currOffset = this->currLength;
+
+ // ! Seek to the expected offset, some versions of Host_IO::SetEOF implicitly seek to EOF.
+ Host_IO::Seek ( this->fileRef, this->currOffset, kXMP_SeekFromStart );
+ XMP_Assert ( this->currOffset == Host_IO::Offset ( this->fileRef ) );
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+
+} // XMPFiles_IO::Truncate
+
+// =================================================================================================
+// XMPFiles_IO::DeriveTemp
+// =======================
+
+XMP_IO* XMPFiles_IO::DeriveTemp()
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+
+ if ( this->derivedTemp != 0 ) return this->derivedTemp;
+
+ if ( this->readOnly ) {
+ XMP_Throw ( "XMPFiles_IO::DeriveTemp, can't derive from read-only", kXMPErr_InternalFailure );
+ }
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+
+ std::string tempPath;
+
+ XMP_FILESIO_START
+ tempPath = Host_IO::CreateTemp ( this->filePath.c_str() );
+
+ XMPFiles_IO* newTemp = XMPFiles_IO::New_XMPFiles_IO ( tempPath.c_str(), Host_IO::openReadWrite );
+ if ( newTemp == 0 ) {
+ Host_IO::Delete ( tempPath.c_str() );
+ XMP_Throw ( "XMPFiles_IO::DeriveTemp, can't open temp file", kXMPErr_InternalFailure );
+ }
+
+ newTemp->isTemp = true;
+ this->derivedTemp = newTemp;
+ newTemp->progressTracker = this->progressTracker; // Automatically track writes to the temp file.
+ XMP_FILESIO_END2 ( tempPath.c_str(), kXMPErrSev_FileFatal )
+ return this->derivedTemp;
+
+} // XMPFiles_IO::DeriveTemp
+
+// =================================================================================================
+// XMPFiles_IO::AbsorbTemp
+// =======================
+
+void XMPFiles_IO::AbsorbTemp()
+{
+ XMP_FILESIO_START
+ XMP_Assert ( this->fileRef != Host_IO::noFileRef );
+
+ XMPFiles_IO * temp = this->derivedTemp;
+ if ( temp == 0 ) {
+ XMP_Throw ( "XMPFiles_IO::AbsorbTemp, no temp to absorb", kXMPErr_InternalFailure );
+ }
+ XMP_Assert ( temp->isTemp );
+
+ this->Close();
+ temp->Close();
+
+ Host_IO::SwapData ( this->filePath.c_str(), temp->filePath.c_str() );
+ this->DeleteTemp();
+
+ this->fileRef = Host_IO::Open ( this->filePath.c_str(), Host_IO::openReadWrite );
+ this->currLength = Host_IO::Length ( this->fileRef );
+ this->currOffset = 0;
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+
+} // XMPFiles_IO::AbsorbTemp
+
+// =================================================================================================
+// XMPFiles_IO::DeleteTemp
+// =======================
+
+void XMPFiles_IO::DeleteTemp()
+{
+ XMP_FILESIO_START
+ XMPFiles_IO * temp = this->derivedTemp;
+
+ if ( temp != 0 ) {
+
+ if ( temp->fileRef != Host_IO::noFileRef ) {
+ Host_IO::Close ( temp->fileRef );
+ temp->fileRef = Host_IO::noFileRef;
+ }
+
+ if ( ! temp->filePath.empty() ) {
+ Host_IO::Delete ( temp->filePath.c_str() );
+ temp->filePath.erase();
+ }
+
+ delete temp;
+ this->derivedTemp = 0;
+
+ }
+ XMP_FILESIO_END2 ( this->derivedTemp->filePath.c_str(), kXMPErrSev_FileFatal )
+
+} // XMPFiles_IO::DeleteTemp
+
+// =================================================================================================
+// XMPFiles_IO::Close
+// ==================
+
+void XMPFiles_IO::Close()
+{
+ XMP_FILESIO_START
+ if ( this->fileRef != Host_IO::noFileRef ) {
+ Host_IO::Close ( this->fileRef );
+ this->fileRef = Host_IO::noFileRef;
+ }
+ XMP_FILESIO_END1 ( kXMPErrSev_FileFatal )
+
+} // XMPFiles_IO::Close
+
+// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/XMPFiles_IO.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMPFiles_IO.hpp
new file mode 100644
index 0000000000..728641f033
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMPFiles_IO.hpp
@@ -0,0 +1,97 @@
+#ifndef __XMPFiles_IO_hpp__
+#define __XMPFiles_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 "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+#include "public/include/XMP_IO.hpp"
+
+#include "source/Host_IO.hpp"
+#include "source/XMP_ProgressTracker.hpp"
+#include "XMP_LibUtils.hpp"
+
+#include <string>
+
+// =================================================================================================
+
+class XMPFiles_IO : public XMP_IO {
+ // Implementation class for I/O inside XMPFiles, uses host O/S file services. All of the common
+ // functions behave as described for XMP_IO. Use openReadOnly and openReadWrite constants from
+ // Host_IO for the readOnly parameter to the constructors.
+public:
+ static XMPFiles_IO * New_XMPFiles_IO(
+ const char * filePath,
+ bool readOnly,
+ GenericErrorCallback * _errorCallback = 0,
+ XMP_ProgressTracker * _progressTracker = 0);
+
+ XMPFiles_IO(Host_IO::FileRef hostFile,
+ const char * filePath,
+ bool readOnly,
+ GenericErrorCallback* _errorCallback = 0,
+ XMP_ProgressTracker * _progressTracker = 0);
+
+ virtual ~XMPFiles_IO();
+
+ XMP_Uns32 Read(void * buffer, XMP_Uns32 count, bool readAll = false);
+
+ void Write(const void * buffer, XMP_Uns32 count);
+
+ XMP_Int64 Seek(XMP_Int64 offset, SeekMode mode);
+
+ XMP_Int64 Length();
+
+ void Truncate(XMP_Int64 length);
+
+ XMP_IO * DeriveTemp();
+ void AbsorbTemp();
+ void DeleteTemp();
+
+ void SetProgressTracker(XMP_ProgressTracker * _progressTracker) {
+ this->progressTracker = _progressTracker;
+ };
+
+ void SetErrorCallback(GenericErrorCallback & _errorCallback) {
+ this->errorCallback = &_errorCallback;
+ };
+
+ void Close(); // Not part of XMP_IO, added here to let errors propagate.
+
+private:
+ bool readOnly;
+ std::string filePath;
+ Host_IO::FileRef fileRef;
+ XMP_Int64 currOffset;
+ XMP_Int64 currLength;
+ bool isTemp;
+ XMPFiles_IO * derivedTemp;
+
+ XMP_ProgressTracker * progressTracker; // ! Owned by the XMPFiles object!
+ GenericErrorCallback * errorCallback; // ! Owned by the XMPFiles object!
+
+ // Hidden on purpose.
+ XMPFiles_IO()
+ : fileRef(Host_IO::noFileRef)
+ , isTemp(false)
+ , derivedTemp(0)
+ , progressTracker(0) {};
+
+ // The copy constructor and assignment operators are private to prevent client use. Allowing
+ // them would require shared I/O state between XMPFiles_IO objects.
+ XMPFiles_IO(const XMPFiles_IO & original);
+ void operator = (const XMP_IO & in);
+ void operator = (const XMPFiles_IO & in);
+};
+
+// =================================================================================================
+
+#endif // __XMPFiles_IO_hpp__
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/XMP_LibUtils.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_LibUtils.cpp
new file mode 100644
index 0000000000..e27ea304c8
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_LibUtils.cpp
@@ -0,0 +1,666 @@
+// =================================================================================================
+// 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 "source/XMP_LibUtils.hpp"
+
+#include "source/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.
+}
+
+// =================================================================================================
+// 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/core/libs/dngwriter/extra/xmp_sdk/source/XMP_LibUtils.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_LibUtils.hpp
new file mode 100644
index 0000000000..e4477fab5f
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_LibUtils.hpp
@@ -0,0 +1,642 @@
+#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
+
+#define XMP_Error_Throw(error) { AnnounceThrow (error.GetErrMsg()); throw error; }
+
+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
+ {
+
+ 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
+
+ // 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
+ {
+
+ 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 );
+
+ } // GenericErrorCallback::NotifyClient
+
+ virtual bool CanNotify ( ) const = 0;
+ virtual bool ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const = 0;
+
+};
+
+// -------------------------------------------------------------------------------------------------
+
+struct ErrorCallbackBox
+{
+ XMPFiles_ErrorCallbackWrapper wrapperProc;
+ XMPFiles_ErrorCallbackProc clientProc;
+ void * context;
+ XMP_Uns32 limit;
+
+ ErrorCallbackBox( XMPFiles_ErrorCallbackWrapper wrapperProcedure,
+ XMPFiles_ErrorCallbackProc clientProcedure,
+ void * contextPtr,
+ XMP_Uns32 limit32 ): wrapperProc(wrapperProcedure), clientProc(clientProcedure), context(contextPtr), limit(limit32) { }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+#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 UseHomeGrownLock 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) OSAtomicIncrement32Barrier ( &(x) )
+ #define XMP_AtomicDecrement(x) OSAtomicDecrement32Barrier ( &(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 ); }
+
+#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/core/libs/dngwriter/extra/xmp_sdk/source/XMP_ProgressTracker.cpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_ProgressTracker.cpp
new file mode 100644
index 0000000000..99824251b4
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_ProgressTracker.cpp
@@ -0,0 +1,163 @@
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// 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.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+
+#include "source/XMP_LibUtils.hpp"
+#include "source/XMP_ProgressTracker.hpp"
+
+// =================================================================================================
+// XMP_ProgressTracker::XMP_ProgressTracker
+// ========================================
+
+XMP_ProgressTracker::XMP_ProgressTracker ( const CallbackInfo & _cbInfo )
+{
+
+ this->Clear();
+ if ( _cbInfo.clientProc == 0 ) return;
+ XMP_Assert ( _cbInfo.wrapperProc != 0 );
+
+ this->cbInfo = _cbInfo;
+ if ( this->cbInfo.interval < 0.0 ) this->cbInfo.interval = 1.0;
+
+} // XMP_ProgressTracker::XMP_ProgressTracker
+
+// =================================================================================================
+// XMP_ProgressTracker::BeginWork
+// ==============================
+
+void XMP_ProgressTracker::BeginWork ( float _totalWork )
+{
+
+ if ( _totalWork < 0.0 ) _totalWork = 0.0;
+ this->totalWork = _totalWork;
+ this->workDone = 0.0;
+ this->workInProgress = true;
+
+ this->startTime = this->prevTime = PerfUtils::NoteThisMoment();
+ if ( this->cbInfo.sendStartStop ) this->NotifyClient ( true );
+
+} // XMP_ProgressTracker::BeginWork
+
+// =================================================================================================
+// XMP_ProgressTracker::AddTotalWork
+// =================================
+
+void XMP_ProgressTracker::AddTotalWork ( float workIncrement )
+{
+
+ if ( workIncrement < 0.0 ) workIncrement = 0.0;
+ this->totalWork += workIncrement;
+
+} // XMP_ProgressTracker::AddTotalWork
+
+// =================================================================================================
+// XMP_ProgressTracker::AddWorkDone
+// ================================
+
+void XMP_ProgressTracker::AddWorkDone ( float workIncrement )
+{
+
+ if ( workIncrement < 0.0 ) workIncrement = 0.0;
+ this->workDone += workIncrement;
+ this->NotifyClient();
+
+} // XMP_ProgressTracker::AddWorkDone
+
+// =================================================================================================
+// XMP_ProgressTracker::WorkComplete
+// =================================
+
+void XMP_ProgressTracker::WorkComplete ()
+{
+
+ if ( this->totalWork == 0.0 ) this->totalWork = 1.0; // Force non-zero fraction done.
+ this->workDone = this->totalWork;
+ XMP_Assert ( this->workDone > 0.0 ); // Needed in NotifyClient for start/stop case.
+
+ this->NotifyClient ( this->cbInfo.sendStartStop );
+ this->workInProgress = false;
+
+} // XMP_ProgressTracker::WorkComplete
+
+// =================================================================================================
+// XMP_ProgressTracker::Clear
+// ==========================
+
+void XMP_ProgressTracker::Clear ()
+{
+
+ this->cbInfo.Clear();
+ this->workInProgress = false;
+ this->totalWork = 0.0;
+ this->workDone = 0.0;
+ this->startTime = this->prevTime = PerfUtils::kZeroMoment;
+ // ! There is no standard zero value for PerfUtils::MomentValue.
+
+} // XMP_ProgressTracker::Clear
+
+// =================================================================================================
+// XMP_ProgressTracker::NotifyClient
+// =================================
+//
+// The math for the time remaining is easy but not immediately obvious. We know the elapsed time and
+// fraction of work done:
+//
+// elapsedTime = totalTime * fractionDone or totalTime = (elapsedTime / fractionDone)
+// remainingTime = totalTime * (1 - fractionDone)
+// so:
+// remainingTime = (elapsedTime / fractionDone) * (1 - fractionDone)
+
+void XMP_ProgressTracker::NotifyClient ( bool isStartStop )
+{
+ XMP_Bool ok = !kXMP_Bool_False;
+ float fractionDone = 0.0;
+
+ if ( this->cbInfo.clientProc == 0 ) return;
+ XMP_Assert ( this->cbInfo.wrapperProc != 0 );
+ XMP_Assert ( (this->totalWork >= 0.0) && (this->workDone >= 0.0) && (this->cbInfo.interval >= 0.0) );
+ // ! Note that totalWork might be unknown or understimated, and workDone greater than totalWork.
+
+ if ( isStartStop ) {
+
+ float totalTime = 0.0;
+ if ( this->workDone > 0.0 ) {
+ fractionDone = 1.0; // This is the stop call.
+ totalTime = PerfUtils::GetElapsedSeconds ( this->startTime, PerfUtils::NoteThisMoment() );
+ }
+ ok = (*this->cbInfo.wrapperProc ) ( this->cbInfo.clientProc, this->cbInfo.context,
+ totalTime, fractionDone, 0.0 );
+
+ } else {
+
+ PerfUtils::MomentValue currentTime = PerfUtils::NoteThisMoment();
+ float elapsedTime = PerfUtils::GetElapsedSeconds ( this->prevTime, currentTime );
+ if ( elapsedTime < this->cbInfo.interval ) return;
+
+ float remainingTime = 0.0;
+ if ( (this->totalWork > 0.0) && (this->workDone > 0.0) ) {
+ fractionDone = this->workDone / this->totalWork;
+ if ( fractionDone > 1.0 ) fractionDone = 1.0;
+ elapsedTime = PerfUtils::GetElapsedSeconds ( this->startTime, currentTime );
+ remainingTime = (elapsedTime / fractionDone) * (1.0 - fractionDone);
+ }
+
+ this->prevTime = currentTime;
+ ok = (*this->cbInfo.wrapperProc ) ( this->cbInfo.clientProc, this->cbInfo.context,
+ elapsedTime, fractionDone, remainingTime );
+
+ }
+
+ if ( ok == kXMP_Bool_False ) XMP_Throw ( "Abort signaled by progress reporting callback", kXMPErr_ProgressAbort );
+
+} // XMP_ProgressTracker::NotifyClient
+
+// =================================================================================================
diff --git a/core/libs/dngwriter/extra/xmp_sdk/source/XMP_ProgressTracker.hpp b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_ProgressTracker.hpp
new file mode 100644
index 0000000000..14b5d5445c
--- /dev/null
+++ b/core/libs/dngwriter/extra/xmp_sdk/source/XMP_ProgressTracker.hpp
@@ -0,0 +1,72 @@
+#ifndef __XMP_ProgressTracker_hpp__
+#define __XMP_ProgressTracker_hpp__ 1
+
+// =================================================================================================
+// ADOBE SYSTEMS INCORPORATED
+// 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.
+// =================================================================================================
+
+#include "public/include/XMP_Environment.h" // ! XMP_Environment.h must be the first included header.
+
+#include "public/include/XMP_Const.h"
+
+#include "source/PerfUtils.hpp"
+
+// =================================================================================================
+
+class XMP_ProgressTracker {
+public:
+
+ struct CallbackInfo {
+
+ XMP_ProgressReportWrapper wrapperProc;
+ XMP_ProgressReportProc clientProc;
+ void * context;
+ float interval;
+ bool sendStartStop;
+
+ void Clear() { this->wrapperProc = 0; this->clientProc = 0;
+ this->context = 0; this->interval = 1.0; this->sendStartStop = false; };
+ CallbackInfo() { this->Clear(); };
+ CallbackInfo ( XMP_ProgressReportWrapper _wrapperProc, XMP_ProgressReportProc _clientProc,
+ void * _context, float _interval, bool _sendStartStop )
+ : wrapperProc(_wrapperProc), clientProc(_clientProc),
+ context(_context), interval(_interval), sendStartStop(_sendStartStop) {};
+
+ };
+
+ XMP_ProgressTracker ( const CallbackInfo & _cbInfo );
+
+ void BeginWork ( float _totalWork = 0.0 );
+ void AddTotalWork ( float workIncrement );
+ void AddWorkDone ( float workIncrement );
+ void WorkComplete();
+ CallbackInfo * GetCallbackInfo() {
+ return ( (&cbInfo) ? (&cbInfo) : NULL);
+ }
+
+ bool WorkInProgress() { return this->workInProgress; };
+
+ ~XMP_ProgressTracker() {};
+
+private:
+
+ XMP_ProgressTracker() { this->Clear(); }; // Hidden on purpose.
+
+ void Clear();
+ void NotifyClient ( bool isStartStop = false );
+
+ CallbackInfo cbInfo;
+ bool workInProgress;
+ float totalWork, workDone;
+ PerfUtils::MomentValue startTime, prevTime;
+
+}; // XMP_ProgressTracker
+
+// =================================================================================================
+
+#endif // __XMP_ProgressTracker_hpp__