Subversion Repositories Scribus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2454 craig 1
//
2
//  Little cms - profiler construction set
3
//  Copyright (C) 1998-2001 Marti Maria
4
//
5
// THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
6
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
7
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
8
//
9
// IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
10
// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
11
// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
12
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
13
// LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
14
// OF THIS SOFTWARE.
15
//
16
// This file is free software; you can redistribute it and/or modify it
17
// under the terms of the GNU General Public License as published by
18
// the Free Software Foundation; either version 2 of the License, or
19
// (at your option) any later version.
20
//
21
// This program is distributed in the hope that it will be useful, but
22
// WITHOUT ANY WARRANTY; without even the implied warranty of
23
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24
// General Public License for more details.
25
//
26
// You should have received a copy of the GNU General Public License
27
// along with this program; if not, write to the Free Software
28
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
//
30
// As a special exception to the GNU General Public License, if you
31
// distribute this file as part of a program that contains a
32
// configuration script generated by Autoconf, you may include it under
33
// the same distribution terms that you use for the rest of that program.
34
//
35
// Version 1.08a
36
 
37
 
38
#include "lcmsprf.h"
39
 
40
// #define _DEBUG  1 
41
 
42
 
43
 
44
// IT8.7 / CGATS.17-200x handling
45
LCMSHANDLE      cdecl cmsxIT8Alloc(void);
46
void            cdecl cmsxIT8Free(LCMSHANDLE IT8);
47
 
48
// Persistence
49
LCMSHANDLE      cdecl cmsxIT8LoadFromFile(const char* cFileName);
50
LCMSHANDLE      cdecl cmsxIT8LoadFromMem(void *Ptr, size_t len);
51
BOOL            cdecl cmsxIT8SaveToFile(LCMSHANDLE IT8, const char* cFileName);
52
 
53
// Properties
54
const char* cdecl cmsxIT8GetSheetType(LCMSHANDLE hIT8);
55
BOOL        cdecl cmsxIT8SetSheetType(LCMSHANDLE hIT8, const char* Type);
56
 
57
BOOL        cdecl cmsxIT8SetProperty(LCMSHANDLE hIT8, const char* cProp, const char *Str);
58
BOOL        cdecl cmsxIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val);
59
 
60
const char* cdecl cmsxIT8GetProperty(LCMSHANDLE hIT8, const char* cProp);
61
double      cdecl cmsxIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp);
62
int         cdecl cmsxIT8EnumProperties(LCMSHANDLE IT8, char ***PropertyNames);
63
 
64
 
65
// Datasets
66
 
67
BOOL        cdecl cmsxIT8GetDataSetByPos(LCMSHANDLE IT8, int col, int row, char* Val, int ValBufferLen);
68
 
69
BOOL        cdecl cmsxIT8GetDataSet(LCMSHANDLE IT8, const char* cPatch,
70
                                                const char* cSample,
71
                                                char* Val, int ValBufferLen);
72
 
73
 
74
BOOL        cdecl cmsxIT8GetDataSetDbl(LCMSHANDLE IT8, const char* cPatch, const char* cSample, double* d);
75
 
76
BOOL        cdecl cmsxIT8SetDataSet(LCMSHANDLE IT8, const char* cPatch,
77
                                                const char* cSample,
78
                                                char *Val);
79
 
80
BOOL        cdecl cmsxIT8SetDataFormat(LCMSHANDLE IT8, int n, const char *Sample);
81
int         cdecl cmsxIT8EnumDataFormat(LCMSHANDLE IT8, char ***SampleNames);
82
 
83
const char *cdecl cmsxIT8GenericPatchName(int nPatch, char* buffer);
84
int         cdecl cmsxIT8GenericPatchNum(const char *Name);
85
 
86
 
87
// ------------------------------------------------------------- Implementation
88
 
89
 
90
#define MAXID   128     // Max lenght of identifier
91
#define MAXSTR  255     // Max lenght of string
92
 
93
#ifndef NON_WINDOWS
94
#include <io.h>
95
#endif
96
 
97
// Symbols
98
 
99
typedef enum { SNONE,
100
               SINUM,      // Integer
101
               SDNUM,      // Real
102
               SIDENT,     // Identifier
103
               SSTRING,    // string
104
               SCOMMENT,   // comment
105
               SEOLN,      // End of line
106
               SEOF,       // End of stream
107
               SSYNERROR,  // Syntax error found on stream
108
 
109
               // Keywords
110
 
111
               SBEGIN_DATA,
112
               SBEGIN_DATA_FORMAT,
113
               SEND_DATA,
114
               SEND_DATA_FORMAT,
115
               SKEYWORD,
116
               SSTRING_SY
117
 
118
           } SYMBOL;
119
 
120
 
121
// Linked list of variable names
122
 
123
typedef struct _KeyVal {
124
 
125
    struct _KeyVal*  Next;
126
    char*            Keyword;       // Name of variable
127
    char*            Value;         // Points to value
128
 
129
   } KEYVALUE, FAR* LPKEYVALUE;
130
 
131
// Linked list of values (Memory sink)
132
 
133
typedef struct _OwnedMem {
134
 
135
    struct _OwnedMem* Next;
136
    void *            Ptr;          // Point to value
137
 
138
   } OWNEDMEM, FAR* LPOWNEDMEM;
139
 
140
 
141
// This struct hold all information about an openened
142
// IT8 handler. Only one dataset is allowed.
143
 
144
typedef struct {
145
 
146
    int            nSamples, nPatches;    // Rows, Cols
147
    int            SampleID;              // Pos of ID
148
    LPKEYVALUE     HeaderList;            // The properties
149
    char*          FileBuffer;            // The ASCII stream
150
    char**         DataFormat;            // The binary stream descriptor
151
    char**         Data;                  // The binary stream
152
    LPOWNEDMEM     MemorySink;            // The storage bakend
153
 
154
    // Parser state machine
155
 
156
    SYMBOL         sy;              // Current symbol
157
    int            ch;              // Current character
158
    char*          Source;          // Points to loc. being parsed
159
    int            inum;            // integer value
160
    double         dnum;            // real value
161
    char           id[MAXID];       // identifier
162
    char           str[MAXSTR];     // string
163
 
164
    // Allowed keywords & datasets
165
 
166
    LPKEYVALUE    ValidKeywords;
167
    LPKEYVALUE    ValidSampleID;
168
 
169
    char           FileName[MAX_PATH];  
170
    int            lineno;          // line counter for error reporting
171
 
172
        char           SheetType[MAXSTR];  // New 1.09
173
 
174
   } IT8, FAR* LPIT8;
175
 
176
 
177
 
178
// ------------------------------------------------------ IT8 parsing routines
179
 
180
 
181
// A keyword
182
typedef struct {
183
               const char *id;
184
               SYMBOL sy;
185
 
186
               } KEYWORD;
187
 
188
// The keyword->symbol translation table. Sorting is required.
189
static const KEYWORD TabKeys[] = {
190
 
191
           {"BEGIN_DATA",          SBEGIN_DATA },
192
           {"BEGIN_DATA_FORMAT",   SBEGIN_DATA_FORMAT },
193
           {"END_DATA",            SEND_DATA},
194
           {"END_DATA_FORMAT",     SEND_DATA_FORMAT},
195
           {"KEYWORD",             SKEYWORD},
196
           {"STRING",              SSTRING_SY}};
