summaryrefslogtreecommitdiff
path: root/src/cmsplugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmsplugin.c')
-rw-r--r--src/cmsplugin.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/src/cmsplugin.c b/src/cmsplugin.c
new file mode 100644
index 0000000..1fa5ff4
--- /dev/null
+++ b/src/cmsplugin.c
@@ -0,0 +1,612 @@
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 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
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+
+// ----------------------------------------------------------------------------------
+// Encoding & Decoding support functions
+// ----------------------------------------------------------------------------------
+
+// Little-Endian to Big-Endian
+
+// Adjust a word value after being readed/ before being written from/to an ICC profile
+cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)
+{
+#ifndef CMS_USE_BIG_ENDIAN
+
+ cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
+ cmsUInt8Number tmp;
+
+ tmp = pByte[0];
+ pByte[0] = pByte[1];
+ pByte[1] = tmp;
+#endif
+
+ return Word;
+}
+
+
+// Transports to properly encoded values - note that icc profiles does use big endian notation.
+
+// 1 2 3 4
+// 4 3 2 1
+
+cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)
+{
+#ifndef CMS_USE_BIG_ENDIAN
+
+ cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
+ cmsUInt8Number temp1;
+ cmsUInt8Number temp2;
+
+ temp1 = *pByte++;
+ temp2 = *pByte++;
+ *(pByte-1) = *pByte;
+ *pByte++ = temp2;
+ *(pByte-3) = *pByte;
+ *pByte = temp1;
+#endif
+ return DWord;
+}
+
+// 1 2 3 4 5 6 7 8
+// 8 7 6 5 4 3 2 1
+
+void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord)
+{
+
+#ifndef CMS_USE_BIG_ENDIAN
+
+ cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord;
+ cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
+
+ _cmsAssert(Result != NULL);
+
+ pOut[7] = pIn[0];
+ pOut[6] = pIn[1];
+ pOut[5] = pIn[2];
+ pOut[4] = pIn[3];
+ pOut[3] = pIn[4];
+ pOut[2] = pIn[5];
+ pOut[1] = pIn[6];
+ pOut[0] = pIn[7];
+
+#else
+
+ _cmsAssert(Result != NULL);
+
+ *Result = QWord;
+#endif
+}
+
+// Auxiliar -- read 8, 16 and 32-bit numbers
+cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
+{
+ cmsUInt8Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) *n = tmp;
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
+{
+ cmsUInt16Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
+{
+ cmsUInt32Number i;
+
+ _cmsAssert(io != NULL);
+
+ for (i=0; i < n; i++) {
+
+ if (Array != NULL) {
+ if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
+ }
+ else {
+ if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
+ }
+
+ }
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) {
+
+ tmp = _cmsAdjustEndianess32(tmp);
+ *n = *(cmsFloat32Number*) &tmp;
+ }
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
+{
+ cmsUInt64Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) _cmsAdjustEndianess64(n, tmp);
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
+
+ if (n != NULL) {
+ *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
+ }
+
+ return TRUE;
+}
+
+
+// Jun-21-2000: Some profiles (those that comes with W2K) comes
+// with the media white (media black?) x 100. Add a sanity check
+
+static
+void NormalizeXYZ(cmsCIEXYZ* Dest)
+{
+ while (Dest -> X > 2. &&
+ Dest -> Y > 2. &&
+ Dest -> Z > 2.) {
+
+ Dest -> X /= 10.;
+ Dest -> Y /= 10.;
+ Dest -> Z /= 10.;
+ }
+}
+
+cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
+{
+ cmsEncodedXYZNumber xyz;
+
+ _cmsAssert(io != NULL);
+
+ if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
+
+ if (XYZ != NULL) {
+
+ XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
+ XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
+ XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
+
+ NormalizeXYZ(XYZ);
+ }
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
+{
+ _cmsAssert(io != NULL);
+
+ if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
+{
+ cmsUInt16Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = _cmsAdjustEndianess16(n);
+ if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
+{
+ cmsUInt32Number i;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(Array != NULL);
+
+ for (i=0; i < n; i++) {
+ if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
+ }
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = _cmsAdjustEndianess32(n);
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = *(cmsUInt32Number*) &n;
+ tmp = _cmsAdjustEndianess32(tmp);
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
+{
+ cmsUInt64Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ _cmsAdjustEndianess64(&tmp, n);
+ if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
+{
+ cmsUInt32Number tmp;
+
+ _cmsAssert(io != NULL);
+
+ tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
+ return TRUE;
+}
+
+cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
+{
+ cmsEncodedXYZNumber xyz;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(XYZ != NULL);
+
+ xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
+ xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
+ xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
+
+ return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
+}
+
+// from Fixed point 8.8 to double
+cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
+{
+ cmsUInt8Number msb, lsb;
+
+ lsb = (cmsUInt8Number) (fixed8 & 0xff);
+ msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
+
+ return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
+}
+
+cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
+{
+ cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
+ return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
+}
+
+// from Fixed point 15.16 to double
+cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
+{
+ cmsFloat64Number floater, sign, mid;
+ int Whole, FracPart;
+
+ sign = (fix32 < 0 ? -1 : 1);
+ fix32 = abs(fix32);
+
+ Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
+ FracPart = (cmsUInt16Number)(fix32 & 0xffff);
+
+ mid = (cmsFloat64Number) FracPart / 65536.0;
+ floater = (cmsFloat64Number) Whole + mid;
+
+ return sign * floater;
+}
+
+// from double to Fixed point 15.16
+cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
+{
+ return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
+}
+
+// Date/Time functions
+
+void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
+{
+
+ _cmsAssert(Dest != NULL);
+ _cmsAssert(Source != NULL);
+
+ Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds);
+ Dest->tm_min = _cmsAdjustEndianess16(Source->minutes);
+ Dest->tm_hour = _cmsAdjustEndianess16(Source->hours);
+ Dest->tm_mday = _cmsAdjustEndianess16(Source->day);
+ Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1;
+ Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900;
+ Dest->tm_wday = -1;
+ Dest->tm_yday = -1;
+ Dest->tm_isdst = 0;
+}
+
+void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
+{
+ _cmsAssert(Dest != NULL);
+ _cmsAssert(Source != NULL);
+
+ Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
+ Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
+ Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
+ Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
+ Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
+ Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
+}
+
+// Read base and return type base
+cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
+{
+ _cmsTagBase Base;
+
+ _cmsAssert(io != NULL);
+
+ if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
+ return (cmsTagTypeSignature) 0;
+
+ return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
+}
+
+// Setup base marker
+cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
+{
+ _cmsTagBase Base;
+
+ _cmsAssert(io != NULL);
+
+ Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
+ memset(&Base.reserved, 0, sizeof(Base.reserved));
+ return io -> Write(io, sizeof(_cmsTagBase), &Base);
+}
+
+cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
+{
+ cmsUInt8Number Buffer[4];
+ cmsUInt32Number NextAligned, At;
+ cmsUInt32Number BytesToNextAlignedPos;
+
+ _cmsAssert(io != NULL);
+
+ At = io -> Tell(io);
+ NextAligned = _cmsALIGNLONG(At);
+ BytesToNextAlignedPos = NextAligned - At;
+ if (BytesToNextAlignedPos == 0) return TRUE;
+ if (BytesToNextAlignedPos > 4) return FALSE;
+
+ return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
+}
+
+cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
+{
+ cmsUInt8Number Buffer[4];
+ cmsUInt32Number NextAligned, At;
+ cmsUInt32Number BytesToNextAlignedPos;
+
+ _cmsAssert(io != NULL);
+
+ At = io -> Tell(io);
+ NextAligned = _cmsALIGNLONG(At);
+ BytesToNextAlignedPos = NextAligned - At;
+ if (BytesToNextAlignedPos == 0) return TRUE;
+ if (BytesToNextAlignedPos > 4) return FALSE;
+
+ memset(Buffer, 0, BytesToNextAlignedPos);
+ return io -> Write(io, BytesToNextAlignedPos, Buffer);
+}
+
+
+// To deal with text streams. 2K at most
+cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
+{
+ va_list args;
+ int len;
+ cmsUInt8Number Buffer[2048];
+ cmsBool rc;
+
+ _cmsAssert(io != NULL);
+ _cmsAssert(frm != NULL);
+
+ va_start(args, frm);
+
+ len = vsnprintf((char*) Buffer, 2047, frm, args);
+ if (len < 0) return FALSE; // Truncated, which is a fatal error for us
+
+ rc = io ->Write(io, len, Buffer);
+
+ va_end(args);
+
+ return rc;
+}
+
+
+// Plugin memory management -------------------------------------------------------------------------------------------------
+
+static _cmsSubAllocator* PluginPool = NULL;
+
+// Specialized malloc for plug-ins, that is freed upon exit.
+void* _cmsPluginMalloc(cmsUInt32Number size)
+{
+ if (PluginPool == NULL)
+ PluginPool = _cmsCreateSubAlloc(0, 4*1024);
+
+ return _cmsSubAlloc(PluginPool, size);
+}
+
+
+// Main plug-in dispatcher
+cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
+{
+ cmsPluginBase* Plugin;
+
+ for (Plugin = (cmsPluginBase*) Plug_in;
+ Plugin != NULL;
+ Plugin = Plugin -> Next) {
+
+ if (Plugin -> Magic != cmsPluginMagicNumber) {
+ cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
+ return FALSE;
+ }
+
+ if (Plugin ->ExpectedVersion > LCMS_VERSION) {
+ cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
+ Plugin ->ExpectedVersion, LCMS_VERSION);
+ return FALSE;
+ }
+
+ switch (Plugin -> Type) {
+
+ case cmsPluginMemHandlerSig:
+ if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginInterpolationSig:
+ if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginTagTypeSig:
+ if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginTagSig:
+ if (!_cmsRegisterTagPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginFormattersSig:
+ if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginRenderingIntentSig:
+ if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginParametricCurveSig:
+ if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginMultiProcessElementSig:
+ if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE;
+ break;
+
+ case cmsPluginOptimizationSig:
+ if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
+ break;
+
+ default:
+ cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
+ return FALSE;
+ }
+ }
+
+ // Keep a reference to the plug-in
+ return TRUE;
+}
+
+
+// Revert all plug-ins to default
+void CMSEXPORT cmsUnregisterPlugins(void)
+{
+ _cmsRegisterMemHandlerPlugin(NULL);
+ _cmsRegisterInterpPlugin(NULL);
+ _cmsRegisterTagTypePlugin(NULL);
+ _cmsRegisterTagPlugin(NULL);
+ _cmsRegisterFormattersPlugin(NULL);
+ _cmsRegisterRenderingIntentPlugin(NULL);
+ _cmsRegisterParametricCurvesPlugin(NULL);
+ _cmsRegisterMultiProcessElementPlugin(NULL);
+ _cmsRegisterOptimizationPlugin(NULL);
+
+ if (PluginPool != NULL)
+ _cmsSubAllocDestroy(PluginPool);
+
+ PluginPool = NULL;
+}