NetSurf
filetype.c
Go to the documentation of this file.
1/*
2 * Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
3 * Copyright 2007 Vincent Sanders <vince@debian.org>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * \file
22 * file extension to mimetype mapping for the monkey frontend
23 *
24 * allows monkey frontend to map file extension to mime types using a
25 * default builtin list and /etc/mime.types file if present.
26 *
27 * mime type and content type handling is derived from the BNF in
28 * RFC822 section 3.3, RFC2045 section 5.1 and RFC6838 section
29 * 4.2. Upshot is their charset and parsing is all a strict subset of
30 * ASCII hence not using locale dependant ctype functions for parsing.
31 */
32
33#include <stdio.h>
34#include <stdbool.h>
35#include <stdint.h>
36#include <string.h>
37#include <strings.h>
38#include <stdlib.h>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <unistd.h>
42
43#include "utils/log.h"
44#include "utils/ascii.h"
45#include "utils/hashtable.h"
46
47#include "monkey/filetype.h"
48
49#define HASH_SIZE 117
50#define MAX_LINE_LEN 256
51
52static struct hash_table *mime_hash = NULL;
53
54void monkey_fetch_filetype_init(const char *mimefile)
55{
56 struct stat statbuf;
57 FILE *fh = NULL;
58
60
61 /* Some OSes (mentioning no Solarises) have a worthlessly tiny
62 * /etc/mime.types that don't include essential things, so we
63 * pre-seed our hash with the essentials. These will get
64 * over-ridden if they are mentioned in the mime.types file.
65 */
66
67 hash_add(mime_hash, "css", "text/css");
68 hash_add(mime_hash, "htm", "text/html");
69 hash_add(mime_hash, "html", "text/html");
70 hash_add(mime_hash, "jpg", "image/jpeg");
71 hash_add(mime_hash, "jpeg", "image/jpeg");
72 hash_add(mime_hash, "bmp", "image/bmp");
73 hash_add(mime_hash, "gif", "image/gif");
74 hash_add(mime_hash, "png", "image/png");
75 hash_add(mime_hash, "ico", "image/ico");
76 hash_add(mime_hash, "jng", "image/jng");
77 hash_add(mime_hash, "mng", "image/mng");
78 hash_add(mime_hash, "webp", "image/webp");
79 hash_add(mime_hash, "spr", "image/x-riscos-sprite");
80
81 /* first, check to see if /etc/mime.types in preference */
82 if ((stat("/etc/mime.types", &statbuf) == 0) &&
83 S_ISREG(statbuf.st_mode)) {
84 mimefile = "/etc/mime.types";
85
86 }
87
88 fh = fopen(mimefile, "r");
89
90 if (fh == NULL) {
91 NSLOG(netsurf, INFO,
92 "Unable to open a mime.types file, so using a minimal one for you.");
93 return;
94 }
95
96 while (!feof(fh)) {
97 char line[MAX_LINE_LEN], *ptr, *type, *ext;
98 if (fgets(line, MAX_LINE_LEN, fh) == NULL)
99 break;
100 if (!feof(fh) && line[0] != '#') {
101 ptr = line;
102
103 /* search for the first non-whitespace character */
104 while (ascii_is_space(*ptr))
105 ptr++;
106
107 /* is this line empty other than leading whitespace? */
108 if (*ptr == '\n' || *ptr == '\0')
109 continue;
110
111 type = ptr;
112
113 /* search for the first whitespace char or NUL or
114 * NL */
115 while (*ptr && (!ascii_is_space(*ptr)))
116 ptr++;
117
118 if (*ptr == '\0' || *ptr == '\n') {
119 /* this mimetype has no extensions - read next
120 * line.
121 */
122 continue;
123 }
124
125 *ptr++ = '\0';
126
127 /* search for the first non-whitespace character which
128 * will be the first filename extenion */
129 while (ascii_is_space(*ptr))
130 ptr++;
131
132 while(true) {
133 ext = ptr;
134
135 /* search for the first whitespace char or
136 * NUL or NL which is the end of the ext.
137 */
138 while (*ptr && (!ascii_is_space(*ptr)))
139 ptr++;
140
141 if (*ptr == '\0' || *ptr == '\n') {
142 /* special case for last extension on
143 * the line
144 */
145 *ptr = '\0';
146 hash_add(mime_hash, ext, type);
147 break;
148 }
149
150 *ptr++ = '\0';
151 hash_add(mime_hash, ext, type);
152
153 /* search for the first non-whitespace char or
154 * NUL or NL, to find start of next ext.
155 */
156 while (*ptr &&
157 (ascii_is_space(*ptr)) &&
158 *ptr != '\n') {
159 ptr++;
160 }
161 }
162 }
163 }
164
165 fclose(fh);
166}
167
169{
171}
172
173/**
174 * Determine the MIME type of a local file.
175 *
176 * @note used in file fetcher
177 *
178 * \param unix_path Unix style path to file on disk
179 * \return Pointer to static MIME type string (should not be freed) not NULL.
180 * invalidated on next call to fetch_filetype.
181 */
182const char *monkey_fetch_filetype(const char *unix_path)
183{
184 struct stat statbuf;
185 char *ext;
186 const char *ptr;
187 char *lowerchar;
188 const char *type;
189 int l;
190
191 if (stat(unix_path, &statbuf) != 0) {
192 /* error calling stat, the file has probably become
193 * inacessible, this routine cannot fail so just
194 * return the default mime type.
195 */
196 return "text/plain";
197 }
198 if (S_ISDIR(statbuf.st_mode)) {
199 return "application/x-netsurf-directory";
200 }
201
202 l = strlen(unix_path);
203 if ((3 < l) && (strcasecmp(unix_path + l - 4, ",f79") == 0)) {
204 return "text/css";
205 }
206
207 if (strchr(unix_path, '.') == NULL) {
208 /* no extension anywhere! */
209 return "text/plain";
210 }
211
212 ptr = unix_path + strlen(unix_path);
213 while (*ptr != '.' && *ptr != '/')
214 ptr--;
215
216 if (*ptr != '.') {
217 return "text/plain";
218 }
219
220 ext = strdup(ptr + 1); /* skip the . */
221
222 /* the hash table only contains lower-case versions - make sure this
223 * copy is lower case too.
224 */
225 lowerchar = ext;
226 while(*lowerchar) {
227 *lowerchar = ascii_to_lower(*lowerchar);
228 lowerchar++;
229 }
230
231 type = hash_get(mime_hash, ext);
232 free(ext);
233
234 return type != NULL ? type : "text/plain";
235}
Helpers for ASCII string handling.
static char ascii_to_lower(char c)
Convert an upper case character to lower case.
Definition: ascii.h:212
static bool ascii_is_space(char c)
Test whether a character is a whitespace character.
Definition: ascii.h:40
const char * type
Definition: filetype.cpp:44
struct hash_table * hash_create(unsigned int chains)
Create a new hash table.
Definition: hashtable.c:254
bool hash_add(struct hash_table *ht, const char *key, const char *value)
Adds a key/value pair to a hash table.
Definition: hashtable.c:303
void hash_destroy(struct hash_table *ht)
Destroys a hash table.
Definition: hashtable.c:278
const char * hash_get(struct hash_table *ht, const char *key)
Looks up a the value associated with with a key from a specific hash table.
Definition: hashtable.c:339
Interface to Write-Once hash table for string to string mapping.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
void monkey_fetch_filetype_fin(void)
Definition: filetype.c:168
void monkey_fetch_filetype_init(const char *mimefile)
Definition: filetype.c:54
#define MAX_LINE_LEN
Definition: filetype.c:50
const char * monkey_fetch_filetype(const char *unix_path)
Determine the MIME type of a local file.
Definition: filetype.c:182
static struct hash_table * mime_hash
Definition: filetype.c:52
#define HASH_SIZE
Definition: filetype.c:49
Interface to utility string handling.
static nserror line(const struct redraw_context *ctx, const plot_style_t *style, const struct rect *line)
Plots a line.
Definition: plot.c:579