197
 
198
#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
199
 
200
// Predefined properties
201
static char* PredefinedProperties[] = {
202
 
203
            "NUMBER_OF_FIELDS",     // Required - NUMBER OF FIELDS
204
            "NUMBER_OF_SETS",       // Required - NUMBER OF SETS
205
            "ORIGINATOR",          // Required - Identifies the specific system, organization or individual that created the data file.
206
            "CREATED",             // Required - Indicates date of creation of the data file.
207
            "DESCRIPTOR",          // Required  - Describes the purpose or contents of the data file.
208
            "DIFFUSE_GEOMETRY",    // The diffuse geometry used. Allowed values are "sphere" or "opal".
209
            "MANUFACTURER",
210
            "MANUFACTURE",         // Some broken Fuji targets does store this value
211
            "PROD_DATE",           // Identifies year and month of production of the target in the form yyyy:mm.
212
            "SERIAL",              // Uniquely identifies individual physical target.
213
 
214
            "MATERIAL",            // Identifies the material on which the target was produced using a code
215
                                   // uniquely identifying th e material. Th is is intend ed to be used for IT8.7
216
                                   // physical targets only (i.e . IT8.7/1 a nd IT8.7/2).
217
 
218
            "INSTRUMENTATION",     // Used to report the specific instrumentation used (manufacturer and
219
                                   // model number) to generate the data reported. This data will often
220
                                   // provide more information about the particular data collected than an
221
                                   // extensive list of specific details. This is particularly important for
222
                                   // spectral data or data derived from spectrophotometry.
223
 
224
            "MEASUREMENT_SOURCE",  // Illumination used for spectral measurements. This data helps provide
225
                                   // a guide to the potential for issues of paper fluorescence, etc.
226
 
227
            "PRINT_CONDITIONS",    // Used to define the ch aracteristics of the printed sheet being reported.
228
                                   // Where standard conditions have been defined (e.g., SW OP at nominal)
229
                                   // named conditions may suffice. Otherwise, detailed in formation is
230
                                   // needed.
231
 
232
            "SAMPLE_BACKING",      // Identifies the backing material used behind the sample during
233
                                   // measurement. Allowed values are “black”, “white”, or "na".
234
 
235
            "CHISQ_DOF"            // Degrees of freedom associated with the Chi squared statistic
236
            };
237
 
238
#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(char *))
239
 
240
 
241
// Predefined sample types on dataset
242
static char* PredefinedSampleID[] = {
243
 
244
            "CMYK_C",         // Cyan component of CMYK data expressed as a percentage
245
            "CMYK_M",         // Magenta component of CMYK data expressed as a percentage
246
            "CMYK_Y",         // Yellow component of CMYK data expressed as a percentage
247
            "CMYK_K",         // Black component of CMYK data expressed as a percentage
248
            "D_RED",          // Red filter density
249
            "D_GREEN",        // Green filter density
250
            "D_BLUE",         // Blue filter density
251
            "D_VIS",          // Visual filter density
252
            "D_MAJOR_FILTER", // Major filter d ensity
253
            "RGB_R",          // Red component of RGB data
254
            "RGB_G",          // Green component of RGB data
255
            "RGB_B",          // Blue com ponent of RGB data
256
            "SPECTRAL_NM",    // Wavelength of measurement expressed in nanometers
257
            "SPECTRAL_PCT",   // Percentage reflectance/transmittance
258
            "SPECTRAL_DEC",   // Reflectance/transmittance
259
            "XYZ_X",          // X component of tristimulus data
260
            "XYZ_Y",          // Y component of tristimulus data
261
            "XYZ_Z",          // Z component of tristimulus data
262
            "XYY_X"           // x component of chromaticity data
263
            "XYY_Y",          // y component of chromaticity data
264
            "XYY_CAPY",       // Y component of tristimulus data
265
            "LAB_L",          // L* component of Lab data
266
            "LAB_A",          // a* component of Lab data
267
            "LAB_B",          // b* component of Lab data
268
            "LAB_C",          // C*ab component of Lab data
269
            "LAB_H",          // hab component of Lab data
270
            "LAB_DE"          //  CIE dE
271
            "LAB_DE_94",      //  CIE dE using CIE 94
272
            "LAB_DE_CMC",     //  dE using CMC
273
            "LAB_DE_2000",    // CIE dE using CIE DE 2000
274
            "MEAN_DE",        // Mean Delta E (LAB_DE) of samples compared to batch average
275
                              // (Used for data files for ANSI IT8.7/1 and IT8.7/2 targets)
276
            "STDEV_X",        // Standard deviation of X (tristimulus data)
277
            "STDEV_Y",        // Standard deviation of Y (tristimulus data)
278
            "STDEV_Z",        // Standard deviation of Z (tristimulus data)
279
            "STDEV_L",        // Standard deviation of L*
280
            "STDEV_A"         // Standard deviation of a*
281
            "STDEV_B",        // Standard deviation of b*
282
            "STDEV_DE",       // Standard deviation of CIE dE
283
            "CHI_SQD_PAR"};   // The average of the standard deviations of L*, a* and b*. It is
284
                              // used to derive an estimate of the chi-squared parameter which is
285
                              // recommended as the predictor of the variability of dE
286
 
287
#define NUMPREDEFINEDSAMPLEID (sizeof(PredefinedSampleID)/sizeof(char *))
288
 
289
 
290
// Checks whatsever if c is a valid identifier middle char.
291
static
292
BOOL isidchar(int c)
293
{
294
   return (isalnum(c) || c == '$' || c == '%' || c == '&' || c == '/' || c == '.' || c == '_');
295
 
296
}
297
 
298
// Checks whatsever if c is a valid identifier first char.
299
static
300
BOOL isfirstidchar(int c)
301
{
302
        return !isdigit(c) && isidchar(c);
303
}
304
 
305
// Checks if c is a separator
306
static
307
BOOL isseparator(int c)
308
{
309
        return (c == ' ' || c == '\t' || c == '\r');
310
}
311
 
312
// a replacement for strupr(), just for compatiblity sake
313
 
314
static
315
void xstrupr(char *cp)
316
{
317
        for (;*cp;cp++)
318
                if (*cp >= 'a' && *cp <= 'z')
319
                        *cp += 'A'-'a';
320
}
321
 
322
// A replacement for (the nonstandard) filelenght
323
 
324
static
325
int xfilelength(int fd)
326
{
327
#ifdef _MSC_VER
328
                return _filelength(fd);
329
#else
330
        struct stat sb;
331
        if (fstat(fd, &sb) < 0)
332
                return(-1);
333
        return(sb.st_size);
334
#endif
335
 
336
 
337
}
338
 
339
static
340
BOOL SynError(LPIT8 it8, const char *Txt, ...)
341
{
342
        char Buffer[256], ErrMsg[1024];
343
        va_list args;
344
 
345
        va_start(args, Txt);
346
        vsprintf(Buffer, Txt, args);
347
        va_end(args);
348
 
349
        sprintf(ErrMsg, "%s: Line %d, %s", it8->FileName, it8->lineno, Buffer);
350
        it8->sy = SSYNERROR;
351
        cmsSignalError(LCMS_ERRC_ABORTED, ErrMsg);
352
        return FALSE;
353
}
354
 
