1 /* 2 Copyright (c) 2014 Cinesite VFX Ltd, et al. 3 All Rights Reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are 7 met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of Sony Pictures Imageworks nor the names of its 14 contributors may be used to endorse or promote products derived from 15 this software without specific prior written permission. 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <map> 30 #include <tinyxml.h> 31 32 #include <OpenColorIO/OpenColorIO.h> 33 34 #include "CDLTransform.h" 35 #include "FileTransform.h" 36 #include "OpBuilders.h" 37 #include "ParseUtils.h" 38 #include "pystring/pystring.h" 39 40 OCIO_NAMESPACE_ENTER 41 { 42 //////////////////////////////////////////////////////////////// 43 44 namespace 45 { 46 class LocalCachedFile : public CachedFile 47 { 48 public: 49 LocalCachedFile () {}; 50 ~LocalCachedFile() {}; 51 52 CDLTransformMap transformMap; 53 CDLTransformVec transformVec; 54 }; 55 56 typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr; 57 typedef OCIO_SHARED_PTR<TiXmlDocument> TiXmlDocumentRcPtr; 58 59 60 61 class LocalFileFormat : public FileFormat 62 { 63 public: 64 65 ~LocalFileFormat() {}; 66 67 virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const; 68 69 virtual CachedFileRcPtr Read(std::istream & istream) const; 70 71 virtual void BuildFileOps(OpRcPtrVec & ops, 72 const Config& config, 73 const ConstContextRcPtr & context, 74 CachedFileRcPtr untypedCachedFile, 75 const FileTransform& fileTransform, 76 TransformDirection dir) const; 77 }; 78 79 void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const 80 { 81 FormatInfo info; 82 info.name = "ColorDecisionList"; 83 info.extension = "cdl"; 84 info.capabilities = FORMAT_CAPABILITY_READ; 85 formatInfoVec.push_back(info); 86 } 87 88 // Try and load the format 89 // Raise an exception if it can't be loaded. 90 91 CachedFileRcPtr LocalFileFormat::Read(std::istream & istream) const 92 { 93 std::ostringstream rawdata; 94 rawdata << istream.rdbuf(); 95 96 LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile()); 97 98 TiXmlDocumentRcPtr doc = TiXmlDocumentRcPtr(new TiXmlDocument()); 99 doc->Parse(rawdata.str().c_str()); 100 101 if(doc->Error()) 102 { 103 std::ostringstream os; 104 os << "XML Parse Error. "; 105 os << doc->ErrorDesc() << " (line "; 106 os << doc->ErrorRow() << ", character "; 107 os << doc->ErrorCol() << ")"; 108 throw Exception(os.str().c_str()); 109 } 110 111 TiXmlElement* rootElement = doc->RootElement(); 112 GetCDLTransforms(cachedFile->transformMap, 113 cachedFile->transformVec, 114 rootElement); 115 return cachedFile; 116 } 117 118 void 119 LocalFileFormat::BuildFileOps(OpRcPtrVec & ops, 120 const Config& config, 121 const ConstContextRcPtr & context, 122 CachedFileRcPtr untypedCachedFile, 123 const FileTransform& fileTransform, 124 TransformDirection dir) const 125 { 126 LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile); 127 128 // This should never happen. 129 if(!cachedFile) 130 { 131 std::ostringstream os; 132 os << "Cannot build .cdl Op. Invalid cache type."; 133 throw Exception(os.str().c_str()); 134 } 135 136 TransformDirection newDir = CombineTransformDirections(dir, 137 fileTransform.getDirection()); 138 if(newDir == TRANSFORM_DIR_UNKNOWN) 139 { 140 std::ostringstream os; 141 os << "Cannot build ASC FileTransform,"; 142 os << " unspecified transform direction."; 143 throw Exception(os.str().c_str()); 144 } 145 146 // Below this point, we should throw ExceptionMissingFile on 147 // errors rather than Exception 148 // This is because we've verified that the cdl file is valid, 149 // at now we're only querying whether the specified cccid can 150 // be found. 151 // 152 // Using ExceptionMissingFile enables the missing looks fallback 153 // mechanism to function properly. 154 // At the time ExceptionMissingFile was named, we errently assumed 155 // a 1:1 relationship between files and color corrections, which is 156 // not true for .cdl files. 157 // 158 // In a future OCIO release, it may be more appropriate to 159 // rename ExceptionMissingFile -> ExceptionMissingCorrection. 160 // But either way, it's what we should throw below. 161 162 std::string cccid = fileTransform.getCCCId(); 163 cccid = context->resolveStringVar(cccid.c_str()); 164 165 if(cccid.empty()) 166 { 167 std::ostringstream os; 168 os << "You must specify which cccid to load from the ccc file"; 169 os << " (either by name or index)."; 170 throw ExceptionMissingFile(os.str().c_str()); 171 } 172 173 bool success=false; 174 175 // Try to parse the cccid as a string id 176 CDLTransformMap::const_iterator iter = cachedFile->transformMap.find(cccid); 177 if(iter != cachedFile->transformMap.end()) 178 { 179 success = true; 180 BuildCDLOps(ops, 181 config, 182 *(iter->second), 183 newDir); 184 } 185 186 // Try to parse the cccid as an integer index 187 // We want to be strict, so fail if leftover chars in the parse. 188 if(!success) 189 { 190 int cccindex=0; 191 if(StringToInt(&cccindex, cccid.c_str(), true)) 192 { 193 int maxindex = ((int)cachedFile->transformVec.size())-1; 194 if(cccindex<0 || cccindex>maxindex) 195 { 196 std::ostringstream os; 197 os << "The specified cccindex " << cccindex; 198 os << " is outside the valid range for this file [0,"; 199 os << maxindex << "]"; 200 throw ExceptionMissingFile(os.str().c_str()); 201 } 202 203 success = true; 204 BuildCDLOps(ops, 205 config, 206 *cachedFile->transformVec[cccindex], 207 newDir); 208 } 209 } 210 211 if(!success) 212 { 213 std::ostringstream os; 214 os << "You must specify a valid cccid to load from the ccc file"; 215 os << " (either by name or index). id='" << cccid << "' "; 216 os << "is not found in the file, and is not parsable as an "; 217 os << "integer index."; 218 throw ExceptionMissingFile(os.str().c_str()); 219 } 220 } 221 } 222 223 FileFormat * CreateFileFormatCDL() 224 { 225 return new LocalFileFormat(); 226 } 227 } 228 OCIO_NAMESPACE_EXIT 229 230