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-2017 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// Auxiliary -- 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(cmsUInt32Number), 1) != 1)
205 return FALSE;
206
207 if (n != NULL) {
208
209 tmp = _cmsAdjustEndianess32(tmp);
210 *n = *(cmsFloat32Number*)(void*)&tmp;
211
212 // Safeguard which covers against absurd values
213 if (*n > 1E+20 || *n < -1E+20) return FALSE;
214
215 #if defined(_MSC_VER) && _MSC_VER < 1800
216 return TRUE;
217 #elif defined (__BORLANDC__)
218 return TRUE;
219 #else
220
221 // fpclassify() required by C99 (only provided by MSVC >= 1800, VS2013 onwards)
222 return ((fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL));
223 #endif
224 }
225
226 return TRUE;
227}
228
229
230cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
231{
232 cmsUInt64Number tmp;
233
234 _cmsAssert(io != NULL);
235
236 if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
237 return FALSE;
238
239 if (n != NULL) {
240
241 _cmsAdjustEndianess64(n, &tmp);
242 }
243
244 return TRUE;
245}
246
247
248cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
249{
250 cmsUInt32Number tmp;
251
252 _cmsAssert(io != NULL);
253
254 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
255 return FALSE;
256
257 if (n != NULL) {
258 *n = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32(tmp));
259 }
260
261 return TRUE;
262}
263
264
265cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
266{
267 cmsEncodedXYZNumber xyz;
268
269 _cmsAssert(io != NULL);
270
271 if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
272
273 if (XYZ != NULL) {
274
275 XYZ->X = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.X));
276 XYZ->Y = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Y));
277 XYZ->Z = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Z));
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*) (void*) &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((cmsUInt32Number) _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 = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->X));
381 xyz.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Y));
382 xyz.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _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) {
536 va_end(args);
537 return FALSE; // Truncated, which is a fatal error for us
538 }
539
540 rc = io ->Write(io, (cmsUInt32Number) len, Buffer);
541
542 va_end(args);
543
544 return rc;
545}
546
547
548// Plugin memory management -------------------------------------------------------------------------------------------------
549
550// Specialized malloc for plug-ins, that is freed upon exit.
551void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
552{
553 struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
554
555 if (ctx ->MemPool == NULL) {
556
557 if (ContextID == NULL) {
558
559 ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
560 if (ctx->MemPool == NULL) return NULL;
561 }
562 else {
563 cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
564 return NULL;
565 }
566 }
567
568 return _cmsSubAlloc(ctx->MemPool, size);
569}
570
571
572// Main plug-in dispatcher
573cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
574{
575 return cmsPluginTHR(NULL, Plug_in);
576}
577
578cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
579{
580 cmsPluginBase* Plugin;
581
582 for (Plugin = (cmsPluginBase*) Plug_in;
583 Plugin != NULL;
584 Plugin = Plugin -> Next) {
585
586 if (Plugin -> Magic != cmsPluginMagicNumber) {
587 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
588 return FALSE;
589 }
590
591 if (Plugin ->ExpectedVersion > LCMS_VERSION) {
592 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
593 Plugin ->ExpectedVersion, LCMS_VERSION);
594 return FALSE;
595 }
596
597 switch (Plugin -> Type) {
598
599 case cmsPluginMemHandlerSig:
600 if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
601 break;
602
603 case cmsPluginInterpolationSig:
604 if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
605 break;
606
607 case cmsPluginTagTypeSig:
608 if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
609 break;
610
611 case cmsPluginTagSig:
612 if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
613 break;
614
615 case cmsPluginFormattersSig:
616 if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
617 break;
618
619 case cmsPluginRenderingIntentSig:
620 if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
621 break;
622
623 case cmsPluginParametricCurveSig:
624 if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
625 break;
626
627 case cmsPluginMultiProcessElementSig:
628 if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
629 break;
630
631 case cmsPluginOptimizationSig:
632 if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
633 break;
634
635 case cmsPluginTransformSig:
636 if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
637 break;
638
639 case cmsPluginMutexSig:
640 if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
641 break;
642
643 default:
644 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
645 return FALSE;
646 }
647 }
648
649 // Keep a reference to the plug-in
650 return TRUE;
651}
652
653
654// Revert all plug-ins to default
655void CMSEXPORT cmsUnregisterPlugins(void)
656{
657 cmsUnregisterPluginsTHR(NULL);
658}
659
660
661// The Global storage for system context. This is the one and only global variable
662// pointers structure. All global vars are referenced here.
663static struct _cmsContext_struct globalContext = {
664
665 NULL, // Not in the linked list
666 NULL, // No suballocator
667 {
668 NULL, // UserPtr,
669 &_cmsLogErrorChunk, // Logger,
670 &_cmsAlarmCodesChunk, // AlarmCodes,
671 &_cmsAdaptationStateChunk, // AdaptationState,
672 &_cmsMemPluginChunk, // MemPlugin,
673 &_cmsInterpPluginChunk, // InterpPlugin,
674 &_cmsCurvesPluginChunk, // CurvesPlugin,
675 &_cmsFormattersPluginChunk, // FormattersPlugin,
676 &_cmsTagTypePluginChunk, // TagTypePlugin,
677 &_cmsTagPluginChunk, // TagPlugin,
678 &_cmsIntentsPluginChunk, // IntentPlugin,
679 &_cmsMPETypePluginChunk, // MPEPlugin,
680 &_cmsOptimizationPluginChunk, // OptimizationPlugin,
681 &_cmsTransformPluginChunk, // TransformPlugin,
682 &_cmsMutexPluginChunk // MutexPlugin
683 },
684
685 { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
686};
687
688
689// The context pool (linked list head)
690static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
691static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
692
693// Internal, get associated pointer, with guessing. Never returns NULL.
694struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
695{
696 struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
697 struct _cmsContext_struct* ctx;
698
699
700 // On 0, use global settings
701 if (id == NULL)
702 return &globalContext;
703
704 // Search
705 for (ctx = _cmsContextPoolHead;
706 ctx != NULL;
707 ctx = ctx ->Next) {
708
709 // Found it?
710 if (id == ctx)
711 return ctx; // New-style context,
712 }
713
714 return &globalContext;
715}
716
717
718// Internal: get the memory area associanted with each context client
719// Returns the block assigned to the specific zone. Never return NULL.
720void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
721{
722 struct _cmsContext_struct* ctx;
723 void *ptr;
724
725 if ((int) mc < 0 || mc >= MemoryClientMax) {
726
727 cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption");
728
729 // This is catastrophic. Should never reach here
730 _cmsAssert(0);
731
732 // Reverts to global context
733 return globalContext.chunks[UserPtr];
734 }
735
736 ctx = _cmsGetContext(ContextID);
737 ptr = ctx ->chunks[mc];
738
739 if (ptr != NULL)
740 return ptr;
741
742 // A null ptr means no special settings for that context, and this
743 // reverts to Context0 globals
744 return globalContext.chunks[mc];
745}
746
747
748// This function returns the given context its default pristine state,
749// as no plug-ins were declared. There is no way to unregister a single
750// plug-in, as a single call to cmsPluginTHR() function may register
751// many different plug-ins simultaneously, then there is no way to
752// identify which plug-in to unregister.
753void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
754{
755 _cmsRegisterMemHandlerPlugin(ContextID, NULL);
756 _cmsRegisterInterpPlugin(ContextID, NULL);
757 _cmsRegisterTagTypePlugin(ContextID, NULL);
758 _cmsRegisterTagPlugin(ContextID, NULL);
759 _cmsRegisterFormattersPlugin(ContextID, NULL);
760 _cmsRegisterRenderingIntentPlugin(ContextID, NULL);
761 _cmsRegisterParametricCurvesPlugin(ContextID, NULL);
762 _cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
763 _cmsRegisterOptimizationPlugin(ContextID, NULL);
764 _cmsRegisterTransformPlugin(ContextID, NULL);
765 _cmsRegisterMutexPlugin(ContextID, NULL);
766}
767
768
769// Returns the memory manager plug-in, if any, from the Plug-in bundle
770static
771cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
772{
773 cmsPluginBase* Plugin;
774
775 for (Plugin = (cmsPluginBase*) PluginBundle;
776 Plugin != NULL;
777 Plugin = Plugin -> Next) {
778
779 if (Plugin -> Magic == cmsPluginMagicNumber &&
780 Plugin -> ExpectedVersion <= LCMS_VERSION &&
781 Plugin -> Type == cmsPluginMemHandlerSig) {
782
783 // Found!
784 return (cmsPluginMemHandler*) Plugin;
785 }
786 }
787
788 // Nope, revert to defaults
789 return NULL;
790}
791
792
793// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
794// data that will be forwarded to plug-ins and logger.
795cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
796{
797 struct _cmsContext_struct* ctx;
798 struct _cmsContext_struct fakeContext;
799
800 // See the comments regarding locking in lcms2_internal.h
801 // for an explanation of why we need the following code.
802#ifdef CMS_IS_WINDOWS_
803#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
804 {
805 static HANDLE _cmsWindowsInitMutex = NULL;
806 static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
807
808 if (*mutex == NULL)
809 {
810 HANDLE p = CreateMutex(NULL, FALSE, NULL);
811 if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL)
812 CloseHandle(p);
813 }
814 if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
815 return NULL;
816 if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL)
817 InitializeCriticalSection(&_cmsContextPoolHeadMutex);
818 if (*mutex == NULL || !ReleaseMutex(*mutex))
819 return NULL;
820 }
821#endif
822#endif
823
824 _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
825
826 fakeContext.chunks[UserPtr] = UserData;
827 fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
828
829 // Create the context structure.
830 ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
831 if (ctx == NULL)
832 return NULL; // Something very wrong happened!
833
834 // Init the structure and the memory manager
835 memset(ctx, 0, sizeof(struct _cmsContext_struct));
836
837 // Keep memory manager
838 memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
839
840 // Maintain the linked list (with proper locking)
841 _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
842 ctx ->Next = _cmsContextPoolHead;
843 _cmsContextPoolHead = ctx;
844 _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
845
846 ctx ->chunks[UserPtr] = UserData;
847 ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
848
849 // Now we can allocate the pool by using default memory manager
850 ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 22 pointers
851 if (ctx ->MemPool == NULL) {
852
853 cmsDeleteContext(ctx);
854 return NULL;
855 }
856
857 _cmsAllocLogErrorChunk(ctx, NULL);
858 _cmsAllocAlarmCodesChunk(ctx, NULL);
859 _cmsAllocAdaptationStateChunk(ctx, NULL);
860 _cmsAllocMemPluginChunk(ctx, NULL);
861 _cmsAllocInterpPluginChunk(ctx, NULL);
862 _cmsAllocCurvesPluginChunk(ctx, NULL);
863 _cmsAllocFormattersPluginChunk(ctx, NULL);
864 _cmsAllocTagTypePluginChunk(ctx, NULL);
865 _cmsAllocMPETypePluginChunk(ctx, NULL);
866 _cmsAllocTagPluginChunk(ctx, NULL);
867 _cmsAllocIntentsPluginChunk(ctx, NULL);
868 _cmsAllocOptimizationPluginChunk(ctx, NULL);
869 _cmsAllocTransformPluginChunk(ctx, NULL);
870 _cmsAllocMutexPluginChunk(ctx, NULL);
871
872 // Setup the plug-ins
873 if (!cmsPluginTHR(ctx, Plugin)) {
874
875 cmsDeleteContext(ctx);
876 return NULL;
877 }
878
879 return (cmsContext) ctx;
880}
881
882// Duplicates a context with all associated plug-ins.
883// Caller may specify an optional pointer to user-defined
884// data that will be forwarded to plug-ins and logger.
885cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
886{
887 int i;
888 struct _cmsContext_struct* ctx;
889 const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
890
891 void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
892
893
894 ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
895 if (ctx == NULL)
896 return NULL; // Something very wrong happened
897
898 // Setup default memory allocators
899 memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
900
901 // Maintain the linked list
902 _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
903 ctx ->Next = _cmsContextPoolHead;
904 _cmsContextPoolHead = ctx;
905 _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
906
907 ctx ->chunks[UserPtr] = userData;
908 ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
909
910 ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
911 if (ctx ->MemPool == NULL) {
912
913 cmsDeleteContext(ctx);
914 return NULL;
915 }
916
917 // Allocate all required chunks.
918 _cmsAllocLogErrorChunk(ctx, src);
919 _cmsAllocAlarmCodesChunk(ctx, src);
920 _cmsAllocAdaptationStateChunk(ctx, src);
921 _cmsAllocMemPluginChunk(ctx, src);
922 _cmsAllocInterpPluginChunk(ctx, src);
923 _cmsAllocCurvesPluginChunk(ctx, src);
924 _cmsAllocFormattersPluginChunk(ctx, src);
925 _cmsAllocTagTypePluginChunk(ctx, src);
926 _cmsAllocMPETypePluginChunk(ctx, src);
927 _cmsAllocTagPluginChunk(ctx, src);
928 _cmsAllocIntentsPluginChunk(ctx, src);
929 _cmsAllocOptimizationPluginChunk(ctx, src);
930 _cmsAllocTransformPluginChunk(ctx, src);
931 _cmsAllocMutexPluginChunk(ctx, src);
932
933 // Make sure no one failed
934 for (i=Logger; i < MemoryClientMax; i++) {
935
936 if (src ->chunks[i] == NULL) {
937 cmsDeleteContext((cmsContext) ctx);
938 return NULL;
939 }
940 }
941
942 return (cmsContext) ctx;
943}
944
945
946/*
947static
948struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
949{
950 struct _cmsContext_struct* prev;
951
952 // Search for previous
953 for (prev = _cmsContextPoolHead;
954 prev != NULL;
955 prev = prev ->Next)
956 {
957 if (prev ->Next == id)
958 return prev;
959 }
960
961 return NULL; // List is empty or only one element!
962}
963*/
964
965// Frees any resources associated with the given context,
966// and destroys the context placeholder.
967// The ContextID can no longer be used in any THR operation.
968void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
969{
970 if (ContextID != NULL) {
971
972 struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
973 struct _cmsContext_struct fakeContext;
974 struct _cmsContext_struct* prev;
975
976 memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
977
978 fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
979 fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
980
981 // Get rid of plugins
982 cmsUnregisterPluginsTHR(ContextID);
983
984 // Since all memory is allocated in the private pool, all what we need to do is destroy the pool
985 if (ctx -> MemPool != NULL)
986 _cmsSubAllocDestroy(ctx ->MemPool);
987 ctx -> MemPool = NULL;
988
989 // Maintain list
990 _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
991 if (_cmsContextPoolHead == ctx) {
992
993 _cmsContextPoolHead = ctx->Next;
994 }
995 else {
996
997 // Search for previous
998 for (prev = _cmsContextPoolHead;
999 prev != NULL;
1000 prev = prev ->Next)
1001 {
1002 if (prev -> Next == ctx) {
1003 prev -> Next = ctx ->Next;
1004 break;
1005 }
1006 }
1007 }
1008 _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
1009
1010 // free the memory block itself
1011 _cmsFree(&fakeContext, ctx);
1012 }
1013}
1014
1015// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
1016void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
1017{
1018 return _cmsContextGetClientChunk(ContextID, UserPtr);
1019}
1020
1021
1022