355
static
356
BOOL Check(LPIT8 it8, SYMBOL sy, const char* Err)
357
{
358
        if (it8 -> sy != sy)
359
                return SynError(it8, Err);
360
        return TRUE;
361
}
362
 
363
 
364
 
365
// Read Next character from stream
366
static
367
void NextCh(LPIT8 it8)
368
{
369
        it8->ch = *it8->Source;
370
        if (it8->ch) it8->Source++;
371
}
372
 
373
 
374
// Try to see if current identifier is a keyword, if so return the referred symbol
375
static
376
SYMBOL BinSrchKey(const char *id)
377
{
378
        int l = 1;
379
        int r = NUMKEYS;
380
        int x, res;
381
 
382
        while (r >= l)
383
        {
384
                x = (l+r)/2;
385
                res = strcmp(id, TabKeys[x-1].id);
386
                if (res == 0) return TabKeys[x-1].sy;
387
                if (res < 0) r = x - 1;
388
                else l = x + 1;
389
        }
390
 
391
        return SNONE;
392
}
393
 
394
 
395
// 10 ^n
396
static
397
double pow10(int n)
398
{
399
    return pow(10, n);
400
}
401
 
402
 
403
//  Reads a Real number, tries to follow from integer number
404
static
405
void ReadReal(LPIT8 it8, int inum)
406
{
407
        it8->dnum = (double) inum;
408
 
409
        while (isdigit(it8->ch)) {
410
 
411
        it8->dnum = it8->dnum * 10.0 + (it8->ch - '0');
412
        NextCh(it8);
413
        }
414
 
415
        if (it8->ch == '.') {        // Decimal point
416
 
417
                double frac = 0.0;      // fraction
418
                int prec = 0;           // precission
419
 
420
                NextCh(it8);               // Eats dec. point
421
 
422
                while (isdigit(it8->ch)) {
423
 
424
                        frac = frac * 10.0 + (it8->ch - '0');
425
                        prec++;
426
                        NextCh(it8);
427
                }
428
 
429
                it8->dnum = it8->dnum + (frac / pow10(prec));
430
        }
431
 
432
        // Exponent, example 34.00E+20
433
        if (toupper(it8->ch) == 'E') {
434
 
435
                int e;
436
                int sgn;
437
 
438
                NextCh(it8); sgn = 1;
439
 
440
                if (it8->ch == '-') {
441
 
442
                        sgn = -1; NextCh(it8);
443
                }
444
                else
445
                if (it8->ch == '+') {
446
 
447
                        sgn = +1;
448
                        NextCh(it8);
449
                }
450
 
451
 
452
                e = 0;
453
                while (isdigit(it8->ch)) {
454
 
455
                        if ((double) e * 10L < INT_MAX)
456
                            e = e * 10 + (it8->ch - '0');
457
 
458
                        NextCh(it8);
459
                }
460
 
461
                e = sgn*e;
462
 
463
                it8 -> dnum = it8 -> dnum * pow10(e);
464
        }
465
}
466
 
467
 
468
 
469
// Reads next symbol
470
static
471
void InSymbol(LPIT8 it8)
472
{
473
        register char *idptr;
474
        register int k;
475
        SYMBOL key;
476
        int sng;
477
 
478
        do {
479
 
480
        while (isseparator(it8->ch))
481
                                NextCh(it8);
482
 
483
        if (isfirstidchar(it8->ch)) {          // Identifier
484
 
485
 
486
                k = 0;
487
                idptr = it8->id;
488
 
489
                do {
490
 
491
                if (++k < MAXID) *idptr++ = (char) it8->ch;
492
 
493
                NextCh(it8);
494
 
495
                } while (isidchar(it8->ch));
496
 
497
                *idptr = '\0';
498
                xstrupr(it8->id);
499
 
500
                key = BinSrchKey(it8->id);
501
                if (key == SNONE) it8->sy = SIDENT;
502
                else it8->sy = key;
503
 
504
        }
505
        else                         // Is a number?
506
        if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+')
507
        {
508
        int sign = 1;
509
 
510
        if (it8->ch == '-') {
511
                sign = -1;
512
                NextCh(it8);
513
                }
514
 
515
        it8->inum = 0;
516
        it8->sy   = SINUM;
517
 
518
        while (isdigit(it8->ch))
519
        {
520
                if ((long) it8->inum * 10L > (long) INT_MAX)
521
                {
522
                ReadReal(it8, it8->inum);
523
                it8->sy = SDNUM;
524
                it8->dnum *= sign;
525
                return;
526
                }
527
 
528
        it8->inum = it8->inum * 10 + (it8->ch - '0');
529
        NextCh(it8);
530
        }
531
 
532
        if (it8->ch == '.') {
533
 
534
                ReadReal(it8, it8->inum);
535
                it8->sy = SDNUM;
536
                it8->dnum *= sign;
537
                return;
538
                }
539
 
540
        it8 -> inum *= sign;
541
        return;
542
 
543
        }
544
        else
545
        switch ((int) it8->ch) {
546
 
547
        case '\0':
548
        case '\x1a':
549
                    it8->sy = SEOF;
550
                    break;
551
 
552
 
553
 
554
        case '\n':
555
                  NextCh(it8);
556
                  it8->sy = SEOLN;
557
                  it8->lineno++;
558
                  break;
559
 
560
        // Comment
561
 
562
        case '#':
563
                 NextCh(it8);
564
                 while (it8->ch && it8->ch != '\n')
565
             NextCh(it8);
566
 
567
                 it8->sy = SCOMMENT;
568
                 break;
569
 
570
        // String. I will support \", \n, \t and \\.
571
    // But otherwise I hardly doubt these will be used ...
572
 
573
        case '\'':
574
        case '\"':
575
                  idptr = it8->str;
576
                  sng = it8->ch;
577
                  k = 0;
578
                  NextCh(it8);
579
 
580
                  while (k < MAXSTR && it8->ch != sng) {
581
 
582
                  if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1;
583
                  else {
584
 
585
                        if (it8->ch == '\\')
586
                        {
587
                                NextCh(it8);
588
 
589
                                switch (it8->ch) {
590
 
591
                                case 'n': *idptr++ = '\n'; break;
592
                                case 'r': *idptr++ = '\r'; break;
593
                                case 't': *idptr++ = '\t'; break;
594
                                case '\\': *idptr++ = '\\'; break;
595
 
596
                                default:
597
                                        *idptr++ = (char) it8->ch;
598
                                }
599
 
600
                                NextCh(it8);
601
                        }
602
                        else
603
            {
604
                        *idptr++ = (char) it8->ch;
605
                        NextCh(it8);
606
                        }
607
 
608
                  k++;
609
          }
610
                  }
611
 
612
                  it8->sy = SSTRING;
613
                  *idptr = '\0';
614
                  NextCh(it8);
615
                  break;
616
 
617
 
618
        default:
619
                it8->sy = SSYNERROR;
620
                NextCh(it8);
621
 
622
       }
623
 
624
    } while (it8->sy == SCOMMENT);
625
}
626
 
