Repository: xbmc/xbmc
File: xbmc/cores/VideoPlayer/DVDSubtitles/DVDSubtitlesLibass.cpp (C++)

Code before:
  StringUtils::Replace(escapedSystemFontsDir, "&", "&amp;");
  StringUtils::Replace(escapedSystemFontsDir, "<", "&lt;");
  StringUtils::Replace(escapedSystemFontsDir, ">", "&gt;");
  StringUtils::Replace(escapedSystemFontsDir, "\"", "&quot;");
  StringUtils::Replace(escapedSystemFontsDir, "'", "&apos;");

  std::string escapedCacheDir = fontconfigCacheDir;
  StringUtils::Replace(escapedCacheDir, "&", "&amp;");
  StringUtils::Replace(escapedCacheDir, "<", "&lt;");
  StringUtils::Replace(escapedCacheDir, ">", "&gt;");
  StringUtils::Replace(escapedCacheDir, "\"", "&quot;");
  StringUtils::Replace(escapedCacheDir, "'", "&apos;");

  std::string fontconfigXml = "<?xml version=\"1.0\"?>\n"
                              "<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n"
                              "<fontconfig>\n"
                              "  <dir>" +
                              escapedFontsDir +
                              "</dir>\n"
                              "  <dir>" +
                              escapedSystemFontsDir +
                              "</dir>\n"
                              "  <dir>/system/fonts</dir>\n"
                              "  <dir>/product/fonts</dir>\n"
                              "  <dir>/system_ext/fonts</dir>\n"
                              "  <dir>/vendor/fonts</dir>\n"
                              "  <cachedir>" +
                              escapedCacheDir +
                              "</cachedir>\n"
                              "</fontconfig>\n";

  // Write fontconfig configuration to temp directory (only if it doesn't exist)
  fontconfigPath = CSpecialProtocol::TranslatePath("special://temp/fonts.conf");

  if (!XFILE::CFile::Exists(fontconfigPath))
  {
    XFILE::CFile fontconfigFile;
    if (fontconfigFile.OpenForWrite(fontconfigPath, true))
    {
      fontconfigFile.Write(fontconfigXml.c_str(), fontconfigXml.length());
      fontconfigFile.Close();
      fontconfigConfig = fontconfigPath.c_str();
      CLog::Log(LOGINFO, "CDVDSubtitlesLibass: Created fontconfig configuration at {}",
                fontconfigPath);
    }
    else
    {
      CLog::Log(LOGERROR, "CDVDSubtitlesLibass: Failed to create fontconfig configuration, falling "
                          "back to AUTODETECT");
      fontProvider = ASS_FONTPROVIDER_AUTODETECT;
      fontconfigConfig = nullptr;

Review comment (suggestion):
Some of these paths may not exist because brands do not always follow standards,
if there is any documentation regarding these paths, it would be best to mention it

Code after:
    CXBMCTinyXML2 xmlDoc;
    xmlDoc.InsertEndChild(xmlDoc.NewDeclaration("xml version=\"1.0\""));
    xmlDoc.InsertEndChild(xmlDoc.NewUnknown("DOCTYPE fontconfig SYSTEM \"fonts.dtd\""));

    tinyxml2::XMLElement* eRoot = xmlDoc.NewElement("fontconfig");
    xmlDoc.InsertEndChild(eRoot);

    auto addRootChildText = [&](const char* name, const std::string& value)
    {
      tinyxml2::XMLElement* elem = xmlDoc.NewElement(name);
      elem->SetText(value.c_str());
      eRoot->InsertEndChild(elem);
    };

    // Add Android system font directories
    // Note: USER and SYSTEM dirs are handled by ass_set_fonts_dir below
    const std::vector<std::string> fontDirs = {
        "/system/fonts", // AOSP standard
        "/product/fonts", // AOSP vendor-specific
        "/system_ext/fonts" // OEM-specific (may not exist on all devices)
    };

    for (const auto& dir : fontDirs)
    {
      if (XFILE::CDirectory::Exists(dir))
        addRootChildText("dir", dir);
    }

    addRootChildText("cachedir", fontconfigCacheDir);

    if (xmlDoc.SaveFile(fontconfigPath))
    {
      fontconfigConfig = fontconfigPath.c_str();
      CLog::Log(LOGINFO, "CDVDSubtitlesLibass: Created fontconfig configuration at {}",
                fontconfigPath);
    }
    else
    {
      CLog::LogF(LOGERROR, "Failed to create fontconfig configuration, falling back to "
                           "ASS_FONTPROVIDER_AUTODETECT");
      fontProvider = ASS_FONTPROVIDER_AUTODETECT;
      fontconfigConfig = nullptr;
    }
  }
  else
  {
    fontconfigConfig = fontconfigPath.c_str();
  }
#endif

  // Set additional fonts directory for libass to scan. This provides font lookup