1 /* 2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <windows.h> 27 #include <stdio.h> 28 29 #include <jni.h> 30 #include <jni_util.h> 31 #include <sun_awt_Win32FontManager.h> 32 33 #define BSIZE (max(512, MAX_PATH+1)) 34 35 /* Typically all local references held by a JNI function are automatically 36 * released by JVM when the function returns. However, there is a limit to the 37 * number of local references that can remain active. If the local references 38 * continue to grow, it could result in out of memory error. Henceforth, we 39 * invoke DeleteLocalRef on objects that are no longer needed for execution in 40 * the JNI function. 41 */ 42 #define DeleteLocalReference(env, jniRef) \ 43 do { \ 44 if (jniRef != NULL) { \ 45 (*env)->DeleteLocalRef(env, jniRef); \ 46 jniRef = NULL; \ 47 } \ 48 } while (0) 49 50 JNIEXPORT jstring JNICALL Java_sun_awt_Win32FontManager_getFontPath(JNIEnv *env, jobject thiz, jboolean noType1) 51 { 52 char windir[BSIZE]; 53 char sysdir[BSIZE]; 54 char fontpath[BSIZE*2]; 55 char *end; 56 57 /* Locate fonts directories relative to the Windows System directory. 58 * If Windows System location is different than the user's window 59 * directory location, as in a shared Windows installation, 60 * return both locations as potential font directories 61 */ 62 GetSystemDirectory(sysdir, BSIZE); 63 end = strrchr(sysdir,'\\'); 64 if (end && (stricmp(end,"\\System") || stricmp(end,"\\System32"))) { 65 *end = 0; 66 strcat(sysdir, "\\Fonts"); 67 } 68 69 GetWindowsDirectory(windir, BSIZE); 70 if (strlen(windir) > BSIZE-7) { 71 *windir = 0; 72 } else { 73 strcat(windir, "\\Fonts"); 74 } 75 76 strcpy(fontpath,sysdir); 77 if (stricmp(sysdir,windir)) { 78 strcat(fontpath,";"); 79 strcat(fontpath,windir); 80 } 81 82 return JNU_NewStringPlatform(env, fontpath); 83 } 84 85 /* The code below is used to obtain information from the windows font APIS 86 * and registry on which fonts are available and what font files hold those 87 * fonts. The results are used to speed font lookup. 88 */ 89 90 typedef struct GdiFontMapInfo { 91 JNIEnv *env; 92 jstring family; 93 jobject fontToFamilyMap; 94 jobject familyToFontListMap; 95 jobject list; 96 jmethodID putMID; 97 jmethodID containsKeyMID; 98 jclass arrayListClass; 99 jmethodID arrayListCtr; 100 jmethodID addMID; 101 jmethodID toLowerCaseMID; 102 jobject locale; 103 } GdiFontMapInfo; 104 105 /* Registry entry for fonts */ 106 static const char FONTKEY_NT[] = 107 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 108 109 typedef struct CheckFamilyInfo { 110 wchar_t *family; 111 wchar_t* fullName; 112 int isDifferent; 113 } CheckFamilyInfo; 114 115 static int CALLBACK CheckFontFamilyProcW( 116 ENUMLOGFONTEXW *lpelfe, 117 NEWTEXTMETRICEX *lpntme, 118 int FontType, 119 LPARAM lParam) 120 { 121 CheckFamilyInfo *info = (CheckFamilyInfo*)lParam; 122 info->isDifferent = wcscmp(lpelfe->elfLogFont.lfFaceName, info->family); 123 124 /* if (!info->isDifferent) { */ 125 /* wprintf(LFor font %s expected family=%s instead got %s\n", */ 126 /* lpelfe->elfFullName, */ 127 /* info->family, */ 128 /* lpelfe->elfLogFont.lfFaceName); */ 129 /* fflush(stdout); */ 130 /* } */ 131 return 0; 132 } 133 134 /* This HDC is initialised and released in the populate family map 135 * JNI entry point, and used within the call which would otherwise 136 * create many DCs. 137 */ 138 static HDC screenDC = NULL; 139 140 static int DifferentFamily(wchar_t *family, wchar_t* fullName) { 141 LOGFONTW lfw; 142 CheckFamilyInfo info; 143 144 /* If fullName can't be stored in the struct, assume correct family */ 145 if (wcslen((LPWSTR)fullName) >= LF_FACESIZE) { 146 return 0; 147 } 148 149 memset(&info, 0, sizeof(CheckFamilyInfo)); 150 info.family = family; 151 info.fullName = fullName; 152 info.isDifferent = 0; 153 154 memset(&lfw, 0, sizeof(lfw)); 155 wcscpy(lfw.lfFaceName, fullName); 156 lfw.lfCharSet = DEFAULT_CHARSET; 157 EnumFontFamiliesExW(screenDC, &lfw, 158 (FONTENUMPROCW)CheckFontFamilyProcW, 159 (LPARAM)(&info), 0L); 160 161 return info.isDifferent; 162 } 163 164 /* Callback for call to EnumFontFamiliesEx in the EnumFamilyNames function. 165 * Expects to be called once for each face name in the family specified 166 * in the call. We extract the full name for the font which is expected 167 * to be in the "system encoding" and create canonical and lower case 168 * Java strings for the name which are added to the maps. The lower case 169 * name is used as key to the family name value in the font to family map, 170 * the canonical name is one of the"list" of members of the family. 171 */ 172 static int CALLBACK EnumFontFacesInFamilyProcW( 173 ENUMLOGFONTEXW *lpelfe, 174 NEWTEXTMETRICEX *lpntme, 175 int FontType, 176 LPARAM lParam) 177 { 178 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 179 JNIEnv *env = fmi->env; 180 jstring fullname, fullnameLC; 181 182 /* Exceptions indicate critical errors such that program cannot continue 183 * with further execution. Henceforth, the function returns immediately 184 * on pending exceptions. In these situations, the function also returns 185 * 0 indicating windows API to stop further enumeration and callbacks. 186 * 187 * The JNI functions do not clear the pending exceptions. This allows the 188 * caller (Java code) to check and handle exceptions in the best possible 189 * way. 190 */ 191 if ((*env)->ExceptionCheck(env)) { 192 return 0; 193 } 194 195 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 196 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 197 return 1; 198 } 199 200 /* Windows has font aliases and so may enumerate fonts from 201 * the aliased family if any actual font of that family is installed. 202 * To protect against it ignore fonts which aren't enumerated under 203 * their true family. 204 */ 205 if (DifferentFamily(lpelfe->elfLogFont.lfFaceName, 206 lpelfe->elfFullName)) { 207 return 1; 208 } 209 210 fullname = (*env)->NewString(env, lpelfe->elfFullName, 211 (jsize)wcslen((LPWSTR)lpelfe->elfFullName)); 212 if (fullname == NULL) { 213 (*env)->ExceptionClear(env); 214 return 1; 215 } 216 217 (*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname); 218 if ((*env)->ExceptionCheck(env)) { 219 /* Delete the created reference before return */ 220 DeleteLocalReference(env, fullname); 221 return 0; 222 } 223 224 fullnameLC = (*env)->CallObjectMethod(env, fullname, 225 fmi->toLowerCaseMID, fmi->locale); 226 /* Delete the created reference after its usage */ 227 DeleteLocalReference(env, fullname); 228 if ((*env)->ExceptionCheck(env)) { 229 return 0; 230 } 231 232 (*env)->CallObjectMethod(env, fmi->fontToFamilyMap, 233 fmi->putMID, fullnameLC, fmi->family); 234 /* Delete the created reference after its usage */ 235 DeleteLocalReference(env, fullnameLC); 236 if ((*env)->ExceptionCheck(env)) { 237 return 0; 238 } 239 240 return 1; 241 } 242 243 /* Callback for EnumFontFamiliesEx in populateFontFileNameMap. 244 * Expects to be called for every charset of every font family. 245 * If this is the first time we have been called for this family, 246 * add a new mapping to the familyToFontListMap from this family to a 247 * list of its members. To populate that list, further enumerate all faces 248 * in this family for the matched charset. This assumes that all fonts 249 * in a family support the same charset, which is a fairly safe assumption 250 * and saves time as the call we make here to EnumFontFamiliesEx will 251 * enumerate the members of this family just once each. 252 * Because we set fmi->list to be the newly created list the call back 253 * can safely add to that list without a search. 254 */ 255 static int CALLBACK EnumFamilyNamesW( 256 ENUMLOGFONTEXW *lpelfe, /* pointer to logical-font data */ 257 NEWTEXTMETRICEX *lpntme, /* pointer to physical-font data */ 258 int FontType, /* type of font */ 259 LPARAM lParam ) /* application-defined data */ 260 { 261 GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam; 262 JNIEnv *env = fmi->env; 263 jstring familyLC; 264 size_t slen; 265 LOGFONTW lfw; 266 267 /* Exceptions indicate critical errors such that program cannot continue 268 * with further execution. Henceforth, the function returns immediately 269 * on pending exceptions. In these situations, the function also returns 270 * 0 indicating windows API to stop further enumeration and callbacks. 271 * 272 * The JNI functions do not clear the pending exceptions. This allows the 273 * caller (Java code) to check and handle exceptions in the best possible 274 * way. 275 */ 276 if ((*env)->ExceptionCheck(env)) { 277 return 0; 278 } 279 280 /* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */ 281 if (FontType != TRUETYPE_FONTTYPE && FontType != DEVICE_FONTTYPE) { 282 return 1; 283 } 284 /* wprintf(L"FAMILY=%s charset=%d FULL=%s\n", */ 285 /* lpelfe->elfLogFont.lfFaceName, */ 286 /* lpelfe->elfLogFont.lfCharSet, */ 287 /* lpelfe->elfFullName); */ 288 /* fflush(stdout); */ 289 290 /* Windows lists fonts which have a vmtx (vertical metrics) table twice. 291 * Once using their normal name, and again preceded by '@'. These appear 292 * in font lists in some windows apps, such as wordpad. We don't want 293 * these so we skip any font where the first character is '@' 294 */ 295 if (lpelfe->elfLogFont.lfFaceName[0] == L'@') { 296 return 1; 297 } 298 slen = wcslen(lpelfe->elfLogFont.lfFaceName); 299 fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen); 300 if (fmi->family == NULL) { 301 (*env)->ExceptionClear(env); 302 return 1; 303 } 304 305 familyLC = (*env)->CallObjectMethod(env, fmi->family, 306 fmi->toLowerCaseMID, fmi->locale); 307 /* Delete the created reference after its usage */ 308 DeleteLocalReference(env, fmi->family); 309 if ((*env)->ExceptionCheck(env)) { 310 return 0; 311 } 312 313 /* check if already seen this family with a different charset */ 314 jboolean mapHasKey = (*env)->CallBooleanMethod(env, 315 fmi->familyToFontListMap, 316 fmi->containsKeyMID, 317 familyLC); 318 if ((*env)->ExceptionCheck(env)) { 319 /* Delete the created references before return */ 320 DeleteLocalReference(env, familyLC); 321 return 0; 322 } else if (mapHasKey) { 323 /* Delete the created references before return */ 324 DeleteLocalReference(env, familyLC); 325 return 1; 326 } 327 328 fmi->list = (*env)->NewObject(env, 329 fmi->arrayListClass, fmi->arrayListCtr, 4); 330 if (fmi->list == NULL) { 331 /* Delete the created references before return */ 332 DeleteLocalReference(env, familyLC); 333 return 0; 334 } 335 336 (*env)->CallObjectMethod(env, fmi->familyToFontListMap, 337 fmi->putMID, familyLC, fmi->list); 338 /* Delete the created reference after its usage */ 339 DeleteLocalReference(env, familyLC); 340 if ((*env)->ExceptionCheck(env)) { 341 /* Delete the created reference before return */ 342 DeleteLocalReference(env, fmi->list); 343 return 0; 344 } 345 346 memset(&lfw, 0, sizeof(lfw)); 347 wcscpy(lfw.lfFaceName, lpelfe->elfLogFont.lfFaceName); 348 lfw.lfCharSet = lpelfe->elfLogFont.lfCharSet; 349 EnumFontFamiliesExW(screenDC, &lfw, 350 (FONTENUMPROCW)EnumFontFacesInFamilyProcW, 351 lParam, 0L); 352 353 /* Delete the created reference after its usage in the enum function */ 354 DeleteLocalReference(env, fmi->list); 355 return 1; 356 } 357 358 /* It looks like TrueType fonts have " (TrueType)" tacked on the end of their 359 * name, so we can try to use that to distinguish TT from other fonts. 360 * However if a program "installed" a font in the registry the key may 361 * not include that. We could also try to "pass" fonts which have no "(..)" 362 * at the end. But that turns out to pass a few .FON files that MS supply. 363 * If there's no parenthesized type string, we could next try to infer 364 * the file type from the file name extension. Since the MS entries that 365 * have no type string are very few, and have odd names like "MS-DOS CP 437" 366 * and would never return a Java Font anyway its currently OK to put these 367 * in the font map, although clearly the returned names must never percolate 368 * up into a list of available fonts returned to the application. 369 * Additionally for TTC font files the key looks like 370 * Font 1 & Font 2 (TrueType) 371 * or sometimes even : 372 * Font 1 & Font 2 & Font 3 (TrueType) 373 * Also if a Font has a name for this locale that name also 374 * exists in the registry using the appropriate platform encoding. 375 * What do we do then? 376 * 377 * Note: OpenType fonts seems to have " (TrueType)" suffix on Vista 378 * but " (OpenType)" on XP. 379 */ 380 static BOOL RegistryToBaseTTNameW(LPWSTR name) { 381 static const wchar_t TTSUFFIX[] = L" (TrueType)"; 382 static const wchar_t OTSUFFIX[] = L" (OpenType)"; 383 size_t TTSLEN = wcslen(TTSUFFIX); 384 wchar_t *suffix; 385 386 size_t len = wcslen(name); 387 if (len == 0) { 388 return FALSE; 389 } 390 if (name[len-1] != L')') { 391 return FALSE; 392 } 393 if (len <= TTSLEN) { 394 return FALSE; 395 } 396 /* suffix length is the same for truetype and opentype fonts */ 397 suffix = name + (len - TTSLEN); 398 if (wcscmp(suffix, TTSUFFIX) == 0 || wcscmp(suffix, OTSUFFIX) == 0) { 399 suffix[0] = L'\0'; /* truncate name */ 400 return TRUE; 401 } 402 return FALSE; 403 } 404 405 static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap, 406 LPWSTR name, LPWSTR data) { 407 408 wchar_t *ptr1, *ptr2; 409 jstring fontStr; 410 jstring fontStrLC; 411 JNIEnv *env = fmi->env; 412 size_t dslen = wcslen(data); 413 jstring fileStr = (*env)->NewString(env, data, (jsize)dslen); 414 if (fileStr == NULL) { 415 (*env)->ExceptionClear(env); 416 return; 417 } 418 419 /* TTC or ttc means it may be a collection. Need to parse out 420 * multiple font face names separated by " & " 421 * By only doing this for fonts which look like collections based on 422 * file name we are adhering to MS recommendations for font file names 423 * so it seems that we can be sure that this identifies precisely 424 * the MS-supplied truetype collections. 425 * This avoids any potential issues if a TTF file happens to have 426 * a & in the font name (I can't find anything which prohibits this) 427 * and also means we only parse the key in cases we know to be 428 * worthwhile. 429 */ 430 431 if ((data[dslen-1] == L'C' || data[dslen-1] == L'c') && 432 (ptr1 = wcsstr(name, L" & ")) != NULL) { 433 ptr1+=3; 434 while (ptr1 >= name) { /* marginally safer than while (true) */ 435 while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) { 436 ptr1 = ptr2+3; 437 } 438 fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1)); 439 if (fontStr == NULL) { 440 (*env)->ExceptionClear(env); 441 /* Delete the created reference before return */ 442 DeleteLocalReference(env, fileStr); 443 return; 444 } 445 446 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 447 fmi->toLowerCaseMID, 448 fmi->locale); 449 /* Delete the created reference after its usage */ 450 DeleteLocalReference(env, fontStr); 451 if ((*env)->ExceptionCheck(env)) { 452 /* Delete the created reference before return */ 453 DeleteLocalReference(env, fileStr); 454 return; 455 } 456 457 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 458 fontStrLC, fileStr); 459 /* Delete the reference after its usage */ 460 DeleteLocalReference(env, fontStrLC); 461 if ((*env)->ExceptionCheck(env)) { 462 /* Delete the created reference before return */ 463 DeleteLocalReference(env, fileStr); 464 return; 465 } 466 467 if (ptr1 == name) { 468 break; 469 } else { 470 *(ptr1-3) = L'\0'; 471 ptr1 = name; 472 } 473 } 474 } else { 475 fontStr = (*env)->NewString(env, name, (jsize)wcslen(name)); 476 if (fontStr == NULL) { 477 (*env)->ExceptionClear(env); 478 /* Delete the created reference before return */ 479 DeleteLocalReference(env, fileStr); 480 return; 481 } 482 483 fontStrLC = (*env)->CallObjectMethod(env, fontStr, 484 fmi->toLowerCaseMID, fmi->locale); 485 /* Delete the created reference after its usage */ 486 DeleteLocalReference(env, fontStr); 487 if ((*env)->ExceptionCheck(env)) { 488 /* Delete the created reference before return */ 489 DeleteLocalReference(env, fileStr); 490 return; 491 } 492 493 (*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID, 494 fontStrLC, fileStr); 495 /* Delete the created reference after its usage */ 496 DeleteLocalReference(env, fontStrLC); 497 if ((*env)->ExceptionCheck(env)) { 498 /* Delete the created reference before return */ 499 DeleteLocalReference(env, fileStr); 500 return; 501 } 502 } 503 504 /* Delete the created reference after its usage */ 505 DeleteLocalReference(env, fileStr); 506 } 507 508 /* Obtain all the fontname -> filename mappings. 509 * This is called once and the results returned to Java code which can 510 * use it for lookups to reduce or avoid the need to search font files. 511 */ 512 JNIEXPORT void JNICALL 513 Java_sun_awt_Win32FontManager_populateFontFileNameMap0 514 (JNIEnv *env, jclass obj, jobject fontToFileMap, 515 jobject fontToFamilyMap, jobject familyToFontListMap, jobject locale) 516 { 517 #define MAX_BUFFER (FILENAME_MAX+1) 518 const wchar_t wname[MAX_BUFFER]; 519 const char data[MAX_BUFFER]; 520 521 DWORD type; 522 LONG ret; 523 HKEY hkeyFonts; 524 DWORD dwNameSize; 525 DWORD dwDataValueSize; 526 DWORD nval; 527 DWORD dwNumValues, dwMaxValueNameLen, dwMaxValueDataLen; 528 DWORD numValues = 0; 529 jclass classIDHashMap; 530 jclass classIDString; 531 jmethodID putMID; 532 GdiFontMapInfo fmi; 533 534 /* Check we were passed all the maps we need, and do lookup of 535 * methods for JNI up-calls 536 */ 537 if (fontToFileMap == NULL || 538 fontToFamilyMap == NULL || 539 familyToFontListMap == NULL) { 540 return; 541 } 542 classIDHashMap = (*env)->FindClass(env, "java/util/HashMap"); 543 if (classIDHashMap == NULL) { 544 return; 545 } 546 putMID = (*env)->GetMethodID(env, classIDHashMap, "put", 547 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 548 if (putMID == NULL) { 549 return; 550 } 551 552 fmi.env = env; 553 fmi.fontToFamilyMap = fontToFamilyMap; 554 fmi.familyToFontListMap = familyToFontListMap; 555 fmi.putMID = putMID; 556 fmi.locale = locale; 557 fmi.containsKeyMID = (*env)->GetMethodID(env, classIDHashMap, 558 "containsKey", 559 "(Ljava/lang/Object;)Z"); 560 if (fmi.containsKeyMID == NULL) { 561 return; 562 } 563 564 fmi.arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); 565 if (fmi.arrayListClass == NULL) { 566 return; 567 } 568 fmi.arrayListCtr = (*env)->GetMethodID(env, fmi.arrayListClass, 569 "<init>", "(I)V"); 570 if (fmi.arrayListCtr == NULL) { 571 return; 572 } 573 fmi.addMID = (*env)->GetMethodID(env, fmi.arrayListClass, 574 "add", "(Ljava/lang/Object;)Z"); 575 if (fmi.addMID == NULL) { 576 return; 577 } 578 579 classIDString = (*env)->FindClass(env, "java/lang/String"); 580 if (classIDString == NULL) { 581 return; 582 } 583 fmi.toLowerCaseMID = 584 (*env)->GetMethodID(env, classIDString, "toLowerCase", 585 "(Ljava/util/Locale;)Ljava/lang/String;"); 586 if (fmi.toLowerCaseMID == NULL) { 587 return; 588 } 589 590 screenDC = GetDC(NULL); 591 if (screenDC == NULL) { 592 return; 593 } 594 595 /* Enumerate fonts via GDI to build maps of fonts and families */ 596 LOGFONTW lfw; 597 memset(&lfw, 0, sizeof(lfw)); 598 lfw.lfCharSet = DEFAULT_CHARSET; /* all charsets */ 599 wcscpy(lfw.lfFaceName, L""); /* one face per family (CHECK) */ 600 EnumFontFamiliesExW(screenDC, &lfw, 601 (FONTENUMPROCW)EnumFamilyNamesW, 602 (LPARAM)(&fmi), 0L); 603 604 /* Use the windows registry to map font names to files */ 605 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 606 FONTKEY_NT, 0L, KEY_READ, &hkeyFonts); 607 if (ret != ERROR_SUCCESS) { 608 ReleaseDC(NULL, screenDC); 609 screenDC = NULL; 610 return; 611 } 612 613 ret = RegQueryInfoKeyW(hkeyFonts, NULL, NULL, NULL, NULL, NULL, NULL, 614 &dwNumValues, &dwMaxValueNameLen, 615 &dwMaxValueDataLen, NULL, NULL); 616 617 if (ret != ERROR_SUCCESS || 618 dwMaxValueNameLen >= MAX_BUFFER || 619 dwMaxValueDataLen >= MAX_BUFFER) { 620 RegCloseKey(hkeyFonts); 621 ReleaseDC(NULL, screenDC); 622 screenDC = NULL; 623 return; 624 } 625 for (nval = 0; nval < dwNumValues; nval++ ) { 626 dwNameSize = MAX_BUFFER; 627 dwDataValueSize = MAX_BUFFER; 628 ret = RegEnumValueW(hkeyFonts, nval, (LPWSTR)wname, &dwNameSize, 629 NULL, &type, (LPBYTE)data, &dwDataValueSize); 630 631 if (ret != ERROR_SUCCESS) { 632 break; 633 } 634 if (type != REG_SZ) { /* REG_SZ means a null-terminated string */ 635 continue; 636 } 637 638 if (!RegistryToBaseTTNameW((LPWSTR)wname) ) { 639 /* If the filename ends with ".ttf" or ".otf" also accept it. 640 * Not expecting to need to do this for .ttc files. 641 * Also note this code is not mirrored in the "A" (win9x) path. 642 */ 643 LPWSTR dot = wcsrchr((LPWSTR)data, L'.'); 644 if (dot == NULL || ((wcsicmp(dot, L".ttf") != 0) 645 && (wcsicmp(dot, L".otf") != 0))) { 646 continue; /* not a TT font... */ 647 } 648 } 649 registerFontW(&fmi, fontToFileMap, (LPWSTR)wname, (LPWSTR)data); 650 } 651 652 RegCloseKey(hkeyFonts); 653 ReleaseDC(NULL, screenDC); 654 screenDC = NULL; 655 }