diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | data/epiphany-extension.xsd | 162 | ||||
-rw-r--r-- | src/ephy-extensions-manager.c | 103 |
3 files changed, 137 insertions, 138 deletions
@@ -1,3 +1,13 @@ +2004-10-18 Adam Hooper <adamh@cvs.gnome.org> + + * data/epiphany-extension.xsd: + * src/ephy-extensions-manager.c: + (ephy_extensions_manager_load_file), (load_extension), + (xml_error_cb), (init_schema_ctxt), (ephy_extensions_manager_init), + (ephy_extensions_manager_finalize): + + Validate extension XML files against an XSD Schema. + 2004-10-18 Christian Persch <chpe@cvs.gnome.org> * configure.ac: diff --git a/data/epiphany-extension.xsd b/data/epiphany-extension.xsd index aca452b2b..4898b1ce7 100644 --- a/data/epiphany-extension.xsd +++ b/data/epiphany-extension.xsd @@ -7,21 +7,7 @@ </xsd:documentation> </xsd:annotation> - <xsd:element name="extension-list" type="ExtensionListType"/> - - <xsd:complexType name="ExtensionListType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - List of extensions. Each extension has its set - of metadata. - </xsd:documentation> - </xsd:annotation> - <xsd:sequence> - <xsd:element name="extension" - type="ExtensionType" - minOccurs="1"/> - </xsd:sequence> - </xsd:complexType> + <xsd:element name="extension" type="ExtensionType"/> <xsd:complexType name="ExtensionType"> <xsd:annotation> @@ -30,152 +16,62 @@ </xsd:documentation> </xsd:annotation> <xsd:sequence> - <xsd:element name="filename" - type="ExtensionFilenameType" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="name" - type="xsd:string" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="description" - type="xsd:string" - minOccurs="1" maxOccurs="1"/> + <xsd:element name="name" type="xsd:string"/> + <xsd:element name="description" type="xsd:string"/> + <xsd:element name="author" type="AuthorType" + maxOccurs="unbounded"/> + <xsd:element name="url" type="xsd:anyURI" + minOccurs="0"/> <xsd:element name="version" - type="ExtensionVersionType" - minOccurs="1" maxOccurs="1"/> -<!-- - <xsd:element name="min-epiphany-version" - type="EpiphanyVersionType" - maxOccurs="1"/> - <xsd:element name="max-epiphany-version" - type="EpiphanyVersionType" - maxOccurs="1"/> - <xsd:element name="min-mozilla-version" - type="MozillaVersionType" - maxOccurs="1"/> - <xsd:element name="max-mozilla-version" - type="MozillaVersionType" - maxOccurs="1"/> ---> - <xsd:element name="author" type="AuthorType"/> - <xsd:element name="url" type="xsd:anyURI"/> + type="ExtensionVersionType"/> + <xsd:element name="gettext-domain" type="xsd:string"/> + <xsd:element name="locale-directory" type="xsd:string"/> + <xsd:element name="loader" type="LoaderType"/> </xsd:sequence> </xsd:complexType> - <xsd:simpleType name="ExtensionFilenameType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - The "core" of the extension's - filename. For example, use "gestures" - for an extension with a shared object name of - "libgesturesextension.so". - </xsd:documentation> - </xsd:annotation> - <xsd:restriction base="xsd:string"> - <xsd:pattern value="[a-zA-Z0-9_-]+"/> - </xsd:restriction> - </xsd:simpleType> - <xsd:simpleType name="ExtensionVersionType"> <xsd:annotation> <xsd:documentation xml:lang="en"> The version of the extension's API. For most extensions, this number will remain at "1" indefinitely. The only reason to - increase it would be if any GObject classess + increase it would be if any GObject classes within the extension change parents. </xsd:documentation> </xsd:annotation> <xsd:restriction base="xsd:positiveInteger"/> </xsd:simpleType> -<!-- - <xsd:complexType name="EpiphanyVersionType"> + <xsd:simpleType name="AuthorType"> <xsd:annotation> <xsd:documentation xml:lang="en"> - An Epiphany version (major.minor.micro). - Extensions may function properly across a range - of Epiphany versions, as long as the relevant - parts of the Epiphany API have not changed. - </xsd:documentation> - </xsd:annotation> - <xsd:sequence> - <xsd:element name="major" - type="xsd:positiveInteger" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="minor" - type="xsd:positiveInteger" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="micro" - type="xsd:positiveInteger" - minOccurs="1" maxOccurs="1"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="MozillaVersionType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - A Mozilla version (major, minor, type, micro). - Extensions my function properly across a range - of Mozilla versions, as long as the relevant - parts of the Mozilla API have not changed. - </xsd:documentation> - </xsd:annotation> - <xsd:sequence> - <xsd:element name="major" - type="xsd:positiveInteger" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="minor" - type="xsd:positiveInteger" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="type" - type="MozillaVersionTypeType" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="micro" - type="xsd:positiveInteger" - minOccurs="1" maxOccurs="1"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:simpleType name="MozillaVersionTypeType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - The "type" of a Mozilla version. 1 - means Alpha, 2 means Beta, 3 means RC and 4 - means release. + An extension author -- a name and (optionally) + an email address. </xsd:documentation> </xsd:annotation> - <xsd:restriction base="xsd:positiveInteger"> - <xsd:minInclusive value="1"/> - <xsd:maxInclusive value="4"/> - </xsd:restriction> + <xsd:restriction base="xsd:string"/> </xsd:simpleType> ---> - <xsd:complexType name="AuthorType"> + <xsd:complexType name="LoaderType"> <xsd:annotation> <xsd:documentation xml:lang="en"> - An extension author -- a name and (optionally) - an email address. + The type of loader to use for the extension. + For example, "shlib". </xsd:documentation> </xsd:annotation> <xsd:sequence> - <xsd:element name="name" - type="xsd:normalizedString" - minOccurs="1" maxOccurs="1"/> - <xsd:element name="email" - type="EmailType" - maxOccurs="1"/> + <xsd:element name="attribute" maxOccurs="unbounded"> + <xsd:complexType> + <xsd:simpleContent> + <xsd:extension base="xsd:string"> + <xsd:attribute name="name" type="xsd:ID"/> + </xsd:extension> + </xsd:simpleContent> + </xsd:complexType> + </xsd:element> </xsd:sequence> + <xsd:attribute name="type" type="xsd:ID" use="required"/> </xsd:complexType> - <xsd:simpleType name="EmailType"> - <xsd:annotation> - <xsd:documentation xml:lang="en"> - An email address - </xsd:documentation> - </xsd:annotation> - <xsd:restriction base="xsd:string"> - <xsd:pattern value="[\.a-zA-Z0-9_-]+@([a-zA-Z0-9_-])+(([a-zA-Z0-9_-])*\.([a-zA-Z0-9_-])+)+"/> - </xsd:restriction> - </xsd:simpleType> </xsd:schema> diff --git a/src/ephy-extensions-manager.c b/src/ephy-extensions-manager.c index 0fc15bcbd..5ec951168 100644 --- a/src/ephy-extensions-manager.c +++ b/src/ephy-extensions-manager.c @@ -35,13 +35,16 @@ #include "ephy-file-helpers.h" #include "ephy-debug.h" +#include <libxml/tree.h> #include <libxml/xmlreader.h> +#include <libxml/xmlschemas.h> #include <gmodule.h> #include <dirent.h> #include <string.h> -#define CONF_LOADED_EXTENSIONS "/apps/epiphany/general/active_extensions" +#define CONF_LOADED_EXTENSIONS "/apps/epiphany/general/active_extensions" +#define SCHEMA_FILE "/epiphany-extension.xsd" #define EPHY_EXTENSIONS_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_EXTENSIONS_MANAGER, EphyExtensionsManagerPrivate)) @@ -54,6 +57,9 @@ struct _EphyExtensionsManagerPrivate GList *extensions; GList *windows; guint active_extensions_notifier_id; + + xmlSchemaPtr schema; + xmlSchemaValidCtxtPtr schema_ctxt; }; typedef struct @@ -307,6 +313,7 @@ ephy_extensions_manager_load_file (EphyExtensionsManager *manager, const char *dir, const char *filename) { + xmlDocPtr doc; xmlTextReaderPtr reader; ParserState state = STATE_START; GQuark attr_quark = 0; @@ -339,17 +346,35 @@ ephy_extensions_manager_load_file (EphyExtensionsManager *manager, g_free (path); return; } - - reader = xmlNewTextReaderFilename (path); + + /* FIXME: Ideally we'd put the schema validator in the reader. libxml2 + * doesn't seem to support that at this point in time, so we've got to + * put the schema validation on the Doc Tree and then pass that to the + * reader. (maybe switch to RelaxNG?) + */ + doc = xmlParseFile (path); g_free (path); - if (reader == NULL) + if (doc == NULL) { g_warning ("Couldn't read '%s'\n", filename); g_free (identifier); return; } + if (manager->priv->schema_ctxt) + { + if (xmlSchemaValidateDoc (manager->priv->schema_ctxt, doc)) + { + g_warning ("Validation errors in '%s'\n", filename); + xmlFreeDoc (doc); + return; + } + } + + reader = xmlReaderWalker (doc); + g_return_if_fail (reader != NULL); + info = g_new0 (ExtensionInfo, 1); einfo = (EphyExtensionInfo *) info; einfo->identifier = identifier; @@ -580,6 +605,7 @@ ephy_extensions_manager_load_file (EphyExtensionsManager *manager, } xmlFreeTextReader (reader); + xmlFreeDoc (doc); /* sanity check */ if (ret < 0 || state != STATE_STOP || @@ -647,7 +673,6 @@ static void load_extension (EphyExtensionsManager *manager, ExtensionInfo *info) { - EphyLoader *loader; g_return_if_fail (info->extension == NULL); @@ -797,6 +822,63 @@ active_extensions_notifier (GConfClient *client, } static void +xml_error_cb (EphyExtensionsManager *manager, + const char *msg, + ...) + +{ + va_list args; + + va_start (args, msg); + g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, msg, args); + va_end(args); +} + +static void +init_schema_ctxt (EphyExtensionsManager *manager) +{ + xmlSchemaParserCtxtPtr parse_ctxt; + const char *filename; + + manager->priv->schema = NULL; + manager->priv->schema_ctxt = NULL; + + filename = ephy_file (SCHEMA_FILE); + g_return_if_fail (filename != NULL); + + parse_ctxt = xmlSchemaNewParserCtxt (filename); + if (parse_ctxt == NULL) + { + g_warning ("Error opening extensions description schema file " + "\"" SCHEMA_FILE "\""); + return; + } + + manager->priv->schema = xmlSchemaParse (parse_ctxt); + xmlSchemaFreeParserCtxt (parse_ctxt); + if (manager->priv->schema == NULL) + { + g_warning ("Error parsing extensions description schema file " + "\"" SCHEMA_FILE "\""); + return; + } + + manager->priv->schema_ctxt = xmlSchemaNewValidCtxt + (manager->priv->schema); + if (manager->priv->schema == NULL) + { + g_warning ("Error creating extensions description schema " + "validation context for \"" SCHEMA_FILE "\""); + return; + } + + xmlSchemaSetValidErrors (manager->priv->schema_ctxt, + (xmlSchemaValidityErrorFunc) xml_error_cb, + (xmlSchemaValidityWarningFunc) xml_error_cb, + manager); +} + +static void ephy_extensions_manager_init (EphyExtensionsManager *manager) { char *path; @@ -805,6 +887,8 @@ ephy_extensions_manager_init (EphyExtensionsManager *manager) LOG ("EphyExtensionsManager initialising") + init_schema_ctxt (manager); + /* load the extensions descriptions */ path = g_build_filename (ephy_dot_dir (), "extensions", NULL); ephy_extensions_manager_load_dir (manager, path); @@ -841,6 +925,15 @@ ephy_extensions_manager_finalize (GObject *object) g_list_free (priv->windows); + if (priv->schema) + { + xmlSchemaFree (priv->schema); + } + if (priv->schema_ctxt) + { + xmlSchemaFreeValidCtxt (priv->schema_ctxt); + } + parent_class->finalize (object); } |