diff options
Diffstat (limited to 'src/libs/lprof/cmssheet.cpp')
-rw-r--r-- | src/libs/lprof/cmssheet.cpp | 1746 |
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; +} + + + + + |