cmsio0.c 57.4 KB
Newer Older
D
duke 已提交
1 2 3 4 5
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
6
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
7
 * particular file as subject to the "Classpath" exception as provided
8
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
9 10 11 12 13 14 15 16 17 18 19
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
20 21 22
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
23 24 25 26 27 28 29
 */

// This file is available under and governed by the GNU General Public
// License version 2 only, as published by the Free Software Foundation.
// However, the following notice accompanied the original version of this
// file:
//
30
//---------------------------------------------------------------------------------
D
duke 已提交
31
//
32
//  Little Color Management System
B
bae 已提交
33
//  Copyright (c) 1998-2012 Marti Maria Saguer
D
duke 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
53 54 55 56
//---------------------------------------------------------------------------------
//

#include "lcms2_internal.h"
D
duke 已提交
57 58 59

// Generic I/O, tag dictionary management, profile struct

60 61 62 63
// IOhandlers are abstractions used by littleCMS to read from whatever file, stream,
// memory block or any storage. Each IOhandler provides implementations for read,
// write, seek and tell functions. LittleCMS code deals with IO across those objects.
// In this way, is easier to add support for new storage media.
D
duke 已提交
64

65
// NULL stream, for taking care of used space -------------------------------------
D
duke 已提交
66

67 68 69 70
// NULL IOhandler basically does nothing but keep track on how many bytes have been
// written. This is handy when creating profiles, where the file size is needed in the
// header. Then, whole profile is serialized across NULL IOhandler and a second pass
// writes the bytes to the pertinent IOhandler.
D
duke 已提交
71

72 73 74
typedef struct {
    cmsUInt32Number Pointer;         // Points to current location
} FILENULL;
D
duke 已提交
75

76 77 78 79
static
cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
{
    FILENULL* ResData = (FILENULL*) iohandler ->stream;
D
duke 已提交
80

81 82 83
    cmsUInt32Number len = size * count;
    ResData -> Pointer += len;
    return count;
D
duke 已提交
84

85 86
    cmsUNUSED_PARAMETER(Buffer);
}
D
duke 已提交
87 88

static
89
cmsBool  NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
D
duke 已提交
90
{
91
    FILENULL* ResData = (FILENULL*) iohandler ->stream;
92

93 94 95
    ResData ->Pointer = offset;
    return TRUE;
}
D
duke 已提交
96

97 98 99 100 101 102
static
cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler)
{
    FILENULL* ResData = (FILENULL*) iohandler ->stream;
    return ResData -> Pointer;
}
D
duke 已提交
103

104 105 106 107
static
cmsBool  NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Ptr)
{
    FILENULL* ResData = (FILENULL*) iohandler ->stream;
D
duke 已提交
108

109 110 111
    ResData ->Pointer += size;
    if (ResData ->Pointer > iohandler->UsedSpace)
        iohandler->UsedSpace = ResData ->Pointer;
D
duke 已提交
112

113
    return TRUE;
D
duke 已提交
114

115
    cmsUNUSED_PARAMETER(Ptr);
D
duke 已提交
116 117 118
}

static
119
cmsBool  NULLClose(cmsIOHANDLER* iohandler)
D
duke 已提交
120
{
121
    FILENULL* ResData = (FILENULL*) iohandler ->stream;
D
duke 已提交
122

123 124 125 126
    _cmsFree(iohandler ->ContextID, ResData);
    _cmsFree(iohandler ->ContextID, iohandler);
    return TRUE;
}
D
duke 已提交
127

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
// The NULL IOhandler creator
cmsIOHANDLER*  CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID)
{
    struct _cms_io_handler* iohandler = NULL;
    FILENULL* fm = NULL;

    iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler));
    if (iohandler == NULL) return NULL;

    fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL));
    if (fm == NULL) goto Error;

    fm ->Pointer = 0;

    iohandler ->ContextID = ContextID;
    iohandler ->stream  = (void*) fm;
    iohandler ->UsedSpace = 0;
B
bae 已提交
145
    iohandler ->ReportedSize = 0;
146
    iohandler ->PhysicalFile[0] = 0;
D
duke 已提交
147

148 149 150 151 152
    iohandler ->Read    = NULLRead;
    iohandler ->Seek    = NULLSeek;
    iohandler ->Close   = NULLClose;
    iohandler ->Tell    = NULLTell;
    iohandler ->Write   = NULLWrite;
153

154
    return iohandler;
D
duke 已提交
155

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
Error:
    if (iohandler) _cmsFree(ContextID, iohandler);
    return NULL;

}


// Memory-based stream --------------------------------------------------------------

// Those functions implements an iohandler which takes a block of memory as storage medium.

typedef struct {
    cmsUInt8Number* Block;    // Points to allocated memory
    cmsUInt32Number Size;     // Size of allocated memory
    cmsUInt32Number Pointer;  // Points to current location
    int FreeBlockOnClose;     // As title

} FILEMEM;

static
cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
{
    FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
    cmsUInt8Number* Ptr;
    cmsUInt32Number len = size * count;

    if (ResData -> Pointer + len > ResData -> Size){

        len = (ResData -> Size - ResData -> Pointer);
        cmsSignalError(iohandler ->ContextID, cmsERROR_READ, "Read from memory error. Got %d bytes, block should be of %d bytes", len, count * size);
        return 0;
    }
D
duke 已提交
188 189 190

    Ptr  = ResData -> Block;
    Ptr += ResData -> Pointer;
191 192
    memmove(Buffer, Ptr, len);
    ResData -> Pointer += len;
D
duke 已提交
193 194 195 196 197 198

    return count;
}

// SEEK_CUR is assumed
static
199
cmsBool  MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset)
D
duke 已提交
200
{
201
    FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
D
duke 已提交
202 203

    if (offset > ResData ->Size) {
204 205
        cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK,  "Too few data; probably corrupted profile");
        return FALSE;
D
duke 已提交
206 207
    }

208 209
    ResData ->Pointer = offset;
    return TRUE;
D
duke 已提交
210 211
}

212
// Tell for memory
D
duke 已提交
213
static
214
cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler)
D
duke 已提交
215
{
216
    FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
D
duke 已提交
217

218
    if (ResData == NULL) return 0;
D
duke 已提交
219 220 221 222
    return ResData -> Pointer;
}


223
// Writes data to memory, also keeps used space for further reference.
D
duke 已提交
224
static
P
prr 已提交
225
cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr)
D
duke 已提交
226
{
227 228 229 230
    FILEMEM* ResData = (FILEMEM*) iohandler ->stream;

    if (ResData == NULL) return FALSE; // Housekeeping

P
prr 已提交
231
    // Check for available space. Clip.
P
prr 已提交
232 233
    if (ResData->Pointer + size > ResData->Size) {
        size = ResData ->Size - ResData->Pointer;
P
prr 已提交
234 235
    }

236 237 238 239
    if (size == 0) return TRUE;     // Write zero bytes is ok, but does nothing

    memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
    ResData ->Pointer += size;
D
duke 已提交
240

241 242
    if (ResData ->Pointer > iohandler->UsedSpace)
        iohandler->UsedSpace = ResData ->Pointer;
D
duke 已提交
243

244
    return TRUE;
D
duke 已提交
245 246 247
}


A
avu 已提交
248
static
249
cmsBool  MemoryClose(struct _cms_io_handler* iohandler)
A
avu 已提交
250
{
251
    FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
A
avu 已提交
252

253
    if (ResData ->FreeBlockOnClose) {
254

255 256
        if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block);
    }
257

258 259
    _cmsFree(iohandler ->ContextID, ResData);
    _cmsFree(iohandler ->ContextID, iohandler);
A
avu 已提交
260 261 262 263

    return TRUE;
}

