@@ -241,55 +241,66 @@ void ColorSpace::setInteropID(const char * interopID)
241241
242242 if (!id.empty ())
243243 {
244- // Count the number of ':' characters in the string
245- // and check for non-ASCII characters
246- size_t colonCount = 0 ;
247- size_t lastColonPos = std::string::npos;
248-
249- for (size_t i = 0 ; i < id.length (); ++i)
244+ // check if it only uses ASCII characters: 0-9, a-z, and the following characters (no spaces):
245+ // - _ ~ / * # % ^ + ( ) [ ] |
246+ auto allowed = [](char c)
247+ {
248+ return (c >= ' 0' && c <= ' 9' )||
249+ (c >= ' a' && c <= ' z' )||
250+ c==' .' ||c==' -' ||c==' _' ||c==' ~' ||c==' /' ||c==' *' ||c==' #' ||c==' %' ||
251+ c==' ^' ||c==' +' ||c==' (' ||c==' )' ||c==' [' ||c==' ]' ||c==' |' ||c==' :' ;
252+ };
253+
254+ if (!std::all_of (id.begin (), id.end (), allowed))
250255 {
251- if (id[i] == ' :' )
256+ std::ostringstream oss;
257+ oss << " InteropID '" << id << " ' contains invalid characters. "
258+ " Only lowercase a-z, 0-9 and . - _ ~ / * # % ^ + ( ) [ ] | are allowed." <<
259+ std::endl;
260+ throw Exception (oss.str ().c_str ());
261+ }
262+
263+ // Check if has a namespace.
264+ size_t pos = id.find (' :' );
265+ if (pos != std::string::npos)
266+ {
267+ // Namespace found, split into namespace and color space.
268+ std::string ns = id.substr (0 , pos);
269+ std::string cs = id.substr (pos+1 );
270+
271+ // both should be non-empty
272+ if (ns.empty () || cs.empty ())
252273 {
253- colonCount++;
254- lastColonPos = i;
274+ std::ostringstream oss;
275+ oss << " InteropID '" << id << " ' is not valid. "
276+ " If ':' is used, both the namespace and the color space parts must be non-empty." <<
277+ std::endl;
278+ throw Exception (oss.str ().c_str ());
255279 }
256- else if (static_cast <unsigned char >(id[i]) >= 0x80 )
280+
281+ // More than one ':' is an error.
282+ if (cs.find (' :' ) != std::string::npos)
257283 {
258284 std::ostringstream oss;
259- oss << " InteropID '" << id << " ' is invalid: only ASCII characters [0x00..0x7F] are allowed." ;
285+ oss << " ERROR: InteropID '" << id << " ' is not valid. "
286+ " Only one ':' is allowed to separate the namespace and the color space." <<
287+ std::endl;
260288 throw Exception (oss.str ().c_str ());
261289 }
262290 }
263-
264- // Validate: only zero or one ':' character allowed
265- if (colonCount > 1 )
266- {
267- std::ostringstream oss;
268- oss << " InteropID '" << id << " ' is invalid: only zero or one ':' character is allowed." ;
269- throw Exception (oss.str ().c_str ());
270- }
271-
272- // Validate: ':' cannot be the last character
273- if (colonCount == 1 && lastColonPos == id.length () - 1 )
274- {
275- std::ostringstream oss;
276- oss << " InteropID '" << id << " ' is invalid: ':' character cannot be the last character." ;
277- throw Exception (oss.str ().c_str ());
278- }
279-
280- // TODO: Do we want to verify the interopID against the CIF list here?
281291 }
282292
283293 getImpl ()->m_interopID = id;
284294}
285295
286296const char * ColorSpace::getInterchangeAttribute (const char * attrName) const
287297{
288- std::string nameTrimmed = StringUtils::Trim (attrName);
298+ std::string name = attrName ? attrName : " " ;
299+
289300 for (auto & key : knownInterchangeNames)
290301 {
291302 // do case-insensitive comparison.
292- if (StringUtils::Compare (key, nameTrimmed ))
303+ if (StringUtils::Compare (key, name ))
293304 {
294305 auto it = m_impl->m_interchangeAttribs .find (key);
295306 if (it != m_impl->m_interchangeAttribs .end ())
@@ -301,19 +312,20 @@ const char * ColorSpace::getInterchangeAttribute(const char* attrName) const
301312 }
302313
303314 std::ostringstream oss;
304- oss << " Unknown attribute name '" << attrName << " '." ;
315+ oss << " Unknown attribute name '" << name << " '." ;
305316 throw Exception (oss.str ().c_str ());
306317}
307318
308319void ColorSpace::setInterchangeAttribute (const char * attrName, const char * value)
309320{
310- std::string nameTrimmed = StringUtils::Trim (attrName);
321+ std::string name = attrName ? attrName : " " ;
322+
311323 for (auto & key : knownInterchangeNames)
312324 {
313325 // Do case-insensitive comparison.
314- if (StringUtils::Compare (key, nameTrimmed ))
326+ if (StringUtils::Compare (key, name ))
315327 {
316- // use key instead of nameTrim for storing in correct capitalization.
328+ // use key instead of name for storing in correct capitalization.
317329 if (!value || !*value)
318330 {
319331 m_impl->m_interchangeAttribs .erase (key);
@@ -327,7 +339,7 @@ void ColorSpace::setInterchangeAttribute(const char* attrName, const char* value
327339 }
328340
329341 std::ostringstream oss;
330- oss << " Unknown attribute name '" << attrName << " '." ;
342+ oss << " Unknown attribute name '" << name << " '." ;
331343 throw Exception (oss.str ().c_str ());
332344}
333345
@@ -336,7 +348,7 @@ std::map<std::string, std::string> ColorSpace::getInterchangeAttributes() const
336348 return m_impl->m_interchangeAttribs ;
337349}
338350
339- BitDepth ColorSpace::ColorSpace:: getBitDepth () const noexcept
351+ BitDepth ColorSpace::getBitDepth () const noexcept
340352{
341353 return getImpl ()->m_bitDepth ;
342354}
@@ -555,7 +567,6 @@ std::ostream & operator<< (std::ostream & os, const ColorSpace & cs)
555567 {
556568 os << " , description=" << str;
557569 }
558- // TODO: Do we need to output the section name too?
559570 for (const auto & attr : cs.getInterchangeAttributes ())
560571 {
561572 os << " , " << attr.first << " =" << attr.second ;
0 commit comments