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