264 265 266 267
// Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes
// a copy of the memory block for letting user to free the memory after invoking open profile. In write
// mode ("w"), Buffere points to the begin of memory block to be written.
cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode)
D
duke 已提交
268
{
269 270
    cmsIOHANDLER* iohandler = NULL;
    FILEMEM* fm = NULL;
D
duke 已提交
271

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
    _cmsAssert(AccessMode != NULL);

    iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
    if (iohandler == NULL) return NULL;

    switch (*AccessMode) {

    case 'r':
        fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM));
        if (fm == NULL) goto Error;

        if (Buffer == NULL) {
            cmsSignalError(ContextID, cmsERROR_READ, "Couldn't read profile from NULL pointer");
            goto Error;
        }

        fm ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, size);
        if (fm ->Block == NULL) {
D
duke 已提交
290

291 292 293 294 295 296 297 298 299 300 301
            _cmsFree(ContextID, fm);
            _cmsFree(ContextID, iohandler);
            cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", size);
            return NULL;
        }


        memmove(fm->Block, Buffer, size);
        fm ->FreeBlockOnClose = TRUE;
        fm ->Size    = size;
        fm ->Pointer = 0;
B
bae 已提交
302
        iohandler -> ReportedSize = size;
303 304 305 306 307 308 309 310 311 312
        break;

    case 'w':
        fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM));
        if (fm == NULL) goto Error;

        fm ->Block = (cmsUInt8Number*) Buffer;
        fm ->FreeBlockOnClose = FALSE;
        fm ->Size    = size;
        fm ->Pointer = 0;
B
bae 已提交
313
        iohandler -> ReportedSize = 0;
314 315 316
        break;

    default:
B
bae 已提交
317
        cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown access mode '%c'", *AccessMode);
318
        return NULL;
D
duke 已提交
319 320
    }

321 322 323 324
    iohandler ->ContextID = ContextID;
    iohandler ->stream  = (void*) fm;
    iohandler ->UsedSpace = 0;
    iohandler ->PhysicalFile[0] = 0;
D
duke 已提交
325

326 327 328 329 330
    iohandler ->Read    = MemoryRead;
    iohandler ->Seek    = MemorySeek;
    iohandler ->Close   = MemoryClose;
    iohandler ->Tell    = MemoryTell;
    iohandler ->Write   = MemoryWrite;
D
duke 已提交
331

332 333 334 335 336 337
    return iohandler;

Error:
    if (fm) _cmsFree(ContextID, fm);
    if (iohandler) _cmsFree(ContextID, iohandler);
    return NULL;
D
duke 已提交
338 339
}

340 341 342
// File-based stream -------------------------------------------------------

// Read count elements of size bytes each. Return number of elements read
D
duke 已提交
343
static
344
cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
D
duke 已提交
345
{
346 347
    cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream);

D
duke 已提交
348
    if (nReaded != count) {
349
            cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
D
duke 已提交
350 351 352 353 354 355
            return 0;
    }

    return nReaded;
}

P
prr 已提交
356
// Postion file pointer in the file
D
duke 已提交
357
static
358
cmsBool  FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
D
duke 已提交
359
{
360
    if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) {
D
duke 已提交
361

362 363
       cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file");
       return FALSE;
D
duke 已提交
364 365
    }

366
    return TRUE;
D
duke 已提交
367 368
}

369
// Returns file pointer position
D
duke 已提交
370
static
371
cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
D
duke 已提交
372
{
P
prr 已提交
373
    return (cmsUInt32Number) ftell((FILE*)iohandler ->stream);
D
duke 已提交
374 375
}

376 377 378 379 380
// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error
static
cmsBool  FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer)
{
       if (size == 0) return TRUE;  // We allow to write 0 bytes, but nothing is written
D
duke 已提交
381

382 383 384
       iohandler->UsedSpace += size;
       return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1);
}
D
duke 已提交
385

386
// Closes the file
D
duke 已提交
387
static
388
cmsBool  FileClose(cmsIOHANDLER* iohandler)
D
duke 已提交
389
{
390 391 392 393
    if (fclose((FILE*) iohandler ->stream) != 0) return FALSE;
    _cmsFree(iohandler ->ContextID, iohandler);
    return TRUE;
}
D
duke 已提交
394

P
prr 已提交
395
// Create a iohandler for disk based files.
396 397 398 399
cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode)
{
    cmsIOHANDLER* iohandler = NULL;
    FILE* fm = NULL;
D
duke 已提交
400

P
prr 已提交
401 402 403
    _cmsAssert(FileName != NULL);
    _cmsAssert(AccessMode != NULL);

404 405
    iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
    if (iohandler == NULL) return NULL;
D
duke 已提交
406

407
    switch (*AccessMode) {
D
duke 已提交
408

409 410 411 412 413 414 415
    case 'r':
        fm = fopen(FileName, "rb");
        if (fm == NULL) {
            _cmsFree(ContextID, iohandler);
             cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
            return NULL;
        }
P
prr 已提交
416
        iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm);
417
        break;
D
duke 已提交
418

419 420 421 422 423 424 425
    case 'w':
        fm = fopen(FileName, "wb");
        if (fm == NULL) {
            _cmsFree(ContextID, iohandler);
             cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
            return NULL;
        }
B
bae 已提交
426
        iohandler -> ReportedSize = 0;
427
        break;
D
duke 已提交
428

429 430
    default:
        _cmsFree(ContextID, iohandler);
B
bae 已提交
431
         cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode);
432 433 434 435 436 437 438 439
        return NULL;
    }

    iohandler ->ContextID = ContextID;
    iohandler ->stream = (void*) fm;
    iohandler ->UsedSpace = 0;

    // Keep track of the original file
P
prr 已提交
440 441
    strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
    iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
442 443 444 445 446 447 448 449 450 451 452 453

    iohandler ->Read    = FileRead;
    iohandler ->Seek    = FileSeek;
    iohandler ->Close   = FileClose;
    iohandler ->Tell    = FileTell;
    iohandler ->Write   = FileWrite;

    return iohandler;
}

// Create a iohandler for stream based files
cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream)
A
avu 已提交
454
{
455 456 457 458 459 460 461 462
    cmsIOHANDLER* iohandler = NULL;

    iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
    if (iohandler == NULL) return NULL;

    iohandler -> ContextID = ContextID;
    iohandler -> stream = (void*) Stream;
    iohandler -> UsedSpace = 0;
P
prr 已提交
463
    iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream);
464 465 466 467 468 469 470 471 472
    iohandler -> PhysicalFile[0] = 0;

    iohandler ->Read    = FileRead;
    iohandler ->Seek    = FileSeek;
    iohandler ->Close   = FileClose;
    iohandler ->Tell    = FileTell;
    iohandler ->Write   = FileWrite;

    return iohandler;
A
avu 已提交
473 474 475
}


476 477 478

// Close an open IO handler
cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
D
duke 已提交
479
{
480
    return io -> Close(io);
D
duke 已提交
481 482
}

483
// -------------------------------------------------------------------------------------------------------
D
duke 已提交
484 485

// Creates an empty structure holding all required parameters
486
cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
D
duke 已提交
487
{
488 489
    time_t now = time(NULL);
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
D
duke 已提交
490 491
    if (Icc == NULL) return NULL;

492
    Icc ->ContextID = ContextID;
D
duke 已提交
493 494 495 496

    // Set it to empty
    Icc -> TagCount   = 0;

497 498 499 500 501 502
    // Set default version
    Icc ->Version =  0x02100000;

    // Set creation date/time
    memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));

P
prr 已提交
503 504 505
    // Create a mutex if the user provided proper plugin. NULL otherwise
    Icc ->UsrMutex = _cmsCreateMutex(ContextID);

D
duke 已提交
506 507 508 509
    // Return the handle
    return (cmsHPROFILE) Icc;
}

