Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2011 John-Mark Bell <jmb@netsurf-browser.org>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.  * Content factory (implementation)
  21.  */
  22.  
  23. #include <assert.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. #include "content/content.h"
  28. #include "content/content_factory.h"
  29. #include "content/content_protected.h"
  30. #include "content/llcache.h"
  31.  
  32. /**
  33.  * Entry in list of content handlers
  34.  */
  35. typedef struct content_handler_entry {
  36.         /** Next entry */
  37.         struct content_handler_entry *next;
  38.  
  39.         /** MIME type handled by handler */
  40.         lwc_string *mime_type;
  41.         /** Content handler object */
  42.         const content_handler *handler;
  43. } content_handler_entry;
  44.  
  45. static content_handler_entry *content_handlers;
  46.  
  47. /**
  48.  * Clean up after the content factory
  49.  */
  50. void content_factory_fini(void)
  51. {
  52.         content_handler_entry *victim;
  53.  
  54.         while (content_handlers != NULL) {
  55.                 victim = content_handlers;
  56.  
  57.                 content_handlers = content_handlers->next;
  58.  
  59.                 if (victim->handler->fini != NULL)
  60.                         victim->handler->fini();
  61.  
  62.                 lwc_string_unref(victim->mime_type);
  63.  
  64.                 free(victim);
  65.         }
  66. }
  67.  
  68. /**
  69.  * Register a handler with the content factory
  70.  *
  71.  * \param mime_type  MIME type to handle
  72.  * \param handler    Content handler for MIME type
  73.  * \return NSERROR_OK on success, appropriate error otherwise
  74.  *
  75.  * \note Latest registration for a MIME type wins
  76.  */
  77. nserror content_factory_register_handler(const char *mime_type,
  78.                 const content_handler *handler)
  79. {
  80.         lwc_string *imime_type;
  81.         lwc_error lerror;
  82.         content_handler_entry *entry;
  83.         bool match;
  84.  
  85.         lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type);
  86.         if (lerror != lwc_error_ok)
  87.                 return NSERROR_NOMEM;
  88.  
  89.         for (entry = content_handlers; entry != NULL; entry = entry->next) {
  90.                 if (lwc_string_caseless_isequal(imime_type, entry->mime_type,
  91.                                 &match) == lwc_error_ok && match)
  92.                         break;
  93.         }
  94.  
  95.         if (entry == NULL) {
  96.                 entry = malloc(sizeof(content_handler_entry));
  97.                 if (entry == NULL)
  98.                         return NSERROR_NOMEM;
  99.  
  100.                 entry->next = content_handlers;
  101.                 content_handlers = entry;
  102.  
  103.                 entry->mime_type = imime_type;
  104.         } else {
  105.                 lwc_string_unref(imime_type);
  106.         }
  107.  
  108.         entry->handler = handler;
  109.  
  110.         return NSERROR_OK;
  111. }
  112.  
  113. /**
  114.  * Find a handler for a MIME type.
  115.  *
  116.  * \param mime_type  MIME type to search for
  117.  * \return Associated handler, or NULL if none
  118.  */
  119. static const content_handler *content_lookup(lwc_string *mime_type)
  120. {
  121.         content_handler_entry *entry;
  122.         bool match;
  123.  
  124.         for (entry = content_handlers; entry != NULL; entry = entry->next) {
  125.                 if (lwc_string_caseless_isequal(mime_type, entry->mime_type,
  126.                                 &match) == lwc_error_ok && match)
  127.                         break;
  128.         }
  129.  
  130.         if (entry != NULL)
  131.                 return entry->handler;
  132.  
  133.         return NULL;
  134. }
  135.  
  136. /**
  137.  * Compute the generic content type for a MIME type
  138.  *
  139.  * \param mime_type  MIME type to consider
  140.  * \return Generic content type
  141.  */
  142. content_type content_factory_type_from_mime_type(lwc_string *mime_type)
  143. {
  144.         const content_handler *handler;
  145.         content_type type = CONTENT_NONE;
  146.  
  147.         handler = content_lookup(mime_type);
  148.         if (handler != NULL) {
  149.                 type = handler->type();
  150.         }
  151.  
  152.         return type;
  153. }
  154.  
  155. /**
  156.  * Create a content object
  157.  *
  158.  * \param llcache           Underlying source data handle
  159.  * \param fallback_charset  Character set to fall back to if none specified
  160.  * \param quirks            Quirkiness of containing document
  161.  * \param effective_type    Effective MIME type of content
  162.  * \return Pointer to content object, or NULL on failure
  163.  */
  164. struct content *content_factory_create_content(llcache_handle *llcache,
  165.                 const char *fallback_charset, bool quirks,
  166.                 lwc_string *effective_type)
  167. {
  168.         struct content *c;
  169.         const char *content_type_header;
  170.         const content_handler *handler;
  171.         http_content_type *ct = NULL;
  172.         nserror error;
  173.  
  174.         handler = content_lookup(effective_type);
  175.         if (handler == NULL)
  176.                 return NULL;
  177.  
  178.         assert(handler->create != NULL);
  179.  
  180.         /* Use the parameters from the declared Content-Type header */
  181.         content_type_header =
  182.                         llcache_handle_get_header(llcache, "Content-Type");
  183.         if (content_type_header != NULL) {
  184.                 /* We don't care if this fails */
  185.                 http_parse_content_type(content_type_header, &ct);
  186.         }
  187.  
  188.         error = handler->create(handler, effective_type,
  189.                         ct != NULL ? ct->parameters : NULL,
  190.                         llcache, fallback_charset, quirks,
  191.                         &c);
  192.  
  193.         if (ct != NULL)
  194.                 http_content_type_destroy(ct);
  195.  
  196.         if (error != NSERROR_OK)
  197.                 return NULL;
  198.  
  199.         return c;
  200. }
  201.  
  202.