• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkFontConfigParser_android.h"
9 #include "SkFontMgr_android.h"
10 #include "SkStream.h"
11 #include "SkTDArray.h"
12 #include "SkTSearch.h"
13 #include "SkTypeface.h"
14 
15 #include <expat.h>
16 #include <dirent.h>
17 #include <stdio.h>
18 
19 #include <limits>
20 #include <stdlib.h>
21 
22 #define LMP_SYSTEM_FONTS_FILE "/system/etc/fonts.xml"
23 #define OLD_SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
24 #define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
25 #define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
26 
27 #define LOCALE_FALLBACK_FONTS_SYSTEM_DIR "/system/etc"
28 #define LOCALE_FALLBACK_FONTS_VENDOR_DIR "/vendor/etc"
29 #define LOCALE_FALLBACK_FONTS_PREFIX "fallback_fonts-"
30 #define LOCALE_FALLBACK_FONTS_SUFFIX ".xml"
31 
32 #ifndef SK_FONT_FILE_PREFIX
33 #    define SK_FONT_FILE_PREFIX "/fonts/"
34 #endif
35 
36 /**
37  * This file contains TWO 'familyset' handlers:
38  * One for JB and earlier which works with
39  *   /system/etc/system_fonts.xml
40  *   /system/etc/fallback_fonts.xml
41  *   /vendor/etc/fallback_fonts.xml
42  *   /system/etc/fallback_fonts-XX.xml
43  *   /vendor/etc/fallback_fonts-XX.xml
44  * and the other for LMP and later which works with
45  *   /system/etc/fonts.xml
46  *
47  * If the 'familyset' 'version' attribute is 21 or higher the LMP parser is used, otherwise the JB.
48  */
49 
50 struct FamilyData;
51 
52 struct TagHandler {
53     /** Called at the start tag.
54      *  Called immediately after the parent tag retuns this handler from a call to 'tag'.
55      *  Allows setting up for handling the tag content and processing attributes.
56      *  If NULL, will not be called.
57      */
58     void (*start)(FamilyData* data, const char* tag, const char** attributes);
59 
60     /** Called at the end tag.
61      *  Allows post-processing of any accumulated information.
62      *  This will be the last call made in relation to the current tag.
63      *  If NULL, will not be called.
64      */
65     void (*end)(FamilyData* data, const char* tag);
66 
67     /** Called when a nested tag is encountered.
68      *  This is responsible for determining how to handle the tag.
69      *  If the tag is not recognized, return NULL to skip the tag.
70      *  If NULL, all nested tags will be skipped.
71      */
72     const TagHandler* (*tag)(FamilyData* data, const char* tag, const char** attributes);
73 
74     /** The character handler for this tag.
75      *  This is only active for character data contained directly in this tag (not sub-tags).
76      *  The first parameter will be castable to a FamilyData*.
77      *  If NULL, any character data in this tag will be ignored.
78      */
79     XML_CharacterDataHandler chars;
80 };
81 
82 /** Represents the current parsing state. */
83 struct FamilyData {
FamilyDataFamilyData84     FamilyData(XML_Parser parser, SkTDArray<FontFamily*>& families,
85                const SkString& basePath, bool isFallback, const char* filename,
86                const TagHandler* topLevelHandler)
87         : fParser(parser)
88         , fFamilies(families)
89         , fCurrentFamily(NULL)
90         , fCurrentFontInfo(NULL)
91         , fVersion(0)
92         , fBasePath(basePath)
93         , fIsFallback(isFallback)
94         , fFilename(filename)
95         , fDepth(1)
96         , fSkip(0)
97         , fHandler(&topLevelHandler, 1)
98     { };
99 
100     XML_Parser fParser;                       // The expat parser doing the work, owned by caller
101     SkTDArray<FontFamily*>& fFamilies;        // The array to append families, owned by caller
102     SkAutoTDelete<FontFamily> fCurrentFamily; // The family being created, owned by this
103     FontFileInfo* fCurrentFontInfo;           // The fontInfo being created, owned by fCurrentFamily
104     int fVersion;                             // The version of the file parsed.
105     const SkString& fBasePath;                // The current base path.
106     const bool fIsFallback;                   // Indicates the file being parsed is a fallback file
107     const char* fFilename;                    // The name of the file currently being parsed.
108 
109     int fDepth;                               // The current element depth of the parse.
110     int fSkip;                                // The depth to stop skipping, 0 if not skipping.
111     SkTDArray<const TagHandler*> fHandler;    // The stack of current tag handlers.
112 };
113 
114 /** Parses a null terminated string into an integer type, checking for overflow.
115  *  http://www.w3.org/TR/html-markup/datatypes.html#common.data.integer.non-negative-def
116  *
117  *  If the string cannot be parsed into 'value', returns false and does not change 'value'.
118  */
parse_non_negative_integer(const char * s,T * value)119 template <typename T> static bool parse_non_negative_integer(const char* s, T* value) {
120     SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, T_must_be_integer);
121     const T nMax = std::numeric_limits<T>::max() / 10;
122     const T dMax = std::numeric_limits<T>::max() - (nMax * 10);
123     T n = 0;
124     for (; *s; ++s) {
125         // Check if digit
126         if (*s < '0' || '9' < *s) {
127             return false;
128         }
129         int d = *s - '0';
130         // Check for overflow
131         if (n > nMax || (n == nMax && d > dMax)) {
132             return false;
133         }
134         n = (n * 10) + d;
135     }
136     *value = n;
137     return true;
138 }
139 
memeq(const char * s1,const char * s2,size_t n1,size_t n2)140 static bool memeq(const char* s1, const char* s2, size_t n1, size_t n2) {
141     return n1 == n2 && 0 == memcmp(s1, s2, n1);
142 }
143 #define MEMEQ(c, s, n) memeq(c, s, sizeof(c) - 1, n)
144 
145 #define ATTS_NON_NULL(a, i) (a[i] != NULL && a[i+1] != NULL)
146 
147 #define SK_FONTCONFIGPARSER_PREFIX "[SkFontConfigParser] "
148 
149 #define SK_FONTCONFIGPARSER_WARNING(message, ...) SkDebugf( \
150     SK_FONTCONFIGPARSER_PREFIX "%s:%d:%d: warning: " message "\n", \
151     self->fFilename, \
152     XML_GetCurrentLineNumber(self->fParser), \
153     XML_GetCurrentColumnNumber(self->fParser), \
154     ##__VA_ARGS__);
155 
is_whitespace(char c)156 static bool is_whitespace(char c) {
157     return c == ' ' || c == '\n'|| c == '\r' || c == '\t';
158 }
159 
trim_string(SkString * s)160 static void trim_string(SkString* s) {
161     char* str = s->writable_str();
162     const char* start = str;  // start is inclusive
163     const char* end = start + s->size();  // end is exclusive
164     while (is_whitespace(*start)) { ++start; }
165     if (start != end) {
166         --end;  // make end inclusive
167         while (is_whitespace(*end)) { --end; }
168         ++end;  // make end exclusive
169     }
170     size_t len = end - start;
171     memmove(str, start, len);
172     s->resize(len);
173 }
174 
175 namespace lmpParser {
176 
177 static const TagHandler fontHandler = {
__anona6e2ef2f0102() 178     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
179         // 'weight' (non-negative integer) [default 0]
180         // 'style' ("normal", "italic") [default "auto"]
181         // 'index' (non-negative integer) [default 0]
182         // The character data should be a filename.
183         FontFileInfo& file = self->fCurrentFamily->fFonts.push_back();
184         self->fCurrentFontInfo = &file;
185         for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
186             const char* name = attributes[i];
187             const char* value = attributes[i+1];
188             size_t nameLen = strlen(name);
189             if (MEMEQ("weight", name, nameLen)) {
190                 if (!parse_non_negative_integer(value, &file.fWeight)) {
191                     SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
192                 }
193             } else if (MEMEQ("style", name, nameLen)) {
194                 size_t valueLen = strlen(value);
195                 if (MEMEQ("normal", value, valueLen)) {
196                     file.fStyle = FontFileInfo::Style::kNormal;
197                 } else if (MEMEQ("italic", value, valueLen)) {
198                     file.fStyle = FontFileInfo::Style::kItalic;
199                 }
200             } else if (MEMEQ("index", name, nameLen)) {
201                 if (!parse_non_negative_integer(value, &file.fIndex)) {
202                     SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
203                 }
204             }
205         }
206     },
__anona6e2ef2f0202() 207     /*end*/[](FamilyData* self, const char* tag) {
208         trim_string(&self->fCurrentFontInfo->fFileName);
209     },
210     /*tag*/NULL,
__anona6e2ef2f0302() 211     /*chars*/[](void* data, const char* s, int len) {
212         FamilyData* self = static_cast<FamilyData*>(data);
213         self->fCurrentFontInfo->fFileName.append(s, len);
214     }
215 };
216 
217 static const TagHandler familyHandler = {
__anona6e2ef2f0402() 218     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
219         // 'name' (string) [optional]
220         // 'lang' (string) [default ""]
221         // 'variant' ("elegant", "compact") [default "default"]
222         // If there is no name, this is a fallback only font.
223         FontFamily* family = new FontFamily(self->fBasePath, true);
224         self->fCurrentFamily.reset(family);
225         for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
226             const char* name = attributes[i];
227             const char* value = attributes[i+1];
228             size_t nameLen = strlen(name);
229             size_t valueLen = strlen(value);
230             if (MEMEQ("name", name, nameLen)) {
231                 SkAutoAsciiToLC tolc(value);
232                 family->fNames.push_back().set(tolc.lc());
233                 family->fIsFallbackFont = false;
234             } else if (MEMEQ("lang", name, nameLen)) {
235                 family->fLanguage = SkLanguage(value, valueLen);
236             } else if (MEMEQ("variant", name, nameLen)) {
237                 if (MEMEQ("elegant", value, valueLen)) {
238                     family->fVariant = kElegant_FontVariant;
239                 } else if (MEMEQ("compact", value, valueLen)) {
240                     family->fVariant = kCompact_FontVariant;
241                 }
242             }
243         }
244     },
__anona6e2ef2f0502() 245     /*end*/[](FamilyData* self, const char* tag) {
246         *self->fFamilies.append() = self->fCurrentFamily.detach();
247     },
__anona6e2ef2f0602() 248     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
249         size_t len = strlen(tag);
250         if (MEMEQ("font", tag, len)) {
251             return &fontHandler;
252         }
253         return NULL;
254     },
255     /*chars*/NULL,
256 };
257 
find_family(FamilyData * self,const SkString & familyName)258 static FontFamily* find_family(FamilyData* self, const SkString& familyName) {
259     for (int i = 0; i < self->fFamilies.count(); i++) {
260         FontFamily* candidate = self->fFamilies[i];
261         for (int j = 0; j < candidate->fNames.count(); j++) {
262             if (candidate->fNames[j] == familyName) {
263                 return candidate;
264             }
265         }
266     }
267     return NULL;
268 }
269 
270 static const TagHandler aliasHandler = {
__anona6e2ef2f0702() 271     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
272         // 'name' (string) introduces a new family name.
273         // 'to' (string) specifies which (previous) family to alias
274         // 'weight' (non-negative integer) [optional]
275         // If it *does not* have a weight, 'name' is an alias for the entire 'to' family.
276         // If it *does* have a weight, 'name' is a new family consisting of
277         // the font(s) with 'weight' from the 'to' family.
278 
279         SkString aliasName;
280         SkString to;
281         int weight = 0;
282         for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
283             const char* name = attributes[i];
284             const char* value = attributes[i+1];
285             size_t nameLen = strlen(name);
286             if (MEMEQ("name", name, nameLen)) {
287                 SkAutoAsciiToLC tolc(value);
288                 aliasName.set(tolc.lc());
289             } else if (MEMEQ("to", name, nameLen)) {
290                 to.set(value);
291             } else if (MEMEQ("weight", name, nameLen)) {
292                 if (!parse_non_negative_integer(value, &weight)) {
293                     SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid weight", value);
294                 }
295             }
296         }
297 
298         // Assumes that the named family is already declared
299         FontFamily* targetFamily = find_family(self, to);
300         if (!targetFamily) {
301             SK_FONTCONFIGPARSER_WARNING("'%s' alias target not found", to.c_str());
302             return;
303         }
304 
305         if (weight) {
306             FontFamily* family = new FontFamily(targetFamily->fBasePath, self->fIsFallback);
307             family->fNames.push_back().set(aliasName);
308 
309             for (int i = 0; i < targetFamily->fFonts.count(); i++) {
310                 if (targetFamily->fFonts[i].fWeight == weight) {
311                     family->fFonts.push_back(targetFamily->fFonts[i]);
312                 }
313             }
314             *self->fFamilies.append() = family;
315         } else {
316             targetFamily->fNames.push_back().set(aliasName);
317         }
318     },
319     /*end*/NULL,
320     /*tag*/NULL,
321     /*chars*/NULL,
322 };
323 
324 static const TagHandler familySetHandler = {
__anona6e2ef2f0802() 325     /*start*/[](FamilyData* self, const char* tag, const char** attributes) { },
326     /*end*/NULL,
__anona6e2ef2f0902() 327     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
328         size_t len = strlen(tag);
329         if (MEMEQ("family", tag, len)) {
330             return &familyHandler;
331         } else if (MEMEQ("alias", tag, len)) {
332             return &aliasHandler;
333         }
334         return NULL;
335     },
336     /*chars*/NULL,
337 };
338 
339 } // lmpParser
340 
341 namespace jbParser {
342 
343 static const TagHandler fileHandler = {
__anona6e2ef2f0a02() 344     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
345         // 'variant' ("elegant", "compact") [default "default"]
346         // 'lang' (string) [default ""]
347         // 'index' (non-negative integer) [default 0]
348         // The character data should be a filename.
349         FontFamily& currentFamily = *self->fCurrentFamily.get();
350         FontFileInfo& newFileInfo = currentFamily.fFonts.push_back();
351         if (attributes) {
352             for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
353                 const char* name = attributes[i];
354                 const char* value = attributes[i+1];
355                 size_t nameLen = strlen(name);
356                 size_t valueLen = strlen(value);
357                 if (MEMEQ("variant", name, nameLen)) {
358                     const FontVariant prevVariant = currentFamily.fVariant;
359                     if (MEMEQ("elegant", value, valueLen)) {
360                         currentFamily.fVariant = kElegant_FontVariant;
361                     } else if (MEMEQ("compact", value, valueLen)) {
362                         currentFamily.fVariant = kCompact_FontVariant;
363                     }
364                     if (currentFamily.fFonts.count() > 1 && currentFamily.fVariant != prevVariant) {
365                         SK_FONTCONFIGPARSER_WARNING("'%s' unexpected variant found\n"
366                             "Note: Every font file within a family must have identical variants.",
367                             value);
368                     }
369 
370                 } else if (MEMEQ("lang", name, nameLen)) {
371                     SkLanguage prevLang = currentFamily.fLanguage;
372                     currentFamily.fLanguage = SkLanguage(value, valueLen);
373                     if (currentFamily.fFonts.count() > 1 && currentFamily.fLanguage != prevLang) {
374                         SK_FONTCONFIGPARSER_WARNING("'%s' unexpected language found\n"
375                             "Note: Every font file within a family must have identical languages.",
376                             value);
377                     }
378 
379                 } else if (MEMEQ("index", name, nameLen)) {
380                     if (!parse_non_negative_integer(value, &newFileInfo.fIndex)) {
381                         SK_FONTCONFIGPARSER_WARNING("'%s' is an invalid index", value);
382                     }
383                 }
384             }
385         }
386         self->fCurrentFontInfo = &newFileInfo;
387     },
388     /*end*/NULL,
389     /*tag*/NULL,
__anona6e2ef2f0b02() 390     /*chars*/[](void* data, const char* s, int len) {
391         FamilyData* self = static_cast<FamilyData*>(data);
392         self->fCurrentFontInfo->fFileName.append(s, len);
393     }
394 };
395 
396 static const TagHandler fileSetHandler = {
397     /*start*/NULL,
398     /*end*/NULL,
__anona6e2ef2f0c02() 399     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
400         size_t len = strlen(tag);
401         if (MEMEQ("file", tag, len)) {
402             return &fileHandler;
403         }
404         return NULL;
405     },
406     /*chars*/NULL,
407 };
408 
409 static const TagHandler nameHandler = {
__anona6e2ef2f0d02() 410     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
411         // The character data should be a name for the font.
412         self->fCurrentFamily->fNames.push_back();
413     },
414     /*end*/NULL,
415     /*tag*/NULL,
__anona6e2ef2f0e02() 416     /*chars*/[](void* data, const char* s, int len) {
417         FamilyData* self = static_cast<FamilyData*>(data);
418         SkAutoAsciiToLC tolc(s, len);
419         self->fCurrentFamily->fNames.back().append(tolc.lc(), len);
420     }
421 };
422 
423 static const TagHandler nameSetHandler = {
424     /*start*/NULL,
425     /*end*/NULL,
__anona6e2ef2f0f02() 426     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
427         size_t len = strlen(tag);
428         if (MEMEQ("name", tag, len)) {
429             return &nameHandler;
430         }
431         return NULL;
432     },
433     /*chars*/NULL,
434 };
435 
436 static const TagHandler familyHandler = {
__anona6e2ef2f1002() 437     /*start*/[](FamilyData* self, const char* tag, const char** attributes) {
438         self->fCurrentFamily.reset(new FontFamily(self->fBasePath, self->fIsFallback));
439         // 'order' (non-negative integer) [default -1]
440         for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
441             const char* value = attributes[i+1];
442             parse_non_negative_integer(value, &self->fCurrentFamily->fOrder);
443         }
444     },
__anona6e2ef2f1102() 445     /*end*/[](FamilyData* self, const char* tag) {
446         *self->fFamilies.append() = self->fCurrentFamily.detach();
447     },
__anona6e2ef2f1202() 448     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
449         size_t len = strlen(tag);
450         if (MEMEQ("nameset", tag, len)) {
451             return &nameSetHandler;
452         } else if (MEMEQ("fileset", tag, len)) {
453             return &fileSetHandler;
454         }
455         return NULL;
456     },
457     /*chars*/NULL,
458 };
459 
460 static const TagHandler familySetHandler = {
461     /*start*/NULL,
462     /*end*/NULL,
__anona6e2ef2f1302() 463     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
464         size_t len = strlen(tag);
465         if (MEMEQ("family", tag, len)) {
466             return &familyHandler;
467         }
468         return NULL;
469     },
470     /*chars*/NULL,
471 };
472 
473 } // namespace jbParser
474 
475 static const TagHandler topLevelHandler = {
476     /*start*/NULL,
477     /*end*/NULL,
__anona6e2ef2f1402() 478     /*tag*/[](FamilyData* self, const char* tag, const char** attributes) -> const TagHandler* {
479         size_t len = strlen(tag);
480         if (MEMEQ("familyset", tag, len)) {
481             // 'version' (non-negative integer) [default 0]
482             for (size_t i = 0; ATTS_NON_NULL(attributes, i); i += 2) {
483                 const char* name = attributes[i];
484                 size_t nameLen = strlen(name);
485                 if (MEMEQ("version", name, nameLen)) {
486                     const char* value = attributes[i+1];
487                     if (parse_non_negative_integer(value, &self->fVersion)) {
488                         if (self->fVersion >= 21) {
489                             return &lmpParser::familySetHandler;
490                         }
491                     }
492                 }
493             }
494             return &jbParser::familySetHandler;
495         }
496         return NULL;
497     },
498     /*chars*/NULL,
499 };
500 
start_element_handler(void * data,const char * tag,const char ** attributes)501 static void XMLCALL start_element_handler(void *data, const char *tag, const char **attributes) {
502     FamilyData* self = static_cast<FamilyData*>(data);
503 
504     if (!self->fSkip) {
505         const TagHandler* parent = self->fHandler.top();
506         const TagHandler* child = parent->tag ? parent->tag(self, tag, attributes) : NULL;
507         if (child) {
508             if (child->start) {
509                 child->start(self, tag, attributes);
510             }
511             self->fHandler.push(child);
512             XML_SetCharacterDataHandler(self->fParser, child->chars);
513         } else {
514             SK_FONTCONFIGPARSER_WARNING("'%s' tag not recognized, skipping", tag);
515             XML_SetCharacterDataHandler(self->fParser, NULL);
516             self->fSkip = self->fDepth;
517         }
518     }
519 
520     ++self->fDepth;
521 }
522 
end_element_handler(void * data,const char * tag)523 static void XMLCALL end_element_handler(void* data, const char* tag) {
524     FamilyData* self = static_cast<FamilyData*>(data);
525     --self->fDepth;
526 
527     if (!self->fSkip) {
528         const TagHandler* child = self->fHandler.top();
529         if (child->end) {
530             child->end(self, tag);
531         }
532         self->fHandler.pop();
533         const TagHandler* parent = self->fHandler.top();
534         XML_SetCharacterDataHandler(self->fParser, parent->chars);
535     }
536 
537     if (self->fSkip == self->fDepth) {
538         self->fSkip = 0;
539         const TagHandler* parent = self->fHandler.top();
540         XML_SetCharacterDataHandler(self->fParser, parent->chars);
541     }
542 }
543 
xml_entity_decl_handler(void * data,const XML_Char * entityName,int is_parameter_entity,const XML_Char * value,int value_length,const XML_Char * base,const XML_Char * systemId,const XML_Char * publicId,const XML_Char * notationName)544 static void XMLCALL xml_entity_decl_handler(void *data,
545                                             const XML_Char *entityName,
546                                             int is_parameter_entity,
547                                             const XML_Char *value,
548                                             int value_length,
549                                             const XML_Char *base,
550                                             const XML_Char *systemId,
551                                             const XML_Char *publicId,
552                                             const XML_Char *notationName)
553 {
554     FamilyData* self = static_cast<FamilyData*>(data);
555     SK_FONTCONFIGPARSER_WARNING("'%s' entity declaration found, stopping processing", entityName);
556     XML_StopParser(self->fParser, XML_FALSE);
557 }
558 
559 static const XML_Memory_Handling_Suite sk_XML_alloc = {
560     sk_malloc_throw,
561     sk_realloc_throw,
562     sk_free
563 };
564 
565 template<typename T> struct remove_ptr {typedef T type;};
566 template<typename T> struct remove_ptr<T*> {typedef T type;};
567 
568 /**
569  * This function parses the given filename and stores the results in the given
570  * families array. Returns the version of the file, negative if the file does not exist.
571  */
parse_config_file(const char * filename,SkTDArray<FontFamily * > & families,const SkString & basePath,bool isFallback)572 static int parse_config_file(const char* filename, SkTDArray<FontFamily*>& families,
573                              const SkString& basePath, bool isFallback)
574 {
575     SkFILEStream file(filename);
576 
577     // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
578     // are optional - failure here is okay because one of these optional files may not exist.
579     if (!file.isValid()) {
580         SkDebugf(SK_FONTCONFIGPARSER_PREFIX "'%s' could not be opened\n", filename);
581         return -1;
582     }
583 
584     SkAutoTCallVProc<remove_ptr<XML_Parser>::type, XML_ParserFree> parser(
585         XML_ParserCreate_MM(NULL, &sk_XML_alloc, NULL));
586     if (!parser) {
587         SkDebugf(SK_FONTCONFIGPARSER_PREFIX "could not create XML parser\n");
588         return -1;
589     }
590 
591     FamilyData self(parser, families, basePath, isFallback, filename, &topLevelHandler);
592     XML_SetUserData(parser, &self);
593 
594     // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340
595     XML_SetEntityDeclHandler(parser, xml_entity_decl_handler);
596 
597     // Start parsing oldschool; switch these in flight if we detect a newer version of the file.
598     XML_SetElementHandler(parser, start_element_handler, end_element_handler);
599 
600     // One would assume it would be faster to have a buffer on the stack and call XML_Parse.
601     // But XML_Parse will call XML_GetBuffer anyway and memmove the passed buffer into it.
602     // (Unless XML_CONTEXT_BYTES is undefined, but all users define it.)
603     // In debug, buffer a small odd number of bytes to detect slicing in XML_CharacterDataHandler.
604     static const int bufferSize = 512 SkDEBUGCODE( - 507);
605     bool done = false;
606     while (!done) {
607         void* buffer = XML_GetBuffer(parser, bufferSize);
608         if (!buffer) {
609             SkDebugf(SK_FONTCONFIGPARSER_PREFIX "could not buffer enough to continue\n");
610             return -1;
611         }
612         size_t len = file.read(buffer, bufferSize);
613         done = file.isAtEnd();
614         XML_Status status = XML_ParseBuffer(parser, len, done);
615         if (XML_STATUS_ERROR == status) {
616             XML_Error error = XML_GetErrorCode(parser);
617             int line = XML_GetCurrentLineNumber(parser);
618             int column = XML_GetCurrentColumnNumber(parser);
619             const XML_LChar* errorString = XML_ErrorString(error);
620             SkDebugf(SK_FONTCONFIGPARSER_PREFIX "%s:%d:%d error %d: %s.\n",
621                      filename, line, column, error, errorString);
622             return -1;
623         }
624     }
625     return self.fVersion;
626 }
627 
628 /** Returns the version of the system font file actually found, negative if none. */
append_system_font_families(SkTDArray<FontFamily * > & fontFamilies,const SkString & basePath)629 static int append_system_font_families(SkTDArray<FontFamily*>& fontFamilies,
630                                        const SkString& basePath)
631 {
632     int initialCount = fontFamilies.count();
633     int version = parse_config_file(LMP_SYSTEM_FONTS_FILE, fontFamilies, basePath, false);
634     if (version < 0 || fontFamilies.count() == initialCount) {
635         version = parse_config_file(OLD_SYSTEM_FONTS_FILE, fontFamilies, basePath, false);
636     }
637     return version;
638 }
639 
640 /**
641  * In some versions of Android prior to Android 4.2 (JellyBean MR1 at API
642  * Level 17) the fallback fonts for certain locales were encoded in their own
643  * XML files with a suffix that identified the locale.  We search the provided
644  * directory for those files,add all of their entries to the fallback chain, and
645  * include the locale as part of each entry.
646  */
append_fallback_font_families_for_locale(SkTDArray<FontFamily * > & fallbackFonts,const char * dir,const SkString & basePath)647 static void append_fallback_font_families_for_locale(SkTDArray<FontFamily*>& fallbackFonts,
648                                                      const char* dir,
649                                                      const SkString& basePath)
650 {
651 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
652     // The framework is beyond Android 4.2 and can therefore skip this function
653     return;
654 #endif
655 
656     SkAutoTCallIProc<DIR, closedir> fontDirectory(opendir(dir));
657     if (NULL == fontDirectory) {
658         return;
659     }
660 
661     for (struct dirent* dirEntry; (dirEntry = readdir(fontDirectory));) {
662         // The size of the prefix and suffix.
663         static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1
664                                      + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1;
665 
666         // The size of the prefix, suffix, and a minimum valid language code
667         static const size_t minSize = fixedLen + 2;
668 
669         SkString fileName(dirEntry->d_name);
670         if (fileName.size() < minSize ||
671             !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) ||
672             !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX))
673         {
674             continue;
675         }
676 
677         SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1,
678                         fileName.size() - fixedLen);
679 
680         SkString absoluteFilename;
681         absoluteFilename.printf("%s/%s", dir, fileName.c_str());
682 
683         SkTDArray<FontFamily*> langSpecificFonts;
684         parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true);
685 
686         for (int i = 0; i < langSpecificFonts.count(); ++i) {
687             FontFamily* family = langSpecificFonts[i];
688             family->fLanguage = SkLanguage(locale);
689             *fallbackFonts.append() = family;
690         }
691     }
692 }
693 
append_system_fallback_font_families(SkTDArray<FontFamily * > & fallbackFonts,const SkString & basePath)694 static void append_system_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts,
695                                                  const SkString& basePath)
696 {
697     parse_config_file(FALLBACK_FONTS_FILE, fallbackFonts, basePath, true);
698     append_fallback_font_families_for_locale(fallbackFonts,
699                                              LOCALE_FALLBACK_FONTS_SYSTEM_DIR,
700                                              basePath);
701 }
702 
mixin_vendor_fallback_font_families(SkTDArray<FontFamily * > & fallbackFonts,const SkString & basePath)703 static void mixin_vendor_fallback_font_families(SkTDArray<FontFamily*>& fallbackFonts,
704                                                 const SkString& basePath)
705 {
706     SkTDArray<FontFamily*> vendorFonts;
707     parse_config_file(VENDOR_FONTS_FILE, vendorFonts, basePath, true);
708     append_fallback_font_families_for_locale(vendorFonts,
709                                              LOCALE_FALLBACK_FONTS_VENDOR_DIR,
710                                              basePath);
711 
712     // This loop inserts the vendor fallback fonts in the correct order in the
713     // overall fallbacks list.
714     int currentOrder = -1;
715     for (int i = 0; i < vendorFonts.count(); ++i) {
716         FontFamily* family = vendorFonts[i];
717         int order = family->fOrder;
718         if (order < 0) {
719             if (currentOrder < 0) {
720                 // Default case - just add it to the end of the fallback list
721                 *fallbackFonts.append() = family;
722             } else {
723                 // no order specified on this font, but we're incrementing the order
724                 // based on an earlier order insertion request
725                 *fallbackFonts.insert(currentOrder++) = family;
726             }
727         } else {
728             // Add the font into the fallback list in the specified order. Set
729             // currentOrder for correct placement of other fonts in the vendor list.
730             *fallbackFonts.insert(order) = family;
731             currentOrder = order + 1;
732         }
733     }
734 }
735 
GetSystemFontFamilies(SkTDArray<FontFamily * > & fontFamilies)736 void SkFontConfigParser::GetSystemFontFamilies(SkTDArray<FontFamily*>& fontFamilies) {
737     // Version 21 of the system font configuration does not need any fallback configuration files.
738     SkString basePath(getenv("ANDROID_ROOT"));
739     basePath.append(SK_FONT_FILE_PREFIX, sizeof(SK_FONT_FILE_PREFIX) - 1);
740 
741     if (append_system_font_families(fontFamilies, basePath) >= 21) {
742         return;
743     }
744 
745     // Append all the fallback fonts to system fonts
746     SkTDArray<FontFamily*> fallbackFonts;
747     append_system_fallback_font_families(fallbackFonts, basePath);
748     mixin_vendor_fallback_font_families(fallbackFonts, basePath);
749     fontFamilies.append(fallbackFonts.count(), fallbackFonts.begin());
750 }
751 
GetCustomFontFamilies(SkTDArray<FontFamily * > & fontFamilies,const SkString & basePath,const char * fontsXml,const char * fallbackFontsXml,const char * langFallbackFontsDir)752 void SkFontConfigParser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies,
753                                                const SkString& basePath,
754                                                const char* fontsXml,
755                                                const char* fallbackFontsXml,
756                                                const char* langFallbackFontsDir)
757 {
758     if (fontsXml) {
759         parse_config_file(fontsXml, fontFamilies, basePath, false);
760     }
761     if (fallbackFontsXml) {
762         parse_config_file(fallbackFontsXml, fontFamilies, basePath, true);
763     }
764     if (langFallbackFontsDir) {
765         append_fallback_font_families_for_locale(fontFamilies,
766                                                  langFallbackFontsDir,
767                                                  basePath);
768     }
769 }
770 
getParent() const771 SkLanguage SkLanguage::getParent() const {
772     SkASSERT(!fTag.isEmpty());
773     const char* tag = fTag.c_str();
774 
775     // strip off the rightmost "-.*"
776     const char* parentTagEnd = strrchr(tag, '-');
777     if (parentTagEnd == NULL) {
778         return SkLanguage();
779     }
780     size_t parentTagLen = parentTagEnd - tag;
781     return SkLanguage(tag, parentTagLen);
782 }
783