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