diff options
-rw-r--r-- | riscos/filetype.c | 169 |
1 files changed, 101 insertions, 68 deletions
diff --git a/riscos/filetype.c b/riscos/filetype.c index 13b2f9aca..9ff9b0df2 100644 --- a/riscos/filetype.c +++ b/riscos/filetype.c @@ -17,47 +17,28 @@ #include "netsurf/utils/log.h" #include "netsurf/utils/utils.h" -/* type_map must be in sorted order by file_type */ -struct type_entry { - bits file_type; - char mime_type[40]; -}; -static const struct type_entry type_map[] = { - {0x188, "application/x-shockwave-flash"}, - {0x695, "image/gif"}, - {0xaff, "image/x-drawfile"}, - {0xb60, "image/png"}, - {0xc85, "image/jpeg"}, - {0xf78, "image/jng"}, - {0xf79, "text/css"}, - {0xf83, "image/mng"}, - {0xfaf, "text/html"}, - {0xff9, "image/x-riscos-sprite"}, - {0xfff, "text/plain"}, -}; -#define TYPE_MAP_COUNT (sizeof(type_map) / sizeof(type_map[0])) - - -static int cmp_type(const void *x, const void *y); - +#define BUF_SIZE (256) +static char type_buf[BUF_SIZE]; /** * Determine the MIME type of a local file. + * + * \param unix_path Unix style path to file on disk + * \return Pointer to MIME type string (should not be freed) - invalidated + * on next call to fetch_filetype. */ - const char *fetch_filetype(const char *unix_path) { - struct type_entry *t; unsigned int len = strlen(unix_path) + 100; char *path = calloc(len, 1); - char *r; + char *r, *slash; os_error *error; - bits file_type; + bits file_type, temp; if (!path) { - LOG(("Insuficient memory for calloc")); - warn_user("NoMemory", 0); - return "application/riscos"; + LOG(("Insufficient memory for calloc")); + warn_user("NoMemory", 0); + return "application/riscos"; } LOG(("unix_path = '%s'", unix_path)); @@ -65,69 +46,121 @@ const char *fetch_filetype(const char *unix_path) r = __riscosify(unix_path, 0, __RISCOSIFY_NO_SUFFIX, path, len, 0); if (r == 0) { LOG(("__riscosify failed")); + free(path); return "application/riscos"; } LOG(("riscos path '%s'", path)); error = xosfile_read_stamped_no_path(path, 0, 0, 0, 0, 0, &file_type); - if (error != 0) { - LOG(("xosfile_read_stamped_no_path failed: %s", error->errmess)); + if (error) { + LOG(("xosfile_read_stamped_no_path failed: %s", + error->errmess)); + free(path); return "application/riscos"; } - /* search for MIME type */ - t = bsearch(&file_type, type_map, TYPE_MAP_COUNT, sizeof(type_map[0]), cmp_type); - if (t == 0) + /* If filetype is text and the file has an extension, try to map the + * extension to a filetype via the MimeMap file. */ + if (file_type == osfile_TYPE_TEXT) { + slash = strrchr(path, '/'); + if (slash) { + error = xmimemaptranslate_extension_to_filetype( + slash+1, &temp); + if (error) + /* ignore error and leave file_type alone */ + LOG(("0x%x %s", + error->errnum, error->errmess)); + else + file_type = temp; + } + } + + error = xmimemaptranslate_filetype_to_mime_type(file_type, type_buf); + if (error) { + LOG(("0x%x %s", error->errnum, error->errmess)); + free(path); return "application/riscos"; - LOG(("mime type '%s'", t->mime_type)); - return t->mime_type; -} + } + /* make sure we're NULL terminated. If we're not, the MimeMap + * module's probably written past the end of the buffer from + * SVC mode. Short of rewriting MimeMap with an incompatible API, + * there's nothing we can do about it. + */ + type_buf[BUF_SIZE - 1] = '\0'; + free(path); -char *fetch_mimetype(const char *ro_path) { + LOG(("mime type '%s'", type_buf)); + return (const char *)type_buf; - os_error *e; - bits filetype = 0, load; - int objtype; - char *mime = calloc(256, sizeof(char)); +} + +/** + * Find a MIME type for a local file + * + * \param ro_path RISC OS style path to file on disk + * \return MIME type string (on heap, caller should free), or NULL + */ +char *fetch_mimetype(const char *ro_path) +{ + os_error *e; + bits filetype = 0, load; + int objtype; + char *mime = calloc(BUF_SIZE, sizeof(char)); + char *slash; if (!mime) { - LOG(("Insuficient memory for calloc")); - warn_user("NoMemory", 0); - return 0; + LOG(("Insufficient memory for calloc")); + warn_user("NoMemory", 0); + return 0; } - e = xosfile_read_no_path(ro_path, &objtype, &load, 0, 0, 0); - if (e) return 0; - - if (objtype == 0x2) return 0; /* directories are pointless */ - - if ((load >> 20) & 0xFFF) { - filetype = (load>>8) & 0x000FFF; - } - else { - return 0; /* no idea */ - } + e = xosfile_read_no_path(ro_path, &objtype, &load, 0, 0, 0); + if (e) + return 0; - e = xmimemaptranslate_filetype_to_mime_type(filetype, mime); - if (e) return 0; + if (objtype == osfile_IS_DIR) + return 0; /* directories are pointless */ - return mime; -} + if ((load >> 20) & 0xFFF) { + filetype = (load>>8) & 0x000FFF; + } + else { + return 0; /* no idea */ + } + /* If filetype is text and the file has an extension, try to map the + * extension to a filetype via the MimeMap file. */ + slash = strrchr(ro_path, '/'); + if (slash && filetype == osfile_TYPE_TEXT) { + e = xmimemaptranslate_extension_to_filetype(slash+1, &load); + if (e) + /* if we get an error here, simply ignore it and + * leave filetype unchanged */ + LOG(("0x%x %s", e->errnum, e->errmess)); + else + filetype = load; + } -int cmp_type(const void *x, const void *y) -{ - const bits *p = x; - const struct type_entry *q = y; - return *p < q->file_type ? -1 : (*p == q->file_type ? 0 : +1); + e = xmimemaptranslate_filetype_to_mime_type(filetype, mime); + if (e) + return 0; + /* make sure we're NULL terminated. If we're not, the MimeMap + * module's probably written past the end of the buffer from + * SVC mode. Short of rewriting MimeMap with an incompatible API, + * there's nothing we can do about it. + */ + mime[BUF_SIZE - 1] = '\0'; + + return mime; } - /** * Determine the RISC OS filetype for a content. + * + * \param content The content to examine. + * \return The RISC OS filetype corresponding to the content */ - int ro_content_filetype(struct content *content) { int file_type; |