627
// Checks end of line separator
628
static
629
BOOL CheckEOLN(LPIT8 it8)
630
{
631
        if (!Check(it8, SEOLN, "Expected separator")) return FALSE;
632
        while (it8 -> sy == SEOLN)
633
                        InSymbol(it8);
634
        return TRUE;
635
 
636
}
637
 
638
// Skip a symbol
639
 
640
static
641
void Skip(LPIT8 it8, SYMBOL sy)
642
{
643
        if (it8->sy == sy && it8->sy != SEOF)
644
                        InSymbol(it8);
645
}
646
 
647
// Returns a string holding current value
648
static
649
BOOL GetVal(LPIT8 it8, char* Buffer)
650
{
651
    switch (it8->sy) {
652
 
653
    case SIDENT:  strncpy(Buffer, it8->id, MAXID-1); break;
654
    case SINUM:   sprintf(Buffer, "%d", it8 -> inum); break;
655
    case SDNUM:   sprintf(Buffer, "%g", it8 -> dnum); break;
656
    case SSTRING: strncpy(Buffer, it8->str, MAXSTR-1); break;
657
 
658
 
659
    default:
660
         return SynError(it8, "Sample data expected");
661
    }
662
 
663
     return TRUE;
664
}
665
 
666
// ---------------------------------------------------------- Memory management
667
 
668
 
669
 
670
// Frees an allocator and owned memory
671
void cmsxIT8Free(LCMSHANDLE hIT8)
672
{
673
   LPIT8 it8 = (LPIT8) hIT8;
674
 
675
    if (it8 == NULL)
676
        return;
677
 
678
    if (it8->MemorySink) {
679
 
680
        LPOWNEDMEM p;
681
        LPOWNEDMEM n;
682
 
683
        for (p = it8->MemorySink; p != NULL; p = n) {
684
 
685
            n = p->Next;
686
            if (p->Ptr) free(p->Ptr);
687
            free(p);
688
        }
689
    }
690
 
691
    if (it8->FileBuffer)
692
        free(it8->FileBuffer);
693
 
694
    free(it8);
695
}
696
 
697
 
698
// Allocates a chunk of data, keep linked list
699
static
700
void* AllocChunk(LPIT8 it8, size_t size)
701
{
702
   LPOWNEDMEM ptr1;
703
   void* ptr = malloc(size);
704
 
705
        if (ptr) {
706
 
707
                ZeroMemory(ptr, size);
708
                ptr1 = (LPOWNEDMEM) malloc(sizeof(OWNEDMEM));
709
 
710
                if (ptr1 == NULL) {
711
 
712
                    free(ptr);
713
                    return NULL;
714
                }
715
 
716
                ZeroMemory(ptr1, sizeof(OWNEDMEM));
717
 
718
                ptr1-> Ptr        = ptr;
719
                ptr1-> Next       = it8 -> MemorySink;
720
                it8 -> MemorySink = ptr1;
721
        }
722
 
723
        return ptr;
724
}
725
 
726
 
727
// Allocates a string
728
static
729
char *AllocString(LPIT8 it8, const char* str)
730
{
731
    int Size = strlen(str)+1;
732
    char *ptr;
733
    ptr = (char *) AllocChunk(it8, Size);
734
    if (ptr) strncpy (ptr, str, Size);
735
    return ptr;
736
}  
737
 
738
// Searches through linked list
739
 
740
static
741
BOOL IsAvailableOnList(LPKEYVALUE p, const char* Key, LPKEYVALUE* LastPtr)
742
{
743
    for (;  p != NULL; p = p->Next) {
744
 
745
        if (LastPtr) *LastPtr = p;
746
        if (stricmp(Key, p->Keyword) == 0)
747
                                    return TRUE;
748
    }
749
 
750
    return FALSE;
751
}
752
 
753
 
754
 
755
// Add a property into a linked list
756
static
757
BOOL AddToList(LPIT8 it8, LPKEYVALUE* Head, const char *Key, const char* Value)
758
{
759
    LPKEYVALUE p;
760
    LPKEYVALUE last;
761
 
762
 
763
    // Check if property is already in list (this is an error)
764
 
765
    if (IsAvailableOnList(*Head, Key, &last)) {
766
                    cmsSignalError(LCMS_ERRC_ABORTED, "duplicate key <%s>", Key);
767
        return FALSE;
768
    }
769
 
770
        // Allocate the container
771
    p = (LPKEYVALUE) AllocChunk(it8, sizeof(KEYVALUE));
772
    if (p == NULL)
773
    {
774
        cmsSignalError(LCMS_ERRC_ABORTED, "AddToList: out of memory");
775
        return FALSE;
776
    }
777
 
778
    // Store name and value
779
    p->Keyword = AllocString(it8, Key);
780
 
781
    if (Value)
782
        p->Value   = AllocString(it8, Value);
783
    else
784
        p->Value   = NULL;
785
 
786
    p->Next    = NULL;
787
 
788
    // Keep the container in our list
789
    if (*Head == NULL)
790
        *Head = p;
791
    else
792
        last->Next = p;
793
 
794
    return TRUE;
795
}
796
 
797
static
798
BOOL AddAvailableProperty(LPIT8 it8, const char* Key)
799
{
800
        return AddToList(it8, &it8->ValidKeywords, Key, NULL);
801
}
802
 
803
 
804
static
805
BOOL AddAvailableSampleID(LPIT8 it8, const char* Key)
806
{
807
        return AddToList(it8, &it8->ValidSampleID, Key, NULL);
808
}
809
 
810
 
811
 
812
// Init an empty container
813
LCMSHANDLE cmsxIT8Alloc(void)
814
{
815
    LPIT8 it8;
816
    int i;
817
 
818
    it8 = (LPIT8) malloc(sizeof(IT8));
819
    if (it8 == NULL) return NULL;
820
 
821
    ZeroMemory(it8, sizeof(IT8));
822
 
823
    it8->HeaderList = NULL;
824
    it8->FileBuffer = NULL;
825
    it8->DataFormat = NULL;
826
    it8->Data       = NULL;
827
    it8->MemorySink = NULL;
828
    it8->ValidKeywords = NULL;
829
    it8->ValidSampleID = NULL;
830
 
831
    it8 -> sy = SNONE;
832
    it8 -> ch = ' ';
833
    it8 -> Source = NULL;
834
    it8 -> inum = 0;
835
    it8 -> dnum = 0.0;
836
 
837
    it8 -> lineno = 1;
838
 
839
        strcpy(it8->SheetType, "IT8.7/2");
840
 
841
    // Initialize predefined properties & data
842
 
843
    for (i=0; i < NUMPREDEFINEDPROPS; i++)
844
            AddAvailableProperty(it8, PredefinedProperties[i]);
845
 
846
    for (i=0; i < NUMPREDEFINEDSAMPLEID; i++)
847
            AddAvailableSampleID(it8, PredefinedSampleID[i]);
848
 
849
 
850
   return (LCMSHANDLE) it8;
851
}
852
 
853
 
854
const char* cdecl cmsxIT8GetSheetType(LCMSHANDLE hIT8)
855
{
856
            LPIT8 it8 = (LPIT8) hIT8;
857
 
858
                return it8 ->SheetType;
859
 
860
}
861
 
