Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/lcms2/src/cmsnamed.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 //--------------------------------------------------------------------------------- | |
| 2 // | |
| 3 // Little Color Management System | |
| 4 // Copyright (c) 1998-2023 Marti Maria Saguer | |
| 5 // | |
| 6 // Permission is hereby granted, free of charge, to any person obtaining | |
| 7 // a copy of this software and associated documentation files (the "Software"), | |
| 8 // to deal in the Software without restriction, including without limitation | |
| 9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 10 // and/or sell copies of the Software, and to permit persons to whom the Software | |
| 11 // is furnished to do so, subject to the following conditions: | |
| 12 // | |
| 13 // The above copyright notice and this permission notice shall be included in | |
| 14 // all copies or substantial portions of the Software. | |
| 15 // | |
| 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO | |
| 18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
| 20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
| 21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
| 22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| 23 // | |
| 24 //--------------------------------------------------------------------------------- | |
| 25 // | |
| 26 | |
| 27 #include "lcms2_internal.h" | |
| 28 | |
| 29 // Multilocalized unicode objects. That is an attempt to encapsulate i18n. | |
| 30 | |
| 31 | |
| 32 // Allocates an empty multi localizad unicode object | |
| 33 cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems) | |
| 34 { | |
| 35 cmsMLU* mlu; | |
| 36 | |
| 37 // nItems should be positive if given | |
| 38 if (nItems <= 0) nItems = 2; | |
| 39 | |
| 40 // Create the container | |
| 41 mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU)); | |
| 42 if (mlu == NULL) return NULL; | |
| 43 | |
| 44 // Create entry array | |
| 45 mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry)); | |
| 46 if (mlu ->Entries == NULL) { | |
| 47 _cmsFree(ContextID, mlu); | |
| 48 return NULL; | |
| 49 } | |
| 50 | |
| 51 // Ok, keep indexes up to date | |
| 52 mlu ->AllocatedEntries = nItems; | |
| 53 mlu ->UsedEntries = 0; | |
| 54 | |
| 55 return mlu; | |
| 56 } | |
| 57 | |
| 58 | |
| 59 // Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two. | |
| 60 static | |
| 61 cmsBool GrowMLUpool(cmsContext ContextID, cmsMLU* mlu) | |
| 62 { | |
| 63 cmsUInt32Number size; | |
| 64 void *NewPtr; | |
| 65 | |
| 66 // Sanity check | |
| 67 if (mlu == NULL) return FALSE; | |
| 68 | |
| 69 if (mlu ->PoolSize == 0) | |
| 70 size = 256; | |
| 71 else | |
| 72 size = mlu ->PoolSize * 2; | |
| 73 | |
| 74 // Check for overflow | |
| 75 if (size < mlu ->PoolSize) return FALSE; | |
| 76 | |
| 77 // Reallocate the pool | |
| 78 NewPtr = _cmsRealloc(ContextID, mlu ->MemPool, size); | |
| 79 if (NewPtr == NULL) return FALSE; | |
| 80 | |
| 81 | |
| 82 mlu ->MemPool = NewPtr; | |
| 83 mlu ->PoolSize = size; | |
| 84 | |
| 85 return TRUE; | |
| 86 } | |
| 87 | |
| 88 | |
| 89 // Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two. | |
| 90 static | |
| 91 cmsBool GrowMLUtable(cmsContext ContextID, cmsMLU* mlu) | |
| 92 { | |
| 93 cmsUInt32Number AllocatedEntries; | |
| 94 _cmsMLUentry *NewPtr; | |
| 95 | |
| 96 // Sanity check | |
| 97 if (mlu == NULL) return FALSE; | |
| 98 | |
| 99 AllocatedEntries = mlu ->AllocatedEntries * 2; | |
| 100 | |
| 101 // Check for overflow | |
| 102 if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; | |
| 103 | |
| 104 // Reallocate the memory | |
| 105 NewPtr = (_cmsMLUentry*)_cmsRealloc(ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); | |
| 106 if (NewPtr == NULL) return FALSE; | |
| 107 | |
| 108 mlu ->Entries = NewPtr; | |
| 109 mlu ->AllocatedEntries = AllocatedEntries; | |
| 110 | |
| 111 return TRUE; | |
| 112 } | |
| 113 | |
| 114 | |
| 115 // Search for a specific entry in the structure. Language and Country are used. | |
| 116 static | |
| 117 int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) | |
| 118 { | |
| 119 cmsUInt32Number i; | |
| 120 | |
| 121 // Sanity check | |
| 122 if (mlu == NULL) return -1; | |
| 123 | |
| 124 // Iterate whole table | |
| 125 for (i=0; i < mlu ->UsedEntries; i++) { | |
| 126 | |
| 127 if (mlu ->Entries[i].Country == CountryCode && | |
| 128 mlu ->Entries[i].Language == LanguageCode) return (int) i; | |
| 129 } | |
| 130 | |
| 131 // Not found | |
| 132 return -1; | |
| 133 } | |
| 134 | |
| 135 // Add a block of characters to the intended MLU. Language and country are specified. | |
| 136 // Only one entry for Language/country pair is allowed. | |
| 137 static | |
| 138 cmsBool AddMLUBlock(cmsContext ContextID, cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block, | |
| 139 cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode) | |
| 140 { | |
| 141 cmsUInt32Number Offset; | |
| 142 cmsUInt8Number* Ptr; | |
| 143 | |
| 144 // Sanity check | |
| 145 if (mlu == NULL) return FALSE; | |
| 146 | |
| 147 // Is there any room available? | |
| 148 if (mlu ->UsedEntries >= mlu ->AllocatedEntries) { | |
| 149 if (!GrowMLUtable(ContextID, mlu)) return FALSE; | |
| 150 } | |
| 151 | |
| 152 // Only one ASCII string | |
| 153 if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed! | |
| 154 | |
| 155 // Check for size | |
| 156 while ((mlu ->PoolSize - mlu ->PoolUsed) < size) { | |
| 157 | |
| 158 if (!GrowMLUpool(ContextID, mlu)) return FALSE; | |
| 159 } | |
| 160 | |
| 161 Offset = mlu ->PoolUsed; | |
| 162 | |
| 163 Ptr = (cmsUInt8Number*) mlu ->MemPool; | |
| 164 if (Ptr == NULL) return FALSE; | |
| 165 | |
| 166 // Set the entry | |
| 167 memmove(Ptr + Offset, Block, size); | |
| 168 mlu ->PoolUsed += size; | |
| 169 | |
| 170 mlu ->Entries[mlu ->UsedEntries].StrW = Offset; | |
| 171 mlu ->Entries[mlu ->UsedEntries].Len = size; | |
| 172 mlu ->Entries[mlu ->UsedEntries].Country = CountryCode; | |
| 173 mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode; | |
| 174 mlu ->UsedEntries++; | |
| 175 | |
| 176 return TRUE; | |
| 177 } | |
| 178 | |
| 179 // Convert from a 3-char code to a cmsUInt16Number. It is done in this way because some | |
| 180 // compilers don't properly align beginning of strings | |
| 181 static | |
| 182 cmsUInt16Number strTo16(const char str[3]) | |
| 183 { | |
| 184 const cmsUInt8Number* ptr8; | |
| 185 cmsUInt16Number n; | |
| 186 | |
| 187 // For non-existent strings | |
| 188 if (str == NULL) return 0; | |
| 189 ptr8 = (const cmsUInt8Number*)str; | |
| 190 n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]); | |
| 191 | |
| 192 return n; | |
| 193 } | |
| 194 | |
| 195 static | |
| 196 void strFrom16(char str[3], cmsUInt16Number n) | |
| 197 { | |
| 198 str[0] = (char)(n >> 8); | |
| 199 str[1] = (char)n; | |
| 200 str[2] = (char)0; | |
| 201 } | |
| 202 | |
| 203 | |
| 204 // Convert from UTF8 to wchar, returns len. | |
| 205 static | |
| 206 cmsUInt32Number decodeUTF8(wchar_t* out, const char* in) | |
| 207 { | |
| 208 cmsUInt32Number codepoint = 0; | |
| 209 cmsUInt32Number size = 0; | |
| 210 | |
| 211 while (*in) | |
| 212 { | |
| 213 cmsUInt8Number ch = (cmsUInt8Number) *in; | |
| 214 | |
| 215 if (ch <= 0x7f) | |
| 216 { | |
| 217 codepoint = ch; | |
| 218 } | |
| 219 else if (ch <= 0xbf) | |
| 220 { | |
| 221 codepoint = (codepoint << 6) | (ch & 0x3f); | |
| 222 } | |
| 223 else if (ch <= 0xdf) | |
| 224 { | |
| 225 codepoint = ch & 0x1f; | |
| 226 } | |
| 227 else if (ch <= 0xef) | |
| 228 { | |
| 229 codepoint = ch & 0x0f; | |
| 230 } | |
| 231 else | |
| 232 { | |
| 233 codepoint = ch & 0x07; | |
| 234 } | |
| 235 | |
| 236 in++; | |
| 237 | |
| 238 if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) | |
| 239 { | |
| 240 if (sizeof(wchar_t) > 2) | |
| 241 { | |
| 242 if (out) *out++ = (wchar_t) codepoint; | |
| 243 size++; | |
| 244 } | |
| 245 else | |
| 246 if (codepoint > 0xffff) | |
| 247 { | |
| 248 if (out) | |
| 249 { | |
| 250 *out++ = (wchar_t)(0xd800 + (codepoint >> 10)); | |
| 251 *out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff)); | |
| 252 size += 2; | |
| 253 } | |
| 254 } | |
| 255 else | |
| 256 if (codepoint < 0xd800 || codepoint >= 0xe000) | |
| 257 { | |
| 258 if (out) *out++ = (wchar_t) codepoint; | |
| 259 size++; | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 return size; | |
| 265 } | |
| 266 | |
| 267 // Convert from wchar_t to UTF8 | |
| 268 static | |
| 269 cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wchars, cmsUInt32Number max_chars) | |
| 270 { | |
| 271 cmsUInt32Number codepoint = 0; | |
| 272 cmsUInt32Number size = 0; | |
| 273 cmsUInt32Number len_w = 0; | |
| 274 | |
| 275 while (*in && len_w < max_wchars) | |
| 276 { | |
| 277 if (*in >= 0xd800 && *in <= 0xdbff) | |
| 278 codepoint = ((*in - 0xd800) << 10) + 0x10000; | |
| 279 else | |
| 280 { | |
| 281 if (*in >= 0xdc00 && *in <= 0xdfff) | |
| 282 codepoint |= *in - 0xdc00; | |
| 283 else | |
| 284 codepoint = *in; | |
| 285 | |
| 286 if (codepoint <= 0x7f) | |
| 287 { | |
| 288 if (out && (size + 1 < max_chars)) *out++ = (char)codepoint; | |
| 289 size++; | |
| 290 } | |
| 291 | |
| 292 else if (codepoint <= 0x7ff) | |
| 293 { | |
| 294 if (out && (max_chars > 0) && (size + 2 < max_chars)) | |
| 295 { | |
| 296 *out++ = (char)(cmsUInt32Number)(0xc0 | ((codepoint >> 6) & 0x1f)); | |
| 297 *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); | |
| 298 } | |
| 299 size += 2; | |
| 300 } | |
| 301 else if (codepoint <= 0xffff) | |
| 302 { | |
| 303 if (out && (max_chars > 0) && (size + 3 < max_chars)) | |
| 304 { | |
| 305 *out++ = (char)(cmsUInt32Number)(0xe0 | ((codepoint >> 12) & 0x0f)); | |
| 306 *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f)); | |
| 307 *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); | |
| 308 } | |
| 309 size += 3; | |
| 310 } | |
| 311 else | |
| 312 { | |
| 313 if (out && (max_chars > 0) && (size + 4 < max_chars)) | |
| 314 { | |
| 315 *out++ = (char)(cmsUInt32Number)(0xf0 | ((codepoint >> 18) & 0x07)); | |
| 316 *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 12) & 0x3f)); | |
| 317 *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f)); | |
| 318 *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); | |
| 319 } | |
| 320 size += 4; | |
| 321 } | |
| 322 | |
| 323 codepoint = 0; | |
| 324 } | |
| 325 | |
| 326 in++; len_w++; | |
| 327 } | |
| 328 | |
| 329 return size; | |
| 330 } | |
| 331 | |
| 332 // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) | |
| 333 // In the case the user explicitly sets an empty string, we force a \0 | |
| 334 cmsBool CMSEXPORT cmsMLUsetASCII(cmsContext ContextID, cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) | |
| 335 { | |
| 336 cmsUInt32Number i, len = (cmsUInt32Number)strlen(ASCIIString); | |
| 337 wchar_t* WStr; | |
| 338 cmsBool rc; | |
| 339 cmsUInt16Number Lang = strTo16(LanguageCode); | |
| 340 cmsUInt16Number Cntry = strTo16(CountryCode); | |
| 341 | |
| 342 if (mlu == NULL) return FALSE; | |
| 343 | |
| 344 // len == 0 would prevent operation, so we set a empty string pointing to zero | |
| 345 if (len == 0) | |
| 346 { | |
| 347 wchar_t empty = 0; | |
| 348 return AddMLUBlock(ContextID, mlu, sizeof(wchar_t), &empty, Lang, Cntry); | |
| 349 } | |
| 350 | |
| 351 WStr = (wchar_t*) _cmsCalloc(ContextID, len, sizeof(wchar_t)); | |
| 352 if (WStr == NULL) return FALSE; | |
| 353 | |
| 354 for (i = 0; i < len; i++) | |
| 355 WStr[i] = (wchar_t)ASCIIString[i]; | |
| 356 | |
| 357 rc = AddMLUBlock(ContextID, mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); | |
| 358 | |
| 359 _cmsFree(ContextID, WStr); | |
| 360 return rc; | |
| 361 | |
| 362 } | |
| 363 | |
| 364 // Add an UTF8 entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) | |
| 365 // In the case the user explicitly sets an empty string, we force a \0 | |
| 366 cmsBool CMSEXPORT cmsMLUsetUTF8(cmsContext ContextID, cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* UTF8String) | |
| 367 { | |
| 368 cmsUInt32Number UTF8len; | |
| 369 wchar_t* WStr; | |
| 370 cmsBool rc; | |
| 371 cmsUInt16Number Lang = strTo16(LanguageCode); | |
| 372 cmsUInt16Number Cntry = strTo16(CountryCode); | |
| 373 | |
| 374 if (mlu == NULL) return FALSE; | |
| 375 | |
| 376 if (*UTF8String == '\0') | |
| 377 { | |
| 378 wchar_t empty = 0; | |
| 379 return AddMLUBlock(ContextID, mlu, sizeof(wchar_t), &empty, Lang, Cntry); | |
| 380 } | |
| 381 | |
| 382 // Len excluding terminator 0 | |
| 383 UTF8len = decodeUTF8(NULL, UTF8String); | |
| 384 | |
| 385 // Get space for dest | |
| 386 WStr = (wchar_t*) _cmsCalloc(ContextID, UTF8len, sizeof(wchar_t)); | |
| 387 if (WStr == NULL) return FALSE; | |
| 388 | |
| 389 decodeUTF8(WStr, UTF8String); | |
| 390 | |
| 391 rc = AddMLUBlock(ContextID, mlu, UTF8len * sizeof(wchar_t), WStr, Lang, Cntry); | |
| 392 | |
| 393 _cmsFree(ContextID, WStr); | |
| 394 return rc; | |
| 395 } | |
| 396 | |
| 397 // We don't need any wcs support library | |
| 398 static | |
| 399 cmsUInt32Number mywcslen(const wchar_t *s) | |
| 400 { | |
| 401 const wchar_t *p; | |
| 402 | |
| 403 p = s; | |
| 404 while (*p) | |
| 405 p++; | |
| 406 | |
| 407 return (cmsUInt32Number)(p - s); | |
| 408 } | |
| 409 | |
| 410 // Add a wide entry. Do not add any \0 terminator (ICC1v43_2010-12.pdf page 61) | |
| 411 cmsBool CMSEXPORT cmsMLUsetWide(cmsContext ContextID, cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString) | |
| 412 { | |
| 413 cmsUInt16Number Lang = strTo16(Language); | |
| 414 cmsUInt16Number Cntry = strTo16(Country); | |
| 415 cmsUInt32Number len; | |
| 416 | |
| 417 if (mlu == NULL) return FALSE; | |
| 418 if (WideString == NULL) return FALSE; | |
| 419 | |
| 420 len = (cmsUInt32Number) (mywcslen(WideString)) * sizeof(wchar_t); | |
| 421 if (len == 0) | |
| 422 len = sizeof(wchar_t); | |
| 423 | |
| 424 return AddMLUBlock(ContextID, mlu, len, WideString, Lang, Cntry); | |
| 425 } | |
| 426 | |
| 427 // Duplicating a MLU is as easy as copying all members | |
| 428 cmsMLU* CMSEXPORT cmsMLUdup(cmsContext ContextID, const cmsMLU* mlu) | |
| 429 { | |
| 430 cmsMLU* NewMlu = NULL; | |
| 431 | |
| 432 // Duplicating a NULL obtains a NULL | |
| 433 if (mlu == NULL) return NULL; | |
| 434 | |
| 435 NewMlu = cmsMLUalloc(ContextID, mlu ->UsedEntries); | |
| 436 if (NewMlu == NULL) return NULL; | |
| 437 | |
| 438 // Should never happen | |
| 439 if (NewMlu ->AllocatedEntries < mlu ->UsedEntries) | |
| 440 goto Error; | |
| 441 | |
| 442 // Sanitize... | |
| 443 if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error; | |
| 444 | |
| 445 memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry)); | |
| 446 NewMlu ->UsedEntries = mlu ->UsedEntries; | |
| 447 | |
| 448 // The MLU may be empty | |
| 449 if (mlu ->PoolUsed == 0) { | |
| 450 NewMlu ->MemPool = NULL; | |
| 451 } | |
| 452 else { | |
| 453 // It is not empty | |
| 454 NewMlu ->MemPool = _cmsMalloc(ContextID, mlu ->PoolUsed); | |
| 455 if (NewMlu ->MemPool == NULL) goto Error; | |
| 456 } | |
| 457 | |
| 458 NewMlu ->PoolSize = mlu ->PoolUsed; | |
| 459 | |
| 460 if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error; | |
| 461 | |
| 462 memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed); | |
| 463 NewMlu ->PoolUsed = mlu ->PoolUsed; | |
| 464 | |
| 465 return NewMlu; | |
| 466 | |
| 467 Error: | |
| 468 | |
| 469 if (NewMlu != NULL) cmsMLUfree(ContextID, NewMlu); | |
| 470 return NULL; | |
| 471 } | |
| 472 | |
| 473 // Free any used memory | |
| 474 void CMSEXPORT cmsMLUfree(cmsContext ContextID, cmsMLU* mlu) | |
| 475 { | |
| 476 if (mlu) { | |
| 477 | |
| 478 if (mlu -> Entries) _cmsFree(ContextID, mlu->Entries); | |
| 479 if (mlu -> MemPool) _cmsFree(ContextID, mlu->MemPool); | |
| 480 | |
| 481 _cmsFree(ContextID, mlu); | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 | |
| 486 // The algorithm first searches for an exact match of country and language, if not found it uses | |
| 487 // the Language. If none is found, first entry is used instead. | |
| 488 static | |
| 489 const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, | |
| 490 cmsUInt32Number *len, | |
| 491 cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode, | |
| 492 cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode) | |
| 493 { | |
| 494 cmsUInt32Number i; | |
| 495 int Best = -1; | |
| 496 _cmsMLUentry* v; | |
| 497 | |
| 498 if (mlu == NULL) return NULL; | |
| 499 | |
| 500 if (mlu -> AllocatedEntries <= 0) return NULL; | |
| 501 | |
| 502 for (i=0; i < mlu ->UsedEntries; i++) { | |
| 503 | |
| 504 v = mlu ->Entries + i; | |
| 505 | |
| 506 if (v -> Language == LanguageCode) { | |
| 507 | |
| 508 if (Best == -1) Best = (int) i; | |
| 509 | |
| 510 if (v -> Country == CountryCode) { | |
| 511 | |
| 512 if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; | |
| 513 if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; | |
| 514 | |
| 515 if (len != NULL) *len = v ->Len; | |
| 516 | |
| 517 return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match | |
| 518 } | |
| 519 } | |
| 520 } | |
| 521 | |
| 522 // No string found. Return First one | |
| 523 if (Best == -1) | |
| 524 Best = 0; | |
| 525 | |
| 526 v = mlu ->Entries + Best; | |
| 527 | |
| 528 if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; | |
| 529 if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; | |
| 530 | |
| 531 if (len != NULL) *len = v ->Len; | |
| 532 | |
| 533 if (v->StrW + v->Len > mlu->PoolSize) return NULL; | |
| 534 | |
| 535 return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); | |
| 536 } | |
| 537 | |
| 538 | |
| 539 // Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len | |
| 540 cmsUInt32Number CMSEXPORT cmsMLUgetASCII(cmsContext ContextID, const cmsMLU* mlu, | |
| 541 const char LanguageCode[3], const char CountryCode[3], | |
| 542 char* Buffer, cmsUInt32Number BufferSize) | |
| 543 { | |
| 544 const wchar_t *Wide; | |
| 545 cmsUInt32Number StrLen = 0; | |
| 546 cmsUInt32Number ASCIIlen, i; | |
| 547 | |
| 548 cmsUInt16Number Lang = strTo16(LanguageCode); | |
| 549 cmsUInt16Number Cntry = strTo16(CountryCode); | |
| 550 cmsUNUSED_PARAMETER(ContextID); | |
| 551 | |
| 552 // Sanitize | |
| 553 if (mlu == NULL) return 0; | |
| 554 | |
| 555 // Get WideChar | |
| 556 Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); | |
| 557 if (Wide == NULL) return 0; | |
| 558 | |
| 559 ASCIIlen = StrLen / sizeof(wchar_t); | |
| 560 | |
| 561 // Maybe we want only to know the len? | |
| 562 if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end | |
| 563 | |
| 564 // No buffer size means no data | |
| 565 if (BufferSize <= 0) return 0; | |
| 566 | |
| 567 // Some clipping may be required | |
| 568 if (BufferSize < ASCIIlen + 1) | |
| 569 ASCIIlen = BufferSize - 1; | |
| 570 | |
| 571 // Precess each character | |
| 572 for (i=0; i < ASCIIlen; i++) { | |
| 573 | |
| 574 wchar_t wc = Wide[i]; | |
| 575 | |
| 576 if (wc < 0xff) | |
| 577 Buffer[i] = (char)wc; | |
| 578 else | |
| 579 Buffer[i] = '?'; | |
| 580 } | |
| 581 | |
| 582 // We put a termination "\0" | |
| 583 Buffer[ASCIIlen] = 0; | |
| 584 return ASCIIlen + 1; | |
| 585 } | |
| 586 | |
| 587 | |
| 588 // Obtain a UTF8 representation of the wide string. Setting buffer to NULL returns the len | |
| 589 cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(cmsContext ContextID, const cmsMLU* mlu, | |
| 590 const char LanguageCode[3], const char CountryCode[3], | |
| 591 char* Buffer, cmsUInt32Number BufferSize) | |
| 592 { | |
| 593 const wchar_t *Wide; | |
| 594 cmsUInt32Number StrLen = 0; | |
| 595 cmsUInt32Number UTF8len; | |
| 596 | |
| 597 cmsUInt16Number Lang = strTo16(LanguageCode); | |
| 598 cmsUInt16Number Cntry = strTo16(CountryCode); | |
| 599 | |
| 600 // Sanitize | |
| 601 if (mlu == NULL) return 0; | |
| 602 | |
| 603 // Get WideChar | |
| 604 Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); | |
| 605 if (Wide == NULL) return 0; | |
| 606 | |
| 607 UTF8len = encodeUTF8(NULL, Wide, StrLen / sizeof(wchar_t), BufferSize); | |
| 608 | |
| 609 // Maybe we want only to know the len? | |
| 610 if (Buffer == NULL) return UTF8len + 1; // Note the zero at the end | |
| 611 | |
| 612 // No buffer size means no data | |
| 613 if (BufferSize <= 0) return 0; | |
| 614 | |
| 615 // Some clipping may be required | |
| 616 if (BufferSize < UTF8len + 1) | |
| 617 UTF8len = BufferSize - 1; | |
| 618 | |
| 619 // Process it | |
| 620 encodeUTF8(Buffer, Wide, StrLen / sizeof(wchar_t), BufferSize); | |
| 621 | |
| 622 // We put a termination "\0" | |
| 623 Buffer[UTF8len] = 0; | |
| 624 return UTF8len + 1; | |
| 625 } | |
| 626 | |
| 627 // Obtain a wide representation of the MLU, on depending on current locale settings | |
| 628 cmsUInt32Number CMSEXPORT cmsMLUgetWide(cmsContext ContextID, const cmsMLU* mlu, | |
| 629 const char LanguageCode[3], const char CountryCode[3], | |
| 630 wchar_t* Buffer, cmsUInt32Number BufferSize) | |
| 631 { | |
| 632 const wchar_t *Wide; | |
| 633 cmsUInt32Number StrLen = 0; | |
| 634 | |
| 635 cmsUInt16Number Lang = strTo16(LanguageCode); | |
| 636 cmsUInt16Number Cntry = strTo16(CountryCode); | |
| 637 cmsUNUSED_PARAMETER(ContextID); | |
| 638 | |
| 639 // Sanitize | |
| 640 if (mlu == NULL) return 0; | |
| 641 | |
| 642 Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); | |
| 643 if (Wide == NULL) return 0; | |
| 644 | |
| 645 // Maybe we want only to know the len? | |
| 646 if (Buffer == NULL) return StrLen + sizeof(wchar_t); | |
| 647 | |
| 648 // Invalid buffer size means no data | |
| 649 if (BufferSize < sizeof(wchar_t)) return 0; | |
| 650 | |
| 651 // Some clipping may be required | |
| 652 if (BufferSize < StrLen + sizeof(wchar_t)) | |
| 653 StrLen = BufferSize - sizeof(wchar_t); | |
| 654 | |
| 655 memmove(Buffer, Wide, StrLen); | |
| 656 Buffer[StrLen / sizeof(wchar_t)] = 0; | |
| 657 | |
| 658 return StrLen + sizeof(wchar_t); | |
| 659 } | |
| 660 | |
| 661 | |
| 662 // Get also the language and country | |
| 663 CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(cmsContext ContextID, const cmsMLU* mlu, | |
| 664 const char LanguageCode[3], const char CountryCode[3], | |
| 665 char ObtainedLanguage[3], char ObtainedCountry[3]) | |
| 666 { | |
| 667 const wchar_t *Wide; | |
| 668 | |
| 669 cmsUInt16Number Lang = strTo16(LanguageCode); | |
| 670 cmsUInt16Number Cntry = strTo16(CountryCode); | |
| 671 cmsUInt16Number ObtLang, ObtCode; | |
| 672 cmsUNUSED_PARAMETER(ContextID); | |
| 673 | |
| 674 // Sanitize | |
| 675 if (mlu == NULL) return FALSE; | |
| 676 | |
| 677 Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode); | |
| 678 if (Wide == NULL) return FALSE; | |
| 679 | |
| 680 // Get used language and code | |
| 681 strFrom16(ObtainedLanguage, ObtLang); | |
| 682 strFrom16(ObtainedCountry, ObtCode); | |
| 683 | |
| 684 return TRUE; | |
| 685 } | |
| 686 | |
| 687 | |
| 688 | |
| 689 // Get the number of translations in the MLU object | |
| 690 cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(cmsContext ContextID, const cmsMLU* mlu) | |
| 691 { | |
| 692 cmsUNUSED_PARAMETER(ContextID); | |
| 693 if (mlu == NULL) return 0; | |
| 694 return mlu->UsedEntries; | |
| 695 } | |
| 696 | |
| 697 // Get the language and country codes for a specific MLU index | |
| 698 cmsBool CMSEXPORT cmsMLUtranslationsCodes(cmsContext ContextID, | |
| 699 const cmsMLU* mlu, | |
| 700 cmsUInt32Number idx, | |
| 701 char LanguageCode[3], | |
| 702 char CountryCode[3]) | |
| 703 { | |
| 704 _cmsMLUentry *entry; | |
| 705 cmsUNUSED_PARAMETER(ContextID); | |
| 706 | |
| 707 if (mlu == NULL) return FALSE; | |
| 708 | |
| 709 if (idx >= mlu->UsedEntries) return FALSE; | |
| 710 | |
| 711 entry = &mlu->Entries[idx]; | |
| 712 | |
| 713 strFrom16(LanguageCode, entry->Language); | |
| 714 strFrom16(CountryCode, entry->Country); | |
| 715 | |
| 716 return TRUE; | |
| 717 } | |
| 718 | |
| 719 | |
| 720 // Named color lists -------------------------------------------------------------------------------------------- | |
| 721 | |
| 722 // Grow the list to keep at least NumElements | |
| 723 static | |
| 724 cmsBool GrowNamedColorList(cmsContext ContextID, cmsNAMEDCOLORLIST* v) | |
| 725 { | |
| 726 cmsUInt32Number size; | |
| 727 _cmsNAMEDCOLOR * NewPtr; | |
| 728 | |
| 729 if (v == NULL) return FALSE; | |
| 730 | |
| 731 if (v ->Allocated == 0) | |
| 732 size = 64; // Initial guess | |
| 733 else | |
| 734 size = v ->Allocated * 2; | |
| 735 | |
| 736 // Keep a maximum color lists can grow, 100K entries seems reasonable | |
| 737 if (size > 1024 * 100) { | |
| 738 _cmsFree(ContextID, (void*) v->List); | |
| 739 v->List = NULL; | |
| 740 return FALSE; | |
| 741 } | |
| 742 | |
| 743 NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); | |
| 744 if (NewPtr == NULL) | |
| 745 return FALSE; | |
| 746 | |
| 747 v ->List = NewPtr; | |
| 748 v ->Allocated = size; | |
| 749 return TRUE; | |
| 750 } | |
| 751 | |
| 752 // Allocate a list for n elements | |
| 753 cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix) | |
| 754 { | |
| 755 cmsNAMEDCOLORLIST* v; | |
| 756 | |
| 757 if (ColorantCount > cmsMAXCHANNELS) | |
| 758 return NULL; | |
| 759 | |
| 760 v = (cmsNAMEDCOLORLIST*)_cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST)); | |
| 761 if (v == NULL) return NULL; | |
| 762 | |
| 763 v ->List = NULL; | |
| 764 v ->nColors = 0; | |
| 765 | |
| 766 while (v -> Allocated < n) { | |
| 767 if (!GrowNamedColorList(ContextID, v)) { | |
| 768 cmsFreeNamedColorList(ContextID, v); | |
| 769 return NULL; | |
| 770 } | |
| 771 } | |
| 772 | |
| 773 strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); | |
| 774 strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); | |
| 775 v->Prefix[32] = v->Suffix[32] = 0; | |
| 776 | |
| 777 v -> ColorantCount = ColorantCount; | |
| 778 | |
| 779 return v; | |
| 780 } | |
| 781 | |
| 782 // Free a list | |
| 783 void CMSEXPORT cmsFreeNamedColorList(cmsContext ContextID, cmsNAMEDCOLORLIST* v) | |
| 784 { | |
| 785 if (v == NULL) return; | |
| 786 if (v ->List) _cmsFree(ContextID, v ->List); | |
| 787 _cmsFree(ContextID, v); | |
| 788 } | |
| 789 | |
| 790 cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(cmsContext ContextID, const cmsNAMEDCOLORLIST* v) | |
| 791 { | |
| 792 cmsNAMEDCOLORLIST* NewNC; | |
| 793 | |
| 794 if (v == NULL) return NULL; | |
| 795 | |
| 796 NewNC= cmsAllocNamedColorList(ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix); | |
| 797 if (NewNC == NULL) return NULL; | |
| 798 | |
| 799 // For really large tables we need this | |
| 800 while (NewNC ->Allocated < v ->Allocated){ | |
| 801 if (!GrowNamedColorList(ContextID, NewNC)) | |
| 802 { | |
| 803 cmsFreeNamedColorList(ContextID, NewNC); | |
| 804 return NULL; | |
| 805 } | |
| 806 } | |
| 807 | |
| 808 memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix)); | |
| 809 memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix)); | |
| 810 NewNC ->ColorantCount = v ->ColorantCount; | |
| 811 memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR)); | |
| 812 NewNC ->nColors = v ->nColors; | |
| 813 return NewNC; | |
| 814 } | |
| 815 | |
| 816 | |
| 817 // Append a color to a list. List pointer may change if reallocated | |
| 818 cmsBool CMSEXPORT cmsAppendNamedColor(cmsContext ContextID, cmsNAMEDCOLORLIST* NamedColorList, | |
| 819 const char* Name, | |
| 820 cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS]) | |
| 821 { | |
| 822 cmsUInt32Number i; | |
| 823 | |
| 824 if (NamedColorList == NULL) return FALSE; | |
| 825 | |
| 826 if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) { | |
| 827 if (!GrowNamedColorList(ContextID, NamedColorList)) return FALSE; | |
| 828 } | |
| 829 | |
| 830 for (i=0; i < NamedColorList ->ColorantCount; i++) | |
| 831 NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL ? (cmsUInt16Number)0 : Colorant[i]; | |
| 832 | |
| 833 for (i=0; i < 3; i++) | |
| 834 NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? (cmsUInt16Number) 0 : PCS[i]; | |
| 835 | |
| 836 if (Name != NULL) { | |
| 837 | |
| 838 strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1); | |
| 839 NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; | |
| 840 | |
| 841 } | |
| 842 else | |
| 843 NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; | |
| 844 | |
| 845 | |
| 846 NamedColorList ->nColors++; | |
| 847 return TRUE; | |
| 848 } | |
| 849 | |
| 850 // Returns number of elements | |
| 851 cmsUInt32Number CMSEXPORT cmsNamedColorCount(cmsContext ContextID, const cmsNAMEDCOLORLIST* NamedColorList) | |
| 852 { | |
| 853 cmsUNUSED_PARAMETER(ContextID); | |
| 854 if (NamedColorList == NULL) return 0; | |
| 855 return NamedColorList ->nColors; | |
| 856 } | |
| 857 | |
| 858 // Info about a given color | |
| 859 cmsBool CMSEXPORT cmsNamedColorInfo(cmsContext ContextID, const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, | |
| 860 char* Name, | |
| 861 char* Prefix, | |
| 862 char* Suffix, | |
| 863 cmsUInt16Number* PCS, | |
| 864 cmsUInt16Number* Colorant) | |
| 865 { | |
| 866 if (NamedColorList == NULL) return FALSE; | |
| 867 | |
| 868 if (nColor >= cmsNamedColorCount(ContextID, NamedColorList)) return FALSE; | |
| 869 | |
| 870 // strcpy instead of strncpy because many apps are using small buffers | |
| 871 if (Name) strcpy(Name, NamedColorList->List[nColor].Name); | |
| 872 if (Prefix) strcpy(Prefix, NamedColorList->Prefix); | |
| 873 if (Suffix) strcpy(Suffix, NamedColorList->Suffix); | |
| 874 if (PCS) | |
| 875 memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number)); | |
| 876 | |
| 877 if (Colorant) | |
| 878 memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant, | |
| 879 sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount); | |
| 880 | |
| 881 | |
| 882 return TRUE; | |
| 883 } | |
| 884 | |
| 885 // Search for a given color name (no prefix or suffix) | |
| 886 cmsInt32Number CMSEXPORT cmsNamedColorIndex(cmsContext ContextID, const cmsNAMEDCOLORLIST* NamedColorList, const char* Name) | |
| 887 { | |
| 888 cmsUInt32Number i; | |
| 889 cmsUInt32Number n; | |
| 890 | |
| 891 if (NamedColorList == NULL) return -1; | |
| 892 n = cmsNamedColorCount(ContextID, NamedColorList); | |
| 893 for (i=0; i < n; i++) { | |
| 894 if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0) | |
| 895 return (cmsInt32Number) i; | |
| 896 } | |
| 897 | |
| 898 return -1; | |
| 899 } | |
| 900 | |
| 901 // MPE support ----------------------------------------------------------------------------------------------------------------- | |
| 902 | |
| 903 static | |
| 904 void FreeNamedColorList(cmsContext ContextID, cmsStage* mpe) | |
| 905 { | |
| 906 cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; | |
| 907 cmsFreeNamedColorList(ContextID, List); | |
| 908 } | |
| 909 | |
| 910 static | |
| 911 void* DupNamedColorList(cmsContext ContextID, cmsStage* mpe) | |
| 912 { | |
| 913 cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data; | |
| 914 return cmsDupNamedColorList(ContextID, List); | |
| 915 } | |
| 916 | |
| 917 static | |
| 918 void EvalNamedColorPCS(cmsContext ContextID, const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) | |
| 919 { | |
| 920 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; | |
| 921 cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); | |
| 922 | |
| 923 if (index >= NamedColorList-> nColors) { | |
| 924 cmsSignalError(ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); | |
| 925 Out[0] = Out[1] = Out[2] = 0.0f; | |
| 926 } | |
| 927 else { | |
| 928 | |
| 929 // Named color always uses Lab | |
| 930 Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0); | |
| 931 Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0); | |
| 932 Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0); | |
| 933 } | |
| 934 } | |
| 935 | |
| 936 static | |
| 937 void EvalNamedColor(cmsContext ContextID, const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) | |
| 938 { | |
| 939 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data; | |
| 940 cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0); | |
| 941 cmsUInt32Number j; | |
| 942 | |
| 943 if (index >= NamedColorList-> nColors) { | |
| 944 cmsSignalError(ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index); | |
| 945 for (j = 0; j < NamedColorList->ColorantCount; j++) | |
| 946 Out[j] = 0.0f; | |
| 947 } | |
| 948 else { | |
| 949 for (j=0; j < NamedColorList ->ColorantCount; j++) | |
| 950 Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0); | |
| 951 } | |
| 952 } | |
| 953 | |
| 954 | |
| 955 // Named color lookup element | |
| 956 cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsContext ContextID, cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS) | |
| 957 { | |
| 958 return _cmsStageAllocPlaceholder(ContextID, | |
| 959 cmsSigNamedColorElemType, | |
| 960 1, UsePCS ? 3 : NamedColorList ->ColorantCount, | |
| 961 UsePCS ? EvalNamedColorPCS : EvalNamedColor, | |
| 962 DupNamedColorList, | |
| 963 FreeNamedColorList, | |
| 964 cmsDupNamedColorList(ContextID, NamedColorList)); | |
| 965 | |
| 966 } | |
| 967 | |
| 968 | |
| 969 // Retrieve the named color list from a transform. Should be first element in the LUT | |
| 970 cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) | |
| 971 { | |
| 972 _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; | |
| 973 cmsStage* mpe; | |
| 974 | |
| 975 if (v == NULL) return NULL; | |
| 976 if (v->core == NULL) return NULL; | |
| 977 if (v->core->Lut == NULL) return NULL; | |
| 978 | |
| 979 mpe = v->core->Lut->Elements; | |
| 980 if (mpe == NULL) return NULL; | |
| 981 | |
| 982 if (mpe ->Type != cmsSigNamedColorElemType) return NULL; | |
| 983 return (cmsNAMEDCOLORLIST*) mpe ->Data; | |
| 984 } | |
| 985 | |
| 986 | |
| 987 // Profile sequence description routines ------------------------------------------------------------------------------------- | |
| 988 | |
| 989 cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n) | |
| 990 { | |
| 991 cmsSEQ* Seq; | |
| 992 cmsUInt32Number i; | |
| 993 | |
| 994 if (n == 0) return NULL; | |
| 995 | |
| 996 // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked | |
| 997 // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door! | |
| 998 if (n > 255) return NULL; | |
| 999 | |
| 1000 Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ)); | |
| 1001 if (Seq == NULL) return NULL; | |
| 1002 | |
| 1003 Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC)); | |
| 1004 Seq -> n = n; | |
| 1005 | |
| 1006 if (Seq -> seq == NULL) { | |
| 1007 _cmsFree(ContextID, Seq); | |
| 1008 return NULL; | |
| 1009 } | |
| 1010 | |
| 1011 for (i=0; i < n; i++) { | |
| 1012 Seq -> seq[i].Manufacturer = NULL; | |
| 1013 Seq -> seq[i].Model = NULL; | |
| 1014 Seq -> seq[i].Description = NULL; | |
| 1015 } | |
| 1016 | |
| 1017 return Seq; | |
| 1018 } | |
| 1019 | |
| 1020 void CMSEXPORT cmsFreeProfileSequenceDescription(cmsContext ContextID, cmsSEQ* pseq) | |
| 1021 { | |
| 1022 cmsUInt32Number i; | |
| 1023 | |
| 1024 if (pseq == NULL) | |
| 1025 return; | |
| 1026 | |
| 1027 if (pseq ->seq != NULL) { | |
| 1028 for (i=0; i < pseq ->n; i++) { | |
| 1029 if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(ContextID, pseq ->seq[i].Manufacturer); | |
| 1030 if (pseq ->seq[i].Model != NULL) cmsMLUfree(ContextID, pseq ->seq[i].Model); | |
| 1031 if (pseq ->seq[i].Description != NULL) cmsMLUfree(ContextID, pseq ->seq[i].Description); | |
| 1032 } | |
| 1033 | |
| 1034 _cmsFree(ContextID, pseq ->seq); | |
| 1035 } | |
| 1036 | |
| 1037 _cmsFree(ContextID, pseq); | |
| 1038 } | |
| 1039 | |
| 1040 cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(cmsContext ContextID, const cmsSEQ* pseq) | |
| 1041 { | |
| 1042 cmsSEQ *NewSeq; | |
| 1043 cmsUInt32Number i; | |
| 1044 | |
| 1045 if (pseq == NULL) | |
| 1046 return NULL; | |
| 1047 | |
| 1048 NewSeq = (cmsSEQ*) _cmsMalloc(ContextID, sizeof(cmsSEQ)); | |
| 1049 if (NewSeq == NULL) return NULL; | |
| 1050 | |
| 1051 | |
| 1052 NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, pseq ->n, sizeof(cmsPSEQDESC)); | |
| 1053 if (NewSeq ->seq == NULL) goto Error; | |
| 1054 | |
| 1055 NewSeq -> n = pseq ->n; | |
| 1056 | |
| 1057 for (i=0; i < pseq->n; i++) { | |
| 1058 | |
| 1059 memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number)); | |
| 1060 | |
| 1061 NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg; | |
| 1062 NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel; | |
| 1063 memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID)); | |
| 1064 NewSeq ->seq[i].technology = pseq ->seq[i].technology; | |
| 1065 | |
| 1066 NewSeq ->seq[i].Manufacturer = cmsMLUdup(ContextID, pseq ->seq[i].Manufacturer); | |
| 1067 NewSeq ->seq[i].Model = cmsMLUdup(ContextID, pseq ->seq[i].Model); | |
| 1068 NewSeq ->seq[i].Description = cmsMLUdup(ContextID, pseq ->seq[i].Description); | |
| 1069 | |
| 1070 } | |
| 1071 | |
| 1072 return NewSeq; | |
| 1073 | |
| 1074 Error: | |
| 1075 | |
| 1076 cmsFreeProfileSequenceDescription(ContextID, NewSeq); | |
| 1077 return NULL; | |
| 1078 } | |
| 1079 | |
| 1080 // Dictionaries -------------------------------------------------------------------------------------------------------- | |
| 1081 | |
| 1082 // Dictionaries are just very simple linked lists | |
| 1083 | |
| 1084 | |
| 1085 typedef struct _cmsDICT_struct { | |
| 1086 cmsDICTentry* head; | |
| 1087 } _cmsDICT; | |
| 1088 | |
| 1089 | |
| 1090 // Allocate an empty dictionary | |
| 1091 cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID) | |
| 1092 { | |
| 1093 _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT)); | |
| 1094 if (dict == NULL) return NULL; | |
| 1095 | |
| 1096 return (cmsHANDLE) dict; | |
| 1097 | |
| 1098 } | |
| 1099 | |
| 1100 // Dispose resources | |
| 1101 void CMSEXPORT cmsDictFree(cmsContext ContextID, cmsHANDLE hDict) | |
| 1102 { | |
| 1103 _cmsDICT* dict = (_cmsDICT*) hDict; | |
| 1104 cmsDICTentry *entry, *next; | |
| 1105 | |
| 1106 _cmsAssert(dict != NULL); | |
| 1107 | |
| 1108 // Walk the list freeing all nodes | |
| 1109 entry = dict ->head; | |
| 1110 while (entry != NULL) { | |
| 1111 | |
| 1112 if (entry ->DisplayName != NULL) cmsMLUfree(ContextID, entry ->DisplayName); | |
| 1113 if (entry ->DisplayValue != NULL) cmsMLUfree(ContextID, entry ->DisplayValue); | |
| 1114 if (entry ->Name != NULL) _cmsFree(ContextID, entry -> Name); | |
| 1115 if (entry ->Value != NULL) _cmsFree(ContextID, entry -> Value); | |
| 1116 | |
| 1117 // Don't fall in the habitual trap... | |
| 1118 next = entry ->Next; | |
| 1119 _cmsFree(ContextID, entry); | |
| 1120 | |
| 1121 entry = next; | |
| 1122 } | |
| 1123 | |
| 1124 _cmsFree(ContextID, dict); | |
| 1125 } | |
| 1126 | |
| 1127 | |
| 1128 // Duplicate a wide char string | |
| 1129 static | |
| 1130 wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr) | |
| 1131 { | |
| 1132 if (ptr == NULL) return NULL; | |
| 1133 return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t)); | |
| 1134 } | |
| 1135 | |
| 1136 // Add a new entry to the linked list | |
| 1137 cmsBool CMSEXPORT cmsDictAddEntry(cmsContext ContextID, cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue) | |
| 1138 { | |
| 1139 _cmsDICT* dict = (_cmsDICT*) hDict; | |
| 1140 cmsDICTentry *entry; | |
| 1141 | |
| 1142 _cmsAssert(dict != NULL); | |
| 1143 _cmsAssert(Name != NULL); | |
| 1144 | |
| 1145 entry = (cmsDICTentry*) _cmsMallocZero(ContextID, sizeof(cmsDICTentry)); | |
| 1146 if (entry == NULL) return FALSE; | |
| 1147 | |
| 1148 entry ->DisplayName = cmsMLUdup(ContextID, DisplayName); | |
| 1149 entry ->DisplayValue = cmsMLUdup(ContextID, DisplayValue); | |
| 1150 entry ->Name = DupWcs(ContextID, Name); | |
| 1151 entry ->Value = DupWcs(ContextID, Value); | |
| 1152 | |
| 1153 entry ->Next = dict ->head; | |
| 1154 dict ->head = entry; | |
| 1155 | |
| 1156 return TRUE; | |
| 1157 } | |
| 1158 | |
| 1159 | |
| 1160 // Duplicates an existing dictionary | |
| 1161 cmsHANDLE CMSEXPORT cmsDictDup(cmsContext ContextID, cmsHANDLE hDict) | |
| 1162 { | |
| 1163 _cmsDICT* old_dict = (_cmsDICT*) hDict; | |
| 1164 cmsHANDLE hNew; | |
| 1165 cmsDICTentry *entry; | |
| 1166 | |
| 1167 _cmsAssert(old_dict != NULL); | |
| 1168 | |
| 1169 hNew = cmsDictAlloc(ContextID); | |
| 1170 if (hNew == NULL) return NULL; | |
| 1171 | |
| 1172 // Walk the list freeing all nodes | |
| 1173 entry = old_dict ->head; | |
| 1174 while (entry != NULL) { | |
| 1175 | |
| 1176 if (!cmsDictAddEntry(ContextID, hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) { | |
| 1177 | |
| 1178 cmsDictFree(ContextID, hNew); | |
| 1179 return NULL; | |
| 1180 } | |
| 1181 | |
| 1182 entry = entry -> Next; | |
| 1183 } | |
| 1184 | |
| 1185 return hNew; | |
| 1186 } | |
| 1187 | |
| 1188 // Get a pointer to the linked list | |
| 1189 const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsContext ContextID, cmsHANDLE hDict) | |
| 1190 { | |
| 1191 _cmsDICT* dict = (_cmsDICT*) hDict; | |
| 1192 cmsUNUSED_PARAMETER(ContextID); | |
| 1193 | |
| 1194 if (dict == NULL) return NULL; | |
| 1195 return dict ->head; | |
| 1196 } | |
| 1197 | |
| 1198 // Helper For external languages | |
| 1199 const cmsDICTentry* CMSEXPORT cmsDictNextEntry(cmsContext ContextID, const cmsDICTentry* e) | |
| 1200 { | |
| 1201 cmsUNUSED_PARAMETER(ContextID); | |
| 1202 if (e == NULL) return NULL; | |
| 1203 return e ->Next; | |
| 1204 } |
