< prev index next >

src/java.desktop/share/native/liblcms/cmscgats.c

Print this page

  70 #    include <io.h>
  71 #    define DIR_CHAR    '\\'
  72 #else
  73 #    define DIR_CHAR    '/'
  74 #endif
  75 
  76 
  77 // Symbols
  78 typedef enum {
  79 
  80         SUNDEFINED,
  81         SINUM,      // Integer
  82         SDNUM,      // Real
  83         SIDENT,     // Identifier
  84         SSTRING,    // string
  85         SCOMMENT,   // comment
  86         SEOLN,      // End of line
  87         SEOF,       // End of stream
  88         SSYNERROR,  // Syntax error found on stream
  89 
  90         // Keywords
  91 
  92         SBEGIN_DATA,
  93         SBEGIN_DATA_FORMAT,
  94         SEND_DATA,
  95         SEND_DATA_FORMAT,
  96         SKEYWORD,
  97         SDATA_FORMAT_ID,
  98         SINCLUDE












  99 
 100     } SYMBOL;
 101 
 102 
 103 // How to write the value
 104 typedef enum {
 105 
 106         WRITE_UNCOOKED,
 107         WRITE_STRINGIFY,
 108         WRITE_HEXADECIMAL,
 109         WRITE_BINARY,
 110         WRITE_PAIR
 111 
 112     } WRITEMODE;
 113 
 114 // Linked list of variable names
 115 typedef struct _KeyVal {
 116 
 117         struct _KeyVal*  Next;
 118         char*            Keyword;       // Name of variable

 161         char           FileName[cmsMAX_PATH];    // File name if being read from file
 162         FILE*          Stream;                   // File stream or NULL if holded in memory
 163     } FILECTX;
 164 
 165 //Very simple string
 166 typedef struct {
 167 
 168         struct struct_it8* it8;
 169         cmsInt32Number max;
 170         cmsInt32Number len;
 171         char* begin;
 172     } string;
 173 
 174 
 175 // This struct hold all information about an open IT8 handler.
 176 typedef struct struct_it8 {
 177 
 178         cmsUInt32Number  TablesCount;                     // How many tables in this stream
 179         cmsUInt32Number  nTable;                          // The actual table
 180 




 181         TABLE Tab[MAXTABLES];
 182 
 183         // Memory management
 184         OWNEDMEM*      MemorySink;            // The storage backend
 185         SUBALLOCATOR   Allocator;             // String suballocator -- just to keep it fast
 186 
 187         // Parser state machine
 188         SYMBOL             sy;                // Current symbol
 189         int                ch;                // Current character
 190 
 191         cmsInt32Number     inum;              // integer value
 192         cmsFloat64Number   dnum;              // real value
 193 
 194         string*        id;            // identifier
 195         string*        str;           // string
 196 
 197         // Allowed keywords & datasets. They have visibility on whole stream
 198         KEYVALUE*      ValidKeywords;
 199         KEYVALUE*      ValidSampleID;
 200 

 220 
 221         cmsUInt8Number* Base;
 222         cmsUInt8Number* Ptr;        // For save-to-mem behaviour
 223         cmsUInt32Number Used;
 224         cmsUInt32Number Max;
 225 
 226     } SAVESTREAM;
 227 
 228 
 229 // ------------------------------------------------------ cmsIT8 parsing routines
 230 
 231 
 232 // A keyword
 233 typedef struct {
 234 
 235         const char *id;
 236         SYMBOL sy;
 237 
 238    } KEYWORD;
 239 
 240 // The keyword->symbol translation table. Sorting is required.
 241 static const KEYWORD TabKeys[] = {
 242 
 243         {"$INCLUDE",               SINCLUDE},   // This is an extension!
 244         {".INCLUDE",               SINCLUDE},   // This is an extension!
 245 
 246         {"BEGIN_DATA",             SBEGIN_DATA },
 247         {"BEGIN_DATA_FORMAT",      SBEGIN_DATA_FORMAT },
 248         {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID},
 249         {"END_DATA",               SEND_DATA},
 250         {"END_DATA_FORMAT",        SEND_DATA_FORMAT},
 251         {"KEYWORD",                SKEYWORD}
 252         };
 253 
 254 #define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))


















 255 
 256 // Predefined properties
 257 
 258 // A property
 259 typedef struct {
 260         const char *id;    // The identifier
 261         WRITEMODE as;      // How is supposed to be written
 262     } PROPERTY;
 263 
 264 static PROPERTY PredefinedProperties[] = {
 265 
 266         {"NUMBER_OF_FIELDS", WRITE_UNCOOKED},    // Required - NUMBER OF FIELDS
 267         {"NUMBER_OF_SETS",   WRITE_UNCOOKED},    // Required - NUMBER OF SETS
 268         {"ORIGINATOR",       WRITE_STRINGIFY},   // Required - Identifies the specific system, organization or individual that created the data file.
 269         {"FILE_DESCRIPTOR",  WRITE_STRINGIFY},   // Required - Describes the purpose or contents of the data file.
 270         {"CREATED",          WRITE_STRINGIFY},   // Required - Indicates date of creation of the data file.
 271         {"DESCRIPTOR",       WRITE_STRINGIFY},   // Required  - Describes the purpose or contents of the data file.
 272         {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY},   // The diffuse geometry used. Allowed values are "sphere" or "opal".
 273         {"MANUFACTURER",     WRITE_STRINGIFY},
 274         {"MANUFACTURE",      WRITE_STRINGIFY},   // Some broken Fuji targets does store this value

 438 char* StringPtr(string* s)
 439 {
 440     return s->begin;
 441 }
 442 
 443 static
 444 void StringCat(string* s, const char* c)
 445 {
 446     while (*c)
 447     {
 448         StringAppend(s, *c);
 449         c++;
 450     }
 451 }
 452 
 453 
 454 // Checks whatever c is a separator
 455 static
 456 cmsBool isseparator(int c)
 457 {
 458     return (c == ' ') || (c == '\t') ;
 459 }
 460 
 461 // Checks whatever c is a valid identifier char
 462 static
 463 cmsBool ismiddle(int c)
 464 {
 465    return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127));
 466 }
 467 
 468 // Checks whatsever c is a valid identifier middle char.
 469 static
 470 cmsBool isidchar(int c)
 471 {
 472    return isalnum(c) || ismiddle(c);
 473 }
 474 
 475 // Checks whatsever c is a valid identifier first char.
 476 static
 477 cmsBool isfirstidchar(int c)
 478 {
 479      return !isdigit(c) && ismiddle(c);
 480 }
 481 
 482 // Guess whether the supplied path looks like an absolute path
 483 static
 484 cmsBool isabsolutepath(const char *path)
 485 {
 486     char ThreeChars[4];
 487 
 488     if(path == NULL)
 489         return FALSE;
 490     if (path[0] == 0)
 491         return FALSE;
 492 
 493     strncpy(ThreeChars, path, 3);
 494     ThreeChars[3] = 0;
 495 
 496     if(ThreeChars[0] == DIR_CHAR)
 497         return TRUE;
 498 
 499 #ifdef  CMS_IS_WINDOWS_
 500     if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':')
 501         return TRUE;
 502 #endif
 503     return FALSE;
 504 }
 505 
 506 
 507 // Makes a file path based on a given reference path
 508 // NOTE: this function doesn't check if the path exists or even if it's legal
 509 static
 510 cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen)
 511 {
 512     char *tail;
 513     cmsUInt32Number len;
 514 
 515     // Already absolute?
 516     if (isabsolutepath(relPath)) {
 517 
 518         strncpy(buffer, relPath, MaxLen);
 519         buffer[MaxLen-1] = 0;
 520         return TRUE;
 521     }
 522 
 523     // No, search for last
 524     strncpy(buffer, basePath, MaxLen);
 525     buffer[MaxLen-1] = 0;
 526 
 527     tail = strrchr(buffer, DIR_CHAR);
 528     if (tail == NULL) return FALSE;    // Is not absolute and has no separators??
 529 
 530     len = (cmsUInt32Number) (tail - buffer);
 531     if (len >= MaxLen) return FALSE;
 532 
 533     // No need to assure zero terminator over here
 534     strncpy(tail + 1, relPath, MaxLen - len);
 535 
 536     return TRUE;
 537 }
 538 
 539 
 540 // Make sure no exploit is being even tried
 541 static
 542 const char* NoMeta(const char* str)
 543 {
 544     if (strchr(str, '%') != NULL)

 586         if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream))  {
 587 
 588             if (it8 ->IncludeSP > 0) {
 589 
 590                 fclose(it8 ->FileStack[it8->IncludeSP--]->Stream);
 591                 it8 -> ch = ' ';                            // Whitespace to be ignored
 592 
 593             } else
 594                 it8 ->ch = 0;   // EOF
 595         }
 596     }
 597     else {
 598         it8->ch = *it8->Source;
 599         if (it8->ch) it8->Source++;
 600     }
 601 }
 602 
 603 
 604 // Try to see if current identifier is a keyword, if so return the referred symbol
 605 static
 606 SYMBOL BinSrchKey(const char *id)
 607 {
 608     int l = 1;
 609     int r = NUMKEYS;
 610     int x, res;
 611 
 612     while (r >= l)
 613     {
 614         x = (l+r)/2;
 615         res = cmsstrcasecmp(id, TabKeys[x-1].id);
 616         if (res == 0) return TabKeys[x-1].sy;
 617         if (res < 0) r = x - 1;
 618         else l = x + 1;
 619     }
 620 
 621     return SUNDEFINED;
 622 }
 623 
 624 
 625 // 10 ^n
 626 static
 627 cmsFloat64Number xpow10(int n)
 628 {
 629     return pow(10, (cmsFloat64Number) n);

 759 
 760         e = 0;
 761         while (*Buffer && isdigit((int)*Buffer)) {
 762 
 763             cmsInt32Number digit = (*Buffer - '0');
 764 
 765             if ((cmsFloat64Number)e * 10.0 + digit < (cmsFloat64Number)+2147483647.0)
 766                 e = e * 10 + digit;
 767 
 768             if (*Buffer) Buffer++;
 769         }
 770 
 771         e = sgn*e;
 772         dnum = dnum * xpow10(e);
 773     }
 774 
 775     return sign * dnum;
 776 }
 777 
 778 
 779 // Reads a string, special case to avoid infinite resursion on .include
 780 static
 781 void InStringSymbol(cmsIT8* it8)
 782 {
 783     while (isseparator(it8->ch))
 784         NextCh(it8);
 785 
 786     if (it8->ch == '\'' || it8->ch == '\"')
 787     {
 788         int sng;
 789 
 790         sng = it8->ch;
 791         StringClear(it8->str);
 792 
 793         NextCh(it8);
 794 
 795         while (it8->ch != sng) {
 796 
 797             if (it8->ch == '\n' || it8->ch == '\r' || it8->ch == 0) break;
 798             else {
 799                 StringAppend(it8->str, (char)it8->ch);

 816     SYMBOL key;
 817 
 818     do {
 819 
 820         while (isseparator(it8->ch))
 821             NextCh(it8);
 822 
 823         if (isfirstidchar(it8->ch)) {          // Identifier
 824 
 825             StringClear(it8->id);
 826 
 827             do {
 828 
 829                 StringAppend(it8->id, (char) it8->ch);
 830 
 831                 NextCh(it8);
 832 
 833             } while (isidchar(it8->ch));
 834 
 835 
 836             key = BinSrchKey(StringPtr(it8->id));


 837             if (key == SUNDEFINED) it8->sy = SIDENT;
 838             else it8->sy = key;
 839 
 840         }
 841         else                         // Is a number?
 842             if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+')
 843             {
 844                 int sign = 1;
 845 
 846                 if (it8->ch == '-') {
 847                     sign = -1;
 848                     NextCh(it8);
 849                 }
 850 
 851                 it8->inum = 0;
 852                 it8->sy   = SINUM;
 853 
 854                 if (it8->ch == '0') {          // 0xnnnn (Hexa) or 0bnnnn (Binary)
 855 
 856                     NextCh(it8);

 925                     return;
 926                 }
 927 
 928                 it8 -> inum *= sign;
 929 
 930                 // Special case. Numbers followed by letters are taken as identifiers
 931 
 932                 if (isidchar(it8 ->ch)) {
 933 
 934                     char buffer[127];
 935 
 936                     if (it8 ->sy == SINUM) {
 937 
 938                         snprintf(buffer, sizeof(buffer), "%d", it8->inum);
 939                     }
 940                     else {
 941 
 942                         snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum);
 943                     }
 944 

 945                     StringCat(it8->id, buffer);
 946 
 947                     do {
 948 
 949                         StringAppend(it8->id, (char) it8->ch);
 950 
 951                         NextCh(it8);
 952 
 953                     } while (isidchar(it8->ch));
 954 
 955                     it8->sy = SIDENT;
 956                 }
 957                 return;
 958 
 959             }
 960             else
 961                 switch ((int) it8->ch) {
 962 
 963         // Eof stream markers
 964         case '\x1a':
 965         case 0:
 966         case -1:
 967             it8->sy = SEOF;
 968             break;
 969 
 970 
 971         // Next line
 972         case '\r':
 973             NextCh(it8);
 974             if (it8 ->ch == '\n')
 975                 NextCh(it8);
 976             it8->sy = SEOLN;
 977             it8->lineno++;
 978             break;
 979 
 980         case '\n':
 981             NextCh(it8);
 982             it8->sy = SEOLN;
 983             it8->lineno++;
 984             break;
 985 
 986         // Comment
 987         case '#':
 988             NextCh(it8);
 989             while (it8->ch && it8->ch != '\n' && it8->ch != '\r')
 990                 NextCh(it8);
 991 
 992             it8->sy = SCOMMENT;
 993             break;
 994 

1275 
1276     return FALSE;
1277 }
1278 
1279 
1280 
1281 // Add a property into a linked list
1282 static
1283 KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
1284 {
1285     KEYVALUE* p;
1286     KEYVALUE* last;
1287 
1288 
1289     // Check if property is already in list
1290 
1291     if (IsAvailableOnList(*Head, Key, Subkey, &p)) {
1292 
1293         // This may work for editing properties
1294 
1295         //     return SynError(it8, "duplicate key <%s>", Key);





1296     }
1297     else {
1298 
1299         last = p;
1300 
1301         // Allocate the container
1302         p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE));
1303         if (p == NULL)
1304         {
1305             SynError(it8, "AddToList: out of memory");
1306             return NULL;
1307         }
1308 
1309         // Store name and value
1310         p->Keyword = AllocString(it8, Key);
1311         p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
1312 
1313         // Keep the container in our list
1314         if (*Head == NULL) {
1315             *Head = p;

1396 
1397      return (cmsInt32Number) nTable;
1398 }
1399 
1400 
1401 
1402 // Init an empty container
1403 cmsHANDLE  CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
1404 {
1405     cmsIT8* it8;
1406     cmsUInt32Number i;
1407 
1408     it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8));
1409     if (it8 == NULL) return NULL;
1410 
1411     AllocTable(it8);
1412 
1413     it8->MemoryBlock = NULL;
1414     it8->MemorySink  = NULL;
1415 


1416     it8 ->nTable = 0;
1417 
1418     it8->ContextID = ContextID;
1419     it8->Allocator.Used = 0;
1420     it8->Allocator.Block = NULL;
1421     it8->Allocator.BlockSize = 0;
1422 
1423     it8->ValidKeywords = NULL;
1424     it8->ValidSampleID = NULL;
1425 
1426     it8 -> sy = SUNDEFINED;
1427     it8 -> ch = ' ';
1428     it8 -> Source = NULL;
1429     it8 -> inum = 0;
1430     it8 -> dnum = 0.0;
1431 
1432     it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
1433     it8->IncludeSP   = 0;
1434     it8 -> lineno = 1;
1435 

1677     else {
1678         // Some dumb analizers warns of possible overflow here, just take a look couple of lines above.
1679         t->Data = (char**)AllocChunk(it8, ((cmsUInt32Number)t->nSamples + 1) * ((cmsUInt32Number)t->nPatches + 1) * sizeof(char*));
1680         if (t->Data == NULL) {
1681 
1682             SynError(it8, "AllocateDataSet: Unable to allocate data array");
1683             return FALSE;
1684         }
1685     }
1686 
1687     return TRUE;
1688 }
1689 
1690 static
1691 char* GetData(cmsIT8* it8, int nSet, int nField)
1692 {
1693     TABLE* t = GetTable(it8);
1694     int nSamples    = t -> nSamples;
1695     int nPatches    = t -> nPatches;
1696 
1697     if (nSet >= nPatches || nField >= nSamples)
1698         return NULL;
1699 
1700     if (!t->Data) return NULL;
1701     return t->Data [nSet * nSamples + nField];
1702 }
1703 
1704 static
1705 cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val)
1706 {
1707     TABLE* t = GetTable(it8);
1708 
1709     if (!t->Data) {
1710         if (!AllocateDataSet(it8)) return FALSE;
1711     }
1712 
1713     if (!t->Data) return FALSE;
1714 
1715     if (nSet > t -> nPatches || nSet < 0) {
1716 
1717             return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches);

1862 
1863         WriteStr (fp, "\n");
1864     }
1865 
1866 }
1867 
1868 
1869 // Writes the data format
1870 static
1871 void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
1872 {
1873     int i, nSamples;
1874     TABLE* t = GetTable(it8);
1875 
1876     if (!t -> DataFormat) return;
1877 
1878        WriteStr(fp, "BEGIN_DATA_FORMAT\n");
1879        WriteStr(fp, " ");
1880        nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
1881 
1882        for (i = 0; i < nSamples; i++) {
1883 
1884               WriteStr(fp, t->DataFormat[i]);
1885               WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t"));
1886           }



1887 
1888        WriteStr (fp, "END_DATA_FORMAT\n");
1889 }
1890 
1891 
1892 // Writes data array
1893 static
1894 void WriteData(SAVESTREAM* fp, cmsIT8* it8)
1895 {
1896        int  i, j;
1897        TABLE* t = GetTable(it8);
1898 
1899        if (!t->Data) return;
1900 
1901        WriteStr (fp, "BEGIN_DATA\n");
1902 
1903        t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
1904 
1905        for (i = 0; i < t-> nPatches; i++) {
1906 
1907               WriteStr(fp, " ");
1908 
1909               for (j = 0; j < t->nSamples; j++) {
1910 
1911                      char *ptr = t->Data[i*t->nSamples+j];
1912 
1913                      if (ptr == NULL) WriteStr(fp, "\"\"");
1914                      else {
1915                          // If value contains whitespace, enclose within quote
1916 
1917                          if (strchr(ptr, ' ') != NULL) {


1918 
1919                              WriteStr(fp, "\"");
1920                              WriteStr(fp, ptr);
1921                              WriteStr(fp, "\"");
1922                          }
1923                          else
1924                             WriteStr(fp, ptr);
1925                      }
1926 
1927                      WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t"));
1928               }









1929        }
1930        WriteStr (fp, "END_DATA\n");
1931 }
1932 
1933 
1934 
1935 // Saves whole file
1936 cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
1937 {
1938     SAVESTREAM sd;
1939     cmsUInt32Number i;
1940     cmsIT8* it8 = (cmsIT8*) hIT8;
1941 
1942     memset(&sd, 0, sizeof(sd));
1943 
1944     sd.stream = fopen(cFileName, "wt");
1945     if (!sd.stream) return FALSE;
1946 
1947     for (i=0; i < it8 ->TablesCount; i++) {
1948 
1949             cmsIT8SetTable(hIT8, i);
1950             WriteHeader(it8, &sd);
1951             WriteDataFormat(&sd, it8);
1952             WriteData(&sd, it8);










1953     }
1954 
1955     if (fclose(sd.stream) != 0) return FALSE;
1956 
1957     return TRUE;





1958 }
1959 
1960 
1961 // Saves to memory
1962 cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded)
1963 {
1964     SAVESTREAM sd;
1965     cmsUInt32Number i;
1966     cmsIT8* it8 = (cmsIT8*) hIT8;
1967 
1968     memset(&sd, 0, sizeof(sd));
1969 
1970     sd.stream = NULL;
1971     sd.Base   = (cmsUInt8Number*) MemPtr;
1972     sd.Ptr    = sd.Base;
1973 
1974     sd.Used = 0;
1975 
1976     if (sd.Base && (*BytesNeeded > 0)) {
1977 

2314 
2315             default:
2316                     if (!HeaderSection(it8)) return FALSE;
2317            }
2318 
2319     }
2320 
2321     return (it8 -> sy != SSYNERROR);
2322 }
2323 
2324 
2325 
2326 // Init useful pointers
2327 
2328 static
2329 void CookPointers(cmsIT8* it8)
2330 {
2331     int idField, i;
2332     char* Fld;
2333     cmsUInt32Number j;
2334     cmsUInt32Number nOldTable = it8 ->nTable;
2335 
2336     for (j=0; j < it8 ->TablesCount; j++) {
2337 
2338     TABLE* t = it8 ->Tab + j;
2339 
2340     t -> SampleID = 0;
2341     it8 ->nTable = j;
2342 
2343     for (idField = 0; idField < t -> nSamples; idField++)
2344     {
2345         if (t ->DataFormat == NULL){
2346             SynError(it8, "Undefined DATA_FORMAT");
2347             return;
2348         }
2349 
2350         Fld = t->DataFormat[idField];
2351         if (!Fld) continue;
2352 
2353 
2354         if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
2355 
2356             t -> SampleID = idField;
2357         }
2358 
2359         // "LABEL" is an extension. It keeps references to forward tables
2360 
2361         if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
2362 
2363             // Search for table references...
2364             for (i = 0; i < t->nPatches; i++) {
2365 
2366                 char* Label = GetData(it8, i, idField);
2367 
2368                 if (Label) {
2369 
2370                     cmsUInt32Number k;
2371 
2372                     // This is the label, search for a table containing
2373                     // this property
2374 
2375                     for (k = 0; k < it8->TablesCount; k++) {
2376 
2377                         TABLE* Table = it8->Tab + k;
2378                         KEYVALUE* p;
2379 
2380                         if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
2381 
2382                             // Available, keep type and table
2383                             char Buffer[256];
2384 
2385                             char* Type = p->Value;
2386                             int  nTable = (int)k;
2387 
2388                             snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
2389 
2390                             SetData(it8, i, idField, Buffer);

2391                         }
2392                     }
2393 
2394 
2395                 }
2396 
2397             }
2398 
2399 
2400         }
2401 
2402     }
2403     }
2404 
2405     it8 ->nTable = nOldTable;
2406 }
2407 
2408 // Try to infere if the file is a CGATS/IT8 file at all. Read first line
2409 // that should be something like some printable characters plus a \n
2410 // returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line?
2411 static
2412 int IsMyBlock(const cmsUInt8Number* Buffer, cmsUInt32Number n)
2413 {
2414     int words = 1, space = 0, quot = 0;
2415     cmsUInt32Number i;
2416 
2417     if (n < 10) return 0;   // Too small
2418 
2419     if (n > 132)
2420         n = 132;
2421 
2422     for (i = 1; i < n; i++) {
2423 
2424         switch(Buffer[i])
2425         {

2476 cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cmsUInt32Number len)
2477 {
2478     cmsHANDLE hIT8;
2479     cmsIT8*  it8;
2480     int type;
2481 
2482     _cmsAssert(Ptr != NULL);
2483     _cmsAssert(len != 0);
2484 
2485     type = IsMyBlock((const cmsUInt8Number*)Ptr, len);
2486     if (type == 0) return NULL;
2487 
2488     hIT8 = cmsIT8Alloc(ContextID);
2489     if (!hIT8) return NULL;
2490 
2491     it8 = (cmsIT8*) hIT8;
2492     it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1);
2493     if (it8->MemoryBlock == NULL)
2494     {
2495         cmsIT8Free(hIT8);
2496         return FALSE;
2497     }
2498 
2499     strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
2500     it8 ->MemoryBlock[len] = 0;
2501 
2502     strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1);
2503     it8-> Source = it8 -> MemoryBlock;
2504 
2505     if (!ParseIT8(it8, type-1)) {
2506 
2507         cmsIT8Free(hIT8);
2508         return FALSE;
2509     }
2510 
2511     CookPointers(it8);
2512     it8 ->nTable = 0;
2513 
2514     _cmsFree(ContextID, it8->MemoryBlock);
2515     it8 -> MemoryBlock = NULL;
2516 
2517     return hIT8;
2518 
2519 
2520 }
2521 
2522 
2523 cmsHANDLE  CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName)
2524 {
2525 
2526      cmsHANDLE hIT8;
2527      cmsIT8*  it8;
2528      int type;

2585 cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames)
2586 {
2587     cmsIT8* it8 = (cmsIT8*) hIT8;
2588     KEYVALUE* p;
2589     cmsUInt32Number n;
2590     char **Props;
2591     TABLE* t;
2592 
2593     _cmsAssert(hIT8 != NULL);
2594 
2595     t = GetTable(it8);
2596 
2597     // Pass#1 - count properties
2598 
2599     n = 0;
2600     for (p = t -> HeaderList;  p != NULL; p = p->Next) {
2601         n++;
2602     }
2603 
2604 
2605         Props = (char**)AllocChunk(it8, sizeof(char*) * n);
2606         if (Props != NULL) {
2607 
2608                 // Pass#2 - Fill pointers
2609                 n = 0;
2610                 for (p = t->HeaderList; p != NULL; p = p->Next) {
2611                         Props[n++] = p->Keyword;
2612                 }
2613 




2614         }
2615         *PropertyNames = Props;


2616 
2617     return n;
2618 }
2619 
2620 cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
2621 {
2622     cmsIT8* it8 = (cmsIT8*) hIT8;
2623     KEYVALUE *p, *tmp;
2624     cmsUInt32Number n;
2625     const char **Props;
2626     TABLE* t;
2627 
2628     _cmsAssert(hIT8 != NULL);
2629 
2630 
2631     t = GetTable(it8);
2632 
2633     if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) {
2634         *SubpropertyNames = 0;
2635         return 0;

2955 
2956     it8->Tab[it8->nTable].SampleID = pos;
2957     return TRUE;
2958 }
2959 
2960 
2961 void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
2962 {
2963     cmsIT8* it8 = (cmsIT8*) hIT8;
2964 
2965     _cmsAssert(hIT8 != NULL);
2966 
2967     if (Formatter == NULL)
2968         strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
2969     else
2970         strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter));
2971 
2972     it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
2973 }
2974 










































































































































































































































  70 #    include <io.h>
  71 #    define DIR_CHAR    '\\'
  72 #else
  73 #    define DIR_CHAR    '/'
  74 #endif
  75 
  76 
  77 // Symbols
  78 typedef enum {
  79 
  80         SUNDEFINED,
  81         SINUM,      // Integer
  82         SDNUM,      // Real
  83         SIDENT,     // Identifier
  84         SSTRING,    // string
  85         SCOMMENT,   // comment
  86         SEOLN,      // End of line
  87         SEOF,       // End of stream
  88         SSYNERROR,  // Syntax error found on stream
  89 
  90         // IT8 symbols
  91 
  92         SBEGIN_DATA,
  93         SBEGIN_DATA_FORMAT,
  94         SEND_DATA,
  95         SEND_DATA_FORMAT,
  96         SKEYWORD,
  97         SDATA_FORMAT_ID,
  98         SINCLUDE,
  99 
 100         // Cube symbols
 101 
 102         SDOMAIN_MAX,
 103         SDOMAIN_MIN,
 104         S_LUT1D_SIZE,
 105         S_LUT1D_INPUT_RANGE,
 106         S_LUT3D_SIZE,
 107         S_LUT3D_INPUT_RANGE,
 108         S_LUT_IN_VIDEO_RANGE,
 109         S_LUT_OUT_VIDEO_RANGE,
 110         STITLE
 111 
 112     } SYMBOL;
 113 
 114 
 115 // How to write the value
 116 typedef enum {
 117 
 118         WRITE_UNCOOKED,
 119         WRITE_STRINGIFY,
 120         WRITE_HEXADECIMAL,
 121         WRITE_BINARY,
 122         WRITE_PAIR
 123 
 124     } WRITEMODE;
 125 
 126 // Linked list of variable names
 127 typedef struct _KeyVal {
 128 
 129         struct _KeyVal*  Next;
 130         char*            Keyword;       // Name of variable

 173         char           FileName[cmsMAX_PATH];    // File name if being read from file
 174         FILE*          Stream;                   // File stream or NULL if holded in memory
 175     } FILECTX;
 176 
 177 //Very simple string
 178 typedef struct {
 179 
 180         struct struct_it8* it8;
 181         cmsInt32Number max;
 182         cmsInt32Number len;
 183         char* begin;
 184     } string;
 185 
 186 
 187 // This struct hold all information about an open IT8 handler.
 188 typedef struct struct_it8 {
 189 
 190         cmsUInt32Number  TablesCount;                     // How many tables in this stream
 191         cmsUInt32Number  nTable;                          // The actual table
 192 
 193         // Partser type
 194         cmsBool        IsCUBE;
 195 
 196         // Tables
 197         TABLE Tab[MAXTABLES];
 198 
 199         // Memory management
 200         OWNEDMEM*      MemorySink;            // The storage backend
 201         SUBALLOCATOR   Allocator;             // String suballocator -- just to keep it fast
 202 
 203         // Parser state machine
 204         SYMBOL             sy;                // Current symbol
 205         int                ch;                // Current character
 206 
 207         cmsInt32Number     inum;              // integer value
 208         cmsFloat64Number   dnum;              // real value
 209 
 210         string*        id;            // identifier
 211         string*        str;           // string
 212 
 213         // Allowed keywords & datasets. They have visibility on whole stream
 214         KEYVALUE*      ValidKeywords;
 215         KEYVALUE*      ValidSampleID;
 216 

 236 
 237         cmsUInt8Number* Base;
 238         cmsUInt8Number* Ptr;        // For save-to-mem behaviour
 239         cmsUInt32Number Used;
 240         cmsUInt32Number Max;
 241 
 242     } SAVESTREAM;
 243 
 244 
 245 // ------------------------------------------------------ cmsIT8 parsing routines
 246 
 247 
 248 // A keyword
 249 typedef struct {
 250 
 251         const char *id;
 252         SYMBOL sy;
 253 
 254    } KEYWORD;
 255 
 256 // The keyword->symbol translation tables. Sorting is required.
 257 static const KEYWORD TabKeysIT8[] = {
 258 
 259         {"$INCLUDE",               SINCLUDE},   // This is an extension!
 260         {".INCLUDE",               SINCLUDE},   // This is an extension!
 261 
 262         {"BEGIN_DATA",             SBEGIN_DATA },
 263         {"BEGIN_DATA_FORMAT",      SBEGIN_DATA_FORMAT },
 264         {"DATA_FORMAT_IDENTIFIER", SDATA_FORMAT_ID},
 265         {"END_DATA",               SEND_DATA},
 266         {"END_DATA_FORMAT",        SEND_DATA_FORMAT},
 267         {"KEYWORD",                SKEYWORD}
 268         };
 269 
 270 #define NUMKEYS_IT8 (sizeof(TabKeysIT8)/sizeof(KEYWORD))
 271 
 272 static const KEYWORD TabKeysCUBE[] = {
 273 
 274         {"DOMAIN_MAX",             SDOMAIN_MAX },
 275         {"DOMAIN_MIN",             SDOMAIN_MIN },
 276         {"LUT_1D_SIZE",            S_LUT1D_SIZE },
 277         {"LUT_1D_INPUT_RANGE",     S_LUT1D_INPUT_RANGE },
 278         {"LUT_3D_SIZE",            S_LUT3D_SIZE },
 279         {"LUT_3D_INPUT_RANGE",     S_LUT3D_INPUT_RANGE },
 280         {"LUT_IN_VIDEO_RANGE",     S_LUT_IN_VIDEO_RANGE },
 281         {"LUT_OUT_VIDEO_RANGE",    S_LUT_OUT_VIDEO_RANGE },
 282         {"TITLE",                  STITLE }
 283 
 284 };
 285 
 286 #define NUMKEYS_CUBE (sizeof(TabKeysCUBE)/sizeof(KEYWORD))
 287 
 288 
 289 
 290 // Predefined properties
 291 
 292 // A property
 293 typedef struct {
 294         const char *id;    // The identifier
 295         WRITEMODE as;      // How is supposed to be written
 296     } PROPERTY;
 297 
 298 static PROPERTY PredefinedProperties[] = {
 299 
 300         {"NUMBER_OF_FIELDS", WRITE_UNCOOKED},    // Required - NUMBER OF FIELDS
 301         {"NUMBER_OF_SETS",   WRITE_UNCOOKED},    // Required - NUMBER OF SETS
 302         {"ORIGINATOR",       WRITE_STRINGIFY},   // Required - Identifies the specific system, organization or individual that created the data file.
 303         {"FILE_DESCRIPTOR",  WRITE_STRINGIFY},   // Required - Describes the purpose or contents of the data file.
 304         {"CREATED",          WRITE_STRINGIFY},   // Required - Indicates date of creation of the data file.
 305         {"DESCRIPTOR",       WRITE_STRINGIFY},   // Required  - Describes the purpose or contents of the data file.
 306         {"DIFFUSE_GEOMETRY", WRITE_STRINGIFY},   // The diffuse geometry used. Allowed values are "sphere" or "opal".
 307         {"MANUFACTURER",     WRITE_STRINGIFY},
 308         {"MANUFACTURE",      WRITE_STRINGIFY},   // Some broken Fuji targets does store this value

 472 char* StringPtr(string* s)
 473 {
 474     return s->begin;
 475 }
 476 
 477 static
 478 void StringCat(string* s, const char* c)
 479 {
 480     while (*c)
 481     {
 482         StringAppend(s, *c);
 483         c++;
 484     }
 485 }
 486 
 487 
 488 // Checks whatever c is a separator
 489 static
 490 cmsBool isseparator(int c)
 491 {
 492     return (c == ' ') || (c == '\t');
 493 }
 494 
 495 // Checks whatever c is a valid identifier char
 496 static
 497 cmsBool ismiddle(int c)
 498 {
 499    return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127));
 500 }
 501 
 502 // Checks whatsever c is a valid identifier middle char.
 503 static
 504 cmsBool isidchar(int c)
 505 {
 506    return isalnum(c) || ismiddle(c);
 507 }
 508 
 509 // Checks whatsever c is a valid identifier first char.
 510 static
 511 cmsBool isfirstidchar(int c)
 512 {
 513      return c != '-' && !isdigit(c) && ismiddle(c);
 514 }
 515 
 516 // Guess whether the supplied path looks like an absolute path
 517 static
 518 cmsBool isabsolutepath(const char *path)
 519 {
 520     char ThreeChars[4];
 521 
 522     if(path == NULL)
 523         return FALSE;
 524     if (path[0] == 0)
 525         return FALSE;
 526 
 527     strncpy(ThreeChars, path, 3);
 528     ThreeChars[3] = 0;
 529 
 530     if(ThreeChars[0] == DIR_CHAR)
 531         return TRUE;
 532 
 533 #ifdef  CMS_IS_WINDOWS_
 534     if (isalpha((int) ThreeChars[0]) && ThreeChars[1] == ':')
 535         return TRUE;
 536 #endif
 537     return FALSE;
 538 }
 539 
 540 
 541 // Makes a file path based on a given reference path
 542 // NOTE: this function doesn't check if the path exists or even if it's legal
 543 static
 544 cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffer, cmsUInt32Number MaxLen)
 545 {
 546     char *tail;
 547     cmsUInt32Number len;
 548 
 549     // Already absolute?
 550     if (isabsolutepath(relPath)) {
 551 
 552         memcpy(buffer, relPath, MaxLen);
 553         buffer[MaxLen-1] = 0;
 554         return TRUE;
 555     }
 556 
 557     // No, search for last
 558     memcpy(buffer, basePath, MaxLen);
 559     buffer[MaxLen-1] = 0;
 560 
 561     tail = strrchr(buffer, DIR_CHAR);
 562     if (tail == NULL) return FALSE;    // Is not absolute and has no separators??
 563 
 564     len = (cmsUInt32Number) (tail - buffer);
 565     if (len >= MaxLen) return FALSE;
 566 
 567     // No need to assure zero terminator over here
 568     strncpy(tail + 1, relPath, MaxLen - len);
 569 
 570     return TRUE;
 571 }
 572 
 573 
 574 // Make sure no exploit is being even tried
 575 static
 576 const char* NoMeta(const char* str)
 577 {
 578     if (strchr(str, '%') != NULL)

 620         if (feof(it8 -> FileStack[it8 ->IncludeSP]->Stream))  {
 621 
 622             if (it8 ->IncludeSP > 0) {
 623 
 624                 fclose(it8 ->FileStack[it8->IncludeSP--]->Stream);
 625                 it8 -> ch = ' ';                            // Whitespace to be ignored
 626 
 627             } else
 628                 it8 ->ch = 0;   // EOF
 629         }
 630     }
 631     else {
 632         it8->ch = *it8->Source;
 633         if (it8->ch) it8->Source++;
 634     }
 635 }
 636 
 637 
 638 // Try to see if current identifier is a keyword, if so return the referred symbol
 639 static
 640 SYMBOL BinSrchKey(const char *id, int NumKeys, const KEYWORD* TabKeys)
 641 {
 642     int l = 1;
 643     int r = NumKeys;
 644     int x, res;
 645 
 646     while (r >= l)
 647     {
 648         x = (l+r)/2;
 649         res = cmsstrcasecmp(id, TabKeys[x-1].id);
 650         if (res == 0) return TabKeys[x-1].sy;
 651         if (res < 0) r = x - 1;
 652         else l = x + 1;
 653     }
 654 
 655     return SUNDEFINED;
 656 }
 657 
 658 
 659 // 10 ^n
 660 static
 661 cmsFloat64Number xpow10(int n)
 662 {
 663     return pow(10, (cmsFloat64Number) n);

 793 
 794         e = 0;
 795         while (*Buffer && isdigit((int)*Buffer)) {
 796 
 797             cmsInt32Number digit = (*Buffer - '0');
 798 
 799             if ((cmsFloat64Number)e * 10.0 + digit < (cmsFloat64Number)+2147483647.0)
 800                 e = e * 10 + digit;
 801 
 802             if (*Buffer) Buffer++;
 803         }
 804 
 805         e = sgn*e;
 806         dnum = dnum * xpow10(e);
 807     }
 808 
 809     return sign * dnum;
 810 }
 811 
 812 
 813 // Reads a string, special case to avoid infinite recursion on .include
 814 static
 815 void InStringSymbol(cmsIT8* it8)
 816 {
 817     while (isseparator(it8->ch))
 818         NextCh(it8);
 819 
 820     if (it8->ch == '\'' || it8->ch == '\"')
 821     {
 822         int sng;
 823 
 824         sng = it8->ch;
 825         StringClear(it8->str);
 826 
 827         NextCh(it8);
 828 
 829         while (it8->ch != sng) {
 830 
 831             if (it8->ch == '\n' || it8->ch == '\r' || it8->ch == 0) break;
 832             else {
 833                 StringAppend(it8->str, (char)it8->ch);

 850     SYMBOL key;
 851 
 852     do {
 853 
 854         while (isseparator(it8->ch))
 855             NextCh(it8);
 856 
 857         if (isfirstidchar(it8->ch)) {          // Identifier
 858 
 859             StringClear(it8->id);
 860 
 861             do {
 862 
 863                 StringAppend(it8->id, (char) it8->ch);
 864 
 865                 NextCh(it8);
 866 
 867             } while (isidchar(it8->ch));
 868 
 869 
 870             key = BinSrchKey(StringPtr(it8->id),
 871                     it8->IsCUBE ? NUMKEYS_CUBE : NUMKEYS_IT8,
 872                     it8->IsCUBE ? TabKeysCUBE : TabKeysIT8);
 873             if (key == SUNDEFINED) it8->sy = SIDENT;
 874             else it8->sy = key;
 875 
 876         }
 877         else                         // Is a number?
 878             if (isdigit(it8->ch) || it8->ch == '.' || it8->ch == '-' || it8->ch == '+')
 879             {
 880                 int sign = 1;
 881 
 882                 if (it8->ch == '-') {
 883                     sign = -1;
 884                     NextCh(it8);
 885                 }
 886 
 887                 it8->inum = 0;
 888                 it8->sy   = SINUM;
 889 
 890                 if (it8->ch == '0') {          // 0xnnnn (Hexa) or 0bnnnn (Binary)
 891 
 892                     NextCh(it8);

 961                     return;
 962                 }
 963 
 964                 it8 -> inum *= sign;
 965 
 966                 // Special case. Numbers followed by letters are taken as identifiers
 967 
 968                 if (isidchar(it8 ->ch)) {
 969 
 970                     char buffer[127];
 971 
 972                     if (it8 ->sy == SINUM) {
 973 
 974                         snprintf(buffer, sizeof(buffer), "%d", it8->inum);
 975                     }
 976                     else {
 977 
 978                         snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum);
 979                     }
 980 
 981                     StringClear(it8->id);
 982                     StringCat(it8->id, buffer);
 983 
 984                     do {
 985 
 986                         StringAppend(it8->id, (char) it8->ch);
 987 
 988                         NextCh(it8);
 989 
 990                     } while (isidchar(it8->ch));
 991 
 992                     it8->sy = SIDENT;
 993                 }
 994                 return;
 995 
 996             }
 997             else
 998                 switch ((int) it8->ch) {
 999 
1000         // Eof stream markers
1001         case '\x1a':
1002         case 0:
1003         case -1:
1004             it8->sy = SEOF;
1005             break;
1006 
1007 
1008         // Next line
1009         case '\r':
1010             NextCh(it8);
1011             if (it8->ch == '\n')
1012                 NextCh(it8);
1013             it8->sy = SEOLN;
1014             it8->lineno++;
1015             break;
1016 
1017         case '\n':
1018             NextCh(it8);
1019             it8->sy = SEOLN;
1020             it8->lineno++;
1021             break;
1022 
1023         // Comment
1024         case '#':
1025             NextCh(it8);
1026             while (it8->ch && it8->ch != '\n' && it8->ch != '\r')
1027                 NextCh(it8);
1028 
1029             it8->sy = SCOMMENT;
1030             break;
1031 

1312 
1313     return FALSE;
1314 }
1315 
1316 
1317 
1318 // Add a property into a linked list
1319 static
1320 KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *Subkey, const char* xValue, WRITEMODE WriteAs)
1321 {
1322     KEYVALUE* p;
1323     KEYVALUE* last;
1324 
1325 
1326     // Check if property is already in list
1327 
1328     if (IsAvailableOnList(*Head, Key, Subkey, &p)) {
1329 
1330         // This may work for editing properties
1331 
1332         if (cmsstrcasecmp(Key, "NUMBER_OF_FIELDS") == 0 ||
1333             cmsstrcasecmp(Key, "NUMBER_OF_SETS") == 0) {
1334 
1335             SynError(it8, "duplicate key <%s>", Key);
1336             return NULL;
1337         }
1338     }
1339     else {
1340 
1341         last = p;
1342 
1343         // Allocate the container
1344         p = (KEYVALUE*) AllocChunk(it8, sizeof(KEYVALUE));
1345         if (p == NULL)
1346         {
1347             SynError(it8, "AddToList: out of memory");
1348             return NULL;
1349         }
1350 
1351         // Store name and value
1352         p->Keyword = AllocString(it8, Key);
1353         p->Subkey = (Subkey == NULL) ? NULL : AllocString(it8, Subkey);
1354 
1355         // Keep the container in our list
1356         if (*Head == NULL) {
1357             *Head = p;

1438 
1439      return (cmsInt32Number) nTable;
1440 }
1441 
1442 
1443 
1444 // Init an empty container
1445 cmsHANDLE  CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
1446 {
1447     cmsIT8* it8;
1448     cmsUInt32Number i;
1449 
1450     it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8));
1451     if (it8 == NULL) return NULL;
1452 
1453     AllocTable(it8);
1454 
1455     it8->MemoryBlock = NULL;
1456     it8->MemorySink  = NULL;
1457 
1458     it8->IsCUBE = FALSE;
1459 
1460     it8 ->nTable = 0;
1461 
1462     it8->ContextID = ContextID;
1463     it8->Allocator.Used = 0;
1464     it8->Allocator.Block = NULL;
1465     it8->Allocator.BlockSize = 0;
1466 
1467     it8->ValidKeywords = NULL;
1468     it8->ValidSampleID = NULL;
1469 
1470     it8 -> sy = SUNDEFINED;
1471     it8 -> ch = ' ';
1472     it8 -> Source = NULL;
1473     it8 -> inum = 0;
1474     it8 -> dnum = 0.0;
1475 
1476     it8->FileStack[0] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
1477     it8->IncludeSP   = 0;
1478     it8 -> lineno = 1;
1479 

1721     else {
1722         // Some dumb analizers warns of possible overflow here, just take a look couple of lines above.
1723         t->Data = (char**)AllocChunk(it8, ((cmsUInt32Number)t->nSamples + 1) * ((cmsUInt32Number)t->nPatches + 1) * sizeof(char*));
1724         if (t->Data == NULL) {
1725 
1726             SynError(it8, "AllocateDataSet: Unable to allocate data array");
1727             return FALSE;
1728         }
1729     }
1730 
1731     return TRUE;
1732 }
1733 
1734 static
1735 char* GetData(cmsIT8* it8, int nSet, int nField)
1736 {
1737     TABLE* t = GetTable(it8);
1738     int nSamples    = t -> nSamples;
1739     int nPatches    = t -> nPatches;
1740 
1741     if (nSet < 0 || nSet >= nPatches || nField < 0 || nField >= nSamples)
1742         return NULL;
1743 
1744     if (!t->Data) return NULL;
1745     return t->Data [nSet * nSamples + nField];
1746 }
1747 
1748 static
1749 cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val)
1750 {
1751     TABLE* t = GetTable(it8);
1752 
1753     if (!t->Data) {
1754         if (!AllocateDataSet(it8)) return FALSE;
1755     }
1756 
1757     if (!t->Data) return FALSE;
1758 
1759     if (nSet > t -> nPatches || nSet < 0) {
1760 
1761             return SynError(it8, "Patch %d out of range, there are %d patches", nSet, t -> nPatches);

1906 
1907         WriteStr (fp, "\n");
1908     }
1909 
1910 }
1911 
1912 
1913 // Writes the data format
1914 static
1915 void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
1916 {
1917     int i, nSamples;
1918     TABLE* t = GetTable(it8);
1919 
1920     if (!t -> DataFormat) return;
1921 
1922        WriteStr(fp, "BEGIN_DATA_FORMAT\n");
1923        WriteStr(fp, " ");
1924        nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
1925 
1926        if (nSamples <= t->nSamples) {
1927 
1928            for (i = 0; i < nSamples; i++) {
1929 
1930                WriteStr(fp, t->DataFormat[i]);
1931                WriteStr(fp, ((i == (nSamples - 1)) ? "\n" : "\t"));
1932            }
1933        }
1934 
1935        WriteStr (fp, "END_DATA_FORMAT\n");
1936 }
1937 
1938 
1939 // Writes data array
1940 static
1941 void WriteData(SAVESTREAM* fp, cmsIT8* it8)
1942 {
1943        int  i, j, nPatches;
1944        TABLE* t = GetTable(it8);
1945 
1946        if (!t->Data) return;
1947 
1948        WriteStr (fp, "BEGIN_DATA\n");
1949 
1950        nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
1951 
1952        if (nPatches <= t->nPatches) {
1953 
1954            for (i = 0; i < nPatches; i++) {
1955 
1956                WriteStr(fp, " ");
1957 
1958                for (j = 0; j < t->nSamples; j++) {
1959 
1960                    char* ptr = t->Data[i * t->nSamples + j];


1961 
1962                    if (ptr == NULL) WriteStr(fp, "\"\"");
1963                    else {
1964                        // If value contains whitespace, enclose within quote
1965 
1966                        if (strchr(ptr, ' ') != NULL) {






1967 
1968                            WriteStr(fp, "\"");
1969                            WriteStr(fp, ptr);
1970                            WriteStr(fp, "\"");
1971                        }
1972                        else
1973                            WriteStr(fp, ptr);
1974                    }
1975 
1976                    WriteStr(fp, ((j == (t->nSamples - 1)) ? "\n" : "\t"));
1977                }
1978            }
1979        }
1980        WriteStr (fp, "END_DATA\n");
1981 }
1982 
1983 
1984 
1985 // Saves whole file
1986 cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
1987 {
1988     SAVESTREAM sd;
1989     cmsUInt32Number i;
1990     cmsIT8* it8 = (cmsIT8*) hIT8;
1991 
1992     memset(&sd, 0, sizeof(sd));
1993 
1994     sd.stream = fopen(cFileName, "wt");
1995     if (!sd.stream) return FALSE;
1996 
1997     for (i=0; i < it8 ->TablesCount; i++) {
1998 
1999         TABLE* t;
2000 
2001         if (cmsIT8SetTable(hIT8, i) < 0) goto Error;
2002 
2003         /**
2004         * Check for wrong data
2005         */
2006         t = GetTable(it8);
2007         if (t->Data == NULL) goto Error;
2008         if (t->DataFormat == NULL) goto Error;
2009 
2010         WriteHeader(it8, &sd);
2011         WriteDataFormat(&sd, it8);
2012         WriteData(&sd, it8);
2013     }
2014 
2015     if (fclose(sd.stream) != 0) return FALSE;

2016     return TRUE;
2017 
2018 Error:
2019     fclose(sd.stream);
2020     return FALSE;
2021 
2022 }
2023 
2024 
2025 // Saves to memory
2026 cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* BytesNeeded)
2027 {
2028     SAVESTREAM sd;
2029     cmsUInt32Number i;
2030     cmsIT8* it8 = (cmsIT8*) hIT8;
2031 
2032     memset(&sd, 0, sizeof(sd));
2033 
2034     sd.stream = NULL;
2035     sd.Base   = (cmsUInt8Number*) MemPtr;
2036     sd.Ptr    = sd.Base;
2037 
2038     sd.Used = 0;
2039 
2040     if (sd.Base && (*BytesNeeded > 0)) {
2041 

2378 
2379             default:
2380                     if (!HeaderSection(it8)) return FALSE;
2381            }
2382 
2383     }
2384 
2385     return (it8 -> sy != SSYNERROR);
2386 }
2387 
2388 
2389 
2390 // Init useful pointers
2391 
2392 static
2393 void CookPointers(cmsIT8* it8)
2394 {
2395     int idField, i;
2396     char* Fld;
2397     cmsUInt32Number j;
2398     cmsUInt32Number nOldTable = it8->nTable;
2399 
2400     for (j = 0; j < it8->TablesCount; j++) {
2401 
2402         TABLE* t = it8->Tab + j;
2403 
2404         t->SampleID = 0;
2405         it8->nTable = j;
2406 
2407         for (idField = 0; idField < t->nSamples; idField++)
2408         {
2409             if (t->DataFormat == NULL) {
2410                 SynError(it8, "Undefined DATA_FORMAT");
2411                 return;
2412             }
2413 
2414             Fld = t->DataFormat[idField];
2415             if (!Fld) continue;
2416 
2417 
2418             if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
2419 
2420                 t->SampleID = idField;
2421             }
2422 
2423             // "LABEL" is an extension. It keeps references to forward tables
2424 
2425             if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
2426 
2427                 // Search for table references...
2428                 for (i = 0; i < t->nPatches; i++) {
2429 
2430                     char* Label = GetData(it8, i, idField);
2431 
2432                     if (Label) {
2433 
2434                         cmsUInt32Number k;
2435 
2436                         // This is the label, search for a table containing
2437                         // this property
2438 
2439                         for (k = 0; k < it8->TablesCount; k++) {
2440 
2441                             TABLE* Table = it8->Tab + k;
2442                             KEYVALUE* p;
2443 
2444                             if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
2445 
2446                                 // Available, keep type and table
2447                                 char Buffer[256];
2448 
2449                                 char* Type = p->Value;
2450                                 int  nTable = (int)k;
2451 
2452                                 snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
2453 
2454                                 SetData(it8, i, idField, Buffer);
2455                             }
2456                         }
2457                     }


2458                 }

2459             }