862
BOOL  cmsxIT8SetSheetType(LCMSHANDLE hIT8, const char* Type)
863
{
864
                LPIT8 it8 = (LPIT8) hIT8;
865
 
866
                strncpy(it8 ->SheetType, Type, MAXSTR-1);
867
                return TRUE;
868
}
869
 
870
 
871
 
872
// Sets a property
873
BOOL cmsxIT8SetProperty(LCMSHANDLE hIT8, const char* Key, const char *Val)
874
{
875
    LPIT8 it8 = (LPIT8) hIT8;
876
 
877
    if (!Val) return FALSE;
878
    if (!*Val) return FALSE;
879
 
880
    return AddToList(it8, &it8 -> HeaderList, Key, Val);
881
}
882
 
883
 
884
BOOL cmsxIT8SetPropertyDbl(LCMSHANDLE hIT8, const char* cProp, double Val)
885
{
886
    char Buffer[256];
887
 
888
    sprintf(Buffer, "%g", Val);
889
    return cmsxIT8SetProperty(hIT8, cProp, Buffer);
890
}
891
 
892
// Gets a property
893
const char* cmsxIT8GetProperty(LCMSHANDLE hIT8, const char* Key)
894
{
895
    LPIT8 it8 = (LPIT8) hIT8;
896
    LPKEYVALUE p;
897
 
898
    if (IsAvailableOnList(it8 -> HeaderList, Key, &p))
899
    {
900
        return p -> Value;
901
    }
902
    return NULL;
903
}
904
 
905
 
906
double  cmsxIT8GetPropertyDbl(LCMSHANDLE hIT8, const char* cProp)
907
{
908
    const char *v = cmsxIT8GetProperty(hIT8, cProp);
909
    if (v) return atof(v);
910
    else return 0.0;
911
}
912
 
913
// ----------------------------------------------------------------- Datasets
914
 
915
 
