diff options
Diffstat (limited to 'thirdparty/liblcms2/src/cmsio0.c')
| -rw-r--r-- | thirdparty/liblcms2/src/cmsio0.c | 772 |
1 files changed, 457 insertions, 315 deletions
diff --git a/thirdparty/liblcms2/src/cmsio0.c b/thirdparty/liblcms2/src/cmsio0.c index 589ea6a3..4449acd4 100644 --- a/thirdparty/liblcms2/src/cmsio0.c +++ b/thirdparty/liblcms2/src/cmsio0.c @@ -1,24 +1,24 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in +// The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //--------------------------------------------------------------------------------- @@ -37,18 +37,18 @@ // NULL IOhandler basically does nothing but keep track on how many bytes have been // written. This is handy when creating profiles, where the file size is needed in the -// header. Then, whole profile is serialized across NULL IOhandler and a second pass +// header. Then, whole profile is serialized across NULL IOhandler and a second pass // writes the bytes to the pertinent IOhandler. -typedef struct { +typedef struct { cmsUInt32Number Pointer; // Points to current location } FILENULL; static cmsUInt32Number NULLRead(cmsIOHANDLER* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ +{ FILENULL* ResData = (FILENULL*) iohandler ->stream; - + cmsUInt32Number len = size * count; ResData -> Pointer += len; return count; @@ -61,15 +61,15 @@ cmsBool NULLSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) { FILENULL* ResData = (FILENULL*) iohandler ->stream; - ResData ->Pointer = offset; - return TRUE; + ResData ->Pointer = offset; + return TRUE; } static cmsUInt32Number NULLTell(cmsIOHANDLER* iohandler) { FILENULL* ResData = (FILENULL*) iohandler ->stream; - return ResData -> Pointer; + return ResData -> Pointer; } static @@ -88,9 +88,9 @@ cmsBool NULLWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void *Pt static cmsBool NULLClose(cmsIOHANDLER* iohandler) -{ +{ FILENULL* ResData = (FILENULL*) iohandler ->stream; - + _cmsFree(iohandler ->ContextID, ResData); _cmsFree(iohandler ->ContextID, iohandler); return TRUE; @@ -101,17 +101,17 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) { struct _cms_io_handler* iohandler = NULL; FILENULL* fm = NULL; - + iohandler = (struct _cms_io_handler*) _cmsMallocZero(ContextID, sizeof(struct _cms_io_handler)); if (iohandler == NULL) return NULL; fm = (FILENULL*) _cmsMallocZero(ContextID, sizeof(FILENULL)); if (fm == NULL) goto Error; - + fm ->Pointer = 0; iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; + iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; iohandler ->ReportedSize = 0; iohandler ->PhysicalFile[0] = 0; @@ -124,8 +124,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) return iohandler; -Error: - if (fm) _cmsFree(ContextID, fm); +Error: if (iohandler) _cmsFree(ContextID, iohandler); return NULL; @@ -146,7 +145,7 @@ typedef struct { static cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsUInt32Number size, cmsUInt32Number count) -{ +{ FILEMEM* ResData = (FILEMEM*) iohandler ->stream; cmsUInt8Number* Ptr; cmsUInt32Number len = size * count; @@ -160,7 +159,7 @@ cmsUInt32Number MemoryRead(struct _cms_io_handler* iohandler, void *Buffer, cmsU Ptr = ResData -> Block; Ptr += ResData -> Pointer; - memmove(Buffer, Ptr, len); + memmove(Buffer, Ptr, len); ResData -> Pointer += len; return count; @@ -173,12 +172,12 @@ cmsBool MemorySeek(struct _cms_io_handler* iohandler, cmsUInt32Number offset) FILEMEM* ResData = (FILEMEM*) iohandler ->stream; if (offset > ResData ->Size) { - cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); + cmsSignalError(iohandler ->ContextID, cmsERROR_SEEK, "Too few data; probably corrupted profile"); return FALSE; } - ResData ->Pointer = offset; - return TRUE; + ResData ->Pointer = offset; + return TRUE; } // Tell for memory @@ -187,19 +186,24 @@ cmsUInt32Number MemoryTell(struct _cms_io_handler* iohandler) { FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - if (ResData == NULL) return 0; - return ResData -> Pointer; + if (ResData == NULL) return 0; + return ResData -> Pointer; } -// Writes data to memory, also keeps used space for further reference. +// Writes data to memory, also keeps used space for further reference. static -cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) +cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) { FILEMEM* ResData = (FILEMEM*) iohandler ->stream; - if (ResData == NULL) return FALSE; // Housekeeping + if (ResData == NULL) return FALSE; // Housekeeping + // Check for available space. Clip. + if (ResData->Pointer + size > ResData->Size) { + size = ResData ->Size - ResData->Pointer; + } + if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing memmove(ResData ->Block + ResData ->Pointer, Ptr, size); @@ -208,23 +212,20 @@ cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, co if (ResData ->Pointer > iohandler->UsedSpace) iohandler->UsedSpace = ResData ->Pointer; - - iohandler->UsedSpace += size; - return TRUE; } static cmsBool MemoryClose(struct _cms_io_handler* iohandler) -{ +{ FILEMEM* ResData = (FILEMEM*) iohandler ->stream; if (ResData ->FreeBlockOnClose) { if (ResData ->Block) _cmsFree(iohandler ->ContextID, ResData ->Block); } - + _cmsFree(iohandler ->ContextID, ResData); _cmsFree(iohandler ->ContextID, iohandler); @@ -232,14 +233,14 @@ cmsBool MemoryClose(struct _cms_io_handler* iohandler) } // Create a iohandler for memory block. AccessMode=='r' assumes the iohandler is going to read, and makes -// a copy of the memory block for letting user to free the memory after invoking open profile. In write +// a copy of the memory block for letting user to free the memory after invoking open profile. In write // mode ("w"), Buffere points to the begin of memory block to be written. cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buffer, cmsUInt32Number size, const char* AccessMode) { cmsIOHANDLER* iohandler = NULL; FILEMEM* fm = NULL; - _cmsAssert(AccessMode != NULL); + _cmsAssert(AccessMode != NULL); iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; @@ -272,14 +273,14 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buff iohandler -> ReportedSize = size; break; - case 'w': + case 'w': fm = (FILEMEM*) _cmsMallocZero(ContextID, sizeof(FILEMEM)); if (fm == NULL) goto Error; fm ->Block = (cmsUInt8Number*) Buffer; fm ->FreeBlockOnClose = FALSE; fm ->Size = size; - fm ->Pointer = 0; + fm ->Pointer = 0; iohandler -> ReportedSize = 0; break; @@ -289,7 +290,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buff } iohandler ->ContextID = ContextID; - iohandler ->stream = (void*) fm; + iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; iohandler ->PhysicalFile[0] = 0; @@ -339,8 +340,8 @@ cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) // Returns file pointer position static cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) -{ - return ftell((FILE*)iohandler ->stream); +{ + return (cmsUInt32Number) ftell((FILE*)iohandler ->stream); } // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error @@ -356,19 +357,21 @@ cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Bu // Closes the file static cmsBool FileClose(cmsIOHANDLER* iohandler) -{ +{ if (fclose((FILE*) iohandler ->stream) != 0) return FALSE; _cmsFree(iohandler ->ContextID, iohandler); return TRUE; } -// Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set -// to NULL and no real writting is performed. This only happens in writting access mode +// Create a iohandler for disk based files. cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) { cmsIOHANDLER* iohandler = NULL; FILE* fm = NULL; + _cmsAssert(FileName != NULL); + _cmsAssert(AccessMode != NULL); + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; @@ -381,7 +384,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); return NULL; } - iohandler -> ReportedSize = cmsfilelength(fm); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm); break; case 'w': @@ -404,12 +407,9 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; - // Keep track of the original file - if (FileName != NULL) { - - strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); - iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; - } + // Keep track of the original file + strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); + iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; iohandler ->Read = FileRead; iohandler ->Seek = FileSeek; @@ -420,20 +420,20 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha return iohandler; } -// Create a iohandler for stream based files +// Create a iohandler for stream based files cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* Stream) { cmsIOHANDLER* iohandler = NULL; - + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; iohandler -> ContextID = ContextID; iohandler -> stream = (void*) Stream; iohandler -> UsedSpace = 0; - iohandler -> ReportedSize = cmsfilelength(Stream); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream); iohandler -> PhysicalFile[0] = 0; - + iohandler ->Read = FileRead; iohandler ->Seek = FileSeek; iohandler ->Close = FileClose; @@ -465,19 +465,22 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set it to empty Icc -> TagCount = 0; - // Set default version + // Set default version Icc ->Version = 0x02100000; // Set creation date/time memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + // Create a mutex if the user provided proper plugin. NULL otherwise + Icc ->UsrMutex = _cmsCreateMutex(ContextID); + // Return the handle return (cmsHPROFILE) Icc; } cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; if (Icc == NULL) return NULL; return Icc -> ContextID; @@ -487,8 +490,8 @@ cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) // Return the number of tags cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - if (Icc == NULL) return -1; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + if (Icc == NULL) return -1; return Icc->TagCount; } @@ -496,9 +499,9 @@ cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile) // Return the tag signature of a given tag number cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Number n) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available + if (n > Icc->TagCount) return (cmsTagSignature) 0; // Mark as not available if (n >= MAX_TABLE_TAG) return (cmsTagSignature) 0; // As double check return Icc ->TagNames[n]; @@ -508,77 +511,107 @@ cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Numb static int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig) { - cmsUInt32Number i; + cmsUInt32Number i; - for (i=0; i < Profile -> TagCount; i++) { + for (i=0; i < Profile -> TagCount; i++) { - if (sig == Profile -> TagNames[i]) - return i; - } + if (sig == Profile -> TagNames[i]) + return i; + } - return -1; + return -1; } // Search for a specific tag in tag dictionary. Returns position or -1 if tag not found. // If followlinks is turned on, then the position of the linked tag is returned int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks) { - int n; - cmsTagSignature LinkedSig; + int n; + cmsTagSignature LinkedSig; - do { + do { - // Search for given tag in ICC profile directory - n = SearchOneTag(Icc, sig); - if (n < 0) - return -1; // Not found + // Search for given tag in ICC profile directory + n = SearchOneTag(Icc, sig); + if (n < 0) + return -1; // Not found - if (!lFollowLinks) - return n; // Found, don't follow links + if (!lFollowLinks) + return n; // Found, don't follow links - // Is this a linked tag? - LinkedSig = Icc ->TagLinked[n]; + // Is this a linked tag? + LinkedSig = Icc ->TagLinked[n]; - // Yes, follow link - if (LinkedSig != (cmsTagSignature) 0) { - sig = LinkedSig; - } + // Yes, follow link + if (LinkedSig != (cmsTagSignature) 0) { + sig = LinkedSig; + } - } while (LinkedSig != (cmsTagSignature) 0); + } while (LinkedSig != (cmsTagSignature) 0); - return n; + return n; } +// Deletes a tag entry -// Create a new tag entry +static +void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) +{ + _cmsAssert(Icc != NULL); + _cmsAssert(i >= 0); + + if (Icc -> TagPtrs[i] != NULL) { + + // Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + + if (TypeHandler != NULL) { + + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + Icc ->TagPtrs[i] = NULL; + } + } + + } +} + + +// Creates a new tag entry static cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) { - int i; + int i; - // Search for the tag + // Search for the tag i = _cmsSearchTag(Icc, sig, FALSE); - - // Now let's do it easy. If the tag has been already written, that's an error if (i >= 0) { - cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig); - return FALSE; + + // Already exists? delete it + _cmsDeleteTagByPos(Icc, i); + *NewPos = i; } else { - // New one - + // No, make a new one + if (Icc -> TagCount >= MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); return FALSE; } - *NewPos = Icc ->TagCount; + *NewPos = Icc ->TagCount; Icc -> TagCount++; } - return TRUE; + return TRUE; } @@ -602,25 +635,28 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) // Read the header - if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { - return FALSE; + if (io -> Read(io, &Header, sizeof(cmsICCHeader), 1) != 1) { + return FALSE; } // Validate file as an ICC profile if (_cmsAdjustEndianess32(Header.magic) != cmsMagicNumber) { cmsSignalError(Icc ->ContextID, cmsERROR_BAD_SIGNATURE, "not an ICC profile, invalid signature"); - return FALSE; + return FALSE; } // Adjust endianess of the used parameters Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); + Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> model = _cmsAdjustEndianess32(Header.model); - _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes); + Icc -> creator = _cmsAdjustEndianess32(Header.creator); + + _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); Icc -> Version = _cmsAdjustEndianess32(Header.version); // Get size as reported in header @@ -630,7 +666,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) if (HeaderSize >= Icc ->IOhandler ->ReportedSize) HeaderSize = Icc ->IOhandler ->ReportedSize; - + // Get creation date/time _cmsDecodeDateTimeNumber(&Header.date, &Icc ->Created); @@ -639,7 +675,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) // Read tag directory - if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; + if (!_cmsReadUInt32Number(io, &TagCount)) return FALSE; if (TagCount > MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", TagCount); @@ -657,7 +693,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) // Perform some sanity check. Offset + size should fall inside file. if (Tag.offset + Tag.size > HeaderSize || - Tag.offset + Tag.size < Tag.offset) + Tag.offset + Tag.size < Tag.offset) continue; Icc -> TagNames[Icc ->TagCount] = Tag.sig; @@ -670,23 +706,23 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) if ((Icc ->TagOffsets[j] == Tag.offset) && (Icc ->TagSizes[j] == Tag.size)) { - Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; + Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j]; } } Icc ->TagCount++; } - + return TRUE; } // Saves profile header cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) { - cmsICCHeader Header; + cmsICCHeader Header; cmsUInt32Number i; - cmsTagEntry Tag; + cmsTagEntry Tag; cmsInt32Number Count = 0; Header.size = _cmsAdjustEndianess32(UsedSpace); @@ -703,17 +739,17 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); #ifdef CMS_IS_WINDOWS_ - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); #else - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); #endif Header.flags = _cmsAdjustEndianess32(Icc -> flags); Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); Header.model = _cmsAdjustEndianess32(Icc -> model); - _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes); - + _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes); + // Rendering intent in the header (for embedded profiles) Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent); @@ -727,7 +763,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) memset(&Header.reserved, 0, sizeof(Header.reserved)); - // Set profile ID. Endianess is always big endian + // Set profile ID. Endianess is always big endian memmove(&Header.profileID, &Icc ->ProfileID, 16); // Dump the header @@ -742,7 +778,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) } // Store number of tags - if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; + if (!_cmsWriteUInt32Number(Icc ->IOhandler, Count)) return FALSE; for (i=0; i < Icc -> TagCount; i++) { @@ -788,28 +824,33 @@ void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags) cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc ->manufacturer; + return Icc ->manufacturer; } void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = (cmsUInt32Number) manufacturer; + Icc -> manufacturer = manufacturer; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc ->creator; } cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc ->model; + return Icc ->model; } void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = (cmsUInt32Number) model; + Icc -> model = model; } - void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; @@ -824,8 +865,8 @@ void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flag void CMSEXPORT cmsGetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(ProfileID, Icc ->ProfileID.ID8, 16); + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(ProfileID, Icc ->ProfileID.ID8, 16); } void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* ProfileID) @@ -836,8 +877,8 @@ void CMSEXPORT cmsSetHeaderProfileID(cmsHPROFILE hProfile, cmsUInt8Number* Profi cmsBool CMSEXPORT cmsGetHeaderCreationDateTime(cmsHPROFILE hProfile, struct tm *Dest) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - memmove(Dest, &Icc ->Created, sizeof(struct tm)); + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + memmove(Dest, &Icc ->Created, sizeof(struct tm)); return TRUE; } @@ -896,9 +937,9 @@ cmsUInt32Number BaseToBase(cmsUInt32Number in, int BaseIn, int BaseOut) char Buff[100]; int i, len; cmsUInt32Number out; - + for (len=0; in > 0 && len < 100; len++) { - + Buff[len] = (char) (in % BaseIn); in /= BaseIn; } @@ -916,7 +957,7 @@ void CMSEXPORT cmsSetProfileVersion(cmsHPROFILE hProfile, cmsFloat64Number Vers // 4.2 -> 0x4200000 - Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16; + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; } cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) @@ -940,7 +981,32 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIO NewIcc = (_cmsICCPROFILE*) hEmpty; NewIcc ->IOhandler = io; - if (!_cmsReadHeader(NewIcc)) goto Error; + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (write) { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; return hEmpty; Error: @@ -948,6 +1014,7 @@ Error: return NULL; } + // Create profile from disk file cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) { @@ -964,7 +1031,7 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char if (*sAccess == 'W' || *sAccess == 'w') { NewIcc -> IsWrite = TRUE; - + return hEmpty; } @@ -997,11 +1064,11 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromStreamTHR(cmsContext ContextID, FILE* I if (*sAccess == 'w') { - NewIcc -> IsWrite = TRUE; + NewIcc -> IsWrite = TRUE; return hEmpty; } - if (!_cmsReadHeader(NewIcc)) goto Error; + if (!_cmsReadHeader(NewIcc)) goto Error; return hEmpty; Error: @@ -1027,8 +1094,8 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void* NewIcc = (_cmsICCPROFILE*) hEmpty; - // Ok, in this case const void* is casted to void* just because open IO handler - // shares read and writting modes. Don't abuse this feature! + // Ok, in this case const void* is casted to void* just because open IO handler + // shares read and writting modes. Don't abuse this feature! NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r"); if (NewIcc ->IOhandler == NULL) goto Error; @@ -1058,12 +1125,13 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) cmsIOHANDLER* io = Icc ->IOhandler; cmsTagDescriptor* TagDescriptor; cmsTagTypeSignature TypeBase; + cmsTagTypeSignature Type; cmsTagTypeHandler* TypeHandler; - + cmsFloat64Number Version = cmsGetProfileVersion((cmsHPROFILE) Icc); + cmsTagTypeHandler LocalTypeHandler; for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] == 0) continue; // Linked tags are not written @@ -1075,7 +1143,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) if (!Data) { - // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. + // Reach here if we are copying a tag from a disk-based ICC profile which has not been modified by user. // In this case a blind copy of the block data is performed if (FileOrig != NULL && Icc -> TagOffsets[i]) { @@ -1085,7 +1153,7 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE; - Mem = _cmsMalloc(Icc ->ContextID, TagSize); + Mem = _cmsMalloc(Icc ->ContextID, TagSize); if (Mem == NULL) return FALSE; if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE; @@ -1093,11 +1161,11 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) _cmsFree(Icc ->ContextID, Mem); Icc -> TagSizes[i] = (io ->UsedSpace - Begin); - + // Align to 32 bit boundary. - if (! _cmsWriteAlignment(io)) - return FALSE; + if (! _cmsWriteAlignment(io)) + return FALSE; } continue; @@ -1112,38 +1180,48 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) else { // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); if (TagDescriptor == NULL) continue; // Unsupported, ignore it + + if (TagDescriptor ->DecideType != NULL) { - TypeHandler = Icc ->TagTypeHandlers[i]; + Type = TagDescriptor ->DecideType(Version, Data); + } + else { + + Type = TagDescriptor ->SupportedTypes[0]; + } + + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); continue; } - TypeBase = TypeHandler ->Signature; - if (!_cmsWriteTypeBase(io, TypeBase)) + TypeBase = TypeHandler ->Signature; + if (!_cmsWriteTypeBase(io, TypeBase)) return FALSE; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) { + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) { - char String[5]; + char String[5]; - _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); + _cmsTagSignature2String(String, (cmsTagSignature) TypeBase); cmsSignalError(Icc ->ContextID, cmsERROR_WRITE, "Couldn't write type '%s'", String); - return FALSE; + return FALSE; } } - Icc -> TagSizes[i] = (io ->UsedSpace - Begin); + Icc -> TagSizes[i] = (io ->UsedSpace - Begin); // Align to 32 bit boundary. - if (! _cmsWriteAlignment(io)) - return FALSE; + if (! _cmsWriteAlignment(io)) + return FALSE; } @@ -1181,11 +1259,13 @@ cmsBool SetLinks( _cmsICCPROFILE* Icc) cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOHANDLER* io) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - _cmsICCPROFILE Keep; - cmsIOHANDLER* PrevIO; + _cmsICCPROFILE Keep; + cmsIOHANDLER* PrevIO = NULL; cmsUInt32Number UsedSpace; cmsContext ContextID; + _cmsAssert(hProfile != NULL); + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); ContextID = cmsGetProfileContextID(hProfile); @@ -1194,18 +1274,19 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH // Pass #1 does compute offsets - if (!_cmsWriteHeader(Icc, 0)) return 0; - if (!SaveTags(Icc, &Keep)) return 0; + if (!_cmsWriteHeader(Icc, 0)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; UsedSpace = PrevIO ->UsedSpace; // Pass #2 does save to iohandler if (io != NULL) { - Icc ->IOhandler = io; - if (!SetLinks(Icc)) goto CleanUp; - if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp; - if (!SaveTags(Icc, &Keep)) goto CleanUp; + + Icc ->IOhandler = io; + if (!SetLinks(Icc)) goto Error; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; } memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); @@ -1214,20 +1295,20 @@ cmsUInt32Number CMSEXPORT cmsSaveProfileToIOhandler(cmsHPROFILE hProfile, cmsIOH return UsedSpace; -CleanUp: - cmsCloseIOhandler(PrevIO); +Error: + cmsCloseIOhandler(PrevIO); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return 0; } -// Low-level save to disk. +// Low-level save to disk. cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName) -{ +{ cmsContext ContextID = cmsGetProfileContextID(hProfile); cmsIOHANDLER* io = cmsOpenIOhandlerFromFile(ContextID, FileName, "w"); cmsBool rc; - + if (io == NULL) return FALSE; rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); @@ -1245,7 +1326,7 @@ cmsBool CMSEXPORT cmsSaveProfileToStream(cmsHPROFILE hProfile, FILE* Stream) cmsBool rc; cmsContext ContextID = cmsGetProfileContextID(hProfile); cmsIOHANDLER* io = cmsOpenIOhandlerFromStream(ContextID, Stream); - + if (io == NULL) return FALSE; rc = (cmsSaveProfileToIOhandler(hProfile, io) != 0); @@ -1261,12 +1342,14 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn cmsBool rc; cmsIOHANDLER* io; cmsContext ContextID = cmsGetProfileContextID(hProfile); - + + _cmsAssert(BytesNeeded != NULL); + // Should we just calculate the needed space? - if (MemPtr == NULL) { + if (MemPtr == NULL) { *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return TRUE; + return (*BytesNeeded == 0) ? FALSE : TRUE; } // That is a real write operation @@ -1286,15 +1369,15 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsBool rc = TRUE; - cmsUInt32Number i; + cmsUInt32Number i; if (!Icc) return FALSE; - // Was open in write mode? + // Was open in write mode? if (Icc ->IsWrite) { Icc ->IsWrite = FALSE; // Assure no further writting - rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); + rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile); } for (i=0; i < Icc -> TagCount; i++) { @@ -1304,19 +1387,22 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; if (TypeHandler != NULL) { + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; - TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameters - TypeHandler ->ICCVersion = Icc ->Version; - TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); } else _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); } } - if (Icc ->IOhandler != NULL) { - rc &= cmsCloseIOhandler(Icc->IOhandler); - } + if (Icc ->IOhandler != NULL) { + rc &= cmsCloseIOhandler(Icc->IOhandler); + } + + _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory @@ -1336,9 +1422,9 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ nMaxTypes = TagDescriptor->nSupportedTypes; if (nMaxTypes >= MAX_TYPES_IN_LCMS_PLUGIN) nMaxTypes = MAX_TYPES_IN_LCMS_PLUGIN; - + for (i=0; i < nMaxTypes; i++) { - if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; + if (Type == TagDescriptor ->SupportedTypes[i]) return TRUE; } return FALSE; @@ -1348,58 +1434,72 @@ cmsBool IsTypeSupported(cmsTagDescriptor* TagDescriptor, cmsTagTypeSignature Typ // That's the main read function void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsIOHANDLER* io = Icc ->IOhandler; cmsTagTypeHandler* TypeHandler; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor; cmsTagTypeSignature BaseType; cmsUInt32Number Offset, TagSize; cmsUInt32Number ElemCount; int n; - n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return NULL; // Not found, return NULL + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) goto Error; // Not found, return NULL - // If the element is already in memory, return the pointer - if (Icc -> TagPtrs[n]) { + // If the element is already in memory, return the pointer + if (Icc -> TagPtrs[n]) { - if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked - return Icc -> TagPtrs[n]; - } + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return Icc -> TagPtrs[n]; + } - // We need to read it. Get the offset and size to the file + // We need to read it. Get the offset and size to the file Offset = Icc -> TagOffsets[n]; - TagSize = Icc -> TagSizes[n]; - + TagSize = Icc -> TagSizes[n]; + // Seek to its location if (!io -> Seek(io, Offset)) - return NULL; + goto Error; // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(sig); - if (TagDescriptor == NULL) return NULL; // Unsupported. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + + // An unknown element was found. + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); + goto Error; // Unsupported. + } // if supported, get type and check if in list BaseType = _cmsReadTypeBase(io); - if (BaseType == 0) return NULL; + if (BaseType == 0) goto Error; - if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL; + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; TagSize -= 8; // Alredy read by the type base logic // Get type handler - TypeHandler = _cmsGetTagTypeHandler(BaseType); - if (TypeHandler == NULL) return NULL; + TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); + if (TypeHandler == NULL) goto Error; + LocalTypeHandler = *TypeHandler; // Read the tag Icc -> TagTypeHandlers[n] = TypeHandler; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize); + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize); // The tag type is supported, but something wrong happend and we cannot read the tag. // let know the user about this (although it is just a warning) @@ -1409,40 +1509,47 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) _cmsTagSignature2String(String, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); - return NULL; + goto Error; } // This is a weird error that may be a symptom of something more serious, the number of - // stored item is actually less than the number of required elements. + // stored item is actually less than the number of required elements. if (ElemCount < TagDescriptor ->ElemCount) { char String[5]; _cmsTagSignature2String(String, sig); - cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", - String, TagDescriptor ->ElemCount, ElemCount); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", + String, TagDescriptor ->ElemCount, ElemCount); } - + // Return the data + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; + + + // Return error and unlock tha data +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return NULL; } // Get true type of data cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - cmsTagTypeHandler* TypeHandler; - int n; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + cmsTagTypeHandler* TypeHandler; + int n; - // Search for given tag in ICC profile directory - n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL + // Search for given tag in ICC profile directory + n = _cmsSearchTag(Icc, sig, TRUE); + if (n < 0) return (cmsTagTypeSignature) 0; // Not found, return NULL - // Get the handler. The true type is there - TypeHandler = Icc -> TagTypeHandlers[n]; - return TypeHandler ->Signature; + // Get the handler. The true type is there + TypeHandler = Icc -> TagTypeHandlers[n]; + return TypeHandler ->Signature; } @@ -1450,53 +1557,35 @@ cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig // in that list, the previous version is deleted. cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor = NULL; cmsTagTypeSignature Type; int i; cmsFloat64Number Version; char TypeString[5], SigString[5]; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + // To delete tags. if (data == NULL) { - cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag"); - return FALSE; - } - - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >=0) { - - if (Icc -> TagPtrs[i] != NULL) { - - // Already exists. Free previous version - if (Icc ->TagSaveAsRaw[i]) { - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - else { - TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - - TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameter - TypeHandler ->ICCVersion = Icc ->Version; - TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); - } - } - } + // Delete the tag + i = _cmsSearchTag(Icc, sig, FALSE); + if (i >= 0) { + + // Use zero as a mark of deleted + _cmsDeleteTagByPos(Icc, i); + Icc ->TagNames[i] = (cmsTagSignature) 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + } + // Didn't find the tag + goto Error; } - else { - // New one - i = Icc -> TagCount; - if (i >= MAX_TABLE_TAG) { - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); - return FALSE; - } - - Icc -> TagCount++; - } + if (!_cmsNewTag(Icc, sig, &i)) goto Error; // This is not raw Icc ->TagSaveAsRaw[i] = FALSE; @@ -1504,51 +1593,50 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v // This is not a link Icc ->TagLinked[i] = (cmsTagSignature) 0; - // Get information about the TAG. - TagDescriptor = _cmsGetTagDescriptor(sig); + // Get information about the TAG. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL){ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); - return FALSE; + goto Error; } - - // Now we need to know which type to use. It depends on the version. + + // Now we need to know which type to use. It depends on the version. Version = cmsGetProfileVersion(hProfile); if (TagDescriptor ->DecideType != NULL) { // Let the tag descriptor to decide the type base on depending on - // the data. This is useful for example on parametric curves, where + // the data. This is useful for example on parametric curves, where // curves specified by a table cannot be saved as parametric and needs - // to be revented to single v2-curves, even on v4 profiles. + // to be casted to single v2-curves, even on v4 profiles. Type = TagDescriptor ->DecideType(Version, data); } else { - Type = TagDescriptor ->SupportedTypes[0]; } // Does the tag support this type? if (!IsTypeSupported(TagDescriptor, Type)) { - + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } // Does we have a handler for this type? - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; // Should never happen + goto Error; // Should never happen } @@ -1558,23 +1646,30 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); - - return FALSE; + + goto Error; } - + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } -// Read and write raw data. The only way those function would work and keep consistence with normal read and write +// Read and write raw data. The only way those function would work and keep consistence with normal read and write // is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained // data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where // raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows @@ -1582,96 +1677,136 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - void *Object; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + void *Object; int i; cmsIOHANDLER* MemIO; cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor = NULL; cmsUInt32Number rc; cmsUInt32Number Offset, TagSize; - // Search for given tag in ICC profile directory - i = _cmsSearchTag(Icc, sig, TRUE); - if (i < 0) return 0; // Not found, return 0 + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; - // It is already read? + // Search for given tag in ICC profile directory + i = _cmsSearchTag(Icc, sig, TRUE); + if (i < 0) goto Error; // Not found, + + // It is already read? if (Icc -> TagPtrs[i] == NULL) { // No yet, get original position Offset = Icc ->TagOffsets[i]; TagSize = Icc ->TagSizes[i]; - // read the data directly, don't keep copy - if (data != NULL) { + if (data != NULL) { + + if (BufferSize < TagSize) + TagSize = BufferSize; - if (BufferSize < TagSize) - TagSize = BufferSize; + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; - if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; - if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; - } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TagSize; + } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } // The data has been already read, or written. But wait!, maybe the user choosed to save as // raw data. In this case, return the raw data directly if (Icc ->TagSaveAsRaw[i]) { - - if (data != NULL) { - TagSize = Icc ->TagSizes[i]; - if (BufferSize < TagSize) - TagSize = BufferSize; + if (data != NULL) { + + TagSize = Icc ->TagSizes[i]; + if (BufferSize < TagSize) + TagSize = BufferSize; memmove(data, Icc ->TagPtrs[i], TagSize); - } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TagSize; + } + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } - // Already readed, or previously set by cmsWriteTag(). We need to serialize that + // Already readed, or previously set by cmsWriteTag(). We need to serialize that // data to raw in order to maintain consistency. + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); Object = cmsReadTag(hProfile, sig); - if (Object == NULL) return 0; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (Object == NULL) goto Error; // Now we need to serialize to a memory block: just use a memory iohandler - if (data == NULL) { - MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); - } else{ - MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); - } - if (MemIO == NULL) return 0; + if (data == NULL) { + MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); + } else{ + MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); + } + if (MemIO == NULL) goto Error; // Obtain type handling for the tag TypeHandler = Icc ->TagTypeHandlers[i]; - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + if (TypeHandler == NULL) goto Error; // Serialize - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0; + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + + if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { + cmsCloseIOhandler(MemIO); + goto Error; + } + + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { + cmsCloseIOhandler(MemIO); + goto Error; + } // Get Size and close rc = MemIO ->Tell(MemIO); cmsCloseIOhandler(MemIO); // Ignore return code this time + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return rc; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return 0; } // Similar to the anterior. This function allows to write directly to the ICC profile any data, without -// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading +// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading // it as cooked without serializing does result into an error. If that is wha you want, you will need to dump // the profile to memry or disk and then reopen it. cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Mark the tag as being written as RAW Icc ->TagSaveAsRaw[i] = TRUE; @@ -1682,26 +1817,33 @@ cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, cons Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); Icc ->TagSizes[i] = Size; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } // Using this function you can collapse several tag entries to the same block in the profile cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Keep necessary information Icc ->TagSaveAsRaw[i] = FALSE; Icc ->TagNames[i] = sig; Icc ->TagLinked[i] = dest; - + Icc ->TagPtrs[i] = NULL; Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } @@ -1709,12 +1851,12 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi // Returns the tag linked to sig, in the case two tags are sharing same resource cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; // Search for given tag in ICC profile directory - i = _cmsSearchTag(Icc, sig, FALSE); - if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 + i = _cmsSearchTag(Icc, sig, FALSE); + if (i < 0) return (cmsTagSignature) 0; // Not found, return 0 return Icc -> TagLinked[i]; } |
