1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 //--------------------------------------------------------------------------------- 31 // 32 // Little Color Management System 33 // Copyright (c) 1998-2012 Marti Maria Saguer 34 // 35 // Permission is hereby granted, free of charge, to any person obtaining 36 // a copy of this software and associated documentation files (the "Software"), 37 // to deal in the Software without restriction, including without limitation 38 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 39 // and/or sell copies of the Software, and to permit persons to whom the Software 40 // is furnished to do so, subject to the following conditions: 41 // 42 // The above copyright notice and this permission notice shall be included in 43 // all copies or substantial portions of the Software. 44 // 45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 52 // 53 //--------------------------------------------------------------------------------- 54 // 55 56 #include "lcms2_internal.h" 57 58 // Multilocalized unicode objects. That is an attempt to encapsulate i18n. 59 60 61 // Allocates an empty multi localizad unicode object 62 cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems) 63 { 64 cmsMLU* mlu; 65 66 // nItems should be positive if given 67 if (nItems <= 0) nItems = 2; 68 69 // Create the container 70 mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); 71 if (mlu == NULL) return NULL; 72 73 mlu ->ContextID = ContextID; 74 75 // Create entry array 76 mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); 77 if (mlu ->Entries == NULL) { 78 _cmsFree(ContextID, mlu); 79 return NULL; 80 } 81 82 // Ok, keep indexes up to date 83 mlu ->AllocatedEntries = nItems; 84 mlu ->UsedEntries = 0; 85 86 return mlu; 87 } 88 89 90 // Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. 91 static 92 cmsBool GrowMLUpool(cmsMLU* mlu) 93 { 94 cmsUInt32Number size; 95 void *NewPtr; 96 97 // Sanity check 98 if (mlu == NULL) return FALSE; 99 100 if (mlu ->PoolSize == 0) 101 size = 256; 102 else 103 size = mlu ->PoolSize * 2; 104 105 // Check for overflow 106 if (size < mlu ->PoolSize) return FALSE; 107 108 // Reallocate the pool 109 NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size); 110 if (NewPtr == NULL) return FALSE; 111 112 113 mlu ->MemPool = NewPtr; 114 mlu ->PoolSize = size; 115 116 return TRUE; 117 } 118 119 120 // Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two. 121 static 122 cmsBool GrowMLUtable(cmsMLU* mlu) 123 { 124 int AllocatedEntries; 125 _cmsMLUentry *NewPtr; 126 127 // Sanity check 128 if (mlu == NULL) return FALSE; 129 130 AllocatedEntries = mlu ->AllocatedEntries * 2; 131 132 // Check for overflow 133 if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; 134 135 // Reallocate the memory 136 NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); 137 if (NewPtr == NULL) return FALSE; 138 139 mlu ->Entries = NewPtr; 140 mlu ->AllocatedEntries = AllocatedEntries; 141 142 return TRUE; 143 } 144 145 146 // Search for a specific entry in the structure. Language and Country are used. 147 static 148 int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) 149 { 150 int i; 151 152 // Sanity check 153 if (mlu == NULL) return -1; 154 155 // Iterate whole table 156 for (i=0; i < mlu ->UsedEntries; i++) { 157 158 if (mlu ->Entries[i].Country == CountryCode && 159 mlu ->Entries[i].Language == LanguageCode) return i; 160 } 161 162 // Not found 163 return -1; 164 } 165 166 // Add a block of characters to the intended MLU. Language and country are specified. 167 // Only one entry for Language/country pair is allowed. 168 static 169 cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, 170 cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) 171 { 172 cmsUInt32Number Offset; 173 cmsUInt8Number* Ptr; 174 175 // Sanity check 176 if (mlu == NULL) return FALSE; 177 178 // Is there any room available? 179 if (mlu ->UsedEntries >= mlu ->AllocatedEntries) { 180 if (!GrowMLUtable(mlu)) return FALSE; 181 } 182 183 // Only one ASCII string 184 if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed! 185 186 // Check for size 187 while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { 188 189 if (!GrowMLUpool(mlu)) return FALSE; 190 } 191 192 Offset = mlu ->PoolUsed; 193 194 Ptr = (cmsUInt8Number*) mlu ->MemPool; 195 if (Ptr == NULL) return FALSE; 196 197 // Set the entry 198 memmove(Ptr + Offset, Block, size); 199 mlu ->PoolUsed += size; 200 201 mlu ->Entries[mlu ->UsedEntries].StrW = Offset; 202 mlu ->Entries[mlu ->UsedEntries].Len = size; 203 mlu ->Entries[mlu ->UsedEntries].Country = CountryCode; 204 mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode; 205 mlu ->UsedEntries++; 206 207 return TRUE; 208 } 209 210 211 // Add an ASCII entry. 212 cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) 213 { 214 cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1; 215 wchar_t* WStr; 216 cmsBool rc; 217 cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); 218 cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); 219 220 if (mlu == NULL) return FALSE; 221 222 WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); 223 if (WStr == NULL) return FALSE; 224 225 for (i=0; i < len; i++) 226 WStr[i] = (wchar_t) ASCIIString[i]; 227 228 rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); 229 230 _cmsFree(mlu ->ContextID, WStr); 231 return rc; 232 233 } 234 235 // We don't need any wcs support library 236 static 237 cmsUInt32Number mywcslen(const wchar_t *s) 238 { 239 const wchar_t *p; 240 241 p = s; 242 while (*p) 243 p++; 244 245 return (cmsUInt32Number)(p - s); 246 } 247 248 249 // Add a wide entry 250 cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString) 251 { 252 cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language); 253 cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country); 254 cmsUInt32Number len; 255 256 if (mlu == NULL) return FALSE; 257 if (WideString == NULL) return FALSE; 258 259 len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t); 260 return AddMLUBlock(mlu, len, WideString, Lang, Cntry); 261 } 262 263 // Duplicating a MLU is as easy as copying all members 264 cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu) 265 { 266 cmsMLU* NewMlu = NULL; 267 268 // Duplicating a NULL obtains a NULL 269 if (mlu == NULL) return NULL; 270 271 NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries); 272 if (NewMlu == NULL) return NULL; 273 274 // Should never happen 275 if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) 276 goto Error; 277 278 // Sanitize... 279 if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; 280 281 memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); 282 NewMlu ->UsedEntries = mlu ->UsedEntries; 283 284 // The MLU may be empty 285 if (mlu ->PoolUsed == 0) { 286 NewMlu ->MemPool = NULL; 287 } 288 else { 289 // It is not empty 290 NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed); 291 if (NewMlu ->MemPool == NULL) goto Error; 292 } 293 294 NewMlu ->PoolSize = mlu ->PoolUsed; 295 296 if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; 297 298 memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); 299 NewMlu ->PoolUsed = mlu ->PoolUsed; 300 301 return NewMlu; 302 303 Error: 304 305 if (NewMlu != NULL) cmsMLUfree(NewMlu); 306 return NULL; 307 } 308 309 // Free any used memory 310 void CMSEXPORT cmsMLUfree(cmsMLU* mlu) 311 { 312 if (mlu) { 313 314 if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries); 315 if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool); 316 317 _cmsFree(mlu ->ContextID, mlu); 318 } 319 } 320 321 322 // The algorithm first searches for an exact match of country and language, if not found it uses 323 // the Language. If none is found, first entry is used instead. 324 static 325 const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, 326 cmsUInt32Number *len, 327 cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, 328 cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) 329 { 330 int i; 331 int Best = -1; 332 _cmsMLUentry* v; 333 334 if (mlu == NULL) return NULL; 335 336 if (mlu -> AllocatedEntries <= 0) return NULL; 337 338 for (i=0; i < mlu ->UsedEntries; i++) { 339 340 v = mlu ->Entries + i; 341 342 if (v -> Language == LanguageCode) { 343 344 if (Best == -1) Best = i; 345 346 if (v -> Country == CountryCode) { 347 348 if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; 349 if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; 350 351 if (len != NULL) *len = v ->Len; 352 353 return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match 354 } 355 } 356 } 357 358 // No string found. Return First one 359 if (Best == -1) 360 Best = 0; 361 362 v = mlu ->Entries + Best; 363 364 if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; 365 if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; 366 367 if (len != NULL) *len = v ->Len; 368 369 return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); 370 } 371 372 373 // Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len 374 cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, 375 const char LanguageCode[3], const char CountryCode[3], 376 char* Buffer, cmsUInt32Number BufferSize) 377 { 378 const wchar_t *Wide; 379 cmsUInt32Number StrLen = 0; 380 cmsUInt32Number ASCIIlen, i; 381 382 cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); 383 cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); 384 385 // Sanitize 386 if (mlu == NULL) return 0; 387 388 // Get WideChar 389 Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); 390 if (Wide == NULL) return 0; 391 392 ASCIIlen = StrLen / sizeof(wchar_t); 393 394 // Maybe we want only to know the len? 395 if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end 396 397 // No buffer size means no data 398 if (BufferSize <= 0) return 0; 399 400 // Some clipping may be required 401 if (BufferSize < ASCIIlen + 1) 402 ASCIIlen = BufferSize - 1; 403 404 // Precess each character 405 for (i=0; i < ASCIIlen; i++) { 406 407 if (Wide[i] == 0) 408 Buffer[i] = 0; 409 else 410 Buffer[i] = (char) Wide[i]; 411 } 412 413 // We put a termination "\0" 414 Buffer[ASCIIlen] = 0; 415 return ASCIIlen + 1; 416 } 417 418 // Obtain a wide representation of the MLU, on depending on current locale settings 419 cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, 420 const char LanguageCode[3], const char CountryCode[3], 421 wchar_t* Buffer, cmsUInt32Number BufferSize) 422 { 423 const wchar_t *Wide; 424 cmsUInt32Number StrLen = 0; 425 426 cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); 427 cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); 428 429 // Sanitize 430 if (mlu == NULL) return 0; 431 432 Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); 433 if (Wide == NULL) return 0; 434 435 // Maybe we want only to know the len? 436 if (Buffer == NULL) return StrLen + sizeof(wchar_t); 437 438 // No buffer size means no data 439 if (BufferSize <= 0) return 0; 440 441 // Some clipping may be required 442 if (BufferSize < StrLen + sizeof(wchar_t)) 443 StrLen = BufferSize - + sizeof(wchar_t); 444 445 memmove(Buffer, Wide, StrLen); 446 Buffer[StrLen / sizeof(wchar_t)] = 0; 447 448 return StrLen + sizeof(wchar_t); 449 } 450 451 452 // Get also the language and country 453 CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, 454 const char LanguageCode[3], const char CountryCode[3], 455 char ObtainedLanguage[3], char ObtainedCountry[3]) 456 { 457 const wchar_t *Wide; 458 459 cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode); 460 cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode); 461 cmsUInt16Number ObtLang, ObtCode; 462 463 // Sanitize 464 if (mlu == NULL) return FALSE; 465 466 Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode); 467 if (Wide == NULL) return FALSE; 468 469 // Get used language and code 470 *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang); 471 *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode); 472 473 ObtainedLanguage[2] = ObtainedCountry[2] = 0; 474 return TRUE; 475 } 476 477 478 479 // Get the number of translations in the MLU object 480 cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu) 481 { 482 if (mlu == NULL) return 0; 483 return mlu->UsedEntries; 484 } 485 486 // Get the language and country codes for a specific MLU index 487 cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, 488 cmsUInt32Number idx, 489 char LanguageCode[3], 490 char CountryCode[3]) 491 { 492 _cmsMLUentry *entry; 493 494 if (mlu == NULL) return FALSE; 495 496 if (idx >= (cmsUInt32Number) mlu->UsedEntries) return FALSE; 497 498 entry = &mlu->Entries[idx]; 499 500 *(cmsUInt16Number *)LanguageCode = _cmsAdjustEndianess16(entry->Language); 501 *(cmsUInt16Number *)CountryCode = _cmsAdjustEndianess16(entry->Country); 502 503 return TRUE; 504 } 505 506 507 // Named color lists -------------------------------------------------------------------------------------------- 508 509 // Grow the list to keep at least NumElements 510 static 511 cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) 512 { 513 cmsUInt32Number size; 514 _cmsNAMEDCOLOR * NewPtr; 515 516 if (v == NULL) return FALSE; 517 518 if (v ->Allocated == 0) 519 size = 64; // Initial guess 520 else 521 size = v ->Allocated * 2; 522 523 // Keep a maximum color lists can grow, 100K entries seems reasonable 524 if (size > 1024*100) return FALSE; 525 526 NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); 527 if (NewPtr == NULL) 528 return FALSE; 529 530 v ->List = NewPtr; 531 v ->Allocated = size; 532 return TRUE; 533 } 534 535 // Allocate a list for n elements 536 cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix) 537 { 538 cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST)); 539 540 if (v == NULL) return NULL; 541 542 v ->List = NULL; 543 v ->nColors = 0; 544 v ->ContextID = ContextID; 545 546 while (v -> Allocated < n){ 547 if (!GrowNamedColorList(v)) return NULL; 548 } 549 550 strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); 551 strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); 552 v->Prefix[32] = v->Suffix[32] = 0; 553 554 v -> ColorantCount = ColorantCount; 555 556 return v; 557 } 558 559 // Free a list 560 void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) 561 { 562 if (v == NULL) return; 563 if (v ->List) _cmsFree(v ->ContextID, v ->List); 564 _cmsFree(v ->ContextID, v); 565 } 566 567 cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) 568 { 569 cmsNAMEDCOLORLIST* NewNC; 570 571 if (v == NULL) return NULL; 572 573 NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix); 574 if (NewNC == NULL) return NULL; 575 576 // For really large tables we need this 577 while (NewNC ->Allocated < v ->Allocated){ 578 if (!GrowNamedColorList(NewNC)) return NULL; 579 } 580 581 memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); 582 memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix)); 583 NewNC ->ColorantCount = v ->ColorantCount; 584 memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR)); 585 NewNC ->nColors = v ->nColors; 586 return NewNC; 587 } 588 589 590 // Append a color to a list. List pointer may change if reallocated 591 cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, 592 const char* Name, 593 cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS]) 594 { 595 cmsUInt32Number i; 596 597 if (NamedColorList == NULL) return FALSE; 598 599 if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) { 600 if (!GrowNamedColorList(NamedColorList)) return FALSE; 601 } 602 603 for (i=0; i < NamedColorList ->ColorantCount; i++) 604 NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i]; 605 606 for (i=0; i < 3; i++) 607 NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i]; 608 609 if (Name != NULL) { 610 611 strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1); 612 NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; 613 614 } 615 else 616 NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; 617 618 619 NamedColorList ->nColors++; 620 return TRUE; 621 } 622 623 // Returns number of elements 624 cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList) 625 { 626 if (NamedColorList == NULL) return 0; 627 return NamedColorList ->nColors; 628 } 629 630 // Info aboout a given color 631 cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, 632 char* Name, 633 char* Prefix, 634 char* Suffix, 635 cmsUInt16Number* PCS, 636 cmsUInt16Number* Colorant) 637 { 638 if (NamedColorList == NULL) return FALSE; 639 640 if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE; 641 642 if (Name) strcpy(Name, NamedColorList->List[nColor].Name); 643 if (Prefix) strcpy(Prefix, NamedColorList->Prefix); 644 if (Suffix) strcpy(Suffix, NamedColorList->Suffix); 645 if (PCS) 646 memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); 647 648 if (Colorant) 649 memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, 650 sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); 651 652 653 return TRUE; 654 } 655 656 // Search for a given color name (no prefix or suffix) 657 cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name) 658 { 659 int i, n; 660 661 if (NamedColorList == NULL) return -1; 662 n = cmsNamedColorCount(NamedColorList); 663 for (i=0; i < n; i++) { 664 if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0) 665 return i; 666 } 667 668 return -1; 669 } 670 671 // MPE support ----------------------------------------------------------------------------------------------------------------- 672 673 static 674 void FreeNamedColorList(cmsStage* mpe) 675 { 676 cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; 677 cmsFreeNamedColorList(List); 678 } 679 680 static 681 void* DupNamedColorList(cmsStage* mpe) 682 { 683 cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; 684 return cmsDupNamedColorList(List); 685 } 686 687 static 688 void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 689 { 690 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; 691 cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); 692 693 if (index >= NamedColorList-> nColors) { 694 cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); 695 } 696 else { 697 698 // Named color always uses Lab 699 Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0); 700 Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0); 701 Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0); 702 } 703 } 704 705 static 706 void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) 707 { 708 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; 709 cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); 710 cmsUInt32Number j; 711 712 if (index >= NamedColorList-> nColors) { 713 cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); 714 } 715 else { 716 for (j=0; j < NamedColorList ->ColorantCount; j++) 717 Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); 718 } 719 } 720 721 722 // Named color lookup element 723 cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS) 724 { 725 return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, 726 cmsSigNamedColorElemType, 727 1, UsePCS ? 3 : NamedColorList ->ColorantCount, 728 UsePCS ? EvalNamedColorPCS : EvalNamedColor, 729 DupNamedColorList, 730 FreeNamedColorList, 731 cmsDupNamedColorList(NamedColorList)); 732 733 } 734 735 736 // Retrieve the named color list from a transform. Should be first element in the LUT 737 cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) 738 { 739 _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; 740 cmsStage* mpe = v ->Lut->Elements; 741 742 if (mpe ->Type != cmsSigNamedColorElemType) return NULL; 743 return (cmsNAMEDCOLORLIST*) mpe ->Data; 744 } 745 746 747 // Profile sequence description routines ------------------------------------------------------------------------------------- 748 749 cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n) 750 { 751 cmsSEQ* Seq; 752 cmsUInt32Number i; 753 754 if (n == 0) return NULL; 755 756 // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked 757 // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door! 758 if (n > 255) return NULL; 759 760 Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ)); 761 if (Seq == NULL) return NULL; 762 763 Seq -> ContextID = ContextID; 764 Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC)); 765 Seq -> n = n; 766 767 if (Seq -> seq == NULL) { 768 _cmsFree(ContextID, Seq); 769 return NULL; 770 } 771 772 for (i=0; i < n; i++) { 773 Seq -> seq[i].Manufacturer = NULL; 774 Seq -> seq[i].Model = NULL; 775 Seq -> seq[i].Description = NULL; 776 } 777 778 return Seq; 779 } 780 781 void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) 782 { 783 cmsUInt32Number i; 784 785 for (i=0; i < pseq ->n; i++) { 786 if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); 787 if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); 788 if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); 789 } 790 791 if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); 792 _cmsFree(pseq -> ContextID, pseq); 793 } 794 795 cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq) 796 { 797 cmsSEQ *NewSeq; 798 cmsUInt32Number i; 799 800 if (pseq == NULL) 801 return NULL; 802 803 NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ)); 804 if (NewSeq == NULL) return NULL; 805 806 807 NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC)); 808 if (NewSeq ->seq == NULL) goto Error; 809 810 NewSeq -> ContextID = pseq ->ContextID; 811 NewSeq -> n = pseq ->n; 812 813 for (i=0; i < pseq->n; i++) { 814 815 memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number)); 816 817 NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg; 818 NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel; 819 memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID)); 820 NewSeq ->seq[i].technology = pseq ->seq[i].technology; 821 822 NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer); 823 NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model); 824 NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description); 825 826 } 827 828 return NewSeq; 829 830 Error: 831 832 cmsFreeProfileSequenceDescription(NewSeq); 833 return NULL; 834 } 835 836 // Dictionaries -------------------------------------------------------------------------------------------------------- 837 838 // Dictionaries are just very simple linked lists 839 840 841 typedef struct _cmsDICT_struct { 842 cmsDICTentry* head; 843 cmsContext ContextID; 844 } _cmsDICT; 845 846 847 // Allocate an empty dictionary 848 cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID) 849 { 850 _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT)); 851 if (dict == NULL) return NULL; 852 853 dict ->ContextID = ContextID; 854 return (cmsHANDLE) dict; 855 856 } 857 858 // Dispose resources 859 void CMSEXPORT cmsDictFree(cmsHANDLE hDict) 860 { 861 _cmsDICT* dict = (_cmsDICT*) hDict; 862 cmsDICTentry *entry, *next; 863 864 _cmsAssert(dict != NULL); 865 866 // Walk the list freeing all nodes 867 entry = dict ->head; 868 while (entry != NULL) { 869 870 if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName); 871 if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue); 872 if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name); 873 if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value); 874 875 // Don't fall in the habitual trap... 876 next = entry ->Next; 877 _cmsFree(dict ->ContextID, entry); 878 879 entry = next; 880 } 881 882 _cmsFree(dict ->ContextID, dict); 883 } 884 885 886 // Duplicate a wide char string 887 static 888 wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr) 889 { 890 if (ptr == NULL) return NULL; 891 return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t)); 892 } 893 894 // Add a new entry to the linked list 895 cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue) 896 { 897 _cmsDICT* dict = (_cmsDICT*) hDict; 898 cmsDICTentry *entry; 899 900 _cmsAssert(dict != NULL); 901 _cmsAssert(Name != NULL); 902 903 entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry)); 904 if (entry == NULL) return FALSE; 905 906 entry ->DisplayName = cmsMLUdup(DisplayName); 907 entry ->DisplayValue = cmsMLUdup(DisplayValue); 908 entry ->Name = DupWcs(dict ->ContextID, Name); 909 entry ->Value = DupWcs(dict ->ContextID, Value); 910 911 entry ->Next = dict ->head; 912 dict ->head = entry; 913 914 return TRUE; 915 } 916 917 918 // Duplicates an existing dictionary 919 cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict) 920 { 921 _cmsDICT* old_dict = (_cmsDICT*) hDict; 922 cmsHANDLE hNew; 923 cmsDICTentry *entry; 924 925 _cmsAssert(old_dict != NULL); 926 927 hNew = cmsDictAlloc(old_dict ->ContextID); 928 if (hNew == NULL) return NULL; 929 930 // Walk the list freeing all nodes 931 entry = old_dict ->head; 932 while (entry != NULL) { 933 934 if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) { 935 936 cmsDictFree(hNew); 937 return NULL; 938 } 939 940 entry = entry -> Next; 941 } 942 943 return hNew; 944 } 945 946 // Get a pointer to the linked list 947 const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict) 948 { 949 _cmsDICT* dict = (_cmsDICT*) hDict; 950 951 if (dict == NULL) return NULL; 952 return dict ->head; 953 } 954 955 // Helper For external languages 956 const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e) 957 { 958 if (e == NULL) return NULL; 959 return e ->Next; 960 }