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