aboutsummaryrefslogtreecommitdiffstats
path: root/testing/opencolorio
diff options
context:
space:
mode:
authorMark Riedesel <mark@klowner.com>2016-08-15 08:43:10 -0500
committerJakub Jirutka <jakub@jirutka.cz>2016-08-15 18:26:26 +0200
commita696503b386fcb8b9f521af3693f85752f0e9b4a (patch)
tree2a05b91330dd555470a45da4465d072eb7a70cc0 /testing/opencolorio
parent53539e117ead530fd909bff21b1d985335a3ac4e (diff)
downloadaports-a696503b386fcb8b9f521af3693f85752f0e9b4a.tar.bz2
aports-a696503b386fcb8b9f521af3693f85752f0e9b4a.tar.xz
testing/opencolorio: new aport
http://opencolorio.org A color management framework for visual effects and animation
Diffstat (limited to 'testing/opencolorio')
-rw-r--r--testing/opencolorio/APKBUILD83
-rw-r--r--testing/opencolorio/temp-deref-with-yaml-0.5.0.patch112
-rw-r--r--testing/opencolorio/yaml-cpp-0.5-support.patch3815
3 files changed, 4010 insertions, 0 deletions
diff --git a/testing/opencolorio/APKBUILD b/testing/opencolorio/APKBUILD
new file mode 100644
index 0000000000..fa2187a59f
--- /dev/null
+++ b/testing/opencolorio/APKBUILD
@@ -0,0 +1,83 @@
+# Contributor: Mark Riedesel <mark@klowner.com>
+# Maintainer: Mark Riedesel <mark@klowner.com>
+pkgname=opencolorio
+pkgver=1.0.9
+pkgrel=0
+pkgdesc="A color management framework for visual effects and animation"
+url="http://opencolorio.org"
+arch="all"
+license="BSD"
+depends=""
+makedepends="boost-dev cmake freeglut-dev glew-dev lcms2-dev python2-dev
+ python3-dev tinyxml-dev yaml-cpp-dev"
+subpackages="py2-$pkgname:py2 py3-$pkgname:py3 $pkgname-dev $pkgname-tools"
+source="$pkgname-$pkgver.tar.gz::http://github.com/imageworks/OpenColorIO/archive/v$pkgver.tar.gz
+ yaml-cpp-0.5-support.patch
+ temp-deref-with-yaml-0.5.0.patch"
+builddir="$srcdir/OpenColorIO-$pkgver"
+
+build() {
+ cd "$builddir"
+
+ # Just to be sure we're using alpine dev packages
+ rm -f ext/lcms* ext/tinyxml* ext/yaml*
+
+ local pyver
+ for pyver in python3 python2; do
+ mkdir build-$pyver && cd build-$pyver
+
+ cmake .. \
+ -DCMAKE_INSTALL_PREFIX=/usr \
+ -DOCIO_BUILD_TRUELIGHT=OFF \
+ -DOCIO_BUILD_NUKE=OFF \
+ -DOCIO_BUILD_SHARED=ON \
+ -DOCIO_BUILD_STATIC=OFF \
+ -DPYTHON=/usr/bin/$pyver \
+ -DUSE_EXTERNAL_YAML=TRUE \
+ -DUSE_EXTERNAL_TINYXML=TRUE \
+ -DUSE_EXTERNAL_LCMS=TRUE \
+ || return 1
+ make || return 1
+ cd ..
+ done
+}
+
+package() {
+ local pyver
+ for pyver in python3 python2; do
+ cd "$builddir"/build-$pyver
+ make DESTDIR="$pkgdir" install || return 1
+ done
+}
+
+tools() {
+ pkgdesc="OpenColorIO color management framework tools"
+
+ mkdir -p "$subpkgdir"/usr/
+ mv "$pkgdir"/usr/bin "$subpkgdir"/usr
+}
+
+_python() {
+ pkgdesc="Python $1 bindings for OpenColorIO color management framework"
+ depends="python$1"
+
+ mv "$pkgdir"$2 "$subpkgdir"
+}
+
+py2() {
+ _python 2 "$(python2 -c 'import site; print(site.getsitepackages()[0])')"
+}
+
+py3() {
+ _python 3 "$(python3 -c 'import site; print(site.getsitepackages()[0])')"
+}
+
+md5sums="06d0efe9cc1b32d7b14134779c9d1251 opencolorio-1.0.9.tar.gz
+11bb6b587b2e5242f75aca281bab158c yaml-cpp-0.5-support.patch
+5f13bef26e14b2dd908e69a2bc8fb7a4 temp-deref-with-yaml-0.5.0.patch"
+sha256sums="27c81e691c15753cd2b560c2ca4bd5679a60c2350eedd43c99d44ca25d65ea7f opencolorio-1.0.9.tar.gz
+b381912a81342e242d1a6ef39cf1556f7b383407af9c1aefbde06e38186777ad yaml-cpp-0.5-support.patch
+6df29f0d3de06ab0fbc2fa06f6fc7537d0628c4185d7a9f6228b2d0be07917d7 temp-deref-with-yaml-0.5.0.patch"
+sha512sums="ac953ba9904aff44de37cc2ee60dbf524bd86d25f699c1eacaa61ca30fed8f077194d47d34a72c05b706da7e1a3974a988d67d60031d424d91b9240f8ab86ed3 opencolorio-1.0.9.tar.gz
+8b909e1aa688ca38ce7938a4855611cf19781a3c2dc9cc9bca3df3b8d21a2a7772e35917ba9f636c89ea2da8eec2aa7b7118bfa77e0787614110e7441b038de5 yaml-cpp-0.5-support.patch
+3793e39d74f3c585d7fc2fbcc7f131fba9f0fea130de80c31461101355954c3d3fa158028652f074fb129e7c0a7ee1e506dbfc187ca5fbfdce09303b371bf266 temp-deref-with-yaml-0.5.0.patch"
diff --git a/testing/opencolorio/temp-deref-with-yaml-0.5.0.patch b/testing/opencolorio/temp-deref-with-yaml-0.5.0.patch
new file mode 100644
index 0000000000..23d971d5d6
--- /dev/null
+++ b/testing/opencolorio/temp-deref-with-yaml-0.5.0.patch
@@ -0,0 +1,112 @@
+commit 1384029df00525c479e2c7e52fdfa294413fceb6
+Author: Mark Boorer <mkj@dneg.com>
+Date: Wed Sep 3 22:41:28 2014 +0100
+
+ OCIOYaml: Fixed dereference of temporary when yaml-cpp 0.5.x was used.
+ CMakeLists.txt: Improved System yaml-cpp detection.
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 69eca4e..b539ea1 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -202,15 +202,44 @@ if(USE_EXTERNAL_YAML)
+ # Set minimum yaml version for non-patched sources.
+ set(YAML_VERSION_MIN "0.3.0")
+ include(FindPkgConfig)
+- pkg_check_modules(YAML_CPP yaml-cpp)
++ pkg_check_modules(PC_YAML_CPP REQUIRED QUIET yaml-cpp)
++ find_path(YAML_CPP_INCLUDE_DIR yaml-cpp/yaml.h
++ HINTS ${PC_YAML_CPP_INCLUDEDIR} ${PC_YAML_CPP_INCLUDE_DIRS} )
++ find_library(YAML_CPP_LIBRARY LIBRARY_NAMES yaml-cpp libyaml-cpp
++ HINTS ${PC_YAML_CPP_LIBRARY_DIRS} )
++ set(YAML_CPP_LIBRARIES ${YAML_CPP_LIBRARY})
++ set(YAML_CPP_INCLUDE_DIRS ${YAML_CPP_INCLUDE_DIR})
++ set(YAML_CPP_VERSION ${PC_YAML_CPP_VERSION})
++
++ if(YAML_CPP_VERSION VERSION_LESS ${YAML_VERSION_MIN})
++ message(FATAL_ERROR "ERROR: yaml-cpp ${YAML_VERSION_MIN} or greater is required.")
++ endif()
++
++ find_package_handle_standard_args(yaml-cpp
++ REQUIRED_VARS YAML_CPP_LIBRARIES YAML_CPP_INCLUDE_DIRS )
++ set(YAML_CPP_FOUND ${YAML-CPP_FOUND})
++ mark_as_advanced(YAML_CPP_INCLUDE_DIR YAML_CPP_LIBRARY YAML-CPP_FOUND)
++
+ if(YAML_CPP_FOUND)
+- if(YAML_CPP_VERSION VERSION_EQUAL ${YAML_VERSION_MIN} OR
+- YAML_CPP_VERSION VERSION_GREATER ${YAML_VERSION_MIN})
+- message(STATUS "System yaml-cpp library will be used.")
+- include_directories(BEFORE ${YAML_CPP_INCLUDE_DIRS})
+- else()
+- message(FATAL_ERROR "ERROR: yaml-cpp ${YAML_VERSION_MIN} or greater is required.")
++ if(YAML_CPP_VERSION VERSION_GREATER "0.5.0")
++ # Need to also get the boost headers here, as yaml-cpp 0.5.0+ requires them.
++ # Don't bother doing this step if we are already including the boost headers for shared_ptr
++ if(NOT OCIO_USE_BOOST_PTR)
++ set(Boost_ADDITIONAL_VERSIONS "1.49" "1.45" "1.44" "1.43" "1.43.0" "1.42"
++ "1.42.0" "1.41" "1.41.0" "1.40"
++ "1.40.0" "1.39" "1.39.0" "1.38"
++ "1.38.0" "1.37" "1.37.0" "1.34.1"
++ "1_34_1")
++ set(Boost_USE_MULTITHREADED ON)
++ find_package(Boost 1.34)
++ if(NOT Boost_FOUND)
++ message(FATAL_ERROR "Error: Detected system yaml-cpp version ${YAML_CPP_VERSION} is greater than 0.5.0, and therefore requires boost, but a boost installation could not be found.")
++ endif()
++
++ set(EXTERNAL_INCLUDE_DIRS ${EXTERNAL_INCLUDE_DIRS} ${Boost_INCLUDE_DIR})
++ endif()
+ endif()
++ set(EXTERNAL_INCLUDE_DIRS ${EXTERNAL_INCLUDE_DIRS} ${YAML_CPP_INCLUDE_DIRS})
+ else(YAML_CPP_FOUND)
+ message(FATAL_ERROR "ERROR: System yaml-cpp library was not found. Make sure the library is installed and the pkg-config file exists.")
+ endif(YAML_CPP_FOUND)
+diff --git a/src/core/OCIOYaml.cpp b/src/core/OCIOYaml.cpp
+index 5a95353..d9f1345 100644
+--- a/src/core/OCIOYaml.cpp
++++ b/src/core/OCIOYaml.cpp
+@@ -88,26 +88,36 @@ OCIO_NAMESPACE_ENTER
+ #else
+ typedef YAML::const_iterator Iterator;
+ #endif
+-
++
+ // Iterator access
+-
+- inline const YAML::Node& get_first(const Iterator it)
+- {
++ // Note: The ownership semantics have changed between yaml-cpp 0.3.x and 0.5.x .
++ // Returning a const reference to a yaml node screws with the internal yaml-cpp smart ptr
++ // implementation in the newer version. Luckily, the compiler does not care if we maintain
++ // const YAML::Node & = get_first(iter) syntax at the call site even when returning an actual object
++ // (instead of the reference as expected).
+ #ifdef OLDYAML
++ inline const YAML::Node& get_first(const Iterator &it)
++ {
+ return it.first();
++ }
+ #else
++ inline YAML::Node get_first(const Iterator &it)
++ {
+ return it->first;
+-#endif
+ }
++#endif
+
+- inline const YAML::Node& get_second(const Iterator it)
+- {
+ #ifdef OLDYAML
++ inline const YAML::Node& get_second(const Iterator &it)
++ {
+ return it.second();
++ }
+ #else
++ inline YAML::Node get_second(const Iterator &it)
++ {
+ return it->second;
+-#endif
+ }
++#endif
+
+ // Basic types
+
diff --git a/testing/opencolorio/yaml-cpp-0.5-support.patch b/testing/opencolorio/yaml-cpp-0.5-support.patch
new file mode 100644
index 0000000000..e3b51c9362
--- /dev/null
+++ b/testing/opencolorio/yaml-cpp-0.5-support.patch
@@ -0,0 +1,3815 @@
+commit 63c6bde2acac363c8c5e7fd3d744e17ea99e20ab
+Author: Malcolm Humphreys <malcolmhumphreys@gmail.com>
+Date: Thu Jan 30 12:42:21 2014 +0000
+
+ * added support form yaml-cpp > 5.0.1
+ * when yaml-cpp < 5.0.0 define OLDYAML
+ * added yaml-cpp 5.0.1 tarball in preparation for moving to the new api
+ * added OCIOYaml class and moved all yaml-cpp code into OCIOYaml.cpp
+ * moved Config serialize code into OCIOYaml.cpp
+ * added Config::setEnvironmentMode(), Config::getEnvironmentMode(), Config::loadEnvironment()
+ * moved Display code from Config.cpp into it's own files
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 13e2d64..ea3fb8b 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -225,13 +225,15 @@ else(USE_EXTERNAL_YAML)
+ endif()
+ endif(USE_EXTERNAL_YAML)
+
+-
++if(YAML_CPP_VERSION VERSION_LESS "0.5.0")
++ set(YAML_CPP_COMPILE_FLAGS "-DOLDYAML")
++endif()
+
+ ###############################################################################
+ ### Externals ###
+
+ set(EXTERNAL_INCLUDE_DIRS ${EXTERNAL_INCLUDE_DIRS} ${PROJECT_BINARY_DIR}/ext/dist/include)
+-set(EXTERNAL_COMPILE_FLAGS "-DTIXML_USE_STL")
++set(EXTERNAL_COMPILE_FLAGS "-DTIXML_USE_STL ${YAML_CPP_COMPILE_FLAGS}")
+
+ if(CMAKE_COMPILER_IS_GNUCXX)
+
+diff --git a/export/OpenColorIO/OpenColorIO.h b/export/OpenColorIO/OpenColorIO.h
+index 561ce50..00716fa 100644
+--- a/export/OpenColorIO/OpenColorIO.h
++++ b/export/OpenColorIO/OpenColorIO.h
+@@ -279,6 +279,12 @@ OCIO_NAMESPACE_ENTER
+ const char * getEnvironmentVarDefault(const char * name) const;
+ //!cpp:function::
+ void clearEnvironmentVars();
++ //!cpp:function::
++ void setEnvironmentMode(EnvironmentMode mode);
++ //!cpp:function::
++ EnvironmentMode getEnvironmentMode() const;
++ //!cpp:function::
++ void loadEnvironment();
+
+ //!cpp:function::
+ const char * getSearchPath() const;
+diff --git a/ext/yaml-cpp-0.5.1.patch b/ext/yaml-cpp-0.5.1.patch
+new file mode 100644
+index 0000000..23433cb
+--- /dev/null
++++ b/ext/yaml-cpp-0.5.1.patch
+@@ -0,0 +1,12 @@
++diff -Naur yaml-cpp-0.5.1.orig/CMakeLists.txt yaml-cpp-0.5.1/CMakeLists.txt
++--- yaml-cpp-0.5.1.orig/CMakeLists.txt 2014-01-30 09:45:54.000000000 +0000
+++++ yaml-cpp-0.5.1/CMakeLists.txt 2014-01-30 09:51:04.000000000 +0000
++@@ -140,7 +140,7 @@
++ set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}")
++ endif()
++ #
++- set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
+++ set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long -fPIC -fvisibility-inlines-hidden -fvisibility=hidden ${CMAKE_CXX_FLAGS}")
++ #
++ add_custom_target(debuggable $(MAKE) clean
++ COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR}
+diff --git a/ext/yaml-cpp-0.5.1.tar.gz b/ext/yaml-cpp-0.5.1.tar.gz
+new file mode 100644
+index 0000000..f087742
+Binary files /dev/null and b/ext/yaml-cpp-0.5.1.tar.gz differ
+diff --git a/src/core/Config.cpp b/src/core/Config.cpp
+index 00e1e70..82b5073 100644
+--- a/src/core/Config.cpp
++++ b/src/core/Config.cpp
+@@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ #include "HashUtils.h"
+ #include "Logging.h"
+ #include "LookParse.h"
++#include "Display.h"
+ #include "MathUtils.h"
+ #include "Mutex.h"
+ #include "OpBuilders.h"
+@@ -208,7 +209,6 @@ OCIO_NAMESPACE_ENTER
+ if(csname.empty()) return false;
+
+ std::string csnamelower = pystring::lower(csname);
+-
+ for(unsigned int i = 0; i < colorspaces.size(); ++i)
+ {
+ if(csnamelower == pystring::lower(colorspaces[i]->getName()))
+@@ -220,184 +220,7 @@ OCIO_NAMESPACE_ENTER
+
+ return false;
+ }
+-
+-
+- // Displays
+- struct View
+- {
+- std::string name;
+- std::string colorspace;
+- std::string looks;
+-
+- View() { }
+-
+- View(const std::string & name_,
+- const std::string & colorspace_,
+- const std::string & looksList_) :
+- name(name_),
+- colorspace(colorspace_),
+- looks(looksList_)
+- { }
+- };
+-
+- typedef std::vector<View> ViewVec;
+- typedef std::map<std::string, ViewVec> DisplayMap; // (display name : ViewVec)
+-
+- void operator >> (const YAML::Node& node, View& v)
+- {
+- if(node.Tag() != "View")
+- return;
+-
+- std::string key, stringval;
+-
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
+- {
+- iter.first() >> key;
+-
+- if(key == "name")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- v.name = stringval;
+- }
+- else if(key == "colorspace")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- v.colorspace = stringval;
+- }
+- else if(key == "looks" || key == "look")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- v.looks = stringval;
+- }
+- else
+- {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
+- }
+- }
+-
+- if(v.name.empty())
+- {
+- throw Exception("View does not specify 'name'.");
+- }
+- if(v.colorspace.empty())
+- {
+- std::ostringstream os;
+- os << "View '" << v.name << "' ";
+- os << "does not specify colorspace.";
+- throw Exception(os.str().c_str());
+- }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, View view)
+- {
+- out << YAML::VerbatimTag("View");
+- out << YAML::Flow;
+- out << YAML::BeginMap;
+- out << YAML::Key << "name" << YAML::Value << view.name;
+- out << YAML::Key << "colorspace" << YAML::Value << view.colorspace;
+- if(!view.looks.empty()) out << YAML::Key << "looks" << YAML::Value << view.looks;
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- DisplayMap::iterator find_display(DisplayMap & displays, const std::string & display)
+- {
+- for(DisplayMap::iterator iter = displays.begin();
+- iter != displays.end();
+- ++iter)
+- {
+- if(StrEqualsCaseIgnore(display, iter->first)) return iter;
+- }
+- return displays.end();
+- }
+-
+- DisplayMap::const_iterator find_display_const(const DisplayMap & displays, const std::string & display)
+- {
+- for(DisplayMap::const_iterator iter = displays.begin();
+- iter != displays.end();
+- ++iter)
+- {
+- if(StrEqualsCaseIgnore(display, iter->first)) return iter;
+- }
+- return displays.end();
+- }
+-
+- int find_view(const ViewVec & vec, const std::string & name)
+- {
+- for(unsigned int i=0; i<vec.size(); ++i)
+- {
+- if(StrEqualsCaseIgnore(name, vec[i].name)) return i;
+- }
+- return -1;
+- }
+-
+- void AddDisplay(DisplayMap & displays,
+- const std::string & display,
+- const std::string & view,
+- const std::string & colorspace,
+- const std::string & looks)
+- {
+- DisplayMap::iterator iter = find_display(displays, display);
+- if(iter == displays.end())
+- {
+- ViewVec views;
+- views.push_back( View(view, colorspace, looks) );
+- displays[display] = views;
+- }
+- else
+- {
+- ViewVec & views = iter->second;
+- int index = find_view(views, view);
+- if(index<0)
+- {
+- views.push_back( View(view, colorspace, looks) );
+- }
+- else
+- {
+- views[index].colorspace = colorspace;
+- views[index].looks = looks;
+- }
+- }
+- }
+-
+- void ComputeDisplays(StringVec & displayCache,
+- const DisplayMap & displays,
+- const StringVec & activeDisplays,
+- const StringVec & activeDisplaysEnvOverride)
+- {
+- displayCache.clear();
+
+- StringVec displayMasterList;
+- for(DisplayMap::const_iterator iter = displays.begin();
+- iter != displays.end();
+- ++iter)
+- {
+- displayMasterList.push_back(iter->first);
+- }
+-
+- // Apply the env override if it's not empty.
+- if(!activeDisplaysEnvOverride.empty())
+- {
+- displayCache = IntersectStringVecsCaseIgnore(displayMasterList, activeDisplaysEnvOverride);
+- if(!displayCache.empty()) return;
+- }
+- // Otherwise, aApply the active displays if it's not empty.
+- else if(!activeDisplays.empty())
+- {
+- displayCache = IntersectStringVecsCaseIgnore(displayMasterList, activeDisplays);
+- if(!displayCache.empty()) return;
+- }
+-
+- displayCache = displayMasterList;
+- }
+-
+-
+-
+ } // namespace
+
+ class Config::Impl
+@@ -431,6 +254,8 @@ OCIO_NAMESPACE_ENTER
+ mutable StringMap cacheids_;
+ mutable std::string cacheidnocontext_;
+
++ OCIOYaml io_;
++
+ Impl() :
+ context_(Context::Create()),
+ strictParsing_(true),
+@@ -497,8 +322,6 @@ OCIO_NAMESPACE_ENTER
+ return *this;
+ }
+
+- void load(std::istream & istream, const char * name);
+-
+ // Any time you modify the state of the config, you must call this
+ // to reset internal cache states. You also should do this in a
+ // thread safe manner by acquiring the cacheidMutex_;
+@@ -536,7 +359,7 @@ OCIO_NAMESPACE_ENTER
+ istream.str(INTERNAL_RAW_PROFILE);
+
+ ConfigRcPtr config = Config::Create();
+- config->getImpl()->load(istream, "");
++ config->getImpl()->io_.open(istream, config);
+ return config;
+ }
+
+@@ -551,14 +374,14 @@ OCIO_NAMESPACE_ENTER
+ }
+
+ ConfigRcPtr config = Config::Create();
+- config->getImpl()->load(istream, filename);
++ config->getImpl()->io_.open(istream, config, filename);
+ return config;
+ }
+
+ ConstConfigRcPtr Config::CreateFromStream(std::istream & istream)
+ {
+ ConfigRcPtr config = Config::Create();
+- config->getImpl()->load(istream, "");
++ config->getImpl()->io_.open(istream, config);
+ return config;
+ }
+
+@@ -893,6 +716,27 @@ OCIO_NAMESPACE_ENTER
+ getImpl()->resetCacheIDs();
+ }
+
++ void Config::setEnvironmentMode(EnvironmentMode mode)
++ {
++ getImpl()->context_->setEnvironmentMode(mode);
++
++ AutoMutex lock(getImpl()->cacheidMutex_);
++ getImpl()->resetCacheIDs();
++ }
++
++ EnvironmentMode Config::getEnvironmentMode() const
++ {
++ return getImpl()->context_->getEnvironmentMode();
++ }
++
++ void Config::loadEnvironment()
++ {
++ getImpl()->context_->loadEnvironment();
++
++ AutoMutex lock(getImpl()->cacheidMutex_);
++ getImpl()->resetCacheIDs();
++ }
++
+ const char * Config::getSearchPath() const
+ {
+ return getImpl()->context_->getSearchPath();
+@@ -1647,60 +1491,7 @@ OCIO_NAMESPACE_ENTER
+ {
+ try
+ {
+- YAML::Emitter out;
+- out << YAML::Block;
+- out << YAML::BeginMap;
+- out << YAML::Key << "ocio_profile_version" << YAML::Value << 1;
+- out << YAML::Newline;
+- if(getImpl()->env_.size() > 0) {
+- out << YAML::Key << "environment";
+- out << YAML::Value << getImpl()->env_;
+- out << YAML::Newline;
+- }
+- out << YAML::Key << "search_path" << YAML::Value << getImpl()->context_->getSearchPath();
+- out << YAML::Key << "strictparsing" << YAML::Value << getImpl()->strictParsing_;
+- out << YAML::Key << "luma" << YAML::Value << YAML::Flow << getImpl()->defaultLumaCoefs_;
+-
+- if(getImpl()->description_ != "")
+- {
+- out << YAML::Newline;
+- out << YAML::Key << "description";
+- out << YAML::Value << getImpl()->description_;
+- }
+-
+- // Roles
+- out << YAML::Newline;
+- out << YAML::Key << "roles";
+- out << YAML::Value << getImpl()->roles_;
+-
+- // Displays
+- out << YAML::Newline;
+- out << YAML::Key << "displays";
+- out << YAML::Value << getImpl()->displays_;
+- out << YAML::Newline;
+- out << YAML::Key << "active_displays";
+- out << YAML::Value << YAML::Flow << getImpl()->activeDisplays_;
+- out << YAML::Key << "active_views";
+- out << YAML::Value << YAML::Flow << getImpl()->activeViews_;
+-
+- // Looks
+- if(!getImpl()->looksList_.empty())
+- {
+- out << YAML::Newline;
+- out << YAML::Key << "looks";
+- out << YAML::Value << getImpl()->looksList_;
+- }
+-
+- // ColorSpaces
+- {
+- out << YAML::Newline;
+- out << YAML::Key << "colorspaces";
+- out << YAML::Value << getImpl()->colorspaces_;
+- }
+-
+- out << YAML::EndMap;
+-
+- os << out.c_str();
++ getImpl()->io_.write(os, this);
+ }
+ catch( const std::exception & e)
+ {
+@@ -1710,246 +1501,6 @@ OCIO_NAMESPACE_ENTER
+ }
+ }
+
+- void Config::Impl::load(std::istream & istream, const char * filename)
+- {
+- try
+- {
+- YAML::Parser parser(istream);
+- YAML::Node node;
+- parser.GetNextDocument(node);
+-
+- // check profile version
+- int profile_version = 0;
+- if(node.FindValue("ocio_profile_version") == NULL)
+- {
+- std::ostringstream os;
+- os << "The specified file ";
+- os << "does not appear to be an OCIO configuration.";
+- throw Exception (os.str().c_str());
+- }
+-
+- node["ocio_profile_version"] >> profile_version;
+- if(profile_version > 1)
+- {
+- std::ostringstream os;
+- os << "This .ocio config ";
+- if(filename && *filename)
+- {
+- os << " '" << filename << "' ";
+- }
+- os << "is version " << profile_version << ". ";
+- os << "This version of the OpenColorIO library (" << OCIO_VERSION ") ";
+- os << "is not known to be able to load this profile. ";
+- os << "An attempt will be made, but there are no guarantees that the ";
+- os << "results will be accurate. Continue at your own risk.";
+- LogWarning(os.str());
+- }
+-
+-
+- std::string key, stringval;
+- bool boolval = false;
+- EnvironmentMode mode = ENV_ENVIRONMENT_LOAD_ALL;
+-
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
+- {
+- iter.first() >> key;
+-
+- if(key == "ocio_profile_version") { } // Already handled above.
+- else if(key == "environment")
+- {
+- mode = ENV_ENVIRONMENT_LOAD_PREDEFINED;
+- const YAML::Node& environment = iter.second();
+- if(environment.Type() != YAML::NodeType::Map)
+- {
+- std::ostringstream os;
+- os << "'environment' field needs to be a (name: key) map.";
+- throw Exception(os.str().c_str());
+- }
+- for (YAML::Iterator it = environment.begin();
+- it != environment.end(); ++it)
+- {
+- std::string k, v;
+- it.first() >> k;
+- it.second() >> v;
+- env_[k] = v;
+- context_->setStringVar(k.c_str(), v.c_str());
+- }
+- }
+- else if(key == "search_path" || key == "resource_path")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- context_->setSearchPath(stringval.c_str());
+- }
+- else if(key == "strictparsing")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<bool>(boolval))
+- strictParsing_ = boolval;
+- }
+- else if(key == "description")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- description_ = stringval;
+- }
+- else if(key == "luma")
+- {
+- std::vector<float> val;
+- if (iter.second().Type() != YAML::NodeType::Null)
+- {
+- iter.second() >> val;
+- if(val.size() != 3)
+- {
+- std::ostringstream os;
+- os << "'luma' field must be 3 ";
+- os << "floats. Found '" << val.size() << "'.";
+- throw Exception(os.str().c_str());
+- }
+- defaultLumaCoefs_ = val;
+- }
+- }
+- else if(key == "roles")
+- {
+- const YAML::Node& roles = iter.second();
+- if(roles.Type() != YAML::NodeType::Map)
+- {
+- std::ostringstream os;
+- os << "'roles' field needs to be a (name: key) map.";
+- throw Exception(os.str().c_str());
+- }
+- for (YAML::Iterator it = roles.begin();
+- it != roles.end(); ++it)
+- {
+- std::string k, v;
+- it.first() >> k;
+- it.second() >> v;
+- roles_[pystring::lower(k)] = v;
+- }
+- }
+- else if(key == "displays")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null)
+- {
+- iter.second() >> displays_;
+- }
+- }
+- else if(key == "active_displays")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null)
+- {
+- iter.second() >> activeDisplays_;
+- }
+- }
+- else if(key == "active_views")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null)
+- {
+- iter.second() >> activeViews_;
+- }
+- }
+- else if(key == "colorspaces")
+- {
+- const YAML::Node& colorspaces = iter.second();
+-
+- if(colorspaces.Type() != YAML::NodeType::Sequence)
+- {
+- std::ostringstream os;
+- os << "'colorspaces' field needs to be a (- !<ColorSpace>) list.";
+- throw Exception(os.str().c_str());
+- }
+-
+- for(unsigned i = 0; i < colorspaces.size(); ++i)
+- {
+- if(colorspaces[i].Tag() == "ColorSpace")
+- {
+- ColorSpaceRcPtr cs = ColorSpace::Create();
+- colorspaces[i] >> cs;
+- colorspaces_.push_back( cs );
+- }
+- else
+- {
+- std::ostringstream os;
+- os << "Unknown element found in colorspaces:";
+- os << colorspaces[i].Tag() << ". Only ColorSpace(s)";
+- os << " currently handled.";
+- LogWarning(os.str());
+- }
+- }
+- }
+- else if(key == "looks")
+- {
+- const YAML::Node& looks = iter.second();
+-
+- if(looks.Type() != YAML::NodeType::Sequence)
+- {
+- std::ostringstream os;
+- os << "'looks' field needs to be a (- !<Look>) list.";
+- throw Exception(os.str().c_str());
+- }
+-
+- for(unsigned i = 0; i < looks.size(); ++i)
+- {
+- if(looks[i].Tag() == "Look")
+- {
+- LookRcPtr look = Look::Create();
+- looks[i] >> look;
+- looksList_.push_back( look );
+- }
+- else
+- {
+- std::ostringstream os;
+- os << "Unknown element found in looks:";
+- os << looks[i].Tag() << ". Only Look(s)";
+- os << " currently handled.";
+- LogWarning(os.str());
+- }
+- }
+- }
+- else
+- {
+- LogUnknownKeyWarning("profile", iter.first());
+- }
+- }
+-
+- if(filename)
+- {
+- std::string realfilename = pystring::os::path::abspath(filename);
+- std::string configrootdir = pystring::os::path::dirname(realfilename);
+- context_->setWorkingDir(configrootdir.c_str());
+- }
+-
+- context_->setEnvironmentMode(mode);
+- context_->loadEnvironment();
+-
+- if(mode == ENV_ENVIRONMENT_LOAD_ALL)
+- {
+- std::ostringstream os;
+- os << "This .ocio config ";
+- if(filename && *filename)
+- {
+- os << " '" << filename << "' ";
+- }
+- os << "has no environment section defined. The default behaviour is to ";
+- os << "load all environment variables (" << context_->getNumStringVars() << ")";
+- os << ", which reduces the efficiency of OCIO's caching. Considering ";
+- os << "predefining the environment variables used.";
+- LogDebug(os.str());
+- }
+-
+- }
+- catch( const std::exception & e)
+- {
+- std::ostringstream os;
+- os << "Error: Loading the OCIO profile ";
+- if(filename) os << "'" << filename << "' ";
+- os << "failed. " << e.what();
+- throw Exception(os.str().c_str());
+- }
+- }
+-
+ void Config::Impl::resetCacheIDs()
+ {
+ cacheids_.clear();
+@@ -2287,9 +1838,7 @@ OIIO_ADD_TEST(Config, SanityCheck)
+ std::istringstream is;
+ is.str(SIMPLE_PROFILE);
+ OCIO::ConstConfigRcPtr config;
+- OIIO_CHECK_NO_THOW(config = OCIO::Config::CreateFromStream(is));
+-
+- OIIO_CHECK_THOW(config->sanityCheck(), OCIO::Exception);
++ OIIO_CHECK_THOW(config = OCIO::Config::CreateFromStream(is), OCIO::Exception);
+ }
+
+ {
+@@ -2330,8 +1879,6 @@ OIIO_ADD_TEST(Config, EnvCheck)
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+- " - !<ColorSpace>\n"
+- " name: raw\n"
+ "strictparsing: false\n"
+ "roles:\n"
+ " default: raw\n"
+@@ -2345,8 +1892,6 @@ OIIO_ADD_TEST(Config, EnvCheck)
+ "colorspaces:\n"
+ " - !<ColorSpace>\n"
+ " name: raw\n"
+- " - !<ColorSpace>\n"
+- " name: raw\n"
+ "strictparsing: false\n"
+ "roles:\n"
+ " default: raw\n"
+@@ -2370,7 +1915,6 @@ OIIO_ADD_TEST(Config, EnvCheck)
+ "testbarchedder") == 0);
+ OIIO_CHECK_ASSERT(strcmp(config->getCurrentContext()->resolveStringVar("${SHOW}"),
+ "bar") == 0);
+- OIIO_CHECK_THOW(config->sanityCheck(), OCIO::Exception);
+ OIIO_CHECK_ASSERT(strcmp(config->getEnvironmentVarDefault("SHOW"), "super") == 0);
+
+ OCIO::ConfigRcPtr edit = config->createEditableCopy();
+@@ -2403,6 +1947,10 @@ OIIO_ADD_TEST(Config, EnvCheck)
+ "lighting") == 0);
+ OCIO::SetLoggingLevel(loglevel);
+
++ OIIO_CHECK_EQUAL(edit->getEnvironmentMode(), OCIO::ENV_ENVIRONMENT_LOAD_PREDEFINED);
++ edit->setEnvironmentMode(OCIO::ENV_ENVIRONMENT_LOAD_ALL);
++ OIIO_CHECK_EQUAL(edit->getEnvironmentMode(), OCIO::ENV_ENVIRONMENT_LOAD_ALL);
++
+ }
+ }
+
+diff --git a/src/core/Display.cpp b/src/core/Display.cpp
+new file mode 100644
+index 0000000..7c0a1ef
+--- /dev/null
++++ b/src/core/Display.cpp
+@@ -0,0 +1,145 @@
++/*
++Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
++All Rights Reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are
++met:
++* Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++* Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++* Neither the name of Sony Pictures Imageworks nor the names of its
++ contributors may be used to endorse or promote products derived from
++ this software without specific prior written permission.
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*/
++
++#include <string>
++
++#include <OpenColorIO/OpenColorIO.h>
++
++#include "Display.h"
++#include "ParseUtils.h"
++
++OCIO_NAMESPACE_ENTER
++{
++
++ DisplayMap::iterator find_display(DisplayMap & displays, const std::string & display)
++ {
++ for(DisplayMap::iterator iter = displays.begin();
++ iter != displays.end();
++ ++iter)
++ {
++ if(StrEqualsCaseIgnore(display, iter->first)) return iter;
++ }
++ return displays.end();
++ }
++
++ DisplayMap::const_iterator find_display_const(const DisplayMap & displays, const std::string & display)
++ {
++ for(DisplayMap::const_iterator iter = displays.begin();
++ iter != displays.end();
++ ++iter)
++ {
++ if(StrEqualsCaseIgnore(display, iter->first)) return iter;
++ }
++ return displays.end();
++ }
++
++ int find_view(const ViewVec & vec, const std::string & name)
++ {
++ for(unsigned int i=0; i<vec.size(); ++i)
++ {
++ if(StrEqualsCaseIgnore(name, vec[i].name)) return i;
++ }
++ return -1;
++ }
++
++ void AddDisplay(DisplayMap & displays,
++ const std::string & display,
++ const std::string & view,
++ const std::string & colorspace,
++ const std::string & looks)
++ {
++ DisplayMap::iterator iter = find_display(displays, display);
++ if(iter == displays.end())
++ {
++ ViewVec views;
++ views.push_back( View(view, colorspace, looks) );
++ displays[display] = views;
++ }
++ else
++ {
++ ViewVec & views = iter->second;
++ int index = find_view(views, view);
++ if(index<0)
++ {
++ views.push_back( View(view, colorspace, looks) );
++ }
++ else
++ {
++ views[index].colorspace = colorspace;
++ views[index].looks = looks;
++ }
++ }
++ }
++
++ void ComputeDisplays(StringVec & displayCache,
++ const DisplayMap & displays,
++ const StringVec & activeDisplays,
++ const StringVec & activeDisplaysEnvOverride)
++ {
++ displayCache.clear();
++
++ StringVec displayMasterList;
++ for(DisplayMap::const_iterator iter = displays.begin();
++ iter != displays.end();
++ ++iter)
++ {
++ displayMasterList.push_back(iter->first);
++ }
++
++ // Apply the env override if it's not empty.
++ if(!activeDisplaysEnvOverride.empty())
++ {
++ displayCache = IntersectStringVecsCaseIgnore(displayMasterList, activeDisplaysEnvOverride);
++ if(!displayCache.empty()) return;
++ }
++ // Otherwise, aApply the active displays if it's not empty.
++ else if(!activeDisplays.empty())
++ {
++ displayCache = IntersectStringVecsCaseIgnore(displayMasterList, activeDisplays);
++ if(!displayCache.empty()) return;
++ }
++
++ displayCache = displayMasterList;
++ }
++
++}
++OCIO_NAMESPACE_EXIT
++
++///////////////////////////////////////////////////////////////////////////////
++
++#ifdef OCIO_UNIT_TEST
++
++namespace OCIO = OCIO_NAMESPACE;
++#include "UnitTest.h"
++
++OIIO_ADD_TEST(Display, Basic)
++{
++
++}
++
++#endif // OCIO_UNIT_TEST
+\ No newline at end of file
+diff --git a/src/core/Display.h b/src/core/Display.h
+new file mode 100644
+index 0000000..6d63a43
+--- /dev/null
++++ b/src/core/Display.h
+@@ -0,0 +1,85 @@
++/*
++Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
++All Rights Reserved.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are
++met:
++* Redistributions of source code must retain the above copyright
++ notice, this list of conditions and the following disclaimer.
++* Redistributions in binary form must reproduce the above copyright
++ notice, this list of conditions and the following disclaimer in the
++ documentation and/or other materials provided with the distribution.
++* Neither the name of Sony Pictures Imageworks nor the names of its
++ contributors may be used to endorse or promote products derived from
++ this software without specific prior written permission.
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*/
++
++
++#ifndef INCLUDED_OCIO_DISPLAY_H
++#define INCLUDED_OCIO_DISPLAY_H
++
++#include <OpenColorIO/OpenColorIO.h>
++
++#include <string>
++#include <vector>
++#include <map>
++
++#include "PrivateTypes.h"
++
++OCIO_NAMESPACE_ENTER
++{
++
++ // Displays
++ struct View
++ {
++ std::string name;
++ std::string colorspace;
++ std::string looks;
++
++ View() { }
++
++ View(const std::string & name_,
++ const std::string & colorspace_,
++ const std::string & looksList_) :
++ name(name_),
++ colorspace(colorspace_),
++ looks(looksList_)
++ { }
++ };
++
++ typedef std::vector<View> ViewVec;
++ typedef std::map<std::string, ViewVec> DisplayMap; // (display name : ViewVec)
++
++ DisplayMap::iterator find_display(DisplayMap & displays, const std::string & display);
++
++ DisplayMap::const_iterator find_display_const(const DisplayMap & displays, const std::string & display);
++
++ int find_view(const ViewVec & vec, const std::string & name);
++
++ void AddDisplay(DisplayMap & displays,
++ const std::string & display,
++ const std::string & view,
++ const std::string & colorspace,
++ const std::string & looks);
++
++ void ComputeDisplays(StringVec & displayCache,
++ const DisplayMap & displays,
++ const StringVec & activeDisplays,
++ const StringVec & activeDisplaysEnvOverride);
++
++}
++OCIO_NAMESPACE_EXIT
++
++#endif
+\ No newline at end of file
+diff --git a/src/core/OCIOYaml.cpp b/src/core/OCIOYaml.cpp
+index 7089318..fc2f5f8 100644
+--- a/src/core/OCIOYaml.cpp
++++ b/src/core/OCIOYaml.cpp
+@@ -30,1188 +30,1787 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ #include <OpenColorIO/OpenColorIO.h>
+
++#ifndef WINDOWS
++
++// fwd declare yaml-cpp visibility
++#pragma GCC visibility push(hidden)
++namespace YAML {
++ class Exception;
++ class BadDereference;
++ class RepresentationException;
++ class EmitterException;
++ class ParserException;
++ class InvalidScalar;
++ class KeyNotFound;
++ template <typename T> class TypedKeyNotFound;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ColorSpace>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Config>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Exception>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::GpuShaderDesc>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ImageDesc>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Look>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Processor>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::Transform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::AllocationTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::CDLTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ColorSpaceTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::DisplayTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::ExponentTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::FileTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::GroupTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::LogTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::LookTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::MatrixTransform>;
++ template <> class TypedKeyNotFound<OCIO_NAMESPACE::TruelightTransform>;
++}
++#pragma GCC visibility pop
++
++#endif
++
++#include <yaml-cpp/yaml.h>
++
+ #include "Logging.h"
+ #include "MathUtils.h"
++#include "pystring/pystring.h"
++#include "PathUtils.h"
++#include "ParseUtils.h"
++#include "Display.h"
+ #include "OCIOYaml.h"
+
+ OCIO_NAMESPACE_ENTER
+ {
+- ///////////////////////////////////////////////////////////////////////////
+- // Core
+
+- void LogUnknownKeyWarning(const std::string & name, const YAML::Node& tag)
++ namespace
+ {
+- std::string key;
+- tag >> key;
+-
+- std::ostringstream os;
+- os << "Unknown key in " << name << ": ";
+- os << "'" << key << "'. (line ";
+- os << (tag.GetMark().line+1) << ", column "; // (yaml line numbers start at 0)
+- os << tag.GetMark().column << ")";
+- LogWarning(os.str());
+- }
+
+- void operator >> (const YAML::Node& node, ColorSpaceRcPtr& cs)
+- {
+- if(node.Tag() != "ColorSpace")
+- return; // not a !<ColorSpace> tag
++#ifdef OLDYAML
++ typedef YAML::Iterator Iterator;
++#else
++ typedef YAML::const_iterator Iterator;
++#endif
+
+- std::string key, stringval;
+- bool boolval;
++ // Iterator access
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
+- {
+- iter.first() >> key;
+-
+- if(key == "name")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- cs->setName(stringval.c_str());
+- }
+- else if(key == "description")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- cs->setDescription(stringval.c_str());
+- }
+- else if(key == "family")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- cs->setFamily(stringval.c_str());
+- }
+- else if(key == "equalitygroup")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- cs->setEqualityGroup(stringval.c_str());
+- }
+- else if(key == "bitdepth")
+- {
+- BitDepth ret;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<BitDepth>(ret))
+- cs->setBitDepth(ret);
+- }
+- else if(key == "isdata")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<bool>(boolval))
+- cs->setIsData(boolval);
+- }
+- else if(key == "allocation")
+- {
+- Allocation val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<Allocation>(val))
+- cs->setAllocation(val);
+- }
+- else if(key == "allocationvars")
+- {
+- std::vector<float> val;
+- if (iter.second().Type() != YAML::NodeType::Null)
+- {
+- iter.second() >> val;
+- if(!val.empty())
+- {
+- cs->setAllocationVars(static_cast<int>(val.size()), &val[0]);
+- }
+- }
+- }
+- else if(key == "to_reference")
+- {
+- TransformRcPtr val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformRcPtr>(val))
+- cs->setTransform(val, COLORSPACE_DIR_TO_REFERENCE);
+- }
+- else if(key == "from_reference")
+- {
+- TransformRcPtr val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformRcPtr>(val))
+- cs->setTransform(val, COLORSPACE_DIR_FROM_REFERENCE);
+- }
+- else
+- {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
+- }
+- }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceRcPtr cs)
+- {
+- out << YAML::VerbatimTag("ColorSpace");
+- out << YAML::BeginMap;
+-
+- out << YAML::Key << "name" << YAML::Value << cs->getName();
+- out << YAML::Key << "family" << YAML::Value << cs->getFamily();
+- out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup();
+- out << YAML::Key << "bitdepth" << YAML::Value << cs->getBitDepth();
+- if(strlen(cs->getDescription()) > 0)
++ inline const YAML::Node& get_first(const Iterator it)
+ {
+- out << YAML::Key << "description";
+- out << YAML::Value << YAML::Literal << cs->getDescription();
++#ifdef OLDYAML
++ return it.first();
++#else
++ return it->first;
++#endif
+ }
+- out << YAML::Key << "isdata" << YAML::Value << cs->isData();
+
+- out << YAML::Key << "allocation" << YAML::Value << cs->getAllocation();
+- if(cs->getAllocationNumVars() > 0)
++ inline const YAML::Node& get_second(const Iterator it)
+ {
+- std::vector<float> allocationvars(cs->getAllocationNumVars());
+- cs->getAllocationVars(&allocationvars[0]);
+- out << YAML::Key << "allocationvars";
+- out << YAML::Flow << YAML::Value << allocationvars;
++#ifdef OLDYAML
++ return it.second();
++#else
++ return it->second;
++#endif
+ }
+
+- ConstTransformRcPtr toref = \
+- cs->getTransform(COLORSPACE_DIR_TO_REFERENCE);
+- if(toref)
+- out << YAML::Key << "to_reference" << YAML::Value << toref;
+-
+- ConstTransformRcPtr fromref = \
+- cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE);
+- if(fromref)
+- out << YAML::Key << "from_reference" << YAML::Value << fromref;
+-
+- out << YAML::EndMap;
+- out << YAML::Newline;
+-
+- return out;
+- }
+-
+-
+- ///////////////////////////////////////////////////////////////////////////
+-
+- // Look. (not the transform, the top-level class)
+-
+- void operator >> (const YAML::Node& node, LookRcPtr& look)
+- {
+- if(node.Tag() != "Look")
+- return;
+-
+- std::string key, stringval;
++ // Basic types
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void load(const YAML::Node& node, bool& x)
+ {
+- iter.first() >> key;
+-
+- if(key == "name")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- look->setName(stringval.c_str());
+- }
+- else if(key == "process_space")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- look->setProcessSpace(stringval.c_str());
+- }
+- else if(key == "transform")
+- {
+- TransformRcPtr val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformRcPtr>(val))
+- look->setTransform(val);
+- }
+- else if(key == "inverse_transform")
+- {
+- TransformRcPtr val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformRcPtr>(val))
+- look->setInverseTransform(val);
+- }
+- else
+- {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
+- }
++#ifdef OLDYAML
++ node.Read<bool>(x);
++#else
++ x = node.as<bool>();
++#endif
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, LookRcPtr look)
+- {
+- out << YAML::VerbatimTag("Look");
+- out << YAML::BeginMap;
+- out << YAML::Key << "name" << YAML::Value << look->getName();
+- out << YAML::Key << "process_space" << YAML::Value << look->getProcessSpace();
+
+- if(look->getTransform())
++ inline void load(const YAML::Node& node, int& x)
+ {
+- out << YAML::Key << "transform";
+- out << YAML::Value << look->getTransform();
++#ifdef OLDYAML
++ node.Read<int>(x);
++#else
++ x = node.as<int>();
++#endif
+ }
+
+- if(look->getInverseTransform())
++ inline void load(const YAML::Node& node, float& x)
+ {
+- out << YAML::Key << "inverse_transform";
+- out << YAML::Value << look->getInverseTransform();
++#ifdef OLDYAML
++ node.Read<float>(x);
++#else
++ x = node.as<float>();
++#endif
+ }
+
+- out << YAML::EndMap;
+- out << YAML::Newline;
++ inline void load(const YAML::Node& node, std::string& x)
++ {
++#ifdef OLDYAML
++ node.Read<std::string>(x);
++#else
++ x = node.as<std::string>();
++#endif
++ }
+
+- return out;
+- }
+-
+-
+-
+- ///////////////////////////////////////////////////////////////////////////
+-
+-
+- namespace
+- {
+- void EmitBaseTransformKeyValues(YAML::Emitter & out,
+- const ConstTransformRcPtr & t)
++ inline void load(const YAML::Node& node, std::vector<std::string>& x)
+ {
+- if(t->getDirection() != TRANSFORM_DIR_FORWARD)
+- {
+- out << YAML::Key << "direction";
+- out << YAML::Value << YAML::Flow << t->getDirection();
+- }
++#ifdef OLDYAML
++ node >> x;
++#else
++ x = node.as<std::vector<std::string> >();
++#endif
+ }
+- }
+-
+- void operator >> (const YAML::Node& node, TransformRcPtr& t)
+- {
+- if(node.Type() != YAML::NodeType::Map)
++
++ inline void load(const YAML::Node& node, std::vector<float>& x)
+ {
+- std::ostringstream os;
+- os << "Unsupported Transform type encountered: (" << node.Type() << ") in OCIO profile. ";
+- os << "Only Mapping types supported. (line ";
+- os << (node.GetMark().line+1) << ", column "; // (yaml line numbers start at 0)
+- os << node.GetMark().column << ")";
+- throw Exception(os.str().c_str());
++#ifdef OLDYAML
++ node >> x;
++#else
++ x = node.as<std::vector<float> >();
++#endif
+ }
+
+- std::string type = node.Tag();
++ // Enums
+
+- if(type == "AllocationTransform") {
+- AllocationTransformRcPtr temp;
+- node.Read<AllocationTransformRcPtr>(temp);
+- t = temp;
++ inline void load(const YAML::Node& node, BitDepth& depth)
++ {
++ std::string str;
++ load(node, str);
++ depth = BitDepthFromString(str.c_str());
+ }
+- else if(type == "CDLTransform") {
+- CDLTransformRcPtr temp;
+- node.Read<CDLTransformRcPtr>(temp);
+- t = temp;
++
++ inline void save(YAML::Emitter& out, BitDepth depth)
++ {
++ out << BitDepthToString(depth);
+ }
+- else if(type == "ColorSpaceTransform") {
+- ColorSpaceTransformRcPtr temp;
+- node.Read<ColorSpaceTransformRcPtr>(temp);
+- t = temp;
++
++ inline void load(const YAML::Node& node, Allocation& alloc)
++ {
++ std::string str;
++ load(node, str);
++ alloc = AllocationFromString(str.c_str());
+ }
+- // TODO: DisplayTransform
+- else if(type == "ExponentTransform") {
+- ExponentTransformRcPtr temp;
+- node.Read<ExponentTransformRcPtr>(temp);
+- t = temp;
++
++ inline void save(YAML::Emitter& out, Allocation alloc)
++ {
++ out << AllocationToString(alloc);
+ }
+- else if(type == "FileTransform") {
+- FileTransformRcPtr temp;
+- node.Read<FileTransformRcPtr>(temp);
+- t = temp;
++
++ inline void load(const YAML::Node& node, ColorSpaceDirection& dir)
++ {
++ std::string str;
++ load(node, str);
++ dir = ColorSpaceDirectionFromString(str.c_str());
+ }
+- else if(type == "GroupTransform") {
+- GroupTransformRcPtr temp;
+- node.Read<GroupTransformRcPtr>(temp);
+- t = temp;
++
++ inline void save(YAML::Emitter& out, ColorSpaceDirection dir)
++ {
++ out << ColorSpaceDirectionToString(dir);
+ }
+- else if(type == "LogTransform") {
+- LogTransformRcPtr temp;
+- node.Read<LogTransformRcPtr>(temp);
+- t = temp;
++
++ inline void load(const YAML::Node& node, TransformDirection& dir)
++ {
++ std::string str;
++ load(node, str);
++ dir = TransformDirectionFromString(str.c_str());
+ }
+- else if(type == "LookTransform") {
+- LookTransformRcPtr temp;
+- node.Read<LookTransformRcPtr>(temp);
+- t = temp;
++
++ inline void save(YAML::Emitter& out, TransformDirection dir)
++ {
++ out << TransformDirectionToString(dir);
+ }
+- else if(type == "MatrixTransform") {
+- MatrixTransformRcPtr temp;
+- node.Read<MatrixTransformRcPtr>(temp);
+- t = temp;
++
++ inline void load(const YAML::Node& node, Interpolation& interp)
++ {
++ std::string str;
++ load(node, str);
++ interp = InterpolationFromString(str.c_str());
+ }
+- else if(type == "TruelightTransform") {
+- TruelightTransformRcPtr temp;
+- node.Read<TruelightTransformRcPtr>(temp);
+- t = temp;
++
++ inline void save(YAML::Emitter& out, Interpolation interp)
++ {
++ out << InterpolationToString(interp);
+ }
+- else
++
++ //
++
++ inline void LogUnknownKeyWarning(const std::string & name,
++ const YAML::Node& tag)
+ {
+- // TODO: add a new empty (better name?) aka passthru Transform()
+- // which does nothing. This is so upsupported !<tag> types don't
+- // throw an exception. Alternativly this could be caught in the
+- // GroupTransformRcPtr >> operator with some type of
+- // supported_tag() method
+-
+- // TODO: consider the forwards-compatibility implication of
+- // throwing an exception. Should this be a warning, instead?
+-
+- // t = EmptyTransformRcPtr(new EmptyTransform(), &deleter);
++ std::string key;
++ load(tag, key);
++
+ std::ostringstream os;
+- os << "Unsupported transform type !<" << type << "> in OCIO profile. ";
+- os << " (line ";
+- os << (node.GetMark().line+1) << ", column "; // (yaml line numbers start at 0)
+- os << node.GetMark().column << ")";
+- throw Exception(os.str().c_str());
++ os << "Unknown key in " << name << ": '" << key << "'.";
++ LogWarning(os.str());
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstTransformRcPtr t)
+- {
+- if(ConstAllocationTransformRcPtr Allocation_tran = \
+- DynamicPtrCast<const AllocationTransform>(t))
+- out << Allocation_tran;
+- else if(ConstCDLTransformRcPtr CDL_tran = \
+- DynamicPtrCast<const CDLTransform>(t))
+- out << CDL_tran;
+- else if(ConstColorSpaceTransformRcPtr ColorSpace_tran = \
+- DynamicPtrCast<const ColorSpaceTransform>(t))
+- out << ColorSpace_tran;
+- else if(ConstExponentTransformRcPtr Exponent_tran = \
+- DynamicPtrCast<const ExponentTransform>(t))
+- out << Exponent_tran;
+- else if(ConstFileTransformRcPtr File_tran = \
+- DynamicPtrCast<const FileTransform>(t))
+- out << File_tran;
+- else if(ConstGroupTransformRcPtr Group_tran = \
+- DynamicPtrCast<const GroupTransform>(t))
+- out << Group_tran;
+- else if(ConstLogTransformRcPtr Log_tran = \
+- DynamicPtrCast<const LogTransform>(t))
+- out << Log_tran;
+- else if(ConstLookTransformRcPtr Look_tran = \
+- DynamicPtrCast<const LookTransform>(t))
+- out << Look_tran;
+- else if(ConstMatrixTransformRcPtr Matrix_tran = \
+- DynamicPtrCast<const MatrixTransform>(t))
+- out << Matrix_tran;
+- else if(ConstTruelightTransformRcPtr Truelight_tran = \
+- DynamicPtrCast<const TruelightTransform>(t))
+- out << Truelight_tran;
+- else
+- throw Exception("Unsupported Transform() type for serialization.");
+-
+- return out;
+- }
+-
+-
+- ///////////////////////////////////////////////////////////////////////////
+- // Transforms
+-
+- void operator >> (const YAML::Node& node, GroupTransformRcPtr& t)
+- {
+- t = GroupTransform::Create();
+
+- std::string key;
++ // View
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void load(const YAML::Node& node, View& v)
+ {
+- iter.first() >> key;
++ if(node.Tag() != "View")
++ return;
+
+- if(key == "children")
+- {
+- const YAML::Node & children = iter.second();
+- for(unsigned i = 0; i <children.size(); ++i)
++ std::string key, stringval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "name")
+ {
+- TransformRcPtr childTransform;
+- children[i].Read<TransformRcPtr>(childTransform);
+-
+- // TODO: consider the forwards-compatibility implication of
+- // throwing an exception. Should this be a warning, instead?
+- if(!childTransform)
+- {
+- throw Exception("Child transform could not be parsed.");
+- }
+-
+- t->push_back(childTransform);
++ load(second, stringval);
++ v.name = stringval;
++ }
++ else if(key == "colorspace")
++ {
++ load(second, stringval);
++ v.colorspace = stringval;
++ }
++ else if(key == "looks" || key == "look")
++ {
++ load(second, stringval);
++ v.looks = stringval;
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
+ }
+ }
+- else if(key == "direction")
++
++ if(v.name.empty())
+ {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
++ throw Exception("View does not specify 'name'.");
+ }
+- else
++ if(v.colorspace.empty())
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ std::ostringstream os;
++ os << "View '" << v.name << "' ";
++ os << "does not specify colorspace.";
++ throw Exception(os.str().c_str());
+ }
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstGroupTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("GroupTransform");
+- out << YAML::BeginMap;
+- EmitBaseTransformKeyValues(out, t);
+-
+- out << YAML::Key << "children";
+- out << YAML::Value;
+
+- out << YAML::BeginSeq;
+- for(int i = 0; i < t->size(); ++i)
++ inline void save(YAML::Emitter& out, View view)
+ {
+- out << t->getTransform(i);
++ out << YAML::VerbatimTag("View");
++ out << YAML::Flow;
++ out << YAML::BeginMap;
++ out << YAML::Key << "name" << YAML::Value << view.name;
++ out << YAML::Key << "colorspace" << YAML::Value << view.colorspace;
++ if(!view.looks.empty()) out << YAML::Key << "looks" << YAML::Value << view.looks;
++ out << YAML::EndMap;
+ }
+- out << YAML::EndSeq;
+-
+- out << YAML::EndMap;
+-
+- return out;
+- }
+-
+-
+-
+- void operator >> (const YAML::Node& node, FileTransformRcPtr& t)
+- {
+- t = FileTransform::Create();
+
+- std::string key, stringval;
++ // Common Transform
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void EmitBaseTransformKeyValues(YAML::Emitter & out,
++ const ConstTransformRcPtr & t)
+ {
+- iter.first() >> key;
+-
+- if(key == "src")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setSrc(stringval.c_str());
+- }
+- else if(key == "cccid")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setCCCId(stringval.c_str());
+- }
+- else if(key == "interpolation")
+- {
+- Interpolation val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<Interpolation>(val))
+- t->setInterpolation(val);
+- }
+- else if(key == "direction")
+- {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
+- }
+- else
++ if(t->getDirection() != TRANSFORM_DIR_FORWARD)
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ out << YAML::Key << "direction";
++ out << YAML::Value << YAML::Flow;
++ save(out, t->getDirection());
+ }
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstFileTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("FileTransform");
+- out << YAML::Flow << YAML::BeginMap;
+- out << YAML::Key << "src" << YAML::Value << t->getSrc();
+- const char * cccid = t->getCCCId();
+- if(cccid && *cccid)
+- {
+- out << YAML::Key << "cccid" << YAML::Value << t->getCCCId();
+- }
+- out << YAML::Key << "interpolation";
+- out << YAML::Value << t->getInterpolation();
+-
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, ColorSpaceTransformRcPtr& t)
+- {
+- t = ColorSpaceTransform::Create();
+
+- std::string key, stringval;
++ // AllocationTransform
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void load(const YAML::Node& node, AllocationTransformRcPtr& t)
+ {
+- iter.first() >> key;
++ t = AllocationTransform::Create();
+
+- if(key == "src")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setSrc(stringval.c_str());
+- }
+- else if(key == "dst")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setDst(stringval.c_str());
+- }
+- else if(key == "direction")
+- {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
+- }
+- else
+- {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ std::string key;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "allocation")
++ {
++ Allocation val;
++ load(second, val);
++ t->setAllocation(val);
++ }
++ else if(key == "vars")
++ {
++ std::vector<float> val;
++ load(second, val);
++ if(!val.empty())
++ {
++ t->setVars(static_cast<int>(val.size()), &val[0]);
++ }
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
+ }
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstColorSpaceTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("ColorSpaceTransform");
+- out << YAML::Flow << YAML::BeginMap;
+- out << YAML::Key << "src" << YAML::Value << t->getSrc();
+- out << YAML::Key << "dst" << YAML::Value << t->getDst();
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, LookTransformRcPtr& t)
+- {
+- t = LookTransform::Create();
+-
+- std::string key, stringval;
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void save(YAML::Emitter& out, ConstAllocationTransformRcPtr t)
+ {
+- iter.first() >> key;
++ out << YAML::VerbatimTag("AllocationTransform");
++ out << YAML::Flow << YAML::BeginMap;
+
+- if(key == "src")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setSrc(stringval.c_str());
+- }
+- else if(key == "dst")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setDst(stringval.c_str());
+- }
+- else if(key == "looks")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setLooks(stringval.c_str());
+- }
+- else if(key == "direction")
+- {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
+- }
+- else
++ out << YAML::Key << "allocation";
++ out << YAML::Value << YAML::Flow;
++ save(out, t->getAllocation());
++
++ if(t->getNumVars() > 0)
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ std::vector<float> vars(t->getNumVars());
++ t->getVars(&vars[0]);
++ out << YAML::Key << "vars";
++ out << YAML::Flow << YAML::Value << vars;
+ }
++
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstLookTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("LookTransform");
+- out << YAML::Flow << YAML::BeginMap;
+- out << YAML::Key << "src" << YAML::Value << t->getSrc();
+- out << YAML::Key << "dst" << YAML::Value << t->getDst();
+- out << YAML::Key << "looks" << YAML::Value << t->getLooks();
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, ExponentTransformRcPtr& t)
+- {
+- t = ExponentTransform::Create();
+
+- std::string key;
++ // CDLTransform
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void load(const YAML::Node& node, CDLTransformRcPtr& t)
+ {
+- iter.first() >> key;
++ t = CDLTransform::Create();
+
+- if(key == "value")
+- {
+- std::vector<float> val;
+- if (iter.second().Type() != YAML::NodeType::Null)
++ std::string key;
++ std::vector<float> floatvecval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "slope")
+ {
+- iter.second() >> val;
+- if(val.size() != 4)
++ load(second, floatvecval);
++ if(floatvecval.size() != 3)
+ {
+ std::ostringstream os;
+- os << "ExponentTransform parse error, value field must be 4 ";
+- os << "floats. Found '" << val.size() << "'.";
++ os << "CDLTransform parse error, 'slope' field must be 3 ";
++ os << "floats. Found '" << floatvecval.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+- t->setValue(&val[0]);
++ t->setSlope(&floatvecval[0]);
+ }
+- }
+- else if(key == "direction")
+- {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
+- }
+- else
+- {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
+- }
+- }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstExponentTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("ExponentTransform");
+- out << YAML::Flow << YAML::BeginMap;
+-
+- std::vector<float> value(4, 0.0);
+- t->getValue(&value[0]);
+- out << YAML::Key << "value";
+- out << YAML::Value << YAML::Flow << value;
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, LogTransformRcPtr& t)
+- {
+- t = LogTransform::Create();
+-
+- std::string key;
+-
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
+- {
+- iter.first() >> key;
+-
+- if(key == "base")
+- {
+- float val = 0.0f;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<float>(val))
+- t->setBase(val);
+- }
+- else if(key == "direction")
+- {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
+- }
+- else
+- {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
+- }
+- }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstLogTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("LogTransform");
+- out << YAML::Flow << YAML::BeginMap;
+- out << YAML::Key << "base" << YAML::Value << t->getBase();
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, MatrixTransformRcPtr& t)
+- {
+- t = MatrixTransform::Create();
+-
+- std::string key;
+-
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
+- {
+- iter.first() >> key;
+-
+- if(key == "matrix")
+- {
+- std::vector<float> val;
+- if (iter.second().Type() != YAML::NodeType::Null)
++ else if(key == "offset")
+ {
+- iter.second() >> val;
+- if(val.size() != 16)
++ load(second, floatvecval);
++ if(floatvecval.size() != 3)
+ {
+ std::ostringstream os;
+- os << "MatrixTransform parse error, matrix field must be 16 ";
+- os << "floats. Found '" << val.size() << "'.";
++ os << "CDLTransform parse error, 'offset' field must be 3 ";
++ os << "floats. Found '" << floatvecval.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+- t->setMatrix(&val[0]);
++ t->setOffset(&floatvecval[0]);
+ }
+- }
+- else if(key == "offset")
+- {
+- std::vector<float> val;
+- if (iter.second().Type() != YAML::NodeType::Null)
++ else if(key == "power")
+ {
+- iter.second() >> val;
+- if(val.size() != 4)
++ load(second, floatvecval);
++ if(floatvecval.size() != 3)
+ {
+ std::ostringstream os;
+- os << "MatrixTransform parse error, offset field must be 4 ";
+- os << "floats. Found '" << val.size() << "'.";
++ os << "CDLTransform parse error, 'power' field must be 3 ";
++ os << "floats. Found '" << floatvecval.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+- t->setOffset(&val[0]);
++ t->setPower(&floatvecval[0]);
++ }
++ else if(key == "saturation" || key == "sat")
++ {
++ float val = 0.0f;
++ load(second, val);
++ t->setSat(val);
+ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
++ }
++
++ inline void save(YAML::Emitter& out, ConstCDLTransformRcPtr t)
++ {
++ out << YAML::VerbatimTag("CDLTransform");
++ out << YAML::Flow << YAML::BeginMap;
++
++ std::vector<float> slope(3);
++ t->getSlope(&slope[0]);
++ if(!IsVecEqualToOne(&slope[0], 3))
++ {
++ out << YAML::Key << "slope";
++ out << YAML::Value << YAML::Flow << slope;
+ }
+- else if(key == "direction")
++
++ std::vector<float> offset(3);
++ t->getOffset(&offset[0]);
++ if(!IsVecEqualToZero(&offset[0], 3))
+ {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
++ out << YAML::Key << "offset";
++ out << YAML::Value << YAML::Flow << offset;
+ }
+- else
++
++ std::vector<float> power(3);
++ t->getPower(&power[0]);
++ if(!IsVecEqualToOne(&power[0], 3))
++ {
++ out << YAML::Key << "power";
++ out << YAML::Value << YAML::Flow << power;
++ }
++
++ if(!IsScalarEqualToOne(t->getSat()))
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ out << YAML::Key << "sat" << YAML::Value << t->getSat();
+ }
++
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstMatrixTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("MatrixTransform");
+- out << YAML::Flow << YAML::BeginMap;
+
+- std::vector<float> matrix(16, 0.0);
+- t->getMatrix(&matrix[0]);
+- if(!IsM44Identity(&matrix[0]))
++ // ColorSpaceTransform
++
++ inline void load(const YAML::Node& node, ColorSpaceTransformRcPtr& t)
+ {
+- out << YAML::Key << "matrix";
+- out << YAML::Value << YAML::Flow << matrix;
++ t = ColorSpaceTransform::Create();
++
++ std::string key, stringval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "src")
++ {
++ load(second, stringval);
++ t->setSrc(stringval.c_str());
++ }
++ else if(key == "dst")
++ {
++ load(second, stringval);
++ t->setDst(stringval.c_str());
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
+ }
+
+- std::vector<float> offset(4, 0.0);
+- t->getOffset(&offset[0]);
+- if(!IsVecEqualToZero(&offset[0],4))
++ inline void save(YAML::Emitter& out, ConstColorSpaceTransformRcPtr t)
+ {
+- out << YAML::Key << "offset";
+- out << YAML::Value << YAML::Flow << offset;
++ out << YAML::VerbatimTag("ColorSpaceTransform");
++ out << YAML::Flow << YAML::BeginMap;
++ out << YAML::Key << "src" << YAML::Value << t->getSrc();
++ out << YAML::Key << "dst" << YAML::Value << t->getDst();
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
+ }
+
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, CDLTransformRcPtr& t)
+- {
+- t = CDLTransform::Create();
++ // ExponentTransform
+
+- std::string key;
+- std::vector<float> floatvecval;
+-
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void load(const YAML::Node& node, ExponentTransformRcPtr& t)
+ {
+- iter.first() >> key;
++ t = ExponentTransform::Create();
+
+- if(key == "slope")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null)
++ std::string key;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "value")
+ {
+- iter.second() >> floatvecval;
+- if(floatvecval.size() != 3)
++ std::vector<float> val;
++ load(second, val);
++ if(val.size() != 4)
+ {
+ std::ostringstream os;
+- os << "CDLTransform parse error, 'slope' field must be 3 ";
+- os << "floats. Found '" << floatvecval.size() << "'.";
++ os << "ExponentTransform parse error, value field must be 4 ";
++ os << "floats. Found '" << val.size() << "'.";
+ throw Exception(os.str().c_str());
+ }
+- t->setSlope(&floatvecval[0]);
++ t->setValue(&val[0]);
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
+ }
+ }
+- else if(key == "offset")
+- {
+- if (iter.second().Type() != YAML::NodeType::Null)
++ }
++
++ inline void save(YAML::Emitter& out, ConstExponentTransformRcPtr t)
++ {
++ out << YAML::VerbatimTag("ExponentTransform");
++ out << YAML::Flow << YAML::BeginMap;
++
++ std::vector<float> value(4, 0.0);
++ t->getValue(&value[0]);
++ out << YAML::Key << "value";
++ out << YAML::Value << YAML::Flow << value;
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
++ }
++
++ // FileTransform
++
++ inline void load(const YAML::Node& node, FileTransformRcPtr& t)
++ {
++ t = FileTransform::Create();
++
++ std::string key, stringval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "src")
+ {
+- iter.second() >> floatvecval;
+- if(floatvecval.size() != 3)
+- {
+- std::ostringstream os;
+- os << "CDLTransform parse error, 'offset' field must be 3 ";
+- os << "floats. Found '" << floatvecval.size() << "'.";
+- throw Exception(os.str().c_str());
+- }
+- t->setOffset(&floatvecval[0]);
++ load(second, stringval);
++ t->setSrc(stringval.c_str());
++ }
++ else if(key == "cccid")
++ {
++ load(second, stringval);
++ t->setCCCId(stringval.c_str());
++ }
++ else if(key == "interpolation")
++ {
++ Interpolation val;
++ load(second, val);
++ t->setInterpolation(val);
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
+ }
+ }
+- else if(key == "power")
++ }
++
++ inline void save(YAML::Emitter& out, ConstFileTransformRcPtr t)
++ {
++ out << YAML::VerbatimTag("FileTransform");
++ out << YAML::Flow << YAML::BeginMap;
++ out << YAML::Key << "src" << YAML::Value << t->getSrc();
++ const char * cccid = t->getCCCId();
++ if(cccid && *cccid)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null)
++ out << YAML::Key << "cccid" << YAML::Value << t->getCCCId();
++ }
++ out << YAML::Key << "interpolation";
++ out << YAML::Value;
++ save(out, t->getInterpolation());
++
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
++ }
++
++ // GroupTransform
++
++ void load(const YAML::Node& node, TransformRcPtr& t);
++ void save(YAML::Emitter& out, ConstTransformRcPtr t);
++
++ inline void load(const YAML::Node& node, GroupTransformRcPtr& t)
++ {
++ t = GroupTransform::Create();
++
++ std::string key;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "children")
+ {
+- iter.second() >> floatvecval;
+- if(floatvecval.size() != 3)
++ for(unsigned i = 0; i < second.size(); ++i)
+ {
+- std::ostringstream os;
+- os << "CDLTransform parse error, 'power' field must be 3 ";
+- os << "floats. Found '" << floatvecval.size() << "'.";
+- throw Exception(os.str().c_str());
++ TransformRcPtr childTransform;
++ load(second[i], childTransform);
++
++ // TODO: consider the forwards-compatibility implication of
++ // throwing an exception. Should this be a warning, instead?
++ if(!childTransform)
++ {
++ throw Exception("Child transform could not be parsed.");
++ }
++
++ t->push_back(childTransform);
+ }
+- t->setPower(&floatvecval[0]);
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
+ }
+ }
+- else if(key == "saturation" || key == "sat")
+- {
+- float val = 0.0f;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<float>(val))
+- t->setSat(val);
+- }
+- else if(key == "direction")
+- {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
+- }
+- else
++ }
++
++ inline void save(YAML::Emitter& out, ConstGroupTransformRcPtr t)
++ {
++ out << YAML::VerbatimTag("GroupTransform");
++ out << YAML::BeginMap;
++ EmitBaseTransformKeyValues(out, t);
++
++ out << YAML::Key << "children";
++ out << YAML::Value;
++
++ out << YAML::BeginSeq;
++ for(int i = 0; i < t->size(); ++i)
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ save(out, t->getTransform(i));
+ }
++ out << YAML::EndSeq;
++
++ out << YAML::EndMap;
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstCDLTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("CDLTransform");
+- out << YAML::Flow << YAML::BeginMap;
+
+- std::vector<float> slope(3);
+- t->getSlope(&slope[0]);
+- if(!IsVecEqualToOne(&slope[0], 3))
++ // LogTransform
++
++ inline void load(const YAML::Node& node, LogTransformRcPtr& t)
+ {
+- out << YAML::Key << "slope";
+- out << YAML::Value << YAML::Flow << slope;
++ t = LogTransform::Create();
++
++ std::string key;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "base")
++ {
++ float val = 0.0f;
++ load(second, val);
++ t->setBase(val);
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
+ }
+
+- std::vector<float> offset(3);
+- t->getOffset(&offset[0]);
+- if(!IsVecEqualToZero(&offset[0], 3))
++ inline void save(YAML::Emitter& out, ConstLogTransformRcPtr t)
+ {
+- out << YAML::Key << "offset";
+- out << YAML::Value << YAML::Flow << offset;
++ out << YAML::VerbatimTag("LogTransform");
++ out << YAML::Flow << YAML::BeginMap;
++ out << YAML::Key << "base" << YAML::Value << t->getBase();
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
+ }
+
+- std::vector<float> power(3);
+- t->getPower(&power[0]);
+- if(!IsVecEqualToOne(&power[0], 3))
++ // LookTransform
++
++ inline void load(const YAML::Node& node, LookTransformRcPtr& t)
+ {
+- out << YAML::Key << "power";
+- out << YAML::Value << YAML::Flow << power;
++ t = LookTransform::Create();
++
++ std::string key, stringval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "src")
++ {
++ load(second, stringval);
++ t->setSrc(stringval.c_str());
++ }
++ else if(key == "dst")
++ {
++ load(second, stringval);
++ t->setDst(stringval.c_str());
++ }
++ else if(key == "looks")
++ {
++ load(second, stringval);
++ t->setLooks(stringval.c_str());
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
+ }
+
+- if(!IsScalarEqualToOne(t->getSat()))
++ inline void save(YAML::Emitter& out, ConstLookTransformRcPtr t)
+ {
+- out << YAML::Key << "sat" << YAML::Value << t->getSat();
++ out << YAML::VerbatimTag("LookTransform");
++ out << YAML::Flow << YAML::BeginMap;
++ out << YAML::Key << "src" << YAML::Value << t->getSrc();
++ out << YAML::Key << "dst" << YAML::Value << t->getDst();
++ out << YAML::Key << "looks" << YAML::Value << t->getLooks();
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
+ }
+
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, AllocationTransformRcPtr& t)
+- {
+- t = AllocationTransform::Create();
+-
+- std::string key;
++ // MatrixTransform
+
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void load(const YAML::Node& node, MatrixTransformRcPtr& t)
+ {
+- iter.first() >> key;
++ t = MatrixTransform::Create();
+
+- if(key == "allocation")
+- {
+- Allocation val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<Allocation>(val))
+- t->setAllocation(val);
+- }
+- else if(key == "vars")
+- {
+- std::vector<float> val;
+- if (iter.second().Type() != YAML::NodeType::Null)
++ std::string key;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "matrix")
+ {
+- iter.second() >> val;
+- if(!val.empty())
++ std::vector<float> val;
++ load(second, val);
++ if(val.size() != 16)
+ {
+- t->setVars(static_cast<int>(val.size()), &val[0]);
++ std::ostringstream os;
++ os << "MatrixTransform parse error, matrix field must be 16 ";
++ os << "floats. Found '" << val.size() << "'.";
++ throw Exception(os.str().c_str());
++ }
++ t->setMatrix(&val[0]);
++ }
++ else if(key == "offset")
++ {
++ std::vector<float> val;
++ load(second, val);
++ if(val.size() != 4)
++ {
++ std::ostringstream os;
++ os << "MatrixTransform parse error, offset field must be 4 ";
++ os << "floats. Found '" << val.size() << "'.";
++ throw Exception(os.str().c_str());
+ }
++ t->setOffset(&val[0]);
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
+ }
+ }
+- else if(key == "direction")
++ }
++
++ inline void save(YAML::Emitter& out, ConstMatrixTransformRcPtr t)
++ {
++ out << YAML::VerbatimTag("MatrixTransform");
++ out << YAML::Flow << YAML::BeginMap;
++
++ std::vector<float> matrix(16, 0.0);
++ t->getMatrix(&matrix[0]);
++ if(!IsM44Identity(&matrix[0]))
+ {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
++ out << YAML::Key << "matrix";
++ out << YAML::Value << YAML::Flow << matrix;
+ }
+- else
++
++ std::vector<float> offset(4, 0.0);
++ t->getOffset(&offset[0]);
++ if(!IsVecEqualToZero(&offset[0],4))
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ out << YAML::Key << "offset";
++ out << YAML::Value << YAML::Flow << offset;
+ }
++
++ EmitBaseTransformKeyValues(out, t);
++ out << YAML::EndMap;
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstAllocationTransformRcPtr t)
+- {
+- out << YAML::VerbatimTag("AllocationTransform");
+- out << YAML::Flow << YAML::BeginMap;
+
+- out << YAML::Key << "allocation";
+- out << YAML::Value << YAML::Flow << t->getAllocation();
++ // TruelightTransform
+
+- if(t->getNumVars() > 0)
++ inline void load(const YAML::Node& node, TruelightTransformRcPtr& t)
+ {
+- std::vector<float> vars(t->getNumVars());
+- t->getVars(&vars[0]);
+- out << YAML::Key << "vars";
+- out << YAML::Flow << YAML::Value << vars;
++ t = TruelightTransform::Create();
++
++ std::string key, stringval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "config_root")
++ {
++ load(second, stringval);
++ t->setConfigRoot(stringval.c_str());
++ }
++ else if(key == "profile")
++ {
++ load(second, stringval);
++ t->setProfile(stringval.c_str());
++ }
++ else if(key == "camera")
++ {
++ load(second, stringval);
++ t->setCamera(stringval.c_str());
++ }
++ else if(key == "input_display")
++ {
++ load(second, stringval);
++ t->setInputDisplay(stringval.c_str());
++ }
++ else if(key == "recorder")
++ {
++ load(second, stringval);
++ t->setRecorder(stringval.c_str());
++ }
++ else if(key == "print")
++ {
++ load(second, stringval);
++ t->setPrint(stringval.c_str());
++ }
++ else if(key == "lamp")
++ {
++ load(second, stringval);
++ t->setLamp(stringval.c_str());
++ }
++ else if(key == "output_camera")
++ {
++ load(second, stringval);
++ t->setOutputCamera(stringval.c_str());
++ }
++ else if(key == "display")
++ {
++ load(second, stringval);
++ t->setDisplay(stringval.c_str());
++ }
++ else if(key == "cube_input")
++ {
++ load(second, stringval);
++ t->setCubeInput(stringval.c_str());
++ }
++ else if(key == "direction")
++ {
++ TransformDirection val;
++ load(second, val);
++ t->setDirection(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
+ }
+
+- EmitBaseTransformKeyValues(out, t);
+- out << YAML::EndMap;
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, TruelightTransformRcPtr& t)
+- {
+- t = TruelightTransform::Create();
+-
+- std::string key, stringval;
+-
+- for (YAML::Iterator iter = node.begin();
+- iter != node.end();
+- ++iter)
++ inline void save(YAML::Emitter& out, ConstTruelightTransformRcPtr t)
+ {
+- iter.first() >> key;
+
+- if(key == "config_root")
++ out << YAML::VerbatimTag("TruelightTransform");
++ out << YAML::Flow << YAML::BeginMap;
++ if(strcmp(t->getConfigRoot(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setConfigRoot(stringval.c_str());
++ out << YAML::Key << "config_root";
++ out << YAML::Value << YAML::Flow << t->getConfigRoot();
+ }
+- else if(key == "profile")
++ if(strcmp(t->getProfile(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setProfile(stringval.c_str());
++ out << YAML::Key << "profile";
++ out << YAML::Value << YAML::Flow << t->getProfile();
+ }
+- else if(key == "camera")
++ if(strcmp(t->getCamera(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setCamera(stringval.c_str());
++ out << YAML::Key << "camera";
++ out << YAML::Value << YAML::Flow << t->getCamera();
+ }
+- else if(key == "input_display")
++ if(strcmp(t->getInputDisplay(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setInputDisplay(stringval.c_str());
++ out << YAML::Key << "input_display";
++ out << YAML::Value << YAML::Flow << t->getInputDisplay();
+ }
+- else if(key == "recorder")
++ if(strcmp(t->getRecorder(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setRecorder(stringval.c_str());
++ out << YAML::Key << "recorder";
++ out << YAML::Value << YAML::Flow << t->getRecorder();
+ }
+- else if(key == "print")
++ if(strcmp(t->getPrint(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setPrint(stringval.c_str());
++ out << YAML::Key << "print";
++ out << YAML::Value << YAML::Flow << t->getPrint();
+ }
+- else if(key == "lamp")
++ if(strcmp(t->getLamp(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setLamp(stringval.c_str());
++ out << YAML::Key << "lamp";
++ out << YAML::Value << YAML::Flow << t->getLamp();
+ }
+- else if(key == "output_camera")
++ if(strcmp(t->getOutputCamera(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setOutputCamera(stringval.c_str());
++ out << YAML::Key << "output_camera";
++ out << YAML::Value << YAML::Flow << t->getOutputCamera();
+ }
+- else if(key == "display")
++ if(strcmp(t->getDisplay(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setDisplay(stringval.c_str());
++ out << YAML::Key << "display";
++ out << YAML::Value << YAML::Flow << t->getDisplay();
+ }
+- else if(key == "cube_input")
++ if(strcmp(t->getCubeInput(), "") != 0)
+ {
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<std::string>(stringval))
+- t->setCubeInput(stringval.c_str());
++ out << YAML::Key << "cube_input";
++ out << YAML::Value << YAML::Flow << t->getCubeInput();
+ }
+- else if(key == "direction")
++
++ EmitBaseTransformKeyValues(out, t);
++
++ out << YAML::EndMap;
++ }
++
++ // Transform
++
++ void load(const YAML::Node& node, TransformRcPtr& t)
++ {
++ if(node.Type() != YAML::NodeType::Map)
+ {
+- TransformDirection val;
+- if (iter.second().Type() != YAML::NodeType::Null &&
+- iter.second().Read<TransformDirection>(val))
+- t->setDirection(val);
++ std::ostringstream os;
++ os << "Unsupported Transform type encountered: (" << node.Type() << ") in OCIO profile. ";
++ os << "Only Mapping types supported.";
++ throw Exception(os.str().c_str());
++ }
++
++ std::string type = node.Tag();
++
++ if(type == "AllocationTransform") {
++ AllocationTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "CDLTransform") {
++ CDLTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "ColorSpaceTransform") {
++ ColorSpaceTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ // TODO: DisplayTransform
++ else if(type == "ExponentTransform") {
++ ExponentTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "FileTransform") {
++ FileTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "GroupTransform") {
++ GroupTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "LogTransform") {
++ LogTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "LookTransform") {
++ LookTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "MatrixTransform") {
++ MatrixTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
++ }
++ else if(type == "TruelightTransform") {
++ TruelightTransformRcPtr temp;
++ load(node, temp);
++ t = temp;
+ }
+ else
+ {
+- LogUnknownKeyWarning(node.Tag(), iter.first());
++ // TODO: add a new empty (better name?) aka passthru Transform()
++ // which does nothing. This is so upsupported !<tag> types don't
++ // throw an exception. Alternativly this could be caught in the
++ // GroupTransformRcPtr >> operator with some type of
++ // supported_tag() method
++
++ // TODO: consider the forwards-compatibility implication of
++ // throwing an exception. Should this be a warning, instead?
++
++ // t = EmptyTransformRcPtr(new EmptyTransform(), &deleter);
++ std::ostringstream os;
++ os << "Unsupported transform type !<" << type << "> in OCIO profile. ";
++ throw Exception(os.str().c_str());
+ }
+ }
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ConstTruelightTransformRcPtr t)
+- {
+
+- out << YAML::VerbatimTag("TruelightTransform");
+- out << YAML::Flow << YAML::BeginMap;
+- if(strcmp(t->getConfigRoot(), "") != 0)
+- {
+- out << YAML::Key << "config_root";
+- out << YAML::Value << YAML::Flow << t->getConfigRoot();
+- }
+- if(strcmp(t->getProfile(), "") != 0)
++ void save(YAML::Emitter& out, ConstTransformRcPtr t)
+ {
+- out << YAML::Key << "profile";
+- out << YAML::Value << YAML::Flow << t->getProfile();
+- }
+- if(strcmp(t->getCamera(), "") != 0)
+- {
+- out << YAML::Key << "camera";
+- out << YAML::Value << YAML::Flow << t->getCamera();
+- }
+- if(strcmp(t->getInputDisplay(), "") != 0)
+- {
+- out << YAML::Key << "input_display";
+- out << YAML::Value << YAML::Flow << t->getInputDisplay();
++ if(ConstAllocationTransformRcPtr Allocation_tran = \
++ DynamicPtrCast<const AllocationTransform>(t))
++ save(out, Allocation_tran);
++ else if(ConstCDLTransformRcPtr CDL_tran = \
++ DynamicPtrCast<const CDLTransform>(t))
++ save(out, CDL_tran);
++ else if(ConstColorSpaceTransformRcPtr ColorSpace_tran = \
++ DynamicPtrCast<const ColorSpaceTransform>(t))
++ save(out, ColorSpace_tran);
++ else if(ConstExponentTransformRcPtr Exponent_tran = \
++ DynamicPtrCast<const ExponentTransform>(t))
++ save(out, Exponent_tran);
++ else if(ConstFileTransformRcPtr File_tran = \
++ DynamicPtrCast<const FileTransform>(t))
++ save(out, File_tran);
++ else if(ConstGroupTransformRcPtr Group_tran = \
++ DynamicPtrCast<const GroupTransform>(t))
++ save(out, Group_tran);
++ else if(ConstLogTransformRcPtr Log_tran = \
++ DynamicPtrCast<const LogTransform>(t))
++ save(out, Log_tran);
++ else if(ConstLookTransformRcPtr Look_tran = \
++ DynamicPtrCast<const LookTransform>(t))
++ save(out, Look_tran);
++ else if(ConstMatrixTransformRcPtr Matrix_tran = \
++ DynamicPtrCast<const MatrixTransform>(t))
++ save(out, Matrix_tran);
++ else if(ConstTruelightTransformRcPtr Truelight_tran = \
++ DynamicPtrCast<const TruelightTransform>(t))
++ save(out, Truelight_tran);
++ else
++ throw Exception("Unsupported Transform() type for serialization.");
+ }
+- if(strcmp(t->getRecorder(), "") != 0)
++
++ // ColorSpace
++
++ inline void load(const YAML::Node& node, ColorSpaceRcPtr& cs)
+ {
+- out << YAML::Key << "recorder";
+- out << YAML::Value << YAML::Flow << t->getRecorder();
++ if(node.Tag() != "ColorSpace")
++ return; // not a !<ColorSpace> tag
++
++ std::string key, stringval;
++ bool boolval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "name")
++ {
++ load(second, stringval);
++ cs->setName(stringval.c_str());
++ }
++ else if(key == "description")
++ {
++ load(second, stringval);
++ cs->setDescription(stringval.c_str());
++ }
++ else if(key == "family")
++ {
++ load(second, stringval);
++ cs->setFamily(stringval.c_str());
++ }
++ else if(key == "equalitygroup")
++ {
++ load(second, stringval);
++ cs->setEqualityGroup(stringval.c_str());
++ }
++ else if(key == "bitdepth")
++ {
++ BitDepth ret;
++ load(second, ret);
++ cs->setBitDepth(ret);
++ }
++ else if(key == "isdata")
++ {
++ load(second, boolval);
++ cs->setIsData(boolval);
++ }
++ else if(key == "allocation")
++ {
++ Allocation val;
++ load(second, val);
++ cs->setAllocation(val);
++ }
++ else if(key == "allocationvars")
++ {
++ std::vector<float> val;
++ load(second, val);
++ if(!val.empty())
++ cs->setAllocationVars(static_cast<int>(val.size()), &val[0]);
++ }
++ else if(key == "to_reference")
++ {
++ TransformRcPtr val;
++ load(second, val);
++ cs->setTransform(val, COLORSPACE_DIR_TO_REFERENCE);
++ }
++ else if(key == "from_reference")
++ {
++ TransformRcPtr val;
++ load(second, val);
++ cs->setTransform(val, COLORSPACE_DIR_FROM_REFERENCE);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
+ }
+- if(strcmp(t->getPrint(), "") != 0)
++
++ inline void save(YAML::Emitter& out, ConstColorSpaceRcPtr cs)
+ {
+- out << YAML::Key << "print";
+- out << YAML::Value << YAML::Flow << t->getPrint();
++ out << YAML::VerbatimTag("ColorSpace");
++ out << YAML::BeginMap;
++
++ out << YAML::Key << "name" << YAML::Value << cs->getName();
++ out << YAML::Key << "family" << YAML::Value << cs->getFamily();
++ out << YAML::Key << "equalitygroup" << YAML::Value << cs->getEqualityGroup();
++ out << YAML::Key << "bitdepth" << YAML::Value;
++ save(out, cs->getBitDepth());
++ if(cs->getDescription() != NULL && strlen(cs->getDescription()) > 0)
++ {
++ out << YAML::Key << "description";
++ out << YAML::Value << YAML::Literal << cs->getDescription();
++ }
++ out << YAML::Key << "isdata" << YAML::Value << cs->isData();
++
++ out << YAML::Key << "allocation" << YAML::Value;
++ save(out, cs->getAllocation());
++ if(cs->getAllocationNumVars() > 0)
++ {
++ std::vector<float> allocationvars(cs->getAllocationNumVars());
++ cs->getAllocationVars(&allocationvars[0]);
++ out << YAML::Key << "allocationvars";
++ out << YAML::Flow << YAML::Value << allocationvars;
++ }
++
++ ConstTransformRcPtr toref = \
++ cs->getTransform(COLORSPACE_DIR_TO_REFERENCE);
++ if(toref)
++ {
++ out << YAML::Key << "to_reference" << YAML::Value;
++ save(out, toref);
++ }
++
++ ConstTransformRcPtr fromref = \
++ cs->getTransform(COLORSPACE_DIR_FROM_REFERENCE);
++ if(fromref)
++ {
++ out << YAML::Key << "from_reference" << YAML::Value;
++ save(out, fromref);
++ }
++
++ out << YAML::EndMap;
++ out << YAML::Newline;
+ }
+- if(strcmp(t->getLamp(), "") != 0)
++
++ // Look
++
++ inline void load(const YAML::Node& node, LookRcPtr& look)
+ {
+- out << YAML::Key << "lamp";
+- out << YAML::Value << YAML::Flow << t->getLamp();
++ if(node.Tag() != "Look")
++ return;
++
++ std::string key, stringval;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "name")
++ {
++ load(second, stringval);
++ look->setName(stringval.c_str());
++ }
++ else if(key == "process_space")
++ {
++ load(second, stringval);
++ look->setProcessSpace(stringval.c_str());
++ }
++ else if(key == "transform")
++ {
++ TransformRcPtr val;
++ load(second, val);
++ look->setTransform(val);
++ }
++ else if(key == "inverse_transform")
++ {
++ TransformRcPtr val;
++ load(second, val);
++ look->setInverseTransform(val);
++ }
++ else
++ {
++ LogUnknownKeyWarning(node.Tag(), first);
++ }
++ }
+ }
+- if(strcmp(t->getOutputCamera(), "") != 0)
++
++ inline void save(YAML::Emitter& out, ConstLookRcPtr look)
+ {
+- out << YAML::Key << "output_camera";
+- out << YAML::Value << YAML::Flow << t->getOutputCamera();
++ out << YAML::VerbatimTag("Look");
++ out << YAML::BeginMap;
++ out << YAML::Key << "name" << YAML::Value << look->getName();
++ out << YAML::Key << "process_space" << YAML::Value << look->getProcessSpace();
++
++ if(look->getTransform())
++ {
++ out << YAML::Key << "transform";
++ out << YAML::Value;
++ save(out, look->getTransform());
++ }
++
++ if(look->getInverseTransform())
++ {
++ out << YAML::Key << "inverse_transform";
++ out << YAML::Value;
++ save(out, look->getInverseTransform());
++ }
++
++ out << YAML::EndMap;
++ out << YAML::Newline;
+ }
+- if(strcmp(t->getDisplay(), "") != 0)
++
++ // Config
++
++ inline void load(const YAML::Node& node, ConfigRcPtr& c, const char* filename)
+ {
+- out << YAML::Key << "display";
+- out << YAML::Value << YAML::Flow << t->getDisplay();
++
++ // check profile version
++ int profile_version = 0;
++#ifdef OLDYAML
++ if(node.FindValue("ocio_profile_version") == NULL)
++#else
++ if(node["ocio_profile_version"] == NULL)
++#endif
++ {
++ std::ostringstream os;
++ os << "The specified file ";
++ os << "does not appear to be an OCIO configuration.";
++ throw Exception (os.str().c_str());
++ }
++
++ load(node["ocio_profile_version"], profile_version);
++ if(profile_version > 1)
++ {
++ std::ostringstream os;
++ os << "This .ocio config ";
++ if(filename && *filename)
++ {
++ os << " '" << filename << "' ";
++ }
++ os << "is version " << profile_version << ". ";
++ os << "This version of the OpenColorIO library (" << OCIO_VERSION ") ";
++ os << "is not known to be able to load this profile. ";
++ os << "An attempt will be made, but there are no guarantees that the ";
++ os << "results will be accurate. Continue at your own risk.";
++ LogWarning(os.str());
++ }
++
++ std::string key, stringval;
++ bool boolval = false;
++ EnvironmentMode mode = ENV_ENVIRONMENT_LOAD_ALL;
++
++ for (Iterator iter = node.begin();
++ iter != node.end();
++ ++iter)
++ {
++ const YAML::Node& first = get_first(iter);
++ const YAML::Node& second = get_second(iter);
++
++ load(first, key);
++
++ if (second.Type() == YAML::NodeType::Null) continue;
++
++ if(key == "ocio_profile_version") { } // Already handled above.
++ else if(key == "environment")
++ {
++ mode = ENV_ENVIRONMENT_LOAD_PREDEFINED;
++ if(second.Type() != YAML::NodeType::Map)
++ {
++ std::ostringstream os;
++ os << "'environment' field needs to be a (name: key) map.";
++ throw Exception(os.str().c_str());
++ }
++ for (Iterator it = second.begin();
++ it != second.end();
++ ++it)
++ {
++ std::string k, v;
++ load(get_first(it), k);
++ load(get_second(it), v);
++ c->addEnvironmentVar(k.c_str(), v.c_str());
++ }
++ }
++ else if(key == "search_path" || key == "resource_path")
++ {
++ load(second, stringval);
++ c->setSearchPath(stringval.c_str());
++ }
++ else if(key == "strictparsing")
++ {
++ load(second, boolval);
++ c->setStrictParsingEnabled(boolval);
++ }
++ else if(key == "description")
++ {
++ load(second, stringval);
++ c->setDescription(stringval.c_str());
++ }
++ else if(key == "luma")
++ {
++ std::vector<float> val;
++ load(second, val);
++ if(val.size() != 3)
++ {
++ std::ostringstream os;
++ os << "'luma' field must be 3 ";
++ os << "floats. Found '" << val.size() << "'.";
++ throw Exception(os.str().c_str());
++ }
++ c->setDefaultLumaCoefs(&val[0]);
++ }
++ else if(key == "roles")
++ {
++ if(second.Type() != YAML::NodeType::Map)
++ {
++ std::ostringstream os;
++ os << "'roles' field needs to be a (name: key) map.";
++ throw Exception(os.str().c_str());
++ }
++ for (Iterator it = second.begin();
++ it != second.end();
++ ++it)
++ {
++ std::string k, v;
++ load(get_first(it), k);
++ load(get_second(it), v);
++ c->setRole(k.c_str(), v.c_str());
++ }
++ }
++ else if(key == "displays")
++ {
++ if(second.Type() != YAML::NodeType::Map)
++ {
++ std::ostringstream os;
++ os << "'displays' field needs to be a (name: key) map.";
++ throw Exception(os.str().c_str());
++ }
++ for (Iterator it = second.begin();
++ it != second.end();
++ ++it)
++ {
++ std::string display;
++ load(get_first(it), display);
++ const YAML::Node& dsecond = get_second(it);
++ for(unsigned i = 0; i < dsecond.size(); ++i)
++ {
++ View view;
++ load(dsecond[i], view);
++ c->addDisplay(display.c_str(), view.name.c_str(),
++ view.colorspace.c_str(), view.looks.c_str());
++ }
++ }
++ }
++ else if(key == "active_displays")
++ {
++ std::vector<std::string> display;
++ load(second, display);
++ const char* displays = JoinStringEnvStyle(display).c_str();
++ c->setActiveDisplays(displays);
++ }
++ else if(key == "active_views")
++ {
++ std::vector<std::string> view;
++ load(second, view);
++ const char* views = JoinStringEnvStyle(view).c_str();
++ c->setActiveViews(views);
++ }
++ else if(key == "colorspaces")
++ {
++ if(second.Type() != YAML::NodeType::Sequence)
++ {
++ std::ostringstream os;
++ os << "'colorspaces' field needs to be a (- !<ColorSpace>) list.";
++ throw Exception(os.str().c_str());
++ }
++ for(unsigned i = 0; i < second.size(); ++i)
++ {
++ if(second[i].Tag() == "ColorSpace")
++ {
++ ColorSpaceRcPtr cs = ColorSpace::Create();
++ load(second[i], cs);
++ for(int ii = 0; ii < c->getNumColorSpaces(); ++ii)
++ {
++ if(strcmp(c->getColorSpaceNameByIndex(ii), cs->getName()) == 0)
++ {
++ std::ostringstream os;
++ os << "Colorspace with name '" << cs->getName() << "' already defined.";
++ throw Exception(os.str().c_str());
++ }
++ }
++ c->addColorSpace(cs);
++ }
++ else
++ {
++ std::ostringstream os;
++ os << "Unknown element found in colorspaces:";
++ os << second[i].Tag() << ". Only ColorSpace(s)";
++ os << " currently handled.";
++ LogWarning(os.str());
++ }
++ }
++ }
++ else if(key == "looks")
++ {
++ if(second.Type() != YAML::NodeType::Sequence)
++ {
++ std::ostringstream os;
++ os << "'looks' field needs to be a (- !<Look>) list.";
++ throw Exception(os.str().c_str());
++ }
++
++ for(unsigned i = 0; i < second.size(); ++i)
++ {
++ if(second[i].Tag() == "Look")
++ {
++ LookRcPtr look = Look::Create();
++ load(second[i], look);
++ c->addLook(look);
++ }
++ else
++ {
++ std::ostringstream os;
++ os << "Unknown element found in looks:";
++ os << second[i].Tag() << ". Only Look(s)";
++ os << " currently handled.";
++ LogWarning(os.str());
++ }
++ }
++ }
++ else
++ {
++ LogUnknownKeyWarning("profile", first);
++ }
++ }
++
++ if(filename)
++ {
++ std::string realfilename = pystring::os::path::abspath(filename);
++ std::string configrootdir = pystring::os::path::dirname(realfilename);
++ c->setWorkingDir(configrootdir.c_str());
++ }
++
++ c->setEnvironmentMode(mode);
++ c->loadEnvironment();
++
++ if(mode == ENV_ENVIRONMENT_LOAD_ALL)
++ {
++ std::ostringstream os;
++ os << "This .ocio config ";
++ if(filename && *filename)
++ {
++ os << " '" << filename << "' ";
++ }
++ os << "has no environment section defined. The default behaviour is to ";
++ os << "load all environment variables (" << c->getNumEnvironmentVars() << ")";
++ os << ", which reduces the efficiency of OCIO's caching. Considering ";
++ os << "predefining the environment variables used.";
++ LogDebug(os.str());
++ }
++
+ }
+- if(strcmp(t->getCubeInput(), "") != 0)
++
++ inline void save(YAML::Emitter& out, const Config* c)
+ {
+- out << YAML::Key << "cube_input";
+- out << YAML::Value << YAML::Flow << t->getCubeInput();
++ out << YAML::Block;
++ out << YAML::BeginMap;
++ out << YAML::Key << "ocio_profile_version" << YAML::Value << 1;
++ out << YAML::Newline;
++#ifndef OLDYAML
++ out << YAML::Newline;
++#endif
++
++ if(c->getNumEnvironmentVars() > 0)
++ {
++ out << YAML::Key << "environment";
++ out << YAML::Value << YAML::BeginMap;
++ for(unsigned i = 0; i < c->getNumEnvironmentVars(); ++i)
++ {
++ const char* name = c->getEnvironmentVarNameByIndex(i);
++ out << YAML::Key << name;
++ out << YAML::Value << c->getEnvironmentVarDefault(name);
++ }
++ out << YAML::EndMap;
++ out << YAML::Newline;
++ }
++ out << YAML::Key << "search_path" << YAML::Value << c->getSearchPath();
++ out << YAML::Key << "strictparsing" << YAML::Value << c->isStrictParsingEnabled();
++
++ std::vector<float> luma(3, 0.f);
++ c->getDefaultLumaCoefs(&luma[0]);
++ out << YAML::Key << "luma" << YAML::Value << YAML::Flow << luma;
++
++ if(c->getDescription() != NULL && strlen(c->getDescription()) > 0)
++ {
++ out << YAML::Newline;
++ out << YAML::Key << "description";
++ out << YAML::Value << c->getDescription();
++ out << YAML::Newline;
++ }
++
++ // Roles
++ out << YAML::Newline;
++#ifndef OLDYAML
++ out << YAML::Newline;
++#endif
++ out << YAML::Key << "roles";
++ out << YAML::Value << YAML::BeginMap;
++ for(unsigned i = 0; i < c->getNumRoles(); ++i)
++ {
++ const char* role = c->getRoleName(i);
++ out << YAML::Key << role;
++ out << YAML::Value << c->getColorSpace(role)->getName();
++ }
++ out << YAML::EndMap;
++#ifndef OLDYAML
++ out << YAML::Newline;
++#endif
++
++ // Displays
++ out << YAML::Newline;
++ out << YAML::Key << "displays";
++ out << YAML::Value << YAML::BeginMap;
++ for(unsigned i = 0; i < c->getNumDisplays(); ++i)
++ {
++ const char* display = c->getDisplay(i);
++ out << YAML::Key << display;
++ out << YAML::Value << YAML::BeginSeq;
++ for(unsigned v = 0; v < c->getNumViews(display); ++v)
++ {
++ View dview;
++ dview.name = c->getView(display, v);
++ dview.colorspace = c->getDisplayColorSpaceName(display, dview.name.c_str());
++ if(c->getDisplayLooks(display, dview.name.c_str()) != NULL)
++ dview.looks = c->getDisplayLooks(display, dview.name.c_str());
++ save(out, dview);
++
++ }
++ out << YAML::EndSeq;
++ }
++ out << YAML::EndMap;
++
++#ifndef OLDYAML
++ out << YAML::Newline;
++#endif
++ out << YAML::Newline;
++ out << YAML::Key << "active_displays";
++ std::vector<std::string> active_displays;
++ if(c->getActiveDisplays() != NULL && strlen(c->getActiveDisplays()) > 0)
++ SplitStringEnvStyle(active_displays, c->getActiveDisplays());
++ out << YAML::Value << YAML::Flow << active_displays;
++ out << YAML::Key << "active_views";
++ std::vector<std::string> active_views;
++ if(c->getActiveViews() != NULL && strlen(c->getActiveViews()) > 0)
++ SplitStringEnvStyle(active_views, c->getActiveViews());
++ out << YAML::Value << YAML::Flow << active_views;
++#ifndef OLDYAML
++ out << YAML::Newline;
++#endif
++
++ // Looks
++ if(c->getNumLooks() > 0)
++ {
++ out << YAML::Newline;
++ out << YAML::Key << "looks";
++ out << YAML::Value << YAML::BeginSeq;
++ for(unsigned i = 0; i < c->getNumLooks(); ++i)
++ {
++ const char* name = c->getLookNameByIndex(i);
++ save(out, c->getLook(name));
++ }
++ out << YAML::EndSeq;
++ out << YAML::Newline;
++ }
++
++ // ColorSpaces
++ {
++ out << YAML::Newline;
++ out << YAML::Key << "colorspaces";
++ out << YAML::Value << YAML::BeginSeq;
++ for(unsigned i = 0; i < c->getNumColorSpaces(); ++i)
++ {
++ const char* name = c->getColorSpaceNameByIndex(i);
++ save(out, c->getColorSpace(name));
++ }
++ out << YAML::EndSeq;
++ }
++
++ out << YAML::EndMap;
+ }
+
+- EmitBaseTransformKeyValues(out, t);
+-
+- out << YAML::EndMap;
+- return out;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+- // Enums
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, BitDepth depth) {
+- out << BitDepthToString(depth);
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, BitDepth& depth) {
+- std::string str;
+- node.Read<std::string>(str);
+- depth = BitDepthFromString(str.c_str());
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, Allocation alloc) {
+- out << AllocationToString(alloc);
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, Allocation& alloc) {
+- std::string str;
+- node.Read<std::string>(str);
+- alloc = AllocationFromString(str.c_str());
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceDirection dir) {
+- out << ColorSpaceDirectionToString(dir);
+- return out;
+- }
+
+- void operator >> (const YAML::Node& node, ColorSpaceDirection& dir) {
+- std::string str;
+- node.Read<std::string>(str);
+- dir = ColorSpaceDirectionFromString(str.c_str());
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, TransformDirection dir) {
+- out << TransformDirectionToString(dir);
+- return out;
+- }
+-
+- void operator >> (const YAML::Node& node, TransformDirection& dir) {
+- std::string str;
+- node.Read<std::string>(str);
+- dir = TransformDirectionFromString(str.c_str());
+- }
+-
+- YAML::Emitter& operator << (YAML::Emitter& out, Interpolation interp) {
+- out << InterpolationToString(interp);
+- return out;
++ void OCIOYaml::open(std::istream& istream, ConfigRcPtr& c, const char* filename) const
++ {
++ try
++ {
++#ifdef OLDYAML
++ YAML::Parser parser(istream);
++ YAML::Node node;
++ parser.GetNextDocument(node);
++#else
++ YAML::Node node = YAML::Load(istream);
++#endif
++ load(node, c, filename);
++ }
++ catch(const std::exception & e)
++ {
++ std::ostringstream os;
++ os << "Error: Loading the OCIO profile ";
++ if(filename) os << "'" << filename << "' ";
++ os << "failed. " << e.what();
++ throw Exception(os.str().c_str());
++ }
+ }
+
+- void operator >> (const YAML::Node& node, Interpolation& interp) {
+- std::string str;
+- node.Read<std::string>(str);
+- interp = InterpolationFromString(str.c_str());
++ void OCIOYaml::write(std::ostream& ostream, const Config* c) const
++ {
++ YAML::Emitter out;
++ save(out, c);
++ ostream << out.c_str();
+ }
+
+ }
+diff --git a/src/core/OCIOYaml.h b/src/core/OCIOYaml.h
+index 7104123..364a262 100644
+--- a/src/core/OCIOYaml.h
++++ b/src/core/OCIOYaml.h
+@@ -28,97 +28,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ #include <OpenColorIO/OpenColorIO.h>
+
+-#include "Platform.h"
+-
+-#ifndef WINDOWS
+-
+-// fwd declare yaml-cpp visibility
+-#pragma GCC visibility push(hidden)
+-namespace YAML {
+- class Exception;
+- class BadDereference;
+- class RepresentationException;
+- class EmitterException;
+- class ParserException;
+- class InvalidScalar;
+- class KeyNotFound;
+- template <typename T> class TypedKeyNotFound;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::ColorSpace>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::Config>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::Exception>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::GpuShaderDesc>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::ImageDesc>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::Look>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::Processor>;
+-
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::Transform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::AllocationTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::CDLTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::ColorSpaceTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::DisplayTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::ExponentTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::FileTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::GroupTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::LogTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::LookTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::MatrixTransform>;
+- template <> class TypedKeyNotFound<OCIO_NAMESPACE::TruelightTransform>;
+-}
+-#pragma GCC visibility pop
+-
+-#endif
+-
+-#include <yaml-cpp/yaml.h>
+-
+ #ifndef INCLUDED_OCIO_YAML_H
+ #define INCLUDED_OCIO_YAML_H
+
+ OCIO_NAMESPACE_ENTER
+ {
+
+- // Core
+- OCIOHIDDEN void operator >> (const YAML::Node& node, ColorSpaceRcPtr& cs);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceRcPtr cs);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, GroupTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstGroupTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, TransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, LookRcPtr& cs);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, LookRcPtr cs);
+-
+- // Transforms
+- OCIOHIDDEN void operator >> (const YAML::Node& node, AllocationTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstAllocationTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, CDLTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstCDLTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, ColorSpaceTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstColorSpaceTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, ExponentTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstExponentTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, FileTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstFileTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, LogTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstLogTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, LookTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstLookTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, MatrixTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstMatrixTransformRcPtr t);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, TruelightTransformRcPtr& t);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ConstTruelightTransformRcPtr t);
+-
+- // Enums
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, BitDepth depth);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, BitDepth& depth);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, Allocation alloc);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, Allocation& alloc);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, ColorSpaceDirection dir);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, ColorSpaceDirection& dir);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, TransformDirection dir);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, TransformDirection& dir);
+- OCIOHIDDEN YAML::Emitter& operator << (YAML::Emitter& out, Interpolation iterp);
+- OCIOHIDDEN void operator >> (const YAML::Node& node, Interpolation& iterp);
++ class OCIOYaml
++ {
++ public:
++ void open(std::istream& istream, ConfigRcPtr& c, const char* filename = NULL) const;
++ void write(std::ostream& ostream, const Config* c) const;
++ };
+
+- void LogUnknownKeyWarning(const std::string & name, const YAML::Node& tag);
+ }
+ OCIO_NAMESPACE_EXIT
+