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