916
static
917
void AllocateDataFormat(LPIT8 it8)
918
{
919
    if (it8 -> DataFormat) return;    // Already allocated
920
 
921
    it8 -> nSamples  = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
922
 
923
    if (it8 -> nSamples <= 0) {
924
 
925
        cmsSignalError(LCMS_ERRC_WARNING, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS, assuming 10");
926
        it8 -> nSamples = 10;
927
        }
928
 
929
    it8 -> DataFormat = (char**) AllocChunk (it8, (it8->nSamples + 1) * sizeof(char *));
930
    if (it8->DataFormat == NULL)
931
    {
932
        cmsSignalError(LCMS_ERRC_ABORTED, "AllocateDataFormat: Unable to allocate dataFormat array");
933
    }
934
 
935
}
936
 
937
static
938
const char *GetDataFormat(LPIT8 it8, int n)
939
{
940
    if (it8->DataFormat)
941
        return it8->DataFormat[n];
942
 
943
    return NULL;
944
}
945
 
946
static
947
BOOL SetDataFormat(LPIT8 it8, int n, const char *label)
948
{
949
    if (n > it8 -> nSamples) return FALSE;
950
 
951
    if (!it8->DataFormat)
952
        AllocateDataFormat(it8);
953
 
954
    if (it8->DataFormat) {
955
 
956
        it8->DataFormat[n] = AllocString(it8, label);
957
    }
958
 
959
    return TRUE;
960
}
961
 
962
 
963
BOOL cmsxIT8SetDataFormat(LCMSHANDLE h, int n, const char *Sample)
964
{
965
        LPIT8 it8 = (LPIT8) h;
966
        return SetDataFormat(it8, n, Sample);
967
}
968
 
969
static
970
void AllocateDataSet(LPIT8 it8)
971
{
972
    if (it8 -> Data) return;    // Already allocated
973
 
974
    it8-> nSamples   = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
975
    it8-> nPatches   = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_SETS"));
976
    it8-> Data = (char**)AllocChunk (it8, (it8->nSamples + 1) * (it8->nPatches + 1) *sizeof (char*));
977
    if (it8->Data == NULL)
978
    {
979
        cmsSignalError(-1, "AllocateDataSet: Unable to allocate data array");
980
    }
981
 
982
}
983
 
984
static
985
char* GetData(LPIT8 it8, int nSet, int nField)
986
{
987
    int  nSamples = it8 -> nSamples;
988
    int  nPatches   = it8 -> nPatches;
989
 
990
    if (nSet >= nPatches || nField >= nSamples)
991
        return NULL;
992
 
993
    if (!it8->Data) return NULL;
994
    return it8->Data [nSet * nSamples + nField];
995
}
996
 
997
static
998
BOOL SetData(LPIT8 it8, int nSet, int nField, char *Val)
999
{
1000
    if (!it8->Data)
1001
        AllocateDataSet(it8);
1002
 
1003
    if (!it8->Data) return FALSE;
1004
 
1005
 
1006
    if (nSet > it8 -> nPatches) {
1007
 
1008
            SynError(it8, "Patch %d out of range, there are %d datasets", nSet, it8 -> nPatches);
1009
            return FALSE;
1010
    }
1011
 
1012
    if (nField > it8 ->nSamples) {
1013
            SynError(it8, "Sample %d out of range, there are %d datasets", nField, it8 ->nSamples);
1014
            return FALSE;
1015
    }
1016
 
1017
 
1018
    it8->Data [nSet * it8 -> nSamples + nField] = AllocString(it8, Val);
1019
    return TRUE;
1020
}
1021
 
1022
 
1023
// --------------------------------------------------------------- File I/O
1024
 
1025
 
1026
// Writes a string to file
1027
static
1028
void WriteStr(FILE *f, char *str)
1029
{
1030
    if (str == NULL)
1031
        fwrite(" ", 1, 1, f);
1032
    else
1033
        fwrite(str, 1, strlen(str), f);
1034
}
1035
 
1036
 
1037
// Writes full header
1038
static
1039
void WriteHeader(LPIT8 it8, FILE *fp)
1040
{
1041
    LPKEYVALUE p;
1042
 
1043
        WriteStr(fp, it8->SheetType);
1044
    WriteStr(fp, "\n");
1045
    for (p = it8->HeaderList; (p != NULL); p = p->Next)
1046
    {
1047
        if (!IsAvailableOnList(it8-> ValidKeywords, p->Keyword, NULL)) {
1048
 
1049
            WriteStr(fp, "KEYWORD\t\"");
1050
            WriteStr(fp, p->Keyword);
1051
            WriteStr(fp, "\"\n");
1052
 
1053
        }
1054
 
1055
        WriteStr(fp, p->Keyword);
1056
        if (p->Value) {
1057
 
1058
            WriteStr(fp, "\t\"");
1059
            WriteStr(fp, p->Value);
1060
            WriteStr(fp, "\"");
1061
        }
1062
        WriteStr (fp, "\n");
1063
    }
1064
 
1065
}
1066
 
1067
 
1068
// Writes the data format
1069
static
1070
void WriteDataFormat(FILE *fp, LPIT8 it8)
1071
{
1072
       int i, nSamples;
1073
 
1074
    if (!it8 -> DataFormat) return;
1075
 
1076
       WriteStr(fp, "BEGIN_DATA_FORMAT\n");
1077
       nSamples = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
1078
 
1079
       for (i = 0; i < nSamples; i++) {
1080
 
1081
              WriteStr(fp, it8->DataFormat[i]);
1082
              WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t"));
1083
          }
1084
 
1085
       WriteStr (fp, "END_DATA_FORMAT\n");
1086
}
1087
 
1088
 
1089
// Writes data array
1090
static
1091
void WriteData(FILE *fp, LPIT8 it8)
1092
{
1093
       int  i, j;
1094
 
1095
       if (!it8->Data) return;
1096
 
1097
       WriteStr (fp, "BEGIN_DATA\n");
1098
 
1099
       it8->nPatches = atoi(cmsxIT8GetProperty(it8, "NUMBER_OF_SETS"));
1100
 
1101
       for (i = 0; i < it8-> nPatches; i++) {
1102
 
1103
              for (j = 0; j < it8->nSamples; j++) {
1104
 
1105
                     char *ptr = it8->Data[i*it8->nSamples+j];
1106
 
1107
                     WriteStr(fp, ((ptr == NULL) ? "0.00" : ptr));
1108
                     WriteStr(fp, ((j == (it8->nSamples-1)) ? "\n" : "\t"));
1109
              }
1110
       }
1111
       WriteStr (fp, "END_DATA\n");
1112
}
1113
 
1114
 
1115
 
1116
// Saves whole file
1117
BOOL cmsxIT8SaveToFile(LCMSHANDLE hIT8, const char* cFileName)
1118
{
1119
    FILE *fp;
1120
    LPIT8 it8 = (LPIT8) hIT8;
1121
 
1122
    fp = fopen(cFileName, "wt");
1123
    if (!fp) return FALSE;
1124
    WriteHeader(it8, fp);
1125
    WriteDataFormat(fp, it8);
1126
    WriteData(fp, it8);
1127
    fclose(fp);
1128
 
1129
    return TRUE;
1130
}
1131
 
1132
 
1133
// Reads whole file in a memory block
1134
static
1135
BOOL ReadFileInMemory(const char *cFileName, char **Buffer, size_t *Len)
1136
{
1137
       FILE *fp;
1138
       size_t Size;
1139
       char *Ptr;
1140
 
1141
       fp = fopen(cFileName, "rt");
1142
       if (!fp) return FALSE;
1143
 
1144
       Size = xfilelength(fileno(fp));
1145
       if (Size <= 0) {
1146
           fclose(fp);
1147
           return FALSE;
1148
       }
1149
 
1150
       Ptr  = malloc(Size+1);
1151
 
1152
       Size = fread(Ptr, 1, Size, fp);
1153
       fclose(fp);
1154
       Ptr[Size] = '\0';
1155
 
1156
       *Buffer = Ptr;
1157
       *Len    = Size;
1158
       return TRUE;
1159
}
1160
 
1161
 
1162
// -------------------------------------------------------------- Higer lever parsing
1163
 
1164
static
1165
BOOL DataFormatSection(LPIT8 it8)
1166
{
1167
    int iField = 0;
1168
    BOOL Ignoring = FALSE;
1169
 
1170
    InSymbol(it8);   // Eats "BEGIN_DATA_FORMAT"
1171
    CheckEOLN(it8);
1172
 
1173
    while (it8->sy != SEND_DATA_FORMAT &&
1174
           it8->sy != SEOLN &&
1175
               it8->sy != SEOF &&
1176
               it8->sy != SSYNERROR)
1177
    {
1178
 
1179
          if (it8->sy != SIDENT) {
1180
 
1181
                     cmsSignalError(LCMS_ERRC_ABORTED, "Sample type expected");
1182
                     it8->sy = SSYNERROR;
1183
                     return FALSE;
1184
                     }
1185
 
1186
              if (!Ignoring && iField > it8->nSamples) {
1187
                    cmsSignalError(LCMS_ERRC_WARNING, "More than NUMBER_OF_FIELDS fields. Extra is ignored\n");
1188
                    Ignoring = TRUE;
1189
                    }
1190
              else  {
1191
                     if (!SetDataFormat(it8, iField, it8->id)) return FALSE;
1192
                     iField++;
1193
            }
1194
 
1195
            InSymbol(it8);
1196
            Skip(it8, SEOLN);
1197
       }
1198
 
1199
       Skip(it8, SEOLN);
1200
       Skip(it8, SEND_DATA_FORMAT);
1201
       Skip(it8, SEOLN);
1202
       return TRUE;
1203
}
1204
 
1205
 
1206
 
1207
static
1208
BOOL DataSection (LPIT8 it8)
1209
{
1210
    int  iField = 0;
1211
    int  iSet   = 0;
1212
    char Buffer[256];
1213
 
1214
    InSymbol(it8);   // Eats "BEGIN_DATA"
1215
    CheckEOLN(it8);
1216
 
1217
    while (it8->sy != SEND_DATA && it8->sy != SEOF)
1218
    {
1219
        if (iField >= it8 -> nSamples) {
1220
            iField = 0;
1221
            iSet++;
1222
            if (!CheckEOLN(it8))
1223
                return FALSE;
1224
        }
1225
 
1226
        if (it8->sy != SEND_DATA && it8->sy != SEOF) {
1227
 
1228
            if (!GetVal(it8, Buffer))
1229
                return FALSE;
1230
 
1231
            if (!SetData(it8, iSet, iField, Buffer))
1232
                return FALSE;
1233
 
1234
            iField++;
1235
 
1236
            Skip(it8, SEOLN);
1237
            InSymbol(it8);
1238
        }
1239
    }
1240
 
1241
    Skip(it8, SEOLN);
1242
    Skip(it8, SEND_DATA);
1243
    Skip(it8, SEOLN);
1244
    return TRUE;
1245
}
1246
 
1247
 
1248
 
1249
 
1250
 
1251
 
1252
static
1253
BOOL HeaderSection (LPIT8 it8)
1254
{
1255
    char VarName[MAXID];
1256
        char Buffer[MAXSTR];
1257
 
1258
        while (it8->sy != SEOF &&
1259
               it8->sy != SSYNERROR &&
1260
               it8->sy != SBEGIN_DATA_FORMAT &&
1261
               it8->sy != SBEGIN_DATA) {
1262
 
1263
 
1264
        switch (it8 -> sy) {
1265
 
1266
        case SKEYWORD:
1267
                InSymbol(it8);
1268
                if (!Check(it8, SSTRING, "Keyword expected")) return FALSE;
1269
                if (!AddAvailableProperty(it8, it8 -> str)) return FALSE;
1270
                InSymbol(it8);
1271
                break;
1272
 
1273
 
1274
        case SIDENT:
1275
                strncpy(VarName, it8->id, MAXID-1);
1276
                if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL))
1277
                        return SynError(it8, "Undefined keyword '%s'", VarName);
1278
 
1279
                InSymbol(it8);
1280
                GetVal(it8, Buffer);
1281
                cmsxIT8SetProperty((LCMSHANDLE) it8, VarName, Buffer);
1282
                InSymbol(it8);
1283
                break;
1284
 
1285
 
1286
        case SEOLN: break;
1287
 
1288
        default:
1289
                return SynError(it8, "expected keyword or identifier");
1290
        }
1291
 
1292
    Skip(it8, SEOLN);
1293
        }
