1 2/* 3 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 4 * All Rights Reserved 5 * 6 * This file is a component of an X Window System-specific implementation 7 * of Xcms based on the TekColor Color Management System. Permission is 8 * hereby granted to use, copy, modify, sell, and otherwise distribute this 9 * software and its documentation for any purpose and without fee, provided 10 * that this copyright, permission, and disclaimer notice is reproduced in 11 * all copies of this software and in supporting documentation. TekColor 12 * is a trademark of Tektronix, Inc. 13 * 14 * Tektronix makes no representation about the suitability of this software 15 * for any purpose. It is provided "as is" and with all faults. 16 * 17 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 18 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 21 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 22 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 23 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 24 * 25 * NAME 26 * XcmsColNm.c 27 * 28 * DESCRIPTION 29 * Source for _XcmsLookupColorName(). 30 * 31 * 32 */ 33 34#ifdef HAVE_CONFIG_H 35#include <config.h> 36#endif 37#include "Xlibint.h" 38#include "Xcmsint.h" 39#include <X11/Xos.h> 40#include <sys/stat.h> 41#include <stdio.h> 42#include <ctype.h> 43#include <limits.h> 44#define XK_LATIN1 45#include <X11/keysymdef.h> 46#include "Cv.h" 47 48/* forwards/locals */ 49static Status LoadColornameDB(void); 50 51 52/* 53 * LOCAL DEFINES 54 * #define declarations local to this package. 55 */ 56#ifndef XCMSDB 57#define XCMSDB XCMSDIR "/Xcms.txt" 58#endif 59 60#ifndef isgraph 61# define isgraph(c) (isprint((c)) && !isspace((c))) 62#endif 63 64#ifndef XCMSDB_MAXLINELEN 65# define XCMSDB_MAXLINELEN 256 66#endif 67 68#define FORMAT_VERSION "0.1" 69#define START_TOKEN "XCMS_COLORDB_START" 70#define END_TOKEN "XCMS_COLORDB_END" 71#define DELIM_CHAR '\t' 72 73#define NOT_VISITED 0x0 74#define VISITED 0x1 75#define CYCLE 0xFFFF 76#define XcmsDbInitNone -1 77#define XcmsDbInitFailure 0 78#define XcmsDbInitSuccess 1 79 80/* 81 * LOCAL TYPEDEFS 82 */ 83typedef struct _XcmsPair { 84 const char *first; 85 const char *second; 86 int flag; 87} XcmsPair; 88 89/* 90 * LOCAL VARIABLES 91 */ 92static int XcmsColorDbState = XcmsDbInitNone; 93static int nEntries; 94static char *strings; 95static XcmsPair *pairs; 96static const char whitePtStr[] = "WhitePoint"; 97 98 99/************************************************************************ 100 * * 101 * PRIVATE ROUTINES * 102 * * 103 ************************************************************************/ 104 105/* 106 * NAME 107 * _XcmsColorSpaceOfString 108 * 109 * SYNOPSIS 110 */ 111static XcmsColorSpace * 112_XcmsColorSpaceOfString( 113 XcmsCCC ccc, 114 const char *color_string) 115/* 116 * DESCRIPTION 117 * Returns a pointer to the color space structure 118 * (XcmsColorSpace) associated with the specified color string. 119 * 120 * RETURNS 121 * Pointer to matching XcmsColorSpace structure if found; 122 * otherwise NULL. 123 * 124 * CAVEATS 125 * 126 */ 127{ 128 XcmsColorSpace **papColorSpaces; 129 size_t n; 130 char *pchar; 131 132 if ((pchar = strchr(color_string, ':')) == NULL) { 133 return(XcmsFailure); 134 } 135 n = (size_t)(pchar - color_string); 136 137 if (ccc == NULL) { 138 return(NULL); 139 } 140 141 /* 142 * First try Device-Independent color spaces 143 */ 144 papColorSpaces = _XcmsDIColorSpaces; 145 if (papColorSpaces != NULL) { 146 while (*papColorSpaces != NULL) { 147 if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 && 148 !((*papColorSpaces)->prefix)[n]) { 149 return(*papColorSpaces); 150 } 151 papColorSpaces++; 152 } 153 } 154 155 /* 156 * Next try Device-Dependent color spaces 157 */ 158 papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces; 159 if (papColorSpaces != NULL) { 160 while (*papColorSpaces != NULL) { 161 if (strncmp((*papColorSpaces)->prefix, color_string, n) == 0 && 162 !((*papColorSpaces)->prefix)[n]) { 163 return(*papColorSpaces); 164 } 165 papColorSpaces++; 166 } 167 } 168 169 return(NULL); 170} 171 172 173/* 174 * NAME 175 * _XcmsParseColorString 176 * 177 * SYNOPSIS 178 */ 179static int 180_XcmsParseColorString( 181 XcmsCCC ccc, 182 const char *color_string, 183 XcmsColor *pColor) 184/* 185 * DESCRIPTION 186 * Assuming color_string contains a numerical string color 187 * specification, attempts to parse a string into an 188 * XcmsColor structure. 189 * 190 * RETURNS 191 * 0 if failed; otherwise non-zero. 192 * 193 * CAVEATS 194 * A color string containing a numerical color specification 195 * must be in ISO Latin-1 encoding! 196 */ 197{ 198 XcmsColorSpace *pColorSpace; 199 char string_buf[64]; 200 char *string_lowered; 201 size_t len; 202 int res; 203 204 if (ccc == NULL) { 205 return(0); 206 } 207 208 /* 209 * While copying color_string to string_lowered, convert to lowercase 210 */ 211 if ((len = strlen(color_string)) >= sizeof(string_buf)) { 212 string_lowered = Xmalloc(len+1); 213 if (string_lowered == NULL) 214 return(XcmsFailure); 215 } else { 216 string_lowered = string_buf; 217 } 218 219 _XcmsCopyISOLatin1Lowered(string_lowered, color_string); 220 221 if (*string_lowered == '#') { 222 if ((pColorSpace = _XcmsColorSpaceOfString(ccc, "rgb:")) != NULL) { 223 res = (*pColorSpace->parseString)(string_lowered, pColor); 224 if (len >= sizeof(string_buf)) Xfree(string_lowered); 225 return res; 226 } 227 } 228 229 if ((pColorSpace = _XcmsColorSpaceOfString(ccc, string_lowered)) != NULL) { 230 res = (*pColorSpace->parseString)(string_lowered, pColor); 231 if (len >= sizeof(string_buf)) Xfree(string_lowered); 232 return res; 233 } 234 235 if (len >= sizeof(string_buf)) Xfree(string_lowered); 236 return(0); 237} 238 239 240/* 241 * NAME 242 * FirstCmp - Compare color names of pair recs 243 * 244 * SYNOPSIS 245 */ 246static int 247FirstCmp(const void *p1, const void *p2) 248/* 249 * DESCRIPTION 250 * Compares the color names of XcmsColorTuples. 251 * 252 * RETURNS 253 * 0 if equal; 254 * < 0 if first precedes second, 255 * > 0 if first succeeds second. 256 * 257 */ 258{ 259 return(strcmp(((const XcmsPair *)p1)->first, ((const XcmsPair *)p2)->first)); 260} 261 262 263 264/* 265 * NAME 266 * stringSectionSize - determine memory needed for strings 267 * 268 * SYNOPSIS 269 */ 270static void 271SetNoVisit(void) 272/* 273 * DESCRIPTION 274 * 275 * RETURNS 276 * void 277 * 278 */ 279{ 280 int i; 281 XcmsPair *pair = pairs; 282 283 for (i = 0; i < nEntries; i++, pair++) { 284 if (pair->flag != CYCLE) { 285 pair->flag = NOT_VISITED; 286 } 287 } 288} 289 290 291 292 293/* 294 * NAME 295 * field2 - extract two fields 296 * 297 * SYNOPSIS 298 */ 299static int 300field2( 301 char *pBuf, 302 char delim, /* in: field delimiter */ 303 char **p1, /* in/out: pointer to pointer to field 1 */ 304 char **p2) /* in/out: pointer to pointer to field 2 */ 305/* 306 * DESCRIPTION 307 * Extracts two fields from a "record". 308 * 309 * RETURNS 310 * XcmsSuccess if succeeded, otherwise XcmsFailure. 311 * 312 */ 313{ 314 *p1 = *p2 = NULL; 315 316 /* Find Field 1 */ 317 while (!isgraph(*pBuf)) { 318 if ((*pBuf == '\n') || (*pBuf == '\0')) { 319 return(XcmsFailure); 320 } 321 if (isspace(*pBuf) || (*pBuf == delim)) { 322 pBuf++; 323 } 324 } 325 *p1 = pBuf; 326 327 /* Find end of Field 2 */ 328 while (isprint(*pBuf) && (*pBuf != delim)) { 329 pBuf++; 330 } 331 if ((*pBuf == '\n') || (*pBuf == '\0')) { 332 return(XcmsFailure); 333 } 334 if ((*pBuf == ' ') || (*pBuf == delim)) { 335 *pBuf++ = '\0'; /* stuff end of string character */ 336 } else { 337 return(XcmsFailure); 338 } 339 340 /* Find Field 2 */ 341 while (!isgraph(*pBuf)) { 342 if ((*pBuf == '\n') || (*pBuf == '\0')) { 343 return(XcmsFailure); 344 } 345 if (isspace(*pBuf) || (*pBuf == delim)) { 346 pBuf++; 347 } 348 } 349 *p2 = pBuf; 350 351 /* Find end of Field 2 */ 352 while (isprint(*pBuf) && (*pBuf != delim)) { 353 pBuf++; 354 } 355 if (*pBuf != '\0') { 356 *pBuf = '\0'; /* stuff end of string character */ 357 } 358 359 return(XcmsSuccess); 360} 361 362 363/* 364 * NAME 365 * _XcmsLookupColorName - Lookup DB entry for a color name 366 * 367 * SYNOPSIS 368 */ 369static Status 370_XcmsLookupColorName( 371 XcmsCCC ccc, 372 const char **name, 373 XcmsColor *pColor) 374/* 375 * DESCRIPTION 376 * Searches for an entry in the Device-Independent Color Name 377 * Database for the specified string. 378 * 379 * RETURNS 380 * XcmsFailure if failed to find a matching entry in 381 * the database. 382 * XcmsSuccess if succeeded in converting color name to 383 * XcmsColor. 384 * _XCMS_NEWNAME if succeeded in converting color string (which 385 * is a color name to yet another color name. Note 386 * that the new name is passed back via 'name'. 387 */ 388 { 389 Status retval = 0; 390 char name_lowered_64[64]; 391 char *name_lowered; 392 register int i, j, left, right; 393 int len; 394 const char *tmpName; 395 XcmsPair *pair = NULL; 396 397 /* 398 * Check state of Database: 399 * XcmsDbInitNone 400 * XcmsDbInitSuccess 401 * XcmsDbInitFailure 402 */ 403 if (XcmsColorDbState == XcmsDbInitFailure) { 404 return(XcmsFailure); 405 } 406 if (XcmsColorDbState == XcmsDbInitNone) { 407 if (!LoadColornameDB()) { 408 return(XcmsFailure); 409 } 410 } 411 412 SetNoVisit(); 413 414 /* 415 * While copying name to name_lowered, convert to lowercase 416 */ 417 418 tmpName = *name; 419 420Retry: 421 if ((len = (int)strlen(tmpName)) > 63) { 422 name_lowered = Xmalloc(len+1); 423 if (name_lowered == NULL) 424 return(XcmsFailure); 425 } else { 426 name_lowered = name_lowered_64; 427 } 428 429 _XcmsCopyISOLatin1Lowered(name_lowered, tmpName); 430 431 /* 432 * Now, remove spaces. 433 */ 434 for (i = 0, j = 0; j < len; j++) { 435 if (!isspace(name_lowered[j])) { 436 name_lowered[i++] = name_lowered[j]; 437 } 438 } 439 name_lowered[i] = '\0'; 440 441 left = 0; 442 right = nEntries - 1; 443 while (left <= right) { 444 i = (left + right) >> 1; 445 pair = &pairs[i]; 446 j = strcmp(name_lowered, pair->first); 447 if (j < 0) 448 right = i - 1; 449 else if (j > 0) 450 left = i + 1; 451 else { 452 break; 453 } 454 } 455 if (len > 63) Xfree(name_lowered); 456 457 if (left > right) { 458 if (retval == 2) { 459 if (*name != tmpName) { 460 *name = tmpName; 461 } 462 return(_XCMS_NEWNAME); 463 } 464 return(XcmsFailure); 465 } 466 467 if (pair->flag == CYCLE) { 468 return(XcmsFailure); 469 } 470 if (pair->flag == VISITED) { 471 pair->flag = CYCLE; 472 return(XcmsFailure); 473 } 474 475 if (_XcmsParseColorString(ccc, pair->second, pColor) == XcmsSuccess) { 476 /* f2 contains a numerical string specification */ 477 return(XcmsSuccess); 478 } else { 479 /* f2 does not contain a numerical string specification */ 480 tmpName = pair->second; 481 pair->flag = VISITED; 482 retval = 2; 483 goto Retry; 484 } 485} 486 487 488/* 489 * NAME 490 * RemoveSpaces 491 * 492 * SYNOPSIS 493 */ 494static int 495RemoveSpaces( 496 char *pString) 497/* 498 * DESCRIPTION 499 * Removes spaces from string. 500 * 501 * RETURNS 502 * Void 503 * 504 */ 505{ 506 int i, count = 0; 507 char *cptr; 508 509 /* REMOVE SPACES */ 510 cptr = pString; 511 for (i = (int)strlen(pString); i; i--, cptr++) { 512 if (!isspace(*cptr)) { 513 *pString++ = *cptr; 514 count++; 515 } 516 } 517 *pString = '\0'; 518 return(count); 519} 520 521 522/* 523 * NAME 524 * stringSectionSize - determine memory needed for strings 525 * 526 * SYNOPSIS 527 */ 528static int 529stringSectionSize( 530 FILE *stream, 531 int *pNumEntries, 532 int *pSectionSize) 533/* 534 * DESCRIPTION 535 * Determines the amount of memory required to store the 536 * color name strings and also the number of strings. 537 * 538 * RETURNS 539 * XcmsSuccess if succeeded, otherwise XcmsFailure. 540 * 541 */ 542{ 543 char buf[XCMSDB_MAXLINELEN]; 544 char token[XCMSDB_MAXLINELEN]; 545 char token2[XCMSDB_MAXLINELEN]; 546 char *pBuf; 547 char *f1; 548 char *f2; 549 size_t i; 550 551 unsigned int numEntries = 0; 552 unsigned int sectionSize = 0; 553 554 *pNumEntries = 0; 555 *pSectionSize = 0; 556 557 /* 558 * Advance to START_TOKEN 559 * Anything before is just considered as comments. 560 */ 561 562 while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) { 563 if ((sscanf(buf, "%s %s", token, token2)) 564 && (strcmp(token, START_TOKEN) == 0)) { 565 if (strcmp(token2, FORMAT_VERSION) != 0) { 566 /* text file not in the right format */ 567 return(XcmsFailure); 568 } 569 break; 570 } /* else it was just a blank line or comment */ 571 } 572 573 if (pBuf == NULL) { 574 return(XcmsFailure); 575 } 576 577 while((fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) { 578 if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) { 579 break; 580 } 581 582 if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) { 583 return(XcmsFailure); 584 } 585 586 numEntries++; 587 if (numEntries >= INT_MAX) 588 return(XcmsFailure); 589 590 i = strlen(f1); 591 if (i >= INT_MAX - sectionSize) 592 return(XcmsFailure); 593 sectionSize += i + 1; 594 for (; i; i--, f1++) { 595 /* REMOVE SPACES FROM COUNT */ 596 if (isspace(*f1)) { 597 sectionSize--; 598 } 599 } 600 601 i = strlen(f2); 602 if (i >= INT_MAX - sectionSize) 603 return(XcmsFailure); 604 sectionSize += i + 1; 605 for (; i; i--, f2++) { 606 /* REMOVE SPACES FROM COUNT */ 607 if (isspace(*f2)) { 608 sectionSize--; 609 } 610 } 611 612 } 613 614 *pNumEntries = (int) numEntries; 615 *pSectionSize = (int) sectionSize; 616 617 return(XcmsSuccess); 618} 619 620 621/* 622 * NAME 623 * ReadColornameDB - Read the Color Name Database 624 * 625 * SYNOPSIS 626 */ 627static Status 628ReadColornameDB( 629 FILE *stream, 630 XcmsPair *pRec, 631 char *pString) 632/* 633 * DESCRIPTION 634 * Loads the Color Name Database from a text file. 635 * 636 * RETURNS 637 * XcmsSuccess if succeeded, otherwise XcmsFailure. 638 * 639 */ 640{ 641 char buf[XCMSDB_MAXLINELEN]; 642 char token[XCMSDB_MAXLINELEN]; 643 char token2[XCMSDB_MAXLINELEN]; 644 char *f1; 645 char *f2; 646 char *pBuf; 647 648 /* 649 * Advance to START_TOKEN 650 * Anything before is just considered as comments. 651 */ 652 653 while((pBuf = fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) { 654 if ((sscanf(buf, "%s %s", token, token2)) 655 && (strcmp(token, START_TOKEN) == 0)) { 656 if (strcmp(token2, FORMAT_VERSION) != 0) { 657 /* text file not in the right format */ 658 return(XcmsFailure); 659 } 660 break; 661 } /* else it was just a blank line or comment */ 662 } 663 664 if (pBuf == NULL) { 665 return(XcmsFailure); 666 } 667 668 /* 669 * Process lines between START_TOKEN to END_TOKEN 670 */ 671 672 while ((fgets(buf, XCMSDB_MAXLINELEN, stream)) != NULL) { 673 if ((sscanf(buf, "%s", token)) && (strcmp(token, END_TOKEN) == 0)) { 674 /* 675 * Found END_TOKEN so break out of for loop 676 */ 677 break; 678 } 679 680 /* 681 * Get pairs 682 */ 683 if (field2(buf, DELIM_CHAR, &f1, &f2) != XcmsSuccess) { 684 /* Invalid line */ 685 continue; 686 } 687 688 /* 689 * Add strings 690 */ 691 692 /* Left String */ 693 pRec->first = pString; 694 _XcmsCopyISOLatin1Lowered(pString, f1); 695 pString += (1 + RemoveSpaces(pString)); 696 pRec->second = pString; 697 /* Right String */ 698 _XcmsCopyISOLatin1Lowered(pString, f2); 699 pString += RemoveSpaces(pString) + 1; 700 pRec++; 701 702 } 703 704 return(XcmsSuccess); 705} 706 707 708/* 709 * NAME 710 * LoadColornameDB - Load the Color Name Database 711 * 712 * SYNOPSIS 713 */ 714static Status 715LoadColornameDB(void) 716/* 717 * DESCRIPTION 718 * Loads the Color Name Database from a text file. 719 * 720 * RETURNS 721 * XcmsSuccess if succeeded, otherwise XcmsFailure. 722 * 723 */ 724{ 725 int size; 726 FILE *stream; 727 const char *pathname; 728 struct stat txt; 729 int length; 730 731 /* use and name of this env var is not part of the standard */ 732 /* implementation-dependent feature */ 733 if ((pathname = getenv("XCMSDB")) == NULL) { 734 pathname = XCMSDB; 735 } 736 737 length = (int)strlen(pathname); 738 if ((length == 0) || (length >= (BUFSIZ - 5))){ 739 XcmsColorDbState = XcmsDbInitFailure; 740 return(XcmsFailure); 741 } 742 743 if (stat(pathname, &txt)) { 744 /* can't stat file */ 745 XcmsColorDbState = XcmsDbInitFailure; 746 return(XcmsFailure); 747 } 748 749 if ((stream = _XFopenFile (pathname, "r")) == NULL) { 750 /* can't open file */ 751 XcmsColorDbState = XcmsDbInitFailure; 752 return(XcmsFailure); 753 } 754 755 if (stringSectionSize(stream, &nEntries, &size) != XcmsSuccess || 756 nEntries == 0) { 757 (void) fclose(stream); 758 XcmsColorDbState = XcmsDbInitFailure; 759 return(XcmsFailure); 760 } 761 rewind(stream); 762 763 strings = Xmalloc(size); 764 pairs = Xcalloc(nEntries, sizeof(XcmsPair)); 765 if (strings == NULL || pairs == NULL) { 766 free(strings); 767 free(pairs); 768 (void) fclose(stream); 769 XcmsColorDbState = XcmsDbInitFailure; 770 return(XcmsFailure); 771 } 772 773 ReadColornameDB(stream, pairs, strings); 774 (void) fclose(stream); 775 776 /* 777 * sort the pair recs 778 */ 779 qsort((char *)pairs, nEntries, sizeof(XcmsPair), FirstCmp); 780 781 XcmsColorDbState = XcmsDbInitSuccess; 782 return(XcmsSuccess); 783} 784 785 786/************************************************************************ 787 * * 788 * API PRIVATE ROUTINES * 789 * * 790 ************************************************************************/ 791 792/* 793 * NAME 794 * _XcmsCopyISOLatin1Lowered 795 * 796 * SYNOPSIS 797 */ 798void 799_XcmsCopyISOLatin1Lowered( 800 char *dst, 801 const char *src) 802/* 803 * DESCRIPTION 804 * ISO Latin-1 case conversion routine 805 * Identical to XmuCopyISOLatin1Lowered() but provided here 806 * to eliminate need to link with libXmu.a. 807 * 808 * IMPLEMENTORS NOTE: 809 * This routine is also used in XcmsFormatOfPrefix. 810 * 811 * RETURNS 812 * Void 813 * 814 */ 815{ 816 register unsigned char *dest; 817 register const unsigned char *source; 818 819 for (dest = (unsigned char *)dst, source = (const unsigned char *)src; 820 *source; 821 source++, dest++) 822 { 823 if ((*source >= XK_A) && (*source <= XK_Z)) 824 *dest = *source + (XK_a - XK_A); 825 else if ((*source >= XK_Agrave) && (*source <= XK_Odiaeresis)) 826 *dest = *source + (XK_agrave - XK_Agrave); 827 else if ((*source >= XK_Ooblique) && (*source <= XK_Thorn)) 828 *dest = *source + (XK_oslash - XK_Ooblique); 829 else 830 *dest = *source; 831 } 832 *dest = '\0'; 833} 834 835 836/* 837 * NAME 838 * _XcmsResolveColorString - 839 * 840 * SYNOPSIS 841 */ 842Status 843_XcmsResolveColorString ( 844 XcmsCCC ccc, 845 const char **color_string, 846 XcmsColor *pColor_exact_return, 847 XcmsColorFormat result_format) 848/* 849 * DESCRIPTION 850 * The XcmsLookupColor function finds the color specification 851 * associated with a color name in the Device-Independent Color 852 * Name Database. 853 * RETURNS 854 * XcmsFailure if failed to convert valid color string. 855 * XcmsSuccess if succeeded in converting color string to 856 * XcmsColor. 857 * _XCMS_NEWNAME if failed to parse the string or find it in 858 * the database, or if succeeded in looking it up and 859 * found another name which is not in the database. 860 * Note that the new name is returned in color_string. 861 * 862 * This function returns both the color specification found in the 863 * database (db specification) and the color specification for the 864 * color displayable by the specified screen (screen 865 * specification). The calling routine sets the format for these 866 * returned specifications in the XcmsColor format component. 867 * If XcmsUndefinedFormat, the specification is returned in the 868 * format used to store the color in the database. 869 */ 870{ 871 XcmsColor dbWhitePt; /* whitePt associated with pColor_exact_return*/ 872 /* the screen's white point */ 873 XcmsColor *pClientWhitePt; 874 int retval; 875 const char *strptr = whitePtStr; 876 877/* 878 * 0. Check for invalid arguments. 879 */ 880 if (ccc == NULL || (*color_string)[0] == '\0' || pColor_exact_return == NULL) { 881 return(XcmsFailure); 882 } 883 884/* 885 * 1. First attempt to parse the string 886 * If successful, then convert the specification to the target format 887 * and return. 888 */ 889 if (_XcmsParseColorString(ccc, *color_string, pColor_exact_return) 890 == 1) { 891 if (result_format != XcmsUndefinedFormat 892 && pColor_exact_return->format != result_format) { 893 /* need to be converted to the target format */ 894 return(XcmsConvertColors(ccc, pColor_exact_return, 1, 895 result_format, (Bool *)NULL)); 896 } else { 897 return(XcmsSuccess); 898 } 899 } 900 901/* 902 * 2. Attempt to find it in the DI Color Name Database 903 */ 904 905 /* 906 * a. Convert String into a XcmsColor structure 907 * Attempt to extract the specification for color_string from the 908 * DI Database (pColor_exact_return). If the DI Database does not 909 * have this entry, then return failure. 910 */ 911 retval = _XcmsLookupColorName(ccc, color_string, pColor_exact_return); 912 913 if (retval != XcmsSuccess) { 914 /* color_string replaced with a color name, or not found */ 915 return(_XCMS_NEWNAME); 916 } 917 918 if (pColor_exact_return->format == XcmsUndefinedFormat) { 919 return(XcmsFailure); 920 } 921 922 /* 923 * b. If result_format not defined, then assume target format 924 * is the exact format. 925 */ 926 if (result_format == XcmsUndefinedFormat) { 927 result_format = pColor_exact_return->format; 928 } 929 930 if ((ClientWhitePointOfCCC(ccc))->format == XcmsUndefinedFormat) { 931 pClientWhitePt = ScreenWhitePointOfCCC(ccc); 932 } else { 933 pClientWhitePt = ClientWhitePointOfCCC(ccc); 934 } 935 936 /* 937 * c. Convert to the target format, making adjustments for white 938 * point differences as necessary. 939 */ 940 if (XCMS_DD_ID(pColor_exact_return->format)) { 941 /* 942 * The spec format is Device-Dependent, therefore assume the 943 * its white point is the Screen White Point. 944 */ 945 if (XCMS_DD_ID(result_format)) { 946 /* 947 * Target format is Device-Dependent 948 * Therefore, DD --> DD conversion 949 */ 950 return(_XcmsDDConvertColors(ccc, pColor_exact_return, 951 1, result_format, (Bool *) NULL)); 952 } else { 953 /* 954 * Target format is Device-Independent 955 * Therefore, DD --> DI conversion 956 */ 957 if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc, 958 pClientWhitePt, ScreenWhitePointOfCCC(ccc))) { 959 return((*ccc->whitePtAdjProc)(ccc, ScreenWhitePointOfCCC(ccc), 960 pClientWhitePt, result_format, 961 pColor_exact_return, 1, (Bool *) NULL)); 962 } else { 963 if (_XcmsDDConvertColors(ccc, pColor_exact_return, 1, 964 XcmsCIEXYZFormat, (Bool *) NULL) == XcmsFailure) { 965 return(XcmsFailure); 966 } 967 return(_XcmsDIConvertColors(ccc, pColor_exact_return, 968 pClientWhitePt, 1, result_format)); 969 } 970 } 971 } else { 972 /* 973 * The spec format is Device-Independent, therefore attempt 974 * to find a database white point. 975 * 976 * If the Database does not have a white point, then assume the 977 * database white point is the same as the Screen White Point. 978 */ 979 980 if (_XcmsLookupColorName(ccc, &strptr, &dbWhitePt) != 1) { 981 memcpy((char *)&dbWhitePt, 982 (char *)&ccc->pPerScrnInfo->screenWhitePt, 983 sizeof(XcmsColor)); 984 } 985 if (XCMS_DD_ID(result_format)) { 986 /* 987 * Target format is Device-Dependent 988 * Therefore, DI --> DD conversion 989 */ 990 if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc, 991 &dbWhitePt, ScreenWhitePointOfCCC(ccc))) { 992 return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt, 993 ScreenWhitePointOfCCC(ccc), result_format, 994 pColor_exact_return, 1, (Bool *)NULL)); 995 } else { 996 if (pColor_exact_return->format != XcmsCIEXYZFormat) { 997 if (_XcmsDIConvertColors(ccc, pColor_exact_return, 998 &dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) { 999 return(XcmsFailure); 1000 } 1001 } 1002 return (_XcmsDDConvertColors(ccc, pColor_exact_return, 1, 1003 result_format, (Bool *)NULL)); 1004 } 1005 } else { 1006 /* 1007 * Target format is Device-Independent 1008 * Therefore, DI --> DI conversion 1009 */ 1010 if (ccc->whitePtAdjProc && !_XcmsEqualWhitePts(ccc, 1011 &dbWhitePt, pClientWhitePt)) { 1012 /* 1013 * The calling routine wants to resolve this color 1014 * in terms if it's white point (i.e. Client White Point). 1015 * Therefore, apply white adjustment for the displacement 1016 * between dbWhitePt to clientWhitePt. 1017 */ 1018 return((*ccc->whitePtAdjProc)(ccc, &dbWhitePt, 1019 pClientWhitePt, result_format, 1020 pColor_exact_return, 1, (Bool *)NULL)); 1021 } else if (_XcmsEqualWhitePts(ccc, 1022 &dbWhitePt, pClientWhitePt)) { 1023 /* 1024 * Can use either dbWhitePt or pClientWhitePt to 1025 * convert to the result_format. 1026 */ 1027 if (pColor_exact_return->format == result_format) { 1028 return(XcmsSuccess); 1029 } else { 1030 return (_XcmsDIConvertColors(ccc, pColor_exact_return, 1031 &dbWhitePt, 1, result_format)); 1032 } 1033 } else { 1034 /* 1035 * Need to convert to a white point independent color 1036 * space (let's choose CIEXYZ) then convert to the 1037 * target color space. Why? Lets assume that 1038 * pColor_exact_return->format and result format 1039 * are white point dependent format (e.g., CIELUV, CIELAB, 1040 * TekHVC ... same or any combination). If so, we'll 1041 * need to convert the color with dbWhitePt to an absolute 1042 * spec (i.e. non-white point dependent) then convert that 1043 * absolute value with clientWhitePt to the result_format. 1044 */ 1045 if (pColor_exact_return->format != XcmsCIEXYZFormat) { 1046 if (_XcmsDIConvertColors(ccc, pColor_exact_return, 1047 &dbWhitePt, 1, XcmsCIEXYZFormat) == XcmsFailure) { 1048 return(XcmsFailure); 1049 } 1050 } 1051 if (result_format == XcmsCIEXYZFormat) { 1052 return(XcmsSuccess); 1053 } else { 1054 return(_XcmsDIConvertColors(ccc, pColor_exact_return, 1055 pClientWhitePt, 1, result_format)); 1056 } 1057 } 1058 } 1059 } 1060} 1061