summaryrefslogtreecommitdiff
path: root/content/content_factory.c
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2011-05-06 20:40:09 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2011-05-06 20:40:09 +0000
commite71691bae890040b83cfd54a2d9a1097d5026866 (patch)
tree96b2680dc6559ca0ab88fa0b6a533c13b7c9487e /content/content_factory.c
parente77b1a29550e4753f771848705975295a6ebe99e (diff)
downloadnetsurf-e71691bae890040b83cfd54a2d9a1097d5026866.tar.gz
netsurf-e71691bae890040b83cfd54a2d9a1097d5026866.tar.bz2
Merge branches/jmb/content-factory to trunk
svn path=/trunk/netsurf/; revision=12283
Diffstat (limited to 'content/content_factory.c')
-rw-r--r--content/content_factory.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/content/content_factory.c b/content/content_factory.c
new file mode 100644
index 000000000..95e7679ad
--- /dev/null
+++ b/content/content_factory.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content factory (implementation)
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "content/content.h"
+#include "content/content_factory.h"
+#include "content/content_protected.h"
+#include "content/llcache.h"
+
+/**
+ * Entry in list of content handlers
+ */
+typedef struct content_handler_entry {
+ /** Next entry */
+ struct content_handler_entry *next;
+
+ /** MIME type handled by handler */
+ lwc_string *mime_type;
+ /** Content handler object */
+ const content_handler *handler;
+} content_handler_entry;
+
+static content_handler_entry *content_handlers;
+
+/**
+ * Register a handler with the content factory
+ *
+ * \param mime_type MIME type to handle
+ * \param handler Content handler for MIME type
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * \note Latest registration for a MIME type wins
+ */
+nserror content_factory_register_handler(lwc_string *mime_type,
+ const content_handler *handler)
+{
+ content_handler_entry *entry;
+ bool match;
+
+ for (entry = content_handlers; entry != NULL; entry = entry->next) {
+ if (lwc_string_caseless_isequal(mime_type, entry->mime_type,
+ &match) == lwc_error_ok && match)
+ break;
+ }
+
+ if (entry == NULL) {
+ entry = malloc(sizeof(content_handler_entry));
+ if (entry == NULL)
+ return NSERROR_NOMEM;
+
+ entry->next = content_handlers;
+ content_handlers = entry;
+
+ entry->mime_type = lwc_string_ref(mime_type);
+ }
+
+ entry->handler = handler;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Find a handler for a MIME type.
+ *
+ * \param mime_type MIME type to search for
+ * \return Associated handler, or NULL if none
+ */
+static const content_handler *content_lookup(lwc_string *mime_type)
+{
+ content_handler_entry *entry;
+ bool match;
+
+ for (entry = content_handlers; entry != NULL; entry = entry->next) {
+ if (lwc_string_caseless_isequal(mime_type, entry->mime_type,
+ &match) == lwc_error_ok && match)
+ break;
+ }
+
+ if (entry != NULL)
+ return entry->handler;
+
+ return NULL;
+}
+
+/**
+ * Compute the generic content type for a MIME type
+ *
+ * \param mime_type MIME type to consider
+ * \return Generic content type
+ */
+content_type content_factory_type_from_mime_type(const char *mime_type)
+{
+ const content_handler *handler;
+ lwc_string *imime_type;
+ lwc_error lerror;
+ content_type type = CONTENT_NONE;
+
+ lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type);
+ if (lerror != lwc_error_ok)
+ return CONTENT_NONE;
+
+ handler = content_lookup(imime_type);
+ if (handler != NULL) {
+ type = handler->type(imime_type);
+ }
+
+ lwc_string_unref(imime_type);
+
+ return type;
+}
+
+/**
+ * Create a content object
+ *
+ * \param llcache Underlying source data handle
+ * \param fallback_charset Character set to fall back to if none specified
+ * \param quirks Quirkiness of containing document
+ * \return Pointer to content object, or NULL on failure
+ */
+struct content *content_factory_create_content(llcache_handle *llcache,
+ const char *fallback_charset, bool quirks)
+{
+ struct content *c;
+ const char *content_type_header;
+ const content_handler *handler;
+ char *mime_type;
+ http_parameter *params;
+ lwc_string *imime_type;
+ lwc_error lerr;
+ nserror error;
+
+ content_type_header =
+ llcache_handle_get_header(llcache, "Content-Type");
+ if (content_type_header == NULL)
+ content_type_header = "text/plain";
+
+ error = http_parse_content_type(content_type_header, &mime_type,
+ &params);
+ if (error != NSERROR_OK)
+ return NULL;
+
+ lerr = lwc_intern_string(mime_type, strlen(mime_type), &imime_type);
+ if (lerr != lwc_error_ok) {
+ http_parameter_list_destroy(params);
+ free(mime_type);
+ return NULL;
+ }
+
+ free(mime_type);
+
+ handler = content_lookup(imime_type);
+ if (handler == NULL) {
+ lwc_string_unref(imime_type);
+ http_parameter_list_destroy(params);
+ return NULL;
+ }
+
+ assert(handler->create != NULL);
+
+ error = handler->create(handler, imime_type, params, llcache,
+ fallback_charset, quirks, &c);
+ if (error != NSERROR_OK) {
+ lwc_string_unref(imime_type);
+ http_parameter_list_destroy(params);
+ return NULL;
+ }
+
+ lwc_string_unref(imime_type);
+ http_parameter_list_destroy(params);
+
+ return c;
+}
+