510 511 512 513 514 515 516 517
cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
{
     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;

    if (Icc == NULL) return NULL;
    return Icc -> ContextID;
}

D
duke 已提交
518 519

// Return the number of tags
520
cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile)
D
duke 已提交
521
{
522 523 524
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    if (Icc == NULL) return -1;

D
duke 已提交
525 526 527 528
    return  Icc->TagCount;
}

// Return the tag signature of a given tag number
529
cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n)
D
duke 已提交
530
{
531
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
D
duke 已提交
532

533 534
    if (n > Icc->TagCount) return (cmsTagSignature) 0;  // Mark as not available
    if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check
D
duke 已提交
535 536 537 538 539

    return Icc ->TagNames[n];
}


540 541
static
int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig)
D
duke 已提交
542
{
543
    cmsUInt32Number i;
D
duke 已提交
544

545
    for (i=0; i < Profile -> TagCount; i++) {
D
duke 已提交
546

547 548 549
        if (sig == Profile -> TagNames[i])
            return i;
    }
D
duke 已提交
550

551 552
    return -1;
}
D
duke 已提交
553

554 555 556 557 558 559
// Search for a specific tag in tag dictionary. Returns position or -1 if tag not found.
// If followlinks is turned on, then the position of the linked tag is returned
int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks)
{
    int n;
    cmsTagSignature LinkedSig;
D
duke 已提交
560

561
    do {
D
duke 已提交
562

563 564 565 566
        // Search for given tag in ICC profile directory
        n = SearchOneTag(Icc, sig);
        if (n < 0)
            return -1;        // Not found
D
duke 已提交
567

568 569
        if (!lFollowLinks)
            return n;         // Found, don't follow links
D
duke 已提交
570

571 572
        // Is this a linked tag?
        LinkedSig = Icc ->TagLinked[n];
D
duke 已提交
573

574 575 576 577 578 579 580 581 582
        // Yes, follow link
        if (LinkedSig != (cmsTagSignature) 0) {
            sig = LinkedSig;
        }

    } while (LinkedSig != (cmsTagSignature) 0);

    return n;
}
D
duke 已提交
583

P
prr 已提交
584 585 586 587 588 589 590 591
// Deletes a tag entry

static
void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i)
{
    _cmsAssert(Icc != NULL);
    _cmsAssert(i >= 0);

D
duke 已提交
592

P
prr 已提交
593
    if (Icc -> TagPtrs[i] != NULL) {
D
duke 已提交
594

P
prr 已提交
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
        // Free previous version
        if (Icc ->TagSaveAsRaw[i]) {
            _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
        }
        else {
            cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];

            if (TypeHandler != NULL) {

                cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
                LocalTypeHandler.ContextID = Icc ->ContextID;              // As an additional parameter
                LocalTypeHandler.ICCVersion = Icc ->Version;
                LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
                Icc ->TagPtrs[i] = NULL;
            }
        }

    }
}


// Creates a new tag entry
617 618
static
cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
D
duke 已提交
619
{
620
    int i;
D
duke 已提交
621

622
    // Search for the tag
D
duke 已提交
623
    i = _cmsSearchTag(Icc, sig, FALSE);
624
    if (i >= 0) {
P
prr 已提交
625 626 627 628

        // Already exists? delete it
        _cmsDeleteTagByPos(Icc, i);
        *NewPos = i;
D
duke 已提交
629 630 631
    }
    else  {

P
prr 已提交
632
        // No, make a new one
D
duke 已提交
633

634 635 636
        if (Icc -> TagCount >= MAX_TABLE_TAG) {
            cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
            return FALSE;
D
duke 已提交
637
        }
638

639 640 641
        *NewPos = Icc ->TagCount;
        Icc -> TagCount++;
    }
D
duke 已提交
642

643
    return TRUE;
D
duke 已提交
644 645 646
}


647 648 649 650 651 652
// Check existance
cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig)
{
       _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) (void*) hProfile;
       return _cmsSearchTag(Icc, sig, FALSE) >= 0;
}
D
duke 已提交
653

P
prr 已提交
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
/*
 * Enforces that the profile version is per. spec.
 * Operates on the big endian bytes from the profile.
 * Called before converting to platform endianness.
 * Byte 0 is BCD major version, so max 9.
 * Byte 1 is 2 BCD digits, one per nibble.
 * Reserved bytes 2 & 3 must be 0.
 */
static cmsUInt32Number _validatedVersion(cmsUInt32Number DWord)
{
    cmsUInt8Number* pByte = (cmsUInt8Number*)&DWord;
    cmsUInt8Number temp1;
    cmsUInt8Number temp2;

    if (*pByte > 0x09) *pByte = (cmsUInt8Number)9;
    temp1 = *(pByte+1) & 0xf0;
    temp2 = *(pByte+1) & 0x0f;
    if (temp1 > 0x90) temp1 = 0x90;
    if (temp2 > 9) temp2 = 0x09;
    *(pByte+1) = (cmsUInt8Number)(temp1 | temp2);
    *(pByte+2) = (cmsUInt8Number)0;
    *(pByte+3) = (cmsUInt8Number)0;

    return DWord;
}
D
duke 已提交
679

680 681
// Read profile header and validate it
cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
D
duke 已提交
682
{
683 684 685 686 687 688
    cmsTagEntry Tag;
    cmsICCHeader Header;
    cmsUInt32Number i, j;
    cmsUInt32Number HeaderSize;
    cmsIOHANDLER* io = Icc ->IOhandler;
    cmsUInt32Number TagCount;
D
duke 已提交
689 690


691 692 693
    // Read the header
    if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) {
        return FALSE;
D
duke 已提交
694 695
    }

696 697 698 699 700
    // Validate file as an ICC profile
    if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) {
        cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature");
        return FALSE;
    }
D
duke 已提交
701

702 703 704 705
    // Adjust endianess of the used parameters
    Icc -> DeviceClass     = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
    Icc -> ColorSpace      = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.colorSpace);
    Icc -> PCS             = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.pcs);
P
prr 已提交
706

707 708 709 710
    Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
    Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
    Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
    Icc -> model           = _cmsAdjustEndianess32(Header.model);
P
prr 已提交
711 712
    Icc -> creator         = _cmsAdjustEndianess32(Header.creator);

B
bae 已提交
713
    _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes);
P
prr 已提交
714
    Icc -> Version         = _cmsAdjustEndianess32(_validatedVersion(Header.version));
715

716 717
    // Get size as reported in header
    HeaderSize = _cmsAdjustEndianess32(Header.size);
D
duke 已提交
718

B
bae 已提交
719 720 721 722 723
    // Make sure HeaderSize is lower than profile size
    if (HeaderSize >= Icc ->IOhandler ->ReportedSize)
            HeaderSize = Icc ->IOhandler ->ReportedSize;


724 725
    // Get creation date/time
    _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created);
D
duke 已提交
726

727 728
    // The profile ID are 32 raw bytes
    memmove(Icc ->ProfileID.ID32, Header.profileID.ID32, 16);
D
duke 已提交
729 730


731 732 733
    // Read tag directory
    if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE;
    if (TagCount > MAX_TABLE_TAG) {
D
duke 已提交
734

735 736 737
        cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount);
        return FALSE;
    }
D
duke 已提交
738

B
bae 已提交
739

