/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
// This file is available under and governed by the GNU General Public // License version 2 only, as published by the Free Software Foundation. // However, the following notice accompanied the original version of this // file: // //--------------------------------------------------------------------------------- // // Little Color Management System // Copyright (c) 1998-2022 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. // //--------------------------------------------------------------------------------- //
#define MAXID 128 // Max length of identifier #define MAXSTR 1024 // Max length of string #define MAXTABLES 255 // Max Number of tables in a single stream #define MAXINCLUDE 20 // Max number of nested includes
SUNDEFINED,
SINUM, // Integer
SDNUM, // Real
SIDENT, // Identifier
SSTRING, // string
SCOMMENT, // comment
SEOLN, // End of line
SEOF, // End of stream
SSYNERROR, // Syntax error found on stream
// Linked list of variable names typedefstruct _KeyVal {
struct _KeyVal* Next; char* Keyword; // Name of variable struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item char* Subkey; // If key is a dictionary, points to the subkey name char* Value; // Points to value
WRITEMODE WriteAs; // How to write the value
} KEYVALUE;
// Linked list of memory chunks (Memory sink) typedefstruct _OwnedMem {
struct _OwnedMem* Next; void * Ptr; // Point to value
// Table. Each individual table can hold properties and rows & cols typedefstruct _Table {
char SheetType[MAXSTR]; // The first row of the IT8 (the type)
int nSamples, nPatches; // Cols, Rows int SampleID; // Pos of ID
KEYVALUE* HeaderList; // The properties
char** DataFormat; // The binary stream descriptor char** Data; // The binary stream
} TABLE;
// File stream being parsed typedefstruct _FileContext { char FileName[cmsMAX_PATH]; // File name if being read from file
FILE* Stream; // File stream or NULL if holded in memory
} FILECTX;
// A property typedefstruct { constchar *id; // The identifier
WRITEMODE as; // How is supposed to be written
} PROPERTY;
static PROPERTY PredefinedProperties[] = {
{"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS
{"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS
{"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file.
{"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file.
{"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file.
{"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file.
{"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal".
{"MANUFACTURER", WRITE_STRINGIFY},
{"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value
{"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm.
{"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target.
{"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code // uniquely identifying th e material. This is intend ed to be used for IT8.7 // physical targets only (i.e . IT8.7/1 and IT8.7/2).
{"INSTRUMENTATION", WRITE_STRINGIFY}, // 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", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide // a guide to the potential for issues of paper fluorescence, etc.
{"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. // Where standard conditions have been defined (e.g., SWOP at nominal) // named conditions may suffice. Otherwise, detailed information is // needed.
{"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during // measurement. Allowed values are "black", "white", or {"na".
{"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic // below properties are new in recent specs:
{"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated // along with details of the geometry and the aperture size and shape. For example, // for transmission measurements it is important to identify 0/diffuse, diffuse/0, // opal or integrating sphere, etc. For reflection it is important to identify 0/45, // 45/0, sphere (specular included or excluded), etc.
{"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to // denote the use of filters such as none, D65, Red, Green or Blue.
{"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed // values are {"yes", "white", "none" or "na".
{"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the // calculation of various data parameters (2 degree and 10 degree), CIE standard // illuminant functions used in the calculation of various data parameters (e.g., D50, // D65, etc.), density status response, etc. If used there shall be at least one // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute // in the set shall be {"name" and shall identify the particular parameter used. // The second shall be {"value" and shall provide the value associated with that name. // For ASCII data, a string containing the Name and Value attribute pairs shall follow // the weighting function keyword. A semi-colon separates attribute pairs from each // other and within the attribute the name and value are separated by a comma.
{"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name // of the calculation, parameter is the name of the parameter used in the calculation // and value is the value of the parameter.
{"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc.
{"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target.
{"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table.
{"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table.
};
// Predefined sample types on dataset staticconstchar* PredefinedSampleID[] = { "SAMPLE_ID", // Identifies sample that data represents "STRING", // Identifies label, or other non-machine readable value. // Value must begin and end with a " symbol
"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_SQD_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
// Makes a file path based on a given reference path // NOTE: this function doesn't check if the path exists or even if it's legal static
cmsBool BuildAbsolutePath(constchar *relPath, constchar *basePath, char *buffer, cmsUInt32Number MaxLen)
{ char *tail;
cmsUInt32Number len;
// Already absolute? if (isabsolutepath(relPath)) {
// No, search for last
strncpy(buffer, basePath, MaxLen);
buffer[MaxLen-1] = 0;
tail = strrchr(buffer, DIR_CHAR); if (tail == NULL) returnFALSE; // Is not absolute and has no separators??
len = (cmsUInt32Number) (tail - buffer); if (len >= MaxLen) returnFALSE;
// No need to assure zero terminator over here
strncpy(tail + 1, relPath, MaxLen - len);
returnTRUE;
}
// Make sure no exploit is being even tried static constchar* NoMeta(constchar* str)
{ if (strchr(str, '%') != NULL) return"**** CORRUPTED FORMAT STRING ***";
// Check if current symbol is same as specified. issue an error else. static
cmsBool Check(cmsIT8* it8, SYMBOL sy, constchar* Err)
{ if (it8 -> sy != sy) return SynError(it8, NoMeta(Err)); returnTRUE;
}
// Read Next character from stream static void NextCh(cmsIT8* it8)
{ if (it8 -> FileStack[it8 ->IncludeSP]->Stream) {
// Try to see if current identifier is a keyword, if so return the referred symbol static
SYMBOL BinSrchKey(constchar *id)
{ int l = 1; int r = NUMKEYS; int x, res;
while (r >= l)
{
x = (l+r)/2;
res = cmsstrcasecmp(id, TabKeys[x-1].id); if (res == 0) return TabKeys[x-1].sy; if (res < 0) r = x - 1; else l = x + 1;
}
// Reads a Real number, tries to follow from integer number static void ReadReal(cmsIT8* it8, cmsInt32Number inum)
{
it8->dnum = (cmsFloat64Number)inum;
if ((cmsFloat64Number)e * 10.0 + (cmsFloat64Number)digit < (cmsFloat64Number)+2147483647.0)
e = e * 10 + digit;
NextCh(it8);
}
e = sgn*e;
it8->dnum = it8->dnum * xpow10(e);
}
}
// Parses a float number // This can not call directly atof because it uses locale dependent // parsing, while CCMX files always use . as decimal separator static
cmsFloat64Number ParseFloatNumber(constchar *Buffer)
{
cmsFloat64Number dnum = 0.0; int sign = 1;
// Exponent, example 34.00E+20 if (*Buffer && toupper(*Buffer) == 'E') {
int e; int sgn;
if (*Buffer) Buffer++;
sgn = 1;
if (*Buffer == '-') {
sgn = -1; if (*Buffer) Buffer++;
} else if (*Buffer == '+') {
sgn = +1; if (*Buffer) Buffer++;
}
e = 0; while (*Buffer && isdigit((int)*Buffer)) {
cmsInt32Number digit = (*Buffer - '0');
if ((cmsFloat64Number)e * 10.0 + digit < (cmsFloat64Number)+2147483647.0)
e = e * 10 + digit;
if (*Buffer) Buffer++;
}
e = sgn*e;
dnum = dnum * xpow10(e);
}
return sign * dnum;
}
// Reads a string, special case to avoid infinite resursion on .include static void InStringSymbol(cmsIT8* it8)
{ while (isseparator(it8->ch))
NextCh(it8);
if (it8->ch == '\'' || it8->ch == '\"')
{ int sng;
// Checks end of line separator static
cmsBool CheckEOLN(cmsIT8* it8)
{ if (!Check(it8, SEOLN, "Expected separator")) returnFALSE; while (it8 -> sy == SEOLN)
InSymbol(it8); returnTRUE;
}
// Skip a symbol
static void Skip(cmsIT8* it8, SYMBOL sy)
{ if (it8->sy == sy && it8->sy != SEOF)
InSymbol(it8);
}
// Allocate the container
p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE)); if (p == NULL)
{
SynError(it8, "AddToList: out of memory"); return NULL;
}
// Store name and value
p->Keyword = AllocString(it8, Key);
p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
// Keep the container in our list if (*Head == NULL) {
*Head = p;
} else
{ if (Subkey != NULL && last != NULL) {
last->NextSubkey = p;
// If Subkey is not null, then last is the last property with the same key, // but not necessarily is the last property in the list, so we need to move // to the actual list end while (last->Next != NULL)
last = last->Next;
}
InSymbol(it8); if (!GetVal(it8, Buffer, MAXSTR - 1, "Property data expected")) returnFALSE;
if (Key->WriteAs != WRITE_PAIR) {
AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer,
(it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED);
} else { constchar *Subkey; char *Nextkey; if (it8->sy != SSTRING) return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
// chop the string as a list of "subkey, value" pairs, using ';' as a separator for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
{ char *Value, *temp;
// for each pair, split the subkey and the value
Value = (char*)strrchr(Subkey, ','); if (Value == NULL) return SynError(it8, "Invalid value for property '%s'.", VarName);
// gobble the spaces before the coma, and the coma itself
temp = Value++; do *temp-- = '\0'; while (temp >= Subkey && *temp == ' ');
// gobble any space at the right
temp = Value + strlen(Value) - 1; while (*temp == ' ') *temp-- = '\0';
// trim the strings from the left
Subkey += strspn(Subkey, " ");
Value += strspn(Value, " ");
if (Subkey[0] == 0 || Value[0] == 0) return SynError(it8, "Invalid value for property '%s'.", VarName);
AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR);
}
}
InSymbol(it8); break;
case SEOLN: break;
default: return SynError(it8, "expected keyword or identifier");
}
// Read sheet type if present. We only support identifier and string. // <ident> <eoln> is a type string // anything else, is not a type string if (nosheet == 0) {
if (it8 ->sy == SIDENT) {
// May be a type sheet or may be a prop value statement. We cannot use insymbol in // this special case... while (isseparator(it8->ch))
NextCh(it8);
// If a newline is found, then this is a type string if (it8 ->ch == '\n' || it8->ch == '\r') {
cmsIT8SetSheetType(it8, StringPtr(it8 ->id));
InSymbol(it8);
} else
{ // It is not. Just continue
cmsIT8SetSheetType(it8, "");
}
} else // Validate quoted strings if (it8 ->sy == SSTRING) {
cmsIT8SetSheetType(it8, StringPtr(it8 ->str));
InSymbol(it8);
}
}
for (idField = 0; idField < t -> nSamples; idField++)
{ if (t ->DataFormat == NULL){
SynError(it8, "Undefined DATA_FORMAT"); return;
}
Fld = t->DataFormat[idField]; if (!Fld) continue;
if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
t -> SampleID = idField;
}
// "LABEL" is an extension. It keeps references to forward tables
if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
// Search for table references... for (i = 0; i < t->nPatches; i++) {
char* Label = GetData(it8, i, idField);
if (Label) {
cmsUInt32Number k;
// This is the label, search for a table containing // this property
for (k = 0; k < it8->TablesCount; k++) {
TABLE* Table = it8->Tab + k;
KEYVALUE* p;
if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
// Available, keep type and table char Buffer[256];
char* Type = p->Value;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.85Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.