1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2010 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
30 // ----------------------------------------------------------------------------------
31 // Encoding & Decoding support functions
32 // ----------------------------------------------------------------------------------
34 // Little-Endian to Big-Endian
36 // Adjust a word value after being readed/ before being written from/to an ICC profile
37 cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)
39 #ifndef CMS_USE_BIG_ENDIAN
41 cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
53 // Transports to properly encoded values - note that icc profiles does use big endian notation.
58 cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)
60 #ifndef CMS_USE_BIG_ENDIAN
62 cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
79 void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord)
82 #ifndef CMS_USE_BIG_ENDIAN
84 cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord;
85 cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
87 _cmsAssert(Result != NULL);
100 _cmsAssert(Result != NULL);
106 // Auxiliar -- read 8, 16 and 32-bit numbers
107 cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
111 _cmsAssert(io != NULL);
113 if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
116 if (n != NULL) *n = tmp;
120 cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
124 _cmsAssert(io != NULL);
126 if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
129 if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
133 cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
137 _cmsAssert(io != NULL);
139 for (i=0; i < n; i++) {
142 if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
145 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
152 cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
156 _cmsAssert(io != NULL);
158 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
161 if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
165 cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
169 _cmsAssert(io != NULL);
171 if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
176 tmp = _cmsAdjustEndianess32(tmp);
177 *n = *(cmsFloat32Number*) &tmp;
183 cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
187 _cmsAssert(io != NULL);
189 if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
192 if (n != NULL) _cmsAdjustEndianess64(n, tmp);
197 cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
201 _cmsAssert(io != NULL);
203 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
207 *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
214 // Jun-21-2000: Some profiles (those that comes with W2K) comes
215 // with the media white (media black?) x 100. Add a sanity check
218 void NormalizeXYZ(cmsCIEXYZ* Dest)
220 while (Dest -> X > 2. &&
230 cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
232 cmsEncodedXYZNumber xyz;
234 _cmsAssert(io != NULL);
236 if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
240 XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
241 XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
242 XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
249 cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
251 _cmsAssert(io != NULL);
253 if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
259 cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
263 _cmsAssert(io != NULL);
265 tmp = _cmsAdjustEndianess16(n);
266 if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
272 cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
276 _cmsAssert(io != NULL);
277 _cmsAssert(Array != NULL);
279 for (i=0; i < n; i++) {
280 if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
286 cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
290 _cmsAssert(io != NULL);
292 tmp = _cmsAdjustEndianess32(n);
293 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
300 cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
304 _cmsAssert(io != NULL);
306 tmp = *(cmsUInt32Number*) &n;
307 tmp = _cmsAdjustEndianess32(tmp);
308 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
314 cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
318 _cmsAssert(io != NULL);
320 _cmsAdjustEndianess64(&tmp, n);
321 if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
327 cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
331 _cmsAssert(io != NULL);
333 tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
334 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
340 cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
342 cmsEncodedXYZNumber xyz;
344 _cmsAssert(io != NULL);
345 _cmsAssert(XYZ != NULL);
347 xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
348 xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
349 xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
351 return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
354 // from Fixed point 8.8 to double
355 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
357 cmsUInt8Number msb, lsb;
359 lsb = (cmsUInt8Number) (fixed8 & 0xff);
360 msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
362 return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
365 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
367 cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
368 return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
371 // from Fixed point 15.16 to double
372 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
374 cmsFloat64Number floater, sign, mid;
377 sign = (fix32 < 0 ? -1 : 1);
380 Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
381 FracPart = (cmsUInt16Number)(fix32 & 0xffff);
383 mid = (cmsFloat64Number) FracPart / 65536.0;
384 floater = (cmsFloat64Number) Whole + mid;
386 return sign * floater;
389 // from double to Fixed point 15.16
390 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
392 return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
395 // Date/Time functions
397 void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
400 _cmsAssert(Dest != NULL);
401 _cmsAssert(Source != NULL);
403 Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds);
404 Dest->tm_min = _cmsAdjustEndianess16(Source->minutes);
405 Dest->tm_hour = _cmsAdjustEndianess16(Source->hours);
406 Dest->tm_mday = _cmsAdjustEndianess16(Source->day);
407 Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1;
408 Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900;
414 void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
416 _cmsAssert(Dest != NULL);
417 _cmsAssert(Source != NULL);
419 Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
420 Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
421 Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
422 Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
423 Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
424 Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
427 // Read base and return type base
428 cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
432 _cmsAssert(io != NULL);
434 if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
435 return (cmsTagTypeSignature) 0;
437 return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
441 cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
445 _cmsAssert(io != NULL);
447 Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
448 memset(&Base.reserved, 0, sizeof(Base.reserved));
449 return io -> Write(io, sizeof(_cmsTagBase), &Base);
452 cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
454 cmsUInt8Number Buffer[4];
455 cmsUInt32Number NextAligned, At;
456 cmsUInt32Number BytesToNextAlignedPos;
458 _cmsAssert(io != NULL);
461 NextAligned = _cmsALIGNLONG(At);
462 BytesToNextAlignedPos = NextAligned - At;
463 if (BytesToNextAlignedPos == 0) return TRUE;
464 if (BytesToNextAlignedPos > 4) return FALSE;
466 return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
469 cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
471 cmsUInt8Number Buffer[4];
472 cmsUInt32Number NextAligned, At;
473 cmsUInt32Number BytesToNextAlignedPos;
475 _cmsAssert(io != NULL);
478 NextAligned = _cmsALIGNLONG(At);
479 BytesToNextAlignedPos = NextAligned - At;
480 if (BytesToNextAlignedPos == 0) return TRUE;
481 if (BytesToNextAlignedPos > 4) return FALSE;
483 memset(Buffer, 0, BytesToNextAlignedPos);
484 return io -> Write(io, BytesToNextAlignedPos, Buffer);
488 // To deal with text streams. 2K at most
489 cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
493 cmsUInt8Number Buffer[2048];
496 _cmsAssert(io != NULL);
497 _cmsAssert(frm != NULL);
501 len = vsnprintf((char*) Buffer, 2047, frm, args);
502 if (len < 0) return FALSE; // Truncated, which is a fatal error for us
504 rc = io ->Write(io, len, Buffer);
512 // Plugin memory management -------------------------------------------------------------------------------------------------
514 static _cmsSubAllocator* PluginPool = NULL;
516 // Specialized malloc for plug-ins, that is freed upon exit.
517 void* _cmsPluginMalloc(cmsUInt32Number size)
519 if (PluginPool == NULL)
520 PluginPool = _cmsCreateSubAlloc(0, 4*1024);
522 return _cmsSubAlloc(PluginPool, size);
526 // Main plug-in dispatcher
527 cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
529 cmsPluginBase* Plugin;
531 for (Plugin = (cmsPluginBase*) Plug_in;
533 Plugin = Plugin -> Next) {
535 if (Plugin -> Magic != cmsPluginMagicNumber) {
536 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
540 if (Plugin ->ExpectedVersion > LCMS_VERSION) {
541 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
542 Plugin ->ExpectedVersion, LCMS_VERSION);
546 switch (Plugin -> Type) {
548 case cmsPluginMemHandlerSig:
549 if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
552 case cmsPluginInterpolationSig:
553 if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
556 case cmsPluginTagTypeSig:
557 if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE;
560 case cmsPluginTagSig:
561 if (!_cmsRegisterTagPlugin(Plugin)) return FALSE;
564 case cmsPluginFormattersSig:
565 if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE;
568 case cmsPluginRenderingIntentSig:
569 if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE;
572 case cmsPluginParametricCurveSig:
573 if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE;
576 case cmsPluginMultiProcessElementSig:
577 if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE;
580 case cmsPluginOptimizationSig:
581 if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
585 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
590 // Keep a reference to the plug-in
595 // Revert all plug-ins to default
596 void CMSEXPORT cmsUnregisterPlugins(void)
598 _cmsRegisterMemHandlerPlugin(NULL);
599 _cmsRegisterInterpPlugin(NULL);
600 _cmsRegisterTagTypePlugin(NULL);
601 _cmsRegisterTagPlugin(NULL);
602 _cmsRegisterFormattersPlugin(NULL);
603 _cmsRegisterRenderingIntentPlugin(NULL);
604 _cmsRegisterParametricCurvesPlugin(NULL);
605 _cmsRegisterMultiProcessElementPlugin(NULL);
606 _cmsRegisterOptimizationPlugin(NULL);
608 if (PluginPool != NULL)
609 _cmsSubAllocDestroy(PluginPool);