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
);
99 _cmsAssert(Result
!= NULL
);
101 # ifdef CMS_DONT_USE_INT64
102 (*Result
)[0] = QWord
[0];
103 (*Result
)[1] = QWord
[1];
110 // Auxiliar -- read 8, 16 and 32-bit numbers
111 cmsBool CMSEXPORT
_cmsReadUInt8Number(cmsIOHANDLER
* io
, cmsUInt8Number
* n
)
115 _cmsAssert(io
!= NULL
);
117 if (io
-> Read(io
, &tmp
, sizeof(cmsUInt8Number
), 1) != 1)
120 if (n
!= NULL
) *n
= tmp
;
124 cmsBool CMSEXPORT
_cmsReadUInt16Number(cmsIOHANDLER
* io
, cmsUInt16Number
* n
)
128 _cmsAssert(io
!= NULL
);
130 if (io
-> Read(io
, &tmp
, sizeof(cmsUInt16Number
), 1) != 1)
133 if (n
!= NULL
) *n
= _cmsAdjustEndianess16(tmp
);
137 cmsBool CMSEXPORT
_cmsReadUInt16Array(cmsIOHANDLER
* io
, cmsUInt32Number n
, cmsUInt16Number
* Array
)
141 _cmsAssert(io
!= NULL
);
143 for (i
=0; i
< n
; i
++) {
146 if (!_cmsReadUInt16Number(io
, Array
+ i
)) return FALSE
;
149 if (!_cmsReadUInt16Number(io
, NULL
)) return FALSE
;
156 cmsBool CMSEXPORT
_cmsReadUInt32Number(cmsIOHANDLER
* io
, cmsUInt32Number
* n
)
160 _cmsAssert(io
!= NULL
);
162 if (io
-> Read(io
, &tmp
, sizeof(cmsUInt32Number
), 1) != 1)
165 if (n
!= NULL
) *n
= _cmsAdjustEndianess32(tmp
);
169 cmsBool CMSEXPORT
_cmsReadFloat32Number(cmsIOHANDLER
* io
, cmsFloat32Number
* n
)
173 _cmsAssert(io
!= NULL
);
175 if (io
-> Read(io
, &tmp
, sizeof(cmsFloat32Number
), 1) != 1)
179 char *cp
= (char *)&tmp
;
180 tmp
= _cmsAdjustEndianess32(tmp
);
181 *n
= *(cmsFloat32Number
*)cp
;
187 cmsBool CMSEXPORT
_cmsReadUInt64Number(cmsIOHANDLER
* io
, cmsUInt64Number
* n
)
191 _cmsAssert(io
!= NULL
);
193 if (io
-> Read(io
, &tmp
, sizeof(cmsUInt64Number
), 1) != 1)
196 if (n
!= NULL
) _cmsAdjustEndianess64(n
, &tmp
);
201 cmsBool CMSEXPORT
_cmsRead15Fixed16Number(cmsIOHANDLER
* io
, cmsFloat64Number
* n
)
205 _cmsAssert(io
!= NULL
);
207 if (io
-> Read(io
, &tmp
, sizeof(cmsUInt32Number
), 1) != 1)
211 *n
= _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp
));
218 // Jun-21-2000: Some profiles (those that comes with W2K) comes
219 // with the media white (media black?) x 100. Add a sanity check
222 void NormalizeXYZ(cmsCIEXYZ
* Dest
)
224 while (Dest
-> X
> 2. &&
234 cmsBool CMSEXPORT
_cmsReadXYZNumber(cmsIOHANDLER
* io
, cmsCIEXYZ
* XYZ
)
236 cmsEncodedXYZNumber xyz
;
238 _cmsAssert(io
!= NULL
);
240 if (io
->Read(io
, &xyz
, sizeof(cmsEncodedXYZNumber
), 1) != 1) return FALSE
;
244 XYZ
->X
= _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz
.X
));
245 XYZ
->Y
= _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz
.Y
));
246 XYZ
->Z
= _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz
.Z
));
253 cmsBool CMSEXPORT
_cmsWriteUInt8Number(cmsIOHANDLER
* io
, cmsUInt8Number n
)
255 _cmsAssert(io
!= NULL
);
257 if (io
-> Write(io
, sizeof(cmsUInt8Number
), &n
) != 1)
263 cmsBool CMSEXPORT
_cmsWriteUInt16Number(cmsIOHANDLER
* io
, cmsUInt16Number n
)
267 _cmsAssert(io
!= NULL
);
269 tmp
= _cmsAdjustEndianess16(n
);
270 if (io
-> Write(io
, sizeof(cmsUInt16Number
), &tmp
) != 1)
276 cmsBool CMSEXPORT
_cmsWriteUInt16Array(cmsIOHANDLER
* io
, cmsUInt32Number n
, const cmsUInt16Number
* Array
)
280 _cmsAssert(io
!= NULL
);
281 _cmsAssert(Array
!= NULL
);
283 for (i
=0; i
< n
; i
++) {
284 if (!_cmsWriteUInt16Number(io
, Array
[i
])) return FALSE
;
290 cmsBool CMSEXPORT
_cmsWriteUInt32Number(cmsIOHANDLER
* io
, cmsUInt32Number n
)
294 _cmsAssert(io
!= NULL
);
296 tmp
= _cmsAdjustEndianess32(n
);
297 if (io
-> Write(io
, sizeof(cmsUInt32Number
), &tmp
) != 1)
304 cmsBool CMSEXPORT
_cmsWriteFloat32Number(cmsIOHANDLER
* io
, cmsFloat32Number n
)
307 char *cp
= (char *)&n
;
309 _cmsAssert(io
!= NULL
);
311 tmp
= *(cmsUInt32Number
*)cp
;
312 tmp
= _cmsAdjustEndianess32(tmp
);
313 if (io
-> Write(io
, sizeof(cmsUInt32Number
), &tmp
) != 1)
319 cmsBool CMSEXPORT
_cmsWriteUInt64Number(cmsIOHANDLER
* io
, cmsUInt64Number
* n
)
323 _cmsAssert(io
!= NULL
);
325 _cmsAdjustEndianess64(&tmp
, n
);
326 if (io
-> Write(io
, sizeof(cmsUInt64Number
), &tmp
) != 1)
332 cmsBool CMSEXPORT
_cmsWrite15Fixed16Number(cmsIOHANDLER
* io
, cmsFloat64Number n
)
336 _cmsAssert(io
!= NULL
);
338 tmp
= _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n
));
339 if (io
-> Write(io
, sizeof(cmsUInt32Number
), &tmp
) != 1)
345 cmsBool CMSEXPORT
_cmsWriteXYZNumber(cmsIOHANDLER
* io
, const cmsCIEXYZ
* XYZ
)
347 cmsEncodedXYZNumber xyz
;
349 _cmsAssert(io
!= NULL
);
350 _cmsAssert(XYZ
!= NULL
);
352 xyz
.X
= _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ
->X
));
353 xyz
.Y
= _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ
->Y
));
354 xyz
.Z
= _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ
->Z
));
356 return io
-> Write(io
, sizeof(cmsEncodedXYZNumber
), &xyz
);
359 // from Fixed point 8.8 to double
360 cmsFloat64Number CMSEXPORT
_cms8Fixed8toDouble(cmsUInt16Number fixed8
)
362 cmsUInt8Number msb
, lsb
;
364 lsb
= (cmsUInt8Number
) (fixed8
& 0xff);
365 msb
= (cmsUInt8Number
) (((cmsUInt16Number
) fixed8
>> 8) & 0xff);
367 return (cmsFloat64Number
) ((cmsFloat64Number
) msb
+ ((cmsFloat64Number
) lsb
/ 256.0));
370 cmsUInt16Number CMSEXPORT
_cmsDoubleTo8Fixed8(cmsFloat64Number val
)
372 cmsS15Fixed16Number GammaFixed32
= _cmsDoubleTo15Fixed16(val
);
373 return (cmsUInt16Number
) ((GammaFixed32
>> 8) & 0xFFFF);
376 // from Fixed point 15.16 to double
377 cmsFloat64Number CMSEXPORT
_cms15Fixed16toDouble(cmsS15Fixed16Number fix32
)
379 cmsFloat64Number floater
, sign
, mid
;
382 sign
= (fix32
< 0 ? -1 : 1);
385 Whole
= (cmsUInt16Number
)(fix32
>> 16) & 0xffff;
386 FracPart
= (cmsUInt16Number
)(fix32
& 0xffff);
388 mid
= (cmsFloat64Number
) FracPart
/ 65536.0;
389 floater
= (cmsFloat64Number
) Whole
+ mid
;
391 return sign
* floater
;
394 // from double to Fixed point 15.16
395 cmsS15Fixed16Number CMSEXPORT
_cmsDoubleTo15Fixed16(cmsFloat64Number v
)
397 return ((cmsS15Fixed16Number
) floor((v
)*65536.0 + 0.5));
400 // Date/Time functions
402 void CMSEXPORT
_cmsDecodeDateTimeNumber(const cmsDateTimeNumber
*Source
, struct tm
*Dest
)
405 _cmsAssert(Dest
!= NULL
);
406 _cmsAssert(Source
!= NULL
);
408 Dest
->tm_sec
= _cmsAdjustEndianess16(Source
->seconds
);
409 Dest
->tm_min
= _cmsAdjustEndianess16(Source
->minutes
);
410 Dest
->tm_hour
= _cmsAdjustEndianess16(Source
->hours
);
411 Dest
->tm_mday
= _cmsAdjustEndianess16(Source
->day
);
412 Dest
->tm_mon
= _cmsAdjustEndianess16(Source
->month
) - 1;
413 Dest
->tm_year
= _cmsAdjustEndianess16(Source
->year
) - 1900;
419 void CMSEXPORT
_cmsEncodeDateTimeNumber(cmsDateTimeNumber
*Dest
, const struct tm
*Source
)
421 _cmsAssert(Dest
!= NULL
);
422 _cmsAssert(Source
!= NULL
);
424 Dest
->seconds
= _cmsAdjustEndianess16((cmsUInt16Number
) Source
->tm_sec
);
425 Dest
->minutes
= _cmsAdjustEndianess16((cmsUInt16Number
) Source
->tm_min
);
426 Dest
->hours
= _cmsAdjustEndianess16((cmsUInt16Number
) Source
->tm_hour
);
427 Dest
->day
= _cmsAdjustEndianess16((cmsUInt16Number
) Source
->tm_mday
);
428 Dest
->month
= _cmsAdjustEndianess16((cmsUInt16Number
) (Source
->tm_mon
+ 1));
429 Dest
->year
= _cmsAdjustEndianess16((cmsUInt16Number
) (Source
->tm_year
+ 1900));
432 // Read base and return type base
433 cmsTagTypeSignature CMSEXPORT
_cmsReadTypeBase(cmsIOHANDLER
* io
)
437 _cmsAssert(io
!= NULL
);
439 if (io
-> Read(io
, &Base
, sizeof(_cmsTagBase
), 1) != 1)
440 return (cmsTagTypeSignature
) 0;
442 return (cmsTagTypeSignature
) _cmsAdjustEndianess32(Base
.sig
);
446 cmsBool CMSEXPORT
_cmsWriteTypeBase(cmsIOHANDLER
* io
, cmsTagTypeSignature sig
)
450 _cmsAssert(io
!= NULL
);
452 Base
.sig
= (cmsTagTypeSignature
) _cmsAdjustEndianess32(sig
);
453 memset(&Base
.reserved
, 0, sizeof(Base
.reserved
));
454 return io
-> Write(io
, sizeof(_cmsTagBase
), &Base
);
457 cmsBool CMSEXPORT
_cmsReadAlignment(cmsIOHANDLER
* io
)
459 cmsUInt8Number Buffer
[4];
460 cmsUInt32Number NextAligned
, At
;
461 cmsUInt32Number BytesToNextAlignedPos
;
463 _cmsAssert(io
!= NULL
);
466 NextAligned
= _cmsALIGNLONG(At
);
467 BytesToNextAlignedPos
= NextAligned
- At
;
468 if (BytesToNextAlignedPos
== 0) return TRUE
;
469 if (BytesToNextAlignedPos
> 4) return FALSE
;
471 return (io
->Read(io
, Buffer
, BytesToNextAlignedPos
, 1) == 1);
474 cmsBool CMSEXPORT
_cmsWriteAlignment(cmsIOHANDLER
* io
)
476 cmsUInt8Number Buffer
[4];
477 cmsUInt32Number NextAligned
, At
;
478 cmsUInt32Number BytesToNextAlignedPos
;
480 _cmsAssert(io
!= NULL
);
483 NextAligned
= _cmsALIGNLONG(At
);
484 BytesToNextAlignedPos
= NextAligned
- At
;
485 if (BytesToNextAlignedPos
== 0) return TRUE
;
486 if (BytesToNextAlignedPos
> 4) return FALSE
;
488 memset(Buffer
, 0, BytesToNextAlignedPos
);
489 return io
-> Write(io
, BytesToNextAlignedPos
, Buffer
);
493 // To deal with text streams. 2K at most
494 cmsBool CMSEXPORT
_cmsIOPrintf(cmsIOHANDLER
* io
, const char* frm
, ...)
498 cmsUInt8Number Buffer
[2048];
501 _cmsAssert(io
!= NULL
);
502 _cmsAssert(frm
!= NULL
);
506 len
= vsnprintf((char*) Buffer
, 2047, frm
, args
);
507 if (len
< 0) return FALSE
; // Truncated, which is a fatal error for us
509 rc
= io
->Write(io
, len
, Buffer
);
517 // Plugin memory management -------------------------------------------------------------------------------------------------
519 static _cmsSubAllocator
* PluginPool
= NULL
;
521 // Specialized malloc for plug-ins, that is freed upon exit.
522 void* _cmsPluginMalloc(cmsContext id
, cmsUInt32Number size
)
524 if (PluginPool
== NULL
)
525 PluginPool
= _cmsCreateSubAlloc(id
, 4*1024);
527 return _cmsSubAlloc(PluginPool
, size
);
531 // Main plug-in dispatcher
532 cmsBool CMSEXPORT
cmsPlugin(void* Plug_in
)
534 return cmsPluginTHR(NULL
, Plug_in
);
537 cmsBool CMSEXPORT
cmsPluginTHR(cmsContext id
, void* Plug_in
)
539 cmsPluginBase
* Plugin
;
541 for (Plugin
= (cmsPluginBase
*) Plug_in
;
543 Plugin
= Plugin
-> Next
) {
545 if (Plugin
-> Magic
!= cmsPluginMagicNumber
) {
546 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION
, "Unrecognized plugin");
550 if (Plugin
->ExpectedVersion
> LCMS_VERSION
) {
551 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION
, "plugin needs Little CMS %d, current version is %d",
552 Plugin
->ExpectedVersion
, LCMS_VERSION
);
556 switch (Plugin
-> Type
) {
558 case cmsPluginMemHandlerSig
:
559 if (!_cmsRegisterMemHandlerPlugin(Plugin
)) return FALSE
;
562 case cmsPluginInterpolationSig
:
563 if (!_cmsRegisterInterpPlugin(Plugin
)) return FALSE
;
566 case cmsPluginTagTypeSig
:
567 if (!_cmsRegisterTagTypePlugin(id
, Plugin
)) return FALSE
;
570 case cmsPluginTagSig
:
571 if (!_cmsRegisterTagPlugin(id
, Plugin
)) return FALSE
;
574 case cmsPluginFormattersSig
:
575 if (!_cmsRegisterFormattersPlugin(id
, Plugin
)) return FALSE
;
578 case cmsPluginRenderingIntentSig
:
579 if (!_cmsRegisterRenderingIntentPlugin(id
, Plugin
)) return FALSE
;
582 case cmsPluginParametricCurveSig
:
583 if (!_cmsRegisterParametricCurvesPlugin(id
, Plugin
)) return FALSE
;
586 case cmsPluginMultiProcessElementSig
:
587 if (!_cmsRegisterMultiProcessElementPlugin(id
, Plugin
)) return FALSE
;
590 case cmsPluginOptimizationSig
:
591 if (!_cmsRegisterOptimizationPlugin(id
, Plugin
)) return FALSE
;
594 case cmsPluginTransformSig
:
595 if (!_cmsRegisterTransformPlugin(id
, Plugin
)) return FALSE
;
599 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION
, "Unrecognized plugin type '%X'", Plugin
-> Type
);
604 // Keep a reference to the plug-in
609 // Revert all plug-ins to default
610 void CMSEXPORT
cmsUnregisterPlugins(void)
612 _cmsRegisterMemHandlerPlugin(NULL
);
613 _cmsRegisterInterpPlugin(NULL
);
614 _cmsRegisterTagTypePlugin(NULL
, NULL
);
615 _cmsRegisterTagPlugin(NULL
, NULL
);
616 _cmsRegisterFormattersPlugin(NULL
, NULL
);
617 _cmsRegisterRenderingIntentPlugin(NULL
, NULL
);
618 _cmsRegisterParametricCurvesPlugin(NULL
, NULL
);
619 _cmsRegisterMultiProcessElementPlugin(NULL
, NULL
);
620 _cmsRegisterOptimizationPlugin(NULL
, NULL
);
621 _cmsRegisterTransformPlugin(NULL
, NULL
);
623 if (PluginPool
!= NULL
)
624 _cmsSubAllocDestroy(PluginPool
);