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