• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //---------------------------------------------------------------------------------
2 //
3 //  Little Color Management System
4 //  Copyright (c) 1998-2016 Marti Maria Saguer
5 //
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:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
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.
23 //
24 //---------------------------------------------------------------------------------
25 //
26 
27 #include "lcms2_internal.h"
28 
29 
30 // ----------------------------------------------------------------------------------
31 // Encoding & Decoding support functions
32 // ----------------------------------------------------------------------------------
33 
34 //      Little-Endian to Big-Endian
35 
36 // Adjust a word value after being readed/ before being written from/to an ICC profile
_cmsAdjustEndianess16(cmsUInt16Number Word)37 cmsUInt16Number CMSEXPORT  _cmsAdjustEndianess16(cmsUInt16Number Word)
38 {
39 #ifndef CMS_USE_BIG_ENDIAN
40 
41     cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
42     cmsUInt8Number tmp;
43 
44     tmp = pByte[0];
45     pByte[0] = pByte[1];
46     pByte[1] = tmp;
47 #endif
48 
49     return Word;
50 }
51 
52 
53 // Transports to properly encoded values - note that icc profiles does use big endian notation.
54 
55 // 1 2 3 4
56 // 4 3 2 1
57 
_cmsAdjustEndianess32(cmsUInt32Number DWord)58 cmsUInt32Number CMSEXPORT  _cmsAdjustEndianess32(cmsUInt32Number DWord)
59 {
60 #ifndef CMS_USE_BIG_ENDIAN
61 
62     cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
63     cmsUInt8Number temp1;
64     cmsUInt8Number temp2;
65 
66     temp1 = *pByte++;
67     temp2 = *pByte++;
68     *(pByte-1) = *pByte;
69     *pByte++ = temp2;
70     *(pByte-3) = *pByte;
71     *pByte = temp1;
72 #endif
73     return DWord;
74 }
75 
76 // 1 2 3 4 5 6 7 8
77 // 8 7 6 5 4 3 2 1
78 
_cmsAdjustEndianess64(cmsUInt64Number * Result,cmsUInt64Number * QWord)79 void CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)
80 {
81 
82 #ifndef CMS_USE_BIG_ENDIAN
83 
84     cmsUInt8Number* pIn  = (cmsUInt8Number*) QWord;
85     cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
86 
87     _cmsAssert(Result != NULL);
88 
89     pOut[7] = pIn[0];
90     pOut[6] = pIn[1];
91     pOut[5] = pIn[2];
92     pOut[4] = pIn[3];
93     pOut[3] = pIn[4];
94     pOut[2] = pIn[5];
95     pOut[1] = pIn[6];
96     pOut[0] = pIn[7];
97 
98 #else
99     _cmsAssert(Result != NULL);
100 
101 #  ifdef CMS_DONT_USE_INT64
102     (*Result)[0] = QWord[0];
103     (*Result)[1] = QWord[1];
104 #  else
105     *Result = *QWord;
106 #  endif
107 #endif
108 }
109 
110 // Auxiliary -- read 8, 16 and 32-bit numbers
_cmsReadUInt8Number(cmsIOHANDLER * io,cmsUInt8Number * n)111 cmsBool CMSEXPORT  _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
112 {
113     cmsUInt8Number tmp;
114 
115     _cmsAssert(io != NULL);
116 
117     if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
118             return FALSE;
119 
120     if (n != NULL) *n = tmp;
121     return TRUE;
122 }
123 
_cmsReadUInt16Number(cmsIOHANDLER * io,cmsUInt16Number * n)124 cmsBool CMSEXPORT  _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
125 {
126     cmsUInt16Number tmp;
127 
128     _cmsAssert(io != NULL);
129 
130     if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
131             return FALSE;
132 
133     if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
134     return TRUE;
135 }
136 
_cmsReadUInt16Array(cmsIOHANDLER * io,cmsUInt32Number n,cmsUInt16Number * Array)137 cmsBool CMSEXPORT  _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
138 {
139     cmsUInt32Number i;
140 
141     _cmsAssert(io != NULL);
142 
143     for (i=0; i < n; i++) {
144 
145         if (Array != NULL) {
146             if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
147         }
148         else {
149             if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
150         }
151 
152     }
153     return TRUE;
154 }
155 
_cmsReadUInt32Number(cmsIOHANDLER * io,cmsUInt32Number * n)156 cmsBool CMSEXPORT  _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
157 {
158     cmsUInt32Number tmp;
159 
160     _cmsAssert(io != NULL);
161 
162     if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
163             return FALSE;
164 
165     if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
166     return TRUE;
167 }
168 
_cmsReadFloat32Number(cmsIOHANDLER * io,cmsFloat32Number * n)169 cmsBool CMSEXPORT  _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
170 {
171     cmsUInt32Number tmp;
172 
173     _cmsAssert(io != NULL);
174 
175     if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
176             return FALSE;
177 
178     if (n != NULL) {
179 
180         tmp = _cmsAdjustEndianess32(tmp);
181         *n = *(cmsFloat32Number*) (void*) &tmp;
182         if (isnan(*n))
183             return FALSE;
184     }
185 
186     // fpclassify() required by C99
187     return (fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL);
188 }
189 
190 
_cmsReadUInt64Number(cmsIOHANDLER * io,cmsUInt64Number * n)191 cmsBool CMSEXPORT   _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
192 {
193     cmsUInt64Number tmp;
194 
195     _cmsAssert(io != NULL);
196 
197     if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
198             return FALSE;
199 
200     if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
201     return TRUE;
202 }
203 
204 
_cmsRead15Fixed16Number(cmsIOHANDLER * io,cmsFloat64Number * n)205 cmsBool CMSEXPORT  _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
206 {
207     cmsUInt32Number tmp;
208 
209     _cmsAssert(io != NULL);
210 
211     if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
212             return FALSE;
213 
214     if (n != NULL) {
215         *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
216     }
217 
218     return TRUE;
219 }
220 
221 
_cmsReadXYZNumber(cmsIOHANDLER * io,cmsCIEXYZ * XYZ)222 cmsBool CMSEXPORT  _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
223 {
224     cmsEncodedXYZNumber xyz;
225 
226     _cmsAssert(io != NULL);
227 
228     if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
229 
230     if (XYZ != NULL) {
231 
232         XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
233         XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
234         XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
235     }
236     return TRUE;
237 }
238 
_cmsWriteUInt8Number(cmsIOHANDLER * io,cmsUInt8Number n)239 cmsBool CMSEXPORT  _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
240 {
241     _cmsAssert(io != NULL);
242 
243     if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
244             return FALSE;
245 
246     return TRUE;
247 }
248 
_cmsWriteUInt16Number(cmsIOHANDLER * io,cmsUInt16Number n)249 cmsBool CMSEXPORT  _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
250 {
251     cmsUInt16Number tmp;
252 
253     _cmsAssert(io != NULL);
254 
255     tmp = _cmsAdjustEndianess16(n);
256     if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
257             return FALSE;
258 
259     return TRUE;
260 }
261 
_cmsWriteUInt16Array(cmsIOHANDLER * io,cmsUInt32Number n,const cmsUInt16Number * Array)262 cmsBool CMSEXPORT  _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
263 {
264     cmsUInt32Number i;
265 
266     _cmsAssert(io != NULL);
267     _cmsAssert(Array != NULL);
268 
269     for (i=0; i < n; i++) {
270         if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
271     }
272 
273     return TRUE;
274 }
275 
_cmsWriteUInt32Number(cmsIOHANDLER * io,cmsUInt32Number n)276 cmsBool CMSEXPORT  _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
277 {
278     cmsUInt32Number tmp;
279 
280     _cmsAssert(io != NULL);
281 
282     tmp = _cmsAdjustEndianess32(n);
283     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
284             return FALSE;
285 
286     return TRUE;
287 }
288 
289 
_cmsWriteFloat32Number(cmsIOHANDLER * io,cmsFloat32Number n)290 cmsBool CMSEXPORT  _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
291 {
292     cmsUInt32Number tmp;
293 
294     _cmsAssert(io != NULL);
295 
296     tmp = *(cmsUInt32Number*) (void*) &n;
297     tmp = _cmsAdjustEndianess32(tmp);
298     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
299             return FALSE;
300 
301     return TRUE;
302 }
303 
_cmsWriteUInt64Number(cmsIOHANDLER * io,cmsUInt64Number * n)304 cmsBool CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
305 {
306     cmsUInt64Number tmp;
307 
308     _cmsAssert(io != NULL);
309 
310     _cmsAdjustEndianess64(&tmp, n);
311     if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
312             return FALSE;
313 
314     return TRUE;
315 }
316 
_cmsWrite15Fixed16Number(cmsIOHANDLER * io,cmsFloat64Number n)317 cmsBool CMSEXPORT  _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
318 {
319     cmsUInt32Number tmp;
320 
321     _cmsAssert(io != NULL);
322 
323     tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
324     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
325             return FALSE;
326 
327     return TRUE;
328 }
329 
_cmsWriteXYZNumber(cmsIOHANDLER * io,const cmsCIEXYZ * XYZ)330 cmsBool CMSEXPORT  _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
331 {
332     cmsEncodedXYZNumber xyz;
333 
334     _cmsAssert(io != NULL);
335     _cmsAssert(XYZ != NULL);
336 
337     xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
338     xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
339     xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
340 
341     return io -> Write(io,  sizeof(cmsEncodedXYZNumber), &xyz);
342 }
343 
344 // from Fixed point 8.8 to double
_cms8Fixed8toDouble(cmsUInt16Number fixed8)345 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
346 {
347        cmsUInt8Number  msb, lsb;
348 
349        lsb = (cmsUInt8Number) (fixed8 & 0xff);
350        msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
351 
352        return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
353 }
354 
_cmsDoubleTo8Fixed8(cmsFloat64Number val)355 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
356 {
357     cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
358     return  (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
359 }
360 
361 // from Fixed point 15.16 to double
_cms15Fixed16toDouble(cmsS15Fixed16Number fix32)362 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
363 {
364     cmsFloat64Number floater, sign, mid;
365     int Whole, FracPart;
366 
367     sign  = (fix32 < 0 ? -1 : 1);
368     fix32 = abs(fix32);
369 
370     Whole     = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
371     FracPart  = (cmsUInt16Number)(fix32 & 0xffff);
372 
373     mid     = (cmsFloat64Number) FracPart / 65536.0;
374     floater = (cmsFloat64Number) Whole + mid;
375 
376     return sign * floater;
377 }
378 
379 // from double to Fixed point 15.16
_cmsDoubleTo15Fixed16(cmsFloat64Number v)380 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
381 {
382     return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
383 }
384 
385 // Date/Time functions
386 
_cmsDecodeDateTimeNumber(const cmsDateTimeNumber * Source,struct tm * Dest)387 void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
388 {
389 
390     _cmsAssert(Dest != NULL);
391     _cmsAssert(Source != NULL);
392 
393     Dest->tm_sec   = _cmsAdjustEndianess16(Source->seconds);
394     Dest->tm_min   = _cmsAdjustEndianess16(Source->minutes);
395     Dest->tm_hour  = _cmsAdjustEndianess16(Source->hours);
396     Dest->tm_mday  = _cmsAdjustEndianess16(Source->day);
397     Dest->tm_mon   = _cmsAdjustEndianess16(Source->month) - 1;
398     Dest->tm_year  = _cmsAdjustEndianess16(Source->year) - 1900;
399     Dest->tm_wday  = -1;
400     Dest->tm_yday  = -1;
401     Dest->tm_isdst = 0;
402 }
403 
_cmsEncodeDateTimeNumber(cmsDateTimeNumber * Dest,const struct tm * Source)404 void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
405 {
406     _cmsAssert(Dest != NULL);
407     _cmsAssert(Source != NULL);
408 
409     Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
410     Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
411     Dest->hours   = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
412     Dest->day     = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
413     Dest->month   = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
414     Dest->year    = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
415 }
416 
417 // Read base and return type base
_cmsReadTypeBase(cmsIOHANDLER * io)418 cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
419 {
420     _cmsTagBase Base;
421 
422     _cmsAssert(io != NULL);
423 
424     if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
425         return (cmsTagTypeSignature) 0;
426 
427     return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
428 }
429 
430 // Setup base marker
_cmsWriteTypeBase(cmsIOHANDLER * io,cmsTagTypeSignature sig)431 cmsBool  CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
432 {
433     _cmsTagBase  Base;
434 
435     _cmsAssert(io != NULL);
436 
437     Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
438     memset(&Base.reserved, 0, sizeof(Base.reserved));
439     return io -> Write(io, sizeof(_cmsTagBase), &Base);
440 }
441 
_cmsReadAlignment(cmsIOHANDLER * io)442 cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
443 {
444     cmsUInt8Number  Buffer[4];
445     cmsUInt32Number NextAligned, At;
446     cmsUInt32Number BytesToNextAlignedPos;
447 
448     _cmsAssert(io != NULL);
449 
450     At = io -> Tell(io);
451     NextAligned = _cmsALIGNLONG(At);
452     BytesToNextAlignedPos = NextAligned - At;
453     if (BytesToNextAlignedPos == 0) return TRUE;
454     if (BytesToNextAlignedPos > 4)  return FALSE;
455 
456     return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
457 }
458 
_cmsWriteAlignment(cmsIOHANDLER * io)459 cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
460 {
461     cmsUInt8Number  Buffer[4];
462     cmsUInt32Number NextAligned, At;
463     cmsUInt32Number BytesToNextAlignedPos;
464 
465     _cmsAssert(io != NULL);
466 
467     At = io -> Tell(io);
468     NextAligned = _cmsALIGNLONG(At);
469     BytesToNextAlignedPos = NextAligned - At;
470     if (BytesToNextAlignedPos == 0) return TRUE;
471     if (BytesToNextAlignedPos > 4)  return FALSE;
472 
473     memset(Buffer, 0, BytesToNextAlignedPos);
474     return io -> Write(io, BytesToNextAlignedPos, Buffer);
475 }
476 
477 
478 // To deal with text streams. 2K at most
_cmsIOPrintf(cmsIOHANDLER * io,const char * frm,...)479 cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
480 {
481     va_list args;
482     int len;
483     cmsUInt8Number Buffer[2048];
484     cmsBool rc;
485 
486     _cmsAssert(io != NULL);
487     _cmsAssert(frm != NULL);
488 
489     va_start(args, frm);
490 
491     len = vsnprintf((char*) Buffer, 2047, frm, args);
492     if (len < 0) {
493         va_end(args);
494         return FALSE;   // Truncated, which is a fatal error for us
495     }
496 
497     rc = io ->Write(io, len, Buffer);
498 
499     va_end(args);
500 
501     return rc;
502 }
503 
504 
505 // Plugin memory management -------------------------------------------------------------------------------------------------
506 
507 // Specialized malloc for plug-ins, that is freed upon exit.
_cmsPluginMalloc(cmsContext ContextID,cmsUInt32Number size)508 void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
509 {
510     struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
511 
512     if (ctx ->MemPool == NULL) {
513 
514         if (ContextID == NULL) {
515 
516             ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
517             if (ctx->MemPool == NULL) return NULL;
518         }
519         else {
520             cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
521             return NULL;
522         }
523     }
524 
525     return _cmsSubAlloc(ctx->MemPool, size);
526 }
527 
528 
529 // Main plug-in dispatcher
cmsPlugin(void * Plug_in)530 cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
531 {
532     return cmsPluginTHR(NULL, Plug_in);
533 }
534 
cmsPluginTHR(cmsContext id,void * Plug_in)535 cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
536 {
537     cmsPluginBase* Plugin;
538 
539     for (Plugin = (cmsPluginBase*) Plug_in;
540          Plugin != NULL;
541          Plugin = Plugin -> Next) {
542 
543             if (Plugin -> Magic != cmsPluginMagicNumber) {
544                 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
545                 return FALSE;
546             }
547 
548             if (Plugin ->ExpectedVersion > LCMS_VERSION) {
549                 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
550                     Plugin ->ExpectedVersion, LCMS_VERSION);
551                 return FALSE;
552             }
553 
554             switch (Plugin -> Type) {
555 
556                 case cmsPluginMemHandlerSig:
557                     if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
558                     break;
559 
560                 case cmsPluginInterpolationSig:
561                     if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
562                     break;
563 
564                 case cmsPluginTagTypeSig:
565                     if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
566                     break;
567 
568                 case cmsPluginTagSig:
569                     if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
570                     break;
571 
572                 case cmsPluginFormattersSig:
573                     if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
574                     break;
575 
576                 case cmsPluginRenderingIntentSig:
577                     if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
578                     break;
579 
580                 case cmsPluginParametricCurveSig:
581                     if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
582                     break;
583 
584                 case cmsPluginMultiProcessElementSig:
585                     if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
586                     break;
587 
588                 case cmsPluginOptimizationSig:
589                     if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
590                     break;
591 
592                 case cmsPluginTransformSig:
593                     if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
594                     break;
595 
596                 case cmsPluginMutexSig:
597                     if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
598                     break;
599 
600                 default:
601                     cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
602                     return FALSE;
603             }
604     }
605 
606     // Keep a reference to the plug-in
607     return TRUE;
608 }
609 
610 
611 // Revert all plug-ins to default
cmsUnregisterPlugins(void)612 void CMSEXPORT cmsUnregisterPlugins(void)
613 {
614     cmsUnregisterPluginsTHR(NULL);
615 }
616 
617 
618 // The Global storage for system context. This is the one and only global variable
619 // pointers structure. All global vars are referenced here.
620 static struct _cmsContext_struct globalContext = {
621 
622     NULL,                              // Not in the linked list
623     NULL,                              // No suballocator
624     {
625         NULL,                          //  UserPtr,
626         &_cmsLogErrorChunk,            //  Logger,
627         &_cmsAlarmCodesChunk,          //  AlarmCodes,
628         &_cmsAdaptationStateChunk,     //  AdaptationState,
629         &_cmsMemPluginChunk,           //  MemPlugin,
630         &_cmsInterpPluginChunk,        //  InterpPlugin,
631         &_cmsCurvesPluginChunk,        //  CurvesPlugin,
632         &_cmsFormattersPluginChunk,    //  FormattersPlugin,
633         &_cmsTagTypePluginChunk,       //  TagTypePlugin,
634         &_cmsTagPluginChunk,           //  TagPlugin,
635         &_cmsIntentsPluginChunk,       //  IntentPlugin,
636         &_cmsMPETypePluginChunk,       //  MPEPlugin,
637         &_cmsOptimizationPluginChunk,  //  OptimizationPlugin,
638         &_cmsTransformPluginChunk,     //  TransformPlugin,
639         &_cmsMutexPluginChunk          //  MutexPlugin
640     },
641 
642     { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
643 };
644 
645 
646 // The context pool (linked list head)
647 static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
648 static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
649 
650 // Internal, get associated pointer, with guessing. Never returns NULL.
_cmsGetContext(cmsContext ContextID)651 struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
652 {
653     struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
654     struct _cmsContext_struct* ctx;
655 
656 
657     // On 0, use global settings
658     if (id == NULL)
659         return &globalContext;
660 
661     // Search
662     for (ctx = _cmsContextPoolHead;
663          ctx != NULL;
664          ctx = ctx ->Next) {
665 
666             // Found it?
667             if (id == ctx)
668                 return ctx; // New-style context,
669     }
670 
671     return &globalContext;
672 }
673 
674 
675 // Internal: get the memory area associanted with each context client
676 // Returns the block assigned to the specific zone. Never return NULL.
_cmsContextGetClientChunk(cmsContext ContextID,_cmsMemoryClient mc)677 void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
678 {
679     struct _cmsContext_struct* ctx;
680     void *ptr;
681 
682     if ((int) mc < 0 || mc >= MemoryClientMax) {
683 
684            cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption");
685 
686            // This is catastrophic. Should never reach here
687            _cmsAssert(0);
688 
689            // Reverts to global context
690            return globalContext.chunks[UserPtr];
691     }
692 
693     ctx = _cmsGetContext(ContextID);
694     ptr = ctx ->chunks[mc];
695 
696     if (ptr != NULL)
697         return ptr;
698 
699     // A null ptr means no special settings for that context, and this
700     // reverts to Context0 globals
701     return globalContext.chunks[mc];
702 }
703 
704 
705 // This function returns the given context its default pristine state,
706 // as no plug-ins were declared. There is no way to unregister a single
707 // plug-in, as a single call to cmsPluginTHR() function may register
708 // many different plug-ins simultaneously, then there is no way to
709 // identify which plug-in to unregister.
cmsUnregisterPluginsTHR(cmsContext ContextID)710 void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
711 {
712     _cmsRegisterMemHandlerPlugin(ContextID, NULL);
713     _cmsRegisterInterpPlugin(ContextID, NULL);
714     _cmsRegisterTagTypePlugin(ContextID, NULL);
715     _cmsRegisterTagPlugin(ContextID, NULL);
716     _cmsRegisterFormattersPlugin(ContextID, NULL);
717     _cmsRegisterRenderingIntentPlugin(ContextID, NULL);
718     _cmsRegisterParametricCurvesPlugin(ContextID, NULL);
719     _cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
720     _cmsRegisterOptimizationPlugin(ContextID, NULL);
721     _cmsRegisterTransformPlugin(ContextID, NULL);
722     _cmsRegisterMutexPlugin(ContextID, NULL);
723 }
724 
725 
726 // Returns the memory manager plug-in, if any, from the Plug-in bundle
727 static
_cmsFindMemoryPlugin(void * PluginBundle)728 cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
729 {
730     cmsPluginBase* Plugin;
731 
732     for (Plugin = (cmsPluginBase*) PluginBundle;
733         Plugin != NULL;
734         Plugin = Plugin -> Next) {
735 
736             if (Plugin -> Magic == cmsPluginMagicNumber &&
737                 Plugin -> ExpectedVersion <= LCMS_VERSION &&
738                 Plugin -> Type == cmsPluginMemHandlerSig) {
739 
740                     // Found!
741                     return (cmsPluginMemHandler*) Plugin;
742             }
743     }
744 
745     // Nope, revert to defaults
746     return NULL;
747 }
748 
749 
750 // Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
751 // data that will be forwarded to plug-ins and logger.
cmsCreateContext(void * Plugin,void * UserData)752 cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
753 {
754     struct _cmsContext_struct* ctx;
755     struct _cmsContext_struct  fakeContext;
756 
757     _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
758 
759     fakeContext.chunks[UserPtr]     = UserData;
760     fakeContext.chunks[MemPlugin]   = &fakeContext.DefaultMemoryManager;
761 
762     // Create the context structure.
763     ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
764     if (ctx == NULL)
765         return NULL;     // Something very wrong happened!
766 
767     // Init the structure and the memory manager
768     memset(ctx, 0, sizeof(struct _cmsContext_struct));
769 
770     // Keep memory manager
771     memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
772 
773     // Maintain the linked list (with proper locking)
774     _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
775        ctx ->Next = _cmsContextPoolHead;
776        _cmsContextPoolHead = ctx;
777     _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
778 
779     ctx ->chunks[UserPtr]     = UserData;
780     ctx ->chunks[MemPlugin]   = &ctx->DefaultMemoryManager;
781 
782     // Now we can allocate the pool by using default memory manager
783     ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));  // default size about 32 pointers
784     if (ctx ->MemPool == NULL) {
785 
786          cmsDeleteContext(ctx);
787         return NULL;
788     }
789 
790     _cmsAllocLogErrorChunk(ctx, NULL);
791     _cmsAllocAlarmCodesChunk(ctx, NULL);
792     _cmsAllocAdaptationStateChunk(ctx, NULL);
793     _cmsAllocMemPluginChunk(ctx, NULL);
794     _cmsAllocInterpPluginChunk(ctx, NULL);
795     _cmsAllocCurvesPluginChunk(ctx, NULL);
796     _cmsAllocFormattersPluginChunk(ctx, NULL);
797     _cmsAllocTagTypePluginChunk(ctx, NULL);
798     _cmsAllocMPETypePluginChunk(ctx, NULL);
799     _cmsAllocTagPluginChunk(ctx, NULL);
800     _cmsAllocIntentsPluginChunk(ctx, NULL);
801     _cmsAllocOptimizationPluginChunk(ctx, NULL);
802     _cmsAllocTransformPluginChunk(ctx, NULL);
803     _cmsAllocMutexPluginChunk(ctx, NULL);
804 
805     // Setup the plug-ins
806     if (!cmsPluginTHR(ctx, Plugin)) {
807 
808         cmsDeleteContext(ctx);
809         return NULL;
810     }
811 
812     return (cmsContext) ctx;
813 }
814 
815 // Duplicates a context with all associated plug-ins.
816 // Caller may specify an optional pointer to user-defined
817 // data that will be forwarded to plug-ins and logger.
cmsDupContext(cmsContext ContextID,void * NewUserData)818 cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
819 {
820     int i;
821     struct _cmsContext_struct* ctx;
822     const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
823 
824     void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
825 
826 
827     ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
828     if (ctx == NULL)
829         return NULL;     // Something very wrong happened
830 
831     // Setup default memory allocators
832     memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
833 
834     // Maintain the linked list
835     _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
836        ctx ->Next = _cmsContextPoolHead;
837        _cmsContextPoolHead = ctx;
838     _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
839 
840     ctx ->chunks[UserPtr]    = userData;
841     ctx ->chunks[MemPlugin]  = &ctx->DefaultMemoryManager;
842 
843     ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
844     if (ctx ->MemPool == NULL) {
845 
846          cmsDeleteContext(ctx);
847         return NULL;
848     }
849 
850     // Allocate all required chunks.
851     _cmsAllocLogErrorChunk(ctx, src);
852     _cmsAllocAlarmCodesChunk(ctx, src);
853     _cmsAllocAdaptationStateChunk(ctx, src);
854     _cmsAllocMemPluginChunk(ctx, src);
855     _cmsAllocInterpPluginChunk(ctx, src);
856     _cmsAllocCurvesPluginChunk(ctx, src);
857     _cmsAllocFormattersPluginChunk(ctx, src);
858     _cmsAllocTagTypePluginChunk(ctx, src);
859     _cmsAllocMPETypePluginChunk(ctx, src);
860     _cmsAllocTagPluginChunk(ctx, src);
861     _cmsAllocIntentsPluginChunk(ctx, src);
862     _cmsAllocOptimizationPluginChunk(ctx, src);
863     _cmsAllocTransformPluginChunk(ctx, src);
864     _cmsAllocMutexPluginChunk(ctx, src);
865 
866     // Make sure no one failed
867     for (i=Logger; i < MemoryClientMax; i++) {
868 
869         if (src ->chunks[i] == NULL) {
870             cmsDeleteContext((cmsContext) ctx);
871             return NULL;
872         }
873     }
874 
875     return (cmsContext) ctx;
876 }
877 
878 
879 /*
880 static
881 struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
882 {
883     struct _cmsContext_struct* prev;
884 
885     // Search for previous
886     for (prev = _cmsContextPoolHead;
887              prev != NULL;
888              prev = prev ->Next)
889     {
890         if (prev ->Next == id)
891             return prev;
892     }
893 
894     return NULL;  // List is empty or only one element!
895 }
896 */
897 
898 // Frees any resources associated with the given context,
899 // and destroys the context placeholder.
900 // The ContextID can no longer be used in any THR operation.
cmsDeleteContext(cmsContext ContextID)901 void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
902 {
903     if (ContextID != NULL) {
904 
905         struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
906         struct _cmsContext_struct  fakeContext;
907         struct _cmsContext_struct* prev;
908 
909         memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
910 
911         fakeContext.chunks[UserPtr]     = ctx ->chunks[UserPtr];
912         fakeContext.chunks[MemPlugin]   = &fakeContext.DefaultMemoryManager;
913 
914         // Get rid of plugins
915         cmsUnregisterPluginsTHR(ContextID);
916 
917         // Since all memory is allocated in the private pool, all what we need to do is destroy the pool
918         if (ctx -> MemPool != NULL)
919               _cmsSubAllocDestroy(ctx ->MemPool);
920         ctx -> MemPool = NULL;
921 
922         // Maintain list
923         _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
924         if (_cmsContextPoolHead == ctx) {
925 
926             _cmsContextPoolHead = ctx->Next;
927         }
928         else {
929 
930             // Search for previous
931             for (prev = _cmsContextPoolHead;
932                  prev != NULL;
933                  prev = prev ->Next)
934             {
935                 if (prev -> Next == ctx) {
936                     prev -> Next = ctx ->Next;
937                     break;
938                 }
939             }
940         }
941         _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
942 
943         // free the memory block itself
944         _cmsFree(&fakeContext, ctx);
945     }
946 }
947 
948 // Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
cmsGetContextUserData(cmsContext ContextID)949 void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
950 {
951     return _cmsContextGetClientChunk(ContextID, UserPtr);
952 }
953 
954 
955