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