cmscgats.c revision 11948:691879ceb811
129088Smarkm/* 229088Smarkm * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 329088Smarkm * 429088Smarkm * This code is free software; you can redistribute it and/or modify it 529088Smarkm * under the terms of the GNU General Public License version 2 only, as 629088Smarkm * published by the Free Software Foundation. Oracle designates this 729088Smarkm * particular file as subject to the "Classpath" exception as provided 829088Smarkm * by Oracle in the LICENSE file that accompanied this code. 929088Smarkm * 1029088Smarkm * This code is distributed in the hope that it will be useful, but WITHOUT 1129088Smarkm * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1229088Smarkm * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1329088Smarkm * version 2 for more details (a copy is included in the LICENSE file that 1429088Smarkm * accompanied this code). 1529088Smarkm * 1629088Smarkm * You should have received a copy of the GNU General Public License version 1729088Smarkm * 2 along with this work; if not, write to the Free Software Foundation, 1829088Smarkm * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1929088Smarkm * 2029088Smarkm * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2129088Smarkm * or visit www.oracle.com if you need additional information or have any 2229088Smarkm * questions. 2329088Smarkm */ 2429088Smarkm 2529088Smarkm// This file is available under and governed by the GNU General Public 2629088Smarkm// License version 2 only, as published by the Free Software Foundation. 2729088Smarkm// However, the following notice accompanied the original version of this 2829088Smarkm// file: 2929088Smarkm// 3029088Smarkm//--------------------------------------------------------------------------------- 3129088Smarkm// 3229088Smarkm// Little Color Management System 3329088Smarkm// Copyright (c) 1998-2012 Marti Maria Saguer 3484305Smarkm// 3587139Smarkm// Permission is hereby granted, free of charge, to any person obtaining 3684305Smarkm// a copy of this software and associated documentation files (the "Software"), 3784305Smarkm// to deal in the Software without restriction, including without limitation 3829088Smarkm// the rights to use, copy, modify, merge, publish, distribute, sublicense, 3963248Speter// and/or sell copies of the Software, and to permit persons to whom the Software 4029181Smarkm// is furnished to do so, subject to the following conditions: 4163248Speter// 4229088Smarkm// The above copyright notice and this permission notice shall be included in 4329088Smarkm// all copies or substantial portions of the Software. 4429088Smarkm// 4529088Smarkm// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 4629088Smarkm// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 4729088Smarkm// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 4829088Smarkm// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 4929088Smarkm// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 5029088Smarkm// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 5129088Smarkm// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 5229088Smarkm// 5329088Smarkm//--------------------------------------------------------------------------------- 5429088Smarkm// 5529088Smarkm 5629088Smarkm#include "lcms2_internal.h" 5729088Smarkm 5829088Smarkm 5929088Smarkm// IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- 6029088Smarkm 6129088Smarkm 6229088Smarkm#define MAXID 128 // Max length of identifier 6329088Smarkm#define MAXSTR 1024 // Max length of string 6429088Smarkm#define MAXTABLES 255 // Max Number of tables in a single stream 6529088Smarkm#define MAXINCLUDE 20 // Max number of nested includes 6698884Smarkm 6729088Smarkm#define DEFAULT_DBL_FORMAT "%.10g" // Double formatting 6887139Smarkm 6929181Smarkm#ifdef CMS_IS_WINDOWS_ 7087139Smarkm# include <io.h> 7187139Smarkm# define DIR_CHAR '\\' 7229088Smarkm#else 7329088Smarkm# define DIR_CHAR '/' 7429088Smarkm#endif 7529088Smarkm 7629088Smarkm 7729088Smarkm// Symbols 7829088Smarkmtypedef enum { 7929088Smarkm 8087155Smarkm SUNDEFINED, 8187155Smarkm SINUM, // Integer 8229088Smarkm SDNUM, // Real 8329181Smarkm SIDENT, // Identifier 8429181Smarkm SSTRING, // string 8529181Smarkm SCOMMENT, // comment 8629181Smarkm SEOLN, // End of line 8729181Smarkm SEOF, // End of stream 8829181Smarkm SSYNERROR, // Syntax error found on stream 8929181Smarkm 9029181Smarkm // Keywords 9129088Smarkm 9229088Smarkm SBEGIN_DATA, 9329088Smarkm SBEGIN_DATA_FORMAT, 9429088Smarkm SEND_DATA, 9529088Smarkm SEND_DATA_FORMAT, 9629088Smarkm SKEYWORD, 9729088Smarkm SDATA_FORMAT_ID, 9829088Smarkm SINCLUDE 9987139Smarkm 10029088Smarkm } SYMBOL; 10129088Smarkm 10229088Smarkm 10398884Smarkm// How to write the value 10449887Snsayertypedef enum { 10549887Snsayer 10698884Smarkm WRITE_UNCOOKED, 10749887Snsayer WRITE_STRINGIFY, 10849887Snsayer WRITE_HEXADECIMAL, 10949887Snsayer WRITE_BINARY, 11098884Smarkm WRITE_PAIR 11198884Smarkm 11229088Smarkm } WRITEMODE; 11329088Smarkm 11429088Smarkm// Linked list of variable names 11598884Smarkmtypedef struct _KeyVal { 11698884Smarkm 11729088Smarkm struct _KeyVal* Next; 11829088Smarkm char* Keyword; // Name of variable 11929088Smarkm struct _KeyVal* NextSubkey; // If key is a dictionary, points to the next item 12029088Smarkm char* Subkey; // If key is a dictionary, points to the subkey name 12129088Smarkm char* Value; // Points to value 12229088Smarkm WRITEMODE WriteAs; // How to write the value 12329088Smarkm 12429088Smarkm } KEYVALUE; 12529088Smarkm 12629088Smarkm 12729088Smarkm// Linked list of memory chunks (Memory sink) 12829088Smarkmtypedef struct _OwnedMem { 12929088Smarkm 13029088Smarkm struct _OwnedMem* Next; 13129088Smarkm void * Ptr; // Point to value 13229088Smarkm 13329088Smarkm } OWNEDMEM; 13429088Smarkm 13529088Smarkm// Suballocator 13629088Smarkmtypedef struct _SubAllocator { 13729088Smarkm 13829088Smarkm cmsUInt8Number* Block; 13987139Smarkm cmsUInt32Number BlockSize; 14029088Smarkm cmsUInt32Number Used; 14129088Smarkm 14229088Smarkm } SUBALLOCATOR; 14329088Smarkm 14429088Smarkm// Table. Each individual table can hold properties and rows & cols 14529088Smarkmtypedef struct _Table { 14629088Smarkm 14729088Smarkm char SheetType[MAXSTR]; // The first row of the IT8 (the type) 14887139Smarkm 14987139Smarkm int nSamples, nPatches; // Cols, Rows 15029088Smarkm int SampleID; // Pos of ID 15129088Smarkm 15229088Smarkm KEYVALUE* HeaderList; // The properties 15387139Smarkm 15429088Smarkm char** DataFormat; // The binary stream descriptor 15529088Smarkm char** Data; // The binary stream 15629088Smarkm 15729088Smarkm } TABLE; 15829088Smarkm 15929088Smarkm// File stream being parsed 16087139Smarkmtypedef struct _FileContext { 16187139Smarkm char FileName[cmsMAX_PATH]; // File name if being readed from file 16229088Smarkm FILE* Stream; // File stream or NULL if holded in memory 16329088Smarkm } FILECTX; 16429088Smarkm 16587139Smarkm// This struct hold all information about an open IT8 handler. 16629088Smarkmtypedef struct { 16729088Smarkm 16829088Smarkm 16929088Smarkm cmsUInt32Number TablesCount; // How many tables in this stream 17029088Smarkm cmsUInt32Number nTable; // The actual table 17129088Smarkm 17229088Smarkm TABLE Tab[MAXTABLES]; 17329088Smarkm 17429088Smarkm // Memory management 17529088Smarkm OWNEDMEM* MemorySink; // The storage backend 17629088Smarkm SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast 17729088Smarkm 17829088Smarkm // Parser state machine 17987139Smarkm SYMBOL sy; // Current symbol 18029088Smarkm int ch; // Current character 18129088Smarkm 18229088Smarkm int inum; // integer value 18329088Smarkm cmsFloat64Number dnum; // real value 18429088Smarkm char id[MAXID]; // identifier 18529181Smarkm char str[MAXSTR]; // string 18629181Smarkm 18787139Smarkm // Allowed keywords & datasets. They have visibility on whole stream 18887139Smarkm KEYVALUE* ValidKeywords; 18929088Smarkm KEYVALUE* ValidSampleID; 19029088Smarkm 19129088Smarkm char* Source; // Points to loc. being parsed 19229088Smarkm int lineno; // line counter for error reporting 19329088Smarkm 19429088Smarkm FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed 19529088Smarkm int IncludeSP; // Include Stack Pointer 19629088Smarkm 19729088Smarkm char* MemoryBlock; // The stream if holded in memory 19829088Smarkm 19929088Smarkm char DoubleFormatter[MAXID];// Printf-like 'cmsFloat64Number' formatter 20029088Smarkm 20129088Smarkm cmsContext ContextID; // The threading context 20229088Smarkm 20329088Smarkm } cmsIT8; 20429088Smarkm 20529088Smarkm 20629088Smarkm// The stream for save operations 20729088Smarkmtypedef struct { 20829088Smarkm 20929088Smarkm FILE* stream; // For save-to-file behaviour 21029088Smarkm 21129088Smarkm cmsUInt8Number* Base; 21229088Smarkm cmsUInt8Number* Ptr; // For save-to-mem behaviour 21329088Smarkm cmsUInt32Number Used; 21429088Smarkm cmsUInt32Number Max; 21529088Smarkm 21629088Smarkm } SAVESTREAM; 21729088Smarkm 21829088Smarkm 21929088Smarkm// ------------------------------------------------------ cmsIT8 parsing routines 22087139Smarkm 22187139Smarkm 22229088Smarkm// A keyword 22329088Smarkmtypedef struct { 22429088Smarkm 22529088Smarkm const char *id; 22629088Smarkm SYMBOL sy; 22729088Smarkm 22829088Smarkm } KEYWORD; 22929088Smarkm 23029088Smarkm// The keyword->symbol translation table. Sorting is required. 23129088Smarkmstatic const KEYWORD TabKeys[] = { 23287139Smarkm 23387139Smarkm {"$INCLUDE", SINCLUDE}, // This is an extension! 23429088Smarkm {".INCLUDE", SINCLUDE}, // This is an extension! 23529088Smarkm 23629088Smarkm {"BEGIN_DATA", SBEGIN_DATA }, 23729088Smarkm {"BEGIN_DATA_FORMAT", SBEGIN_DATA_FORMAT }, 23829088Smarkm {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID}, 23929088Smarkm {"END_DATA", SEND_DATA}, 24029088Smarkm {"END_DATA_FORMAT", SEND_DATA_FORMAT}, 24129088Smarkm {"KEYWORD", SKEYWORD} 24229088Smarkm }; 24329088Smarkm 24429088Smarkm#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) 24587139Smarkm 24687139Smarkm// Predefined properties 24729088Smarkm 24887139Smarkm// A property 24929088Smarkmtypedef struct { 25029088Smarkm const char *id; // The identifier 25129088Smarkm WRITEMODE as; // How is supposed to be written 25229088Smarkm } PROPERTY; 25329088Smarkm 25429181Smarkmstatic PROPERTY PredefinedProperties[] = { 25529088Smarkm 25629088Smarkm {"NUMBER_OF_FIELDS", WRITE_UNCOOKED}, // Required - NUMBER OF FIELDS 25729181Smarkm {"NUMBER_OF_SETS", WRITE_UNCOOKED}, // Required - NUMBER OF SETS 25829088Smarkm {"ORIGINATOR", WRITE_STRINGIFY}, // Required - Identifies the specific system, organization or individual that created the data file. 25929088Smarkm {"FILE_DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. 26029088Smarkm {"CREATED", WRITE_STRINGIFY}, // Required - Indicates date of creation of the data file. 26129088Smarkm {"DESCRIPTOR", WRITE_STRINGIFY}, // Required - Describes the purpose or contents of the data file. 26229088Smarkm {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY}, // The diffuse geometry used. Allowed values are "sphere" or "opal". 26329088Smarkm {"MANUFACTURER", WRITE_STRINGIFY}, 26429088Smarkm {"MANUFACTURE", WRITE_STRINGIFY}, // Some broken Fuji targets does store this value 26529088Smarkm {"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm. 26629088Smarkm {"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target. 26729088Smarkm 26829088Smarkm {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code 26929088Smarkm // uniquely identifying th e material. This is intend ed to be used for IT8.7 27029088Smarkm // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). 27129088Smarkm 27229088Smarkm {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and 27329088Smarkm // model number) to generate the data reported. This data will often 27429088Smarkm // provide more information about the particular data collected than an 27529088Smarkm // extensive list of specific details. This is particularly important for 27629088Smarkm // spectral data or data derived from spectrophotometry. 27729088Smarkm 27887139Smarkm {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide 27987139Smarkm // a guide to the potential for issues of paper fluorescence, etc. 28029088Smarkm 28187139Smarkm {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported. 28229088Smarkm // Where standard conditions have been defined (e.g., SWOP at nominal) 28329088Smarkm // named conditions may suffice. Otherwise, detailed information is 28429088Smarkm // needed. 28529088Smarkm 28629088Smarkm {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during 28729181Smarkm // measurement. Allowed values are �black�, �white�, or {"na". 28829088Smarkm 28929088Smarkm {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic 29029181Smarkm 29129088Smarkm // below properties are new in recent specs: 29229088Smarkm 29329088Smarkm {"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated 29429088Smarkm // along with details of the geometry and the aperture size and shape. For example, 29529088Smarkm // for transmission measurements it is important to identify 0/diffuse, diffuse/0, 29629088Smarkm // opal or integrating sphere, etc. For reflection it is important to identify 0/45, 29729088Smarkm // 45/0, sphere (specular included or excluded), etc. 29829088Smarkm 29929088Smarkm {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to 30029088Smarkm // denote the use of filters such as none, D65, Red, Green or Blue. 30129088Smarkm 30229088Smarkm {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed 30329088Smarkm // values are {"yes�, �white�, �none� or �na�. 30429088Smarkm 30529088Smarkm {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the 30629088Smarkm // calculation of various data parameters (2 degree and 10 degree), CIE standard 30729088Smarkm // illuminant functions used in the calculation of various data parameters (e.g., D50, 30829088Smarkm // D65, etc.), density status response, etc. If used there shall be at least one 30987139Smarkm // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute 31087139Smarkm // in the set shall be {"name" and shall identify the particular parameter used. 31129088Smarkm // The second shall be {"value" and shall provide the value associated with that name. 31287139Smarkm // For ASCII data, a string containing the Name and Value attribute pairs shall follow 31329088Smarkm // the weighting function keyword. A semi-colon separates attribute pairs from each 31429088Smarkm // other and within the attribute the name and value are separated by a comma. 31529088Smarkm 31629088Smarkm {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name 31729088Smarkm // of the calculation, parameter is the name of the parameter used in the calculation 31829088Smarkm // and value is the value of the parameter. 31929088Smarkm 32029088Smarkm {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc. 32129088Smarkm 32229088Smarkm {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target. 32329088Smarkm 32429088Smarkm {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table. 32529088Smarkm 32629088Smarkm {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table. 32729088Smarkm}; 32829088Smarkm 32929088Smarkm#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY)) 33087139Smarkm 33187139Smarkm 33229088Smarkm// Predefined sample types on dataset 33329088Smarkmstatic const char* PredefinedSampleID[] = { 33429088Smarkm "SAMPLE_ID", // Identifies sample that data represents 33529088Smarkm "STRING", // Identifies label, or other non-machine readable value. 33629088Smarkm // Value must begin and end with a " symbol 33729088Smarkm 33829088Smarkm "CMYK_C", // Cyan component of CMYK data expressed as a percentage 33929088Smarkm "CMYK_M", // Magenta component of CMYK data expressed as a percentage 34029088Smarkm "CMYK_Y", // Yellow component of CMYK data expressed as a percentage 34187139Smarkm "CMYK_K", // Black component of CMYK data expressed as a percentage 34287139Smarkm "D_RED", // Red filter density 34329088Smarkm "D_GREEN", // Green filter density 34429088Smarkm "D_BLUE", // Blue filter density 34529088Smarkm "D_VIS", // Visual filter density 34629088Smarkm "D_MAJOR_FILTER", // Major filter d ensity 34729088Smarkm "RGB_R", // Red component of RGB data 34829088Smarkm "RGB_G", // Green component of RGB data 34929088Smarkm "RGB_B", // Blue com ponent of RGB data 35029088Smarkm "SPECTRAL_NM", // Wavelength of measurement expressed in nanometers 35129088Smarkm "SPECTRAL_PCT", // Percentage reflectance/transmittance 35287139Smarkm "SPECTRAL_DEC", // Reflectance/transmittance 35387139Smarkm "XYZ_X", // X component of tristimulus data 35429088Smarkm "XYZ_Y", // Y component of tristimulus data 35529088Smarkm "XYZ_Z", // Z component of tristimulus data 35629088Smarkm "XYY_X", // x component of chromaticity data 35729088Smarkm "XYY_Y", // y component of chromaticity data 35829088Smarkm "XYY_CAPY", // Y component of tristimulus data 35929088Smarkm "LAB_L", // L* component of Lab data 36029088Smarkm "LAB_A", // a* component of Lab data 36129088Smarkm "LAB_B", // b* component of Lab data 36229088Smarkm "LAB_C", // C*ab component of Lab data 36329088Smarkm "LAB_H", // hab component of Lab data 36429088Smarkm "LAB_DE", // CIE dE 36529088Smarkm "LAB_DE_94", // CIE dE using CIE 94 36629088Smarkm "LAB_DE_CMC", // dE using CMC 36729088Smarkm "LAB_DE_2000", // CIE dE using CIE DE 2000 36829088Smarkm "MEAN_DE", // Mean Delta E (LAB_DE) of samples compared to batch average 36929088Smarkm // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets) 37029088Smarkm "STDEV_X", // Standard deviation of X (tristimulus data) 37129088Smarkm "STDEV_Y", // Standard deviation of Y (tristimulus data) 37229088Smarkm "STDEV_Z", // Standard deviation of Z (tristimulus data) 37387139Smarkm "STDEV_L", // Standard deviation of L* 37487139Smarkm "STDEV_A", // Standard deviation of a* 37529088Smarkm "STDEV_B", // Standard deviation of b* 37629088Smarkm "STDEV_DE", // Standard deviation of CIE dE 37729088Smarkm "CHI_SQD_PAR"}; // The average of the standard deviations of L*, a* and b*. It is 37829088Smarkm // used to derive an estimate of the chi-squared parameter which is 37929088Smarkm // recommended as the predictor of the variability of dE 38087139Smarkm 38187139Smarkm#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *)) 38229088Smarkm 38329088Smarkm//Forward declaration of some internal functions 38429088Smarkmstatic void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); 38529088Smarkm 38629088Smarkm// Checks whatever c is a separator 38787139Smarkmstatic 38887139SmarkmcmsBool isseparator(int c) 38929088Smarkm{ 39029088Smarkm return (c == ' ') || (c == '\t') ; 39129088Smarkm} 39229088Smarkm 39329088Smarkm// Checks whatever c is a valid identifier char 39429088Smarkmstatic 39529088SmarkmcmsBool ismiddle(int c) 39629088Smarkm{ 39729088Smarkm return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); 39887139Smarkm} 39987139Smarkm 40029088Smarkm// Checks whatsever c is a valid identifier middle char. 40129088Smarkmstatic 40229088SmarkmcmsBool isidchar(int c) 40329088Smarkm{ 40429088Smarkm return isalnum(c) || ismiddle(c); 40529088Smarkm} 40629088Smarkm 40729088Smarkm// Checks whatsever c is a valid identifier first char. 40829088Smarkmstatic 40929088SmarkmcmsBool isfirstidchar(int c) 41029088Smarkm{ 41129088Smarkm return !isdigit(c) && ismiddle(c); 41229088Smarkm} 41329088Smarkm 41429088Smarkm// Guess whether the supplied path looks like an absolute path 41529088Smarkmstatic 41629088SmarkmcmsBool isabsolutepath(const char *path) 41729088Smarkm{ 41829088Smarkm char ThreeChars[4]; 41929088Smarkm 42087139Smarkm if(path == NULL) 42187139Smarkm return FALSE; 42229088Smarkm if (path[0] == 0) 42329088Smarkm return FALSE; 42429088Smarkm 42529088Smarkm strncpy(ThreeChars, path, 3); 42629088Smarkm ThreeChars[3] = 0; 42729088Smarkm 42829088Smarkm if(ThreeChars[0] == DIR_CHAR) 42929088Smarkm return TRUE; 43029088Smarkm 43129088Smarkm#ifdef CMS_IS_WINDOWS_ 43229088Smarkm if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':') 43329088Smarkm return TRUE; 43429088Smarkm#endif 43529088Smarkm return FALSE; 43629088Smarkm} 43787139Smarkm 43887139Smarkm 43929088Smarkm// Makes a file path based on a given reference path 44029088Smarkm// NOTE: this function doesn't check if the path exists or even if it's legal 44129088Smarkmstatic 44229088SmarkmcmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen) 44329088Smarkm{ 44429088Smarkm char *tail; 44529088Smarkm cmsUInt32Number len; 44629088Smarkm 44729088Smarkm // Already absolute? 44829088Smarkm if (isabsolutepath(relPath)) { 44987139Smarkm 45087139Smarkm strncpy(buffer, relPath, MaxLen); 45129088Smarkm buffer[MaxLen-1] = 0; 45229088Smarkm return TRUE; 45329088Smarkm } 45429088Smarkm 45529088Smarkm // No, search for last 45629088Smarkm strncpy(buffer, basePath, MaxLen); 45729088Smarkm buffer[MaxLen-1] = 0; 45829088Smarkm 45929088Smarkm tail = strrchr(buffer, DIR_CHAR); 46029088Smarkm if (tail == NULL) return FALSE; // Is not absolute and has no separators?? 46187139Smarkm 46287139Smarkm len = (cmsUInt32Number) (tail - buffer); 46329088Smarkm if (len >= MaxLen) return FALSE; 46429088Smarkm 46529088Smarkm // No need to assure zero terminator over here 46629088Smarkm strncpy(tail + 1, relPath, MaxLen - len); 46729088Smarkm 46829088Smarkm return TRUE; 46929088Smarkm} 47087139Smarkm 47187139Smarkm 47229088Smarkm// Make sure no exploit is being even tried 47329088Smarkmstatic 47429088Smarkmconst char* NoMeta(const char* str) 47529088Smarkm{ 47629088Smarkm if (strchr(str, '%') != NULL) 47729088Smarkm return "**** CORRUPTED FORMAT STRING ***"; 47829088Smarkm 47929088Smarkm return str; 48029088Smarkm} 48129088Smarkm 48287139Smarkm// Syntax error 48387139Smarkmstatic 48429088SmarkmcmsBool SynError(cmsIT8* it8, const char *Txt, ...) 48587139Smarkm{ 48629088Smarkm char Buffer[256], ErrMsg[1024]; 48729088Smarkm va_list args; 48829088Smarkm 48929088Smarkm va_start(args, Txt); 49029088Smarkm vsnprintf(Buffer, 255, Txt, args); 49129088Smarkm Buffer[255] = 0; 49229088Smarkm va_end(args); 49329088Smarkm 49429088Smarkm snprintf(ErrMsg, 1023, "%s: Line %d, %s", it8->FileStack[it8 ->IncludeSP]->FileName, it8->lineno, Buffer); 49529088Smarkm ErrMsg[1023] = 0; 49629088Smarkm it8->sy = SSYNERROR; 49729088Smarkm cmsSignalError(it8 ->ContextID, cmsERROR_CORRUPTION_DETECTED, "%s", ErrMsg); 49829088Smarkm return FALSE; 49929088Smarkm} 50029088Smarkm 50129088Smarkm// Check if current symbol is same as specified. issue an error else. 50229088Smarkmstatic 50329088SmarkmcmsBool Check(cmsIT8* it8, SYMBOL sy, const char* Err) 50429088Smarkm{ 50529088Smarkm if (it8 -> sy != sy) 50629088Smarkm return SynError(it8, NoMeta(Err)); 50729088Smarkm return TRUE; 50829088Smarkm} 50929088Smarkm 51029088Smarkm// Read Next character from stream 51129088Smarkmstatic 51229088Smarkmvoid NextCh(cmsIT8* it8) 51329088Smarkm{ 51429088Smarkm if (it8 -> FileStack[it8 ->IncludeSP]->Stream) { 51529088Smarkm 51629088Smarkm it8 ->ch = fgetc(it8 ->FileStack[it8 ->IncludeSP]->Stream); 51729088Smarkm 51829088Smarkm if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream)) { 51929088Smarkm 52029088Smarkm if (it8 ->IncludeSP > 0) { 52129088Smarkm 52287139Smarkm fclose(it8 ->FileStack[it8->IncludeSP--]->Stream); 52387139Smarkm it8 -> ch = ' '; // Whitespace to be ignored 52429088Smarkm 52529088Smarkm } else 52687139Smarkm it8 ->ch = 0; // EOF 52729088Smarkm } 52829088Smarkm } 52929088Smarkm else { 53029088Smarkm it8->ch = *it8->Source; 53129088Smarkm if (it8->ch) it8->Source++; 53229088Smarkm } 53329088Smarkm} 53429088Smarkm 53529088Smarkm 53629088Smarkm// Try to see if current identifier is a keyword, if so return the referred symbol 53729088Smarkmstatic 53829088SmarkmSYMBOL BinSrchKey(const char *id) 53929088Smarkm{ 54029088Smarkm int l = 1; 54129088Smarkm int r = NUMKEYS; 54229088Smarkm int x, res; 54329088Smarkm 54429088Smarkm while (r >= l) 54529088Smarkm { 54629088Smarkm x = (l+r)/2; 54729088Smarkm res = cmsstrcasecmp(id, TabKeys[x-1].id); 54829088Smarkm if (res == 0) return TabKeys[x-1].sy; 54929088Smarkm if (res < 0) r = x - 1; 55029088Smarkm else l = x + 1; 55129088Smarkm } 55229088Smarkm 55329181Smarkm return SUNDEFINED; 55429088Smarkm} 55529088Smarkm 55629088Smarkm 55729088Smarkm// 10 ^n 55829088Smarkmstatic 55929088SmarkmcmsFloat64Number xpow10(int n) 56029088Smarkm{ 56129088Smarkm return pow(10, (cmsFloat64Number) n); 56229088Smarkm} 56329088Smarkm 56429088Smarkm 56529088Smarkm// Reads a Real number, tries to follow from integer number 56687139Smarkmstatic 56787139Smarkmvoid ReadReal(cmsIT8* it8, int inum) 56829088Smarkm{ 56929088Smarkm it8->dnum = (cmsFloat64Number) inum; 57087139Smarkm 57129088Smarkm while (isdigit(it8->ch)) { 57229088Smarkm 57329088Smarkm it8->dnum = it8->dnum * 10.0 + (it8->ch - '0'); 57429088Smarkm NextCh(it8); 57529088Smarkm } 57629088Smarkm 57729088Smarkm if (it8->ch == '.') { // Decimal point 57829088Smarkm 57929088Smarkm cmsFloat64Number frac = 0.0; // fraction 58029088Smarkm int prec = 0; // precision 58129088Smarkm 58229088Smarkm NextCh(it8); // Eats dec. point 58329088Smarkm 58429088Smarkm while (isdigit(it8->ch)) { 58529088Smarkm 58629088Smarkm frac = frac * 10.0 + (it8->ch - '0'); 58729088Smarkm prec++; 58829088Smarkm NextCh(it8); 58929088Smarkm } 59029088Smarkm 59129088Smarkm it8->dnum = it8->dnum + (frac / xpow10(prec)); 59229088Smarkm } 59329088Smarkm 59429088Smarkm // Exponent, example 34.00E+20 59529181Smarkm if (toupper(it8->ch) == 'E') { 59629088Smarkm 59729088Smarkm int e; 59829088Smarkm int sgn; 59929088Smarkm 60029088Smarkm NextCh(it8); sgn = 1; 60129088Smarkm 60229088Smarkm if (it8->ch == '-') { 60329088Smarkm 60429088Smarkm sgn = -1; NextCh(it8); 60529088Smarkm } 60629088Smarkm else 60729088Smarkm if (it8->ch == '+') { 60829088Smarkm 60929088Smarkm sgn = +1; 61029088Smarkm NextCh(it8); 61129088Smarkm } 61229088Smarkm 61329088Smarkm e = 0; 61487139Smarkm while (isdigit(it8->ch)) { 61587139Smarkm 61629088Smarkm if ((cmsFloat64Number) e * 10L < INT_MAX) 61729088Smarkm e = e * 10 + (it8->ch - '0'); 61829088Smarkm 61929088Smarkm NextCh(it8); 62029088Smarkm } 62129088Smarkm 62229088Smarkm e = sgn*e; 62329088Smarkm it8 -> dnum = it8 -> dnum * xpow10(e); 62429088Smarkm } 62529088Smarkm} 62629088Smarkm 62729088Smarkm// Parses a float number 62829088Smarkm// This can not call directly atof because it uses locale dependant 62929088Smarkm// parsing, while CCMX files always use . as decimal separator 63029088Smarkmstatic 63129181SmarkmcmsFloat64Number ParseFloatNumber(const char *Buffer) 63229088Smarkm{ 63329088Smarkm cmsFloat64Number dnum = 0.0; 63429088Smarkm int sign = 1; 63529088Smarkm 63629088Smarkm // keep safe 63729088Smarkm if (Buffer == NULL) return 0.0; 63829088Smarkm 63929088Smarkm if (*Buffer == '-' || *Buffer == '+') { 64029088Smarkm 64129088Smarkm sign = (*Buffer == '-') ? -1 : 1; 64229088Smarkm Buffer++; 64329088Smarkm } 64429088Smarkm 64529088Smarkm 64629088Smarkm while (*Buffer && isdigit((int) *Buffer)) { 64729088Smarkm 64829088Smarkm dnum = dnum * 10.0 + (*Buffer - '0'); 64929088Smarkm if (*Buffer) Buffer++; 65087139Smarkm } 65187139Smarkm 65229088Smarkm if (*Buffer == '.') { 65329088Smarkm 65429088Smarkm cmsFloat64Number frac = 0.0; // fraction 65529088Smarkm int prec = 0; // precission 65629088Smarkm 65729088Smarkm if (*Buffer) Buffer++; 65829088Smarkm 65929088Smarkm while (*Buffer && isdigit((int) *Buffer)) { 66029088Smarkm 66129088Smarkm frac = frac * 10.0 + (*Buffer - '0'); 66229088Smarkm prec++; 66329088Smarkm if (*Buffer) Buffer++; 66429088Smarkm } 66529088Smarkm 66629088Smarkm dnum = dnum + (frac / xpow10(prec)); 66787139Smarkm } 66887139Smarkm 66929088Smarkm // Exponent, example 34.00E+20 67029088Smarkm if (*Buffer && toupper(*Buffer) == 'E') { 67129088Smarkm 67229088Smarkm int e; 67329088Smarkm int sgn; 67429088Smarkm 67529088Smarkm if (*Buffer) Buffer++; 67629088Smarkm sgn = 1; 67729088Smarkm 67829088Smarkm if (*Buffer == '-') { 67929088Smarkm 68087139Smarkm sgn = -1; 68187139Smarkm if (*Buffer) Buffer++; 68229088Smarkm } 68329088Smarkm else 68429088Smarkm if (*Buffer == '+') { 68529088Smarkm 68629088Smarkm sgn = +1; 68729088Smarkm if (*Buffer) Buffer++; 68829088Smarkm } 68929088Smarkm 69029088Smarkm e = 0; 69129088Smarkm while (*Buffer && isdigit((int) *Buffer)) { 69287139Smarkm 69387139Smarkm if ((cmsFloat64Number) e * 10L < INT_MAX) 69429088Smarkm e = e * 10 + (*Buffer - '0'); 69529088Smarkm 69629088Smarkm if (*Buffer) Buffer++; 69729088Smarkm } 69829088Smarkm 69929088Smarkm e = sgn*e; 70029088Smarkm dnum = dnum * xpow10(e); 70129088Smarkm } 70229088Smarkm 70329088Smarkm return sign * dnum; 70429088Smarkm} 70587139Smarkm 70687139Smarkm 70729088Smarkm// Reads next symbol 70829088Smarkmstatic 70929088Smarkmvoid InSymbol(cmsIT8* it8) 71029088Smarkm{ 71187139Smarkm register char *idptr; 71287139Smarkm register int k; 71329088Smarkm SYMBOL key; 71429088Smarkm int sng; 71529088Smarkm 71629088Smarkm do { 71787139Smarkm 71887139Smarkm while (isseparator(it8->ch)) 71929088Smarkm NextCh(it8); 72029088Smarkm 72129088Smarkm if (isfirstidchar(it8->ch)) { // Identifier 72287139Smarkm 72329088Smarkm k = 0; 724228843Scperciva idptr = it8->id; 725228843Scperciva 726228843Scperciva do { 72729088Smarkm 72829088Smarkm if (++k < MAXID) *idptr++ = (char) it8->ch; 72929088Smarkm 73029088Smarkm NextCh(it8); 73129088Smarkm 73229088Smarkm } while (isidchar(it8->ch)); 73329088Smarkm 73429088Smarkm *idptr = '\0'; 73529088Smarkm 73629088Smarkm 73729088Smarkm key = BinSrchKey(it8->id); 73829088Smarkm if (key == SUNDEFINED) it8->sy = SIDENT; 73929088Smarkm else it8->sy = key; 74029088Smarkm 74129088Smarkm } 74229088Smarkm else // Is a number? 74329088Smarkm if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+') 74429088Smarkm { 74529088Smarkm int sign = 1; 74629088Smarkm 74729088Smarkm if (it8->ch == '-') { 74829088Smarkm sign = -1; 74929088Smarkm NextCh(it8); 75029088Smarkm } 75129088Smarkm 75229088Smarkm it8->inum = 0; 75329088Smarkm it8->sy = SINUM; 75429088Smarkm 75529088Smarkm if (it8->ch == '0') { // 0xnnnn (Hexa) or 0bnnnn (Binary) 75629088Smarkm 75729088Smarkm NextCh(it8); 75829088Smarkm if (toupper(it8->ch) == 'X') { 75929088Smarkm 76029088Smarkm int j; 76187139Smarkm 76287139Smarkm NextCh(it8); 76329088Smarkm while (isxdigit(it8->ch)) 76429088Smarkm { 76529088Smarkm it8->ch = toupper(it8->ch); 76629088Smarkm if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10; 76729088Smarkm else j = it8->ch - '0'; 76829088Smarkm 76929088Smarkm if ((long) it8->inum * 16L > (long) INT_MAX) 77029088Smarkm { 77129088Smarkm SynError(it8, "Invalid hexadecimal number"); 77229088Smarkm return; 77329088Smarkm } 77429088Smarkm 77529088Smarkm it8->inum = it8->inum * 16 + j; 77629088Smarkm NextCh(it8); 77729088Smarkm } 77829088Smarkm return; 77929088Smarkm } 78029088Smarkm 78129088Smarkm if (toupper(it8->ch) == 'B') { // Binary 78229088Smarkm 78329088Smarkm int j; 78487139Smarkm 78587139Smarkm NextCh(it8); 78629088Smarkm while (it8->ch == '0' || it8->ch == '1') 78729088Smarkm { 78829088Smarkm j = it8->ch - '0'; 78929088Smarkm 79029088Smarkm if ((long) it8->inum * 2L > (long) INT_MAX) 79129088Smarkm { 79229088Smarkm SynError(it8, "Invalid binary number"); 79387139Smarkm return; 79487139Smarkm } 79529088Smarkm 79629088Smarkm it8->inum = it8->inum * 2 + j; 79729088Smarkm NextCh(it8); 79829088Smarkm } 79929088Smarkm return; 80029088Smarkm } 80129088Smarkm } 80287139Smarkm 80387139Smarkm 80429088Smarkm while (isdigit(it8->ch)) { 80529088Smarkm 80687139Smarkm if ((long) it8->inum * 10L > (long) INT_MAX) { 80787139Smarkm ReadReal(it8, it8->inum); 80829088Smarkm it8->sy = SDNUM; 80929088Smarkm it8->dnum *= sign; 81029088Smarkm return; 81129088Smarkm } 81229088Smarkm 81329088Smarkm it8->inum = it8->inum * 10 + (it8->ch - '0'); 81429088Smarkm NextCh(it8); 81529088Smarkm } 81629088Smarkm 81729088Smarkm if (it8->ch == '.') { 81829088Smarkm 81929088Smarkm ReadReal(it8, it8->inum); 82029088Smarkm it8->sy = SDNUM; 82129088Smarkm it8->dnum *= sign; 82229088Smarkm return; 82329088Smarkm } 82429088Smarkm 82529088Smarkm it8 -> inum *= sign; 82629088Smarkm 82729088Smarkm // Special case. Numbers followed by letters are taken as identifiers 82829088Smarkm 82929088Smarkm if (isidchar(it8 ->ch)) { 83029088Smarkm 83129088Smarkm if (it8 ->sy == SINUM) { 83229088Smarkm 83329088Smarkm sprintf(it8->id, "%d", it8->inum); 83429088Smarkm } 83529088Smarkm else { 83629088Smarkm 83729088Smarkm sprintf(it8->id, it8 ->DoubleFormatter, it8->dnum); 83829088Smarkm } 83929088Smarkm 84029088Smarkm k = (int) strlen(it8 ->id); 84129088Smarkm idptr = it8 ->id + k; 84229088Smarkm do { 84329088Smarkm 84429088Smarkm if (++k < MAXID) *idptr++ = (char) it8->ch; 84529088Smarkm 84629088Smarkm NextCh(it8); 84729088Smarkm 84829088Smarkm } while (isidchar(it8->ch)); 84929088Smarkm 85029088Smarkm *idptr = '\0'; 85129088Smarkm it8->sy = SIDENT; 85229088Smarkm } 85329088Smarkm return; 85429088Smarkm 85529088Smarkm } 85629088Smarkm else 85729088Smarkm switch ((int) it8->ch) { 85887139Smarkm 85987139Smarkm // EOF marker -- ignore it 86029088Smarkm case '\x1a': 86129088Smarkm NextCh(it8); 86229088Smarkm break; 86329088Smarkm 86429088Smarkm // Eof stream markers 86529088Smarkm case 0: 86629088Smarkm case -1: 86729088Smarkm it8->sy = SEOF; 86829088Smarkm break; 86929088Smarkm 87029088Smarkm 87129088Smarkm // Next line 87229088Smarkm case '\r': 87329088Smarkm NextCh(it8); 87429088Smarkm if (it8 ->ch == '\n') 87529088Smarkm NextCh(it8); 87629088Smarkm it8->sy = SEOLN; 87729088Smarkm it8->lineno++; 87829088Smarkm break; 87987139Smarkm 88087139Smarkm case '\n': 88129088Smarkm NextCh(it8); 88287139Smarkm it8->sy = SEOLN; 88387139Smarkm it8->lineno++; 88429088Smarkm break; 88529088Smarkm 88629088Smarkm // Comment 88729088Smarkm case '#': 88829088Smarkm NextCh(it8); 88929088Smarkm while (it8->ch && it8->ch != '\n' && it8->ch != '\r') 89029088Smarkm NextCh(it8); 89129088Smarkm 89229088Smarkm it8->sy = SCOMMENT; 89329088Smarkm break; 89429088Smarkm 89529088Smarkm // String. 89629088Smarkm case '\'': 89729088Smarkm case '\"': 89829088Smarkm idptr = it8->str; 89987139Smarkm sng = it8->ch; 90087139Smarkm k = 0; 90129088Smarkm NextCh(it8); 90229088Smarkm 90329088Smarkm while (k < MAXSTR && it8->ch != sng) { 90429088Smarkm 90529088Smarkm if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1; 90629088Smarkm else { 90729088Smarkm *idptr++ = (char) it8->ch; 90829088Smarkm NextCh(it8); 90929088Smarkm k++; 91087139Smarkm } 91187139Smarkm } 91229088Smarkm 91329088Smarkm it8->sy = SSTRING; 91429088Smarkm *idptr = '\0'; 91529088Smarkm NextCh(it8); 91629088Smarkm break; 91729088Smarkm 91829088Smarkm 91929088Smarkm default: 92029088Smarkm SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); 92129088Smarkm return; 92287139Smarkm } 92387139Smarkm 92429088Smarkm } while (it8->sy == SCOMMENT); 92529088Smarkm 92629088Smarkm // Handle the include special token 92729088Smarkm 92829088Smarkm if (it8 -> sy == SINCLUDE) { 92929088Smarkm 93029088Smarkm FILECTX* FileNest; 93129088Smarkm 93229088Smarkm if(it8 -> IncludeSP >= (MAXINCLUDE-1)) { 93329088Smarkm 93429088Smarkm SynError(it8, "Too many recursion levels"); 93529088Smarkm return; 93629088Smarkm } 93729088Smarkm 93829088Smarkm InSymbol(it8); 93929088Smarkm if (!Check(it8, SSTRING, "Filename expected")) return; 94029088Smarkm 94129088Smarkm FileNest = it8 -> FileStack[it8 -> IncludeSP + 1]; 94287139Smarkm if(FileNest == NULL) { 94387139Smarkm 94429088Smarkm FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); 94529088Smarkm //if(FileNest == NULL) 94687139Smarkm // TODO: how to manage out-of-memory conditions? 94729088Smarkm } 94829088Smarkm 94929088Smarkm if (BuildAbsolutePath(it8->str, 95029088Smarkm it8->FileStack[it8->IncludeSP]->FileName, 95129088Smarkm FileNest->FileName, cmsMAX_PATH-1) == FALSE) { 95229088Smarkm SynError(it8, "File path too long"); 95329088Smarkm return; 95429088Smarkm } 95529088Smarkm 95629088Smarkm FileNest->Stream = fopen(FileNest->FileName, "rt"); 957 if (FileNest->Stream == NULL) { 958 959 SynError(it8, "File %s not found", FileNest->FileName); 960 return; 961 } 962 it8->IncludeSP++; 963 964 it8 ->ch = ' '; 965 InSymbol(it8); 966 } 967 968} 969 970// Checks end of line separator 971static 972cmsBool CheckEOLN(cmsIT8* it8) 973{ 974 if (!Check(it8, SEOLN, "Expected separator")) return FALSE; 975 while (it8 -> sy == SEOLN) 976 InSymbol(it8); 977 return TRUE; 978 979} 980 981// Skip a symbol 982 983static 984void Skip(cmsIT8* it8, SYMBOL sy) 985{ 986 if (it8->sy == sy && it8->sy != SEOF) 987 InSymbol(it8); 988} 989 990 991// Skip multiple EOLN 992static 993void SkipEOLN(cmsIT8* it8) 994{ 995 while (it8->sy == SEOLN) { 996 InSymbol(it8); 997 } 998} 999 1000 1001// Returns a string holding current value 1002static 1003cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* ErrorTitle) 1004{ 1005 switch (it8->sy) { 1006 1007 case SEOLN: // Empty value 1008 Buffer[0]=0; 1009 break; 1010 case SIDENT: strncpy(Buffer, it8->id, max); 1011 Buffer[max-1]=0; 1012 break; 1013 case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; 1014 case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; 1015 case SSTRING: strncpy(Buffer, it8->str, max); 1016 Buffer[max-1] = 0; 1017 break; 1018 1019 1020 default: 1021 return SynError(it8, "%s", ErrorTitle); 1022 } 1023 1024 Buffer[max] = 0; 1025 return TRUE; 1026} 1027 1028// ---------------------------------------------------------- Table 1029 1030static 1031TABLE* GetTable(cmsIT8* it8) 1032{ 1033 if ((it8 -> nTable >= it8 ->TablesCount)) { 1034 1035 SynError(it8, "Table %d out of sequence", it8 -> nTable); 1036 return it8 -> Tab; 1037 } 1038 1039 return it8 ->Tab + it8 ->nTable; 1040} 1041 1042// ---------------------------------------------------------- Memory management 1043 1044 1045// Frees an allocator and owned memory 1046void CMSEXPORT cmsIT8Free(cmsHANDLE hIT8) 1047{ 1048 cmsIT8* it8 = (cmsIT8*) hIT8; 1049 1050 if (it8 == NULL) 1051 return; 1052 1053 if (it8->MemorySink) { 1054 1055 OWNEDMEM* p; 1056 OWNEDMEM* n; 1057 1058 for (p = it8->MemorySink; p != NULL; p = n) { 1059 1060 n = p->Next; 1061 if (p->Ptr) _cmsFree(it8 ->ContextID, p->Ptr); 1062 _cmsFree(it8 ->ContextID, p); 1063 } 1064 } 1065 1066 if (it8->MemoryBlock) 1067 _cmsFree(it8 ->ContextID, it8->MemoryBlock); 1068 1069 _cmsFree(it8 ->ContextID, it8); 1070} 1071 1072 1073// Allocates a chunk of data, keep linked list 1074static 1075void* AllocBigBlock(cmsIT8* it8, cmsUInt32Number size) 1076{ 1077 OWNEDMEM* ptr1; 1078 void* ptr = _cmsMallocZero(it8->ContextID, size); 1079 1080 if (ptr != NULL) { 1081 1082 ptr1 = (OWNEDMEM*) _cmsMallocZero(it8 ->ContextID, sizeof(OWNEDMEM)); 1083 1084 if (ptr1 == NULL) { 1085 1086 _cmsFree(it8 ->ContextID, ptr); 1087 return NULL; 1088 } 1089 1090 ptr1-> Ptr = ptr; 1091 ptr1-> Next = it8 -> MemorySink; 1092 it8 -> MemorySink = ptr1; 1093 } 1094 1095 return ptr; 1096} 1097 1098 1099// Suballocator. 1100static 1101void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) 1102{ 1103 cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used; 1104 cmsUInt8Number* ptr; 1105 1106 size = _cmsALIGNMEM(size); 1107 1108 if (size > Free) { 1109 1110 if (it8 -> Allocator.BlockSize == 0) 1111 1112 it8 -> Allocator.BlockSize = 20*1024; 1113 else 1114 it8 ->Allocator.BlockSize *= 2; 1115 1116 if (it8 ->Allocator.BlockSize < size) 1117 it8 ->Allocator.BlockSize = size; 1118 1119 it8 ->Allocator.Used = 0; 1120 it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize); 1121 } 1122 1123 ptr = it8 ->Allocator.Block + it8 ->Allocator.Used; 1124 it8 ->Allocator.Used += size; 1125 1126 return (void*) ptr; 1127 1128} 1129 1130 1131// Allocates a string 1132static 1133char *AllocString(cmsIT8* it8, const char* str) 1134{ 1135 cmsUInt32Number Size = (cmsUInt32Number) strlen(str)+1; 1136 char *ptr; 1137 1138 1139 ptr = (char *) AllocChunk(it8, Size); 1140 if (ptr) strncpy (ptr, str, Size-1); 1141 1142 return ptr; 1143} 1144 1145// Searches through linked list 1146 1147static 1148cmsBool IsAvailableOnList(KEYVALUE* p, const char* Key, const char* Subkey, KEYVALUE** LastPtr) 1149{ 1150 if (LastPtr) *LastPtr = p; 1151 1152 for (; p != NULL; p = p->Next) { 1153 1154 if (LastPtr) *LastPtr = p; 1155 1156 if (*Key != '#') { // Comments are ignored 1157 1158 if (cmsstrcasecmp(Key, p->Keyword) == 0) 1159 break; 1160 } 1161 } 1162 1163 if (p == NULL) 1164 return FALSE; 1165 1166 if (Subkey == 0) 1167 return TRUE; 1168 1169 for (; p != NULL; p = p->NextSubkey) { 1170 1171 if (p ->Subkey == NULL) continue; 1172 1173 if (LastPtr) *LastPtr = p; 1174 1175 if (cmsstrcasecmp(Subkey, p->Subkey) == 0) 1176 return TRUE; 1177 } 1178 1179 return FALSE; 1180} 1181 1182 1183 1184// Add a property into a linked list 1185static 1186KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs) 1187{ 1188 KEYVALUE* p; 1189 KEYVALUE* last; 1190 1191 1192 // Check if property is already in list 1193 1194 if (IsAvailableOnList(*Head, Key, Subkey, &p)) { 1195 1196 // This may work for editing properties 1197 1198 // return SynError(it8, "duplicate key <%s>", Key); 1199 } 1200 else { 1201 1202 last = p; 1203 1204 // Allocate the container 1205 p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE)); 1206 if (p == NULL) 1207 { 1208 SynError(it8, "AddToList: out of memory"); 1209 return NULL; 1210 } 1211 1212 // Store name and value 1213 p->Keyword = AllocString(it8, Key); 1214 p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey); 1215 1216 // Keep the container in our list 1217 if (*Head == NULL) { 1218 *Head = p; 1219 } 1220 else 1221 { 1222 if (Subkey != NULL && last != NULL) { 1223 1224 last->NextSubkey = p; 1225 1226 // If Subkey is not null, then last is the last property with the same key, 1227 // but not necessarily is the last property in the list, so we need to move 1228 // to the actual list end 1229 while (last->Next != NULL) 1230 last = last->Next; 1231 } 1232 1233 if (last != NULL) last->Next = p; 1234 } 1235 1236 p->Next = NULL; 1237 p->NextSubkey = NULL; 1238 } 1239 1240 p->WriteAs = WriteAs; 1241 1242 if (xValue != NULL) { 1243 1244 p->Value = AllocString(it8, xValue); 1245 } 1246 else { 1247 p->Value = NULL; 1248 } 1249 1250 return p; 1251} 1252 1253static 1254KEYVALUE* AddAvailableProperty(cmsIT8* it8, const char* Key, WRITEMODE as) 1255{ 1256 return AddToList(it8, &it8->ValidKeywords, Key, NULL, NULL, as); 1257} 1258 1259 1260static 1261KEYVALUE* AddAvailableSampleID(cmsIT8* it8, const char* Key) 1262{ 1263 return AddToList(it8, &it8->ValidSampleID, Key, NULL, NULL, WRITE_UNCOOKED); 1264} 1265 1266 1267static 1268void AllocTable(cmsIT8* it8) 1269{ 1270 TABLE* t; 1271 1272 t = it8 ->Tab + it8 ->TablesCount; 1273 1274 t->HeaderList = NULL; 1275 t->DataFormat = NULL; 1276 t->Data = NULL; 1277 1278 it8 ->TablesCount++; 1279} 1280 1281 1282cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) 1283{ 1284 cmsIT8* it8 = (cmsIT8*) IT8; 1285 1286 if (nTable >= it8 ->TablesCount) { 1287 1288 if (nTable == it8 ->TablesCount) { 1289 1290 AllocTable(it8); 1291 } 1292 else { 1293 SynError(it8, "Table %d is out of sequence", nTable); 1294 return -1; 1295 } 1296 } 1297 1298 it8 ->nTable = nTable; 1299 1300 return (cmsInt32Number) nTable; 1301} 1302 1303 1304 1305// Init an empty container 1306cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) 1307{ 1308 cmsIT8* it8; 1309 cmsUInt32Number i; 1310 1311 it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8)); 1312 if (it8 == NULL) return NULL; 1313 1314 AllocTable(it8); 1315 1316 it8->MemoryBlock = NULL; 1317 it8->MemorySink = NULL; 1318 1319 it8 ->nTable = 0; 1320 1321 it8->ContextID = ContextID; 1322 it8->Allocator.Used = 0; 1323 it8->Allocator.Block = NULL; 1324 it8->Allocator.BlockSize = 0; 1325 1326 it8->ValidKeywords = NULL; 1327 it8->ValidSampleID = NULL; 1328 1329 it8 -> sy = SUNDEFINED; 1330 it8 -> ch = ' '; 1331 it8 -> Source = NULL; 1332 it8 -> inum = 0; 1333 it8 -> dnum = 0.0; 1334 1335 it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX)); 1336 it8->IncludeSP = 0; 1337 it8 -> lineno = 1; 1338 1339 strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); 1340 cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17"); 1341 1342 // Initialize predefined properties & data 1343 1344 for (i=0; i < NUMPREDEFINEDPROPS; i++) 1345 AddAvailableProperty(it8, PredefinedProperties[i].id, PredefinedProperties[i].as); 1346 1347 for (i=0; i < NUMPREDEFINEDSAMPLEID; i++) 1348 AddAvailableSampleID(it8, PredefinedSampleID[i]); 1349 1350 1351 return (cmsHANDLE) it8; 1352} 1353 1354 1355const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8) 1356{ 1357 return GetTable((cmsIT8*) hIT8)->SheetType; 1358} 1359 1360cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type) 1361{ 1362 TABLE* t = GetTable((cmsIT8*) hIT8); 1363 1364 strncpy(t ->SheetType, Type, MAXSTR-1); 1365 t ->SheetType[MAXSTR-1] = 0; 1366 return TRUE; 1367} 1368 1369cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val) 1370{ 1371 cmsIT8* it8 = (cmsIT8*) hIT8; 1372 1373 if (!Val) return FALSE; 1374 if (!*Val) return FALSE; 1375 1376 return AddToList(it8, &GetTable(it8)->HeaderList, "# ", NULL, Val, WRITE_UNCOOKED) != NULL; 1377} 1378 1379// Sets a property 1380cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const char *Val) 1381{ 1382 cmsIT8* it8 = (cmsIT8*) hIT8; 1383 1384 if (!Val) return FALSE; 1385 if (!*Val) return FALSE; 1386 1387 return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Val, WRITE_STRINGIFY) != NULL; 1388} 1389 1390cmsBool CMSEXPORT cmsIT8SetPropertyDbl(cmsHANDLE hIT8, const char* cProp, cmsFloat64Number Val) 1391{ 1392 cmsIT8* it8 = (cmsIT8*) hIT8; 1393 char Buffer[1024]; 1394 1395 sprintf(Buffer, it8->DoubleFormatter, Val); 1396 1397 return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_UNCOOKED) != NULL; 1398} 1399 1400cmsBool CMSEXPORT cmsIT8SetPropertyHex(cmsHANDLE hIT8, const char* cProp, cmsUInt32Number Val) 1401{ 1402 cmsIT8* it8 = (cmsIT8*) hIT8; 1403 char Buffer[1024]; 1404 1405 sprintf(Buffer, "%u", Val); 1406 1407 return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; 1408} 1409 1410cmsBool CMSEXPORT cmsIT8SetPropertyUncooked(cmsHANDLE hIT8, const char* Key, const char* Buffer) 1411{ 1412 cmsIT8* it8 = (cmsIT8*) hIT8; 1413 1414 return AddToList(it8, &GetTable(it8)->HeaderList, Key, NULL, Buffer, WRITE_UNCOOKED) != NULL; 1415} 1416 1417cmsBool CMSEXPORT cmsIT8SetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char* SubKey, const char *Buffer) 1418{ 1419 cmsIT8* it8 = (cmsIT8*) hIT8; 1420 1421 return AddToList(it8, &GetTable(it8)->HeaderList, Key, SubKey, Buffer, WRITE_PAIR) != NULL; 1422} 1423 1424// Gets a property 1425const char* CMSEXPORT cmsIT8GetProperty(cmsHANDLE hIT8, const char* Key) 1426{ 1427 cmsIT8* it8 = (cmsIT8*) hIT8; 1428 KEYVALUE* p; 1429 1430 if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, NULL, &p)) 1431 { 1432 return p -> Value; 1433 } 1434 return NULL; 1435} 1436 1437 1438cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cProp) 1439{ 1440 const char *v = cmsIT8GetProperty(hIT8, cProp); 1441 1442 if (v == NULL) return 0.0; 1443 1444 return ParseFloatNumber(v); 1445} 1446 1447const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey) 1448{ 1449 cmsIT8* it8 = (cmsIT8*) hIT8; 1450 KEYVALUE* p; 1451 1452 if (IsAvailableOnList(GetTable(it8) -> HeaderList, Key, SubKey, &p)) { 1453 return p -> Value; 1454 } 1455 return NULL; 1456} 1457 1458// ----------------------------------------------------------------- Datasets 1459 1460 1461static 1462void AllocateDataFormat(cmsIT8* it8) 1463{ 1464 TABLE* t = GetTable(it8); 1465 1466 if (t -> DataFormat) return; // Already allocated 1467 1468 t -> nSamples = (int) cmsIT8GetPropertyDbl(it8, "NUMBER_OF_FIELDS"); 1469 1470 if (t -> nSamples <= 0) { 1471 1472 SynError(it8, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS"); 1473 t -> nSamples = 10; 1474 } 1475 1476 t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *)); 1477 if (t->DataFormat == NULL) { 1478 1479 SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); 1480 } 1481 1482} 1483 1484static 1485const char *GetDataFormat(cmsIT8* it8, int n) 1486{ 1487 TABLE* t = GetTable(it8); 1488 1489 if (t->DataFormat) 1490 return t->DataFormat[n]; 1491 1492 return NULL; 1493} 1494 1495static 1496cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) 1497{ 1498 TABLE* t = GetTable(it8); 1499 1500 if (!t->DataFormat) 1501 AllocateDataFormat(it8); 1502 1503 if (n > t -> nSamples) { 1504 SynError(it8, "More than NUMBER_OF_FIELDS fields."); 1505 return FALSE; 1506 } 1507 1508 if (t->DataFormat) { 1509 t->DataFormat[n] = AllocString(it8, label); 1510 } 1511 1512 return TRUE; 1513} 1514 1515 1516cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample) 1517{ 1518 cmsIT8* it8 = (cmsIT8*) h; 1519 return SetDataFormat(it8, n, Sample); 1520} 1521 1522static 1523void AllocateDataSet(cmsIT8* it8) 1524{ 1525 TABLE* t = GetTable(it8); 1526 1527 if (t -> Data) return; // Already allocated 1528 1529 t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); 1530 t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); 1531 1532 t-> Data = (char**)AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * ((cmsUInt32Number) t->nPatches + 1) *sizeof (char*)); 1533 if (t->Data == NULL) { 1534 1535 SynError(it8, "AllocateDataSet: Unable to allocate data array"); 1536 } 1537 1538} 1539 1540static 1541char* GetData(cmsIT8* it8, int nSet, int nField) 1542{ 1543 TABLE* t = GetTable(it8); 1544 int nSamples = t -> nSamples; 1545 int nPatches = t -> nPatches; 1546 1547 if (nSet >= nPatches || nField >= nSamples) 1548 return NULL; 1549 1550 if (!t->Data) return NULL; 1551 return t->Data [nSet * nSamples + nField]; 1552} 1553 1554static 1555cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val) 1556{ 1557 TABLE* t = GetTable(it8); 1558 1559 if (!t->Data) 1560 AllocateDataSet(it8); 1561 1562 if (!t->Data) return FALSE; 1563 1564 if (nSet > t -> nPatches || nSet < 0) { 1565 1566 return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches); 1567 } 1568 1569 if (nField > t ->nSamples || nField < 0) { 1570 return SynError(it8, "Sample %d out of range, there are %d samples", nField, t ->nSamples); 1571 1572 } 1573 1574 t->Data [nSet * t -> nSamples + nField] = AllocString(it8, Val); 1575 return TRUE; 1576} 1577 1578 1579// --------------------------------------------------------------- File I/O 1580 1581 1582// Writes a string to file 1583static 1584void WriteStr(SAVESTREAM* f, const char *str) 1585{ 1586 cmsUInt32Number len; 1587 1588 if (str == NULL) 1589 str = " "; 1590 1591 // Length to write 1592 len = (cmsUInt32Number) strlen(str); 1593 f ->Used += len; 1594 1595 1596 if (f ->stream) { // Should I write it to a file? 1597 1598 if (fwrite(str, 1, len, f->stream) != len) { 1599 cmsSignalError(0, cmsERROR_WRITE, "Write to file error in CGATS parser"); 1600 return; 1601 } 1602 1603 } 1604 else { // Or to a memory block? 1605 1606 if (f ->Base) { // Am I just counting the bytes? 1607 1608 if (f ->Used > f ->Max) { 1609 1610 cmsSignalError(0, cmsERROR_WRITE, "Write to memory overflows in CGATS parser"); 1611 return; 1612 } 1613 1614 memmove(f ->Ptr, str, len); 1615 f->Ptr += len; 1616 } 1617 1618 } 1619} 1620 1621 1622// Write formatted 1623 1624static 1625void Writef(SAVESTREAM* f, const char* frm, ...) 1626{ 1627 char Buffer[4096]; 1628 va_list args; 1629 1630 va_start(args, frm); 1631 vsnprintf(Buffer, 4095, frm, args); 1632 Buffer[4095] = 0; 1633 WriteStr(f, Buffer); 1634 va_end(args); 1635 1636} 1637 1638// Writes full header 1639static 1640void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) 1641{ 1642 KEYVALUE* p; 1643 TABLE* t = GetTable(it8); 1644 1645 // Writes the type 1646 WriteStr(fp, t->SheetType); 1647 WriteStr(fp, "\n"); 1648 1649 for (p = t->HeaderList; (p != NULL); p = p->Next) 1650 { 1651 if (*p ->Keyword == '#') { 1652 1653 char* Pt; 1654 1655 WriteStr(fp, "#\n# "); 1656 for (Pt = p ->Value; *Pt; Pt++) { 1657 1658 1659 Writef(fp, "%c", *Pt); 1660 1661 if (*Pt == '\n') { 1662 WriteStr(fp, "# "); 1663 } 1664 } 1665 1666 WriteStr(fp, "\n#\n"); 1667 continue; 1668 } 1669 1670 1671 if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL, NULL)) { 1672 1673#ifdef CMS_STRICT_CGATS 1674 WriteStr(fp, "KEYWORD\t\""); 1675 WriteStr(fp, p->Keyword); 1676 WriteStr(fp, "\"\n"); 1677#endif 1678 1679 AddAvailableProperty(it8, p->Keyword, WRITE_UNCOOKED); 1680 } 1681 1682 WriteStr(fp, p->Keyword); 1683 if (p->Value) { 1684 1685 switch (p ->WriteAs) { 1686 1687 case WRITE_UNCOOKED: 1688 Writef(fp, "\t%s", p ->Value); 1689 break; 1690 1691 case WRITE_STRINGIFY: 1692 Writef(fp, "\t\"%s\"", p->Value ); 1693 break; 1694 1695 case WRITE_HEXADECIMAL: 1696 Writef(fp, "\t0x%X", atoi(p ->Value)); 1697 break; 1698 1699 case WRITE_BINARY: 1700 Writef(fp, "\t0x%B", atoi(p ->Value)); 1701 break; 1702 1703 case WRITE_PAIR: 1704 Writef(fp, "\t\"%s,%s\"", p->Subkey, p->Value); 1705 break; 1706 1707 default: SynError(it8, "Unknown write mode %d", p ->WriteAs); 1708 return; 1709 } 1710 } 1711 1712 WriteStr (fp, "\n"); 1713 } 1714 1715} 1716 1717 1718// Writes the data format 1719static 1720void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) 1721{ 1722 int i, nSamples; 1723 TABLE* t = GetTable(it8); 1724 1725 if (!t -> DataFormat) return; 1726 1727 WriteStr(fp, "BEGIN_DATA_FORMAT\n"); 1728 WriteStr(fp, " "); 1729 nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); 1730 1731 for (i = 0; i < nSamples; i++) { 1732 1733 WriteStr(fp, t->DataFormat[i]); 1734 WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t")); 1735 } 1736 1737 WriteStr (fp, "END_DATA_FORMAT\n"); 1738} 1739 1740 1741// Writes data array 1742static 1743void WriteData(SAVESTREAM* fp, cmsIT8* it8) 1744{ 1745 int i, j; 1746 TABLE* t = GetTable(it8); 1747 1748 if (!t->Data) return; 1749 1750 WriteStr (fp, "BEGIN_DATA\n"); 1751 1752 t->nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); 1753 1754 for (i = 0; i < t-> nPatches; i++) { 1755 1756 WriteStr(fp, " "); 1757 1758 for (j = 0; j < t->nSamples; j++) { 1759 1760 char *ptr = t->Data[i*t->nSamples+j]; 1761 1762 if (ptr == NULL) WriteStr(fp, "\"\""); 1763 else { 1764 // If value contains whitespace, enclose within quote 1765 1766 if (strchr(ptr, ' ') != NULL) { 1767 1768 WriteStr(fp, "\""); 1769 WriteStr(fp, ptr); 1770 WriteStr(fp, "\""); 1771 } 1772 else 1773 WriteStr(fp, ptr); 1774 } 1775 1776 WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t")); 1777 } 1778 } 1779 WriteStr (fp, "END_DATA\n"); 1780} 1781 1782 1783 1784// Saves whole file 1785cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) 1786{ 1787 SAVESTREAM sd; 1788 cmsUInt32Number i; 1789 cmsIT8* it8 = (cmsIT8*) hIT8; 1790 1791 memset(&sd, 0, sizeof(sd)); 1792 1793 sd.stream = fopen(cFileName, "wt"); 1794 if (!sd.stream) return FALSE; 1795 1796 for (i=0; i < it8 ->TablesCount; i++) { 1797 1798 cmsIT8SetTable(hIT8, i); 1799 WriteHeader(it8, &sd); 1800 WriteDataFormat(&sd, it8); 1801 WriteData(&sd, it8); 1802 } 1803 1804 if (fclose(sd.stream) != 0) return FALSE; 1805 1806 return TRUE; 1807} 1808 1809 1810// Saves to memory 1811cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded) 1812{ 1813 SAVESTREAM sd; 1814 cmsUInt32Number i; 1815 cmsIT8* it8 = (cmsIT8*) hIT8; 1816 1817 memset(&sd, 0, sizeof(sd)); 1818 1819 sd.stream = NULL; 1820 sd.Base = (cmsUInt8Number*) MemPtr; 1821 sd.Ptr = sd.Base; 1822 1823 sd.Used = 0; 1824 1825 if (sd.Base) 1826 sd.Max = *BytesNeeded; // Write to memory? 1827 else 1828 sd.Max = 0; // Just counting the needed bytes 1829 1830 for (i=0; i < it8 ->TablesCount; i++) { 1831 1832 cmsIT8SetTable(hIT8, i); 1833 WriteHeader(it8, &sd); 1834 WriteDataFormat(&sd, it8); 1835 WriteData(&sd, it8); 1836 } 1837 1838 sd.Used++; // The \0 at the very end 1839 1840 if (sd.Base) 1841 *sd.Ptr = 0; 1842 1843 *BytesNeeded = sd.Used; 1844 1845 return TRUE; 1846} 1847 1848 1849// -------------------------------------------------------------- Higer level parsing 1850 1851static 1852cmsBool DataFormatSection(cmsIT8* it8) 1853{ 1854 int iField = 0; 1855 TABLE* t = GetTable(it8); 1856 1857 InSymbol(it8); // Eats "BEGIN_DATA_FORMAT" 1858 CheckEOLN(it8); 1859 1860 while (it8->sy != SEND_DATA_FORMAT && 1861 it8->sy != SEOLN && 1862 it8->sy != SEOF && 1863 it8->sy != SSYNERROR) { 1864 1865 if (it8->sy != SIDENT) { 1866 1867 return SynError(it8, "Sample type expected"); 1868 } 1869 1870 if (!SetDataFormat(it8, iField, it8->id)) return FALSE; 1871 iField++; 1872 1873 InSymbol(it8); 1874 SkipEOLN(it8); 1875 } 1876 1877 SkipEOLN(it8); 1878 Skip(it8, SEND_DATA_FORMAT); 1879 SkipEOLN(it8); 1880 1881 if (iField != t ->nSamples) { 1882 SynError(it8, "Count mismatch. NUMBER_OF_FIELDS was %d, found %d\n", t ->nSamples, iField); 1883 1884 1885 } 1886 1887 return TRUE; 1888} 1889 1890 1891 1892static 1893cmsBool DataSection (cmsIT8* it8) 1894{ 1895 int iField = 0; 1896 int iSet = 0; 1897 char Buffer[256]; 1898 TABLE* t = GetTable(it8); 1899 1900 InSymbol(it8); // Eats "BEGIN_DATA" 1901 CheckEOLN(it8); 1902 1903 if (!t->Data) 1904 AllocateDataSet(it8); 1905 1906 while (it8->sy != SEND_DATA && it8->sy != SEOF) 1907 { 1908 if (iField >= t -> nSamples) { 1909 iField = 0; 1910 iSet++; 1911 1912 } 1913 1914 if (it8->sy != SEND_DATA && it8->sy != SEOF) { 1915 1916 if (!GetVal(it8, Buffer, 255, "Sample data expected")) 1917 return FALSE; 1918 1919 if (!SetData(it8, iSet, iField, Buffer)) 1920 return FALSE; 1921 1922 iField++; 1923 1924 InSymbol(it8); 1925 SkipEOLN(it8); 1926 } 1927 } 1928 1929 SkipEOLN(it8); 1930 Skip(it8, SEND_DATA); 1931 SkipEOLN(it8); 1932 1933 // Check for data completion. 1934 1935 if ((iSet+1) != t -> nPatches) 1936 return SynError(it8, "Count mismatch. NUMBER_OF_SETS was %d, found %d\n", t ->nPatches, iSet+1); 1937 1938 return TRUE; 1939} 1940 1941 1942 1943 1944static 1945cmsBool HeaderSection(cmsIT8* it8) 1946{ 1947 char VarName[MAXID]; 1948 char Buffer[MAXSTR]; 1949 KEYVALUE* Key; 1950 1951 while (it8->sy != SEOF && 1952 it8->sy != SSYNERROR && 1953 it8->sy != SBEGIN_DATA_FORMAT && 1954 it8->sy != SBEGIN_DATA) { 1955 1956 1957 switch (it8 -> sy) { 1958 1959 case SKEYWORD: 1960 InSymbol(it8); 1961 if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; 1962 if (!AddAvailableProperty(it8, Buffer, WRITE_UNCOOKED)) return FALSE; 1963 InSymbol(it8); 1964 break; 1965 1966 1967 case SDATA_FORMAT_ID: 1968 InSymbol(it8); 1969 if (!GetVal(it8, Buffer, MAXSTR-1, "Keyword expected")) return FALSE; 1970 if (!AddAvailableSampleID(it8, Buffer)) return FALSE; 1971 InSymbol(it8); 1972 break; 1973 1974 1975 case SIDENT: 1976 strncpy(VarName, it8->id, MAXID-1); 1977 VarName[MAXID-1] = 0; 1978 1979 if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) { 1980 1981#ifdef CMS_STRICT_CGATS 1982 return SynError(it8, "Undefined keyword '%s'", VarName); 1983#else 1984 Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED); 1985 if (Key == NULL) return FALSE; 1986#endif 1987 } 1988 1989 InSymbol(it8); 1990 if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE; 1991 1992 if(Key->WriteAs != WRITE_PAIR) { 1993 AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer, 1994 (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED); 1995 } 1996 else { 1997 const char *Subkey; 1998 char *Nextkey; 1999 if (it8->sy != SSTRING) 2000 return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName); 2001 2002 // chop the string as a list of "subkey, value" pairs, using ';' as a separator 2003 for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey) 2004 { 2005 char *Value, *temp; 2006 2007 // identify token pair boundary 2008 Nextkey = (char*) strchr(Subkey, ';'); 2009 if(Nextkey) 2010 *Nextkey++ = '\0'; 2011 2012 // for each pair, split the subkey and the value 2013 Value = (char*) strrchr(Subkey, ','); 2014 if(Value == NULL) 2015 return SynError(it8, "Invalid value for property '%s'.", VarName); 2016 2017 // gobble the spaces before the coma, and the coma itself 2018 temp = Value++; 2019 do *temp-- = '\0'; while(temp >= Subkey && *temp == ' '); 2020 2021 // gobble any space at the right 2022 temp = Value + strlen(Value) - 1; 2023 while(*temp == ' ') *temp-- = '\0'; 2024 2025 // trim the strings from the left 2026 Subkey += strspn(Subkey, " "); 2027 Value += strspn(Value, " "); 2028 2029 if(Subkey[0] == 0 || Value[0] == 0) 2030 return SynError(it8, "Invalid value for property '%s'.", VarName); 2031 AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR); 2032 } 2033 } 2034 2035 InSymbol(it8); 2036 break; 2037 2038 2039 case SEOLN: break; 2040 2041 default: 2042 return SynError(it8, "expected keyword or identifier"); 2043 } 2044 2045 SkipEOLN(it8); 2046 } 2047 2048 return TRUE; 2049 2050} 2051 2052 2053static 2054void ReadType(cmsIT8* it8, char* SheetTypePtr) 2055{ 2056 // First line is a very special case. 2057 2058 while (isseparator(it8->ch)) 2059 NextCh(it8); 2060 2061 while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != -1) { 2062 2063 *SheetTypePtr++= (char) it8 ->ch; 2064 NextCh(it8); 2065 } 2066 2067 *SheetTypePtr = 0; 2068} 2069 2070 2071static 2072cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) 2073{ 2074 char* SheetTypePtr = it8 ->Tab[0].SheetType; 2075 2076 if (nosheet == 0) { 2077 ReadType(it8, SheetTypePtr); 2078 } 2079 2080 InSymbol(it8); 2081 2082 SkipEOLN(it8); 2083 2084 while (it8-> sy != SEOF && 2085 it8-> sy != SSYNERROR) { 2086 2087 switch (it8 -> sy) { 2088 2089 case SBEGIN_DATA_FORMAT: 2090 if (!DataFormatSection(it8)) return FALSE; 2091 break; 2092 2093 case SBEGIN_DATA: 2094 2095 if (!DataSection(it8)) return FALSE; 2096 2097 if (it8 -> sy != SEOF) { 2098 2099 AllocTable(it8); 2100 it8 ->nTable = it8 ->TablesCount - 1; 2101 2102 // Read sheet type if present. We only support identifier and string. 2103 // <ident> <eoln> is a type string 2104 // anything else, is not a type string 2105 if (nosheet == 0) { 2106 2107 if (it8 ->sy == SIDENT) { 2108 2109 // May be a type sheet or may be a prop value statement. We cannot use insymbol in 2110 // this special case... 2111 while (isseparator(it8->ch)) 2112 NextCh(it8); 2113 2114 // If a newline is found, then this is a type string 2115 if (it8 ->ch == '\n' || it8->ch == '\r') { 2116 2117 cmsIT8SetSheetType(it8, it8 ->id); 2118 InSymbol(it8); 2119 } 2120 else 2121 { 2122 // It is not. Just continue 2123 cmsIT8SetSheetType(it8, ""); 2124 } 2125 } 2126 else 2127 // Validate quoted strings 2128 if (it8 ->sy == SSTRING) { 2129 cmsIT8SetSheetType(it8, it8 ->str); 2130 InSymbol(it8); 2131 } 2132 } 2133 2134 } 2135 break; 2136 2137 case SEOLN: 2138 SkipEOLN(it8); 2139 break; 2140 2141 default: 2142 if (!HeaderSection(it8)) return FALSE; 2143 } 2144 2145 } 2146 2147 return (it8 -> sy != SSYNERROR); 2148} 2149 2150 2151 2152// Init usefull pointers 2153 2154static 2155void CookPointers(cmsIT8* it8) 2156{ 2157 int idField, i; 2158 char* Fld; 2159 cmsUInt32Number j; 2160 cmsUInt32Number nOldTable = it8 ->nTable; 2161 2162 for (j=0; j < it8 ->TablesCount; j++) { 2163 2164 TABLE* t = it8 ->Tab + j; 2165 2166 t -> SampleID = 0; 2167 it8 ->nTable = j; 2168 2169 for (idField = 0; idField < t -> nSamples; idField++) 2170 { 2171 if (t ->DataFormat == NULL){ 2172 SynError(it8, "Undefined DATA_FORMAT"); 2173 return; 2174 } 2175 2176 Fld = t->DataFormat[idField]; 2177 if (!Fld) continue; 2178 2179 2180 if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { 2181 2182 t -> SampleID = idField; 2183 2184 for (i=0; i < t -> nPatches; i++) { 2185 2186 char *Data = GetData(it8, i, idField); 2187 if (Data) { 2188 char Buffer[256]; 2189 2190 strncpy(Buffer, Data, 255); 2191 Buffer[255] = 0; 2192 2193 if (strlen(Buffer) <= strlen(Data)) 2194 strcpy(Data, Buffer); 2195 else 2196 SetData(it8, i, idField, Buffer); 2197 2198 } 2199 } 2200 2201 } 2202 2203 // "LABEL" is an extension. It keeps references to forward tables 2204 2205 if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$' ) { 2206 2207 // Search for table references... 2208 for (i=0; i < t -> nPatches; i++) { 2209 2210 char *Label = GetData(it8, i, idField); 2211 2212 if (Label) { 2213 2214 cmsUInt32Number k; 2215 2216 // This is the label, search for a table containing 2217 // this property 2218 2219 for (k=0; k < it8 ->TablesCount; k++) { 2220 2221 TABLE* Table = it8 ->Tab + k; 2222 KEYVALUE* p; 2223 2224 if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { 2225 2226 // Available, keep type and table 2227 char Buffer[256]; 2228 2229 char *Type = p ->Value; 2230 int nTable = (int) k; 2231 2232 snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); 2233 2234 SetData(it8, i, idField, Buffer); 2235 } 2236 } 2237 2238 2239 } 2240 2241 } 2242 2243 2244 } 2245 2246 } 2247 } 2248 2249 it8 ->nTable = nOldTable; 2250} 2251 2252// Try to infere if the file is a CGATS/IT8 file at all. Read first line 2253// that should be something like some printable characters plus a \n 2254// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line? 2255static 2256int IsMyBlock(cmsUInt8Number* Buffer, int n) 2257{ 2258 int words = 1, space = 0, quot = 0; 2259 int i; 2260 2261 if (n < 10) return 0; // Too small 2262 2263 if (n > 132) 2264 n = 132; 2265 2266 for (i = 1; i < n; i++) { 2267 2268 switch(Buffer[i]) 2269 { 2270 case '\n': 2271 case '\r': 2272 return ((quot == 1) || (words > 2)) ? 0 : words; 2273 case '\t': 2274 case ' ': 2275 if(!quot && !space) 2276 space = 1; 2277 break; 2278 case '\"': 2279 quot = !quot; 2280 break; 2281 default: 2282 if (Buffer[i] < 32) return 0; 2283 if (Buffer[i] > 127) return 0; 2284 words += space; 2285 space = 0; 2286 break; 2287 } 2288 } 2289 2290 return 0; 2291} 2292 2293 2294static 2295cmsBool IsMyFile(const char* FileName) 2296{ 2297 FILE *fp; 2298 cmsUInt32Number Size; 2299 cmsUInt8Number Ptr[133]; 2300 2301 fp = fopen(FileName, "rt"); 2302 if (!fp) { 2303 cmsSignalError(0, cmsERROR_FILE, "File '%s' not found", FileName); 2304 return FALSE; 2305 } 2306 2307 Size = (cmsUInt32Number) fread(Ptr, 1, 132, fp); 2308 2309 if (fclose(fp) != 0) 2310 return FALSE; 2311 2312 Ptr[Size] = '\0'; 2313 2314 return IsMyBlock(Ptr, Size); 2315} 2316 2317// ---------------------------------------------------------- Exported routines 2318 2319 2320cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, void *Ptr, cmsUInt32Number len) 2321{ 2322 cmsHANDLE hIT8; 2323 cmsIT8* it8; 2324 int type; 2325 2326 _cmsAssert(Ptr != NULL); 2327 _cmsAssert(len != 0); 2328 2329 type = IsMyBlock((cmsUInt8Number*)Ptr, len); 2330 if (type == 0) return NULL; 2331 2332 hIT8 = cmsIT8Alloc(ContextID); 2333 if (!hIT8) return NULL; 2334 2335 it8 = (cmsIT8*) hIT8; 2336 it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1); 2337 2338 strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); 2339 it8 ->MemoryBlock[len] = 0; 2340 2341 strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1); 2342 it8-> Source = it8 -> MemoryBlock; 2343 2344 if (!ParseIT8(it8, type-1)) { 2345 2346 cmsIT8Free(hIT8); 2347 return FALSE; 2348 } 2349 2350 CookPointers(it8); 2351 it8 ->nTable = 0; 2352 2353 _cmsFree(ContextID, it8->MemoryBlock); 2354 it8 -> MemoryBlock = NULL; 2355 2356 return hIT8; 2357 2358 2359} 2360 2361 2362cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName) 2363{ 2364 2365 cmsHANDLE hIT8; 2366 cmsIT8* it8; 2367 int type; 2368 2369 _cmsAssert(cFileName != NULL); 2370 2371 type = IsMyFile(cFileName); 2372 if (type == 0) return NULL; 2373 2374 hIT8 = cmsIT8Alloc(ContextID); 2375 it8 = (cmsIT8*) hIT8; 2376 if (!hIT8) return NULL; 2377 2378 2379 it8 ->FileStack[0]->Stream = fopen(cFileName, "rt"); 2380 2381 if (!it8 ->FileStack[0]->Stream) { 2382 cmsIT8Free(hIT8); 2383 return NULL; 2384 } 2385 2386 2387 strncpy(it8->FileStack[0]->FileName, cFileName, cmsMAX_PATH-1); 2388 it8->FileStack[0]->FileName[cmsMAX_PATH-1] = 0; 2389 2390 if (!ParseIT8(it8, type-1)) { 2391 2392 fclose(it8 ->FileStack[0]->Stream); 2393 cmsIT8Free(hIT8); 2394 return NULL; 2395 } 2396 2397 CookPointers(it8); 2398 it8 ->nTable = 0; 2399 2400 if (fclose(it8 ->FileStack[0]->Stream)!= 0) { 2401 cmsIT8Free(hIT8); 2402 return NULL; 2403 } 2404 2405 return hIT8; 2406 2407} 2408 2409int CMSEXPORT cmsIT8EnumDataFormat(cmsHANDLE hIT8, char ***SampleNames) 2410{ 2411 cmsIT8* it8 = (cmsIT8*) hIT8; 2412 TABLE* t; 2413 2414 _cmsAssert(hIT8 != NULL); 2415 2416 t = GetTable(it8); 2417 2418 if (SampleNames) 2419 *SampleNames = t -> DataFormat; 2420 return t -> nSamples; 2421} 2422 2423 2424cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames) 2425{ 2426 cmsIT8* it8 = (cmsIT8*) hIT8; 2427 KEYVALUE* p; 2428 cmsUInt32Number n; 2429 char **Props; 2430 TABLE* t; 2431 2432 _cmsAssert(hIT8 != NULL); 2433 2434 t = GetTable(it8); 2435 2436 // Pass#1 - count properties 2437 2438 n = 0; 2439 for (p = t -> HeaderList; p != NULL; p = p->Next) { 2440 n++; 2441 } 2442 2443 2444 Props = (char **) AllocChunk(it8, sizeof(char *) * n); 2445 2446 // Pass#2 - Fill pointers 2447 n = 0; 2448 for (p = t -> HeaderList; p != NULL; p = p->Next) { 2449 Props[n++] = p -> Keyword; 2450 } 2451 2452 *PropertyNames = Props; 2453 return n; 2454} 2455 2456cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames) 2457{ 2458 cmsIT8* it8 = (cmsIT8*) hIT8; 2459 KEYVALUE *p, *tmp; 2460 cmsUInt32Number n; 2461 const char **Props; 2462 TABLE* t; 2463 2464 _cmsAssert(hIT8 != NULL); 2465 2466 2467 t = GetTable(it8); 2468 2469 if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) { 2470 *SubpropertyNames = 0; 2471 return 0; 2472 } 2473 2474 // Pass#1 - count properties 2475 2476 n = 0; 2477 for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { 2478 if(tmp->Subkey != NULL) 2479 n++; 2480 } 2481 2482 2483 Props = (const char **) AllocChunk(it8, sizeof(char *) * n); 2484 2485 // Pass#2 - Fill pointers 2486 n = 0; 2487 for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) { 2488 if(tmp->Subkey != NULL) 2489 Props[n++] = p ->Subkey; 2490 } 2491 2492 *SubpropertyNames = Props; 2493 return n; 2494} 2495 2496static 2497int LocatePatch(cmsIT8* it8, const char* cPatch) 2498{ 2499 int i; 2500 const char *data; 2501 TABLE* t = GetTable(it8); 2502 2503 for (i=0; i < t-> nPatches; i++) { 2504 2505 data = GetData(it8, i, t->SampleID); 2506 2507 if (data != NULL) { 2508 2509 if (cmsstrcasecmp(data, cPatch) == 0) 2510 return i; 2511 } 2512 } 2513 2514 // SynError(it8, "Couldn't find patch '%s'\n", cPatch); 2515 return -1; 2516} 2517 2518 2519static 2520int LocateEmptyPatch(cmsIT8* it8) 2521{ 2522 int i; 2523 const char *data; 2524 TABLE* t = GetTable(it8); 2525 2526 for (i=0; i < t-> nPatches; i++) { 2527 2528 data = GetData(it8, i, t->SampleID); 2529 2530 if (data == NULL) 2531 return i; 2532 2533 } 2534 2535 return -1; 2536} 2537 2538static 2539int LocateSample(cmsIT8* it8, const char* cSample) 2540{ 2541 int i; 2542 const char *fld; 2543 TABLE* t = GetTable(it8); 2544 2545 for (i=0; i < t->nSamples; i++) { 2546 2547 fld = GetDataFormat(it8, i); 2548 if (cmsstrcasecmp(fld, cSample) == 0) 2549 return i; 2550 } 2551 2552 return -1; 2553 2554} 2555 2556 2557int CMSEXPORT cmsIT8FindDataFormat(cmsHANDLE hIT8, const char* cSample) 2558{ 2559 cmsIT8* it8 = (cmsIT8*) hIT8; 2560 2561 _cmsAssert(hIT8 != NULL); 2562 2563 return LocateSample(it8, cSample); 2564} 2565 2566 2567 2568const char* CMSEXPORT cmsIT8GetDataRowCol(cmsHANDLE hIT8, int row, int col) 2569{ 2570 cmsIT8* it8 = (cmsIT8*) hIT8; 2571 2572 _cmsAssert(hIT8 != NULL); 2573 2574 return GetData(it8, row, col); 2575} 2576 2577 2578cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int col) 2579{ 2580 const char* Buffer; 2581 2582 Buffer = cmsIT8GetDataRowCol(hIT8, row, col); 2583 2584 if (Buffer == NULL) return 0.0; 2585 2586 return ParseFloatNumber(Buffer); 2587} 2588 2589 2590cmsBool CMSEXPORT cmsIT8SetDataRowCol(cmsHANDLE hIT8, int row, int col, const char* Val) 2591{ 2592 cmsIT8* it8 = (cmsIT8*) hIT8; 2593 2594 _cmsAssert(hIT8 != NULL); 2595 2596 return SetData(it8, row, col, Val); 2597} 2598 2599 2600cmsBool CMSEXPORT cmsIT8SetDataRowColDbl(cmsHANDLE hIT8, int row, int col, cmsFloat64Number Val) 2601{ 2602 cmsIT8* it8 = (cmsIT8*) hIT8; 2603 char Buff[256]; 2604 2605 _cmsAssert(hIT8 != NULL); 2606 2607 sprintf(Buff, it8->DoubleFormatter, Val); 2608 2609 return SetData(it8, row, col, Buff); 2610} 2611 2612 2613 2614const char* CMSEXPORT cmsIT8GetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample) 2615{ 2616 cmsIT8* it8 = (cmsIT8*) hIT8; 2617 int iField, iSet; 2618 2619 _cmsAssert(hIT8 != NULL); 2620 2621 iField = LocateSample(it8, cSample); 2622 if (iField < 0) { 2623 return NULL; 2624 } 2625 2626 iSet = LocatePatch(it8, cPatch); 2627 if (iSet < 0) { 2628 return NULL; 2629 } 2630 2631 return GetData(it8, iSet, iField); 2632} 2633 2634 2635cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, const char* cSample) 2636{ 2637 const char* Buffer; 2638 2639 Buffer = cmsIT8GetData(it8, cPatch, cSample); 2640 2641 return ParseFloatNumber(Buffer); 2642} 2643 2644 2645 2646cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* cSample, const char *Val) 2647{ 2648 cmsIT8* it8 = (cmsIT8*) hIT8; 2649 int iField, iSet; 2650 TABLE* t; 2651 2652 _cmsAssert(hIT8 != NULL); 2653 2654 t = GetTable(it8); 2655 2656 iField = LocateSample(it8, cSample); 2657 2658 if (iField < 0) 2659 return FALSE; 2660 2661 if (t-> nPatches == 0) { 2662 2663 AllocateDataFormat(it8); 2664 AllocateDataSet(it8); 2665 CookPointers(it8); 2666 } 2667 2668 if (cmsstrcasecmp(cSample, "SAMPLE_ID") == 0) { 2669 2670 iSet = LocateEmptyPatch(it8); 2671 if (iSet < 0) { 2672 return SynError(it8, "Couldn't add more patches '%s'\n", cPatch); 2673 } 2674 2675 iField = t -> SampleID; 2676 } 2677 else { 2678 iSet = LocatePatch(it8, cPatch); 2679 if (iSet < 0) { 2680 return FALSE; 2681 } 2682 } 2683 2684 return SetData(it8, iSet, iField, Val); 2685} 2686 2687 2688cmsBool CMSEXPORT cmsIT8SetDataDbl(cmsHANDLE hIT8, const char* cPatch, 2689 const char* cSample, 2690 cmsFloat64Number Val) 2691{ 2692 cmsIT8* it8 = (cmsIT8*) hIT8; 2693 char Buff[256]; 2694 2695 _cmsAssert(hIT8 != NULL); 2696 2697 snprintf(Buff, 255, it8->DoubleFormatter, Val); 2698 return cmsIT8SetData(hIT8, cPatch, cSample, Buff); 2699} 2700 2701// Buffer should get MAXSTR at least 2702 2703const char* CMSEXPORT cmsIT8GetPatchName(cmsHANDLE hIT8, int nPatch, char* buffer) 2704{ 2705 cmsIT8* it8 = (cmsIT8*) hIT8; 2706 TABLE* t; 2707 char* Data; 2708 2709 _cmsAssert(hIT8 != NULL); 2710 2711 t = GetTable(it8); 2712 Data = GetData(it8, nPatch, t->SampleID); 2713 2714 if (!Data) return NULL; 2715 if (!buffer) return Data; 2716 2717 strncpy(buffer, Data, MAXSTR-1); 2718 buffer[MAXSTR-1] = 0; 2719 return buffer; 2720} 2721 2722int CMSEXPORT cmsIT8GetPatchByName(cmsHANDLE hIT8, const char *cPatch) 2723{ 2724 _cmsAssert(hIT8 != NULL); 2725 2726 return LocatePatch((cmsIT8*)hIT8, cPatch); 2727} 2728 2729cmsUInt32Number CMSEXPORT cmsIT8TableCount(cmsHANDLE hIT8) 2730{ 2731 cmsIT8* it8 = (cmsIT8*) hIT8; 2732 2733 _cmsAssert(hIT8 != NULL); 2734 2735 return it8 ->TablesCount; 2736} 2737 2738// This handles the "LABEL" extension. 2739// Label, nTable, Type 2740 2741int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char* cField, const char* ExpectedType) 2742{ 2743 const char* cLabelFld; 2744 char Type[256], Label[256]; 2745 int nTable; 2746 2747 _cmsAssert(hIT8 != NULL); 2748 2749 if (cField != NULL && *cField == 0) 2750 cField = "LABEL"; 2751 2752 if (cField == NULL) 2753 cField = "LABEL"; 2754 2755 cLabelFld = cmsIT8GetData(hIT8, cSet, cField); 2756 if (!cLabelFld) return -1; 2757 2758 if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3) 2759 return -1; 2760 2761 if (ExpectedType != NULL && *ExpectedType == 0) 2762 ExpectedType = NULL; 2763 2764 if (ExpectedType) { 2765 2766 if (cmsstrcasecmp(Type, ExpectedType) != 0) return -1; 2767 } 2768 2769 return cmsIT8SetTable(hIT8, nTable); 2770} 2771 2772 2773cmsBool CMSEXPORT cmsIT8SetIndexColumn(cmsHANDLE hIT8, const char* cSample) 2774{ 2775 cmsIT8* it8 = (cmsIT8*) hIT8; 2776 int pos; 2777 2778 _cmsAssert(hIT8 != NULL); 2779 2780 pos = LocateSample(it8, cSample); 2781 if(pos == -1) 2782 return FALSE; 2783 2784 it8->Tab[it8->nTable].SampleID = pos; 2785 return TRUE; 2786} 2787 2788 2789void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) 2790{ 2791 cmsIT8* it8 = (cmsIT8*) hIT8; 2792 2793 _cmsAssert(hIT8 != NULL); 2794 2795 if (Formatter == NULL) 2796 strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); 2797 else 2798 strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter)); 2799 2800 it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; 2801} 2802 2803