jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c
changeset 6482 0f6a4442b29e
parent 5506 202f599c92aa
child 9784 3a0ebf0b855d
equal deleted inserted replaced
6481:78d56f33c3a7 6482:0f6a4442b29e
    25 // This file is available under and governed by the GNU General Public
    25 // This file is available under and governed by the GNU General Public
    26 // License version 2 only, as published by the Free Software Foundation.
    26 // License version 2 only, as published by the Free Software Foundation.
    27 // However, the following notice accompanied the original version of this
    27 // However, the following notice accompanied the original version of this
    28 // file:
    28 // file:
    29 //
    29 //
       
    30 //---------------------------------------------------------------------------------
    30 //
    31 //
    31 //  Little cms
    32 //  Little Color Management System
    32 //  Copyright (C) 1998-2007 Marti Maria
    33 //  Copyright (c) 1998-2010 Marti Maria Saguer
    33 //
    34 //
    34 // Permission is hereby granted, free of charge, to any person obtaining
    35 // Permission is hereby granted, free of charge, to any person obtaining
    35 // a copy of this software and associated documentation files (the "Software"),
    36 // a copy of this software and associated documentation files (the "Software"),
    36 // to deal in the Software without restriction, including without limitation
    37 // to deal in the Software without restriction, including without limitation
    37 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
    38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
    47 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    48 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    49 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    50 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    51 //
    52 //
       
    53 //---------------------------------------------------------------------------------
       
    54 //
       
    55 
       
    56 #include "lcms2_internal.h"
    52 
    57 
    53 // Generic I/O, tag dictionary management, profile struct
    58 // Generic I/O, tag dictionary management, profile struct
    54 
    59 
    55 
    60 // IOhandlers are abstractions used by littleCMS to read from whatever file, stream,
    56 
    61 // memory block or any storage. Each IOhandler provides implementations for read,
    57 #include "lcms.h"
    62 // write, seek and tell functions. LittleCMS code deals with IO across those objects.
    58 
    63 // In this way, is easier to add support for new storage media.
    59 
    64 
    60 // Memory-based stream ---------------------------------------------------
    65 // NULL stream, for taking care of used space -------------------------------------
       
    66 
       
    67 // NULL IOhandler basically does nothing but keep track on how many bytes have been
       
    68 // written. This is handy when creating profiles, where the file size is needed in the
       
    69 // header. Then, whole profile is serialized across NULL IOhandler and a second pass
       
    70 // writes the bytes to the pertinent IOhandler.
    61 
    71 
    62 typedef struct {
    72 typedef struct {
    63                 LPBYTE Block;           // Points to allocated memory
    73     cmsUInt32Number Pointer;         // Points to current location
    64                 size_t Size;            // Size of allocated memory
    74 } FILENULL;
    65                 size_t Pointer;         // Points to current location
    75 
    66                 int FreeBlockOnClose;   // As title
    76 static
    67 
    77 cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
    68                 } FILEMEM;
    78 {
    69 
    79     FILENULL* ResData = (FILENULL*) iohandler ->stream;
    70 static
    80 
    71 LPVOID MemoryOpen(LPBYTE Block, size_t Size, char Mode)
    81     cmsUInt32Number len = size * count;
    72 {
    82     ResData -> Pointer += len;
    73     FILEMEM* fm = (FILEMEM*) _cmsMalloc(sizeof(FILEMEM));
    83     return count;
    74     if (fm == NULL) return NULL;
    84 
    75 
    85     cmsUNUSED_PARAMETER(Buffer);
    76     ZeroMemory(fm, sizeof(FILEMEM));
    86 }
    77 
    87 
    78     if (Mode == 'r') {
    88 static
    79 
    89 cmsBool  NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
    80         fm ->Block   = (LPBYTE) _cmsMalloc(Size);
    90 {
       
    91     FILENULL* ResData = (FILENULL*) iohandler ->stream;
       
    92 
       
    93     ResData ->Pointer = offset;
       
    94     return TRUE;
       
    95 }
       
    96 
       
    97 static
       
    98 cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler)
       
    99 {
       
   100     FILENULL* ResData = (FILENULL*) iohandler ->stream;
       
   101     return ResData -> Pointer;
       
   102 }
       
   103 
       
   104 static
       
   105 cmsBool  NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Ptr)
       
   106 {
       
   107     FILENULL* ResData = (FILENULL*) iohandler ->stream;
       
   108 
       
   109     ResData ->Pointer += size;
       
   110     if (ResData ->Pointer > iohandler->UsedSpace)
       
   111         iohandler->UsedSpace = ResData ->Pointer;
       
   112 
       
   113     return TRUE;
       
   114 
       
   115     cmsUNUSED_PARAMETER(Ptr);
       
   116 }
       
   117 
       
   118 static
       
   119 cmsBool  NULLClose(cmsIOHANDLER* iohandler)
       
   120 {
       
   121     FILENULL* ResData = (FILENULL*) iohandler ->stream;
       
   122 
       
   123     _cmsFree(iohandler ->ContextID, ResData);
       
   124     _cmsFree(iohandler ->ContextID, iohandler);
       
   125     return TRUE;
       
   126 }
       
   127 
       
   128 // The NULL IOhandler creator
       
   129 cmsIOHANDLER*  CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID)
       
   130 {
       
   131     struct _cms_io_handler* iohandler = NULL;
       
   132     FILENULL* fm = NULL;
       
   133 
       
   134     iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler));
       
   135     if (iohandler == NULL) return NULL;
       
   136 
       
   137     fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL));
       
   138     if (fm == NULL) goto Error;
       
   139 
       
   140     fm ->Pointer = 0;
       
   141 
       
   142     iohandler ->ContextID = ContextID;
       
   143     iohandler ->stream  = (void*) fm;
       
   144     iohandler ->UsedSpace = 0;
       
   145     iohandler ->PhysicalFile[0] = 0;
       
   146 
       
   147     iohandler ->Read    = NULLRead;
       
   148     iohandler ->Seek    = NULLSeek;
       
   149     iohandler ->Close   = NULLClose;
       
   150     iohandler ->Tell    = NULLTell;
       
   151     iohandler ->Write   = NULLWrite;
       
   152 
       
   153     return iohandler;
       
   154 
       
   155 Error:
       
   156     if (fm) _cmsFree(ContextID, fm);
       
   157     if (iohandler) _cmsFree(ContextID, iohandler);
       
   158     return NULL;
       
   159 
       
   160 }
       
   161 
       
   162 
       
   163 // Memory-based stream --------------------------------------------------------------
       
   164 
       
   165 // Those functions implements an iohandler which takes a block of memory as storage medium.
       
   166 
       
   167 typedef struct {
       
   168     cmsUInt8Number* Block;    // Points to allocated memory
       
   169     cmsUInt32Number Size;     // Size of allocated memory
       
   170     cmsUInt32Number Pointer;  // Points to current location
       
   171     int FreeBlockOnClose;     // As title
       
   172 
       
   173 } FILEMEM;
       
   174 
       
   175 static
       
   176 cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
       
   177 {
       
   178     FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
       
   179     cmsUInt8Number* Ptr;
       
   180     cmsUInt32Number len = size * count;
       
   181 
       
   182     if (ResData -> Pointer + len > ResData -> Size){
       
   183 
       
   184         len = (ResData -> Size - ResData -> Pointer);
       
   185         cmsSignalError(iohandler ->ContextID, cmsERROR_READ, "Read from memory error. Got %d bytes, block should be of %d bytes", len, count * size);
       
   186         return 0;
       
   187     }
       
   188 
       
   189     Ptr  = ResData -> Block;
       
   190     Ptr += ResData -> Pointer;
       
   191     memmove(Buffer, Ptr, len);
       
   192     ResData -> Pointer += len;
       
   193 
       
   194     return count;
       
   195 }
       
   196 
       
   197 // SEEK_CUR is assumed
       
   198 static
       
   199 cmsBool  MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset)
       
   200 {
       
   201     FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
       
   202 
       
   203     if (offset > ResData ->Size) {
       
   204         cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK,  "Too few data; probably corrupted profile");
       
   205         return FALSE;
       
   206     }
       
   207 
       
   208     ResData ->Pointer = offset;
       
   209     return TRUE;
       
   210 }
       
   211 
       
   212 // Tell for memory
       
   213 static
       
   214 cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler)
       
   215 {
       
   216     FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
       
   217 
       
   218     if (ResData == NULL) return 0;
       
   219     return ResData -> Pointer;
       
   220 }
       
   221 
       
   222 
       
   223 // Writes data to memory, also keeps used space for further reference.
       
   224 static
       
   225 cmsBool  MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr)
       
   226 {
       
   227     FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
       
   228 
       
   229     if (ResData == NULL) return FALSE; // Housekeeping
       
   230 
       
   231     if (size == 0) return TRUE;     // Write zero bytes is ok, but does nothing
       
   232 
       
   233     memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
       
   234     ResData ->Pointer += size;
       
   235 
       
   236     if (ResData ->Pointer > iohandler->UsedSpace)
       
   237         iohandler->UsedSpace = ResData ->Pointer;
       
   238 
       
   239 
       
   240     iohandler->UsedSpace += size;
       
   241 
       
   242     return TRUE;
       
   243 }
       
   244 
       
   245 
       
   246 static
       
   247 cmsBool  MemoryClose(struct _cms_io_handler* iohandler)
       
   248 {
       
   249     FILEMEM* ResData = (FILEMEM*) iohandler ->stream;
       
   250 
       
   251     if (ResData ->FreeBlockOnClose) {
       
   252 
       
   253         if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block);
       
   254     }
       
   255 
       
   256     _cmsFree(iohandler ->ContextID, ResData);
       
   257     _cmsFree(iohandler ->ContextID, iohandler);
       
   258 
       
   259     return TRUE;
       
   260 }
       
   261 
       
   262 // Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes
       
   263 // a copy of the memory block for letting user to free the memory after invoking open profile. In write
       
   264 // mode ("w"), Buffere points to the begin of memory block to be written.
       
   265 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode)
       
   266 {
       
   267     cmsIOHANDLER* iohandler = NULL;
       
   268     FILEMEM* fm = NULL;
       
   269 
       
   270     _cmsAssert(AccessMode != NULL);
       
   271 
       
   272     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
       
   273     if (iohandler == NULL) return NULL;
       
   274 
       
   275     switch (*AccessMode) {
       
   276 
       
   277     case 'r':
       
   278         fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM));
       
   279         if (fm == NULL) goto Error;
       
   280 
       
   281         if (Buffer == NULL) {
       
   282             cmsSignalError(ContextID, cmsERROR_READ, "Couldn't read profile from NULL pointer");
       
   283             goto Error;
       
   284         }
       
   285 
       
   286         fm ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, size);
    81         if (fm ->Block == NULL) {
   287         if (fm ->Block == NULL) {
    82              _cmsFree(fm);
   288 
       
   289             _cmsFree(ContextID, fm);
       
   290             _cmsFree(ContextID, iohandler);
       
   291             cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", size);
    83             return NULL;
   292             return NULL;
    84         }
   293         }
    85 
   294 
    86         CopyMemory(fm->Block, Block, Size);
   295 
       
   296         memmove(fm->Block, Buffer, size);
    87         fm ->FreeBlockOnClose = TRUE;
   297         fm ->FreeBlockOnClose = TRUE;
    88     }
   298         fm ->Size    = size;
    89     else {
   299         fm ->Pointer = 0;
    90         fm ->Block = Block;
   300         break;
       
   301 
       
   302     case 'w':
       
   303         fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM));
       
   304         if (fm == NULL) goto Error;
       
   305 
       
   306         fm ->Block = (cmsUInt8Number*) Buffer;
    91         fm ->FreeBlockOnClose = FALSE;
   307         fm ->FreeBlockOnClose = FALSE;
    92     }
   308         fm ->Size    = size;
    93 
   309         fm ->Pointer = 0;
    94     fm ->Size    = Size;
   310         break;
    95     fm ->Pointer = 0;
   311 
    96 
   312     default:
    97     return (LPVOID) fm;
   313         cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow access mode '%c'", *AccessMode);
    98 }
   314         return NULL;
    99 
   315     }
   100 
   316 
   101 static
   317     iohandler ->ContextID = ContextID;
   102 size_t MemoryRead(LPVOID buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc)
   318     iohandler ->stream  = (void*) fm;
   103 {
   319     iohandler ->UsedSpace = 0;
   104      FILEMEM* ResData = (FILEMEM*) Icc ->stream;
   320     iohandler ->PhysicalFile[0] = 0;
   105      LPBYTE Ptr;
   321 
   106      size_t len = size * count;
   322     iohandler ->Read    = MemoryRead;
   107      size_t extent = ResData -> Pointer + len;
   323     iohandler ->Seek    = MemorySeek;
   108 
   324     iohandler ->Close   = MemoryClose;
   109         if (len == 0) {
   325     iohandler ->Tell    = MemoryTell;
   110                 return 0;
   326     iohandler ->Write   = MemoryWrite;
       
   327 
       
   328     return iohandler;
       
   329 
       
   330 Error:
       
   331     if (fm) _cmsFree(ContextID, fm);
       
   332     if (iohandler) _cmsFree(ContextID, iohandler);
       
   333     return NULL;
       
   334 }
       
   335 
       
   336 // File-based stream -------------------------------------------------------
       
   337 
       
   338 // Read count elements of size bytes each. Return number of elements read
       
   339 static
       
   340 cmsUInt32Number FileRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count)
       
   341 {
       
   342     cmsUInt32Number nReaded = (cmsUInt32Number) fread(Buffer, size, count, (FILE*) iohandler->stream);
       
   343 
       
   344     if (nReaded != count) {
       
   345             cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
       
   346             return 0;
       
   347     }
       
   348 
       
   349     return nReaded;
       
   350 }
       
   351 
       
   352 // Postion file pointer in the file
       
   353 static
       
   354 cmsBool  FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
       
   355 {
       
   356     if (fseek((FILE*) iohandler ->stream, (long) offset, SEEK_SET) != 0) {
       
   357 
       
   358        cmsSignalError(iohandler ->ContextID, cmsERROR_FILE, "Seek error; probably corrupted file");
       
   359        return FALSE;
       
   360     }
       
   361 
       
   362     return TRUE;
       
   363 }
       
   364 
       
   365 // Returns file pointer position
       
   366 static
       
   367 cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
       
   368 {
       
   369     return ftell((FILE*)iohandler ->stream);
       
   370 }
       
   371 
       
   372 // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error
       
   373 static
       
   374 cmsBool  FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer)
       
   375 {
       
   376        if (size == 0) return TRUE;  // We allow to write 0 bytes, but nothing is written
       
   377 
       
   378        iohandler->UsedSpace += size;
       
   379        return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1);
       
   380 }
       
   381 
       
   382 // Closes the file
       
   383 static
       
   384 cmsBool  FileClose(cmsIOHANDLER* iohandler)
       
   385 {
       
   386     if (fclose((FILE*) iohandler ->stream) != 0) return FALSE;
       
   387     _cmsFree(iohandler ->ContextID, iohandler);
       
   388     return TRUE;
       
   389 }
       
   390 
       
   391 // Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set
       
   392 // to NULL and no real writting is performed. This only happens in writting access mode
       
   393 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode)
       
   394 {
       
   395     cmsIOHANDLER* iohandler = NULL;
       
   396     FILE* fm = NULL;
       
   397 
       
   398     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
       
   399     if (iohandler == NULL) return NULL;
       
   400 
       
   401     switch (*AccessMode) {
       
   402 
       
   403     case 'r':
       
   404         fm = fopen(FileName, "rb");
       
   405         if (fm == NULL) {
       
   406             _cmsFree(ContextID, iohandler);
       
   407              cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
       
   408             return NULL;
   111         }
   409         }
   112 
   410         break;
   113         if (len / size != count) {
   411 
   114           cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with count / size.");
   412     case 'w':
   115           return 0;
   413         fm = fopen(FileName, "wb");
   116       }
   414         if (fm == NULL) {
   117 
   415             _cmsFree(ContextID, iohandler);
   118       if (extent < len || extent < ResData -> Pointer) {
   416              cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
   119           cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Integer overflow with len.");
   417             return NULL;
   120           return 0;
   418         }
   121       }
   419         break;
   122 
   420 
   123       if (ResData -> Pointer + len > ResData -> Size) {
   421     default:
   124 
   422         _cmsFree(ContextID, iohandler);
   125          len = (ResData -> Size - ResData -> Pointer);
   423          cmsSignalError(ContextID, cmsERROR_FILE, "Unknow access mode '%c'", *AccessMode);
   126          cmsSignalError(LCMS_ERRC_ABORTED, "Read from memory error. Got %d bytes, block should be of %d bytes", len * size, count * size);
   424         return NULL;
   127          return 0;
   425     }
   128      }
   426 
   129 
   427     iohandler ->ContextID = ContextID;
   130     Ptr  = ResData -> Block;
   428     iohandler ->stream = (void*) fm;
   131     Ptr += ResData -> Pointer;
   429     iohandler ->UsedSpace = 0;
   132     CopyMemory(buffer, Ptr, len);
   430 
   133     ResData -> Pointer += (int) len;
   431     // Keep track of the original file
   134 
   432     if (FileName != NULL)  {
   135     return count;
   433 
   136 }
   434         strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1);
   137 
   435         iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0;
   138 // SEEK_CUR is assumed
   436     }
   139 
   437 
   140 static
   438     iohandler ->Read    = FileRead;
   141 LCMSBOOL MemorySeek(struct _lcms_iccprofile_struct* Icc, size_t offset)
   439     iohandler ->Seek    = FileSeek;
   142 {
   440     iohandler ->Close   = FileClose;
   143     FILEMEM* ResData = (FILEMEM*) Icc ->stream;
   441     iohandler ->Tell    = FileTell;
   144 
   442     iohandler ->Write   = FileWrite;
   145     if (offset > ResData ->Size) {
   443 
   146          cmsSignalError(LCMS_ERRC_ABORTED,  "Pointer error; probably corrupted file");
   444     return iohandler;
   147          return TRUE;
   445 }
   148     }
   446 
   149 
   447 // Create a iohandler for stream based files
   150     ResData ->Pointer = (DWORD) offset;
   448 cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream)
   151     return FALSE;
   449 {
   152 }
   450     cmsIOHANDLER* iohandler = NULL;
   153 
   451 
   154 // FTell
   452     iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
   155 
   453     if (iohandler == NULL) return NULL;
   156 static
   454 
   157 size_t MemoryTell(struct _lcms_iccprofile_struct* Icc)
   455     iohandler -> ContextID = ContextID;
   158 {
   456     iohandler -> stream = (void*) Stream;
   159     FILEMEM* ResData = (FILEMEM*) Icc ->stream;
   457     iohandler -> UsedSpace = 0;
   160 
   458     iohandler -> PhysicalFile[0] = 0;
   161     return ResData -> Pointer;
   459 
   162 }
   460     iohandler ->Read    = FileRead;
   163 
   461     iohandler ->Seek    = FileSeek;
   164 
   462     iohandler ->Close   = FileClose;
   165 // Writes data to memory, also keeps used space for further reference. NO CHECK IS PERFORMED
   463     iohandler ->Tell    = FileTell;
   166 
   464     iohandler ->Write   = FileWrite;
   167 static
   465 
   168 LCMSBOOL MemoryWrite(struct _lcms_iccprofile_struct* Icc, size_t size, void *Ptr)
   466     return iohandler;
   169 {
   467 }
   170         FILEMEM* ResData = (FILEMEM*) Icc ->stream;
   468 
   171 
   469 
   172        if (size == 0) return TRUE;
   470 
   173 
   471 // Close an open IO handler
   174        if (ResData != NULL)
   472 cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io)
   175            CopyMemory(ResData ->Block + ResData ->Pointer, Ptr, size);
   473 {
   176 
   474     return io -> Close(io);
   177        ResData->Pointer += size;
   475 }
   178        Icc->UsedSpace += size;
   476 
   179 
   477 // -------------------------------------------------------------------------------------------------------
   180        return TRUE;
       
   181 }
       
   182 
       
   183 
       
   184 static
       
   185 LCMSBOOL MemoryGrow(struct _lcms_iccprofile_struct* Icc, size_t size)
       
   186 {
       
   187     FILEMEM* ResData = (FILEMEM*) Icc->stream;
       
   188 
       
   189     void* newBlock = NULL;
       
   190 
       
   191     /* Follow same policies as functions in lcms.h  */
       
   192     if (ResData->Size + size < 0) return NULL;
       
   193     if (ResData->Size + size > ((size_t)1024*1024*500)) return NULL;
       
   194 
       
   195     newBlock = realloc(ResData->Block, ResData->Size + size);
       
   196 
       
   197     if (!newBlock) {
       
   198         return FALSE;
       
   199     }
       
   200     ResData->Block = newBlock;
       
   201     ResData->Size += size;
       
   202     return TRUE;
       
   203 }
       
   204 
       
   205 
       
   206 static
       
   207 LCMSBOOL MemoryClose(struct _lcms_iccprofile_struct* Icc)
       
   208 {
       
   209     FILEMEM* ResData = (FILEMEM*) Icc ->stream;
       
   210 
       
   211     if (ResData ->FreeBlockOnClose) {
       
   212 
       
   213         if (ResData ->Block)  _cmsFree(ResData ->Block);
       
   214     }
       
   215      _cmsFree(ResData);
       
   216     return 0;
       
   217 }
       
   218 
       
   219 
       
   220 // File-based stream -------------------------------------------------------
       
   221 
       
   222 static
       
   223 LPVOID FileOpen(const char* filename)
       
   224 {
       
   225     return (void*) fopen(filename, "rb");
       
   226 }
       
   227 
       
   228 static
       
   229 size_t FileRead(void *buffer, size_t size, size_t count, struct _lcms_iccprofile_struct* Icc)
       
   230 {
       
   231     size_t nReaded = fread(buffer, size, count, (FILE*) Icc->stream);
       
   232     if (nReaded != count) {
       
   233             cmsSignalError(LCMS_ERRC_ABORTED, "Read error. Got %d bytes, block should be of %d bytes", nReaded * size, count * size);
       
   234             return 0;
       
   235     }
       
   236 
       
   237     return nReaded;
       
   238 }
       
   239 
       
   240 
       
   241 static
       
   242 LCMSBOOL FileSeek(struct _lcms_iccprofile_struct* Icc, size_t offset)
       
   243 {
       
   244     if (fseek((FILE*) Icc ->stream, (long) offset, SEEK_SET) != 0) {
       
   245 
       
   246        cmsSignalError(LCMS_ERRC_ABORTED, "Seek error; probably corrupted file");
       
   247        return TRUE;
       
   248     }
       
   249 
       
   250     return FALSE;
       
   251 }
       
   252 
       
   253 
       
   254 static
       
   255 size_t FileTell(struct _lcms_iccprofile_struct* Icc)
       
   256 {
       
   257     return ftell((FILE*) Icc ->stream);
       
   258 }
       
   259 
       
   260 // Writes data to stream, also keeps used space for further reference
       
   261 
       
   262 
       
   263 static
       
   264 LCMSBOOL FileWrite(struct _lcms_iccprofile_struct* Icc, size_t size, LPVOID Ptr)
       
   265 {
       
   266        if (size == 0) return TRUE;
       
   267 
       
   268        Icc->UsedSpace += size;
       
   269 
       
   270        if (Icc->stream == NULL) {
       
   271 
       
   272               return TRUE;
       
   273        }
       
   274 
       
   275        return (fwrite(Ptr, size, 1, (FILE*) Icc->stream) == 1);
       
   276 }
       
   277 
       
   278 
       
   279 static
       
   280 LCMSBOOL FileGrow(struct _lcms_iccprofile_struct* Icc, size_t size)
       
   281 {
       
   282   return TRUE;
       
   283 }
       
   284 
       
   285 
       
   286 static
       
   287 LCMSBOOL FileClose(struct _lcms_iccprofile_struct* Icc)
       
   288 {
       
   289     return fclose((FILE*) Icc ->stream);
       
   290 }
       
   291 
       
   292 // ----------------------------------------------------------------------------------------------------
       
   293 
       
   294 
   478 
   295 // Creates an empty structure holding all required parameters
   479 // Creates an empty structure holding all required parameters
   296 
   480 cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
   297 cmsHPROFILE _cmsCreateProfilePlaceholder(void)
   481 {
   298 {
   482     time_t now = time(NULL);
   299 
   483     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE));
   300     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) _cmsMalloc(sizeof(LCMSICCPROFILE));
       
   301     if (Icc == NULL) return NULL;
   484     if (Icc == NULL) return NULL;
   302 
   485 
   303     // Empty values
   486     Icc ->ContextID = ContextID;
   304     ZeroMemory(Icc, sizeof(LCMSICCPROFILE));
       
   305 
       
   306     // Make sure illuminant is correct
       
   307     Icc ->Illuminant = *cmsD50_XYZ();
       
   308 
   487 
   309     // Set it to empty
   488     // Set it to empty
   310     Icc -> TagCount   = 0;
   489     Icc -> TagCount   = 0;
   311 
   490 
       
   491     // Set default version
       
   492     Icc ->Version =  0x02100000;
       
   493 
       
   494     // Set creation date/time
       
   495     memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));
       
   496 
   312     // Return the handle
   497     // Return the handle
   313     return (cmsHPROFILE) Icc;
   498     return (cmsHPROFILE) Icc;
   314 }
   499 }
   315 
   500 
       
   501 cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile)
       
   502 {
       
   503      _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
   504 
       
   505     if (Icc == NULL) return NULL;
       
   506     return Icc -> ContextID;
       
   507 }
       
   508 
   316 
   509 
   317 // Return the number of tags
   510 // Return the number of tags
   318 icInt32Number LCMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile)
   511 cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile)
   319 {
   512 {
   320     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
   513     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
   514     if (Icc == NULL) return -1;
       
   515 
   321     return  Icc->TagCount;
   516     return  Icc->TagCount;
   322 }
   517 }
   323 
   518 
   324 // Return the tag signature of a given tag number
   519 // Return the tag signature of a given tag number
   325 icTagSignature LCMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, icInt32Number n)
   520 cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n)
   326 {
   521 {
   327     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) hProfile;
   522     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
   328 
   523 
   329     if (n < 0 || n > Icc->TagCount) return (icTagSignature) 0;  // Mark as not available
   524     if (n > Icc->TagCount) return (cmsTagSignature) 0;  // Mark as not available
       
   525     if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check
   330 
   526 
   331     return Icc ->TagNames[n];
   527     return Icc ->TagNames[n];
   332 }
   528 }
   333 
   529 
   334 
   530 
   335 // Search for a specific tag in tag dictionary
   531 static
   336 // Returns position or -1 if tag not found
   532 int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig)
   337 
   533 {
   338 icInt32Number _cmsSearchTag(LPLCMSICCPROFILE Profile, icTagSignature sig, LCMSBOOL lSignalError)
   534     cmsUInt32Number i;
   339 {
   535 
   340        icInt32Number i;
   536     for (i=0; i < Profile -> TagCount; i++) {
   341 
   537 
   342        if (sig == 0) return -1;     // 0 identifies a special tag holding raw memory.
   538         if (sig == Profile -> TagNames[i])
   343 
   539             return i;
   344        for (i=0; i < Profile -> TagCount; i++) {
   540     }
   345 
   541 
   346               if (sig == Profile -> TagNames[i])
   542     return -1;
   347                             return i;
   543 }
   348        }
   544 
   349 
   545 // Search for a specific tag in tag dictionary. Returns position or -1 if tag not found.
   350        if (lSignalError)
   546 // If followlinks is turned on, then the position of the linked tag is returned
   351             cmsSignalError(LCMS_ERRC_ABORTED, "Tag '%lx' not found", sig);
   547 int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks)
   352 
   548 {
   353        return -1;
   549     int n;
       
   550     cmsTagSignature LinkedSig;
       
   551 
       
   552     do {
       
   553 
       
   554         // Search for given tag in ICC profile directory
       
   555         n = SearchOneTag(Icc, sig);
       
   556         if (n < 0)
       
   557             return -1;        // Not found
       
   558 
       
   559         if (!lFollowLinks)
       
   560             return n;         // Found, don't follow links
       
   561 
       
   562         // Is this a linked tag?
       
   563         LinkedSig = Icc ->TagLinked[n];
       
   564 
       
   565         // Yes, follow link
       
   566         if (LinkedSig != (cmsTagSignature) 0) {
       
   567             sig = LinkedSig;
       
   568         }
       
   569 
       
   570     } while (LinkedSig != (cmsTagSignature) 0);
       
   571 
       
   572     return n;
       
   573 }
       
   574 
       
   575 
       
   576 // Create a new tag entry
       
   577 
       
   578 static
       
   579 cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
       
   580 {
       
   581     int i;
       
   582 
       
   583     // Search for the tag
       
   584     i = _cmsSearchTag(Icc, sig, FALSE);
       
   585 
       
   586     // Now let's do it easy. If the tag has been already written, that's an error
       
   587     if (i >= 0) {
       
   588         cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig);
       
   589         return FALSE;
       
   590     }
       
   591     else  {
       
   592 
       
   593         // New one
       
   594 
       
   595         if (Icc -> TagCount >= MAX_TABLE_TAG) {
       
   596             cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
       
   597             return FALSE;
       
   598         }
       
   599 
       
   600         *NewPos = Icc ->TagCount;
       
   601         Icc -> TagCount++;
       
   602     }
       
   603 
       
   604     return TRUE;
   354 }
   605 }
   355 
   606 
   356 
   607 
   357 // Check existance
   608 // Check existance
   358 
   609 cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig)
   359 LCMSBOOL LCMSEXPORT cmsIsTag(cmsHPROFILE hProfile, icTagSignature sig)
   610 {
   360 {
   611        _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) (void*) hProfile;
   361        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   362        return _cmsSearchTag(Icc, sig, FALSE) >= 0;
   612        return _cmsSearchTag(Icc, sig, FALSE) >= 0;
   363 }
   613 }
   364 
   614 
   365 
   615 
   366 
   616 // Read profile header and validate it
   367 // Search for a particular tag, replace if found or add new one else
   617 cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
   368 
   618 {
   369 LPVOID _cmsInitTag(LPLCMSICCPROFILE Icc, icTagSignature sig, size_t size, const void* Init)
   619     cmsTagEntry Tag;
   370 {
   620     cmsICCHeader Header;
   371     LPVOID Ptr;
   621     cmsUInt32Number i, j;
   372     icInt32Number i;
   622     cmsUInt32Number HeaderSize;
       
   623     cmsIOHANDLER* io = Icc ->IOhandler;
       
   624     cmsUInt32Number TagCount;
       
   625 
       
   626 
       
   627     // Read the header
       
   628     if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) {
       
   629         return FALSE;
       
   630     }
       
   631 
       
   632     // Validate file as an ICC profile
       
   633     if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) {
       
   634         cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature");
       
   635         return FALSE;
       
   636     }
       
   637 
       
   638     // Adjust endianess of the used parameters
       
   639     Icc -> DeviceClass     = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
       
   640     Icc -> ColorSpace      = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.colorSpace);
       
   641     Icc -> PCS             = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.pcs);
       
   642     Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
       
   643     Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
       
   644     Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
       
   645     Icc -> model           = _cmsAdjustEndianess32(Header.model);
       
   646     _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes);
       
   647     Icc -> Version         = _cmsAdjustEndianess32(Header.version);
       
   648 
       
   649     // Get size as reported in header
       
   650     HeaderSize = _cmsAdjustEndianess32(Header.size);
       
   651 
       
   652     // Get creation date/time
       
   653     _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created);
       
   654 
       
   655     // The profile ID are 32 raw bytes
       
   656     memmove(Icc ->ProfileID.ID32, Header.profileID.ID32, 16);
       
   657 
       
   658 
       
   659     // Read tag directory
       
   660     if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE;
       
   661     if (TagCount > MAX_TABLE_TAG) {
       
   662 
       
   663         cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount);
       
   664         return FALSE;
       
   665     }
       
   666 
       
   667     // Read tag directory
       
   668     Icc -> TagCount = 0;
       
   669     for (i=0; i < TagCount; i++) {
       
   670 
       
   671         if (!_cmsReadUInt32Number(io, (cmsUInt32Number *) &Tag.sig)) return FALSE;
       
   672         if (!_cmsReadUInt32Number(io, &Tag.offset)) return FALSE;
       
   673         if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE;
       
   674 
       
   675         // Perform some sanity check. Offset + size should fall inside file.
       
   676         if (Tag.offset + Tag.size > HeaderSize)
       
   677                   continue;
       
   678 
       
   679         Icc -> TagNames[Icc ->TagCount]   = Tag.sig;
       
   680         Icc -> TagOffsets[Icc ->TagCount] = Tag.offset;
       
   681         Icc -> TagSizes[Icc ->TagCount]   = Tag.size;
       
   682 
       
   683        // Search for links
       
   684         for (j=0; j < Icc ->TagCount; j++) {
       
   685 
       
   686             if ((Icc ->TagOffsets[j] == Tag.offset) &&
       
   687                 (Icc ->TagSizes[j]   == Tag.size)) {
       
   688 
       
   689                 Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j];
       
   690             }
       
   691 
       
   692         }
       
   693 
       
   694         Icc ->TagCount++;
       
   695     }
       
   696 
       
   697     return TRUE;
       
   698 }
       
   699 
       
   700 // Saves profile header
       
   701 cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
       
   702 {
       
   703     cmsICCHeader Header;
       
   704     cmsUInt32Number i;
       
   705     cmsTagEntry Tag;
       
   706     cmsInt32Number Count = 0;
       
   707 
       
   708     Header.size        = _cmsAdjustEndianess32(UsedSpace);
       
   709     Header.cmmId       = _cmsAdjustEndianess32(lcmsSignature);
       
   710     Header.version     = _cmsAdjustEndianess32(Icc ->Version);
       
   711 
       
   712     Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass);
       
   713     Header.colorSpace  = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> ColorSpace);
       
   714     Header.pcs         = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Icc -> PCS);
       
   715 
       
   716     //   NOTE: in v4 Timestamp must be in UTC rather than in local time
       
   717     _cmsEncodeDateTimeNumber(&Header.date, &Icc ->Created);
       
   718 
       
   719     Header.magic       = _cmsAdjustEndianess32(cmsMagicNumber);
       
   720 
       
   721 #ifdef CMS_IS_WINDOWS_
       
   722     Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft);
       
   723 #else
       
   724     Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh);
       
   725 #endif
       
   726 
       
   727     Header.flags        = _cmsAdjustEndianess32(Icc -> flags);
       
   728     Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
       
   729     Header.model        = _cmsAdjustEndianess32(Icc -> model);
       
   730 
       
   731     _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes);
       
   732 
       
   733     // Rendering intent in the header (for embedded profiles)
       
   734     Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
       
   735 
       
   736     // Illuminant is always D50
       
   737     Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
       
   738     Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
       
   739     Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
       
   740 
       
   741     // Created by LittleCMS (that's me!)
       
   742     Header.creator      = _cmsAdjustEndianess32(lcmsSignature);
       
   743 
       
   744     memset(&Header.reserved, 0, sizeof(Header.reserved));
       
   745 
       
   746     // Set profile ID. Endianess is always big endian
       
   747     memmove(&Header.profileID, &Icc ->ProfileID, 16);
       
   748 
       
   749     // Dump the header
       
   750     if (!Icc -> IOhandler->Write(Icc->IOhandler, sizeof(cmsICCHeader), &Header)) return FALSE;
       
   751 
       
   752     // Saves Tag directory
       
   753 
       
   754     // Get true count
       
   755     for (i=0;  i < Icc -> TagCount; i++) {
       
   756         if (Icc ->TagNames[i] != 0)
       
   757             Count++;
       
   758     }
       
   759 
       
   760     // Store number of tags
       
   761     if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE;
       
   762 
       
   763     for (i=0; i < Icc -> TagCount; i++) {
       
   764 
       
   765         if (Icc ->TagNames[i] == 0) continue;   // It is just a placeholder
       
   766 
       
   767         Tag.sig    = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]);
       
   768         Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]);
       
   769         Tag.size   = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]);
       
   770 
       
   771         if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE;
       
   772     }
       
   773 
       
   774     return TRUE;
       
   775 }
       
   776 
       
   777 // ----------------------------------------------------------------------- Set/Get several struct members
       
   778 
       
   779 
       
   780 cmsUInt32Number CMSEXPORT cmsGetHeaderRenderingIntent(cmsHPROFILE hProfile)
       
   781 {
       
   782     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   783     return Icc -> RenderingIntent;
       
   784 }
       
   785 
       
   786 void CMSEXPORT cmsSetHeaderRenderingIntent(cmsHPROFILE hProfile, cmsUInt32Number RenderingIntent)
       
   787 {
       
   788     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   789     Icc -> RenderingIntent = RenderingIntent;
       
   790 }
       
   791 
       
   792 cmsUInt32Number CMSEXPORT cmsGetHeaderFlags(cmsHPROFILE hProfile)
       
   793 {
       
   794     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   795     return (cmsUInt32Number) Icc -> flags;
       
   796 }
       
   797 
       
   798 void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags)
       
   799 {
       
   800     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   801     Icc -> flags = (cmsUInt32Number) Flags;
       
   802 }
       
   803 
       
   804 cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile)
       
   805 {
       
   806     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   807     return (cmsUInt32Number) Icc ->manufacturer;
       
   808 }
       
   809 
       
   810 void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer)
       
   811 {
       
   812     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   813     Icc -> manufacturer = (cmsUInt32Number) manufacturer;
       
   814 }
       
   815 
       
   816 cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile)
       
   817 {
       
   818     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   819     return (cmsUInt32Number) Icc ->model;
       
   820 }
       
   821 
       
   822 void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model)
       
   823 {
       
   824     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   825     Icc -> manufacturer = (cmsUInt32Number) model;
       
   826 }
       
   827 
       
   828 
       
   829 void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags)
       
   830 {
       
   831     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   832     memmove(Flags, &Icc -> attributes, sizeof(cmsUInt64Number));
       
   833 }
       
   834 
       
   835 void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags)
       
   836 {
       
   837     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   838     memmove(&Icc -> attributes, &Flags, sizeof(cmsUInt64Number));
       
   839 }
       
   840 
       
   841 void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID)
       
   842 {
       
   843     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   844     memmove(ProfileID, Icc ->ProfileID.ID8, 16);
       
   845 }
       
   846 
       
   847 void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID)
       
   848 {
       
   849     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   850     memmove(&Icc -> ProfileID, ProfileID, 16);
       
   851 }
       
   852 
       
   853 cmsBool  CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest)
       
   854 {
       
   855     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   856     memmove(Dest, &Icc ->Created, sizeof(struct tm));
       
   857     return TRUE;
       
   858 }
       
   859 
       
   860 cmsColorSpaceSignature CMSEXPORT cmsGetPCS(cmsHPROFILE hProfile)
       
   861 {
       
   862     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   863     return Icc -> PCS;
       
   864 }
       
   865 
       
   866 void CMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, cmsColorSpaceSignature pcs)
       
   867 {
       
   868     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   869     Icc -> PCS = pcs;
       
   870 }
       
   871 
       
   872 cmsColorSpaceSignature CMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile)
       
   873 {
       
   874     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   875     return Icc -> ColorSpace;
       
   876 }
       
   877 
       
   878 void CMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, cmsColorSpaceSignature sig)
       
   879 {
       
   880     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   881     Icc -> ColorSpace = sig;
       
   882 }
       
   883 
       
   884 cmsProfileClassSignature CMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile)
       
   885 {
       
   886     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   887     return Icc -> DeviceClass;
       
   888 }
       
   889 
       
   890 void CMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, cmsProfileClassSignature sig)
       
   891 {
       
   892     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   893     Icc -> DeviceClass = sig;
       
   894 }
       
   895 
       
   896 cmsUInt32Number CMSEXPORT cmsGetEncodedICCversion(cmsHPROFILE hProfile)
       
   897 {
       
   898     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   899     return Icc -> Version;
       
   900 }
       
   901 
       
   902 void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, cmsUInt32Number Version)
       
   903 {
       
   904     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   905     Icc -> Version = Version;
       
   906 }
       
   907 
       
   908 // Get an hexadecimal number with same digits as v
       
   909 static
       
   910 cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut)
       
   911 {
       
   912     char Buff[100];
       
   913     int i, len;
       
   914     cmsUInt32Number out;
       
   915 
       
   916     for (len=0; in > 0 && len < 100; len++) {
       
   917 
       
   918         Buff[len] = (char) (in % BaseIn);
       
   919         in /= BaseIn;
       
   920     }
       
   921 
       
   922     for (i=len-1, out=0; i >= 0; --i) {
       
   923         out = out * BaseOut + Buff[i];
       
   924     }
       
   925 
       
   926     return out;
       
   927 }
       
   928 
       
   929 void  CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Version)
       
   930 {
       
   931     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   932 
       
   933     // 4.2 -> 0x4200000
       
   934 
       
   935     Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16;
       
   936 }
       
   937 
       
   938 cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile)
       
   939 {
       
   940     _cmsICCPROFILE*  Icc = (_cmsICCPROFILE*) hProfile;
       
   941     cmsUInt32Number n = Icc -> Version >> 16;
       
   942 
       
   943     return BaseToBase(n, 16, 10) / 100.0;
       
   944 }
       
   945 // --------------------------------------------------------------------------------------------------------------
       
   946 
       
   947 
       
   948 // Create profile from IOhandler
       
   949 cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io)
       
   950 {
       
   951     _cmsICCPROFILE* NewIcc;
       
   952     cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
       
   953 
       
   954     if (hEmpty == NULL) return NULL;
       
   955 
       
   956     NewIcc = (_cmsICCPROFILE*) hEmpty;
       
   957 
       
   958     NewIcc ->IOhandler = io;
       
   959     if (!_cmsReadHeader(NewIcc)) goto Error;
       
   960     return hEmpty;
       
   961 
       
   962 Error:
       
   963     cmsCloseProfile(hEmpty);
       
   964     return NULL;
       
   965 }
       
   966 
       
   967 // Create profile from disk file
       
   968 cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess)
       
   969 {
       
   970     _cmsICCPROFILE* NewIcc;
       
   971     cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
       
   972 
       
   973     if (hEmpty == NULL) return NULL;
       
   974 
       
   975     NewIcc = (_cmsICCPROFILE*) hEmpty;
       
   976 
       
   977     NewIcc ->IOhandler = cmsOpenIOhandlerFromFile(ContextID, lpFileName, sAccess);
       
   978     if (NewIcc ->IOhandler == NULL) goto Error;
       
   979 
       
   980     if (*sAccess == 'W' || *sAccess == 'w') {
       
   981 
       
   982         NewIcc -> IsWrite = TRUE;
       
   983 
       
   984         return hEmpty;
       
   985     }
       
   986 
       
   987     if (!_cmsReadHeader(NewIcc)) goto Error;
       
   988     return hEmpty;
       
   989 
       
   990 Error:
       
   991     cmsCloseProfile(hEmpty);
       
   992     return NULL;
       
   993 }
       
   994 
       
   995 
       
   996 cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess)
       
   997 {
       
   998     return cmsOpenProfileFromFileTHR(NULL, ICCProfile, sAccess);
       
   999 }
       
  1000 
       
  1001 
       
  1002 cmsHPROFILE  CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* ICCProfile, const char *sAccess)
       
  1003 {
       
  1004     _cmsICCPROFILE* NewIcc;
       
  1005     cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
       
  1006 
       
  1007     if (hEmpty == NULL) return NULL;
       
  1008 
       
  1009     NewIcc = (_cmsICCPROFILE*) hEmpty;
       
  1010 
       
  1011     NewIcc ->IOhandler = cmsOpenIOhandlerFromStream(ContextID, ICCProfile);
       
  1012     if (NewIcc ->IOhandler == NULL) goto Error;
       
  1013 
       
  1014     if (*sAccess == 'w') {
       
  1015 
       
  1016         NewIcc -> IsWrite = TRUE;
       
  1017         return hEmpty;
       
  1018     }
       
  1019 
       
  1020     if (!_cmsReadHeader(NewIcc)) goto Error;
       
  1021     return hEmpty;
       
  1022 
       
  1023 Error:
       
  1024     cmsCloseProfile(hEmpty);
       
  1025     return NULL;
       
  1026 
       
  1027 }
       
  1028 
       
  1029 cmsHPROFILE  CMSEXPORT cmsOpenProfileFromStream(FILE* ICCProfile, const char *sAccess)
       
  1030 {
       
  1031     return cmsOpenProfileFromStreamTHR(NULL, ICCProfile, sAccess);
       
  1032 }
       
  1033 
       
  1034 
       
  1035 // Open from memory block
       
  1036 cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* MemPtr, cmsUInt32Number dwSize)
       
  1037 {
       
  1038     _cmsICCPROFILE* NewIcc;
       
  1039     cmsHPROFILE hEmpty;
       
  1040 
       
  1041     hEmpty = cmsCreateProfilePlaceholder(ContextID);
       
  1042     if (hEmpty == NULL) return NULL;
       
  1043 
       
  1044     NewIcc = (_cmsICCPROFILE*) hEmpty;
       
  1045 
       
  1046     // Ok, in this case const void* is casted to void* just because open IO handler
       
  1047     // shares read and writting modes. Don't abuse this feature!
       
  1048     NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r");
       
  1049     if (NewIcc ->IOhandler == NULL) goto Error;
       
  1050 
       
  1051     if (!_cmsReadHeader(NewIcc)) goto Error;
       
  1052 
       
  1053     return hEmpty;
       
  1054 
       
  1055 Error:
       
  1056     cmsCloseProfile(hEmpty);
       
  1057     return NULL;
       
  1058 }
       
  1059 
       
  1060 cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void* MemPtr, cmsUInt32Number dwSize)
       
  1061 {
       
  1062     return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize);
       
  1063 }
       
  1064 
       
  1065 
       
  1066 
       
  1067 // Dump tag contents. If the profile is being modified, untouched tags are copied from FileOrig
       
  1068 static
       
  1069 cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig)
       
  1070 {
       
  1071     cmsUInt8Number* Data;
       
  1072     cmsUInt32Number i;
       
  1073     cmsUInt32Number Begin;
       
  1074     cmsIOHANDLER* io = Icc ->IOhandler;
       
  1075     cmsTagDescriptor* TagDescriptor;
       
  1076     cmsTagTypeSignature TypeBase;
       
  1077     cmsTagTypeHandler* TypeHandler;
       
  1078 
       
  1079 
       
  1080     for (i=0; i < Icc -> TagCount; i++) {
       
  1081 
       
  1082 
       
  1083         if (Icc ->TagNames[i] == 0) continue;
       
  1084 
       
  1085         // Linked tags are not written
       
  1086         if (Icc ->TagLinked[i] != (cmsTagSignature) 0) continue;
       
  1087 
       
  1088         Icc -> TagOffsets[i] = Begin = io ->UsedSpace;
       
  1089 
       
  1090         Data = (cmsUInt8Number*)  Icc -> TagPtrs[i];
       
  1091 
       
  1092         if (!Data) {
       
  1093 
       
  1094             // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user.
       
  1095             // In this case a blind copy of the block data is performed
       
  1096             if (FileOrig != NULL && Icc -> TagOffsets[i]) {
       
  1097 
       
  1098                 cmsUInt32Number TagSize   = FileOrig -> TagSizes[i];
       
  1099                 cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
       
  1100                 void* Mem;
       
  1101 
       
  1102                 if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE;
       
  1103 
       
  1104                 Mem = _cmsMalloc(Icc ->ContextID, TagSize);
       
  1105                 if (Mem == NULL) return FALSE;
       
  1106 
       
  1107                 if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE;
       
  1108                 if (!io ->Write(io, TagSize, Mem)) return FALSE;
       
  1109                 _cmsFree(Icc ->ContextID, Mem);
       
  1110 
       
  1111                 Icc -> TagSizes[i] = (io ->UsedSpace - Begin);
       
  1112 
       
  1113 
       
  1114                 // Align to 32 bit boundary.
       
  1115                 if (! _cmsWriteAlignment(io))
       
  1116                     return FALSE;
       
  1117             }
       
  1118 
       
  1119             continue;
       
  1120         }
       
  1121 
       
  1122 
       
  1123         // Should this tag be saved as RAW? If so, tagsizes should be specified in advance (no further cooking is done)
       
  1124         if (Icc ->TagSaveAsRaw[i]) {
       
  1125 
       
  1126             if (io -> Write(io, Icc ->TagSizes[i], Data) != 1) return FALSE;
       
  1127         }
       
  1128         else {
       
  1129 
       
  1130             // Search for support on this tag
       
  1131             TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]);
       
  1132             if (TagDescriptor == NULL) continue;                        // Unsupported, ignore it
       
  1133 
       
  1134             TypeHandler = Icc ->TagTypeHandlers[i];
       
  1135 
       
  1136             if (TypeHandler == NULL) {
       
  1137                 cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]);
       
  1138                 continue;
       
  1139             }
       
  1140 
       
  1141             TypeBase    = TypeHandler ->Signature;
       
  1142             if (!_cmsWriteTypeBase(io, TypeBase))
       
  1143                 return FALSE;
       
  1144 
       
  1145             if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) {
       
  1146 
       
  1147                 char String[5];
       
  1148 
       
  1149                 _cmsTagSignature2String(String, (cmsTagSignature) TypeBase);
       
  1150                 cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String);
       
  1151                 return FALSE;
       
  1152             }
       
  1153         }
       
  1154 
       
  1155 
       
  1156         Icc -> TagSizes[i] = (io ->UsedSpace - Begin);
       
  1157 
       
  1158         // Align to 32 bit boundary.
       
  1159         if (! _cmsWriteAlignment(io))
       
  1160             return FALSE;
       
  1161     }
       
  1162 
       
  1163 
       
  1164     return TRUE;
       
  1165 }
       
  1166 
       
  1167 
       
  1168 // Fill the offset and size fields for all linked tags
       
  1169 static
       
  1170 cmsBool SetLinks( _cmsICCPROFILE* Icc)
       
  1171 {
       
  1172     cmsUInt32Number i;
       
  1173 
       
  1174     for (i=0; i < Icc -> TagCount; i++) {
       
  1175 
       
  1176         cmsTagSignature lnk = Icc ->TagLinked[i];
       
  1177         if (lnk != (cmsTagSignature) 0) {
       
  1178 
       
  1179             int j = _cmsSearchTag(Icc, lnk, FALSE);
       
  1180             if (j >= 0) {
       
  1181 
       
  1182                 Icc ->TagOffsets[i] = Icc ->TagOffsets[j];
       
  1183                 Icc ->TagSizes[i]   = Icc ->TagSizes[j];
       
  1184             }
       
  1185 
       
  1186         }
       
  1187     }
       
  1188 
       
  1189     return TRUE;
       
  1190 }
       
  1191 
       
  1192 // Low-level save to IOHANDLER. It returns the number of bytes used to
       
  1193 // store the profile, or zero on error. io may be NULL and in this case
       
  1194 // no data is written--only sizes are calculated
       
  1195 cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io)
       
  1196 {
       
  1197     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
  1198     _cmsICCPROFILE Keep;
       
  1199     cmsIOHANDLER* PrevIO;
       
  1200     cmsUInt32Number UsedSpace;
       
  1201     cmsContext ContextID;
       
  1202 
       
  1203     memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
       
  1204 
       
  1205     ContextID = cmsGetProfileContextID(hProfile);
       
  1206     PrevIO = Icc ->IOhandler = cmsOpenIOhandlerFromNULL(ContextID);
       
  1207     if (PrevIO == NULL) return 0;
       
  1208 
       
  1209     // Pass #1 does compute offsets
       
  1210 
       
  1211     if (!_cmsWriteHeader(Icc, 0)) return 0;
       
  1212     if (!SaveTags(Icc, &Keep)) return 0;
       
  1213 
       
  1214     UsedSpace = PrevIO ->UsedSpace;
       
  1215 
       
  1216     // Pass #2 does save to iohandler
       
  1217 
       
  1218     if (io != NULL) {
       
  1219         Icc ->IOhandler = io;
       
  1220         if (!SetLinks(Icc)) goto CleanUp;
       
  1221         if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp;
       
  1222         if (!SaveTags(Icc, &Keep)) goto CleanUp;
       
  1223     }
       
  1224 
       
  1225     memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
       
  1226     if (!cmsCloseIOhandler(PrevIO)) return 0;
       
  1227 
       
  1228     return UsedSpace;
       
  1229 
       
  1230 
       
  1231 CleanUp:
       
  1232     cmsCloseIOhandler(PrevIO);
       
  1233     memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
       
  1234     return 0;
       
  1235 }
       
  1236 
       
  1237 
       
  1238 // Low-level save to disk.
       
  1239 cmsBool  CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName)
       
  1240 {
       
  1241     cmsContext ContextID = cmsGetProfileContextID(hProfile);
       
  1242     cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w");
       
  1243     cmsBool rc;
       
  1244 
       
  1245     if (io == NULL) return FALSE;
       
  1246 
       
  1247     rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
       
  1248     rc &= cmsCloseIOhandler(io);
       
  1249 
       
  1250     if (rc == FALSE) {          // remove() is C99 per 7.19.4.1
       
  1251             remove(FileName);   // We have to IGNORE return value in this case
       
  1252     }
       
  1253     return rc;
       
  1254 }
       
  1255 
       
  1256 // Same as anterior, but for streams
       
  1257 cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream)
       
  1258 {
       
  1259     cmsBool rc;
       
  1260     cmsContext ContextID = cmsGetProfileContextID(hProfile);
       
  1261     cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream);
       
  1262 
       
  1263     if (io == NULL) return FALSE;
       
  1264 
       
  1265     rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
       
  1266     rc &= cmsCloseIOhandler(io);
       
  1267 
       
  1268     return rc;
       
  1269 }
       
  1270 
       
  1271 
       
  1272 // Same as anterior, but for memory blocks. In this case, a NULL as MemPtr means calculate needed space only
       
  1273 cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUInt32Number* BytesNeeded)
       
  1274 {
       
  1275     cmsBool rc;
       
  1276     cmsIOHANDLER* io;
       
  1277     cmsContext ContextID = cmsGetProfileContextID(hProfile);
       
  1278 
       
  1279     // Should we just calculate the needed space?
       
  1280     if (MemPtr == NULL) {
       
  1281 
       
  1282            *BytesNeeded =  cmsSaveProfileToIOhandler(hProfile, NULL);
       
  1283             return TRUE;
       
  1284     }
       
  1285 
       
  1286     // That is a real write operation
       
  1287     io =  cmsOpenIOhandlerFromMem(ContextID, MemPtr, *BytesNeeded, "w");
       
  1288     if (io == NULL) return FALSE;
       
  1289 
       
  1290     rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0);
       
  1291     rc &= cmsCloseIOhandler(io);
       
  1292 
       
  1293     return rc;
       
  1294 }
       
  1295 
       
  1296 
       
  1297 
       
  1298 // Closes a profile freeing any involved resources
       
  1299 cmsBool  CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
       
  1300 {
       
  1301     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
  1302     cmsBool  rc = TRUE;
       
  1303     cmsUInt32Number i;
       
  1304 
       
  1305     if (!Icc) return FALSE;
       
  1306 
       
  1307     // Was open in write mode?
       
  1308     if (Icc ->IsWrite) {
       
  1309 
       
  1310         Icc ->IsWrite = FALSE;      // Assure no further writting
       
  1311         rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile);
       
  1312     }
       
  1313 
       
  1314     for (i=0; i < Icc -> TagCount; i++) {
       
  1315 
       
  1316         if (Icc -> TagPtrs[i]) {
       
  1317 
       
  1318             cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
       
  1319 
       
  1320             if (TypeHandler != NULL)
       
  1321                 TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
       
  1322             else
       
  1323                 _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
       
  1324         }
       
  1325     }
       
  1326 
       
  1327     if (Icc ->IOhandler != NULL) {
       
  1328         rc &= cmsCloseIOhandler(Icc->IOhandler);
       
  1329     }
       
  1330 
       
  1331     _cmsFree(Icc ->ContextID, Icc);   // Free placeholder memory
       
  1332 
       
  1333     return rc;
       
  1334 }
       
  1335 
       
  1336 
       
  1337 // -------------------------------------------------------------------------------------------------------------------
       
  1338 
       
  1339 
       
  1340 // Returns TRUE if a given tag is supported by a plug-in
       
  1341 static
       
  1342 cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Type)
       
  1343 {
       
  1344     cmsUInt32Number i, nMaxTypes;
       
  1345 
       
  1346     nMaxTypes = TagDescriptor->nSupportedTypes;
       
  1347     if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN)
       
  1348         nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN;
       
  1349 
       
  1350     for (i=0; i < nMaxTypes; i++) {
       
  1351         if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE;
       
  1352     }
       
  1353 
       
  1354     return FALSE;
       
  1355 }
       
  1356 
       
  1357 
       
  1358 // That's the main read function
       
  1359 void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
       
  1360 {
       
  1361     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
  1362     cmsIOHANDLER* io = Icc ->IOhandler;
       
  1363     cmsTagTypeHandler* TypeHandler;
       
  1364     cmsTagDescriptor*  TagDescriptor;
       
  1365     cmsTagTypeSignature BaseType;
       
  1366     cmsUInt32Number Offset, TagSize;
       
  1367     cmsUInt32Number ElemCount;
       
  1368     int n;
       
  1369 
       
  1370     n = _cmsSearchTag(Icc, sig, TRUE);
       
  1371     if (n < 0) return NULL;                 // Not found, return NULL
       
  1372 
       
  1373 
       
  1374 
       
  1375     // If the element is already in memory, return the pointer
       
  1376     if (Icc -> TagPtrs[n]) {
       
  1377 
       
  1378         if (Icc ->TagSaveAsRaw[n]) return NULL;  // We don't support read raw tags as cooked
       
  1379         return Icc -> TagPtrs[n];
       
  1380     }
       
  1381 
       
  1382     // We need to read it. Get the offset and size to the file
       
  1383     Offset    = Icc -> TagOffsets[n];
       
  1384     TagSize   = Icc -> TagSizes[n];
       
  1385 
       
  1386     // Seek to its location
       
  1387     if (!io -> Seek(io, Offset))
       
  1388             return NULL;
       
  1389 
       
  1390     // Search for support on this tag
       
  1391     TagDescriptor = _cmsGetTagDescriptor(sig);
       
  1392     if (TagDescriptor == NULL) return NULL;     // Unsupported.
       
  1393 
       
  1394     // if supported, get type and check if in list
       
  1395     BaseType = _cmsReadTypeBase(io);
       
  1396     if (BaseType == 0) return NULL;
       
  1397 
       
  1398     if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL;
       
  1399 
       
  1400     TagSize  -= 8;                      // Alredy read by the type base logic
       
  1401 
       
  1402     // Get type handler
       
  1403     TypeHandler = _cmsGetTagTypeHandler(BaseType);
       
  1404     if (TypeHandler == NULL) return NULL;
       
  1405 
       
  1406 
       
  1407     // Read the tag
       
  1408     Icc -> TagTypeHandlers[n] = TypeHandler;
       
  1409     Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize);
       
  1410 
       
  1411     // The tag type is supported, but something wrong happend and we cannot read the tag.
       
  1412     // let know the user about this (although it is just a warning)
       
  1413     if (Icc -> TagPtrs[n] == NULL) {
       
  1414 
       
  1415         char String[5];
       
  1416 
       
  1417         _cmsTagSignature2String(String, sig);
       
  1418         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
       
  1419         return NULL;
       
  1420     }
       
  1421 
       
  1422     // This is a weird error that may be a symptom of something more serious, the number of
       
  1423     // stored item is actually less than the number of required elements.
       
  1424     if (ElemCount < TagDescriptor ->ElemCount) {
       
  1425 
       
  1426         char String[5];
       
  1427 
       
  1428         _cmsTagSignature2String(String, sig);
       
  1429         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d",
       
  1430                                                              String, TagDescriptor ->ElemCount, ElemCount);
       
  1431     }
       
  1432 
       
  1433 
       
  1434     // Return the data
       
  1435     return Icc -> TagPtrs[n];
       
  1436 }
       
  1437 
       
  1438 
       
  1439 // Get true type of data
       
  1440 cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig)
       
  1441 {
       
  1442     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
  1443     cmsTagTypeHandler* TypeHandler;
       
  1444     int n;
       
  1445 
       
  1446     // Search for given tag in ICC profile directory
       
  1447     n = _cmsSearchTag(Icc, sig, TRUE);
       
  1448     if (n < 0) return (cmsTagTypeSignature) 0;                // Not found, return NULL
       
  1449 
       
  1450     // Get the handler. The true type is there
       
  1451     TypeHandler =  Icc -> TagTypeHandlers[n];
       
  1452     return TypeHandler ->Signature;
       
  1453 }
       
  1454 
       
  1455 
       
  1456 // Write a single tag. This just keeps track of the tak into a list of "to be written". If the tag is already
       
  1457 // in that list, the previous version is deleted.
       
  1458 cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data)
       
  1459 {
       
  1460     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
  1461     cmsTagTypeHandler* TypeHandler = NULL;
       
  1462     cmsTagDescriptor* TagDescriptor = NULL;
       
  1463     cmsTagTypeSignature Type;
       
  1464     int i;
       
  1465     cmsFloat64Number Version;
       
  1466 
       
  1467 
       
  1468     if (data == NULL) {
       
  1469 
       
  1470          cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag");
       
  1471          return FALSE;
       
  1472     }
   373 
  1473 
   374     i = _cmsSearchTag(Icc, sig, FALSE);
  1474     i = _cmsSearchTag(Icc, sig, FALSE);
   375 
       
   376     if (i >=0) {
  1475     if (i >=0) {
   377 
  1476 
   378         if (Icc -> TagPtrs[i]) _cmsFree(Icc -> TagPtrs[i]);
  1477         if (Icc -> TagPtrs[i] != NULL) {
       
  1478 
       
  1479             // Already exists. Free previous version
       
  1480             if (Icc ->TagSaveAsRaw[i]) {
       
  1481                 _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
       
  1482             }
       
  1483             else {
       
  1484                 TypeHandler = Icc ->TagTypeHandlers[i];
       
  1485                 TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]);
       
  1486             }
       
  1487         }
   379     }
  1488     }
   380     else  {
  1489     else  {
   381 
  1490         // New one
   382         i = Icc -> TagCount;
  1491         i = Icc -> TagCount;
       
  1492 
       
  1493         if (i >= MAX_TABLE_TAG) {
       
  1494             cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
       
  1495             return FALSE;
       
  1496         }
       
  1497 
   383         Icc -> TagCount++;
  1498         Icc -> TagCount++;
   384 
  1499     }
   385         if (Icc ->TagCount >= MAX_TABLE_TAG) {
  1500 
   386 
  1501     // This is not raw
   387             cmsSignalError(LCMS_ERRC_ABORTED, "Too many tags (%d)", MAX_TABLE_TAG);
  1502     Icc ->TagSaveAsRaw[i] = FALSE;
   388             Icc ->TagCount = MAX_TABLE_TAG-1;
  1503 
   389             return NULL;
  1504     // This is not a link
       
  1505     Icc ->TagLinked[i] = (cmsTagSignature) 0;
       
  1506 
       
  1507     // Get information about the TAG.
       
  1508     TagDescriptor = _cmsGetTagDescriptor(sig);
       
  1509     if (TagDescriptor == NULL){
       
  1510          cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig);
       
  1511         return FALSE;
       
  1512     }
       
  1513 
       
  1514 
       
  1515     // Now we need to know which type to use. It depends on the version.
       
  1516     Version = cmsGetProfileVersion(hProfile);
       
  1517     if (TagDescriptor ->DecideType != NULL) {
       
  1518 
       
  1519         // Let the tag descriptor to decide the type base on depending on
       
  1520         // the data. This is useful for example on parametric curves, where
       
  1521         // curves specified by a table cannot be saved as parametric and needs
       
  1522         // to be revented to single v2-curves, even on v4 profiles.
       
  1523 
       
  1524         Type = TagDescriptor ->DecideType(Version, data);
       
  1525     }
       
  1526     else {
       
  1527 
       
  1528         Type = TagDescriptor ->SupportedTypes[0];
       
  1529     }
       
  1530 
       
  1531     // Does the tag support this type?
       
  1532     if (!IsTypeSupported(TagDescriptor, Type)) {
       
  1533         cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig);
       
  1534         return FALSE;
       
  1535     }
       
  1536 
       
  1537     // Does we have a handler for this type?
       
  1538     TypeHandler =  _cmsGetTagTypeHandler(Type);
       
  1539     if (TypeHandler == NULL) {
       
  1540         cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig);
       
  1541         return FALSE;           // Should never happen
       
  1542     }
       
  1543 
       
  1544     // Fill fields on icc structure
       
  1545     Icc ->TagTypeHandlers[i]  = TypeHandler;
       
  1546     Icc ->TagNames[i]         = sig;
       
  1547     Icc ->TagSizes[i]         = 0;
       
  1548     Icc ->TagOffsets[i]       = 0;
       
  1549     Icc ->TagPtrs[i]          = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
       
  1550 
       
  1551     if (Icc ->TagPtrs[i] == NULL)  {
       
  1552 
       
  1553         TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount);
       
  1554         cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%x' for tag '%x'", Type, sig);
       
  1555 
       
  1556         return FALSE;
       
  1557     }
       
  1558 
       
  1559     return TRUE;
       
  1560 }
       
  1561 
       
  1562 // Read and write raw data. The only way those function would work and keep consistence with normal read and write
       
  1563 // is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained
       
  1564 // data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where
       
  1565 // raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows
       
  1566 // to write a tag as raw data and the read it as handled.
       
  1567 
       
  1568 cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize)
       
  1569 {
       
  1570     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
       
  1571     void *Object;
       
  1572     int i;
       
  1573     cmsIOHANDLER* MemIO;
       
  1574     cmsTagTypeHandler* TypeHandler = NULL;
       
  1575     cmsTagDescriptor* TagDescriptor = NULL;
       
  1576     cmsUInt32Number rc;
       
  1577     cmsUInt32Number Offset, TagSize;
       
  1578 
       
  1579     // Search for given tag in ICC profile directory
       
  1580     i = _cmsSearchTag(Icc, sig, TRUE);
       
  1581     if (i < 0) return 0;                 // Not found, return 0
       
  1582 
       
  1583     // It is already read?
       
  1584     if (Icc -> TagPtrs[i] == NULL) {
       
  1585 
       
  1586         // No yet, get original position
       
  1587         Offset   = Icc ->TagOffsets[i];
       
  1588         TagSize  = Icc ->TagSizes[i];
       
  1589 
       
  1590 
       
  1591         // read the data directly, don't keep copy
       
  1592         if (data != NULL) {
       
  1593 
       
  1594             if (BufferSize < TagSize)
       
  1595                  TagSize = BufferSize;
       
  1596 
       
  1597             if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0;
       
  1598             if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0;
   390         }
  1599         }
   391     }
  1600 
   392 
  1601         return Icc ->TagSizes[i];
   393 
  1602     }
   394     Ptr = _cmsMalloc(size);
  1603 
   395     if (Ptr == NULL) return NULL;
  1604     // The data has been already read, or written. But wait!, maybe the user choosed to save as
   396 
  1605     // raw data. In this case, return the raw data directly
   397     CopyMemory(Ptr, Init, size);
  1606     if (Icc ->TagSaveAsRaw[i]) {
   398 
  1607 
   399     Icc ->TagNames[i] = sig;
  1608         if (data != NULL)  {
   400     Icc ->TagSizes[i] = size;
  1609 
   401     Icc ->TagPtrs[i]  = Ptr;
  1610             TagSize  = Icc ->TagSizes[i];
   402 
  1611             if (BufferSize < TagSize)
   403     return Ptr;
  1612                        TagSize = BufferSize;
   404 }
  1613 
   405 
  1614             memmove(data, Icc ->TagPtrs[i], TagSize);
   406 
  1615         }
   407 
  1616 
   408 
  1617         return Icc ->TagSizes[i];
   409 
  1618     }
   410 // Creates a profile from file read placeholder
  1619 
   411 
  1620     // Already readed, or previously set by cmsWriteTag(). We need to serialize that
   412 LPLCMSICCPROFILE _cmsCreateProfileFromFilePlaceholder(const char* FileName)
  1621     // data to raw in order to maintain consistency.
   413 {
  1622     Object = cmsReadTag(hProfile, sig);
   414     LPLCMSICCPROFILE NewIcc;
  1623     if (Object == NULL) return 0;
   415     LPVOID ICCfile = FileOpen(FileName);
  1624 
   416 
  1625     // Now we need to serialize to a memory block: just use a memory iohandler
   417     if (ICCfile == NULL) {
  1626 
   418 
  1627     if (data == NULL) {
   419               cmsSignalError(LCMS_ERRC_ABORTED, "File '%s' not found", FileName);
  1628         MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile));
   420               return NULL;
  1629     } else{
   421     }
  1630           MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
   422 
  1631     }
   423     NewIcc = (LPLCMSICCPROFILE) _cmsCreateProfilePlaceholder();
  1632     if (MemIO == NULL) return 0;
   424     if (NewIcc == NULL) return NULL;
  1633 
   425 
  1634     // Obtain type handling for the tag
   426     strncpy(NewIcc -> PhysicalFile, FileName, MAX_PATH-1);
  1635     TypeHandler = Icc ->TagTypeHandlers[i];
   427     NewIcc -> PhysicalFile[MAX_PATH-1] = 0;
  1636     TagDescriptor = _cmsGetTagDescriptor(sig);
   428 
  1637 
   429     NewIcc ->stream = ICCfile;
  1638     // Serialize
   430 
  1639     if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0;
   431     NewIcc ->Read  = FileRead;
  1640 
   432     NewIcc ->Seek  = FileSeek;
  1641     // Get Size and close
   433     NewIcc ->Tell  = FileTell;
  1642     rc = MemIO ->Tell(MemIO);
   434     NewIcc ->Close = FileClose;
  1643     cmsCloseIOhandler(MemIO);      // Ignore return code this time
   435     NewIcc ->Grow  = FileGrow;
  1644 
   436     NewIcc ->Write = NULL;
  1645     return rc;
   437 
  1646 }
   438     NewIcc ->IsWrite = FALSE;
  1647 
   439 
  1648 // Similar to the anterior. This function allows to write directly to the ICC profile any data, without
   440 
  1649 // checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading
   441 
  1650 // it as cooked without serializing does result into an error. If that is wha you want, you will need to dump
   442 
  1651 // the profile to memry or disk and then reopen it.
   443     return NewIcc;
  1652 cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size)
   444 }
  1653 {
   445 
  1654     _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
   446 
  1655     int i;
   447 // Creates a profile from memory read placeholder
  1656 
   448 
  1657     if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
   449 LPLCMSICCPROFILE _cmsCreateProfileFromMemPlaceholder(LPVOID MemPtr, DWORD dwSize)
  1658 
   450 {
  1659     // Mark the tag as being written as RAW
   451 
  1660     Icc ->TagSaveAsRaw[i] = TRUE;
   452     LPLCMSICCPROFILE NewIcc;
  1661     Icc ->TagNames[i]     = sig;
   453     LPVOID ICCfile = MemoryOpen((LPBYTE) MemPtr, (size_t) dwSize, 'r');
  1662     Icc ->TagLinked[i]    = (cmsTagSignature) 0;
   454 
  1663 
   455 
  1664     // Keep a copy of the block
   456     if (ICCfile == NULL) {
  1665     Icc ->TagPtrs[i]  = _cmsDupMem(Icc ->ContextID, data, Size);
   457 
  1666     Icc ->TagSizes[i] = Size;
   458         cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't allocate %ld bytes for profile", dwSize);
  1667 
   459         return NULL;
       
   460     }
       
   461 
       
   462 
       
   463     NewIcc = (LPLCMSICCPROFILE) _cmsCreateProfilePlaceholder();
       
   464     if (NewIcc == NULL) return NULL;
       
   465 
       
   466     NewIcc -> PhysicalFile[0] = 0;
       
   467     NewIcc ->stream = ICCfile;
       
   468 
       
   469     NewIcc ->Read  = MemoryRead;
       
   470     NewIcc ->Seek  = MemorySeek;
       
   471     NewIcc ->Tell  = MemoryTell;
       
   472     NewIcc ->Close = MemoryClose;
       
   473     NewIcc ->Grow  = MemoryGrow;
       
   474     NewIcc ->Write = MemoryWrite;
       
   475 
       
   476     NewIcc ->IsWrite = FALSE;
       
   477 
       
   478 
       
   479     return NewIcc;
       
   480 }
       
   481 
       
   482 
       
   483 // Turn a placeholder into file writter
       
   484 
       
   485 void _cmsSetSaveToDisk(LPLCMSICCPROFILE Icc, const char* FileName)
       
   486 {
       
   487 
       
   488     if (FileName == NULL) {
       
   489 
       
   490           Icc ->stream = NULL;
       
   491     }
       
   492     else {
       
   493 
       
   494           Icc ->stream = fopen(FileName, "wb");
       
   495           if (Icc ->stream == NULL)
       
   496                 cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't write to file '%s'", FileName);
       
   497     }
       
   498 
       
   499     Icc ->Write = FileWrite;   // Save to disk
       
   500     Icc ->Close = FileClose;
       
   501 }
       
   502 
       
   503 
       
   504 
       
   505 // Turn a  placeholder into memory writter
       
   506 
       
   507 void _cmsSetSaveToMemory(LPLCMSICCPROFILE Icc, LPVOID MemPtr, size_t dwSize)
       
   508 {
       
   509 
       
   510     if (MemPtr == NULL) {
       
   511 
       
   512         Icc ->stream = NULL;
       
   513     }
       
   514     else {
       
   515 
       
   516         Icc ->stream = (FILEMEM*) MemoryOpen((LPBYTE) MemPtr, dwSize, 'w');
       
   517         if (Icc ->stream == NULL)
       
   518                 cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't write to memory");
       
   519     }
       
   520 
       
   521     Icc ->Write = MemoryWrite;
       
   522     Icc ->Close = MemoryClose;
       
   523 }
       
   524 
       
   525 
       
   526 // ----------------------------------------------------------------------- Set/Get several struct members
       
   527 
       
   528 
       
   529 
       
   530 
       
   531 LCMSBOOL LCMSEXPORT cmsTakeMediaWhitePoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile)
       
   532 {
       
   533      LPLCMSICCPROFILE    Icc = (LPLCMSICCPROFILE) hProfile;
       
   534      *Dest = Icc -> MediaWhitePoint;
       
   535      return TRUE;
       
   536 }
       
   537 
       
   538 
       
   539 LCMSBOOL LCMSEXPORT cmsTakeMediaBlackPoint(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile)
       
   540 {
       
   541       LPLCMSICCPROFILE    Icc = (LPLCMSICCPROFILE) hProfile;
       
   542       *Dest = Icc -> MediaBlackPoint;
       
   543       return TRUE;
       
   544 }
       
   545 
       
   546 LCMSBOOL  LCMSEXPORT cmsTakeIluminant(LPcmsCIEXYZ Dest, cmsHPROFILE hProfile)
       
   547 {
       
   548        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   549        *Dest = Icc -> Illuminant;
       
   550        return TRUE;
       
   551 }
       
   552 
       
   553 int LCMSEXPORT cmsTakeRenderingIntent(cmsHPROFILE hProfile)
       
   554 {
       
   555        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   556        return (int) Icc -> RenderingIntent;
       
   557 }
       
   558 
       
   559 void LCMSEXPORT cmsSetRenderingIntent(cmsHPROFILE hProfile, int RenderingIntent)
       
   560 {
       
   561     LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   562     Icc -> RenderingIntent = (icRenderingIntent) RenderingIntent;
       
   563 }
       
   564 
       
   565 
       
   566 DWORD LCMSEXPORT cmsTakeHeaderFlags(cmsHPROFILE hProfile)
       
   567 {
       
   568        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   569        return (DWORD) Icc -> flags;
       
   570 }
       
   571 
       
   572 void LCMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, DWORD Flags)
       
   573 {
       
   574     LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   575     Icc -> flags = (icUInt32Number) Flags;
       
   576 }
       
   577 
       
   578 DWORD LCMSEXPORT cmsTakeHeaderAttributes(cmsHPROFILE hProfile)
       
   579 {
       
   580        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   581        return (DWORD) Icc -> attributes;
       
   582 }
       
   583 
       
   584 void LCMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, DWORD Flags)
       
   585 {
       
   586     LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   587     Icc -> attributes = (icUInt32Number) Flags;
       
   588 }
       
   589 
       
   590 
       
   591 const BYTE* LCMSEXPORT cmsTakeProfileID(cmsHPROFILE hProfile)
       
   592 {
       
   593     LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   594     return Icc ->ProfileID;
       
   595 }
       
   596 
       
   597 void LCMSEXPORT cmsSetProfileID(cmsHPROFILE hProfile, LPBYTE ProfileID)
       
   598 {
       
   599     LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   600     CopyMemory(Icc -> ProfileID, ProfileID, 16);
       
   601 }
       
   602 
       
   603 
       
   604 LCMSBOOL LCMSEXPORT cmsTakeCreationDateTime(struct tm *Dest, cmsHPROFILE hProfile)
       
   605 {
       
   606     LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   607     CopyMemory(Dest, &Icc ->Created, sizeof(struct tm));
       
   608     return TRUE;
  1668     return TRUE;
   609 }
  1669 }
   610 
  1670 
   611 
  1671 // Using this function you can collapse several tag entries to the same block in the profile
   612 icColorSpaceSignature LCMSEXPORT cmsGetPCS(cmsHPROFILE hProfile)
  1672 cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest)
   613 {
  1673 {
   614        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
  1674      _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
   615        return Icc -> PCS;
  1675     int i;
   616 }
  1676 
   617 
  1677     if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
   618 
  1678 
   619 void LCMSEXPORT cmsSetPCS(cmsHPROFILE hProfile, icColorSpaceSignature pcs)
  1679     // Keep necessary information
   620 {
  1680     Icc ->TagSaveAsRaw[i] = FALSE;
   621        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
  1681     Icc ->TagNames[i]     = sig;
   622        Icc -> PCS = pcs;
  1682     Icc ->TagLinked[i]    = dest;
   623 }
  1683 
   624 
  1684     Icc ->TagPtrs[i]    = NULL;
   625 icColorSpaceSignature LCMSEXPORT cmsGetColorSpace(cmsHPROFILE hProfile)
  1685     Icc ->TagSizes[i]   = 0;
   626 {
  1686     Icc ->TagOffsets[i] = 0;
   627        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
  1687 
   628        return Icc -> ColorSpace;
       
   629 }
       
   630 
       
   631 void LCMSEXPORT cmsSetColorSpace(cmsHPROFILE hProfile, icColorSpaceSignature sig)
       
   632 {
       
   633        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   634        Icc -> ColorSpace = sig;
       
   635 }
       
   636 
       
   637 icProfileClassSignature LCMSEXPORT cmsGetDeviceClass(cmsHPROFILE hProfile)
       
   638 {
       
   639        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   640        return Icc -> DeviceClass;
       
   641 }
       
   642 
       
   643 DWORD LCMSEXPORT cmsGetProfileICCversion(cmsHPROFILE hProfile)
       
   644 {
       
   645        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   646        return (DWORD) Icc -> Version;
       
   647 }
       
   648 
       
   649 void LCMSEXPORT cmsSetProfileICCversion(cmsHPROFILE hProfile, DWORD Version)
       
   650 {
       
   651    LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   652    Icc -> Version = Version;
       
   653 }
       
   654 
       
   655 
       
   656 void LCMSEXPORT cmsSetDeviceClass(cmsHPROFILE hProfile, icProfileClassSignature sig)
       
   657 {
       
   658        LPLCMSICCPROFILE  Icc = (LPLCMSICCPROFILE) hProfile;
       
   659        Icc -> DeviceClass = sig;
       
   660 }
       
   661 
       
   662 
       
   663 // --------------------------------------------------------------------------------------------------------------
       
   664 
       
   665 
       
   666 static
       
   667 int SizeOfGammaTab(LPGAMMATABLE In)
       
   668 {
       
   669        return sizeof(GAMMATABLE) + (In -> nEntries - 1)*sizeof(WORD);
       
   670 }
       
   671 
       
   672 
       
   673 // Creates a phantom tag holding a memory block
       
   674 
       
   675 static
       
   676 LPVOID DupBlock(LPLCMSICCPROFILE Icc, LPVOID Block, size_t size)
       
   677 {
       
   678     if (Block != NULL && size > 0)
       
   679         return _cmsInitTag(Icc, (icTagSignature) 0, size, Block);
       
   680     else
       
   681         return NULL;
       
   682 
       
   683 }
       
   684 
       
   685 // This is tricky, since LUT structs does have pointers
       
   686 
       
   687 LCMSBOOL LCMSEXPORT _cmsAddLUTTag(cmsHPROFILE hProfile, icTagSignature sig, const void* lut)
       
   688 {
       
   689        LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   690        LPLUT Orig, Stored;
       
   691        unsigned int i;
       
   692 
       
   693        // The struct itself
       
   694 
       
   695        Orig   = (LPLUT) lut;
       
   696        Stored = (LPLUT) _cmsInitTag(Icc, (icTagSignature) sig, sizeof(LUT), lut);
       
   697 
       
   698        // dup' the memory blocks
       
   699        for (i=0; i < Orig ->InputChan; i++)
       
   700             Stored -> L1[i] = (LPWORD) DupBlock(Icc, (LPWORD) Orig ->L1[i],
       
   701                                             sizeof(WORD) * Orig ->In16params.nSamples);
       
   702 
       
   703        for (i=0; i < Orig ->OutputChan; i++)
       
   704             Stored -> L2[i] = (LPWORD) DupBlock(Icc, (LPWORD) Orig ->L2[i],
       
   705                                             sizeof(WORD) * Orig ->Out16params.nSamples);
       
   706 
       
   707        Stored -> T     = (LPWORD) DupBlock(Icc, (LPWORD) Orig ->T, Orig -> Tsize);
       
   708 
       
   709        // Zero any additional pointer
       
   710        Stored ->CLut16params.p8 = NULL;
       
   711        return TRUE;
       
   712 }
       
   713 
       
   714 
       
   715 LCMSBOOL LCMSEXPORT _cmsAddXYZTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* XYZ)
       
   716 {
       
   717        LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   718 
       
   719        _cmsInitTag(Icc, sig, sizeof(cmsCIEXYZ), XYZ);
       
   720        return TRUE;
       
   721 }
       
   722 
       
   723 
       
   724 LCMSBOOL LCMSEXPORT _cmsAddTextTag(cmsHPROFILE hProfile, icTagSignature sig, const char* Text)
       
   725 {
       
   726        LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   727 
       
   728        _cmsInitTag(Icc, sig, strlen(Text)+1, (LPVOID) Text);
       
   729        return TRUE;
       
   730 }
       
   731 
       
   732 LCMSBOOL LCMSEXPORT _cmsAddGammaTag(cmsHPROFILE hProfile, icTagSignature sig, LPGAMMATABLE TransferFunction)
       
   733 {
       
   734     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   735 
       
   736     _cmsInitTag(Icc, sig, SizeOfGammaTab(TransferFunction), TransferFunction);
       
   737     return TRUE;
  1688     return TRUE;
   738 }
  1689 }
   739 
       
   740 
       
   741 LCMSBOOL LCMSEXPORT _cmsAddChromaticityTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsCIExyYTRIPLE Chrm)
       
   742 {
       
   743     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   744 
       
   745     _cmsInitTag(Icc, sig, sizeof(cmsCIExyYTRIPLE), Chrm);
       
   746     return TRUE;
       
   747 }
       
   748 
       
   749 
       
   750 LCMSBOOL LCMSEXPORT _cmsAddSequenceDescriptionTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsSEQ pseq)
       
   751 {
       
   752     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   753 
       
   754     _cmsInitTag(Icc, sig, sizeof(int) + pseq -> n * sizeof(cmsPSEQDESC), pseq);
       
   755     return TRUE;
       
   756 
       
   757 }
       
   758 
       
   759 
       
   760 LCMSBOOL LCMSEXPORT _cmsAddNamedColorTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc)
       
   761 {
       
   762     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   763 
       
   764     _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc);
       
   765     return TRUE;
       
   766 }
       
   767 
       
   768 
       
   769 LCMSBOOL LCMSEXPORT _cmsAddDateTimeTag(cmsHPROFILE hProfile, icTagSignature sig, struct tm *DateTime)
       
   770 {
       
   771     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   772 
       
   773     _cmsInitTag(Icc, sig, sizeof(struct tm), DateTime);
       
   774     return TRUE;
       
   775 }
       
   776 
       
   777 
       
   778 LCMSBOOL LCMSEXPORT _cmsAddColorantTableTag(cmsHPROFILE hProfile, icTagSignature sig, LPcmsNAMEDCOLORLIST nc)
       
   779 {
       
   780     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   781 
       
   782     _cmsInitTag(Icc, sig, sizeof(cmsNAMEDCOLORLIST) + (nc ->nColors - 1) * sizeof(cmsNAMEDCOLOR), nc);
       
   783     return TRUE;
       
   784 }
       
   785 
       
   786 
       
   787 LCMSBOOL LCMSEXPORT _cmsAddChromaticAdaptationTag(cmsHPROFILE hProfile, icTagSignature sig, const cmsCIEXYZ* mat)
       
   788 {
       
   789     LPLCMSICCPROFILE Icc = (LPLCMSICCPROFILE) (LPSTR) hProfile;
       
   790 
       
   791     _cmsInitTag(Icc, sig, 3*sizeof(cmsCIEXYZ), mat);
       
   792     return TRUE;
       
   793 
       
   794 }
       
   795 
       
   796