Home | History | Annotate | Download | only in ports
      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 {
     84     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  */
    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 
    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 
    156 static bool is_whitespace(char c) {
    157     return c == ' ' || c == '\n'|| c == '\r' || c == '\t';
    158 }
    159 
    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 = {
    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     },
    207     /*end*/[](FamilyData* self, const char* tag) {
    208         trim_string(&self->fCurrentFontInfo->fFileName);
    209     },
    210     /*tag*/NULL,
    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 = {
    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     },
    245     /*end*/[](FamilyData* self, const char* tag) {
    246         *self->fFamilies.append() = self->fCurrentFamily.detach();
    247     },
    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 
    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 = {
    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 = {
    325     /*start*/[](FamilyData* self, const char* tag, const char** attributes) { },
    326     /*end*/NULL,
    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 = {
    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,
    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,
    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 = {
    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,
    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,
    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 = {
    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     },
    445     /*end*/[](FamilyData* self, const char* tag) {
    446         *self->fFamilies.append() = self->fCurrentFamily.detach();
    447     },
    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,
    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,
    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 
    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 
    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 
    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  */
    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. */
    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  */
    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 
    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 
    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 
    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 
    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 
    771 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