277
284
{".INCLUDE", SINCLUDE},
278
285
{"BEGIN_DATA", SBEGIN_DATA },
279
286
{"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT },
287
{"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID},
280
288
{"END_DATA", SEND_DATA},
281
289
{"END_DATA_FORMAT", SEND_DATA_FORMAT},
282
290
{"KEYWORD", SKEYWORD}
286
293
#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
288
295
// Predefined properties
290
static const char* PredefinedProperties[] = {
292
"NUMBER_OF_FIELDS", // Required - NUMBER OF FIELDS
293
"NUMBER_OF_SETS", // Required - NUMBER OF SETS
294
"ORIGINATOR", // Required - Identifies the specific system, organization or individual that created the data file.
295
"FILE_DESCRIPTOR", // Required - Describes the purpose or contents of the data file.
296
"CREATED", // Required - Indicates date of creation of the data file.
297
"DESCRIPTOR", // Required - Describes the purpose or contents of the data file.
298
"DIFFUSE_GEOMETRY", // The diffuse geometry used. Allowed values are "sphere" or "opal".
300
"MANUFACTURE", // Some broken Fuji targets does store this value
301
"PROD_DATE", // Identifies year and month of production of the target in the form yyyy:mm.
302
"SERIAL", // Uniquely identifies individual physical target.
304
"MATERIAL", // Identifies the material on which the target was produced using a code
303
static PROPERTY PredefinedProperties[] = {
305
{"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS
306
{"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS
307
{"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file.
308
{"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file.
309
{"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file.
310
{"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file.
311
{"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal".
312
{"MANUFACTURER", WRITE_STRINGIFY},
313
{"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value
314
{"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm.
315
{"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target.
317
{"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code
305
318
// uniquely identifying th e material. This is intend ed to be used for IT8.7
306
319
// physical targets only (i.e . IT8.7/1 a nd IT8.7/2).
308
"INSTRUMENTATION", // Used to report the specific instrumentation used (manufacturer and
321
{"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and
309
322
// model number) to generate the data reported. This data will often
310
323
// provide more information about the particular data collected than an
311
324
// extensive list of specific details. This is particularly important for
312
325
// spectral data or data derived from spectrophotometry.
314
"MEASUREMENT_SOURCE", // Illumination used for spectral measurements. This data helps provide
327
{"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide
315
328
// a guide to the potential for issues of paper fluorescence, etc.
317
"PRINT_CONDITIONS", // Used to define the characteristics of the printed sheet being reported.
330
{"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported.
318
331
// Where standard conditions have been defined (e.g., SWOP at nominal)
319
332
// named conditions may suffice. Otherwise, detailed information is
322
"SAMPLE_BACKING", // Identifies the backing material used behind the sample during
323
// measurement. Allowed values are �black�, �white�, or "na".
325
"CHISQ_DOF" // Degrees of freedom associated with the Chi squared statistic
335
{"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during
336
// measurement. Allowed values are �black�, �white�, or {"na".
338
{"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic
340
// new in recent specs:
341
{"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated
342
// along with details of the geometry and the aperture size and shape. For example,
343
// for transmission measurements it is important to identify 0/diffuse, diffuse/0,
344
// opal or integrating sphere, etc. For reflection it is important to identify 0/45,
345
// 45/0, sphere (specular included or excluded), etc.
347
{"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to
348
// denote the use of filters such as none, D65, Red, Green or Blue.
350
{"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed
351
// values are {"yes�, �white�, �none� or �na�.
353
{"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the
354
// calculation of various data parameters (2 degree and 10 degree), CIE standard
355
// illuminant functions used in the calculation of various data parameters (e.g., D50,
356
// D65, etc.), density status response, etc. If used there shall be at least one
357
// name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute
358
// in the set shall be {"name" and shall identify the particular parameter used.
359
// The second shall be {"value" and shall provide the value associated with that name.
360
// For ASCII data, a string containing the Name and Value attribute pairs shall follow
361
// the weighting function keyword. A semi-colon separates attribute pairs from each
362
// other and within the attribute the name and value are separated by a comma.
364
{"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name
365
// of the calculation, parameter is the name of the parameter used in the calculation
366
// and value is the value of the parameter.
368
{"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc.
370
{"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target.
372
{"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table.
374
{"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table.
328
#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(char *))
377
#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY))
331
380
// Predefined sample types on dataset
332
381
static const char* PredefinedSampleID[] = {
382
"SAMPLE_ID", // Identifies sample that data represents
383
"STRING", // Identifies label, or other non-machine readable value.
384
// Value must begin and end with a " symbol
334
386
"CMYK_C", // Cyan component of CMYK data expressed as a percentage
335
387
"CMYK_M", // Magenta component of CMYK data expressed as a percentage
1075
1148
// Add a property into a linked list
1077
LCMSBOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* xValue, WRITEMODE WriteAs)
1150
LPKEYVALUE AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
1083
1154
// Check if property is already in list (this is an error)
1085
if (IsAvailableOnList(*Head, Key, &last)) {
1087
// This may work for editing properties
1089
last->Value = AllocString(it8, xValue);
1090
last->WriteAs = WriteAs;
1156
if (IsAvailableOnList(*Head, Key, Subkey, &p)) {
1158
// This may work for editing properties
1160
// return SynError(it8, "duplicate key <%s>", Key);
1163
LPKEYVALUE last = p;
1094
1165
// Allocate the container
1095
1166
p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE));
1098
return SynError(it8, "AddToList: out of memory");
1169
SynError(it8, "AddToList: out of memory");
1101
1173
// Store name and value
1102
1174
p->Keyword = AllocString(it8, Key);
1175
p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
1177
// Keep the container in our list
1182
if(Subkey != 0 && last != 0) {
1183
last->NextSubkey = p;
1185
// If Subkey is not null, then last is the last property with the same key,
1186
// but not necessarily is the last property in the list, so we need to move
1187
// to the actual list end
1188
while(last->Next != 0)
1195
p->NextSubkey = NULL;
1198
p->WriteAs = WriteAs;
1104
1199
if (xValue != NULL) {
1106
1201
p->Value = AllocString(it8, xValue);
1822
1939
if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE;
1823
if (!AddAvailableProperty(it8, Buffer)) return FALSE;
1940
if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE;
1945
case SDATA_FORMAT_ID:
1947
if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE;
1948
if (!AddAvailableSampleID(it8, Buffer)) return FALSE;
1829
1954
strncpy(VarName, it8->id, MAXID-1);
1955
VarName[MAXID-1] = 0;
1831
if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL)) {
1957
if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) {
1833
1959
#ifdef STRICT_CGATS
1834
1960
return SynError(it8, "Undefined keyword '%s'", VarName);
1836
if (!AddAvailableProperty(it8, VarName)) return FALSE;
1962
Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED);
1963
if (Key == NULL) return FALSE;
1841
1968
if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE;
1844
AddToList(it8, &GetTable(it8)->HeaderList, VarName, Buffer,
1845
(it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED);
1970
if(Key->WriteAs != WRITE_PAIR) {
1971
AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer,
1972
(it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED);
1977
if (it8->sy != SSTRING)
1978
return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
1980
// chop the string as a list of "subkey, value" pairs, using ';' as a separator
1981
for(Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
1985
// identify token pair boundary
1986
Nextkey = (char*) strchr(Subkey, ';');
1990
// for each pair, split the subkey and the value
1991
Value = (char*) strrchr(Subkey, ',');
1993
return SynError(it8, "Invalid value for property '%s'.", VarName);
1995
// gobble the spaces before the coma, and the coma itself
1997
do *temp-- = '\0'; while(temp >= Subkey && *temp == ' ');
1999
// gobble any space at the right
2000
temp = Value + strlen(Value) - 1;
2001
while(*temp == ' ') *temp-- = '\0';
2003
// trim the strings from the left
2004
Subkey += strspn(Subkey, " ");
2005
Value += strspn(Value, " ");
2007
if(Subkey[0] == 0 || Value[0] == 0)
2008
return SynError(it8, "Invalid value for property '%s'.", VarName);
2009
AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR);