NetSurf
filetype.c
Go to the documentation of this file.
1/*
2 * Copyright 2008, 2011 Chris Young <chris@unsatisfactorysoftware.co.uk>
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#include "amiga/os3support.h"
20
21#include <stdlib.h>
22#include <string.h>
23#include <proto/icon.h>
24#include <proto/dos.h>
25#include <proto/datatypes.h>
26#include <proto/exec.h>
27#include <workbench/icon.h>
28
29#include "netsurf/content.h"
30#include "utils/log.h"
31#include "utils/utils.h"
32
33#include "amiga/filetype.h"
34#include "amiga/object.h"
35
36/**
37 * filetype -- determine the MIME type of a local file
38 */
39
40static struct MinList *ami_mime_list = NULL;
41
43{
44 lwc_string *mimetype;
45 lwc_string *datatype;
46 lwc_string *filetype;
47 lwc_string *plugincmd;
48};
49
50enum
51{
56};
57
58const char *fetch_filetype(const char *unix_path)
59{
60 static char mimetype[50];
61 struct DiskObject *dobj = NULL;
62 struct DataType *dtn;
63 BOOL found = FALSE;
64 lwc_string *lwc_mimetype;
65
66 /* First, check if we appear to have an icon.
67 We'll just do a filename check here for quickness, although the
68 first word ought to be checked against WB_DISKMAGIC really. */
69
70 if(strncmp(unix_path + strlen(unix_path) - 5, ".info", 5) == 0) {
71 strcpy(mimetype,"image/x-amiga-icon");
72 found = TRUE;
73 }
74
75
76 /* Secondly try getting a tooltype "MIMETYPE" and use that as the MIME type.
77 Will fail over to default icons if the file doesn't have a real icon. */
78
79 if(!found) {
80 if((dobj = GetIconTags(unix_path,ICONGETA_FailIfUnavailable,FALSE,
81 TAG_DONE))) {
82 STRPTR ttype = NULL;
83 ttype = FindToolType(dobj->do_ToolTypes, "MIMETYPE");
84 if(ttype) {
85 strcpy(mimetype,ttype);
86 found = TRUE;
87 }
88 FreeDiskObject(dobj);
89 }
90 }
91
92 /* If that didn't work, use the MIME file and DataTypes */
93
94 if(!found) {
95 BPTR lock;
96 if ((lock = Lock(unix_path, ACCESS_READ))) {
97 if ((dtn = ObtainDataTypeA (DTST_FILE, (APTR)lock, NULL))) {
98 if(ami_mime_from_datatype(dtn, &lwc_mimetype, NULL)) {
99 strcpy(mimetype, lwc_string_data(lwc_mimetype));
100 found = TRUE;
101 ReleaseDataType(dtn);
102 }
103 }
104 UnLock(lock);
105 }
106 }
107
108 /* Have a quick check for file extensions (inc RISC OS filetype).
109 * Makes detection a little more robust, and some of the redirects
110 * caused by links in the SVN tree prevent NetSurf from reading the
111 * MIME type from the icon (step two, above).
112 */
113
114 if((!found) || (strcmp("text/plain", mimetype) == 0))
115 {
116 if((strncmp(unix_path + strlen(unix_path) - 4, ".css", 4) == 0) ||
117 (strncmp(unix_path + strlen(unix_path) - 4, ",f79", 4) == 0))
118 {
119 strcpy(mimetype,"text/css");
120 found = TRUE;
121 }
122
123 if((strncmp(unix_path + strlen(unix_path) - 4, ".htm", 4) == 0) ||
124 (strncmp(unix_path + strlen(unix_path) - 5, ".html", 5) == 0) ||
125 (strncmp(unix_path + strlen(unix_path) - 4, ",faf", 4) == 0))
126 {
127 strcpy(mimetype,"text/html");
128 found = TRUE;
129 }
130 if(strncmp(unix_path + strlen(unix_path) - 3, ".js", 3) == 0) {
131 strcpy(mimetype,"application/javascript");
132 found = TRUE;
133 }
134 }
135
136 if(!found) strcpy(mimetype,"text/plain"); /* If all else fails */
137
138 return mimetype;
139}
140
142{
143 switch(type)
144 {
145 case CONTENT_HTML:
146 return "html";
147 break;
148
150 return "ascii";
151 break;
152
153 case CONTENT_CSS:
154 return "css";
155 break;
156
157 case CONTENT_IMAGE:
158 return "picture";
159 break;
160
161 default:
162 return "project";
163 break;
164 }
165}
166
167static void ami_mime_entry_free(void *nso)
168{
169 struct ami_mime_entry *mimeentry = (struct ami_mime_entry *)nso;
170
171 if(mimeentry->mimetype) lwc_string_unref(mimeentry->mimetype);
172 if(mimeentry->datatype) lwc_string_unref(mimeentry->datatype);
173 if(mimeentry->filetype) lwc_string_unref(mimeentry->filetype);
174 if(mimeentry->plugincmd) lwc_string_unref(mimeentry->plugincmd);
175}
176
177nserror ami_mime_init(const char *mimefile)
178{
179 lwc_error lerror;
180 char buffer[256];
181 BPTR fh = 0;
182 struct RDArgs *rargs = NULL;
183 CONST_STRPTR template = "MIMETYPE/A,DT=DATATYPE/K,TYPE=DEFICON/K,CMD=PLUGINCMD/K";
184 long rarray[] = {0,0,0,0};
185 struct nsObject *node;
186 struct ami_mime_entry *mimeentry;
187
188 NSLOG(netsurf, INFO, "mimetypes file: %s", mimefile);
189
190 if(ami_mime_list == NULL)
192
193 rargs = AllocDosObjectTags(DOS_RDARGS,TAG_DONE);
194 if(rargs == NULL) return NSERROR_NOMEM;
195
196 if((fh = FOpen(mimefile, MODE_OLDFILE, 0)))
197 {
198 while((FGets(fh, (STRPTR)&buffer, 256) != 0))
199 {
200 rargs->RDA_Source.CS_Buffer = (char *)&buffer;
201 rargs->RDA_Source.CS_Length = 256;
202 rargs->RDA_Source.CS_CurChr = 0;
203
204 rargs->RDA_DAList = NULL;
205 rargs->RDA_Buffer = NULL;
206 rargs->RDA_BufSiz = 0;
207 rargs->RDA_ExtHelp = NULL;
208 rargs->RDA_Flags = 0;
209
210 rarray[AMI_MIME_MIMETYPE] = 0;
211 rarray[AMI_MIME_DATATYPE] = 0;
212 rarray[AMI_MIME_FILETYPE] = 0;
213 rarray[AMI_MIME_PLUGINCMD] = 0;
214
215 if(ReadArgs(template, rarray, rargs))
216 {
217 if ((node = AddObject(ami_mime_list, AMINS_MIME))) {
219 mimeentry = calloc(1, sizeof(struct ami_mime_entry));
220 node->objstruct = mimeentry;
221
222 if(rarray[AMI_MIME_MIMETYPE])
223 {
224 lerror = lwc_intern_string((char *)rarray[AMI_MIME_MIMETYPE],
225 strlen((char *)rarray[AMI_MIME_MIMETYPE]), &mimeentry->mimetype);
226 if (lerror != lwc_error_ok)
227 return NSERROR_NOMEM;
228 }
229
230 if(rarray[AMI_MIME_DATATYPE])
231 {
232 lerror = lwc_intern_string((char *)rarray[AMI_MIME_DATATYPE],
233 strlen((char *)rarray[AMI_MIME_DATATYPE]), &mimeentry->datatype);
234 if (lerror != lwc_error_ok)
235 return NSERROR_NOMEM;
236 }
237
238 if(rarray[AMI_MIME_FILETYPE])
239 {
240 lerror = lwc_intern_string((char *)rarray[AMI_MIME_FILETYPE],
241 strlen((char *)rarray[AMI_MIME_FILETYPE]), &mimeentry->filetype);
242 if (lerror != lwc_error_ok)
243 return NSERROR_NOMEM;
244 }
245
246 if(rarray[AMI_MIME_PLUGINCMD])
247 {
248 lerror = lwc_intern_string((char *)rarray[AMI_MIME_PLUGINCMD],
249 strlen((char *)rarray[AMI_MIME_PLUGINCMD]), &mimeentry->plugincmd);
250 if (lerror != lwc_error_ok)
251 return NSERROR_NOMEM;
252 }
253 }
254 FreeArgs(rargs);
255 }
256 }
257 FClose(fh);
258 }
259 FreeDosObject(DOS_RDARGS, rargs);
260
261 return NSERROR_OK;
262}
263
265{
268}
269
270/**
271 * Return next matching MIME entry
272 *
273 * \param search lwc_string to search for (or NULL for all)
274 * \param type of value being searched for (AMI_MIME_#?)
275 * \param start_node node to continue search (updated on exit)
276 * \return entry or NULL if no match
277 */
278
279static struct ami_mime_entry *ami_mime_entry_locate(lwc_string *search,
280 int type, struct Node **start_node)
281{
282 struct nsObject *node;
283 struct nsObject *nnode;
284 struct ami_mime_entry *mimeentry;
285 lwc_error lerror;
286 bool ret = false;
287
288 if(IsMinListEmpty(ami_mime_list)) return NULL;
289
290 if(*start_node)
291 {
292 node = (struct nsObject *)GetSucc(*start_node);
293 if(node == NULL) return NULL;
294 }
295 else
296 {
297 node = (struct nsObject *)GetHead((struct List *)ami_mime_list);
298 }
299
300 do
301 {
302 nnode=(struct nsObject *)GetSucc((struct Node *)node);
303 mimeentry = node->objstruct;
304
305 lerror = lwc_error_ok;
306
307 switch(type)
308 {
310 if(search != NULL)
311 lerror = lwc_string_isequal(mimeentry->mimetype, search, &ret);
312 else if(mimeentry->mimetype != NULL)
313 ret = true;
314 break;
315
317 if(search != NULL)
318 lerror = lwc_string_isequal(mimeentry->datatype, search, &ret);
319 else if(mimeentry->datatype != NULL)
320 ret = true;
321 break;
322
324 if(search != NULL)
325 lerror = lwc_string_isequal(mimeentry->filetype, search, &ret);
326 else if(mimeentry->filetype != NULL)
327 ret = true;
328 break;
329
331 if(search != NULL)
332 lerror = lwc_string_isequal(mimeentry->plugincmd, search, &ret);
333 else if(mimeentry->plugincmd != NULL)
334 ret = true;
335 break;
336 }
337
338 if((lerror == lwc_error_ok) && (ret == true))
339 break;
340
341 } while((node=nnode));
342
343 *start_node = (struct Node *)node;
344
345 if(ret == true) return mimeentry;
346 else return NULL;
347}
348
349
350static APTR ami_mime_guess_add_datatype(struct DataType *dt, lwc_string **lwc_mimetype)
351{
352 struct nsObject *node;
353 char mimetype[100];
354 char *dt_name_lwr = NULL;
355 struct ami_mime_entry *mimeentry;
356 lwc_error lerror;
357 struct DataTypeHeader *dth = dt->dtn_Header;
358 char *p;
359
361 if(node == NULL) return NULL;
362
363 mimeentry = calloc(1, sizeof(struct ami_mime_entry));
364 if(mimeentry == NULL) return NULL;
365
366 node->objstruct = mimeentry;
368
369 lerror = lwc_intern_string(dth->dth_Name, strlen(dth->dth_Name), &mimeentry->datatype);
370 if (lerror != lwc_error_ok)
371 return NULL;
372
373 dt_name_lwr = strdup(dth->dth_Name);
374 if(dt_name_lwr == NULL) return NULL;
375
376 strlwr(dt_name_lwr);
377 p = dt_name_lwr;
378
379 while(*p != '\0')
380 {
381 if(*p == ' ') *p = '-';
382 if(*p == '/') *p = '-';
383 p++;
384 }
385
386 switch(dth->dth_GroupID)
387 {
388 case GID_TEXT:
389 case GID_DOCUMENT:
390 if(strcmp("ascii", dt_name_lwr)==0)
391 {
392 strcpy(mimetype,"text/plain");
393 }
394 else
395 {
396 sprintf(mimetype,"text/%s", dt_name_lwr);
397 }
398 break;
399 case GID_SOUND:
400 case GID_INSTRUMENT:
401 case GID_MUSIC:
402 sprintf(mimetype,"audio/%s", dt_name_lwr);
403 break;
404 case GID_PICTURE:
405 if(strcmp("sprite", dt_name_lwr)==0)
406 {
407 strcpy(mimetype,"image/x-riscos-sprite");
408 }
409 else
410 {
411 sprintf(mimetype,"image/%s", dt_name_lwr);
412 }
413 break;
414 case GID_ANIMATION:
415 case GID_MOVIE:
416 sprintf(mimetype,"video/%s", dt_name_lwr);
417 break;
418 case GID_SYSTEM:
419 default:
420 if(strcmp("directory", dt_name_lwr)==0)
421 {
422 strcpy(mimetype,"application/x-netsurf-directory");
423 }
424 else if(strcmp("binary", dt_name_lwr)==0)
425 {
426 strcpy(mimetype,"application/octet-stream");
427 }
428 else sprintf(mimetype,"application/%s", dt_name_lwr);
429 break;
430 }
431
432 lerror = lwc_intern_string(mimetype, strlen(mimetype), &mimeentry->mimetype);
433 if (lerror != lwc_error_ok)
434 return NULL;
435
436 *lwc_mimetype = mimeentry->mimetype;
437
438 lerror = lwc_intern_string(dt_name_lwr, strlen(dt_name_lwr), &mimeentry->filetype);
439 if (lerror != lwc_error_ok)
440 return NULL;
441
442 free(dt_name_lwr);
443 return node;
444}
445
446/**
447 * Return a MIME Type matching a DataType
448 *
449 * \param dt a DataType structure
450 * \param mimetype lwc_string to hold the MIME type
451 * \param start_node node to feed back in to continue search
452 * \return node or NULL if no match
453 */
454
455struct Node *ami_mime_from_datatype(struct DataType *dt,
456 lwc_string **mimetype, struct Node *start_node)
457{
458 struct DataTypeHeader *dth;
459 struct Node *node;
460 struct ami_mime_entry *mimeentry;
461 lwc_string *dt_name;
462 lwc_error lerror;
463
464 if(dt == NULL) return NULL;
465
466 dth = dt->dtn_Header;
467 lerror = lwc_intern_string(dth->dth_Name, strlen(dth->dth_Name), &dt_name);
468 if (lerror != lwc_error_ok)
469 return NULL;
470
471 node = start_node;
472 mimeentry = ami_mime_entry_locate(dt_name, AMI_MIME_DATATYPE, &node);
473 lwc_string_unref(dt_name);
474
475 if(mimeentry != NULL)
476 {
477 *mimetype = mimeentry->mimetype;
478 return (struct Node *)node;
479 }
480 else
481 {
482 if(start_node == NULL)
483 {
484 /* If there are no matching entries in the file, guess */
485 return ami_mime_guess_add_datatype(dt, mimetype);
486 }
487 else
488 {
489 return NULL;
490 }
491 }
492}
493
494/**
495 * Return the DefIcons type matching a MIME type
496 *
497 * \param mimetype lwc_string MIME type
498 * \param filetype ptr to lwc_string to hold DefIcons type
499 * \param start_node node to feed back in to continue search
500 * \return node or NULL if no match
501 */
502
503struct Node *ami_mime_to_filetype(lwc_string *mimetype,
504 lwc_string **filetype, struct Node *start_node)
505{
506 struct Node *node;
507 struct ami_mime_entry *mimeentry;
508
509 node = start_node;
510 mimeentry = ami_mime_entry_locate(mimetype, AMI_MIME_MIMETYPE, &node);
511
512 if(mimeentry != NULL)
513 {
514 *filetype = mimeentry->filetype;
515 return (struct Node *)node;
516 }
517 else
518 {
519 return NULL;
520 }
521}
522
524{
525 struct Node *node;
526 lwc_string *filetype;
527 lwc_string *mimetype;
528
529 mimetype = content_get_mime_type(c);
530
531 node = ami_mime_to_filetype(mimetype, &filetype, NULL);
532
533 if(node && (filetype != NULL))
534 return lwc_string_data(filetype);
535 else
537}
538
539/**
540 * Return all MIME types containing a plugincmd
541 *
542 * \param mimetype ptr to lwc_string MIME type
543 * \param start_node node to feed back in to continue search
544 * \return node or NULL if no match
545 */
546
547struct Node *ami_mime_has_cmd(lwc_string **mimetype, struct Node *start_node)
548{
549 struct Node *node;
550 struct ami_mime_entry *mimeentry;
551
552 node = start_node;
553 mimeentry = ami_mime_entry_locate(NULL, AMI_MIME_PLUGINCMD, &node);
554
555 if(mimeentry != NULL)
556 {
557 *mimetype = mimeentry->mimetype;
558 return (struct Node *)node;
559 }
560 else
561 {
562 return NULL;
563 }
564}
565
566/**
567 * Return the plugincmd matching a MIME type
568 *
569 * \param mimetype lwc_string MIME type
570 * \param plugincmd ptr to lwc_string to hold plugincmd
571 * \param start_node node to feed back in to continue search
572 * \return node or NULL if no match
573 */
574
575static struct Node *ami_mime_to_plugincmd(lwc_string *mimetype,
576 lwc_string **plugincmd, struct Node *start_node)
577{
578 struct Node *node;
579 struct ami_mime_entry *mimeentry;
580
581 node = start_node;
582 mimeentry = ami_mime_entry_locate(mimetype, AMI_MIME_MIMETYPE, &node);
583
584 if(mimeentry != NULL)
585 {
586 *plugincmd = mimeentry->plugincmd;
587 return (struct Node *)node;
588 }
589 else
590 {
591 return NULL;
592 }
593}
594
596{
597 struct Node *node;
598 lwc_string *plugincmd;
599 lwc_string *mimetype;
600
601 mimetype = content_get_mime_type(c);
602
603 node = ami_mime_to_plugincmd(mimetype,
604 &plugincmd, NULL);
605
606 if(node && (plugincmd != NULL)) return plugincmd;
607 else return NULL;
608}
609
610/**
611 * Compare the MIME type of an hlcache_handle to a DefIcons type
612 */
613
614bool ami_mime_compare(struct hlcache_handle *c, const char *type)
615{
616 bool ret = false;
617 lwc_error lerror;
618 lwc_string *filetype;
619 lwc_string *mime_filetype;
620 lwc_string *mime = content_get_mime_type(c);
621
622 if(ami_mime_to_filetype(mime, &mime_filetype, NULL) == NULL)
623 return false;
624
625 lerror = lwc_intern_string(type, strlen(type), &filetype);
626 if (lerror != lwc_error_ok)
627 return false;
628
629 lerror = lwc_string_isequal(filetype, mime_filetype, &ret);
630 if (lerror != lwc_error_ok)
631 return false;
632
633 lwc_string_unref(filetype);
634
635 return ret;
636}
637
638
640{
641 struct Node *node = NULL;
642 struct ami_mime_entry *mimeentry;
643
644 while((mimeentry = ami_mime_entry_locate(NULL, AMI_MIME_MIMETYPE, &node))) {
645 NSLOG(netsurf, INFO, "%s DT=\"%s\" TYPE=\"%s\" CMD=\"%s\"",
646 mimeentry->mimetype ? lwc_string_data(mimeentry->mimetype) : "",
647 mimeentry->datatype ? lwc_string_data(mimeentry->datatype) : "",
648 mimeentry->filetype ? lwc_string_data(mimeentry->filetype) : "",
649 mimeentry->plugincmd ? lwc_string_data(mimeentry->plugincmd) : "");
650 };
651}
static struct MinList * ami_mime_list
filetype – determine the MIME type of a local file
Definition: filetype.c:40
static struct Node * ami_mime_to_plugincmd(lwc_string *mimetype, lwc_string **plugincmd, struct Node *start_node)
Return the plugincmd matching a MIME type.
Definition: filetype.c:575
const char * ami_content_type_to_file_type(content_type type)
Definition: filetype.c:141
void ami_mime_free(void)
Definition: filetype.c:264
lwc_string * ami_mime_content_to_cmd(struct hlcache_handle *c)
Definition: filetype.c:595
static APTR ami_mime_guess_add_datatype(struct DataType *dt, lwc_string **lwc_mimetype)
Definition: filetype.c:350
const char * fetch_filetype(const char *unix_path)
Determine the MIME type of a local file.
Definition: filetype.c:58
struct Node * ami_mime_from_datatype(struct DataType *dt, lwc_string **mimetype, struct Node *start_node)
Return a MIME Type matching a DataType.
Definition: filetype.c:455
nserror ami_mime_init(const char *mimefile)
Definition: filetype.c:177
@ AMI_MIME_MIMETYPE
Definition: filetype.c:52
@ AMI_MIME_PLUGINCMD
Definition: filetype.c:55
@ AMI_MIME_FILETYPE
Definition: filetype.c:54
@ AMI_MIME_DATATYPE
Definition: filetype.c:53
static struct ami_mime_entry * ami_mime_entry_locate(lwc_string *search, int type, struct Node **start_node)
Return next matching MIME entry.
Definition: filetype.c:279
struct Node * ami_mime_to_filetype(lwc_string *mimetype, lwc_string **filetype, struct Node *start_node)
Return the DefIcons type matching a MIME type.
Definition: filetype.c:503
void ami_mime_dump(void)
Definition: filetype.c:639
bool ami_mime_compare(struct hlcache_handle *c, const char *type)
Compare the MIME type of an hlcache_handle to a DefIcons type.
Definition: filetype.c:614
static void ami_mime_entry_free(void *nso)
Definition: filetype.c:167
const char * ami_mime_content_to_filetype(struct hlcache_handle *c)
Definition: filetype.c:523
struct Node * ami_mime_has_cmd(lwc_string **mimetype, struct Node *start_node)
Return all MIME types containing a plugincmd.
Definition: filetype.c:547
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
content_type
The type of a content.
Definition: content_type.h:53
@ CONTENT_IMAGE
All images.
Definition: content_type.h:67
@ CONTENT_CSS
content is CSS
Definition: content_type.h:64
@ CONTENT_HTML
content is HTML
Definition: content_type.h:58
@ CONTENT_TEXTPLAIN
content is plain text
Definition: content_type.h:61
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
struct MinList * NewObjList(void)
Definition: object.c:71
void FreeObjList(struct MinList *objlist)
Definition: object.c:117
void ObjectCallback(struct nsObject *dtzo, void(*callback)(void *nso))
Definition: object.c:92
struct nsObject * AddObject(struct MinList *objlist, ULONG otype)
Definition: object.c:77
@ AMINS_MIME
Definition: object.h:38
Public content interface.
lwc_string * content_get_mime_type(struct hlcache_handle *h)
Retrieve mime-type of content.
Definition: content.c:1073
content_type content_get_type(struct hlcache_handle *h)
Retrieve computed type of content.
Definition: content.c:1061
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
char * strlwr(char *str)
Definition: os3support.c:160
struct Node * GetHead(struct List *list)
Definition: os3support.c:364
struct Node * GetSucc(struct Node *node)
Definition: os3support.c:381
Minimal compatibility header for AmigaOS 3.
#define FOpen(A, B, C)
Definition: os3support.h:158
#define IsMinListEmpty(L)
Definition: os3support.h:54
#define FClose(A)
Definition: os3support.h:159
Interface to utility string handling.
Definition: filetype.c:43
lwc_string * mimetype
Definition: filetype.c:44
lwc_string * filetype
Definition: filetype.c:46
lwc_string * plugincmd
Definition: filetype.c:47
lwc_string * datatype
Definition: filetype.c:45
High-level cache handle.
Definition: hlcache.c:66
void * objstruct
Definition: object.h:46
Interface to a number of general purpose functionality.