0N/A/*
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A// This file is available under and governed by the GNU General Public
0N/A// License version 2 only, as published by the Free Software Foundation.
0N/A// However, the following notice accompanied the original version of this
0N/A// file:
0N/A//
2693N/A//---------------------------------------------------------------------------------
0N/A//
2693N/A// Little Color Management System
6271N/A// Copyright (c) 1998-2012 Marti Maria Saguer
0N/A//
0N/A// Permission is hereby granted, free of charge, to any person obtaining
0N/A// a copy of this software and associated documentation files (the "Software"),
0N/A// to deal in the Software without restriction, including without limitation
0N/A// the rights to use, copy, modify, merge, publish, distribute, sublicense,
0N/A// and/or sell copies of the Software, and to permit persons to whom the Software
0N/A// is furnished to do so, subject to the following conditions:
0N/A//
0N/A// The above copyright notice and this permission notice shall be included in
0N/A// all copies or substantial portions of the Software.
0N/A//
0N/A// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0N/A// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
0N/A// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0N/A// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0N/A// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0N/A// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0N/A// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0N/A//
2693N/A//---------------------------------------------------------------------------------
2693N/A//
2693N/A
2693N/A#include "lcms2_internal.h"
2693N/A
2693N/A
2693N/A// IT8.7 / CGATS.17-200x handling -----------------------------------------------------------------------------
2693N/A
2693N/A
2693N/A#define MAXID 128 // Max lenght of identifier
1002N/A#define MAXSTR 1024 // Max lenght of string
2693N/A#define MAXTABLES 255 // Max Number of tables in a single stream
2693N/A#define MAXINCLUDE 20 // Max number of nested includes
0N/A
0N/A#define DEFAULT_DBL_FORMAT "%.10g" // Double formatting
0N/A
2693N/A#ifdef CMS_IS_WINDOWS_
2693N/A# include <io.h>
2693N/A# define DIR_CHAR '\\'
1002N/A#else
2693N/A# define DIR_CHAR '/'
0N/A#endif
0N/A
6271N/A
0N/A// Symbols
0N/Atypedef enum {
0N/A
0N/A SNONE,
0N/A SINUM, // Integer
0N/A SDNUM, // Real
0N/A SIDENT, // Identifier
0N/A SSTRING, // string
0N/A SCOMMENT, // comment
0N/A SEOLN, // End of line
0N/A SEOF, // End of stream
0N/A SSYNERROR, // Syntax error found on stream
0N/A
0N/A // Keywords
0N/A
0N/A SBEGIN_DATA,
0N/A SBEGIN_DATA_FORMAT,
0N/A SEND_DATA,
0N/A SEND_DATA_FORMAT,
0N/A SKEYWORD,
1002N/A SDATA_FORMAT_ID,
0N/A SINCLUDE
0N/A
0N/A } SYMBOL;
0N/A
0N/A
0N/A// How to write the value
0N/Atypedef enum {
2693N/A
0N/A WRITE_UNCOOKED,
0N/A WRITE_STRINGIFY,
0N/A WRITE_HEXADECIMAL,
1002N/A WRITE_BINARY,
1002N/A WRITE_PAIR
0N/A
0N/A } WRITEMODE;
0N/A
0N/A// Linked list of variable names
0N/Atypedef struct _KeyVal {
0N/A
0N/A struct _KeyVal* Next;
0N/A char* Keyword; // Name of variable
1002N/A struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item
1002N/A char* Subkey; // If key is a dictionary, points to the subkey name
0N/A char* Value; // Points to value
0N/A WRITEMODE WriteAs; // How to write the value
0N/A
2693N/A } KEYVALUE;
0N/A
0N/A
0N/A// Linked list of memory chunks (Memory sink)
0N/Atypedef struct _OwnedMem {
0N/A
0N/A struct _OwnedMem* Next;
0N/A void * Ptr; // Point to value
0N/A
2693N/A } OWNEDMEM;
0N/A
0N/A// Suballocator
0N/Atypedef struct _SubAllocator {
0N/A
2693N/A cmsUInt8Number* Block;
2693N/A cmsUInt32Number BlockSize;
2693N/A cmsUInt32Number Used;
2693N/A
2693N/A } SUBALLOCATOR;
0N/A
0N/A// Table. Each individual table can hold properties and rows & cols
0N/Atypedef struct _Table {
0N/A
6271N/A char SheetType[MAXSTR]; // The first row of the IT8 (the type)
6271N/A
0N/A int nSamples, nPatches; // Cols, Rows
0N/A int SampleID; // Pos of ID
0N/A
2693N/A KEYVALUE* HeaderList; // The properties
0N/A
0N/A char** DataFormat; // The binary stream descriptor
0N/A char** Data; // The binary stream
0N/A
2693N/A } TABLE;
0N/A
1002N/A// File stream being parsed
1002N/Atypedef struct _FileContext {
2693N/A char FileName[cmsMAX_PATH]; // File name if being readed from file
2693N/A FILE* Stream; // File stream or NULL if holded in memory
2693N/A } FILECTX;
2693N/A
2693N/A// This struct hold all information about an open IT8 handler.
0N/Atypedef struct {
0N/A
2693N/A
2693N/A cmsUInt32Number TablesCount; // How many tables in this stream
2693N/A cmsUInt32Number nTable; // The actual table
0N/A
0N/A TABLE Tab[MAXTABLES];
0N/A
0N/A // Memory management
2693N/A OWNEDMEM* MemorySink; // The storage backend
0N/A SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast
0N/A
0N/A // Parser state machine
0N/A SYMBOL sy; // Current symbol
0N/A int ch; // Current character
0N/A
0N/A int inum; // integer value
2693N/A cmsFloat64Number dnum; // real value
0N/A char id[MAXID]; // identifier
0N/A char str[MAXSTR]; // string
0N/A
0N/A // Allowed keywords & datasets. They have visibility on whole stream
2693N/A KEYVALUE* ValidKeywords;
2693N/A KEYVALUE* ValidSampleID;
0N/A
0N/A char* Source; // Points to loc. being parsed
0N/A int lineno; // line counter for error reporting
0N/A
2693N/A FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed
0N/A int IncludeSP; // Include Stack Pointer
1002N/A
0N/A char* MemoryBlock; // The stream if holded in memory
0N/A
2693N/A char DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter
2693N/A
2693N/A cmsContext ContextID; // The threading context
2693N/A
2693N/A } cmsIT8;
2693N/A
2693N/A
2693N/A// The stream for save operations
0N/Atypedef struct {
0N/A
1002N/A FILE* stream; // For save-to-file behaviour
1002N/A
2693N/A cmsUInt8Number* Base;
2693N/A cmsUInt8Number* Ptr; // For save-to-mem behaviour
2693N/A cmsUInt32Number Used;
2693N/A cmsUInt32Number Max;
2693N/A
2693N/A } SAVESTREAM;
2693N/A
2693N/A
2693N/A// ------------------------------------------------------ cmsIT8 parsing routines
0N/A
0N/A
0N/A// A keyword
0N/Atypedef struct {
0N/A
0N/A const char *id;
0N/A SYMBOL sy;
0N/A
0N/A } KEYWORD;
0N/A
0N/A// The keyword->symbol translation table. Sorting is required.
0N/Astatic const KEYWORD TabKeys[] = {
0N/A
2693N/A {"$INCLUDE", SINCLUDE}, // This is an extension!
2693N/A {".INCLUDE", SINCLUDE}, // This is an extension!
2693N/A
2693N/A {"BEGIN_DATA", SBEGIN_DATA },
2693N/A {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT },
1002N/A {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID},
2693N/A {"END_DATA", SEND_DATA},
2693N/A {"END_DATA_FORMAT", SEND_DATA_FORMAT},
2693N/A {"KEYWORD", SKEYWORD}
0N/A };
0N/A
0N/A#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
0N/A
0N/A// Predefined properties
0N/A
1002N/A// A property
1002N/Atypedef struct {
2693N/A const char *id; // The identifier
2693N/A WRITEMODE as; // How is supposed to be written
1002N/A } PROPERTY;
1002N/A
1002N/Astatic PROPERTY PredefinedProperties[] = {
1002N/A
1002N/A {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS
1002N/A {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS
1002N/A {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file.
1002N/A {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file.
1002N/A {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file.
1002N/A {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file.
1002N/A {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal".
1002N/A {"MANUFACTURER", WRITE_STRINGIFY},
1002N/A {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value
1002N/A {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm.
1002N/A {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target.
1002N/A
1002N/A {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code
0N/A // uniquely identifying th e material. This is intend ed to be used for IT8.7
0N/A // physical targets only (i.e . IT8.7/1 a nd IT8.7/2).
0N/A
1002N/A {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and
0N/A // model number) to generate the data reported. This data will often
0N/A // provide more information about the particular data collected than an
0N/A // extensive list of specific details. This is particularly important for
0N/A // spectral data or data derived from spectrophotometry.
0N/A
1002N/A {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide
0N/A // a guide to the potential for issues of paper fluorescence, etc.
0N/A
1002N/A {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported.
0N/A // Where standard conditions have been defined (e.g., SWOP at nominal)
0N/A // named conditions may suffice. Otherwise, detailed information is
0N/A // needed.
0N/A
1002N/A {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during
1002N/A // measurement. Allowed values are �black�, �white�, or {"na".
1002N/A
1002N/A {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic
1002N/A
2693N/A // below properties are new in recent specs:
2693N/A
1002N/A {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated
1002N/A // along with details of the geometry and the aperture size and shape. For example,
1002N/A // for transmission measurements it is important to identify 0/diffuse, diffuse/0,
1002N/A // opal or integrating sphere, etc. For reflection it is important to identify 0/45,
1002N/A // 45/0, sphere (specular included or excluded), etc.
1002N/A
1002N/A {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to
1002N/A // denote the use of filters such as none, D65, Red, Green or Blue.
1002N/A
1002N/A {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed
1002N/A // values are {"yes�, �white�, �none� or �na�.
1002N/A
1002N/A {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the
1002N/A // calculation of various data parameters (2 degree and 10 degree), CIE standard
1002N/A // illuminant functions used in the calculation of various data parameters (e.g., D50,
1002N/A // D65, etc.), density status response, etc. If used there shall be at least one
1002N/A // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute
1002N/A // in the set shall be {"name" and shall identify the particular parameter used.
1002N/A // The second shall be {"value" and shall provide the value associated with that name.
1002N/A // For ASCII data, a string containing the Name and Value attribute pairs shall follow
1002N/A // the weighting function keyword. A semi-colon separates attribute pairs from each
1002N/A // other and within the attribute the name and value are separated by a comma.
1002N/A
1002N/A {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name
1002N/A // of the calculation, parameter is the name of the parameter used in the calculation
1002N/A // and value is the value of the parameter.
1002N/A
1002N/A {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc.
1002N/A
1002N/A {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target.
1002N/A
1002N/A {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table.
1002N/A
1002N/A {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table.
0N/A};
0N/A
1002N/A#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY))
0N/A
0N/A
0N/A// Predefined sample types on dataset
0N/Astatic const char* PredefinedSampleID[] = {
1002N/A "SAMPLE_ID", // Identifies sample that data represents
1002N/A "STRING", // Identifies label, or other non-machine readable value.
1002N/A // Value must begin and end with a " symbol
0N/A
0N/A "CMYK_C", // Cyan component of CMYK data expressed as a percentage
0N/A "CMYK_M", // Magenta component of CMYK data expressed as a percentage
0N/A "CMYK_Y", // Yellow component of CMYK data expressed as a percentage
0N/A "CMYK_K", // Black component of CMYK data expressed as a percentage
0N/A "D_RED", // Red filter density
0N/A "D_GREEN", // Green filter density
0N/A "D_BLUE", // Blue filter density
0N/A "D_VIS", // Visual filter density
0N/A "D_MAJOR_FILTER", // Major filter d ensity
0N/A "RGB_R", // Red component of RGB data
0N/A "RGB_G", // Green component of RGB data
0N/A "RGB_B", // Blue com ponent of RGB data
0N/A "SPECTRAL_NM", // Wavelength of measurement expressed in nanometers
0N/A "SPECTRAL_PCT", // Percentage reflectance/transmittance
0N/A "SPECTRAL_DEC", // Reflectance/transmittance
0N/A "XYZ_X", // X component of tristimulus data
0N/A "XYZ_Y", // Y component of tristimulus data
0N/A "XYZ_Z", // Z component of tristimulus data
0N/A "XYY_X" // x component of chromaticity data
0N/A "XYY_Y", // y component of chromaticity data
0N/A "XYY_CAPY", // Y component of tristimulus data
0N/A "LAB_L", // L* component of Lab data
0N/A "LAB_A", // a* component of Lab data
0N/A "LAB_B", // b* component of Lab data
0N/A "LAB_C", // C*ab component of Lab data
0N/A "LAB_H", // hab component of Lab data
2693N/A "LAB_DE", // CIE dE
2693N/A "LAB_DE_94", // CIE dE using CIE 94
2693N/A "LAB_DE_CMC", // dE using CMC
0N/A "LAB_DE_2000", // CIE dE using CIE DE 2000
0N/A "MEAN_DE", // Mean Delta E (LAB_DE) of samples compared to batch average
0N/A // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets)
0N/A "STDEV_X", // Standard deviation of X (tristimulus data)
0N/A "STDEV_Y", // Standard deviation of Y (tristimulus data)
0N/A "STDEV_Z", // Standard deviation of Z (tristimulus data)
0N/A "STDEV_L", // Standard deviation of L*
1002N/A "STDEV_A", // Standard deviation of a*
0N/A "STDEV_B", // Standard deviation of b*
0N/A "STDEV_DE", // Standard deviation of CIE dE
0N/A "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is
0N/A // used to derive an estimate of the chi-squared parameter which is
0N/A // recommended as the predictor of the variability of dE
0N/A
0N/A#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *))
0N/A
1002N/A//Forward declaration of some internal functions
2693N/Astatic void* AllocChunk(cmsIT8* it8, cmsUInt32Number size);
1002N/A
0N/A// Checks if c is a separator
0N/Astatic
2693N/AcmsBool isseparator(int c)
0N/A{
0N/A return (c == ' ') || (c == '\t') || (c == '\r');
0N/A}
0N/A
0N/A// Checks whatever if c is a valid identifier char
0N/Astatic
2693N/AcmsBool ismiddle(int c)
0N/A{
0N/A return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127));
0N/A}
0N/A
0N/A// Checks whatsever if c is a valid identifier middle char.
0N/Astatic
2693N/AcmsBool isidchar(int c)
0N/A{
0N/A return isalnum(c) || ismiddle(c);
0N/A}
0N/A
0N/A// Checks whatsever if c is a valid identifier first char.
0N/Astatic
2693N/AcmsBool isfirstidchar(int c)
0N/A{
0N/A return !isdigit(c) && ismiddle(c);
0N/A}
0N/A
2693N/A// Guess whether the supplied path looks like an absolute path
1002N/Astatic
2693N/AcmsBool isabsolutepath(const char *path)
1002N/A{
2693N/A char ThreeChars[4];
2693N/A
1002N/A if(path == NULL)
1002N/A return FALSE;
2693N/A if (path[0] == 0)
2693N/A return FALSE;
2693N/A
2693N/A strncpy(ThreeChars, path, 3);
2693N/A ThreeChars[3] = 0;
2693N/A
2693N/A if(ThreeChars[0] == DIR_CHAR)
1002N/A return TRUE;
1002N/A
2693N/A#ifdef CMS_IS_WINDOWS_
2693N/A if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':')
1002N/A return TRUE;
1002N/A#endif
1002N/A return FALSE;
1002N/A}
1002N/A
6271N/A
6271N/A
1002N/A// Makes a file path based on a given reference path
1002N/A// NOTE: this function doesn't check if the path exists or even if it's legal
1002N/Astatic
2693N/AcmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen)
1002N/A{
2693N/A char *tail;
2693N/A cmsUInt32Number len;
2693N/A
2693N/A // Already absolute?
2693N/A if (isabsolutepath(relPath)) {
2693N/A
2693N/A strncpy(buffer, relPath, MaxLen);
2693N/A buffer[MaxLen-1] = 0;
2693N/A return TRUE;
1002N/A }
2693N/A
2693N/A // No, search for last
2693N/A strncpy(buffer, basePath, MaxLen);
2693N/A buffer[MaxLen-1] = 0;
2693N/A
2693N/A tail = strrchr(buffer, DIR_CHAR);
2693N/A if (tail == NULL) return FALSE; // Is not absolute and has no separators??
2693N/A
2693N/A len = (cmsUInt32Number) (tail - buffer);
2693N/A if (len >= MaxLen) return FALSE;
2693N/A
2693N/A // No need to assure zero terminator over here
2693N/A strncpy(tail + 1, relPath, MaxLen - len);
2693N/A
1002N/A return TRUE;
1002N/A}
1002N/A
1002N/A
1002N/A// Make sure no exploit is being even tried
0N/Astatic
1002N/Aconst char* NoMeta(const char* str)
1002N/A{
1002N/A if (strchr(str, '%') != NULL)
1002N/A return "**** CORRUPTED FORMAT STRING ***";
1002N/A
1002N/A return str;
1002N/A}
1002N/A
1002N/A// Syntax error
1002N/Astatic
2693N/AcmsBool SynError(cmsIT8* it8, const char *Txt, ...)
0N/A{
2693N/A char Buffer[256], ErrMsg[1024];
2693N/A va_list args;
2693N/A
2693N/A va_start(args, Txt);
2693N/A vsnprintf(Buffer, 255, Txt, args);
2693N/A Buffer[255] = 0;
2693N/A va_end(args);
2693N/A
2693N/A snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer);
2693N/A ErrMsg[1023] = 0;
2693N/A it8->sy = SSYNERROR;
2693N/A cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg);
2693N/A return FALSE;
0N/A}
0N/A
1002N/A// Check if current symbol is same as specified. issue an error else.
0N/Astatic
2693N/AcmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err)
0N/A{
0N/A if (it8 -> sy != sy)
1002N/A return SynError(it8, NoMeta(Err));
0N/A return TRUE;
0N/A}
0N/A
0N/A// Read Next character from stream
0N/Astatic
2693N/Avoid NextCh(cmsIT8* it8)
0N/A{
1002N/A if (it8 -> FileStack[it8 ->IncludeSP]->Stream) {
1002N/A
1002N/A it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream);
1002N/A
1002N/A if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) {
0N/A
0N/A if (it8 ->IncludeSP > 0) {
0N/A
1002N/A fclose(it8 ->FileStack[it8->IncludeSP--]->Stream);
0N/A it8 -> ch = ' '; // Whitespace to be ignored
0N/A
0N/A } else
0N/A it8 ->ch = 0; // EOF
0N/A }
0N/A }
0N/A else {
0N/A it8->ch = *it8->Source;
0N/A if (it8->ch) it8->Source++;
0N/A }
0N/A}
0N/A
0N/A
0N/A// Try to see if current identifier is a keyword, if so return the referred symbol
0N/Astatic
0N/ASYMBOL BinSrchKey(const char *id)
0N/A{
2693N/A int l = 1;
2693N/A int r = NUMKEYS;
2693N/A int x, res;
2693N/A
2693N/A while (r >= l)
2693N/A {
2693N/A x = (l+r)/2;
2693N/A res = cmsstrcasecmp(id, TabKeys[x-1].id);
2693N/A if (res == 0) return TabKeys[x-1].sy;
2693N/A if (res < 0) r = x - 1;
2693N/A else l = x + 1;
2693N/A }
2693N/A
2693N/A return SNONE;
0N/A}
0N/A
0N/A
0N/A// 10 ^n
0N/Astatic
2693N/AcmsFloat64Number xpow10(int n)
0N/A{
2693N/A return pow(10, (cmsFloat64Number) n);
0N/A}
0N/A
0N/A
0N/A// Reads a Real number, tries to follow from integer number
0N/Astatic
2693N/Avoid ReadReal(cmsIT8* it8, int inum)
0N/A{
2693N/A it8->dnum = (cmsFloat64Number) inum;
2693N/A
2693N/A while (isdigit(it8->ch)) {
0N/A
0N/A it8->dnum = it8->dnum * 10.0 + (it8->ch - '0');
0N/A NextCh(it8);
2693N/A }
2693N/A
2693N/A if (it8->ch == '.') { // Decimal point
2693N/A
2693N/A cmsFloat64Number frac = 0.0; // fraction
6271N/A int prec = 0; // precision
2693N/A
2693N/A NextCh(it8); // Eats dec. point
2693N/A
2693N/A while (isdigit(it8->ch)) {
2693N/A
2693N/A frac = frac * 10.0 + (it8->ch - '0');
2693N/A prec++;
2693N/A NextCh(it8);
0N/A }
0N/A
2693N/A it8->dnum = it8->dnum + (frac / xpow10(prec));
2693N/A }
2693N/A
2693N/A // Exponent, example 34.00E+20
2693N/A if (toupper(it8->ch) == 'E') {
2693N/A
2693N/A int e;
2693N/A int sgn;
2693N/A
2693N/A NextCh(it8); sgn = 1;
2693N/A
2693N/A if (it8->ch == '-') {
2693N/A
2693N/A sgn = -1; NextCh(it8);
0N/A }
2693N/A else
2693N/A if (it8->ch == '+') {
2693N/A
2693N/A sgn = +1;
2693N/A NextCh(it8);
2693N/A }
2693N/A
2693N/A e = 0;
2693N/A while (isdigit(it8->ch)) {
2693N/A
2693N/A if ((cmsFloat64Number) e * 10L < INT_MAX)
2693N/A e = e * 10 + (it8->ch - '0');
2693N/A
2693N/A NextCh(it8);
2693N/A }
2693N/A
2693N/A e = sgn*e;
2693N/A it8 -> dnum = it8 -> dnum * xpow10(e);
2693N/A }
0N/A}
0N/A
6271N/A// Parses a float number
6271N/A// This can not call directly atof because it uses locale dependant
6271N/A// parsing, while CCMX files always use . as decimal separator
6271N/Astatic
6271N/AcmsFloat64Number ParseFloatNumber(const char *Buffer)
6271N/A{
6271N/A cmsFloat64Number dnum = 0.0;
6271N/A int sign = 1;
6271N/A
6271N/A if (*Buffer == '-' || *Buffer == '+') {
6271N/A
6271N/A sign = (*Buffer == '-') ? -1 : 1;
6271N/A Buffer++;
6271N/A }
6271N/A
6271N/A
6271N/A while (*Buffer && isdigit((int) *Buffer)) {
6271N/A
6271N/A dnum = dnum * 10.0 + (*Buffer - '0');
6271N/A if (*Buffer) Buffer++;
6271N/A }
6271N/A
6271N/A if (*Buffer == '.') {
6271N/A
6271N/A cmsFloat64Number frac = 0.0; // fraction
6271N/A int prec = 0; // precission
6271N/A
6271N/A if (*Buffer) Buffer++;
6271N/A
6271N/A while (*Buffer && isdigit((int) *Buffer)) {
6271N/A
6271N/A frac = frac * 10.0 + (*Buffer - '0');
6271N/A prec++;
6271N/A if (*Buffer) Buffer++;
6271N/A }
6271N/A
6271N/A dnum = dnum + (frac / xpow10(prec));
6271N/A }
6271N/A
6271N/A // Exponent, example 34.00E+20
6271N/A if (*Buffer && toupper(*Buffer) == 'E') {
6271N/A
6271N/A int e;
6271N/A int sgn;
6271N/A
6271N/A if (*Buffer) Buffer++;
6271N/A sgn = 1;
6271N/A
6271N/A if (*Buffer == '-') {
6271N/A
6271N/A sgn = -1;
6271N/A if (*Buffer) Buffer++;
6271N/A }
6271N/A else
6271N/A if (*Buffer == '+') {
6271N/A
6271N/A sgn = +1;
6271N/A if (*Buffer) Buffer++;
6271N/A }
6271N/A
6271N/A e = 0;
6271N/A while (*Buffer && isdigit((int) *Buffer)) {
6271N/A
6271N/A if ((cmsFloat64Number) e * 10L < INT_MAX)
6271N/A e = e * 10 + (*Buffer - '0');
6271N/A
6271N/A if (*Buffer) Buffer++;
6271N/A }
6271N/A
6271N/A e = sgn*e;
6271N/A dnum = dnum * xpow10(e);
6271N/A }
6271N/A
6271N/A return sign * dnum;
6271N/A}
0N/A
0N/A
0N/A// Reads next symbol
0N/Astatic
2693N/Avoid InSymbol(cmsIT8* it8)
0N/A{
0N/A register char *idptr;
0N/A register int k;
0N/A SYMBOL key;
0N/A int sng;
0N/A
0N/A do {
0N/A
0N/A while (isseparator(it8->ch))
0N/A NextCh(it8);
0N/A
0N/A if (isfirstidchar(it8->ch)) { // Identifier
0N/A
0N/A k = 0;
0N/A idptr = it8->id;
0N/A
0N/A do {
0N/A
0N/A if (++k < MAXID) *idptr++ = (char) it8->ch;
0N/A
0N/A NextCh(it8);
0N/A
0N/A } while (isidchar(it8->ch));
0N/A
0N/A *idptr = '\0';
0N/A
0N/A
0N/A key = BinSrchKey(it8->id);
0N/A if (key == SNONE) it8->sy = SIDENT;
0N/A else it8->sy = key;
0N/A
0N/A }
0N/A else // Is a number?
0N/A if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+')
0N/A {
0N/A int sign = 1;
0N/A
0N/A if (it8->ch == '-') {
0N/A sign = -1;
0N/A NextCh(it8);
0N/A }
0N/A
0N/A it8->inum = 0;
0N/A it8->sy = SINUM;
0N/A
0N/A if (it8->ch == '0') { // 0xnnnn (Hexa) or 0bnnnn (Binary)
0N/A
0N/A NextCh(it8);
0N/A if (toupper(it8->ch) == 'X') {
0N/A
0N/A int j;
0N/A
0N/A NextCh(it8);
0N/A while (isxdigit(it8->ch))
0N/A {
0N/A it8->ch = toupper(it8->ch);
0N/A if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10;
0N/A else j = it8->ch - '0';
0N/A
0N/A if ((long) it8->inum * 16L > (long) INT_MAX)
0N/A {
0N/A SynError(it8, "Invalid hexadecimal number");
0N/A return;
0N/A }
0N/A
0N/A it8->inum = it8->inum * 16 + j;
0N/A NextCh(it8);
0N/A }
0N/A return;
0N/A }
0N/A
0N/A if (toupper(it8->ch) == 'B') { // Binary
0N/A
0N/A int j;
0N/A
0N/A NextCh(it8);
0N/A while (it8->ch == '0' || it8->ch == '1')
0N/A {
0N/A j = it8->ch - '0';
0N/A
0N/A if ((long) it8->inum * 2L > (long) INT_MAX)
0N/A {
0N/A SynError(it8, "Invalid binary number");
0N/A return;
0N/A }
0N/A
0N/A it8->inum = it8->inum * 2 + j;
0N/A NextCh(it8);
0N/A }
0N/A return;
0N/A }
0N/A }
0N/A
0N/A
0N/A while (isdigit(it8->ch)) {
0N/A
0N/A if ((long) it8->inum * 10L > (long) INT_MAX) {
0N/A ReadReal(it8, it8->inum);
0N/A it8->sy = SDNUM;
0N/A it8->dnum *= sign;
0N/A return;
0N/A }
0N/A
0N/A it8->inum = it8->inum * 10 + (it8->ch - '0');
0N/A NextCh(it8);
0N/A }
0N/A
0N/A if (it8->ch == '.') {
0N/A
0N/A ReadReal(it8, it8->inum);
0N/A it8->sy = SDNUM;
0N/A it8->dnum *= sign;
0N/A return;
0N/A }
0N/A
0N/A it8 -> inum *= sign;
0N/A
0N/A // Special case. Numbers followed by letters are taken as identifiers
0N/A
0N/A if (isidchar(it8 ->ch)) {
0N/A
0N/A if (it8 ->sy == SINUM) {
0N/A
0N/A sprintf(it8->id, "%d", it8->inum);
0N/A }
0N/A else {
0N/A
0N/A sprintf(it8->id, it8 ->DoubleFormatter, it8->dnum);
0N/A }
0N/A
0N/A k = (int) strlen(it8 ->id);
0N/A idptr = it8 ->id + k;
0N/A do {
0N/A
0N/A if (++k < MAXID) *idptr++ = (char) it8->ch;
0N/A
0N/A NextCh(it8);
0N/A
0N/A } while (isidchar(it8->ch));
0N/A
0N/A *idptr = '\0';
0N/A it8->sy = SIDENT;
0N/A }
0N/A return;
0N/A
0N/A }
0N/A else
0N/A switch ((int) it8->ch) {
0N/A
0N/A // EOF marker -- ignore it
0N/A case '\x1a':
0N/A NextCh(it8);
0N/A break;
0N/A
0N/A // Eof stream markers
0N/A case 0:
0N/A case -1:
0N/A it8->sy = SEOF;
0N/A break;
0N/A
0N/A
0N/A // Next line
0N/A case '\n':
0N/A NextCh(it8);
0N/A it8->sy = SEOLN;
0N/A it8->lineno++;
0N/A break;
0N/A
0N/A // Comment
0N/A case '#':
0N/A NextCh(it8);
0N/A while (it8->ch && it8->ch != '\n')
0N/A NextCh(it8);
0N/A
0N/A it8->sy = SCOMMENT;
0N/A break;
0N/A
2693N/A // String.
0N/A case '\'':
0N/A case '\"':
0N/A idptr = it8->str;
0N/A sng = it8->ch;
0N/A k = 0;
0N/A NextCh(it8);
0N/A
0N/A while (k < MAXSTR && it8->ch != sng) {
0N/A
0N/A if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1;
0N/A else {
0N/A *idptr++ = (char) it8->ch;
0N/A NextCh(it8);
0N/A k++;
0N/A }
0N/A }
0N/A
0N/A it8->sy = SSTRING;
0N/A *idptr = '\0';
0N/A NextCh(it8);
0N/A break;
0N/A
0N/A
0N/A default:
0N/A SynError(it8, "Unrecognized character: 0x%x", it8 ->ch);
0N/A return;
0N/A }
0N/A
0N/A } while (it8->sy == SCOMMENT);
0N/A
0N/A // Handle the include special token
0N/A
0N/A if (it8 -> sy == SINCLUDE) {
0N/A
2693N/A FILECTX* FileNest;
2693N/A
2693N/A if(it8 -> IncludeSP >= (MAXINCLUDE-1)) {
2693N/A
1002N/A SynError(it8, "Too many recursion levels");
1002N/A return;
1002N/A }
0N/A
0N/A InSymbol(it8);
0N/A if (!Check(it8, SSTRING, "Filename expected")) return;
1002N/A
1002N/A FileNest = it8 -> FileStack[it8 -> IncludeSP + 1];
2693N/A if(FileNest == NULL) {
2693N/A
2693N/A FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
1002N/A //if(FileNest == NULL)
2693N/A // TODO: how to manage out-of-memory conditions?
1002N/A }
1002N/A
2693N/A if (BuildAbsolutePath(it8->str,
2693N/A it8->FileStack[it8->IncludeSP]->FileName,
2693N/A FileNest->FileName, cmsMAX_PATH-1) == FALSE) {
1002N/A SynError(it8, "File path too long");
1002N/A return;
1002N/A }
1002N/A
1002N/A FileNest->Stream = fopen(FileNest->FileName, "rt");
1002N/A if (FileNest->Stream == NULL) {
1002N/A
1002N/A SynError(it8, "File %s not found", FileNest->FileName);
0N/A return;
0N/A }
1002N/A it8->IncludeSP++;
1002N/A
0N/A it8 ->ch = ' ';
0N/A InSymbol(it8);
0N/A }
0N/A
0N/A}
0N/A
0N/A// Checks end of line separator
0N/Astatic
2693N/AcmsBool CheckEOLN(cmsIT8* it8)
0N/A{
0N/A if (!Check(it8, SEOLN, "Expected separator")) return FALSE;
0N/A while (it8 -> sy == SEOLN)
0N/A InSymbol(it8);
0N/A return TRUE;
0N/A
0N/A}
0N/A
0N/A// Skip a symbol
0N/A
0N/Astatic
2693N/Avoid Skip(cmsIT8* it8, SYMBOL sy)
0N/A{
0N/A if (it8->sy == sy && it8->sy != SEOF)
0N/A InSymbol(it8);
0N/A}
0N/A
0N/A
0N/A// Skip multiple EOLN
0N/Astatic
2693N/Avoid SkipEOLN(cmsIT8* it8)
0N/A{
0N/A while (it8->sy == SEOLN) {
0N/A InSymbol(it8);
0N/A }
0N/A}
0N/A
0N/A
0N/A// Returns a string holding current value
0N/Astatic
2693N/AcmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle)
0N/A{
0N/A switch (it8->sy) {
0N/A
1002N/A case SIDENT: strncpy(Buffer, it8->id, max);
1002N/A Buffer[max-1]=0;
1002N/A break;
1002N/A case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break;
1002N/A case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break;
1002N/A case SSTRING: strncpy(Buffer, it8->str, max);
1002N/A Buffer[max-1] = 0;
1002N/A break;
0N/A
0N/A
0N/A default:
1002N/A return SynError(it8, "%s", ErrorTitle);
0N/A }
0N/A
1002N/A Buffer[max] = 0;
1002N/A return TRUE;
0N/A}
0N/A
0N/A// ---------------------------------------------------------- Table
0N/A
0N/Astatic
2693N/ATABLE* GetTable(cmsIT8* it8)
0N/A{
2693N/A if ((it8 -> nTable >= it8 ->TablesCount)) {
1002N/A
1002N/A SynError(it8, "Table %d out of sequence", it8 -> nTable);
1002N/A return it8 -> Tab;
1002N/A }
1002N/A
1002N/A return it8 ->Tab + it8 ->nTable;
0N/A}
0N/A
0N/A// ---------------------------------------------------------- Memory management
0N/A
0N/A
0N/A// Frees an allocator and owned memory
2693N/Avoid CMSEXPORT cmsIT8Free(cmsHANDLE hIT8)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A
0N/A if (it8 == NULL)
0N/A return;
0N/A
0N/A if (it8->MemorySink) {
0N/A
2693N/A OWNEDMEM* p;
2693N/A OWNEDMEM* n;
0N/A
0N/A for (p = it8->MemorySink; p != NULL; p = n) {
0N/A
0N/A n = p->Next;
2693N/A if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr);
2693N/A _cmsFree(it8 ->ContextID, p);
0N/A }
0N/A }
0N/A
0N/A if (it8->MemoryBlock)
2693N/A _cmsFree(it8 ->ContextID, it8->MemoryBlock);
2693N/A
2693N/A _cmsFree(it8 ->ContextID, it8);
0N/A}
0N/A
0N/A
0N/A// Allocates a chunk of data, keep linked list
0N/Astatic
2693N/Avoid* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size)
0N/A{
2693N/A OWNEDMEM* ptr1;
2693N/A void* ptr = _cmsMallocZero(it8->ContextID, size);
2693N/A
2693N/A if (ptr != NULL) {
2693N/A
2693N/A ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM));
2693N/A
2693N/A if (ptr1 == NULL) {
2693N/A
2693N/A _cmsFree(it8 ->ContextID, ptr);
2693N/A return NULL;
0N/A }
0N/A
2693N/A ptr1-> Ptr = ptr;
2693N/A ptr1-> Next = it8 -> MemorySink;
2693N/A it8 -> MemorySink = ptr1;
2693N/A }
2693N/A
2693N/A return ptr;
0N/A}
0N/A
0N/A
0N/A// Suballocator.
0N/Astatic
2693N/Avoid* AllocChunk(cmsIT8* it8, cmsUInt32Number size)
0N/A{
2693N/A cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used;
2693N/A cmsUInt8Number* ptr;
2693N/A
6271N/A size = _cmsALIGNMEM(size);
2693N/A
2693N/A if (size > Free) {
0N/A
0N/A if (it8 -> Allocator.BlockSize == 0)
0N/A
0N/A it8 -> Allocator.BlockSize = 20*1024;
0N/A else
0N/A it8 ->Allocator.BlockSize *= 2;
0N/A
0N/A if (it8 ->Allocator.BlockSize < size)
0N/A it8 ->Allocator.BlockSize = size;
0N/A
0N/A it8 ->Allocator.Used = 0;
2693N/A it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize);
0N/A }
0N/A
0N/A ptr = it8 ->Allocator.Block + it8 ->Allocator.Used;
0N/A it8 ->Allocator.Used += size;
0N/A
0N/A return (void*) ptr;
0N/A
0N/A}
0N/A
0N/A
0N/A// Allocates a string
0N/Astatic
2693N/Achar *AllocString(cmsIT8* it8, const char* str)
0N/A{
2693N/A cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1;
0N/A char *ptr;
0N/A
0N/A
0N/A ptr = (char *) AllocChunk(it8, Size);
0N/A if (ptr) strncpy (ptr, str, Size-1);
0N/A
0N/A return ptr;
0N/A}
0N/A
0N/A// Searches through linked list
0N/A
0N/Astatic
2693N/AcmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr)
0N/A{
1002N/A if (LastPtr) *LastPtr = p;
0N/A
0N/A for (; p != NULL; p = p->Next) {
0N/A
0N/A if (LastPtr) *LastPtr = p;
0N/A
0N/A if (*Key != '#') { // Comments are ignored
0N/A
2693N/A if (cmsstrcasecmp(Key, p->Keyword) == 0)
1002N/A break;
1002N/A }
0N/A }
1002N/A
1002N/A if (p == NULL)
1002N/A return FALSE;
1002N/A
1002N/A if (Subkey == 0)
1002N/A return TRUE;
1002N/A
1002N/A for (; p != NULL; p = p->NextSubkey) {
1002N/A
1002N/A if (LastPtr) *LastPtr = p;
1002N/A
2693N/A if (cmsstrcasecmp(Subkey, p->Subkey) == 0)
2693N/A return TRUE;
2693N/A }
0N/A
0N/A return FALSE;
0N/A}
0N/A
0N/A
0N/A
0N/A// Add a property into a linked list
0N/Astatic
2693N/AKEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
0N/A{
2693N/A KEYVALUE* p;
2693N/A KEYVALUE* last;
2693N/A
2693N/A
2693N/A // Check if property is already in list
0N/A
1002N/A if (IsAvailableOnList(*Head, Key, Subkey, &p)) {
1002N/A
2693N/A // This may work for editing properties
1002N/A
1002N/A // return SynError(it8, "duplicate key <%s>", Key);
0N/A }
1002N/A else {
2693N/A
2693N/A last = p;
2693N/A
2693N/A // Allocate the container
2693N/A p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE));
2693N/A if (p == NULL)
2693N/A {
1002N/A SynError(it8, "AddToList: out of memory");
1002N/A return NULL;
2693N/A }
2693N/A
2693N/A // Store name and value
2693N/A p->Keyword = AllocString(it8, Key);
1002N/A p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
1002N/A
1002N/A // Keep the container in our list
2693N/A if (*Head == NULL) {
1002N/A *Head = p;
2693N/A }
1002N/A else
1002N/A {
2693N/A if (Subkey != NULL && last != NULL) {
2693N/A
1002N/A last->NextSubkey = p;
1002N/A
1002N/A // If Subkey is not null, then last is the last property with the same key,
1002N/A // but not necessarily is the last property in the list, so we need to move
1002N/A // to the actual list end
2693N/A while (last->Next != NULL)
2693N/A last = last->Next;
2693N/A }
2693N/A
2693N/A if (last != NULL) last->Next = p;
2693N/A }
2693N/A
2693N/A p->Next = NULL;
1002N/A p->NextSubkey = NULL;
1002N/A }
1002N/A
1002N/A p->WriteAs = WriteAs;
2693N/A
0N/A if (xValue != NULL) {
0N/A
0N/A p->Value = AllocString(it8, xValue);
0N/A }
0N/A else {
0N/A p->Value = NULL;
0N/A }
0N/A
1002N/A return p;
0N/A}
0N/A
0N/Astatic
2693N/AKEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as)
0N/A{
2693N/A return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as);
0N/A}
0N/A
0N/A
0N/Astatic
2693N/AKEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key)
0N/A{
2693N/A return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED);
0N/A}
0N/A
0N/A
0N/Astatic
2693N/Avoid AllocTable(cmsIT8* it8)
0N/A{
2693N/A TABLE* t;
0N/A
0N/A t = it8 ->Tab + it8 ->TablesCount;
0N/A
0N/A t->HeaderList = NULL;
0N/A t->DataFormat = NULL;
0N/A t->Data = NULL;
0N/A
0N/A it8 ->TablesCount++;
0N/A}
0N/A
0N/A
2693N/AcmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) IT8;
0N/A
0N/A if (nTable >= it8 ->TablesCount) {
0N/A
0N/A if (nTable == it8 ->TablesCount) {
0N/A
0N/A AllocTable(it8);
0N/A }
0N/A else {
0N/A SynError(it8, "Table %d is out of sequence", nTable);
0N/A return -1;
0N/A }
0N/A }
0N/A
0N/A it8 ->nTable = nTable;
0N/A
0N/A return nTable;
0N/A}
0N/A
0N/A
0N/A
0N/A// Init an empty container
2693N/AcmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
0N/A{
2693N/A cmsIT8* it8;
6271N/A cmsUInt32Number i;
0N/A
2693N/A it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8));
0N/A if (it8 == NULL) return NULL;
0N/A
0N/A AllocTable(it8);
0N/A
0N/A it8->MemoryBlock = NULL;
0N/A it8->MemorySink = NULL;
0N/A
0N/A it8 ->nTable = 0;
0N/A
2693N/A it8->ContextID = ContextID;
0N/A it8->Allocator.Used = 0;
0N/A it8->Allocator.Block = NULL;
0N/A it8->Allocator.BlockSize = 0;
0N/A
0N/A it8->ValidKeywords = NULL;
0N/A it8->ValidSampleID = NULL;
0N/A
0N/A it8 -> sy = SNONE;
0N/A it8 -> ch = ' ';
0N/A it8 -> Source = NULL;
0N/A it8 -> inum = 0;
0N/A it8 -> dnum = 0.0;
0N/A
2693N/A it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
1002N/A it8->IncludeSP = 0;
0N/A it8 -> lineno = 1;
0N/A
0N/A strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
6271N/A cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17");
0N/A
0N/A // Initialize predefined properties & data
0N/A
0N/A for (i=0; i < NUMPREDEFINEDPROPS; i++)
1002N/A AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as);
0N/A
0N/A for (i=0; i < NUMPREDEFINEDSAMPLEID; i++)
0N/A AddAvailableSampleID(it8, PredefinedSampleID[i]);
0N/A
0N/A
2693N/A return (cmsHANDLE) it8;
0N/A}
0N/A
0N/A
2693N/Aconst char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8)
0N/A{
6271N/A return GetTable((cmsIT8*) hIT8)->SheetType;
0N/A}
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type)
0N/A{
6271N/A TABLE* t = GetTable((cmsIT8*) hIT8);
6271N/A
6271N/A strncpy(t ->SheetType, Type, MAXSTR-1);
6271N/A t ->SheetType[MAXSTR-1] = 0;
0N/A return TRUE;
0N/A}
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A
0N/A if (!Val) return FALSE;
0N/A if (!*Val) return FALSE;
0N/A
1002N/A return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL;
0N/A}
0N/A
0N/A// Sets a property
2693N/AcmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A
0N/A if (!Val) return FALSE;
0N/A if (!*Val) return FALSE;
0N/A
1002N/A return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL;
0N/A}
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A char Buffer[1024];
0N/A
0N/A sprintf(Buffer, it8->DoubleFormatter, Val);
0N/A
1002N/A return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL;
0N/A}
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A char Buffer[1024];
0N/A
0N/A sprintf(Buffer, "%d", Val);
0N/A
1002N/A return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL;
0N/A}
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A
1002N/A return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL;
0N/A}
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer)
1002N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
1002N/A
1002N/A return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL;
1002N/A}
0N/A
0N/A// Gets a property
2693N/Aconst char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A KEYVALUE* p;
0N/A
1002N/A if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p))
0N/A {
0N/A return p -> Value;
0N/A }
0N/A return NULL;
0N/A}
0N/A
0N/A
2693N/AcmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp)
0N/A{
0N/A const char *v = cmsIT8GetProperty(hIT8, cProp);
0N/A
6271N/A return ParseFloatNumber(v);
0N/A}
0N/A
2693N/Aconst char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey)
1002N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A KEYVALUE* p;
2693N/A
2693N/A if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) {
1002N/A return p -> Value;
1002N/A }
1002N/A return NULL;
1002N/A}
1002N/A
0N/A// ----------------------------------------------------------------- Datasets
0N/A
0N/A
0N/Astatic
2693N/Avoid AllocateDataFormat(cmsIT8* it8)
0N/A{
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A if (t -> DataFormat) return; // Already allocated
0N/A
0N/A t -> nSamples = (int) cmsIT8GetPropertyDbl(it8, "NUMBER_OF_FIELDS");
0N/A
0N/A if (t -> nSamples <= 0) {
0N/A
0N/A SynError(it8, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS");
0N/A t -> nSamples = 10;
0N/A }
0N/A
0N/A t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *));
2693N/A if (t->DataFormat == NULL) {
2693N/A
0N/A SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array");
0N/A }
0N/A
0N/A}
0N/A
0N/Astatic
2693N/Aconst char *GetDataFormat(cmsIT8* it8, int n)
0N/A{
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A if (t->DataFormat)
0N/A return t->DataFormat[n];
0N/A
0N/A return NULL;
0N/A}
0N/A
0N/Astatic
2693N/AcmsBool SetDataFormat(cmsIT8* it8, int n, const char *label)
0N/A{
2693N/A TABLE* t = GetTable(it8);
1002N/A
0N/A if (!t->DataFormat)
0N/A AllocateDataFormat(it8);
0N/A
0N/A if (n > t -> nSamples) {
0N/A SynError(it8, "More than NUMBER_OF_FIELDS fields.");
0N/A return FALSE;
0N/A }
0N/A
0N/A if (t->DataFormat) {
0N/A t->DataFormat[n] = AllocString(it8, label);
0N/A }
0N/A
0N/A return TRUE;
0N/A}
0N/A
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) h;
0N/A return SetDataFormat(it8, n, Sample);
0N/A}
0N/A
0N/Astatic
2693N/Avoid AllocateDataSet(cmsIT8* it8)
0N/A{
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A if (t -> Data) return; // Already allocated
0N/A
0N/A t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
0N/A t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
0N/A
0N/A t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*));
2693N/A if (t->Data == NULL) {
2693N/A
0N/A SynError(it8, "AllocateDataSet: Unable to allocate data array");
0N/A }
0N/A
0N/A}
0N/A
0N/Astatic
2693N/Achar* GetData(cmsIT8* it8, int nSet, int nField)
0N/A{
2693N/A TABLE* t = GetTable(it8);
0N/A int nSamples = t -> nSamples;
0N/A int nPatches = t -> nPatches;
0N/A
0N/A if (nSet >= nPatches || nField >= nSamples)
0N/A return NULL;
0N/A
0N/A if (!t->Data) return NULL;
0N/A return t->Data [nSet * nSamples + nField];
0N/A}
0N/A
0N/Astatic
2693N/AcmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val)
0N/A{
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A if (!t->Data)
0N/A AllocateDataSet(it8);
0N/A
0N/A if (!t->Data) return FALSE;
0N/A
0N/A if (nSet > t -> nPatches || nSet < 0) {
0N/A
0N/A return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches);
0N/A }
0N/A
0N/A if (nField > t ->nSamples || nField < 0) {
0N/A return SynError(it8, "Sample %d out of range, there are %d samples", nField, t ->nSamples);
0N/A
0N/A }
0N/A
0N/A t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val);
0N/A return TRUE;
0N/A}
0N/A
0N/A
0N/A// --------------------------------------------------------------- File I/O
0N/A
0N/A
0N/A// Writes a string to file
0N/Astatic
2693N/Avoid WriteStr(SAVESTREAM* f, const char *str)
0N/A{
2693N/A cmsUInt32Number len;
1002N/A
1002N/A if (str == NULL)
1002N/A str = " ";
1002N/A
1002N/A // Lenghth to write
2693N/A len = (cmsUInt32Number) strlen(str);
0N/A f ->Used += len;
0N/A
0N/A
1002N/A if (f ->stream) { // Should I write it to a file?
1002N/A
2693N/A if (fwrite(str, 1, len, f->stream) != len) {
2693N/A cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser");
2693N/A return;
2693N/A }
1002N/A
1002N/A }
1002N/A else { // Or to a memory block?
1002N/A
1002N/A if (f ->Base) { // Am I just counting the bytes?
1002N/A
1002N/A if (f ->Used > f ->Max) {
1002N/A
2693N/A cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser");
2693N/A return;
1002N/A }
1002N/A
2693N/A memmove(f ->Ptr, str, len);
1002N/A f->Ptr += len;
0N/A }
1002N/A
1002N/A }
0N/A}
0N/A
0N/A
1002N/A// Write formatted
1002N/A
0N/Astatic
2693N/Avoid Writef(SAVESTREAM* f, const char* frm, ...)
0N/A{
0N/A char Buffer[4096];
0N/A va_list args;
0N/A
0N/A va_start(args, frm);
1002N/A vsnprintf(Buffer, 4095, frm, args);
1002N/A Buffer[4095] = 0;
0N/A WriteStr(f, Buffer);
0N/A va_end(args);
0N/A
0N/A}
0N/A
0N/A// Writes full header
0N/Astatic
2693N/Avoid WriteHeader(cmsIT8* it8, SAVESTREAM* fp)
0N/A{
2693N/A KEYVALUE* p;
2693N/A TABLE* t = GetTable(it8);
0N/A
6271N/A // Writes the type
6271N/A WriteStr(fp, t->SheetType);
6271N/A WriteStr(fp, "\n");
0N/A
0N/A for (p = t->HeaderList; (p != NULL); p = p->Next)
0N/A {
0N/A if (*p ->Keyword == '#') {
0N/A
0N/A char* Pt;
0N/A
0N/A WriteStr(fp, "#\n# ");
0N/A for (Pt = p ->Value; *Pt; Pt++) {
0N/A
0N/A
1002N/A Writef(fp, "%c", *Pt);
0N/A
0N/A if (*Pt == '\n') {
0N/A WriteStr(fp, "# ");
0N/A }
0N/A }
0N/A
0N/A WriteStr(fp, "\n#\n");
0N/A continue;
0N/A }
0N/A
0N/A
1002N/A if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) {
0N/A
2693N/A#ifdef CMS_STRICT_CGATS
0N/A WriteStr(fp, "KEYWORD\t\"");
0N/A WriteStr(fp, p->Keyword);
0N/A WriteStr(fp, "\"\n");
0N/A#endif
0N/A
1002N/A AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED);
0N/A }
0N/A
0N/A WriteStr(fp, p->Keyword);
0N/A if (p->Value) {
0N/A
0N/A switch (p ->WriteAs) {
0N/A
0N/A case WRITE_UNCOOKED:
0N/A Writef(fp, "\t%s", p ->Value);
0N/A break;
0N/A
0N/A case WRITE_STRINGIFY:
0N/A Writef(fp, "\t\"%s\"", p->Value );
0N/A break;
0N/A
0N/A case WRITE_HEXADECIMAL:
0N/A Writef(fp, "\t0x%X", atoi(p ->Value));
0N/A break;
0N/A
0N/A case WRITE_BINARY:
0N/A Writef(fp, "\t0x%B", atoi(p ->Value));
0N/A break;
0N/A
1002N/A case WRITE_PAIR:
1002N/A Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value);
1002N/A break;
1002N/A
0N/A default: SynError(it8, "Unknown write mode %d", p ->WriteAs);
0N/A return;
0N/A }
0N/A }
0N/A
0N/A WriteStr (fp, "\n");
0N/A }
0N/A
0N/A}
0N/A
0N/A
0N/A// Writes the data format
0N/Astatic
2693N/Avoid WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
0N/A{
0N/A int i, nSamples;
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A if (!t -> DataFormat) return;
0N/A
0N/A WriteStr(fp, "BEGIN_DATA_FORMAT\n");
0N/A WriteStr(fp, " ");
0N/A nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
0N/A
0N/A for (i = 0; i < nSamples; i++) {
0N/A
0N/A WriteStr(fp, t->DataFormat[i]);
0N/A WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t"));
0N/A }
0N/A
0N/A WriteStr (fp, "END_DATA_FORMAT\n");
0N/A}
0N/A
0N/A
0N/A// Writes data array
0N/Astatic
2693N/Avoid WriteData(SAVESTREAM* fp, cmsIT8* it8)
0N/A{
0N/A int i, j;
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A if (!t->Data) return;
0N/A
0N/A WriteStr (fp, "BEGIN_DATA\n");
0N/A
0N/A t->nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
0N/A
0N/A for (i = 0; i < t-> nPatches; i++) {
0N/A
0N/A WriteStr(fp, " ");
0N/A
0N/A for (j = 0; j < t->nSamples; j++) {
0N/A
0N/A char *ptr = t->Data[i*t->nSamples+j];
0N/A
0N/A if (ptr == NULL) WriteStr(fp, "\"\"");
0N/A else {
0N/A // If value contains whitespace, enclose within quote
0N/A
0N/A if (strchr(ptr, ' ') != NULL) {
0N/A
0N/A WriteStr(fp, "\"");
0N/A WriteStr(fp, ptr);
0N/A WriteStr(fp, "\"");
0N/A }
0N/A else
0N/A WriteStr(fp, ptr);
0N/A }
0N/A
0N/A WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t"));
0N/A }
0N/A }
0N/A WriteStr (fp, "END_DATA\n");
0N/A}
0N/A
0N/A
0N/A
0N/A// Saves whole file
2693N/AcmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
0N/A{
0N/A SAVESTREAM sd;
2693N/A cmsUInt32Number i;
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A memset(&sd, 0, sizeof(sd));
0N/A
0N/A sd.stream = fopen(cFileName, "wt");
0N/A if (!sd.stream) return FALSE;
0N/A
0N/A for (i=0; i < it8 ->TablesCount; i++) {
0N/A
0N/A cmsIT8SetTable(hIT8, i);
0N/A WriteHeader(it8, &sd);
0N/A WriteDataFormat(&sd, it8);
0N/A WriteData(&sd, it8);
0N/A }
0N/A
2693N/A if (fclose(sd.stream) != 0) return FALSE;
0N/A
0N/A return TRUE;
0N/A}
0N/A
0N/A
0N/A// Saves to memory
2693N/AcmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded)
0N/A{
0N/A SAVESTREAM sd;
2693N/A cmsUInt32Number i;
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A memset(&sd, 0, sizeof(sd));
0N/A
0N/A sd.stream = NULL;
2693N/A sd.Base = (cmsUInt8Number*) MemPtr;
1002N/A sd.Ptr = sd.Base;
1002N/A
1002N/A sd.Used = 0;
1002N/A
1002N/A if (sd.Base)
1002N/A sd.Max = *BytesNeeded; // Write to memory?
1002N/A else
1002N/A sd.Max = 0; // Just counting the needed bytes
0N/A
0N/A for (i=0; i < it8 ->TablesCount; i++) {
0N/A
6271N/A cmsIT8SetTable(hIT8, i);
6271N/A WriteHeader(it8, &sd);
6271N/A WriteDataFormat(&sd, it8);
6271N/A WriteData(&sd, it8);
0N/A }
0N/A
1002N/A sd.Used++; // The \0 at the very end
1002N/A
1002N/A if (sd.Base)
6271N/A *sd.Ptr = 0;
1002N/A
1002N/A *BytesNeeded = sd.Used;
0N/A
0N/A return TRUE;
0N/A}
0N/A
0N/A
0N/A// -------------------------------------------------------------- Higer level parsing
0N/A
0N/Astatic
2693N/AcmsBool DataFormatSection(cmsIT8* it8)
0N/A{
0N/A int iField = 0;
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A InSymbol(it8); // Eats "BEGIN_DATA_FORMAT"
0N/A CheckEOLN(it8);
0N/A
0N/A while (it8->sy != SEND_DATA_FORMAT &&
0N/A it8->sy != SEOLN &&
0N/A it8->sy != SEOF &&
0N/A it8->sy != SSYNERROR) {
0N/A
0N/A if (it8->sy != SIDENT) {
0N/A
0N/A return SynError(it8, "Sample type expected");
0N/A }
0N/A
0N/A if (!SetDataFormat(it8, iField, it8->id)) return FALSE;
0N/A iField++;
0N/A
0N/A InSymbol(it8);
0N/A SkipEOLN(it8);
0N/A }
0N/A
0N/A SkipEOLN(it8);
0N/A Skip(it8, SEND_DATA_FORMAT);
0N/A SkipEOLN(it8);
0N/A
0N/A if (iField != t ->nSamples) {
0N/A SynError(it8, "Count mismatch. NUMBER_OF_FIELDS was %d, found %d\n", t ->nSamples, iField);
0N/A
0N/A
0N/A }
0N/A
0N/A return TRUE;
0N/A}
0N/A
0N/A
0N/A
0N/Astatic
2693N/AcmsBool DataSection (cmsIT8* it8)
0N/A{
0N/A int iField = 0;
0N/A int iSet = 0;
2693N/A char Buffer[256];
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A InSymbol(it8); // Eats "BEGIN_DATA"
0N/A CheckEOLN(it8);
0N/A
1002N/A if (!t->Data)
1002N/A AllocateDataSet(it8);
1002N/A
0N/A while (it8->sy != SEND_DATA && it8->sy != SEOF)
0N/A {
0N/A if (iField >= t -> nSamples) {
0N/A iField = 0;
0N/A iSet++;
0N/A
0N/A }
0N/A
0N/A if (it8->sy != SEND_DATA && it8->sy != SEOF) {
0N/A
1002N/A if (!GetVal(it8, Buffer, 255, "Sample data expected"))
0N/A return FALSE;
0N/A
0N/A if (!SetData(it8, iSet, iField, Buffer))
0N/A return FALSE;
0N/A
0N/A iField++;
0N/A
0N/A InSymbol(it8);
0N/A SkipEOLN(it8);
0N/A }
0N/A }
0N/A
0N/A SkipEOLN(it8);
0N/A Skip(it8, SEND_DATA);
0N/A SkipEOLN(it8);
0N/A
0N/A // Check for data completion.
0N/A
0N/A if ((iSet+1) != t -> nPatches)
0N/A return SynError(it8, "Count mismatch. NUMBER_OF_SETS was %d, found %d\n", t ->nPatches, iSet+1);
0N/A
0N/A return TRUE;
0N/A}
0N/A
0N/A
0N/A
0N/A
0N/Astatic
2693N/AcmsBool HeaderSection(cmsIT8* it8)
0N/A{
0N/A char VarName[MAXID];
0N/A char Buffer[MAXSTR];
2693N/A KEYVALUE* Key;
0N/A
0N/A while (it8->sy != SEOF &&
0N/A it8->sy != SSYNERROR &&
0N/A it8->sy != SBEGIN_DATA_FORMAT &&
0N/A it8->sy != SBEGIN_DATA) {
0N/A
0N/A
0N/A switch (it8 -> sy) {
0N/A
0N/A case SKEYWORD:
0N/A InSymbol(it8);
1002N/A if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE;
1002N/A if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE;
1002N/A InSymbol(it8);
1002N/A break;
1002N/A
1002N/A
1002N/A case SDATA_FORMAT_ID:
1002N/A InSymbol(it8);
1002N/A if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE;
1002N/A if (!AddAvailableSampleID(it8, Buffer)) return FALSE;
0N/A InSymbol(it8);
0N/A break;
0N/A
0N/A
0N/A case SIDENT:
0N/A strncpy(VarName, it8->id, MAXID-1);
1002N/A VarName[MAXID-1] = 0;
1002N/A
1002N/A if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) {
0N/A
2693N/A#ifdef CMS_STRICT_CGATS
0N/A return SynError(it8, "Undefined keyword '%s'", VarName);
0N/A#else
1002N/A Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED);
1002N/A if (Key == NULL) return FALSE;
0N/A#endif
0N/A }
0N/A
0N/A InSymbol(it8);
1002N/A if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE;
1002N/A
1002N/A if(Key->WriteAs != WRITE_PAIR) {
1002N/A AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer,
1002N/A (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED);
1002N/A }
1002N/A else {
1002N/A const char *Subkey;
1002N/A char *Nextkey;
1002N/A if (it8->sy != SSTRING)
1002N/A return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
1002N/A
1002N/A // chop the string as a list of "subkey, value" pairs, using ';' as a separator
2693N/A for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
1002N/A {
1002N/A char *Value, *temp;
1002N/A
1002N/A // identify token pair boundary
1002N/A Nextkey = (char*) strchr(Subkey, ';');
1002N/A if(Nextkey)
1002N/A *Nextkey++ = '\0';
1002N/A
1002N/A // for each pair, split the subkey and the value
1002N/A Value = (char*) strrchr(Subkey, ',');
1002N/A if(Value == NULL)
1002N/A return SynError(it8, "Invalid value for property '%s'.", VarName);
1002N/A
1002N/A // gobble the spaces before the coma, and the coma itself
1002N/A temp = Value++;
1002N/A do *temp-- = '\0'; while(temp >= Subkey && *temp == ' ');
1002N/A
1002N/A // gobble any space at the right
1002N/A temp = Value + strlen(Value) - 1;
1002N/A while(*temp == ' ') *temp-- = '\0';
1002N/A
1002N/A // trim the strings from the left
1002N/A Subkey += strspn(Subkey, " ");
1002N/A Value += strspn(Value, " ");
1002N/A
1002N/A if(Subkey[0] == 0 || Value[0] == 0)
1002N/A return SynError(it8, "Invalid value for property '%s'.", VarName);
1002N/A AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR);
1002N/A }
1002N/A }
0N/A
0N/A InSymbol(it8);
0N/A break;
0N/A
0N/A
0N/A case SEOLN: break;
0N/A
0N/A default:
0N/A return SynError(it8, "expected keyword or identifier");
0N/A }
0N/A
0N/A SkipEOLN(it8);
0N/A }
0N/A
0N/A return TRUE;
0N/A
0N/A}
0N/A
0N/A
0N/Astatic
6271N/Avoid ReadType(cmsIT8* it8, char* SheetTypePtr)
0N/A{
0N/A // First line is a very special case.
0N/A
0N/A while (isseparator(it8->ch))
0N/A NextCh(it8);
0N/A
0N/A while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) {
0N/A
0N/A *SheetTypePtr++= (char) it8 ->ch;
0N/A NextCh(it8);
0N/A }
0N/A
0N/A *SheetTypePtr = 0;
6271N/A}
6271N/A
6271N/A
6271N/Astatic
6271N/AcmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet)
6271N/A{
6271N/A char* SheetTypePtr = it8 ->Tab[0].SheetType;
6271N/A
6271N/A if (nosheet == 0) {
6271N/A ReadType(it8, SheetTypePtr);
6271N/A }
6271N/A
0N/A InSymbol(it8);
0N/A
0N/A SkipEOLN(it8);
0N/A
0N/A while (it8-> sy != SEOF &&
0N/A it8-> sy != SSYNERROR) {
0N/A
0N/A switch (it8 -> sy) {
0N/A
0N/A case SBEGIN_DATA_FORMAT:
0N/A if (!DataFormatSection(it8)) return FALSE;
0N/A break;
0N/A
0N/A case SBEGIN_DATA:
0N/A
0N/A if (!DataSection(it8)) return FALSE;
0N/A
0N/A if (it8 -> sy != SEOF) {
0N/A
0N/A AllocTable(it8);
0N/A it8 ->nTable = it8 ->TablesCount - 1;
6271N/A
6271N/A // Read sheet type if present. We only support identifier and string.
6271N/A // <ident> <eoln> is a type string
6271N/A // anything else, is not a type string
6271N/A if (nosheet == 0) {
6271N/A
6271N/A if (it8 ->sy == SIDENT) {
6271N/A
6271N/A // May be a type sheet or may be a prop value statement. We cannot use insymbol in
6271N/A // this special case...
6271N/A while (isseparator(it8->ch))
6271N/A NextCh(it8);
6271N/A
6271N/A // If a newline is found, then this is a type string
6271N/A if (it8 ->ch == '\n') {
6271N/A
6271N/A cmsIT8SetSheetType(it8, it8 ->id);
6271N/A InSymbol(it8);
6271N/A }
6271N/A else
6271N/A {
6271N/A // It is not. Just continue
6271N/A cmsIT8SetSheetType(it8, "");
6271N/A }
6271N/A }
6271N/A else
6271N/A // Validate quoted strings
6271N/A if (it8 ->sy == SSTRING) {
6271N/A cmsIT8SetSheetType(it8, it8 ->str);
6271N/A InSymbol(it8);
6271N/A }
6271N/A }
6271N/A
0N/A }
0N/A break;
0N/A
0N/A case SEOLN:
0N/A SkipEOLN(it8);
0N/A break;
0N/A
0N/A default:
0N/A if (!HeaderSection(it8)) return FALSE;
0N/A }
0N/A
0N/A }
0N/A
0N/A return (it8 -> sy != SSYNERROR);
0N/A}
0N/A
0N/A
0N/A
0N/A// Init usefull pointers
0N/A
0N/Astatic
2693N/Avoid CookPointers(cmsIT8* it8)
0N/A{
0N/A int idField, i;
0N/A char* Fld;
2693N/A cmsUInt32Number j;
2693N/A cmsUInt32Number nOldTable = it8 ->nTable;
0N/A
0N/A for (j=0; j < it8 ->TablesCount; j++) {
0N/A
2693N/A TABLE* t = it8 ->Tab + j;
0N/A
0N/A t -> SampleID = 0;
0N/A it8 ->nTable = j;
0N/A
0N/A for (idField = 0; idField < t -> nSamples; idField++)
0N/A {
2693N/A if (t ->DataFormat == NULL){
2693N/A SynError(it8, "Undefined DATA_FORMAT");
2693N/A return;
1002N/A }
1002N/A
0N/A Fld = t->DataFormat[idField];
0N/A if (!Fld) continue;
0N/A
0N/A
2693N/A if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
0N/A
0N/A t -> SampleID = idField;
0N/A
0N/A for (i=0; i < t -> nPatches; i++) {
0N/A
0N/A char *Data = GetData(it8, i, idField);
0N/A if (Data) {
0N/A char Buffer[256];
0N/A
0N/A strncpy(Buffer, Data, 255);
1002N/A Buffer[255] = 0;
0N/A
0N/A if (strlen(Buffer) <= strlen(Data))
0N/A strcpy(Data, Buffer);
0N/A else
0N/A SetData(it8, i, idField, Buffer);
0N/A
0N/A }
0N/A }
0N/A
0N/A }
0N/A
0N/A // "LABEL" is an extension. It keeps references to forward tables
0N/A
2693N/A if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) {
0N/A
0N/A // Search for table references...
0N/A for (i=0; i < t -> nPatches; i++) {
0N/A
0N/A char *Label = GetData(it8, i, idField);
0N/A
0N/A if (Label) {
0N/A
2693N/A cmsUInt32Number k;
0N/A
0N/A // This is the label, search for a table containing
0N/A // this property
0N/A
0N/A for (k=0; k < it8 ->TablesCount; k++) {
0N/A
2693N/A TABLE* Table = it8 ->Tab + k;
2693N/A KEYVALUE* p;
0N/A
1002N/A if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
0N/A
0N/A // Available, keep type and table
0N/A char Buffer[256];
0N/A
0N/A char *Type = p ->Value;
0N/A int nTable = k;
0N/A
1002N/A snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type );
0N/A
0N/A SetData(it8, i, idField, Buffer);
0N/A }
0N/A }
0N/A
0N/A
0N/A }
0N/A
0N/A }
0N/A
0N/A
0N/A }
0N/A
0N/A }
0N/A }
0N/A
0N/A it8 ->nTable = nOldTable;
0N/A}
0N/A
0N/A// Try to infere if the file is a CGATS/IT8 file at all. Read first line
0N/A// that should be something like some printable characters plus a \n
6271N/A// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line?
0N/Astatic
2693N/Aint IsMyBlock(cmsUInt8Number* Buffer, int n)
0N/A{
6271N/A int words = 1, space = 0, quot = 0;
2693N/A int i;
0N/A
6271N/A if (n < 10) return 0; // Too small
0N/A
0N/A if (n > 132)
0N/A n = 132;
0N/A
0N/A for (i = 1; i < n; i++) {
0N/A
1002N/A switch(Buffer[i])
1002N/A {
1002N/A case '\n':
1002N/A case '\r':
6271N/A return ((quot == 1) || (words > 2)) ? 0 : words;
1002N/A case '\t':
1002N/A case ' ':
1002N/A if(!quot && !space)
1002N/A space = 1;
1002N/A break;
1002N/A case '\"':
1002N/A quot = !quot;
1002N/A break;
1002N/A default:
1002N/A if (Buffer[i] < 32) return 0;
1002N/A if (Buffer[i] > 127) return 0;
6271N/A words += space;
1002N/A space = 0;
1002N/A break;
1002N/A }
0N/A }
0N/A
6271N/A return 0;
0N/A}
0N/A
0N/A
0N/Astatic
2693N/AcmsBool IsMyFile(const char* FileName)
0N/A{
0N/A FILE *fp;
2693N/A cmsUInt32Number Size;
2693N/A cmsUInt8Number Ptr[133];
0N/A
0N/A fp = fopen(FileName, "rt");
0N/A if (!fp) {
2693N/A cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName);
0N/A return FALSE;
0N/A }
0N/A
2693N/A Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp);
2693N/A
2693N/A if (fclose(fp) != 0)
2693N/A return FALSE;
0N/A
0N/A Ptr[Size] = '\0';
0N/A
0N/A return IsMyBlock(Ptr, Size);
0N/A}
0N/A
0N/A// ---------------------------------------------------------- Exported routines
0N/A
0N/A
2693N/AcmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len)
0N/A{
2693N/A cmsHANDLE hIT8;
2693N/A cmsIT8* it8;
2693N/A int type;
2693N/A
2693N/A _cmsAssert(Ptr != NULL);
2693N/A _cmsAssert(len != 0);
2693N/A
2693N/A type = IsMyBlock((cmsUInt8Number*)Ptr, len);
1002N/A if (type == 0) return NULL;
0N/A
2693N/A hIT8 = cmsIT8Alloc(ContextID);
0N/A if (!hIT8) return NULL;
0N/A
2693N/A it8 = (cmsIT8*) hIT8;
2693N/A it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1);
0N/A
0N/A strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
0N/A it8 ->MemoryBlock[len] = 0;
0N/A
2693N/A strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1);
0N/A it8-> Source = it8 -> MemoryBlock;
0N/A
1002N/A if (!ParseIT8(it8, type-1)) {
0N/A
0N/A cmsIT8Free(hIT8);
0N/A return FALSE;
0N/A }
0N/A
0N/A CookPointers(it8);
0N/A it8 ->nTable = 0;
0N/A
2693N/A _cmsFree(ContextID, it8->MemoryBlock);
0N/A it8 -> MemoryBlock = NULL;
0N/A
0N/A return hIT8;
0N/A
0N/A
0N/A}
0N/A
0N/A
2693N/AcmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName)
0N/A{
0N/A
2693N/A cmsHANDLE hIT8;
2693N/A cmsIT8* it8;
2693N/A int type;
2693N/A
2693N/A _cmsAssert(cFileName != NULL);
2693N/A
2693N/A type = IsMyFile(cFileName);
1002N/A if (type == 0) return NULL;
0N/A
2693N/A hIT8 = cmsIT8Alloc(ContextID);
2693N/A it8 = (cmsIT8*) hIT8;
0N/A if (!hIT8) return NULL;
0N/A
0N/A
1002N/A it8 ->FileStack[0]->Stream = fopen(cFileName, "rt");
1002N/A
1002N/A if (!it8 ->FileStack[0]->Stream) {
0N/A cmsIT8Free(hIT8);
0N/A return NULL;
0N/A }
0N/A
0N/A
2693N/A strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1);
2693N/A it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0;
1002N/A
1002N/A if (!ParseIT8(it8, type-1)) {
1002N/A
1002N/A fclose(it8 ->FileStack[0]->Stream);
0N/A cmsIT8Free(hIT8);
0N/A return NULL;
0N/A }
0N/A
0N/A CookPointers(it8);
0N/A it8 ->nTable = 0;
0N/A
2693N/A if (fclose(it8 ->FileStack[0]->Stream)!= 0) {
6271N/A cmsIT8Free(hIT8);
2693N/A return NULL;
2693N/A }
2693N/A
0N/A return hIT8;
0N/A
0N/A}
0N/A
2693N/Aint CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A TABLE* t;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A t = GetTable(it8);
2693N/A
2693N/A if (SampleNames)
0N/A *SampleNames = t -> DataFormat;
2693N/A return t -> nSamples;
0N/A}
0N/A
0N/A
2693N/AcmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A KEYVALUE* p;
2693N/A cmsUInt32Number n;
2693N/A char **Props;
2693N/A TABLE* t;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A t = GetTable(it8);
0N/A
0N/A // Pass#1 - count properties
0N/A
0N/A n = 0;
0N/A for (p = t -> HeaderList; p != NULL; p = p->Next) {
0N/A n++;
0N/A }
0N/A
0N/A
2693N/A Props = (char **) AllocChunk(it8, sizeof(char *) * n);
0N/A
0N/A // Pass#2 - Fill pointers
0N/A n = 0;
0N/A for (p = t -> HeaderList; p != NULL; p = p->Next) {
0N/A Props[n++] = p -> Keyword;
0N/A }
0N/A
0N/A *PropertyNames = Props;
0N/A return n;
0N/A}
0N/A
2693N/AcmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
1002N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A KEYVALUE *p, *tmp;
2693N/A cmsUInt32Number n;
1002N/A const char **Props;
2693N/A TABLE* t;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A
2693N/A t = GetTable(it8);
1002N/A
1002N/A if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) {
1002N/A *SubpropertyNames = 0;
1002N/A return 0;
1002N/A }
1002N/A
1002N/A // Pass#1 - count properties
1002N/A
1002N/A n = 0;
1002N/A for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) {
1002N/A if(tmp->Subkey != NULL)
1002N/A n++;
1002N/A }
1002N/A
1002N/A
1002N/A Props = (const char **) AllocChunk(it8, sizeof(char *) * n);
1002N/A
1002N/A // Pass#2 - Fill pointers
1002N/A n = 0;
1002N/A for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) {
1002N/A if(tmp->Subkey != NULL)
1002N/A Props[n++] = p ->Subkey;
1002N/A }
1002N/A
1002N/A *SubpropertyNames = Props;
1002N/A return n;
1002N/A}
1002N/A
0N/Astatic
2693N/Aint LocatePatch(cmsIT8* it8, const char* cPatch)
0N/A{
0N/A int i;
0N/A const char *data;
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A for (i=0; i < t-> nPatches; i++) {
0N/A
0N/A data = GetData(it8, i, t->SampleID);
0N/A
0N/A if (data != NULL) {
0N/A
2693N/A if (cmsstrcasecmp(data, cPatch) == 0)
0N/A return i;
0N/A }
0N/A }
0N/A
0N/A // SynError(it8, "Couldn't find patch '%s'\n", cPatch);
0N/A return -1;
0N/A}
0N/A
0N/A
0N/Astatic
2693N/Aint LocateEmptyPatch(cmsIT8* it8)
0N/A{
0N/A int i;
0N/A const char *data;
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A for (i=0; i < t-> nPatches; i++) {
0N/A
0N/A data = GetData(it8, i, t->SampleID);
0N/A
0N/A if (data == NULL)
2693N/A return i;
2693N/A
2693N/A }
2693N/A
2693N/A return -1;
0N/A}
0N/A
0N/Astatic
2693N/Aint LocateSample(cmsIT8* it8, const char* cSample)
0N/A{
0N/A int i;
0N/A const char *fld;
2693N/A TABLE* t = GetTable(it8);
0N/A
0N/A for (i=0; i < t->nSamples; i++) {
0N/A
0N/A fld = GetDataFormat(it8, i);
2693N/A if (cmsstrcasecmp(fld, cSample) == 0)
0N/A return i;
0N/A }
0N/A
0N/A return -1;
0N/A
0N/A}
0N/A
0N/A
2693N/Aint CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
0N/A return LocateSample(it8, cSample);
0N/A}
0N/A
0N/A
0N/A
2693N/Aconst char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
0N/A
0N/A return GetData(it8, row, col);
0N/A}
0N/A
0N/A
2693N/AcmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col)
0N/A{
0N/A const char* Buffer;
0N/A
0N/A Buffer = cmsIT8GetDataRowCol(hIT8, row, col);
0N/A
6271N/A return ParseFloatNumber(Buffer);
0N/A}
0N/A
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
0N/A
0N/A return SetData(it8, row, col, Val);
0N/A}
0N/A
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A char Buff[256];
0N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
0N/A sprintf(Buff, it8->DoubleFormatter, Val);
0N/A
0N/A return SetData(it8, row, col, Buff);
0N/A}
0N/A
0N/A
0N/A
2693N/Aconst char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A int iField, iSet;
0N/A
2693N/A _cmsAssert(hIT8 != NULL);
0N/A
0N/A iField = LocateSample(it8, cSample);
0N/A if (iField < 0) {
0N/A return NULL;
0N/A }
0N/A
0N/A iSet = LocatePatch(it8, cPatch);
0N/A if (iSet < 0) {
0N/A return NULL;
0N/A }
0N/A
0N/A return GetData(it8, iSet, iField);
0N/A}
0N/A
0N/A
2693N/AcmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* cSample)
0N/A{
0N/A const char* Buffer;
0N/A
0N/A Buffer = cmsIT8GetData(it8, cPatch, cSample);
0N/A
6271N/A return ParseFloatNumber(Buffer);
0N/A}
0N/A
0N/A
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A int iField, iSet;
2693N/A TABLE* t;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A t = GetTable(it8);
0N/A
0N/A iField = LocateSample(it8, cSample);
0N/A
0N/A if (iField < 0)
0N/A return FALSE;
0N/A
2693N/A if (t-> nPatches == 0) {
2693N/A
2693N/A AllocateDataFormat(it8);
2693N/A AllocateDataSet(it8);
2693N/A CookPointers(it8);
2693N/A }
2693N/A
2693N/A if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) {
2693N/A
2693N/A iSet = LocateEmptyPatch(it8);
2693N/A if (iSet < 0) {
2693N/A return SynError(it8, "Couldn't add more patches '%s'\n", cPatch);
0N/A }
2693N/A
2693N/A iField = t -> SampleID;
2693N/A }
2693N/A else {
2693N/A iSet = LocatePatch(it8, cPatch);
2693N/A if (iSet < 0) {
2693N/A return FALSE;
0N/A }
2693N/A }
2693N/A
2693N/A return SetData(it8, iSet, iField, Val);
0N/A}
0N/A
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch,
2693N/A const char* cSample,
2693N/A cmsFloat64Number Val)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
0N/A char Buff[256];
0N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A snprintf(Buff, 255, it8->DoubleFormatter, Val);
2693N/A return cmsIT8SetData(hIT8, cPatch, cSample, Buff);
0N/A}
0N/A
1002N/A// Buffer should get MAXSTR at least
0N/A
2693N/Aconst char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A TABLE* t;
2693N/A char* Data;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A t = GetTable(it8);
2693N/A Data = GetData(it8, nPatch, t->SampleID);
2693N/A
2693N/A if (!Data) return NULL;
2693N/A if (!buffer) return Data;
2693N/A
2693N/A strncpy(buffer, Data, MAXSTR-1);
2693N/A buffer[MAXSTR-1] = 0;
2693N/A return buffer;
0N/A}
0N/A
2693N/Aint CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch)
1002N/A{
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A return LocatePatch((cmsIT8*)hIT8, cPatch);
1002N/A}
1002N/A
2693N/AcmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A return it8 ->TablesCount;
0N/A}
0N/A
0N/A// This handles the "LABEL" extension.
0N/A// Label, nTable, Type
0N/A
2693N/Aint CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType)
0N/A{
0N/A const char* cLabelFld;
0N/A char Type[256], Label[256];
0N/A int nTable;
0N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
0N/A if (cField != NULL && *cField == 0)
0N/A cField = "LABEL";
0N/A
0N/A if (cField == NULL)
0N/A cField = "LABEL";
0N/A
0N/A cLabelFld = cmsIT8GetData(hIT8, cSet, cField);
0N/A if (!cLabelFld) return -1;
0N/A
1002N/A if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3)
0N/A return -1;
0N/A
0N/A if (ExpectedType != NULL && *ExpectedType == 0)
0N/A ExpectedType = NULL;
0N/A
0N/A if (ExpectedType) {
0N/A
2693N/A if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1;
0N/A }
0N/A
0N/A return cmsIT8SetTable(hIT8, nTable);
0N/A}
0N/A
0N/A
2693N/AcmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample)
1002N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A int pos;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
2693N/A
2693N/A pos = LocateSample(it8, cSample);
1002N/A if(pos == -1)
1002N/A return FALSE;
1002N/A
1002N/A it8->Tab[it8->nTable].SampleID = pos;
1002N/A return TRUE;
1002N/A}
1002N/A
1002N/A
2693N/Avoid CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
0N/A{
2693N/A cmsIT8* it8 = (cmsIT8*) hIT8;
2693N/A
2693N/A _cmsAssert(hIT8 != NULL);
0N/A
0N/A if (Formatter == NULL)
0N/A strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
0N/A else
0N/A strcpy(it8->DoubleFormatter, Formatter);
6271N/A
6271N/A it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
0N/A}
1002N/A