740 741 742
    // Read tag directory
    Icc -> TagCount = 0;
    for (i=0; i < TagCount; i++) {
D
duke 已提交
743

744 745 746
        if (!_cmsReadUInt32Number(io, (cmsUInt32Number *) &Tag.sig)) return FALSE;
        if (!_cmsReadUInt32Number(io, &Tag.offset)) return FALSE;
        if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE;
D
duke 已提交
747

748
        // Perform some sanity check. Offset + size should fall inside file.
B
bae 已提交
749 750
        if (Tag.offset + Tag.size > HeaderSize ||
            Tag.offset + Tag.size < Tag.offset)
751
                  continue;
D
duke 已提交
752

753 754 755
        Icc -> TagNames[Icc ->TagCount]   = Tag.sig;
        Icc -> TagOffsets[Icc ->TagCount] = Tag.offset;
        Icc -> TagSizes[Icc ->TagCount]   = Tag.size;
D
duke 已提交
756

757 758
       // Search for links
        for (j=0; j < Icc ->TagCount; j++) {
D
duke 已提交
759

760 761
            if ((Icc ->TagOffsets[j] == Tag.offset) &&
                (Icc ->TagSizes[j]   == Tag.size)) {
D
duke 已提交
762

763 764
                Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j];
            }
D
duke 已提交
765

766 767 768
        }

        Icc ->TagCount++;
D
duke 已提交
769 770
    }

771 772
    return TRUE;
}
D
duke 已提交
773

774 775 776 777 778 779 780
// Saves profile header
cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
{
    cmsICCHeader Header;
    cmsUInt32Number i;
    cmsTagEntry Tag;
    cmsInt32Number Count = 0;
D
duke 已提交
781

782 783 784
    Header.size        = _cmsAdjustEndianess32(UsedSpace);
    Header.cmmId       = _cmsAdjustEndianess32(lcmsSignature);
    Header.version     = _cmsAdjustEndianess32(Icc ->Version);
D
duke 已提交
785

786 787 788
    Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass);
    Header.colorSpace  = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> ColorSpace);
    Header.pcs         = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> PCS);
D
duke 已提交
789

790 791
    //   NOTE: in v4 Timestamp must be in UTC rather than in local time
    _cmsEncodeDateTimeNumber(&Header.date, &Icc ->Created);
D
duke 已提交
792

793
    Header.magic       = _cmsAdjustEndianess32(cmsMagicNumber);
D
duke 已提交
794

795 796 797 798 799
#ifdef CMS_IS_WINDOWS_
    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft);
#else
    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh);
#endif
D
duke 已提交
800

801 802 803
    Header.flags        = _cmsAdjustEndianess32(Icc -> flags);
    Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
    Header.model        = _cmsAdjustEndianess32(Icc -> model);
D
duke 已提交
804

B
bae 已提交
805
    _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes);
D
duke 已提交
806

807 808
    // Rendering intent in the header (for embedded profiles)
    Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
D
duke 已提交
809

810 811 812 813
    // Illuminant is always D50
    Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
    Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
    Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
D
duke 已提交
814

815 816
    // Created by LittleCMS (that's me!)
    Header.creator      = _cmsAdjustEndianess32(lcmsSignature);
D
duke 已提交
817

818
    memset(&Header.reserved, 0, sizeof(Header.reserved));
D
duke 已提交
819

820 821
    // Set profile ID. Endianess is always big endian
    memmove(&Header.profileID, &Icc ->ProfileID, 16);
D
duke 已提交
822

823 824
    // Dump the header
    if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE;
D
duke 已提交
825

826
    // Saves Tag directory
D
duke 已提交
827

828 829 830 831 832
    // Get true count
    for (i=0;  i < Icc -> TagCount; i++) {
        if (Icc ->TagNames[i] != 0)
            Count++;
    }
D
duke 已提交
833

834 835
    // Store number of tags
    if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE;
D
duke 已提交
836

837
    for (i=0; i < Icc -> TagCount; i++) {
D
duke 已提交
838

839 840 841 842 843
        if (Icc ->TagNames[i] == 0) continue;   // It is just a placeholder

        Tag.sig    = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]);
        Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]);
        Tag.size   = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]);
D
duke 已提交
844

845
        if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE;
D
duke 已提交
846 847
    }

848
    return TRUE;
D
duke 已提交
849 850 851 852 853
}

// ----------------------------------------------------------------------- Set/Get several struct members


854 855 856 857 858
cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return Icc -> RenderingIntent;
}
D
duke 已提交
859

860 861 862 863 864
void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    Icc -> RenderingIntent = RenderingIntent;
}
D
duke 已提交
865

866
cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile)
D
duke 已提交
867
{
868 869
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return (cmsUInt32Number) Icc -> flags;
D
duke 已提交
870 871
}

872 873 874 875 876
void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    Icc -> flags = (cmsUInt32Number) Flags;
}
D
duke 已提交
877

878
cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile)
D
duke 已提交
879
{
880
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
P
prr 已提交
881
    return Icc ->manufacturer;
D
duke 已提交
882 883
}

884
void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer)
D
duke 已提交
885
{
886
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
P
prr 已提交
887 888 889 890 891 892 893
    Icc -> manufacturer = manufacturer;
}

cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return Icc ->creator;
D
duke 已提交
894 895
}

896
cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile)
D
duke 已提交
897
{
898
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
P
prr 已提交
899
    return Icc ->model;
D
duke 已提交
900 901
}

902
void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model)
D
duke 已提交
903
{
904
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
P
prr 已提交
905
    Icc -> model = model;
D
duke 已提交
906 907
}

908
void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags)
D
duke 已提交
909
{
910 911
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    memmove(Flags, &Icc -> attributes, sizeof(cmsUInt64Number));
D
duke 已提交
912 913
}

914
void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags)
D
duke 已提交
915
{
916 917
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    memmove(&Icc -> attributes, &Flags, sizeof(cmsUInt64Number));
D
duke 已提交
918 919
}

920
void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID)
D
duke 已提交
921
{
922 923
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    memmove(ProfileID, Icc ->ProfileID.ID8, 16);
D
duke 已提交
924 925
}

926
void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID)
D
duke 已提交
927
{
928 929
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    memmove(&Icc -> ProfileID, ProfileID, 16);
D
duke 已提交
930 931
}

932 933 934 935 936 937
cmsBool  CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    memmove(Dest, &Icc ->Created, sizeof(struct tm));
    return TRUE;
}
D
duke 已提交
938

939
cmsColorSpaceSignature CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile)
D
duke 已提交
940
{
941 942
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return Icc -> PCS;
D
duke 已提交
943 944
}

945
void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs)
D
duke 已提交
946
{
947 948
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    Icc -> PCS = pcs;
D
duke 已提交
949 950
}

951 952 953 954 955
cmsColorSpaceSignature CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return Icc -> ColorSpace;
}
D
duke 已提交
956

957
void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig)
D
duke 已提交
958
{
959 960
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    Icc -> ColorSpace = sig;
D
duke 已提交
961 962
}

963 964 965 966 967
cmsProfileClassSignature CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return Icc -> DeviceClass;
}
D
duke 已提交
968

969
void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig)
D
duke 已提交
970
{
971 972
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    Icc -> DeviceClass = sig;
D
duke 已提交
973 974
}

975 976 977 978 979
cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile)
{
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    return Icc -> Version;
}
D
duke 已提交
980

981
void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version)
D
duke 已提交
982
{
983 984
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    Icc -> Version = Version;
D
duke 已提交
985 986
}

987 988 989
// Get an hexadecimal number with same digits as v
static
cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut)
D
duke 已提交
990
{
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
    char Buff[100];
    int i, len;
    cmsUInt32Number out;

    for (len=0; in > 0 && len < 100; len++) {

        Buff[len] = (char) (in % BaseIn);
        in /= BaseIn;
    }

    for (i=len-1, out=0; i >= 0; --i) {
        out = out * BaseOut + Buff[i];
    }

    return out;
D
duke 已提交
1006 1007
}

1008
void  CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version)
D
duke 已提交
1009
{
1010 1011 1012 1013
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;

    // 4.2 -> 0x4200000

P
prr 已提交
1014
    Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16;
D
duke 已提交
1015 1016
}

1017
cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile)
D
duke 已提交
1018
{
1019 1020 1021 1022
    _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
    cmsUInt32Number n = Icc -> Version >> 16;

    return BaseToBase(n, 16, 10) / 100.0;
D
duke 已提交
1023
}
1024 1025
// --------------------------------------------------------------------------------------------------------------

D
duke 已提交
1026

1027 1028
// Create profile from IOhandler
cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io)
D
duke 已提交
1029
{
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    _cmsICCPROFILE* NewIcc;
    cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);

    if (hEmpty == NULL) return NULL;

    NewIcc = (_cmsICCPROFILE*) hEmpty;

    NewIcc ->IOhandler = io;
    if (!_cmsReadHeader(NewIcc)) goto Error;
    return hEmpty;

Error:
    cmsCloseProfile(hEmpty);
    return NULL;
D
duke 已提交
1044 1045
}

P
prr 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
// Create profile from IOhandler
cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write)
{
    _cmsICCPROFILE* NewIcc;
    cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);

    if (hEmpty == NULL) return NULL;

    NewIcc = (_cmsICCPROFILE*) hEmpty;

    NewIcc ->IOhandler = io;
    if (write) {

        NewIcc -> IsWrite = TRUE;
        return hEmpty;
    }

    if (!_cmsReadHeader(NewIcc)) goto Error;
    return hEmpty;

Error:
    cmsCloseProfile(hEmpty);
    return NULL;
}


1072 1073
// Create profile from disk file
cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess)
D
duke 已提交
1074
{
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
    _cmsICCPROFILE* NewIcc;
    cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);

    if (hEmpty == NULL) return NULL;

    NewIcc = (_cmsICCPROFILE*) hEmpty;

    NewIcc ->IOhandler = cmsOpenIOhandlerFromFile(ContextID, lpFileName, sAccess);
    if (NewIcc ->IOhandler == NULL) goto Error;

    if (*sAccess == 'W' || *sAccess == 'w') {

        NewIcc -> IsWrite = TRUE;

        return hEmpty;
    }

    if (!_cmsReadHeader(NewIcc)) goto Error;
    return hEmpty;

Error:
    cmsCloseProfile(hEmpty);
    return NULL;
D
duke 已提交
1098 1099 1100
}


1101
cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess)
D
duke 已提交
1102
{
1103
    return cmsOpenProfileFromFileTHR(NULL, ICCProfile, sAccess);
D
duke 已提交
1104 1105 1106
}


1107 1108 1109 1110
cmsHPROFILE  CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char *sAccess)
{
    _cmsICCPROFILE* NewIcc;
    cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
D
duke 已提交
1111

1112
    if (hEmpty == NULL) return NULL;
D
duke 已提交
1113

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
    NewIcc = (_cmsICCPROFILE*) hEmpty;

    NewIcc ->IOhandler = cmsOpenIOhandlerFromStream(ContextID, ICCProfile);
    if (NewIcc ->IOhandler == NULL) goto Error;

    if (*sAccess == 'w') {

        NewIcc -> IsWrite = TRUE;
        return hEmpty;
    }

    if (!_cmsReadHeader(NewIcc)) goto Error;
    return hEmpty;

Error:
    cmsCloseProfile(hEmpty);
    return NULL;

}

cmsHPROFILE  CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char *sAccess)
D
duke 已提交
1135
{
1136
    return cmsOpenProfileFromStreamTHR(NULL, ICCProfile, sAccess);
D
duke 已提交
1137 1138 1139
}


1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
// Open from memory block
cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* MemPtr, cmsUInt32Number dwSize)
{
    _cmsICCPROFILE* NewIcc;
    cmsHPROFILE hEmpty;

    hEmpty = cmsCreateProfilePlaceholder(ContextID);
    if (hEmpty == NULL) return NULL;

    NewIcc = (_cmsICCPROFILE*) hEmpty;

    // Ok, in this case const void* is casted to void* just because open IO handler
    // shares read and writting modes. Don't abuse this feature!
    NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r");
    if (NewIcc ->IOhandler == NULL) goto Error;

    if (!_cmsReadHeader(NewIcc)) goto Error;

    return hEmpty;

Error:
    cmsCloseProfile(hEmpty);
    return NULL;
}

cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number dwSize)
{
    return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize);
}

J
jchen 已提交
1170 1171 1172
static
cmsBool SanityCheck(_cmsICCPROFILE* profile)
{
1173 1174 1175 1176 1177 1178 1179
    cmsIOHANDLER* io;

    if (!profile) {
        return FALSE;
    }

    io = profile->IOhandler;
J
jchen 已提交
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
    if (!io) {
        return FALSE;
    }

    if (!io->Seek ||
        !(io->Seek==NULLSeek || io->Seek==MemorySeek || io->Seek==FileSeek))
    {
        return FALSE;
    }
    if (!io->Read ||
        !(io->Read==NULLRead || io->Read==MemoryRead || io->Read==FileRead))
    {
        return FALSE;
    }

    return TRUE;
}
1197 1198

// Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig
D
duke 已提交
1199
static
1200
cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
D
duke 已提交
1201
{
1202 1203 1204 1205 1206 1207
    cmsUInt8Number* Data;
    cmsUInt32Number i;
    cmsUInt32Number Begin;
    cmsIOHANDLER* io = Icc ->IOhandler;
    cmsTagDescriptor* TagDescriptor;
    cmsTagTypeSignature TypeBase;
P
prr 已提交
1208
    cmsTagTypeSignature Type;
1209
    cmsTagTypeHandler* TypeHandler;
P
prr 已提交
1210 1211
    cmsFloat64Number   Version = cmsGetProfileVersion((cmsHPROFILE) Icc);
    cmsTagTypeHandler LocalTypeHandler;
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227

    for (i=0; i < Icc -> TagCount; i++) {

        if (Icc ->TagNames[i] == 0) continue;

        // Linked tags are not written
        if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue;

        Icc -> TagOffsets[i] = Begin = io ->UsedSpace;

        Data = (cmsUInt8Number*)  Icc -> TagPtrs[i];

        if (!Data) {

            // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user.
            // In this case a blind copy of the block data is performed
1228
            if (SanityCheck(FileOrig) && Icc -> TagOffsets[i]) {
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262

                cmsUInt32Number TagSize   = FileOrig -> TagSizes[i];
                cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
                void* Mem;

                if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE;

                Mem = _cmsMalloc(Icc ->ContextID, TagSize);
                if (Mem == NULL) return FALSE;

                if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE;
                if (!io ->Write(io, TagSize, Mem)) return FALSE;
                _cmsFree(Icc ->ContextID, Mem);

                Icc -> TagSizes[i] = (io ->UsedSpace - Begin);


                // Align to 32 bit boundary.
                if (! _cmsWriteAlignment(io))
                    return FALSE;
            }

            continue;
        }


        // Should this tag be saved as RAW? If so, tagsizes should be specified in advance (no further cooking is done)
        if (Icc ->TagSaveAsRaw[i]) {

            if (io -> Write(io, Icc ->TagSizes[i], Data) != 1) return FALSE;
        }
        else {

            // Search for support on this tag
P
prr 已提交
1263
            TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]);
1264 1265
            if (TagDescriptor == NULL) continue;                        // Unsupported, ignore it

P
prr 已提交
1266 1267 1268 1269 1270 1271 1272 1273 1274
            if (TagDescriptor ->DecideType != NULL) {

                Type = TagDescriptor ->DecideType(Version, Data);
            }
            else {

                Type = TagDescriptor ->SupportedTypes[0];
            }

P
prr 已提交
1275
            TypeHandler =  _cmsGetTagTypeHandler(Icc->ContextID, Type);
1276 1277 1278 1279 1280 1281

            if (TypeHandler == NULL) {
                cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]);
                continue;
            }

B
bae 已提交
1282
            TypeBase = TypeHandler ->Signature;
1283 1284 1285
            if (!_cmsWriteTypeBase(io, TypeBase))
                return FALSE;

P
prr 已提交
1286 1287 1288 1289
            LocalTypeHandler = *TypeHandler;
            LocalTypeHandler.ContextID  = Icc ->ContextID;
            LocalTypeHandler.ICCVersion = Icc ->Version;
            if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) {
D
duke 已提交
1290

1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
                char String[5];

                _cmsTagSignature2String(String, (cmsTagSignature) TypeBase);
                cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String);
                return FALSE;
            }
        }


        Icc -> TagSizes[i] = (io ->UsedSpace - Begin);

        // Align to 32 bit boundary.
        if (! _cmsWriteAlignment(io))
            return FALSE;
    }


    return TRUE;
D
duke 已提交
1309 1310 1311
}


1312 1313 1314
// Fill the offset and size fields for all linked tags
static
cmsBool SetLinks( _cmsICCPROFILE* Icc)
D
duke 已提交
1315
{
1316
    cmsUInt32Number i;
D
duke 已提交
1317

1318
    for (i=0; i < Icc -> TagCount; i++) {
D
duke 已提交
1319

1320 1321
        cmsTagSignature lnk = Icc ->TagLinked[i];
        if (lnk != (cmsTagSignature) 0) {
D
duke 已提交
1322

1323 1324
            int j = _cmsSearchTag(Icc, lnk, FALSE);
            if (j >= 0) {
D
duke 已提交
1325

1326 1327 1328
                Icc ->TagOffsets[i] = Icc ->TagOffsets[j];
                Icc ->TagSizes[i]   = Icc ->TagSizes[j];
            }
D
duke 已提交
1329

1330 1331
        }
    }
D
duke 已提交
1332

1333
    return TRUE;
D
duke 已提交
1334 1335
}

1336 1337 1338 1339
// Low-level save to IOHANDLER. It returns the number of bytes used to
// store the profile, or zero on error. io may be NULL and in this case
// no data is written--only sizes are calculated
cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io)
D
duke 已提交
1340
{
1341 1342
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    _cmsICCPROFILE Keep;
P
prr 已提交
1343
    cmsIOHANDLER* PrevIO = NULL;
1344 1345 1346
    cmsUInt32Number UsedSpace;
    cmsContext ContextID;

P
prr 已提交
1347 1348
    _cmsAssert(hProfile != NULL);

1349
    memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
D
duke 已提交
1350

1351 1352 1353 1354 1355 1356
    ContextID = cmsGetProfileContextID(hProfile);
    PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID);
    if (PrevIO == NULL) return 0;

    // Pass #1 does compute offsets

P
prr 已提交
1357 1358
    if (!_cmsWriteHeader(Icc, 0)) goto Error;
    if (!SaveTags(Icc, &Keep)) goto Error;
1359 1360 1361 1362 1363 1364

    UsedSpace = PrevIO ->UsedSpace;

    // Pass #2 does save to iohandler

    if (io != NULL) {
P
prr 已提交
1365

1366
        Icc ->IOhandler = io;
P
prr 已提交
1367 1368 1369
        if (!SetLinks(Icc)) goto Error;
        if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error;
        if (!SaveTags(Icc, &Keep)) goto Error;
1370 1371 1372 1373 1374 1375 1376 1377
    }

    memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
    if (!cmsCloseIOhandler(PrevIO)) return 0;

    return UsedSpace;


P
prr 已提交
1378
Error:
1379 1380 1381
    cmsCloseIOhandler(PrevIO);
    memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
    return 0;
D
duke 已提交
1382 1383 1384
}


1385 1386
// Low-level save to disk.
cmsBool  CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName)
D
duke 已提交
1387
{
1388 1389 1390
    cmsContext ContextID = cmsGetProfileContextID(hProfile);
    cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w");
    cmsBool rc;
D
duke 已提交
1391

1392 1393 1394 1395 1396 1397 1398 1399 1400
    if (io == NULL) return FALSE;

    rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
    rc &= cmsCloseIOhandler(io);

    if (rc == FALSE) {          // remove() is C99 per 7.19.4.1
            remove(FileName);   // We have to IGNORE return value in this case
    }
    return rc;
D
duke 已提交
1401 1402
}

1403 1404
// Same as anterior, but for streams
cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream)
D
duke 已提交
1405
{
1406 1407 1408
    cmsBool rc;
    cmsContext ContextID = cmsGetProfileContextID(hProfile);
    cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream);
D
duke 已提交
1409

1410 1411 1412 1413 1414 1415
    if (io == NULL) return FALSE;

    rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
    rc &= cmsCloseIOhandler(io);

    return rc;
D
duke 已提交
1416 1417 1418
}


1419 1420
// Same as anterior, but for memory blocks. In this case, a NULL as MemPtr means calculate needed space only
cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded)
D
duke 已提交
1421
{
1422 1423 1424
    cmsBool rc;
    cmsIOHANDLER* io;
    cmsContext ContextID = cmsGetProfileContextID(hProfile);
D
duke 已提交
1425

P
prr 已提交
1426 1427
    _cmsAssert(BytesNeeded != NULL);

1428 1429 1430
    // Should we just calculate the needed space?
    if (MemPtr == NULL) {

P
prr 已提交
1431
           *BytesNeeded =  cmsSaveProfileToIOhandler(hProfile, NULL);
P
prr 已提交
1432
            return (*BytesNeeded == 0) ? FALSE : TRUE;
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
    }

    // That is a real write operation
    io =  cmsOpenIOhandlerFromMem(ContextID, MemPtr, *BytesNeeded, "w");
    if (io == NULL) return FALSE;

    rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
    rc &= cmsCloseIOhandler(io);

    return rc;
D
duke 已提交
1443 1444 1445
}


1446 1447 1448

// Closes a profile freeing any involved resources
cmsBool  CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
D
duke 已提交
1449
{
1450 1451 1452
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    cmsBool  rc = TRUE;
    cmsUInt32Number i;
D
duke 已提交
1453

1454 1455 1456 1457 1458 1459 1460 1461
    if (!Icc) return FALSE;

    // Was open in write mode?
    if (Icc ->IsWrite) {

        Icc ->IsWrite = FALSE;      // Assure no further writting
        rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile);
    }
D
duke 已提交
1462

1463 1464 1465 1466 1467 1468
    for (i=0; i < Icc -> TagCount; i++) {

        if (Icc -> TagPtrs[i]) {

            cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];

B
bae 已提交
1469
            if (TypeHandler != NULL) {
P
prr 已提交
1470
                cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
B
bae 已提交
1471

P
prr 已提交
1472 1473 1474
                LocalTypeHandler.ContextID = Icc ->ContextID;              // As an additional parameters
                LocalTypeHandler.ICCVersion = Icc ->Version;
                LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
B
bae 已提交
1475
            }
1476 1477 1478 1479 1480 1481 1482 1483 1484
            else
                _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
        }
    }

    if (Icc ->IOhandler != NULL) {
        rc &= cmsCloseIOhandler(Icc->IOhandler);
    }

P
prr 已提交
1485 1486
    _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex);

1487 1488 1489
    _cmsFree(Icc ->ContextID, Icc);   // Free placeholder memory

    return rc;
D
duke 已提交
1490 1491 1492
}


1493 1494 1495 1496 1497 1498
// -------------------------------------------------------------------------------------------------------------------


// Returns TRUE if a given tag is supported by a plug-in
static
cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Type)
D
duke 已提交
1499
{
1500
    cmsUInt32Number i, nMaxTypes;
D
duke 已提交
1501

1502 1503 1504 1505 1506 1507 1508 1509 1510
    nMaxTypes = TagDescriptor->nSupportedTypes;
    if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN)
        nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN;

    for (i=0; i < nMaxTypes; i++) {
        if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE;
    }

    return FALSE;
D
duke 已提交
1511 1512 1513
}


1514 1515
// That's the main read function
void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
D
duke 已提交
1516
{
1517 1518 1519
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    cmsIOHANDLER* io = Icc ->IOhandler;
    cmsTagTypeHandler* TypeHandler;
P
prr 已提交
1520
    cmsTagTypeHandler LocalTypeHandler;
1521 1522 1523 1524 1525
    cmsTagDescriptor*  TagDescriptor;
    cmsTagTypeSignature BaseType;
    cmsUInt32Number Offset, TagSize;
    cmsUInt32Number ElemCount;
    int n;
D
duke 已提交
1526

P
prr 已提交
1527 1528
    if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;

1529
    n = _cmsSearchTag(Icc, sig, TRUE);
P
prr 已提交
1530
    if (n < 0) goto Error;               // Not found, return NULL
1531 1532 1533 1534 1535


    // If the element is already in memory, return the pointer
    if (Icc -> TagPtrs[n]) {

P
prr 已提交
1536 1537 1538
        if (Icc ->TagSaveAsRaw[n]) goto Error;  // We don't support read raw tags as cooked

        _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1539 1540 1541 1542 1543 1544 1545 1546 1547
        return Icc -> TagPtrs[n];
    }

    // We need to read it. Get the offset and size to the file
    Offset    = Icc -> TagOffsets[n];
    TagSize   = Icc -> TagSizes[n];

    // Seek to its location
    if (!io -> Seek(io, Offset))
P
prr 已提交
1548
        goto Error;
1549 1550

    // Search for support on this tag
P
prr 已提交
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
    TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
    if (TagDescriptor == NULL) {

        char String[5];

        _cmsTagSignature2String(String, sig);

        // An unknown element was found.
        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String);
        goto Error;     // Unsupported.
    }
1562 1563 1564

    // if supported, get type and check if in list
    BaseType = _cmsReadTypeBase(io);
P
prr 已提交
1565
    if (BaseType == 0) goto Error;
1566

P
prr 已提交
1567
    if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
1568 1569 1570 1571

    TagSize  -= 8;                      // Alredy read by the type base logic

    // Get type handler
P
prr 已提交
1572 1573
    TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType);
    if (TypeHandler == NULL) goto Error;
P
prr 已提交
1574
    LocalTypeHandler = *TypeHandler;
1575 1576 1577 1578


    // Read the tag
    Icc -> TagTypeHandlers[n] = TypeHandler;
B
bae 已提交
1579

P
prr 已提交
1580 1581 1582
    LocalTypeHandler.ContextID = Icc ->ContextID;
    LocalTypeHandler.ICCVersion = Icc ->Version;
    Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize);
1583 1584 1585 1586 1587 1588 1589 1590 1591

    // The tag type is supported, but something wrong happend and we cannot read the tag.
    // let know the user about this (although it is just a warning)
    if (Icc -> TagPtrs[n] == NULL) {

        char String[5];

        _cmsTagSignature2String(String, sig);
        cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
P
prr 已提交
1592
        goto Error;
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
    }

    // This is a weird error that may be a symptom of something more serious, the number of
    // stored item is actually less than the number of required elements.
    if (ElemCount < TagDescriptor ->ElemCount) {

        char String[5];

        _cmsTagSignature2String(String, sig);
        cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d",
P
prr 已提交
1603
            String, TagDescriptor ->ElemCount, ElemCount);
1604 1605 1606 1607
    }


    // Return the data
P
prr 已提交
1608
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1609
    return Icc -> TagPtrs[n];
P
prr 已提交
1610 1611 1612 1613 1614 1615


    // Return error and unlock tha data
Error:
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
    return NULL;
D
duke 已提交
1616 1617 1618
}


1619 1620
// Get true type of data
cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig)
D
duke 已提交
1621
{
1622 1623 1624
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    cmsTagTypeHandler* TypeHandler;
    int n;
D
duke 已提交
1625

1626 1627 1628 1629 1630 1631 1632
    // Search for given tag in ICC profile directory
    n = _cmsSearchTag(Icc, sig, TRUE);
    if (n < 0) return (cmsTagTypeSignature) 0;                // Not found, return NULL

    // Get the handler. The true type is there
    TypeHandler =  Icc -> TagTypeHandlers[n];
    return TypeHandler ->Signature;
1633 1634 1635
}


1636 1637 1638
// Write a single tag. This just keeps track of the tak into a list of "to be written". If the tag is already
// in that list, the previous version is deleted.
cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data)
1639
{
1640 1641
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    cmsTagTypeHandler* TypeHandler = NULL;
P
prr 已提交
1642
    cmsTagTypeHandler LocalTypeHandler;
1643 1644 1645 1646
    cmsTagDescriptor* TagDescriptor = NULL;
    cmsTagTypeSignature Type;
    int i;
    cmsFloat64Number Version;
B
bae 已提交
1647
    char TypeString[5], SigString[5];
1648

P
prr 已提交
1649
    if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
1650

P
prr 已提交
1651
    // To delete tags.
1652 1653
    if (data == NULL) {

P
prr 已提交
1654
         // Delete the tag
B
bae 已提交
1655
         i = _cmsSearchTag(Icc, sig, FALSE);
P
prr 已提交
1656 1657 1658 1659
         if (i >= 0) {

             // Use zero as a mark of deleted
             _cmsDeleteTagByPos(Icc, i);
B
bae 已提交
1660
             Icc ->TagNames[i] = (cmsTagSignature) 0;
P
prr 已提交
1661 1662 1663 1664 1665
             _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
             return TRUE;
         }
         // Didn't find the tag
        goto Error;
1666 1667
    }

P
prr 已提交
1668
    if (!_cmsNewTag(Icc, sig, &i)) goto Error;
1669 1670 1671 1672 1673 1674 1675 1676

    // This is not raw
    Icc ->TagSaveAsRaw[i] = FALSE;

    // This is not a link
    Icc ->TagLinked[i] = (cmsTagSignature) 0;

    // Get information about the TAG.
P
prr 已提交
1677
    TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
1678 1679
    if (TagDescriptor == NULL){
         cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig);
P
prr 已提交
1680
        goto Error;
1681 1682 1683 1684 1685
    }


    // Now we need to know which type to use. It depends on the version.
    Version = cmsGetProfileVersion(hProfile);
B
bae 已提交
1686

1687 1688 1689 1690 1691
    if (TagDescriptor ->DecideType != NULL) {

        // Let the tag descriptor to decide the type base on depending on
        // the data. This is useful for example on parametric curves, where
        // curves specified by a table cannot be saved as parametric and needs
P
prr 已提交
1692
        // to be casted to single v2-curves, even on v4 profiles.
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702

        Type = TagDescriptor ->DecideType(Version, data);
    }
    else {

        Type = TagDescriptor ->SupportedTypes[0];
    }

    // Does the tag support this type?
    if (!IsTypeSupported(TagDescriptor, Type)) {
B
bae 已提交
1703 1704 1705 1706 1707

        _cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
        _cmsTagSignature2String(SigString,  sig);

        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
P
prr 已提交
1708
        goto Error;
1709 1710 1711
    }

    // Does we have a handler for this type?
P
prr 已提交
1712
    TypeHandler =  _cmsGetTagTypeHandler(Icc->ContextID, Type);
