1 /*******************************************************************************
2 * Adobe Font Metric (AFM) file parsing finctions for Wine PostScript driver.
3 * See http://partners.adobe.com/asn/developer/pdfs/tn/5004.AFM_Spec.pdf.
5 * Copyright 2001 Ian Pilcher
8 * NOTE: Many of the functions in this file can return either fatal errors
9 * (memory allocation failure) or non-fatal errors (unusable AFM file).
10 * Fatal errors are indicated by returning FALSE; see individual function
11 * descriptions for how they indicate non-fatal errors.
23 #include <limits.h> /* INT_MIN */
26 #include <float.h> /* FLT_MAX */
33 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(psdrv);
37 /*******************************************************************************
40 * Reads a line from a text file into the buffer and trims trailing whitespace.
41 * Can handle DOS and Unix text files, including weird DOS EOF. Returns FALSE
42 * for unexpected I/O errors; otherwise returns TRUE and sets *p_result to
43 * either the number of characters in the returned string or one of the
46 * 0: Blank (or all whitespace) line. This is just a special case
47 * of the normal behavior.
49 * EOF: End of file has been reached.
51 * INT_MIN: Buffer overflow. Returned string is truncated (duh!) and
52 * trailing whitespace is *not* trimmed. Remaining text in
53 * line is discarded. (I.e. the file pointer is positioned at
54 * the beginning of the next line.)
57 static BOOL ReadLine(FILE *file, CHAR buffer[], INT bufsize, INT *p_result)
62 if (fgets(buffer, bufsize, file) == NULL)
64 if (feof(file) == 0) /* EOF or error? */
66 ERR("%s\n", strerror(errno));
74 cp = strchr(buffer, '\n');
79 if (i == bufsize - 1) /* max possible; was line truncated? */
82 i = fgetc(file); /* find the newline or EOF */
83 while (i != '\n' && i != EOF);
87 if (feof(file) == 0) /* EOF or error? */
89 ERR("%s\n", strerror(errno));
93 WARN("No newline at EOF\n");
99 else /* no newline and not truncated */
101 if (strcmp(buffer, "\x1a") == 0) /* test for DOS EOF */
107 WARN("No newline at EOF\n");
108 cp = buffer + i; /* points to \0 where \n should have been */
114 *cp = '\0'; /* trim trailing whitespace */
116 break; /* don't underflow buffer */
119 while (isspace(*cp));
121 *p_result = strlen(buffer);
125 /*******************************************************************************
128 * Finds a line in the file that begins with the given string. Returns FALSE
129 * for unexpected I/O errors; returns an empty (zero character) string if the
130 * requested line is not found.
132 * NOTE: The file pointer *MUST* be positioned at the beginning of a line when
133 * this function is called. Otherwise, an infinite loop can result.
136 static BOOL FindLine(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key)
138 INT len = strlen(key);
139 LONG start = ftell(file);
146 ok = ReadLine(file, buffer, bufsize, &result);
150 if (result > 0 && strncmp(buffer, key, len) == 0)
157 else if (result == INT_MIN)
159 WARN("Line beginning '%32s...' is too long; ignoring\n", buffer);
162 while (ftell(file) != start);
164 WARN("Couldn't find line '%s...' in AFM file\n", key);
169 /*******************************************************************************
172 * Utility function to convert double to float while checking for overflow.
173 * Will also catch strtod overflows, since HUGE_VAL > FLT_MAX (at least on
177 inline static BOOL DoubleToFloat(float *p_f, double d)
179 if (d > (double)FLT_MAX || d < -(double)FLT_MAX)
186 /*******************************************************************************
189 * Utility function to add or subtract 0.5 before converting to integer type.
192 inline static float Round(float f)
194 return (f >= 0.0) ? (f + 0.5) : (f - 0.5);
197 /*******************************************************************************
200 * Finds and parses a line of the form '<key> <value>', where value is a
201 * number. Sets *p_found to FALSE if a corresponding line cannot be found, or
202 * it cannot be parsed; also sets *p_ret to 0.0, so calling functions can just
203 * skip the check of *p_found if the item is not required.
206 static BOOL ReadFloat(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key,
207 FLOAT *p_ret, BOOL *p_found)
212 if (FindLine(file, buffer, bufsize, key) == FALSE)
215 if (buffer[0] == '\0') /* line not found */
222 cp = buffer + strlen(key); /* first char after key */
224 d = strtod(cp, &end_ptr);
226 if (end_ptr == cp || errno != 0 || DoubleToFloat(p_ret, d) == FALSE)
228 WARN("Error parsing line '%s'\n", buffer);
238 /*******************************************************************************
241 * See description of ReadFloat.
244 static BOOL ReadInt(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key,
245 INT *p_ret, BOOL *p_found)
250 retval = ReadFloat(file, buffer, bufsize, key, &f, p_found);
251 if (retval == FALSE || *p_found == FALSE)
259 if (f > (FLOAT)INT_MAX || f < (FLOAT)INT_MIN)
261 WARN("Error parsing line '%s'\n", buffer);
271 /*******************************************************************************
274 * Returns FALSE on I/O error or memory allocation failure; sets *p_str to NULL
275 * if line cannot be found or can't be parsed.
278 static BOOL ReadString(FILE *file, CHAR buffer[], INT bufsize, LPCSTR key,
283 if (FindLine(file, buffer, bufsize, key) == FALSE)
286 if (buffer[0] == '\0')
292 cp = buffer + strlen(key); /* first char after key */
299 while (isspace(*cp)) /* find first non-whitespace char */
302 *p_str = HeapAlloc(PSDRV_Heap, 0, strlen(cp) + 1);
310 /*******************************************************************************
313 * Similar to ReadFloat above.
316 static BOOL ReadBBox(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
322 if (FindLine(file, buffer, bufsize, "FontBBox") == FALSE)
325 if (buffer[0] == '\0')
333 cp = buffer + sizeof("FontBBox");
334 d = strtod(cp, &end_ptr);
335 if (end_ptr == cp || errno != 0 ||
336 DoubleToFloat(&(afm->FontBBox.llx), d) == FALSE)
340 d = strtod(cp, &end_ptr);
341 if (end_ptr == cp || errno != 0 ||
342 DoubleToFloat(&(afm->FontBBox.lly), d) == FALSE)
346 d = strtod(cp, &end_ptr);
347 if (end_ptr == cp || errno != 0
348 || DoubleToFloat(&(afm->FontBBox.urx), d) == FALSE)
352 d = strtod(cp, &end_ptr);
353 if (end_ptr == cp || errno != 0
354 || DoubleToFloat(&(afm->FontBBox.ury), d) == FALSE)
361 WARN("Error parsing line '%s'\n", buffer);
366 /*******************************************************************************
369 * Finds and parses the 'Weight' line of an AFM file. Only tries to determine
370 * if a font is bold (FW_BOLD) or not (FW_NORMAL) -- ignoring all those cute
371 * little FW_* typedefs in the Win32 doc. AFAICT, this is what the Windows
372 * PostScript driver does.
375 static const struct { LPCSTR keyword; INT weight; } afm_weights[] =
377 { "REGULAR", FW_NORMAL },
378 { "ROMAN", FW_NORMAL },
380 { "BOOK", FW_NORMAL },
381 { "MEDIUM", FW_NORMAL },
382 { "LIGHT", FW_NORMAL },
383 { "BLACK", FW_BOLD },
384 { "HEAVY", FW_BOLD },
386 { "ULTRA", FW_BOLD },
387 { "SUPER" , FW_BOLD },
391 static BOOL ReadWeight(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
398 if (ReadString(file, buffer, bufsize, "Weight", &sz) == FALSE)
407 for (cp = sz; *cp != '\0'; ++cp)
410 for (i = 0; afm_weights[i].keyword != NULL; ++i)
412 if (strstr(sz, afm_weights[i].keyword) != NULL)
414 afm->Weight = afm_weights[i].weight;
416 HeapFree(PSDRV_Heap, 0, sz);
421 WARN("Unknown weight '%s'; treating as Roman\n", sz);
423 afm->Weight = FW_NORMAL;
425 HeapFree(PSDRV_Heap, 0, sz);
429 /*******************************************************************************
433 static BOOL ReadFixedPitch(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
438 if (ReadString(file, buffer, bufsize, "IsFixedPitch", &sz) == FALSE)
447 if (strcasecmp(sz, "false") == 0)
449 afm->IsFixedPitch = FALSE;
451 HeapFree(PSDRV_Heap, 0, sz);
455 if (strcasecmp(sz, "true") == 0)
457 afm->IsFixedPitch = TRUE;
459 HeapFree(PSDRV_Heap, 0, sz);
463 WARN("Can't parse line '%s'\n", buffer);
466 HeapFree(PSDRV_Heap, 0, sz);
470 /*******************************************************************************
473 * Allocates space for the AFM on the driver heap and reads basic font metrics.
474 * Returns FALSE for memory allocation failure; sets *p_afm to NULL if AFM file
478 static BOOL ReadFontMetrics(FILE *file, CHAR buffer[], INT bufsize, AFM **p_afm)
483 *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
487 retval = ReadWeight(file, buffer, bufsize, afm, &found);
488 if (retval == FALSE || found == FALSE)
491 retval = ReadFloat(file, buffer, bufsize, "ItalicAngle",
492 &(afm->ItalicAngle), &found);
493 if (retval == FALSE || found == FALSE)
496 retval = ReadFixedPitch(file, buffer, bufsize, afm, &found);
497 if (retval == FALSE || found == FALSE)
500 retval = ReadBBox(file, buffer, bufsize, afm, &found);
501 if (retval == FALSE || found == FALSE)
504 retval = ReadFloat(file, buffer, bufsize, "UnderlinePosition",
505 &(afm->UnderlinePosition), &found);
506 if (retval == FALSE || found == FALSE)
509 retval = ReadFloat(file, buffer, bufsize, "UnderlineThickness",
510 &(afm->UnderlineThickness), &found);
511 if (retval == FALSE || found == FALSE)
514 retval = ReadFloat(file, buffer, bufsize, "Ascender", /* optional */
515 &(afm->Ascender), &found);
519 retval = ReadFloat(file, buffer, bufsize, "Descender", /* optional */
520 &(afm->Descender), &found);
524 afm->WinMetrics.usUnitsPerEm = 1000;
525 afm->WinMetrics.sTypoAscender = (SHORT)Round(afm->Ascender);
526 afm->WinMetrics.sTypoDescender = (SHORT)Round(afm->Descender);
528 if (afm->WinMetrics.sTypoAscender == 0)
529 afm->WinMetrics.sTypoAscender = (SHORT)Round(afm->FontBBox.ury);
531 if (afm->WinMetrics.sTypoDescender == 0)
532 afm->WinMetrics.sTypoDescender = (SHORT)Round(afm->FontBBox.lly);
534 afm->WinMetrics.sTypoLineGap = 1200 -
535 (afm->WinMetrics.sTypoAscender - afm->WinMetrics.sTypoDescender);
536 if (afm->WinMetrics.sTypoLineGap < 0)
537 afm->WinMetrics.sTypoLineGap = 0;
541 cleanup_afm: /* handle fatal or non-fatal errors */
542 HeapFree(PSDRV_Heap, 0, afm);
547 /*******************************************************************************
550 * Fatal error: return FALSE (none defined)
552 * Non-fatal error: leave metrics->C set to INT_MAX
555 static BOOL ParseC(LPSTR sz, OLD_AFMMETRICS *metrics)
570 l = strtol(cp, &end_ptr, base);
571 if (end_ptr == cp || errno != 0 || l > INT_MAX || l < INT_MIN)
573 WARN("Error parsing character code '%s'\n", sz);
581 /*******************************************************************************
584 * Fatal error: return FALSE (none defined)
586 * Non-fatal error: leave metrics->WX set to FLT_MAX
589 static BOOL ParseW(LPSTR sz, OLD_AFMMETRICS *metrics)
610 d = strtod(cp, &end_ptr);
611 if (end_ptr == cp || errno != 0 ||
612 DoubleToFloat(&(metrics->WX), d) == FALSE)
618 /* Make sure that Y component of vector is zero */
620 d = strtod(cp, &end_ptr); /* errno == 0 */
621 if (end_ptr == cp || errno != 0 || d != 0.0)
623 metrics->WX = FLT_MAX;
630 WARN("Error parsing character width '%s'\n", sz);
634 /*******************************************************************************
638 * Fatal error: return FALSE (none defined)
640 * Non-fatal error: leave metrics->B.ury set to FLT_MAX
643 static BOOL ParseB(LPSTR sz, OLD_AFMMETRICS *metrics)
651 d = strtod(cp, &end_ptr);
652 if (end_ptr == cp || errno != 0 ||
653 DoubleToFloat(&(metrics->B.llx), d) == FALSE)
657 d = strtod(cp, &end_ptr);
658 if (end_ptr == cp || errno != 0 ||
659 DoubleToFloat(&(metrics->B.lly), d) == FALSE)
663 d = strtod(cp, &end_ptr);
664 if (end_ptr == cp || errno != 0 ||
665 DoubleToFloat(&(metrics->B.urx), d) == FALSE)
669 d = strtod(cp, &end_ptr);
670 if (end_ptr == cp || errno != 0 ||
671 DoubleToFloat(&(metrics->B.ury), d) == FALSE)
677 WARN("Error parsing glyph bounding box '%s'\n", sz);
681 /*******************************************************************************
684 * Fatal error: return FALSE (PSDRV_GlyphName failure)
686 * Non-fatal error: leave metrics-> set to NULL
689 static BOOL ParseN(LPSTR sz, OLD_AFMMETRICS *metrics)
691 CHAR save, *cp, *end_ptr;
700 while (*end_ptr != '\0' && !isspace(*end_ptr))
705 WARN("Error parsing glyph name '%s'\n", sz);
712 metrics->N = PSDRV_GlyphName(cp);
713 if (metrics->N == NULL)
720 /*******************************************************************************
723 * Parses the metrics line for a single glyph in an AFM file. Returns FALSE on
724 * fatal error; sets *metrics to 'badmetrics' on non-fatal error.
727 static const OLD_AFMMETRICS badmetrics =
733 { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }, /* B */
737 static BOOL ParseCharMetrics(LPSTR buffer, INT len, OLD_AFMMETRICS *metrics)
741 *metrics = badmetrics;
750 case 'C': if (ParseC(cp, metrics) == FALSE)
754 case 'W': if (ParseW(cp, metrics) == FALSE)
758 case 'N': if (ParseN(cp, metrics) == FALSE)
762 case 'B': if (ParseB(cp, metrics) == FALSE)
767 cp = strchr(cp, ';');
770 WARN("No terminating semicolon\n");
777 if (metrics->C == INT_MAX || metrics->WX == FLT_MAX || metrics->N == NULL ||
778 metrics->B.ury == FLT_MAX)
780 *metrics = badmetrics;
787 /*******************************************************************************
790 * Checks whether Unicode value is part of Microsoft code page 1252
793 static const LONG ansiChars[21] =
795 0x0152, 0x0153, 0x0160, 0x0161, 0x0178, 0x017d, 0x017e, 0x0192, 0x02c6,
796 0x02c9, 0x02dc, 0x03bc, 0x2013, 0x2014, 0x2026, 0x2030, 0x2039, 0x203a,
797 0x20ac, 0x2122, 0x2219
800 static int cmpUV(const void *a, const void *b)
802 return (int)(*((const LONG *)a) - *((const LONG *)b));
805 inline static BOOL IsWinANSI(LONG uv)
807 if ((0x0020 <= uv && uv <= 0x007e) || (0x00a0 <= uv && uv <= 0x00ff) ||
808 (0x2018 <= uv && uv <= 0x201a) || (0x201c <= uv && uv <= 0x201e) ||
809 (0x2020 <= uv && uv <= 0x2022))
812 if (bsearch(&uv, ansiChars, 21, sizeof(INT), cmpUV) != NULL)
818 /*******************************************************************************
821 * Determines Unicode value (UV) for each glyph, based on font encoding.
823 * FontSpecific: Usable encodings (0x20 - 0xff) are mapped into the
824 * Unicode private use range U+F020 - U+F0FF.
826 * other: UV determined by glyph name, based on Adobe Glyph List.
828 * Also does some font metric calculations that require UVs to be known.
831 static int UnicodeGlyphByNameIndex(const void *a, const void *b)
833 return ((const UNICODEGLYPH *)a)->name->index -
834 ((const UNICODEGLYPH *)b)->name->index;
837 static VOID Unicodify(AFM *afm, OLD_AFMMETRICS *metrics)
841 if (strcmp(afm->EncodingScheme, "FontSpecific") == 0)
843 for (i = 0; i < afm->NumofMetrics; ++i)
845 if (metrics[i].C >= 0x20 && metrics[i].C <= 0xff)
847 metrics[i].UV = ((LONG)(metrics[i].C)) | 0xf000L;
851 TRACE("Unencoded glyph '%s'\n", metrics[i].N->sz);
856 afm->WinMetrics.sAscender = (SHORT)Round(afm->FontBBox.ury);
857 afm->WinMetrics.sDescender = (SHORT)Round(afm->FontBBox.lly);
859 else /* non-FontSpecific encoding */
861 UNICODEGLYPH ug, *p_ug;
863 PSDRV_IndexGlyphList(); /* for fast searching of glyph names */
865 afm->WinMetrics.sAscender = afm->WinMetrics.sDescender = 0;
867 for (i = 0; i < afm->NumofMetrics; ++i)
869 ug.name = metrics[i].N;
870 p_ug = bsearch(&ug, PSDRV_AGLbyName, PSDRV_AGLbyNameSize,
871 sizeof(ug), UnicodeGlyphByNameIndex);
874 TRACE("Glyph '%s' not in Adobe Glyph List\n", ug.name->sz);
879 metrics[i].UV = p_ug->UV;
881 if (IsWinANSI(p_ug->UV))
883 SHORT ury = (SHORT)Round(metrics[i].B.ury);
884 SHORT lly = (SHORT)Round(metrics[i].B.lly);
886 if (ury > afm->WinMetrics.sAscender)
887 afm->WinMetrics.sAscender = ury;
888 if (lly < afm->WinMetrics.sDescender)
889 afm->WinMetrics.sDescender = lly;
894 if (afm->WinMetrics.sAscender == 0)
895 afm->WinMetrics.sAscender = (SHORT)Round(afm->FontBBox.ury);
896 if (afm->WinMetrics.sDescender == 0)
897 afm->WinMetrics.sDescender = (SHORT)Round(afm->FontBBox.lly);
900 afm->WinMetrics.sLineGap =
901 1150 - (afm->WinMetrics.sAscender - afm->WinMetrics.sDescender);
902 if (afm->WinMetrics.sLineGap < 0)
903 afm->WinMetrics.sLineGap = 0;
905 afm->WinMetrics.usWinAscent = (afm->WinMetrics.sAscender > 0) ?
906 afm->WinMetrics.sAscender : 0;
907 afm->WinMetrics.usWinDescent = (afm->WinMetrics.sDescender < 0) ?
908 -(afm->WinMetrics.sDescender) : 0;
911 /*******************************************************************************
914 * Reads metrics for all glyphs. *p_metrics will be NULL on non-fatal error.
917 static int OldAFMMetricsByUV(const void *a, const void *b)
919 return ((const OLD_AFMMETRICS *)a)->UV - ((const OLD_AFMMETRICS *)b)->UV;
922 static BOOL ReadCharMetrics(FILE *file, CHAR buffer[], INT bufsize, AFM *afm,
923 AFMMETRICS **p_metrics)
926 OLD_AFMMETRICS *old_metrics, *encoded_metrics;
930 retval = ReadInt(file, buffer, bufsize, "StartCharMetrics",
931 &(afm->NumofMetrics), &found);
932 if (retval == FALSE || found == FALSE)
938 old_metrics = HeapAlloc(PSDRV_Heap, 0,
939 afm->NumofMetrics * sizeof(*old_metrics));
940 if (old_metrics == NULL)
943 for (i = 0; i < afm->NumofMetrics; ++i)
945 retval = ReadLine(file, buffer, bufsize, &len);
947 goto cleanup_old_metrics;
951 retval = ParseCharMetrics(buffer, len, old_metrics + i);
952 if (retval == FALSE || old_metrics[i].C == INT_MAX)
953 goto cleanup_old_metrics;
963 case INT_MIN: WARN("Ignoring long line '%32s...'\n", buffer);
964 goto cleanup_old_metrics; /* retval == TRUE */
966 case EOF: WARN("Unexpected EOF\n");
967 goto cleanup_old_metrics; /* retval == TRUE */
971 Unicodify(afm, old_metrics); /* wait until glyph names have been read */
973 qsort(old_metrics, afm->NumofMetrics, sizeof(*old_metrics),
976 for (i = 0; old_metrics[i].UV == -1; ++i); /* count unencoded glyphs */
978 afm->NumofMetrics -= i;
979 encoded_metrics = old_metrics + i;
981 afm->Metrics = *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0,
982 afm->NumofMetrics * sizeof(*metrics));
983 if (afm->Metrics == NULL)
984 goto cleanup_old_metrics; /* retval == TRUE */
986 for (i = 0; i < afm->NumofMetrics; ++i, ++metrics, ++encoded_metrics)
988 metrics->C = encoded_metrics->C;
989 metrics->UV = encoded_metrics->UV;
990 metrics->WX = encoded_metrics->WX;
991 metrics->N = encoded_metrics->N;
994 HeapFree(PSDRV_Heap, 0, old_metrics);
996 afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
1000 cleanup_old_metrics: /* handle fatal or non-fatal errors */
1001 HeapFree(PSDRV_Heap, 0, old_metrics);
1006 /*******************************************************************************
1009 * Builds the AFM for a PostScript font and adds it to the driver font list.
1010 * Returns FALSE only on an unexpected error (memory allocation or I/O error).
1013 static BOOL BuildAFM(FILE *file)
1015 CHAR buffer[258]; /* allow for <cr>, <lf>, and <nul> */
1017 AFMMETRICS *metrics;
1018 LPSTR font_name, full_name, family_name, encoding_scheme;
1021 retval = ReadFontMetrics(file, buffer, sizeof(buffer), &afm);
1022 if (retval == FALSE || afm == NULL)
1025 retval = ReadString(file, buffer, sizeof(buffer), "FontName", &font_name);
1026 if (retval == FALSE || font_name == NULL)
1029 retval = ReadString(file, buffer, sizeof(buffer), "FullName", &full_name);
1030 if (retval == FALSE || full_name == NULL)
1031 goto cleanup_font_name;
1033 retval = ReadString(file, buffer, sizeof(buffer), "FamilyName",
1035 if (retval == FALSE || family_name == NULL)
1036 goto cleanup_full_name;
1038 retval = ReadString(file, buffer, sizeof(buffer), "EncodingScheme",
1040 if (retval == FALSE || encoding_scheme == NULL)
1041 goto cleanup_family_name;
1043 afm->FontName = font_name;
1044 afm->FullName = full_name;
1045 afm->FamilyName = family_name;
1046 afm->EncodingScheme = encoding_scheme;
1048 retval = ReadCharMetrics(file, buffer, sizeof(buffer), afm, &metrics);
1049 if (retval == FALSE || metrics == FALSE)
1050 goto cleanup_encoding_scheme;
1052 retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
1053 if (retval == FALSE || added == FALSE)
1054 goto cleanup_encoding_scheme;
1058 /* clean up after fatal or non-fatal errors */
1060 cleanup_encoding_scheme:
1061 HeapFree(PSDRV_Heap, 0, encoding_scheme);
1062 cleanup_family_name:
1063 HeapFree(PSDRV_Heap, 0, family_name);
1065 HeapFree(PSDRV_Heap, 0, full_name);
1067 HeapFree(PSDRV_Heap, 0, font_name);
1069 HeapFree(PSDRV_Heap, 0, afm);
1074 /*******************************************************************************
1077 * Reads font metrics from Type 1 AFM file. Only returns FALSE for
1078 * unexpected errors (memory allocation or I/O).
1081 static BOOL ReadAFMFile(LPCSTR filename)
1086 TRACE("%s\n", filename);
1088 f = fopen(filename, "r");
1091 WARN("%s: %s\n", filename, strerror(errno));
1095 retval = BuildAFM(f);
1101 /*******************************************************************************
1104 * Reads all Type 1 AFM files in a directory.
1107 static BOOL ReadAFMDir(LPCSTR dirname)
1109 struct dirent *dent;
1113 dir = opendir(dirname);
1116 WARN("%s: %s\n", dirname, strerror(errno));
1120 while ((dent = readdir(dir)) != NULL)
1122 CHAR *file_extension = strchr(dent->d_name, '.');
1125 if (file_extension == NULL || strcasecmp(file_extension, ".afm") != 0)
1128 fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
1129 if (fn_len < 0 || fn_len > sizeof(filename) - 1)
1131 WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
1135 if (ReadAFMFile(filename) == FALSE)
1146 /*******************************************************************************
1147 * PSDRV_GetType1Metrics
1149 * Reads font metrics from Type 1 AFM font files in directories listed in the
1150 * [afmdirs] section of the Wine configuration file.
1152 * If this function fails (returns FALSE), the dirver will fail to initialize
1153 * and the driver heap will be destroyed, so it's not necessary to HeapFree
1154 * everything in that event.
1157 BOOL PSDRV_GetType1Metrics(void)
1159 CHAR name_buf[256], value_buf[256];
1162 DWORD type, name_len, value_len;
1164 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1165 "Software\\Wine\\Wine\\Config\\afmdirs",
1166 0, KEY_READ, &hkey) != ERROR_SUCCESS)
1169 name_len = sizeof(name_buf);
1170 value_len = sizeof(value_buf);
1172 while (RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
1173 &value_len) == ERROR_SUCCESS)
1175 value_buf[sizeof(value_buf) - 1] = '\0';
1177 if (ReadAFMDir(value_buf) == FALSE)
1183 /* initialize lengths for new iteration */
1185 name_len = sizeof(name_buf);
1186 value_len = sizeof(value_buf);