1294
 
1295
    return TRUE;
1296
 
1297
}
1298
 
1299
 
1300
static
1301
BOOL ParseIT8(LPIT8 it8)
1302
{
1303
 
1304
    InSymbol(it8);
1305
 
1306
    if (it8->sy == SIDENT) {
1307
 
1308
                        strncpy(it8->SheetType, it8->id, MAXSTR-1);
1309
            InSymbol(it8);
1310
 
1311
            // if (!AddAvailableProperty(it8, it8 -> id)) return FALSE;
1312
            // cmsxIT8SetProperty((LCMSHANDLE) it8, it8->id, NULL);
1313
    }
1314
 
1315
    Skip(it8, SEOLN);
1316
 
1317
    while (it8-> sy != SEOF &&
1318
           it8-> sy != SSYNERROR) {
1319
 
1320
            switch (it8 -> sy) {
1321
 
1322
            case SBEGIN_DATA_FORMAT:
1323
                    if (!DataFormatSection(it8)) return FALSE;
1324
                    break;
1325
 
1326
            case SBEGIN_DATA:
1327
                    if (!DataSection(it8)) return FALSE;
1328
                    break;
1329
 
1330
            case SEOLN:
1331
                    Skip(it8, SEOLN);
1332
                    break;
1333
 
1334
            default:
1335
                    if (!HeaderSection(it8)) return FALSE;
1336
           }
1337
 
1338
    }
1339
 
1340
    return TRUE;
1341
}
1342
 
1343
 
1344
static
1345
void CleanPatchName(char *cell)
1346
{
1347
       char cleaned[256], Buffer[256], ident[256];
1348
       char *orig = cell, *id;
1349
       int n, lOneNum;
1350
 
1351
 
1352
       id = ident;
1353
       while (*cell && isalpha(*cell))
1354
       {
1355
          *id++ = (char) toupper(*cell);
1356
              cell++;
1357
       }
1358
       *id = 0;
1359
       strcpy(cleaned, ident);
1360
 
1361
 
1362
       n = 0;
1363
       lOneNum = FALSE;
1364
       while (*cell && isdigit(*cell))
1365
       {
1366
              n = n * 10 + (*cell -'0');
1367
              cell++;
1368
              lOneNum = TRUE;
1369
       }
1370
 
1371
       if (lOneNum) {
1372
 
1373
              sprintf(Buffer, "%d", n);
1374
              strcat(cleaned, Buffer);              
1375
       }
1376
 
1377
       if (strcmp(cleaned, "GS0") == 0)
1378
              strcpy(orig, "DMIN");
1379
           else
1380
           if (strcmp(cleaned, "GS23") == 0)
1381
              strcpy(orig, "DMAX");
1382
       else
1383
              strcpy(orig, cleaned);
1384
}
1385
 
1386
 
1387
// Init usefull pointers
1388
 
1389
static
1390
void CookPointers(LPIT8 it8)
1391
{
1392
    int idField, i;
1393
        char* Fld;
1394
 
1395
    it8 -> SampleID = 0;
1396
    for (idField = 0; idField < it8 -> nSamples; idField++)
1397
    {
1398
                Fld = it8->DataFormat[idField];
1399
                if (!Fld) continue;
1400
 
1401
        if (strcmp(Fld, "SAMPLE_ID") == 0) {
1402
                    it8 -> SampleID = idField;
1403
 
1404
 
1405
        for (i=0; i < it8 -> nPatches; i++) {
1406
 
1407
                char *Data = GetData(it8, i, idField);
1408
                if (Data) {
1409
                    char Buffer[256];
1410
 
1411
                    strncpy(Buffer, Data, 255);
1412
                    CleanPatchName(Buffer);
1413
 
1414
                    if (strlen(Buffer) <= strlen(Data))
1415
                        strcpy(Data, Buffer);
1416
                    else
1417
                        SetData(it8, i, idField, Buffer);
1418
 
1419
                }
1420
                }
1421
 
1422
        }
1423
    }
1424
 
1425
}
1426
 
1427
 
1428
// ---------------------------------------------------------- Exported routines
1429
 
1430
 
1431
LCMSHANDLE cmsxIT8LoadFromMem(void *Ptr, size_t len)
1432
{
1433
    LCMSHANDLE hIT8 = cmsxIT8Alloc();
1434
    LPIT8  it8 = (LPIT8) hIT8;
1435
 
1436
    if (!hIT8) return NULL;
1437
        it8 ->FileBuffer = (char*) malloc(len + 1);
1438
 
1439
        strncpy(it8 ->FileBuffer, Ptr, len);
1440
    strncpy(it8->FileName, "", MAX_PATH-1);
1441
    it8-> Source = it8 -> FileBuffer;
1442
 
1443
    ParseIT8(it8);
1444
    CookPointers(it8);
1445
 
1446
    free(it8->FileBuffer);
1447
    it8 -> FileBuffer = NULL;
1448
 
1449
    return hIT8;
1450
 
1451
 
1452
}
1453
 
1454
 
1455
LCMSHANDLE cmsxIT8LoadFromFile(const char* cFileName)
1456
{
1457
 
1458
    LCMSHANDLE hIT8 = cmsxIT8Alloc();
1459
    LPIT8  it8 = (LPIT8) hIT8;
1460
    size_t Len;
1461
 
1462
    if (!hIT8) return NULL;
1463
    if (!ReadFileInMemory(cFileName, &it8->FileBuffer, &Len)) return NULL;
1464
 
1465
    strncpy(it8->FileName, cFileName, MAX_PATH-1);
1466
    it8-> Source = it8 -> FileBuffer;
1467
 
1468
    ParseIT8(it8);
1469
    CookPointers(it8);
1470
 
1471
    free(it8->FileBuffer);
1472
    it8 -> FileBuffer = NULL;
1473
 
1474
    return hIT8;
1475
 
1476
}
1477
 
1478
int cmsxIT8EnumDataFormat(LCMSHANDLE hIT8, char ***SampleNames)
1479
{
1480
        LPIT8 it8 = (LPIT8) hIT8;
1481
 
1482
        *SampleNames = it8 -> DataFormat;
1483
        return it8 -> nSamples;
1484
}
1485
 
1486
 
1487
int  cmsxIT8EnumProperties(LCMSHANDLE hIT8, char ***PropertyNames)
1488
{
1489
    LPIT8 it8 = (LPIT8) hIT8;
1490
    LPKEYVALUE p;
1491
    int n;
1492
    char **Props;
1493
 
1494
    // Pass#1 - count properties
1495
 
1496
    n = 0;
1497
    for (p = it8 -> HeaderList;  p != NULL; p = p->Next) {
1498
        n++;
1499
    }
1500
 
1501
 
1502
    Props = (char **) malloc(sizeof(char *) * n);
1503
 
1504
    // Pass#2 - Fill pointers
1505
    n = 0;
1506
    for (p = it8 -> HeaderList;  p != NULL; p = p->Next) {
1507
        Props[n++] = p -> Keyword;
1508
    }
1509
 
1510
    *PropertyNames = Props;
1511
    return n;
1512
}
1513
 