1713
    if (TypeHandler == NULL) {
B
bae 已提交
1714 1715 1716 1717 1718

        _cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
        _cmsTagSignature2String(SigString,  sig);

        cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
P
prr 已提交
1719
        goto Error;           // Should never happen
1720 1721
    }

B
bae 已提交
1722

1723 1724 1725 1726 1727
    // Fill fields on icc structure
    Icc ->TagTypeHandlers[i]  = TypeHandler;
    Icc ->TagNames[i]         = sig;
    Icc ->TagSizes[i]         = 0;
    Icc ->TagOffsets[i]       = 0;
B
bae 已提交
1728

P
prr 已提交
1729 1730 1731
    LocalTypeHandler = *TypeHandler;
    LocalTypeHandler.ContextID  = Icc ->ContextID;
    LocalTypeHandler.ICCVersion = Icc ->Version;
P
prr 已提交
1732
    Icc ->TagPtrs[i]            = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount);
1733 1734 1735

    if (Icc ->TagPtrs[i] == NULL)  {

B
bae 已提交
1736 1737 1738
        _cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
        _cmsTagSignature2String(SigString,  sig);
        cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString);
1739

P
prr 已提交
1740
        goto Error;
1741
    }
1742

P
prr 已提交
1743
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1744
    return TRUE;
P
prr 已提交
1745 1746 1747 1748 1749

Error:
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
    return FALSE;

1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
}

// Read and write raw data. The only way those function would work and keep consistence with normal read and write
// is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained
// data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where
// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows
// to write a tag as raw data and the read it as handled.

cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize)
{
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    void *Object;
    int i;
    cmsIOHANDLER* MemIO;
    cmsTagTypeHandler* TypeHandler = NULL;
P
prr 已提交
1765
    cmsTagTypeHandler LocalTypeHandler;
1766 1767 1768 1769
    cmsTagDescriptor* TagDescriptor = NULL;
    cmsUInt32Number rc;
    cmsUInt32Number Offset, TagSize;

P
prr 已提交
1770 1771
    if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;

1772 1773
    // Search for given tag in ICC profile directory
    i = _cmsSearchTag(Icc, sig, TRUE);
P
prr 已提交
1774
    if (i < 0) goto Error;                 // Not found,
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786

    // It is already read?
    if (Icc -> TagPtrs[i] == NULL) {

        // No yet, get original position
        Offset   = Icc ->TagOffsets[i];
        TagSize  = Icc ->TagSizes[i];

        // read the data directly, don't keep copy
        if (data != NULL) {

            if (BufferSize < TagSize)
P
prr 已提交
1787
                TagSize = BufferSize;
1788

P
prr 已提交
1789 1790
            if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error;
            if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error;
P
prr 已提交
1791

P
prr 已提交
1792
            _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
P
prr 已提交
1793
            return TagSize;
1794 1795
        }

P
prr 已提交
1796
        _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
        return Icc ->TagSizes[i];
    }

    // The data has been already read, or written. But wait!, maybe the user choosed to save as
    // raw data. In this case, return the raw data directly
    if (Icc ->TagSaveAsRaw[i]) {

        if (data != NULL)  {

            TagSize  = Icc ->TagSizes[i];
            if (BufferSize < TagSize)
P
prr 已提交
1808
                TagSize = BufferSize;
1809 1810

            memmove(data, Icc ->TagPtrs[i], TagSize);
P
prr 已提交
1811

P
prr 已提交
1812
            _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
P
prr 已提交
1813
            return TagSize;
1814 1815
        }

P
prr 已提交
1816
        _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1817 1818 1819 1820 1821
        return Icc ->TagSizes[i];
    }

    // Already readed, or previously set by cmsWriteTag(). We need to serialize that
    // data to raw in order to maintain consistency.
P
prr 已提交
1822 1823

    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1824
    Object = cmsReadTag(hProfile, sig);
P
prr 已提交
1825 1826 1827
    if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;

    if (Object == NULL) goto Error;
1828 1829 1830 1831 1832 1833

    // Now we need to serialize to a memory block: just use a memory iohandler

    if (data == NULL) {
        MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile));
    } else{
P
prr 已提交
1834
        MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
1835
    }
P
prr 已提交
1836
    if (MemIO == NULL) goto Error;
1837 1838 1839

    // Obtain type handling for the tag
    TypeHandler = Icc ->TagTypeHandlers[i];
P
prr 已提交
1840
    TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
B
bae 已提交
1841
    if (TagDescriptor == NULL) {
P
prr 已提交
1842
        cmsCloseIOhandler(MemIO);
P
prr 已提交
1843
        goto Error;
B
bae 已提交
1844
    }
1845

P
prr 已提交
1846 1847
    if (TypeHandler == NULL) goto Error;

1848
    // Serialize
P
prr 已提交
1849 1850 1851
    LocalTypeHandler = *TypeHandler;
    LocalTypeHandler.ContextID  = Icc ->ContextID;
    LocalTypeHandler.ICCVersion = Icc ->Version;
B
bae 已提交
1852

1853 1854
    if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) {
        cmsCloseIOhandler(MemIO);
P
prr 已提交
1855
        goto Error;
1856 1857
    }

P
prr 已提交
1858
    if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) {
B
bae 已提交
1859
        cmsCloseIOhandler(MemIO);
P
prr 已提交
1860
        goto Error;
B
bae 已提交
1861
    }
1862 1863 1864 1865

    // Get Size and close
    rc = MemIO ->Tell(MemIO);
    cmsCloseIOhandler(MemIO);      // Ignore return code this time
1866

P
prr 已提交
1867
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1868
    return rc;
P
prr 已提交
1869 1870 1871 1872

Error:
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
    return 0;
D
duke 已提交
1873
}
1874

1875 1876 1877 1878 1879 1880 1881 1882 1883
// Similar to the anterior. This function allows to write directly to the ICC profile any data, without
// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading
// it as cooked without serializing does result into an error. If that is wha you want, you will need to dump
// the profile to memry or disk and then reopen it.
cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size)
{
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    int i;

P
prr 已提交
1884 1885 1886 1887 1888 1889
    if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;

    if (!_cmsNewTag(Icc, sig, &i)) {
        _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
         return FALSE;
    }
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899

    // Mark the tag as being written as RAW
    Icc ->TagSaveAsRaw[i] = TRUE;
    Icc ->TagNames[i]     = sig;
    Icc ->TagLinked[i]    = (cmsTagSignature) 0;

    // Keep a copy of the block
    Icc ->TagPtrs[i]  = _cmsDupMem(Icc ->ContextID, data, Size);
    Icc ->TagSizes[i] = Size;

P
prr 已提交
1900
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1901 1902
    return TRUE;
}
1903

1904 1905 1906
// Using this function you can collapse several tag entries to the same block in the profile
cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest)
{
P
prr 已提交
1907
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
1908 1909
    int i;

P
prr 已提交
1910 1911 1912 1913 1914 1915
     if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;

    if (!_cmsNewTag(Icc, sig, &i)) {
        _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
        return FALSE;
    }
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925

    // Keep necessary information
    Icc ->TagSaveAsRaw[i] = FALSE;
    Icc ->TagNames[i]     = sig;
    Icc ->TagLinked[i]    = dest;

    Icc ->TagPtrs[i]    = NULL;
    Icc ->TagSizes[i]   = 0;
    Icc ->TagOffsets[i] = 0;

P
prr 已提交
1926
    _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
1927 1928
    return TRUE;
}
B
bae 已提交
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942


// Returns the tag linked to sig, in the case two tags are sharing same resource
cmsTagSignature  CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig)
{
    _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
    int i;

    // Search for given tag in ICC profile directory
    i = _cmsSearchTag(Icc, sig, FALSE);
    if (i < 0) return (cmsTagSignature) 0;                 // Not found, return 0

    return Icc -> TagLinked[i];
}