Coverage Report

Created: 2025-06-24 07:01

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