1514
static
1515
int LocatePatch(LPIT8 it8, const char* cPatch)
1516
{
1517
    int i;
1518
    const char *data;
1519
 
1520
    for (i=0; i < it8-> nPatches; i++) {
1521
 
1522
        data = GetData(it8, i, it8->SampleID);
1523
 
1524
        if (data != NULL) {
1525
 
1526
                if (stricmp(data, cPatch) == 0)
1527
                        return i;
1528
                }
1529
        }
1530
 
1531
        return -1;
1532
}
1533
 
1534
 
1535
static
1536
int LocateEmptyPatch(LPIT8 it8, const char* cPatch)
1537
{
1538
    int i;
1539
    const char *data;
1540
 
1541
    for (i=0; i < it8-> nPatches; i++) {
1542
 
1543
        data = GetData(it8, i, it8->SampleID);
1544
 
1545
        if (data == NULL)
1546
                    return i;
1547
 
1548
        }
1549
 
1550
        return -1;
1551
}
1552
 
1553
static
1554
int LocateSample(LPIT8 it8, const char* cSample)
1555
{
1556
    int i;
1557
    const char *fld;
1558
 
1559
    for (i=0; i < it8->nSamples; i++) {
1560
 
1561
        fld = GetDataFormat(it8, i);
1562
        if (stricmp(fld, cSample) == 0)
1563
            return i;
1564
    }
1565
 
1566
    return -1;
1567
}
1568
 
1569
 
1570
BOOL cmsxIT8GetDataSetByPos(LCMSHANDLE hIT8, int col, int row, char* Val, int ValBufferLen)
1571
{
1572
    LPIT8 it8 = (LPIT8) hIT8;
1573
    const char *data =  GetData(it8, row, col);
1574
 
1575
    if (!data)
1576
    {
1577
        *Val = '\0';
1578
        return FALSE;
1579
    }
1580
 
1581
    strncpy(Val, data, ValBufferLen-1);
1582
    return TRUE;
1583
}
1584
 
1585
 
1586
 
1587
BOOL  cmsxIT8GetDataSet(LCMSHANDLE hIT8, const char* cPatch,
1588
                        const char* cSample,
1589
                        char* Val, int ValBuffLen)
1590
{
1591
    LPIT8 it8 = (LPIT8) hIT8;
1592
    int iField, iSet;
1593
 
1594
 
1595
    iField = LocateSample(it8, cSample);
1596
    if (iField < 0) {
1597
        // cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find data field %s\n", cSample);
1598
        return FALSE;
1599
    }
1600
 
1601
 
1602
    iSet = LocatePatch(it8, cPatch);
1603
    if (iSet < 0) {
1604
 
1605
            // cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find patch '%s'\n", cPatch);
1606
            return FALSE;
1607
    }
1608
 
1609
    strncpy(Val, GetData(it8, iSet, iField), ValBuffLen-1);
1610
    return TRUE;
1611
}
1612
 
1613
 
1614
BOOL cmsxIT8GetDataSetDbl(LCMSHANDLE it8, const char* cPatch, const char* cSample, double* v)
1615
{
1616
    char Buffer[20];
1617
 
1618
    if (cmsxIT8GetDataSet(it8, cPatch, cSample, Buffer, 20)) {
1619
 
1620
        *v = atof(Buffer);
1621
        return TRUE;
1622
    } else
1623
        return FALSE;
1624
}
1625
 
1626
 
1627
 
1628
BOOL cmsxIT8SetDataSet(LCMSHANDLE hIT8, const char* cPatch,
1629
                        const char* cSample,
1630
                        char *Val)
1631
{
1632
    LPIT8 it8 = (LPIT8) hIT8;
1633
    int iField, iSet;
1634
 
1635
 
1636
    iField = LocateSample(it8, cSample);
1637
 
1638
    if (iField < 0) {
1639
 
1640
        cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find data field %s\n", cSample);
1641
        return FALSE;
1642
        }
1643
 
1644
 
1645
        if (it8-> nPatches == 0) {
1646
 
1647
                AllocateDataFormat(it8);
1648
                AllocateDataSet(it8);
1649
                CookPointers(it8);
1650
        }
1651
 
1652
 
1653
        if (stricmp(cSample, "SAMPLE_ID") == 0)
1654
        {
1655
 
1656
                iSet   = LocateEmptyPatch(it8, cPatch);
1657
                if (iSet < 0) {
1658
                        cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't add more patches '%s'\n", cPatch);
1659
                        return FALSE;
1660
                }
1661
                iField = it8 -> SampleID;
1662
        }
1663
        else {
1664
                iSet = LocatePatch(it8, cPatch);
1665
                if (iSet < 0) {
1666
 
1667
                    cmsSignalError(LCMS_ERRC_ABORTED, "Couldn't find patch '%s'\n", cPatch);
1668
                    return FALSE;
1669
            }
1670
        }
1671
 
1672
        return SetData(it8, iSet, iField, Val);
1673
}
1674
 
1675
 
1676
BOOL cmsxIT8SetDataSetDbl(LCMSHANDLE hIT8, const char* cPatch,
1677
                        const char* cSample,
1678
                        double Val)
1679
{
1680
        char Buff[256];
1681
 
1682
        sprintf(Buff, "%g", Val);
1683
        return cmsxIT8SetDataSet(hIT8, cPatch, cSample, Buff);
1684
 
1685
}
1686
 
1687
 
1688
const char* cmsxIT8GetPatchName(LCMSHANDLE hIT8, int nPatch, char* buffer)
1689
{
1690
                LPIT8 it8 = (LPIT8) hIT8;
1691
                char* Data = GetData(it8, nPatch, it8->SampleID);
1692
                if (!Data) return NULL;
1693
 
1694
                strcpy(buffer, Data);
1695
                return buffer;
1696
}
1697
 
1698
 
1699
const char* cmsxIT8GenericPatchName(int nPatch, char* buffer)
1700
{
1701
    int row, col;
1702
 
1703
    if (nPatch >= cmsxIT8_NORMAL_PATCHES)
1704
        return "$CUSTOM";
1705
 
1706
    if (nPatch >= (cmsxIT8_ROWS * cmsxIT8_COLS)) {
1707
 
1708
        nPatch -= cmsxIT8_ROWS * cmsxIT8_COLS;
1709
        if (nPatch == 0)
1710
            return "DMIN";
1711
        else
1712
        if (nPatch == cmsxIT8_GRAYCOLS - 1)
1713
            return "DMAX";
1714
        else
1715
            sprintf(buffer, "GS%d", nPatch);
1716
            return buffer;
1717
    }
1718
 
1719
 
1720
    row = nPatch / cmsxIT8_COLS;
1721
    col = nPatch % cmsxIT8_COLS;
1722
 
1723
    sprintf (buffer, "%c%d", 'A'+row, col+1);
1724
    return buffer;
1725
}
1726
 
1727
 
1728
 
1729
 
1730
int cmsxIT8GenericPatchNum(const char *name)
1731
{
1732
        int i;
1733
        char Buff[256];
1734
 
1735
 
1736
        for (i=0; i < cmsxIT8_TOTAL_PATCHES; i++)
1737
                if (stricmp(cmsxIT8GenericPatchName(i, Buff), name) == 0)
1738
                        return i;
1739
 
1740
        return -1;
1741
}
1742
 
1743
 
1744
 
1745
 
1746