/** * cra_plugin_process_filename: */ static gboolean cra_plugin_process_filename (CraPlugin *plugin, CraPackage *pkg, const gchar *filename, GList **apps, const gchar *tmpdir, GError **error) { GNode *root = NULL; GString *valid_xml; const gchar *tmp; const GNode *n; gboolean found_header = FALSE; gboolean ret; guint i; _cleanup_free_ gchar *basename = NULL; _cleanup_free_ gchar *data = NULL; _cleanup_free_ gchar *filename_tmp; _cleanup_object_unref_ CraApp *app = NULL; _cleanup_strv_free_ gchar **languages = NULL; _cleanup_strv_free_ gchar **lines = NULL; /* open file */ filename_tmp = g_build_filename (tmpdir, filename, NULL); ret = g_file_get_contents (filename_tmp, &data, NULL, error); if (!ret) goto out; /* some components start with a comment (invalid XML) and some * don't even have '<?xml' -- try to fix up best we can */ valid_xml = g_string_new (""); lines = g_strsplit (data, "\n", -1); for (i = 0; lines[i] != NULL; i++) { if (g_str_has_prefix (lines[i], "<?xml") || g_str_has_prefix (lines[i], "<component>")) found_header = TRUE; if (found_header) g_string_append_printf (valid_xml, "%s\n", lines[i]); } /* parse contents */ root = as_node_from_xml (valid_xml->str, -1, AS_NODE_FROM_XML_FLAG_NONE, error); if (!ret) goto out; /* create new app */ basename = g_path_get_basename (filename); app = cra_app_new (pkg, basename); as_app_set_id_kind (AS_APP (app), AS_ID_KIND_INPUT_METHOD); as_app_add_category (AS_APP (app), "Addons", -1); as_app_add_category (AS_APP (app), "InputSources", -1); as_app_set_icon (AS_APP (app), "system-run-symbolic", -1); as_app_set_icon_kind (AS_APP (app), AS_ICON_KIND_STOCK); cra_app_set_requires_appdata (app, TRUE); /* read the component header which all input methods have */ n = as_node_find (root, "component/description"); if (n != NULL) { as_app_set_name (AS_APP (app), "C", as_node_get_data (n), -1); as_app_set_comment (AS_APP (app), "C", as_node_get_data (n), -1); } n = as_node_find (root, "component/homepage"); if (n != NULL) { as_app_add_url (AS_APP (app), AS_URL_KIND_HOMEPAGE, as_node_get_data (n), -1); } /* do we have a engine section we can use? */ n = as_node_find (root, "component/engines/engine/longname"); if (n != NULL) as_app_set_name (AS_APP (app), "C", as_node_get_data (n), -1); n = as_node_find (root, "component/engines/engine/description"); if (n != NULL) as_app_set_comment (AS_APP (app), "C", as_node_get_data (n), -1); n = as_node_find (root, "component/engines/engine/symbol"); if (n != NULL) { tmp = as_node_get_data (n); if (tmp != NULL && tmp[0] != '\0') { as_app_add_metadata (AS_APP (app), "X-IBus-Symbol", tmp, -1); } } n = as_node_find (root, "component/engines/engine/language"); if (n != NULL) { tmp = as_node_get_data (n); if (tmp != NULL) { languages = g_strsplit (tmp, ",", -1); for (i = 0; languages[i] != NULL; i++) { if (g_strcmp0 (languages[i], "other") == 0) continue; as_app_add_language (AS_APP (app), 100, languages[i], -1); } } } /* add */ cra_plugin_add_app (apps, app); out: if (root != NULL) as_node_unref (root); return ret; }
static gboolean as_app_validate_description (const gchar *xml, AsAppValidateHelper *helper, guint number_para_min, guint number_para_max, gboolean allow_short_para, GError **error) { GNode *l; GNode *l2; g_autoptr(AsNode) node = NULL; /* parse xml */ node = as_node_from_xml (xml, AS_NODE_FROM_XML_FLAG_NONE, error); if (node == NULL) return FALSE; helper->number_paragraphs = 0; helper->previous_para_was_short = FALSE; for (l = node->children; l != NULL; l = l->next) { if (g_strcmp0 (as_node_get_name (l), "p") == 0) { if (as_node_get_attribute (l, "xml:lang") != NULL) continue; as_app_validate_description_para (as_node_get_data (l), helper); } else if (g_strcmp0 (as_node_get_name (l), "ul") == 0 || g_strcmp0 (as_node_get_name (l), "ol") == 0) { as_app_validate_description_list (as_node_get_data (l), allow_short_para, helper); for (l2 = l->children; l2 != NULL; l2 = l2->next) { if (g_strcmp0 (as_node_get_name (l2), "li") == 0) { if (as_node_get_attribute (l2, "xml:lang") != NULL) continue; as_app_validate_description_li (as_node_get_data (l2), helper); } else { /* only <li> supported */ g_set_error (error, AS_APP_ERROR, AS_APP_ERROR_FAILED, "invalid markup: <%s> follows <%s>", as_node_get_name (l2), as_node_get_name (l)); return FALSE; } } } else { /* only <p>, <ol> and <ul> supported */ g_set_error (error, AS_APP_ERROR, AS_APP_ERROR_FAILED, "invalid markup: tag <%s> invalid here", as_node_get_name (l)); return FALSE; } } /* previous paragraph wasn't long enough */ if (helper->previous_para_was_short) { ai_app_validate_add (helper, AS_PROBLEM_KIND_STYLE_INCORRECT, "<p> is too short [%s]", helper->previous_para_was_short_str); } if (helper->number_paragraphs < number_para_min) { ai_app_validate_add (helper, AS_PROBLEM_KIND_STYLE_INCORRECT, "Not enough <p> tags for a good description [%u/%u]", helper->number_paragraphs, number_para_min); } if (helper->number_paragraphs > number_para_max) { ai_app_validate_add (helper, AS_PROBLEM_KIND_STYLE_INCORRECT, "Too many <p> tags for a good description [%u/%u]", helper->number_paragraphs, number_para_max); } return TRUE; }
/** * as_markup_convert_full: * @markup: the text to copy. * @format: the #AsMarkupConvertFormat, e.g. %AS_MARKUP_CONVERT_FORMAT_MARKDOWN * @flags: the #AsMarkupConvertFlag, e.g. %AS_MARKUP_CONVERT_FLAG_IGNORE_ERRORS * @error: A #GError or %NULL * * Converts an XML description into a printable form. * * Returns: (transfer full): a newly allocated %NULL terminated string * * Since: 0.3.5 **/ gchar * as_markup_convert_full (const gchar *markup, AsMarkupConvertFormat format, AsMarkupConvertFlag flags, GError **error) { GNode *tmp; GNode *tmp_c; const gchar *tag; const gchar *tag_c; g_autoptr(AsNode) root = NULL; g_autoptr(GError) error_local = NULL; g_autoptr(GString) str = NULL; /* is this actually markup */ if (g_strstr_len (markup, -1, "<") == NULL) return g_strdup (markup); /* load */ root = as_node_from_xml (markup, AS_NODE_FROM_XML_FLAG_NONE, &error_local); if (root == NULL) { /* truncate to the last tag and try again */ if (flags & AS_MARKUP_CONVERT_FLAG_IGNORE_ERRORS) { gchar *found; g_autofree gchar *markup_new = NULL; markup_new = g_strdup (markup); found = g_strrstr (markup_new, "<"); g_assert (found != NULL); *found = '\0'; return as_markup_convert_full (markup_new, format, flags, error); } /* just return error */ g_propagate_error (error, error_local); error_local = NULL; return NULL; } /* format */ str = g_string_new (""); for (tmp = root->children; tmp != NULL; tmp = tmp->next) { tag = as_node_get_name (tmp); if (g_strcmp0 (tag, "unknown") == 0) continue; if (g_strcmp0 (tag, "p") == 0) { as_markup_render_para (str, format, as_node_get_data (tmp)); continue; } /* loop on the children */ if (g_strcmp0 (tag, "ul") == 0 || g_strcmp0 (tag, "ol") == 0) { as_markup_render_ul_start (str, format); for (tmp_c = tmp->children; tmp_c != NULL; tmp_c = tmp_c->next) { tag_c = as_node_get_name (tmp_c); if (g_strcmp0 (tag_c, "unknown") == 0) continue; if (g_strcmp0 (tag_c, "li") == 0) { as_markup_render_li (str, format, as_node_get_data (tmp_c)); continue; } /* just abort the list */ if (flags & AS_MARKUP_CONVERT_FLAG_IGNORE_ERRORS) break; /* only <li> is valid in lists */ g_set_error (error, AS_NODE_ERROR, AS_NODE_ERROR_FAILED, "Tag %s in %s invalid", tag_c, tag); return NULL; } as_markup_render_ul_end (str, format); continue; } /* just try again */ if (flags & AS_MARKUP_CONVERT_FLAG_IGNORE_ERRORS) continue; /* only <p>, <ul> and <ol> is valid here */ g_set_error (error, AS_NODE_ERROR, AS_NODE_ERROR_FAILED, "Unknown tag '%s'", tag); return NULL; } /* success */ switch (format) { case AS_MARKUP_CONVERT_FORMAT_SIMPLE: case AS_MARKUP_CONVERT_FORMAT_MARKDOWN: if (str->len > 0) g_string_truncate (str, str->len - 1); break; default: break; } return g_strdup (str->str); }