2460         }


2461     }
2462 
2463     it8->nTable = nOldTable;
2464 }
2465 
2466 // Try to infere if the file is a CGATS/IT8 file at all. Read first line
2467 // that should be something like some printable characters plus a \n
2468 // returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line?
2469 static
2470 int IsMyBlock(const cmsUInt8Number* Buffer, cmsUInt32Number n)
2471 {
2472     int words = 1, space = 0, quot = 0;
2473     cmsUInt32Number i;
2474 
2475     if (n < 10) return 0;   // Too small
2476 
2477     if (n > 132)
2478         n = 132;
2479 
2480     for (i = 1; i < n; i++) {
2481 
2482         switch(Buffer[i])
2483         {

2534 cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cmsUInt32Number len)
2535 {
2536     cmsHANDLE hIT8;
2537     cmsIT8*  it8;
2538     int type;
2539 
2540     _cmsAssert(Ptr != NULL);
2541     _cmsAssert(len != 0);
2542 
2543     type = IsMyBlock((const cmsUInt8Number*)Ptr, len);
2544     if (type == 0) return NULL;
2545 
2546     hIT8 = cmsIT8Alloc(ContextID);
2547     if (!hIT8) return NULL;
2548 
2549     it8 = (cmsIT8*) hIT8;
2550     it8 ->MemoryBlock = (char*) _cmsMalloc(ContextID, len + 1);
2551     if (it8->MemoryBlock == NULL)
2552     {
2553         cmsIT8Free(hIT8);
2554         return NULL;
2555     }
2556 
2557     strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
2558     it8 ->MemoryBlock[len] = 0;
2559 
2560     strncpy(it8->FileStack[0]->FileName, "", cmsMAX_PATH-1);
2561     it8-> Source = it8 -> MemoryBlock;
2562 
2563     if (!ParseIT8(it8, type-1)) {
2564 
2565         cmsIT8Free(hIT8);
2566         return NULL;
2567     }
2568 
2569     CookPointers(it8);
2570     it8 ->nTable = 0;
2571 
2572     _cmsFree(ContextID, it8->MemoryBlock);
2573     it8 -> MemoryBlock = NULL;
2574 
2575     return hIT8;
2576 
2577 
2578 }
2579 
2580 
2581 cmsHANDLE  CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileName)
2582 {
2583 
2584      cmsHANDLE hIT8;
2585      cmsIT8*  it8;
2586      int type;

2643 cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyNames)
2644 {
2645     cmsIT8* it8 = (cmsIT8*) hIT8;
2646     KEYVALUE* p;
2647     cmsUInt32Number n;
2648     char **Props;
2649     TABLE* t;
2650 
2651     _cmsAssert(hIT8 != NULL);
2652 
2653     t = GetTable(it8);
2654 
2655     // Pass#1 - count properties
2656 
2657     n = 0;
2658     for (p = t -> HeaderList;  p != NULL; p = p->Next) {
2659         n++;
2660     }
2661 
2662 
2663     Props = (char**)AllocChunk(it8, sizeof(char*) * n);
2664     if (Props != NULL) {






2665 
2666         // Pass#2 - Fill pointers
2667         n = 0;
2668         for (p = t->HeaderList; p != NULL; p = p->Next) {
2669             Props[n++] = p->Keyword;
2670         }
2671 
2672     }
2673     *PropertyNames = Props;
2674 
2675     return n;
2676 }
2677 
2678 cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cProp, const char ***SubpropertyNames)
2679 {
2680     cmsIT8* it8 = (cmsIT8*) hIT8;
2681     KEYVALUE *p, *tmp;
2682     cmsUInt32Number n;
2683     const char **Props;
2684     TABLE* t;
2685 
2686     _cmsAssert(hIT8 != NULL);
2687 
2688 
2689     t = GetTable(it8);
2690 
2691     if(!IsAvailableOnList(t->HeaderList, cProp, NULL, &p)) {
2692         *SubpropertyNames = 0;
2693         return 0;

3013 
3014     it8->Tab[it8->nTable].SampleID = pos;
3015     return TRUE;
3016 }
3017 
3018 
3019 void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
3020 {
3021     cmsIT8* it8 = (cmsIT8*) hIT8;
3022 
3023     _cmsAssert(hIT8 != NULL);
3024 
3025     if (Formatter == NULL)
3026         strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT);
3027     else
3028         strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter));
3029 
3030     it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
3031 }
3032 
3033 
3034 static
3035 cmsBool ReadNumbers(cmsIT8* cube, int n, cmsFloat64Number* arr)
3036 {
3037     int i;
3038 
3039     for (i = 0; i < n; i++) {
3040 
3041         if (cube->sy == SINUM)
3042             arr[i] = cube->inum;
3043         else
3044             if (cube->sy == SDNUM)
3045                 arr[i] = cube->dnum;
3046             else
3047                 return SynError(cube, "Number expected");
3048 
3049         InSymbol(cube);
3050     }
3051 
3052     return CheckEOLN(cube);
3053 }
3054 
3055 static
3056 cmsBool ParseCube(cmsIT8* cube, cmsStage** Shaper, cmsStage** CLUT, char title[])
3057 {
3058     cmsFloat64Number domain_min[3] = { 0, 0, 0 };
3059     cmsFloat64Number domain_max[3] = { 1.0, 1.0, 1.0 };
3060     cmsFloat64Number check_0_1[2] = { 0, 1.0 };
3061     int shaper_size = 0;
3062     int lut_size = 0;
3063     int i;
3064 
3065     InSymbol(cube);
3066 
3067     while (cube->sy != SEOF) {
3068         switch (cube->sy)
3069         {
3070         // Set profile description
3071         case STITLE:
3072             InSymbol(cube);
3073             if (!Check(cube, SSTRING, "Title string expected")) return FALSE;
3074             memcpy(title, StringPtr(cube->str), MAXSTR);
3075             title[MAXSTR - 1] = 0;
3076             InSymbol(cube);
3077             break;
3078 
3079         // Define domain
3080         case SDOMAIN_MIN:
3081             InSymbol(cube);
3082             if (!ReadNumbers(cube, 3, domain_min)) return FALSE;
3083             break;
3084 
3085         case SDOMAIN_MAX:
3086             InSymbol(cube);
3087             if (!ReadNumbers(cube, 3, domain_max)) return FALSE;
3088             break;
3089 
3090         // Define shaper
3091         case S_LUT1D_SIZE:
3092             InSymbol(cube);
3093             if (!Check(cube, SINUM, "Shaper size expected")) return FALSE;
3094             shaper_size = cube->inum;
3095             InSymbol(cube);
3096             break;
3097 
3098         // Deefine CLUT
3099         case S_LUT3D_SIZE:
3100             InSymbol(cube);
3101             if (!Check(cube, SINUM, "LUT size expected")) return FALSE;
3102             lut_size = cube->inum;
3103             InSymbol(cube);
3104             break;
3105 
3106         // Range. If present, has to be 0..1.0
3107         case S_LUT1D_INPUT_RANGE:
3108         case S_LUT3D_INPUT_RANGE:
3109             InSymbol(cube);
3110             if (!ReadNumbers(cube, 2, check_0_1)) return FALSE;
3111             if (check_0_1[0] != 0 || check_0_1[1] != 1.0) {
3112                 return SynError(cube, "Unsupported format");
3113             }
3114             break;
3115 
3116         case SEOLN:
3117             InSymbol(cube);
3118             break;
3119 
3120         default:
3121         case S_LUT_IN_VIDEO_RANGE:
3122         case S_LUT_OUT_VIDEO_RANGE:
3123             return SynError(cube, "Unsupported format");
3124 
3125             // Read and create tables
3126         case SINUM:
3127         case SDNUM:
3128 
3129             if (shaper_size > 0) {
3130 
3131                 cmsToneCurve* curves[3];
3132                 cmsFloat32Number* shapers = (cmsFloat32Number*)_cmsMalloc(cube->ContextID, 3 * shaper_size * sizeof(cmsFloat32Number));
3133                 if (shapers == NULL) return FALSE;
3134 
3135                 for (i = 0; i < shaper_size; i++) {
3136 
3137                     cmsFloat64Number nums[3];
3138 
3139                     if (!ReadNumbers(cube, 3, nums)) return FALSE;
3140 
3141                     shapers[i + 0]               = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0]));
3142                     shapers[i + 1 * shaper_size] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1]));
3143                     shapers[i + 2 * shaper_size] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2]));
3144                 }
3145 
3146                 for (i = 0; i < 3; i++) {
3147 
3148                     curves[i] = cmsBuildTabulatedToneCurveFloat(cube->ContextID, shaper_size,
3149                         &shapers[i * shaper_size]);
3150                     if (curves[i] == NULL) return FALSE;
3151                 }
3152 
3153                 *Shaper = cmsStageAllocToneCurves(cube->ContextID, 3, curves);
3154 
3155                 cmsFreeToneCurveTriple(curves);
3156             }
3157 
3158             if (lut_size > 0) {
3159 
3160                 int nodes = lut_size * lut_size * lut_size;
3161 
3162                 cmsFloat32Number* lut_table = _cmsMalloc(cube->ContextID, nodes * 3 * sizeof(cmsFloat32Number));
3163                 if (lut_table == NULL) return FALSE;
3164 
3165                 for (i = 0; i < nodes; i++) {
3166 
3167                     cmsFloat64Number nums[3];
3168 
3169                     if (!ReadNumbers(cube, 3, nums)) return FALSE;
3170 
3171                     lut_table[i * 3 + 2] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0]));
3172                     lut_table[i * 3 + 1] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1]));
3173                     lut_table[i * 3 + 0] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2]));
3174                 }
3175 
3176                 *CLUT = cmsStageAllocCLutFloat(cube->ContextID, lut_size, 3, 3, lut_table);
3177                 _cmsFree(cube->ContextID, lut_table);
3178             }
3179 
3180             if (!Check(cube, SEOF, "Extra symbols found in file")) return FALSE;
3181         }
3182     }
3183 
3184     return TRUE;
3185 }
3186 
3187 // Share the parser to read .cube format and create RGB devicelink profiles
3188 cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName)
3189 {
3190     cmsHPROFILE hProfile = NULL;
3191     cmsIT8* cube = NULL;
3192     cmsPipeline* Pipeline = NULL;
3193     cmsStage* CLUT = NULL;
3194     cmsStage* Shaper = NULL;
3195     cmsMLU* DescriptionMLU = NULL;
3196     char title[MAXSTR];
3197 
3198     _cmsAssert(cFileName != NULL);
3199 
3200     cube = (cmsIT8*) cmsIT8Alloc(ContextID);
3201     if (!cube) return NULL;
3202 
3203     cube->IsCUBE = TRUE;
3204     cube->FileStack[0]->Stream = fopen(cFileName, "rt");
3205 
3206     if (!cube->FileStack[0]->Stream) goto Done;
3207 
3208     strncpy(cube->FileStack[0]->FileName, cFileName, cmsMAX_PATH - 1);
3209     cube->FileStack[0]->FileName[cmsMAX_PATH - 1] = 0;
3210 
3211     if (!ParseCube(cube, &Shaper, &CLUT, title)) goto Done;
3212 
3213     // Success on parsing, let's create the profile
3214     hProfile = cmsCreateProfilePlaceholder(ContextID);
3215     if (!hProfile) goto Done;
3216 
3217     cmsSetProfileVersion(hProfile, 4.4);
3218 
3219     cmsSetDeviceClass(hProfile, cmsSigLinkClass);
3220     cmsSetColorSpace(hProfile,  cmsSigRgbData);
3221     cmsSetPCS(hProfile,         cmsSigRgbData);
3222 
3223     cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL);
3224 
3225     // Creates a Pipeline to hold CLUT and shaper
3226     Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
3227     if (Pipeline == NULL) goto Done;
3228 
3229     // Populates the pipeline
3230     if (Shaper != NULL) {
3231         if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Shaper))
3232             goto Done;
3233     }
3234 
3235     if (CLUT != NULL) {
3236         if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT))
3237             goto Done;
3238     }
3239 
3240     // Propagate the description. We put no copyright because we know
3241     // nothing on the copyrighted state of the .cube
3242     DescriptionMLU = cmsMLUalloc(ContextID, 1);
3243     if (!cmsMLUsetUTF8(DescriptionMLU, cmsNoLanguage, cmsNoCountry, title)) goto Done;
3244 
3245     // Flush the tags
3246     if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Done;
3247     if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, (void*)Pipeline)) goto Done;
3248 
3249 Done:
3250 
3251     if (DescriptionMLU != NULL)
3252         cmsMLUfree(DescriptionMLU);
3253 
3254     if (Pipeline != NULL)
3255         cmsPipelineFree(Pipeline);
3256 
3257     cmsIT8Free((cmsHANDLE) cube);
3258 
3259     return hProfile;
3260 }
3261 
3262 cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName)
3263 {
3264     return cmsCreateDeviceLinkFromCubeFileTHR(NULL, cFileName);
3265 }
< prev index next >