summaryrefslogtreecommitdiffstats
path: root/src/libs/lprof/cmssheet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/lprof/cmssheet.cpp')
-rw-r--r--src/libs/lprof/cmssheet.cpp1746
1 files changed, 1746 insertions, 0 deletions
diff --git a/src/libs/lprof/cmssheet.cpp b/src/libs/lprof/cmssheet.cpp
new file mode 100644
index 00000000..cf8c569e
--- /dev/null
+++ b/src/libs/lprof/cmssheet.cpp
@@ -0,0 +1,1746 @@
+/* */
+/* Little cms - profiler construction set */
+/* Copyright (C) 1998-2001 Marti Maria <marti@littlecms.com> */
+/* */
+/* THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY */
+/* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */
+/* */
+/* IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, */
+/* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
+/* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, */
+/* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF */
+/* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE */
+/* OF THIS SOFTWARE. */
+/* */
+/* This file is free software; you can redistribute it and/or modify it */
+/* under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, but */
+/* WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+/* */
+/* As a special exception to the GNU General Public License, if you */
+/* distribute this file as part of a program that contains a */
+/* configuration script generated by Autoconf, you may include it under */
+/* the same distribution terms that you use for the rest of that program. */
+/* */
+/* Version 1.08a */
+
+
+#include "lcmsprf.h"
+
+/* #define _DEBUG 1 */
+
+
+
+/* IT8.7 / CGATS.17-200x handling */
+LCMSHANDLE cdecl cmsxIT8Alloc(void);
+void cdecl cmsxIT8Free(LCMSHANDLE IT8);
+
+/* Persistence */
+LCMSHANDLE cdecl cmsxIT8LoadFromFile(const char* cFileName);
+LCMSHANDLE cdecl cmsxIT8LoadFromMem(void *Ptr, size_t len);
+BOOL cdecl cmsxIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName);
+
+/* Properties */
+const char* cdecl cmsxIT8GetSheetType(LCMSHANDLE hIT8);
+BOOL cdecl cmsxIT8SetSheetType(LCMSHANDLE hIT8, const char* Type);
+
+BOOL cdecl cmsxIT8SetProperty(LCMSHANDLE hIT8, const char* cProp, const char *Str);
+BOOL cdecl cmsxIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val);
+
+const char* cdecl cmsxIT8GetProperty(LCMSHANDLE hIT8, const char* cProp);
+double cdecl cmsxIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp);
+int cdecl cmsxIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames);
+
+
+/* Datasets */
+
+BOOL cdecl cmsxIT8GetDataSetByPos(LCMSHANDLE IT8, int col, int row, char* Val, int ValBufferLen);
+
+BOOL cdecl cmsxIT8GetDataSet(LCMSHANDLE IT8, const char* cPatch,
+ const char* cSample,
+ char* Val, int ValBufferLen);
+
+
+BOOL cdecl cmsxIT8GetDataSetDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample, double* d);
+
+BOOL cdecl cmsxIT8SetDataSet(LCMSHANDLE IT8, const char* cPatch,
+ const char* cSample,
+ char *Val);
+
+BOOL cdecl cmsxIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample);
+int cdecl cmsxIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames);
+
+const char *cdecl cmsxIT8GenericPatchName(int nPatch, char* buffer);
+int cdecl cmsxIT8GenericPatchNum(const char *Name);
+
+
+/* ------------------------------------------------------------- Implementation */
+
+
+#define MAXID 128 /* Max length of identifier */
+#define MAXSTR 255 /* Max length of string */
+
+#ifndef NON_WINDOWS
+#include <io.h>
+#endif
+
+/* Symbols */
+
+typedef enum { SNONE,
+ SINUM, /* Integer */
+ SDNUM, /* Real */
+ SIDENT, /* Identifier */
+ SSTRING, /* string */
+ SCOMMENT, /* comment */
+ SEOLN, /* End of line */
+ SEOF, /* End of stream */
+ SSYNERROR, /* Syntax error found on stream */
+
+ /* Keywords */
+
+ SBEGIN_DATA,
+ SBEGIN_DATA_FORMAT,
+ SEND_DATA,
+ SEND_DATA_FORMAT,
+ SKEYWORD,
+ SSTRING_SY
+
+ } SYMBOL;
+
+
+/* Linked list of variable names */
+
+typedef struct _KeyVal {
+
+ struct _KeyVal* Next;
+ char* Keyword; /* Name of variable */
+ char* Value; /* Points to value */
+
+ } KEYVALUE, FAR* LPKEYVALUE;
+
+/* Linked list of values (Memory sink) */
+
+typedef struct _OwnedMem {
+
+ struct _OwnedMem* Next;
+ void * Ptr; /* Point to value */
+
+ } OWNEDMEM, FAR* LPOWNEDMEM;
+
+
+/* This struct hold all information about an openened */
+/* IT8 handler. Only one dataset is allowed. */
+
+typedef struct {
+
+ int nSamples, nPatches; /* Rows, Cols */
+ int SampleID; /* Pos of ID */
+ LPKEYVALUE HeaderList; /* The properties */
+ char* FileBuffer; /* The ASCII stream */
+ char** DataFormat; /* The binary stream descriptor */
+ char** Data; /* The binary stream */
+ LPOWNEDMEM MemorySink; /* The storage bakend */
+
+ /* Parser state machine */
+
+ SYMBOL sy; /* Current symbol */
+ int ch; /* Current character */
+ char* Source; /* Points to loc. being parsed */
+ int inum; /* integer value */
+ double dnum; /* real value */
+ char id[MAXID]; /* identifier */
+ char str[MAXSTR]; /* string */
+
+ /* Allowed keywords & datasets */
+
+ LPKEYVALUE ValidKeywords;
+ LPKEYVALUE ValidSampleID;
+
+ char FileName[MAX_PATH];
+ int lineno; /* line counter for error reporting */
+
+ char SheetType[MAXSTR]; /* New 1.09 */
+
+ } IT8, FAR* LPIT8;
+
+
+
+/* ------------------------------------------------------ IT8 parsing routines */
+
+
+/* A keyword */
+typedef struct {
+ const char *id;
+ SYMBOL sy;
+
+ } KEYWORD;
+
+/* The keyword->symbol translation table. Sorting is required. */
+static const KEYWORD TabKeys[] = {
+
+ {"BEGIN_DATA", SBEGIN_DATA },
+ {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT },
+ {"END_DATA", SEND_DATA},
+ {"END_DATA_FORMAT", SEND_DATA_FORMAT},
+ {"KEYWORD", SKEYWORD},
+ {"STRING", SSTRING_SY}};
+
+#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
+
+/* Predefined properties */
+static char* PredefinedProperties[] = {
+
+ "NUMBER_OF_FIELDS", /* Required - NUMBER OF FIELDS */
+ "NUMBER_OF_SETS", /* Required - NUMBER OF SETS */
+ "ORIGINATOR", /* Required - Identifies the specific system, organization or individual that created the data file. */
+ "CREATED", /* Required - Indicates date of creation of the data file. */
+ "DESCRIPTOR", /* Required - Describes the purpose or contents of the data file. */
+ "DIFFUSE_GEOMETRY", /* The diffuse geometry used. Allowed values are "sphere" or "opal". */
+ "MANUFACTURER",
+ "MANUFACTURE", /* Some broken Fuji targets does store this value */
+ "PROD_DATE", /* Identifies year and month of production of the target in the form yyyy:mm. */
+ "SERIAL", /* Uniquely identifies individual physical target. */
+
+ "MATERIAL", /* Identifies the material on which the target was produced using a code */
+ /* uniquely identifying th e material. Th is is intend ed to be used for IT8.7 */
+ /* physical targets only (i.e . IT8.7/1 a nd IT8.7/2). */
+
+ "INSTRUMENTATION", /* Used to report the specific instrumentation used (manufacturer and */
+ /* model number) to generate the data reported. This data will often */
+ /* provide more information about the particular data collected than an */
+ /* extensive list of specific details. This is particularly important for */
+ /* spectral data or data derived from spectrophotometry. */
+
+ "MEASUREMENT_SOURCE", /* Illumination used for spectral measurements. This data helps provide */
+ /* a guide to the potential for issues of paper fluorescence, etc. */
+
+ "PRINT_CONDITIONS", /* Used to define the ch aracteristics of the printed sheet being reported. */
+ /* Where standard conditions have been defined (e.g., SW OP at nominal) */
+ /* named conditions may suffice. Otherwise, detailed in formation is */
+ /* needed. */
+
+ "SAMPLE_BACKING", /* Identifies the backing material used behind the sample during */
+ /* measurement. Allowed values are “black”, “white”, or "na". */
+
+ "CHISQ_DOF" /* Degrees of freedom associated with the Chi squared statistic */
+ };
+
+#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(char *))
+
+
+/* Predefined sample types on dataset */
+static char* PredefinedSampleID[] = {
+
+ "CMYK_C", /* Cyan component of CMYK data expressed as a percentage */
+ "CMYK_M", /* Magenta component of CMYK data expressed as a percentage */
+ "CMYK_Y", /* Yellow component of CMYK data expressed as a percentage */
+ "CMYK_K", /* Black component of CMYK data expressed as a percentage */
+ "D_RED", /* Red filter density */
+ "D_GREEN", /* Green filter density */
+ "D_BLUE", /* Blue filter density */
+ "D_VIS", /* Visual filter density */
+ "D_MAJOR_FILTER", /* Major filter d ensity */
+ "RGB_R", /* Red component of RGB data */
+ "RGB_G", /* Green component of RGB data */
+ "RGB_B", /* Blue com ponent of RGB data */
+ "SPECTRAL_NM", /* Wavelength of measurement expressed in nanometers */
+ "SPECTRAL_PCT", /* Percentage reflectance/transmittance */
+ "SPECTRAL_DEC", /* Reflectance/transmittance */
+ "XYZ_X", /* X component of tristimulus data */
+ "XYZ_Y", /* Y component of tristimulus data */
+ "XYZ_Z", /* Z component of tristimulus data */
+ "XYY_X" /* x component of chromaticity data */
+ "XYY_Y", /* y component of chromaticity data */
+ "XYY_CAPY", /* Y component of tristimulus data */
+ "LAB_L", /* L* component of Lab data */
+ "LAB_A", /* a* component of Lab data */
+ "LAB_B", /* b* component of Lab data */
+ "LAB_C", /* C*ab component of Lab data */
+ "LAB_H", /* hab component of Lab data */
+ "LAB_DE" /* CIE dE */
+ "LAB_DE_94", /* CIE dE using CIE 94 */
+ "LAB_DE_CMC", /* dE using CMC */
+ "LAB_DE_2000", /* CIE dE using CIE DE 2000 */
+ "MEAN_DE", /* Mean Delta E (LAB_DE) of samples compared to batch average */
+ /* (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets) */
+ "STDEV_X", /* Standard deviation of X (tristimulus data) */
+ "STDEV_Y", /* Standard deviation of Y (tristimulus data) */
+ "STDEV_Z", /* Standard deviation of Z (tristimulus data) */
+ "STDEV_L", /* Standard deviation of L* */
+ "STDEV_A" /* Standard deviation of a* */
+ "STDEV_B", /* Standard deviation of b* */
+ "STDEV_DE", /* Standard deviation of CIE dE */
+ "CHI_STQD_PAR"}; /* The average of the standard deviations of L*, a* and b*. It is */
+ /* used to derive an estimate of the chi-squared parameter which is */
+ /* recommended as the predictor of the variability of dE */
+
+#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *))
+
+
+/* Checks whatsever if c is a valid identifier middle char. */
+static
+BOOL isidchar(int c)
+{
+ return (isalnum(c) || c == '$' || c == '%' || c == '&' || c == '/' || c == '.' || c == '_');
+
+}
+
+/* Checks whatsever if c is a valid identifier first char. */
+static
+BOOL isfirstidchar(int c)
+{
+ return !isdigit(c) && isidchar(c);
+}
+
+/* Checks if c is a separator */
+static
+BOOL isseparator(int c)
+{
+ return (c == ' ' || c == '\t' || c == '\r');
+}
+
+/* a replacement for strupr(), just for compatibility sake */
+
+static
+void xstrupr(char *cp)
+{
+ for (;*cp;cp++)
+ if (*cp >= 'a' && *cp <= 'z')
+ *cp += 'A'-'a';
+}
+
+/* A replacement for (the nonstandard) filelength */
+
+static
+int xfilelength(int fd)
+{
+#ifdef _MSC_VER
+ return _filelength(fd);
+#else
+ struct stat sb;
+ if (fstat(fd, &sb) < 0)
+ return(-1);
+ return(sb.st_size);
+#endif
+
+
+}
+
+static
+BOOL SynError(LPIT8 it8, const char *Txt, ...)
+{
+ char Buffer[256], ErrMsg[1024];
+ va_list args;
+
+ va_start(args, Txt);
+ vsprintf(Buffer, Txt, args);
+ va_end(args);
+
+ sprintf(ErrMsg, "%s: Line %d, %s", it8->FileName, it8->lineno, Buffer);
+ it8->sy = SSYNERROR;
+ cmsSignalError(LCMS_ERRC_ABORTED, ErrMsg);
+ return false;
+}
+
+static
+BOOL Check(LPIT8 it8, SYMBOL sy, const char* Err)
+{
+ if (it8 -> sy != sy)
+ return SynError(it8, Err);
+ return true;
+}
+
+
+
+/* Read Next character from stream */
+static
+void NextCh(LPIT8 it8)
+{
+ it8->ch = *it8->Source;
+ if (it8->ch) it8->Source++;
+}
+
+
+/* Try to see if current identifier is a keyword, if so return the referred symbol */
+static
+SYMBOL BinSrchKey(const char *id)
+{
+ int l = 1;
+ int r = NUMKEYS;
+ int x, res;
+
+ while (r >= l)
+ {
+ x = (l+r)/2;
+ res = strcmp(id, TabKeys[x-1].id);
+ if (res == 0) return TabKeys[x-1].sy;
+ if (res < 0) r = x - 1;
+ else l = x + 1;
+ }
+
+ return SNONE;
+}
+
+
+/* 10 ^n */
+static
+double pow10(int n)
+{
+ return pow(10, n);
+}
+
+
+/* Reads a Real number, tries to follow from integer number */
+static
+void ReadReal(LPIT8 it8, int inum)
+{
+ it8->dnum = (double) inum;
+
+ while (isdigit(it8->ch)) {
+
+ it8->dnum = it8->dnum * 10.0 + (it8->ch - '0');
+ NextCh(it8);
+ }
+
+ if (it8->ch == '.') { /* Decimal point */
+
+ double frac = 0.0; /* fraction */
+ int prec = 0; /* precission */
+
+ NextCh(it8); /* Eats dec. point */
+
+ while (isdigit(it8->ch)) {
+
+ frac = frac * 10.0 + (it8->ch - '0');
+ prec++;
+ NextCh(it8);
+ }
+
+ it8->dnum = it8->dnum + (frac / pow10(prec));
+ }
+
+ /* Exponent, example 34.00E+20 */
+ if (toupper(it8->ch) == 'E') {
+
+ int e;
+ int sgn;
+
+ NextCh(it8); sgn = 1;
+
+ if (it8->ch == '-') {
+
+ sgn = -1; NextCh(it8);
+ }
+ else
+ if (it8->ch == '+') {
+
+ sgn = +1;
+ NextCh(it8);
+ }
+
+
+ e = 0;
+ while (isdigit(it8->ch)) {
+
+ if ((double) e * 10L < INT_MAX)
+ e = e * 10 + (it8->ch - '0');
+
+ NextCh(it8);
+ }
+
+ e = sgn*e;
+
+ it8 -> dnum = it8 -> dnum * pow10(e);
+ }
+}
+
+
+
+/* Reads next symbol */
+static
+void InSymbol(LPIT8 it8)
+{
+ char *idptr;
+ int k;
+ SYMBOL key;
+ int sng;
+
+ do {
+
+ while (isseparator(it8->ch))
+ NextCh(it8);
+
+ if (isfirstidchar(it8->ch)) { /* Identifier */
+
+
+ k = 0;
+ idptr = it8->id;
+
+ do {
+
+ if (++k < MAXID) *idptr++ = (char) it8->ch;
+
+ NextCh(it8);
+
+ } while (isidchar(it8->ch));
+
+ *idptr = '\0';
+ xstrupr(it8->id);
+
+ key = BinSrchKey(it8->id);
+ if (key == SNONE) it8->sy = SIDENT;
+ else it8->sy = key;
+
+ }
+ else /* Is a number? */
+ if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+')
+ {
+ int sign = 1;
+
+ if (it8->ch == '-') {
+ sign = -1;
+ NextCh(it8);
+ }
+
+ it8->inum = 0;
+ it8->sy = SINUM;
+
+ while (isdigit(it8->ch))
+ {
+ if ((long) it8->inum * 10L > (long) INT_MAX)
+ {
+ ReadReal(it8, it8->inum);
+ it8->sy = SDNUM;
+ it8->dnum *= sign;
+ return;
+ }
+
+ it8->inum = it8->inum * 10 + (it8->ch - '0');
+ NextCh(it8);
+ }
+
+ if (it8->ch == '.') {
+
+ ReadReal(it8, it8->inum);
+ it8->sy = SDNUM;
+ it8->dnum *= sign;
+ return;
+ }
+
+ it8 -> inum *= sign;
+ return;
+
+ }
+ else
+ switch ((int) it8->ch) {
+
+ case '\0':
+ case '\x1a':
+ it8->sy = SEOF;
+ break;
+
+
+
+ case '\n':
+ NextCh(it8);
+ it8->sy = SEOLN;
+ it8->lineno++;
+ break;
+
+ /* Comment */
+
+ case '#':
+ NextCh(it8);
+ while (it8->ch && it8->ch != '\n')
+ NextCh(it8);
+
+ it8->sy = SCOMMENT;
+ break;
+
+ /* String. I will support \", \n, \t and \\. */
+ /* But otherwise I hardly doubt these will be used ... */
+
+ case '\'':
+ case '\"':
+ idptr = it8->str;
+ sng = it8->ch;
+ k = 0;
+ NextCh(it8);
+
+ while (k < MAXSTR && it8->ch != sng) {
+
+ if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1;
+ else {
+
+ if (it8->ch == '\\')
+ {
+ NextCh(it8);
+
+ switch (it8->ch) {
+
+ case 'n': *idptr++ = '\n'; break;
+ case 'r': *idptr++ = '\r'; break;
+ case 't': *idptr++ = '\t'; break;
+ case '\\': *idptr++ = '\\'; break;
+
+ default:
+ *idptr++ = (char) it8->ch;
+ }
+
+ NextCh(it8);
+ }
+ else
+ {
+ *idptr++ = (char) it8->ch;
+ NextCh(it8);
+ }
+
+ k++;
+ }
+ }
+
+ it8->sy = SSTRING;
+ *idptr = '\0';
+ NextCh(it8);
+ break;
+
+
+ default:
+ it8->sy = SSYNERROR;
+ NextCh(it8);
+
+ }
+
+ } while (it8->sy == SCOMMENT);
+}
+
+/* Checks end of line separator */
+static
+BOOL CheckEOLN(LPIT8 it8)
+{
+ if (!Check(it8, SEOLN, "Expected separator")) return false;
+ while (it8 -> sy == SEOLN)
+ InSymbol(it8);
+ return true;
+
+}
+
+/* Skip a symbol */
+
+static
+void Skip(LPIT8 it8, SYMBOL sy)
+{
+ if (it8->sy == sy && it8->sy != SEOF)
+ InSymbol(it8);
+}
+
+/* Returns a string holding current value */
+static
+BOOL GetVal(LPIT8 it8, char* Buffer)
+{
+ switch (it8->sy) {
+
+ case SIDENT: strncpy(Buffer, it8->id, MAXID-1); break;
+ case SINUM: sprintf(Buffer, "%d", it8 -> inum); break;
+ case SDNUM: sprintf(Buffer, "%g", it8 -> dnum); break;
+ case SSTRING: strncpy(Buffer, it8->str, MAXSTR-1); break;
+
+
+ default:
+ return SynError(it8, "Sample data expected");
+ }
+
+ return true;
+}
+
+/* ---------------------------------------------------------- Memory management */
+
+
+
+/* Frees an allocator and owned memory */
+void cmsxIT8Free(LCMSHANDLE hIT8)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ if (it8 == NULL)
+ return;
+
+ if (it8->MemorySink) {
+
+ LPOWNEDMEM p;
+ LPOWNEDMEM n;
+
+ for (p = it8->MemorySink; p != NULL; p = n) {
+
+ n = p->Next;
+ if (p->Ptr) free(p->Ptr);
+ free(p);
+ }
+ }
+
+ if (it8->FileBuffer)
+ free(it8->FileBuffer);
+
+ free(it8);
+}
+
+
+/* Allocates a chunk of data, keep linked list */
+static
+void* AllocChunk(LPIT8 it8, size_t size)
+{
+ LPOWNEDMEM ptr1;
+ void* ptr = malloc(size);
+
+ if (ptr) {
+
+ ZeroMemory(ptr, size);
+ ptr1 = (LPOWNEDMEM) malloc(sizeof(OWNEDMEM));
+
+ if (ptr1 == NULL) {
+
+ free(ptr);
+ return NULL;
+ }
+
+ ZeroMemory(ptr1, sizeof(OWNEDMEM));
+
+ ptr1-> Ptr = ptr;
+ ptr1-> Next = it8 -> MemorySink;
+ it8 -> MemorySink = ptr1;
+ }
+
+ return ptr;
+}
+
+
+/* Allocates a string */
+static
+char *AllocString(LPIT8 it8, const char* str)
+{
+ int Size = strlen(str)+1;
+ char *ptr;
+ ptr = (char *) AllocChunk(it8, Size);
+ if (ptr) strncpy (ptr, str, Size);
+ return ptr;
+}
+
+/* Searches through linked list */
+
+static
+BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr)
+{
+ for (; p != NULL; p = p->Next) {
+
+ if (LastPtr) *LastPtr = p;
+ if (stricmp(Key, p->Keyword) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
+
+/* Add a property into a linked list */
+static
+BOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* Value)
+{
+ LPKEYVALUE p;
+ LPKEYVALUE last;
+
+
+ /* Check if property is already in list (this is an error) */
+
+ if (IsAvailableOnList(*Head, Key, &last)) {
+ cmsSignalError(LCMS_ERRC_ABORTED, "duplicate key <%s>", Key);
+ return false;
+ }
+
+ /* Allocate the container */
+ p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE));
+ if (p == NULL)
+ {
+ cmsSignalError(LCMS_ERRC_ABORTED, "AddToList: out of memory");
+ return false;
+ }
+
+ /* Store name and value */
+ p->Keyword = AllocString(it8, Key);
+
+ if (Value)
+ p->Value = AllocString(it8, Value);
+ else
+ p->Value = NULL;
+
+ p->Next = NULL;
+
+ /* Keep the container in our list */
+ if (*Head == NULL)
+ *Head = p;
+ else
+ last->Next = p;
+
+ return true;
+}
+
+static
+BOOL AddAvailableProperty(LPIT8 it8, const char* Key)
+{
+ return AddToList(it8, &it8->ValidKeywords, Key, NULL);
+}
+
+
+static
+BOOL AddAvailableSampleID(LPIT8 it8, const char* Key)
+{
+ return AddToList(it8, &it8->ValidSampleID, Key, NULL);
+}
+
+
+
+/* Init an empty container */
+LCMSHANDLE cmsxIT8Alloc(void)
+{
+ LPIT8 it8;
+ int i;
+
+ it8 = (LPIT8) malloc(sizeof(IT8));
+ if (it8 == NULL) return NULL;
+
+ ZeroMemory(it8, sizeof(IT8));
+
+ it8->HeaderList = NULL;
+ it8->FileBuffer = NULL;
+ it8->DataFormat = NULL;
+ it8->Data = NULL;
+ it8->MemorySink = NULL;
+ it8->ValidKeywords = NULL;
+ it8->ValidSampleID = NULL;
+
+ it8 -> sy = SNONE;
+ it8 -> ch = ' ';
+ it8 -> Source = NULL;
+ it8 -> inum = 0;
+ it8 -> dnum = 0.0;
+
+ it8 -> lineno = 1;
+
+ strcpy(it8->SheetType, "IT8.7/2");
+
+ /* Initialize predefined properties & data */
+
+ for (i=0; i < NUMPREDEFINEDPROPS; i++)
+ AddAvailableProperty(it8, PredefinedProperties[i]);
+
+ for (i=0; i < NUMPREDEFINEDSAMPLEID; i++)
+ AddAvailableSampleID(it8, PredefinedSampleID[i]);
+
+
+ return (LCMSHANDLE) it8;
+}
+
+
+const char* cdecl cmsxIT8GetSheetType(LCMSHANDLE hIT8)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ return it8 ->SheetType;
+
+}
+
+BOOL cmsxIT8SetSheetType(LCMSHANDLE hIT8, const char* Type)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ strncpy(it8 ->SheetType, Type, MAXSTR-1);
+ return true;
+}
+
+
+
+/* Sets a property */
+BOOL cmsxIT8SetProperty(LCMSHANDLE hIT8, const char* Key, const char *Val)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ if (!Val) return false;
+ if (!*Val) return false;
+
+ return AddToList(it8, &it8 -> HeaderList, Key, Val);
+}
+
+
+BOOL cmsxIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val)
+{
+ char Buffer[256];
+
+ sprintf(Buffer, "%g", Val);
+ return cmsxIT8SetProperty(hIT8, cProp, Buffer);
+}
+
+/* Gets a property */
+const char* cmsxIT8GetProperty(LCMSHANDLE hIT8, const char* Key)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+ LPKEYVALUE p;
+
+ if (IsAvailableOnList(it8 -> HeaderList, Key, &p))
+ {
+ return p -> Value;
+ }
+ return NULL;
+}
+
+
+double cmsxIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp)
+{
+ const char *v = cmsxIT8GetProperty(hIT8, cProp);
+ if (v) return atof(v);
+ else return 0.0;
+}
+
+/* ----------------------------------------------------------------- Datasets */
+
+
+static
+void AllocateDataFormat(LPIT8 it8)
+{
+ if (it8 -> DataFormat) return; /* Already allocated */
+
+ it8 -> nSamples = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
+
+ if (it8 -> nSamples <= 0) {
+
+ cmsSignalError(LCMS_ERRC_WARNING, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS, assuming 10");
+ it8 -> nSamples = 10;
+ }
+
+ it8 -> DataFormat = (char**) AllocChunk (it8, (it8->nSamples + 1) * sizeof(char *));
+ if (it8->DataFormat == NULL)
+ {
+ cmsSignalError(LCMS_ERRC_ABORTED, "AllocateDataFormat: Unable to allocate dataFormat array");
+ }
+
+}
+
+static
+const char *GetDataFormat(LPIT8 it8, int n)
+{
+ if (it8->DataFormat)
+ return it8->DataFormat[n];
+
+ return NULL;
+}
+
+static
+BOOL SetDataFormat(LPIT8 it8, int n, const char *label)
+{
+ if (n > it8 -> nSamples) return false;
+
+ if (!it8->DataFormat)
+ AllocateDataFormat(it8);
+
+ if (it8->DataFormat) {
+
+ it8->DataFormat[n] = AllocString(it8, label);
+ }
+
+ return true;
+}
+
+
+BOOL cmsxIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample)
+{
+ LPIT8 it8 = (LPIT8) h;
+ return SetDataFormat(it8, n, Sample);
+}
+
+static
+void AllocateDataSet(LPIT8 it8)
+{
+ if (it8 -> Data) return; /* Already allocated */
+
+ it8-> nSamples = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
+ it8-> nPatches = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_SETS"));
+ it8-> Data = (char**)AllocChunk (it8, (it8->nSamples + 1) * (it8->nPatches + 1) *sizeof (char*));
+ if (it8->Data == NULL)
+ {
+ cmsSignalError(-1, "AllocateDataSet: Unable to allocate data array");
+ }
+
+}
+
+static
+char* GetData(LPIT8 it8, int nSet, int nField)
+{
+ int nSamples = it8 -> nSamples;
+ int nPatches = it8 -> nPatches;
+
+ if (nSet >= nPatches || nField >= nSamples)
+ return NULL;
+
+ if (!it8->Data) return NULL;
+ return it8->Data [nSet * nSamples + nField];
+}
+
+static
+BOOL SetData(LPIT8 it8, int nSet, int nField, char *Val)
+{
+ if (!it8->Data)
+ AllocateDataSet(it8);
+
+ if (!it8->Data) return false;
+
+
+ if (nSet > it8 -> nPatches) {
+
+ SynError(it8, "Patch %d out of range, there are %d datasets", nSet, it8 -> nPatches);
+ return false;
+ }
+
+ if (nField > it8 ->nSamples) {
+ SynError(it8, "Sample %d out of range, there are %d datasets", nField, it8 ->nSamples);
+ return false;
+ }
+
+
+ it8->Data [nSet * it8 -> nSamples + nField] = AllocString(it8, Val);
+ return true;
+}
+
+
+/* --------------------------------------------------------------- File I/O */
+
+
+/* Writes a string to file */
+static
+void WriteStr(FILE *f, char *str)
+{
+ if (str == NULL)
+ fwrite(" ", 1, 1, f);
+ else
+ fwrite(str, 1, strlen(str), f);
+}
+
+
+/* Writes full header */
+static
+void WriteHeader(LPIT8 it8, FILE *fp)
+{
+ LPKEYVALUE p;
+
+ WriteStr(fp, it8->SheetType);
+ WriteStr(fp, "\n");
+ for (p = it8->HeaderList; (p != NULL); p = p->Next)
+ {
+ if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL)) {
+
+ WriteStr(fp, "KEYWORD\t\"");
+ WriteStr(fp, p->Keyword);
+ WriteStr(fp, "\"\n");
+
+ }
+
+ WriteStr(fp, p->Keyword);
+ if (p->Value) {
+
+ WriteStr(fp, "\t\"");
+ WriteStr(fp, p->Value);
+ WriteStr(fp, "\"");
+ }
+ WriteStr (fp, "\n");
+ }
+
+}
+
+
+/* Writes the data format */
+static
+void WriteDataFormat(FILE *fp, LPIT8 it8)
+{
+ int i, nSamples;
+
+ if (!it8 -> DataFormat) return;
+
+ WriteStr(fp, "BEGIN_DATA_FORMAT\n");
+ nSamples = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
+
+ for (i = 0; i < nSamples; i++) {
+
+ WriteStr(fp, it8->DataFormat[i]);
+ WriteStr(fp, (char*)((i == (nSamples-1)) ? "\n" : "\t")); // C->C++ : cast
+ }
+
+ WriteStr (fp, "END_DATA_FORMAT\n");
+}
+
+
+/* Writes data array */
+static
+void WriteData(FILE *fp, LPIT8 it8)
+{
+ int i, j;
+
+ if (!it8->Data) return;
+
+ WriteStr (fp, "BEGIN_DATA\n");
+
+ it8->nPatches = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_SETS"));
+
+ for (i = 0; i < it8-> nPatches; i++) {
+
+ for (j = 0; j < it8->nSamples; j++) {
+
+ char *ptr = it8->Data[i*it8->nSamples+j];
+
+ WriteStr(fp, (char*)((ptr == NULL) ? "0.00" : ptr)); // C->C++ : cast
+ WriteStr(fp, (char*)((j == (it8->nSamples-1)) ? "\n" : "\t")); // C->C++ : cast
+ }
+ }
+ WriteStr (fp, "END_DATA\n");
+}
+
+
+
+/* Saves whole file */
+BOOL cmsxIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName)
+{
+ FILE *fp;
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ fp = fopen(cFileName, "wt");
+ if (!fp) return false;
+ WriteHeader(it8, fp);
+ WriteDataFormat(fp, it8);
+ WriteData(fp, it8);
+ fclose(fp);
+
+ return true;
+}
+
+
+/* Reads whole file in a memory block */
+static
+BOOL ReadFileInMemory(const char *cFileName, char **Buffer, size_t *Len)
+{
+ FILE *fp;
+ size_t Size;
+ char *Ptr;
+
+ fp = fopen(cFileName, "rt");
+ if (!fp) return false;
+
+ Size = xfilelength(fileno(fp));
+ if (Size <= 0) {
+ fclose(fp);
+ return false;
+ }
+
+ Ptr = (char*)malloc(Size+1); // C->C++ : cast
+
+ Size = fread(Ptr, 1, Size, fp);
+ fclose(fp);
+ Ptr[Size] = '\0';
+
+ *Buffer = Ptr;
+ *Len = Size;
+ return true;
+}
+
+
+/* -------------------------------------------------------------- Higer lever parsing */
+
+static
+BOOL DataFormatSection(LPIT8 it8)
+{
+ int iField = 0;
+ BOOL Ignoring = false;
+
+ InSymbol(it8); /* Eats "BEGIN_DATA_FORMAT" */
+ CheckEOLN(it8);
+
+ while (it8->sy != SEND_DATA_FORMAT &&
+ it8->sy != SEOLN &&
+ it8->sy != SEOF &&
+ it8->sy != SSYNERROR)
+ {
+
+ if (it8->sy != SIDENT) {
+
+ cmsSignalError(LCMS_ERRC_ABORTED, "Sample type expected");
+ it8->sy = SSYNERROR;
+ return false;
+ }
+
+ if (!Ignoring && iField > it8->nSamples) {
+ cmsSignalError(LCMS_ERRC_WARNING, "More than NUMBER_OF_FIELDS fields. Extra is ignored\n");
+ Ignoring = true;
+ }
+ else {
+ if (!SetDataFormat(it8, iField, it8->id)) return false;
+ iField++;
+ }
+
+ InSymbol(it8);
+ Skip(it8, SEOLN);
+ }
+
+ Skip(it8, SEOLN);
+ Skip(it8, SEND_DATA_FORMAT);
+ Skip(it8, SEOLN);
+ return true;
+}
+
+
+
+static
+BOOL DataSection (LPIT8 it8)
+{
+ int iField = 0;
+ int iSet = 0;
+ char Buffer[256];
+
+ InSymbol(it8); /* Eats "BEGIN_DATA" */
+ CheckEOLN(it8);
+
+ while (it8->sy != SEND_DATA && it8->sy != SEOF)
+ {
+ if (iField >= it8 -> nSamples) {
+ iField = 0;
+ iSet++;
+ if (!CheckEOLN(it8))
+ return false;
+ }
+
+ if (it8->sy != SEND_DATA && it8->sy != SEOF) {
+
+ if (!GetVal(it8, Buffer))
+ return false;
+
+ if (!SetData(it8, iSet, iField, Buffer))
+ return false;
+
+ iField++;
+
+ Skip(it8, SEOLN);
+ InSymbol(it8);
+ }
+ }
+
+ Skip(it8, SEOLN);
+ Skip(it8, SEND_DATA);
+ Skip(it8, SEOLN);
+ return true;
+}
+
+
+
+
+
+
+static
+BOOL HeaderSection (LPIT8 it8)
+{
+ char VarName[MAXID];
+ char Buffer[MAXSTR];
+
+ while (it8->sy != SEOF &&
+ it8->sy != SSYNERROR &&
+ it8->sy != SBEGIN_DATA_FORMAT &&
+ it8->sy != SBEGIN_DATA) {
+
+
+ switch (it8 -> sy) {
+
+ case SKEYWORD:
+ InSymbol(it8);
+ if (!Check(it8, SSTRING, "Keyword expected")) return false;
+ if (!AddAvailableProperty(it8, it8 -> str)) return false;
+ InSymbol(it8);
+ break;
+
+
+ case SIDENT:
+ strncpy(VarName, it8->id, MAXID-1);
+ if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL))
+ return SynError(it8, "Undefined keyword '%s'", VarName);
+
+ InSymbol(it8);
+ GetVal(it8, Buffer);
+ cmsxIT8SetProperty((LCMSHANDLE) it8, VarName, Buffer);
+ InSymbol(it8);
+ break;
+
+
+ case SEOLN: break;
+
+ default:
+ return SynError(it8, "expected keyword or identifier");
+ }
+
+ Skip(it8, SEOLN);
+ }
+
+ return true;
+
+}
+
+
+static
+BOOL ParseIT8(LPIT8 it8)
+{
+
+ InSymbol(it8);
+
+ if (it8->sy == SIDENT) {
+
+ strncpy(it8->SheetType, it8->id, MAXSTR-1);
+ InSymbol(it8);
+
+ /* if (!AddAvailableProperty(it8, it8 -> id)) return false; */
+ /* cmsxIT8SetProperty((LCMSHANDLE) it8, it8->id, NULL); */
+ }
+
+ Skip(it8, SEOLN);
+
+ while (it8-> sy != SEOF &&
+ it8-> sy != SSYNERROR) {
+
+ switch (it8 -> sy) {
+
+ case SBEGIN_DATA_FORMAT:
+ if (!DataFormatSection(it8)) return false;
+ break;
+
+ case SBEGIN_DATA:
+ if (!DataSection(it8)) return false;
+ break;
+
+ case SEOLN:
+ Skip(it8, SEOLN);
+ break;
+
+ default:
+ if (!HeaderSection(it8)) return false;
+ }
+
+ }
+
+ return true;
+}
+
+
+static
+void CleanPatchName(char *cell)
+{
+ char cleaned[256], Buffer[256], ident[256];
+ char *orig = cell, *id;
+ int n, lOneNum;
+
+
+ id = ident;
+ while (*cell && isalpha(*cell))
+ {
+ *id++ = (char) toupper(*cell);
+ cell++;
+ }
+ *id = 0;
+ strcpy(cleaned, ident);
+
+
+ n = 0;
+ lOneNum = false;
+ while (*cell && isdigit(*cell))
+ {
+ n = n * 10 + (*cell -'0');
+ cell++;
+ lOneNum = true;
+ }
+
+ if (lOneNum) {
+
+ sprintf(Buffer, "%d", n);
+ strcat(cleaned, Buffer);
+ }
+
+ if (strcmp(cleaned, "GS0") == 0)
+ strcpy(orig, "DMIN");
+ else
+ if (strcmp(cleaned, "GS23") == 0)
+ strcpy(orig, "DMAX");
+ else
+ strcpy(orig, cleaned);
+}
+
+
+/* Init useful pointers */
+
+static
+void CookPointers(LPIT8 it8)
+{
+ int idField, i;
+ char* Fld;
+
+ it8 -> SampleID = 0;
+ for (idField = 0; idField < it8 -> nSamples; idField++)
+ {
+ Fld = it8->DataFormat[idField];
+ if (!Fld) continue;
+
+ if (strcmp(Fld, "SAMPLE_ID") == 0) {
+ it8 -> SampleID = idField;
+
+
+ for (i=0; i < it8 -> nPatches; i++) {
+
+ char *Data = GetData(it8, i, idField);
+ if (Data) {
+ char Buffer[256];
+
+ strncpy(Buffer, Data, 255);
+ CleanPatchName(Buffer);
+
+ if (strlen(Buffer) <= strlen(Data))
+ strcpy(Data, Buffer);
+ else
+ SetData(it8, i, idField, Buffer);
+
+ }
+ }
+
+ }
+ }
+
+}
+
+
+/* ---------------------------------------------------------- Exported routines */
+
+
+LCMSHANDLE cmsxIT8LoadFromMem(void *Ptr, size_t len)
+{
+ LCMSHANDLE hIT8 = cmsxIT8Alloc();
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ if (!hIT8) return NULL;
+ it8 ->FileBuffer = (char*) malloc(len + 1);
+
+ strncpy(it8 ->FileBuffer, (const char*)Ptr, len); // C->C++ : cast
+ strncpy(it8->FileName, "", MAX_PATH-1);
+ it8-> Source = it8 -> FileBuffer;
+
+ ParseIT8(it8);
+ CookPointers(it8);
+
+ free(it8->FileBuffer);
+ it8 -> FileBuffer = NULL;
+
+ return hIT8;
+
+
+}
+
+
+LCMSHANDLE cmsxIT8LoadFromFile(const char* cFileName)
+{
+
+ LCMSHANDLE hIT8 = cmsxIT8Alloc();
+ LPIT8 it8 = (LPIT8) hIT8;
+ size_t Len;
+
+ if (!hIT8) return NULL;
+ if (!ReadFileInMemory(cFileName, &it8->FileBuffer, &Len)) return NULL;
+
+ strncpy(it8->FileName, cFileName, MAX_PATH-1);
+ it8-> Source = it8 -> FileBuffer;
+
+ ParseIT8(it8);
+ CookPointers(it8);
+
+ free(it8->FileBuffer);
+ it8 -> FileBuffer = NULL;
+
+ return hIT8;
+
+}
+
+int cmsxIT8EnumDataFormat(LCMSHANDLE hIT8, char ***SampleNames)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+
+ *SampleNames = it8 -> DataFormat;
+ return it8 -> nSamples;
+}
+
+
+int cmsxIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+ LPKEYVALUE p;
+ int n;
+ char **Props;
+
+ /* Pass#1 - count properties */
+
+ n = 0;
+ for (p = it8 -> HeaderList; p != NULL; p = p->Next) {
+ n++;
+ }
+
+
+ Props = (char **) malloc(sizeof(char *) * n);
+
+ /* Pass#2 - Fill pointers */
+ n = 0;
+ for (p = it8 -> HeaderList; p != NULL; p = p->Next) {
+ Props[n++] = p -> Keyword;
+ }
+
+ *PropertyNames = Props;
+ return n;
+}
+
+static
+int LocatePatch(LPIT8 it8, const char* cPatch)
+{
+ int i;
+ const char *data;
+
+ for (i=0; i < it8-> nPatches; i++) {
+
+ data = GetData(it8, i, it8->SampleID);
+
+ if (data != NULL) {
+
+ if (stricmp(data, cPatch) == 0)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+static
+int LocateEmptyPatch(LPIT8 it8, const char* cPatch)
+{
+ int i;
+ const char *data;
+
+ for (i=0; i < it8-> nPatches; i++) {
+
+ data = GetData(it8, i, it8->SampleID);
+
+ if (data == NULL)
+ return i;
+
+ }
+
+ return -1;
+}
+
+static
+int LocateSample(LPIT8 it8, const char* cSample)
+{
+ int i;
+ const char *fld;
+
+ for (i=0; i < it8->nSamples; i++) {
+
+ fld = GetDataFormat(it8, i);
+ if (stricmp(fld, cSample) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+
+BOOL cmsxIT8GetDataSetByPos(LCMSHANDLE hIT8, int col, int row, char* Val, int ValBufferLen)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+ const char *data = GetData(it8, row, col);
+
+ if (!data)
+ {
+ *Val = '\0';
+ return false;
+ }
+
+ strncpy(Val, data, ValBufferLen-1);
+ return true;
+}
+
+
+
+BOOL cmsxIT8GetDataSet(LCMSHANDLE hIT8, const char* cPatch,
+ const char* cSample,
+ char* Val, int ValBuffLen)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+ int iField, iSet;
+
+
+ iField = LocateSample(it8, cSample);
+ if (iField < 0) {
+ /* cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find data field %s\n", cSample); */
+ return false;
+ }
+
+
+ iSet = LocatePatch(it8, cPatch);
+ if (iSet < 0) {
+
+ /* cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find patch '%s'\n", cPatch); */
+ return false;
+ }
+
+ strncpy(Val, GetData(it8, iSet, iField), ValBuffLen-1);
+ return true;
+}
+
+
+BOOL cmsxIT8GetDataSetDbl(LCMSHANDLE it8, const char* cPatch, const char* cSample, double* v)
+{
+ char Buffer[20];
+
+ if (cmsxIT8GetDataSet(it8, cPatch, cSample, Buffer, 20)) {
+
+ *v = atof(Buffer);
+ return true;
+ } else
+ return false;
+}
+
+
+
+BOOL cmsxIT8SetDataSet(LCMSHANDLE hIT8, const char* cPatch,
+ const char* cSample,
+ char *Val)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+ int iField, iSet;
+
+
+ iField = LocateSample(it8, cSample);
+
+ if (iField < 0) {
+
+ cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find data field %s\n", cSample);
+ return false;
+ }
+
+
+ if (it8-> nPatches == 0) {
+
+ AllocateDataFormat(it8);
+ AllocateDataSet(it8);
+ CookPointers(it8);
+ }
+
+
+ if (stricmp(cSample, "SAMPLE_ID") == 0)
+ {
+
+ iSet = LocateEmptyPatch(it8, cPatch);
+ if (iSet < 0) {
+ cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't add more patches '%s'\n", cPatch);
+ return false;
+ }
+ iField = it8 -> SampleID;
+ }
+ else {
+ iSet = LocatePatch(it8, cPatch);
+ if (iSet < 0) {
+
+ cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find patch '%s'\n", cPatch);
+ return false;
+ }
+ }
+
+ return SetData(it8, iSet, iField, Val);
+}
+
+
+BOOL cmsxIT8SetDataSetDbl(LCMSHANDLE hIT8, const char* cPatch,
+ const char* cSample,
+ double Val)
+{
+ char Buff[256];
+
+ sprintf(Buff, "%g", Val);
+ return cmsxIT8SetDataSet(hIT8, cPatch, cSample, Buff);
+
+}
+
+
+const char* cmsxIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer)
+{
+ LPIT8 it8 = (LPIT8) hIT8;
+ char* Data = GetData(it8, nPatch, it8->SampleID);
+ if (!Data) return NULL;
+
+ strcpy(buffer, Data);
+ return buffer;
+}
+
+
+const char* cmsxIT8GenericPatchName(int nPatch, char* buffer)
+{
+ int row, col;
+
+ if (nPatch >= cmsxIT8_NORMAL_PATCHES)
+ return "$CUSTOM";
+
+ if (nPatch >= (cmsxIT8_ROWS * cmsxIT8_COLS)) {
+
+ nPatch -= cmsxIT8_ROWS * cmsxIT8_COLS;
+ if (nPatch == 0)
+ return "DMIN";
+ else
+ if (nPatch == cmsxIT8_GRAYCOLS - 1)
+ return "DMAX";
+ else
+ sprintf(buffer, "GS%d", nPatch);
+ return buffer;
+ }
+
+
+ row = nPatch / cmsxIT8_COLS;
+ col = nPatch % cmsxIT8_COLS;
+
+ sprintf (buffer, "%c%d", 'A'+row, col+1);
+ return buffer;
+}
+
+
+
+
+int cmsxIT8GenericPatchNum(const char *name)
+{
+ int i;
+ char Buff[256];
+
+
+ for (i=0; i < cmsxIT8_TOTAL_PATCHES; i++)
+ if (stricmp(cmsxIT8GenericPatchName(i, Buff), name) == 0)
+ return i;
+
+ return -1;
+}
+
+
+
+
+