comparison mupdf-source/thirdparty/lcms2/src/cmsplugin.c @ 2:b50eed0cc0ef upstream

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