Files
harbour-core/contrib/hbtip/mime.c
2017-09-11 19:56:57 +00:00

782 lines
43 KiB
C

/*
* TIP MIME functions
*
* Copyright 2003 Giancarlo Niccolai <gian@niccolai.ws>
*
* This program 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; either version 2, or (at your option)
* any later version.
*
* This program 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; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/* TODO: move to core and rename:
tip_FileMimeType() -> hb_mimeFile()
tip_FileNameMimeType() -> hb_mimeFName()
tip_MimeType() -> hb_mimeStr() */
#include "hbapi.h"
#include "hbapiitm.h"
#include "hbapierr.h"
#include "hbapifs.h"
/* Detects the MIME type of a given file */
typedef struct tag_mime
{
HB_SIZE pos; /* Position in stream from which the match begins */
const char * pattern; /* String to match */
const char * mime_type; /* MIME type if complete */
int next; /* following entry to determine a MIME type, relative to current position (or 0) */
int alternate; /* alternative entry to determine a MIME type, relative to current position (or 0) */
short unsigned int flags; /* flags for confrontation */
} MIME_ENTRY;
#define MIME_FLAG_CASESENS 0x0000
#define MIME_FLAG_TRIMSPACES 0x0001
#define MIME_FLAG_TRIMTABS 0x0002
#define MIME_FLAG_CASEINSENS 0x0004
#define MIME_FLAG_CONTINUE 0x0008
static const MIME_ENTRY s_mimeTable[] =
{
/* MS-DOS/Windows executable */
/* 0 */ { 0, "MZ", "application/x-dosexec", 0, 0, 0 },
/* ELF file */
/* 1 */ { 0, "\177ELF", NULL, 1, 0, 0 },
/* 2 */ { 4, "\x00", NULL, 3, 1, MIME_FLAG_CONTINUE },
/* 3 */ { 4, "\x01", NULL, 2, 1, MIME_FLAG_CONTINUE },
/* 4 */ { 4, "\x02", NULL, 1, 0, MIME_FLAG_CONTINUE },
/* 5 */ { 5, "\x00", NULL, 2, 1, MIME_FLAG_CONTINUE },
/* 6 */ { 5, "\x01", NULL, 1, 0, MIME_FLAG_CONTINUE },
/* 7 */ { 16, "\x00", "application/x-object", 0, 1, MIME_FLAG_CONTINUE },
/* 8 */ { 16, "\x01", "application/x-object", 0, 1, MIME_FLAG_CONTINUE },
/* 9 */ { 16, "\x02", "application/x-executable", 0, 1, MIME_FLAG_CONTINUE },
/* 10 */ { 16, "\x03", "application/x-sharedlib", 0, 1, MIME_FLAG_CONTINUE },
/* 11 */ { 16, "\x04", "application/x-coredump", 0, 0, MIME_FLAG_CONTINUE },
/* Shell script */
/* 12 */ { 0, "#!/bin/sh", "application/x-shellscript", 0, 0, 0 },
/* 13 */ { 0, "#! /bin/sh", "application/x-shellscript", 0, 0, 0 },
/* 14 */ { 0, "#!/bin/csh", "application/x-shellscript", 0, 0, 0 },
/* 15 */ { 0, "#! /bin/csh", "application/x-shellscript", 0, 0, 0 },
/* 16 */ { 0, "#!/bin/ksh", "application/x-shellscript", 0, 0, 0 },
/* 17 */ { 0, "#! /bin/ksh", "application/x-shellscript", 0, 0, 0 },
/* 18 */ { 0, "#!/bin/tcsh", "application/x-shellscript", 0, 0, 0 },
/* 19 */ { 0, "#! /bin/tcsh", "application/x-shellscript", 0, 0, 0 },
/* 20 */ { 0, "#!/usr/local/bin/tcsh", "application/x-shellscript", 0, 0, 0 },
/* 21 */ { 0, "#! /usr/local/bin/tcsh", "application/x-shellscript", 0, 0, 0 },
/* 22 */ { 0, "#!/bin/bash", "application/x-shellscript", 0, 0, 0 },
/* 23 */ { 0, "#! /bin/bash", "application/x-shellscript", 0, 0, 0 },
/* 24 */ { 0, "#!/usr/local/bin/bash", "application/x-shellscript", 0, 0, 0 },
/* 25 */ { 0, "#! /usr/local/bin/bash", "application/x-shellscript", 0, 0, 0 },
/* Java object code*/
/* 26 */ { 0, "\xCA\xFE\xBA\xBE", "application/java", 0, 0, 0 },
/* Perl */
/* 27 */ { 0, "#!/bin/perl", "application/x-perl", 0, 0, 0 },
/* 28 */ { 0, "#! /bin/perl", "application/x-perl", 0, 0, 0 },
/* 29 */ { 0, "eval \"exec /bin/perl", "application/x-perl", 0, 0, 0 },
/* 30 */ { 0, "#!/usr/bin/perl", "application/x-perl", 0, 0, 0 },
/* 31 */ { 0, "#! /usr/bin/perl", "application/x-perl", 0, 0, 0 },
/* 32 */ { 0, "eval \"exec /usr/bin/perl", "application/x-perl", 0, 0, 0 },
/* 33 */ { 0, "#!/usr/local/bin/perl", "application/x-perl", 0, 0, 0 },
/* 34 */ { 0, "#! /usr/local/bin/perl", "application/x-perl", 0, 0, 0 },
/* 35 */ { 0, "eval \"exec /usr/local/bin/perl", "application/x-perl", 0, 0, 0 },
/* Python */
/* 36 */ { 0, "#!/bin/python", "application/x-python", 0, 0, 0 },
/* 37 */ { 0, "#! /bin/python", "application/x-python", 0, 0, 0 },
/* 38 */ { 0, "eval \"exec /bin/python", "application/x-python", 0, 0, 0 },
/* 39 */ { 0, "#!/usr/bin/python", "application/x-python", 0, 0, 0 },
/* 40 */ { 0, "#! /usr/bin/python", "application/x-python", 0, 0, 0 },
/* 41 */ { 0, "eval \"exec /usr/bin/python", "application/x-python", 0, 0, 0 },
/* 42 */ { 0, "#!/usr/local/bin/python", "application/x-python", 0, 0, 0 },
/* 43 */ { 0, "#! /usr/local/bin/python", "application/x-python", 0, 0, 0 },
/* 44 */ { 0, "eval \"exec /usr/local/bin/python", "application/x-python", 0, 0, 0 },
/* Unix compress (.z) */
/* 45 */ { 0, "\x1F\x9D", "application/x-compress", 0, 0, 0 },
/* Unix gzip */
/* 46 */ { 0, "\x1F\x8B", "application/x-gzip", 0, 0, 0 },
/* PKzip */
/* 47 { 0, "PK\x03\x04", "application/x-zip", 0, 0, 0 }, 2010-12-15 support of xlsx/ods */
/* xml */
/* 48 */ { 0, "<?xml", "application/xml", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* html */
/* 49 */ { 0, "<html", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* 50 */ { 0, "<title", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* 51 */ { 0, "<head", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* 52 */ { 0, "<body", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* 53 */ { 0, "<!--", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS },
/* 54 */ { 0, "<h", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* 55 */ { 0, "<!", "text/html", 0, 0, MIME_FLAG_TRIMSPACES | MIME_FLAG_TRIMTABS | MIME_FLAG_CASEINSENS },
/* Postscript */
/* 56 */ { 0, "%!", "application/postscript", 0, 0, 0 },
/* 57 */ { 0, "\x04%!", "application/postscript", 0, 0, 0 },
/* PDF */
/* 58 */ { 0, "%PDF-", "application/pdf", 0, 0, 0 },
/* DVI */
/* 59 */ { 0, "\xF7\x02", "application/dvi", 0, 0, 0 },
/* PNG image */
/* 60 */ { 0, "\x89PNG", "image/png", 0, 0, 0 },
/* XPM image */
/* 61 */ { 0, "/* XPM", "image/x-xpm", 0, 0, 0 },
/* TIFF image */
/* 62 */ { 0, "II", "image/tiff", 0, 0, 0 },
/* 63 */ { 0, "MM", "image/tiff", 0, 0, 0 },
/* GIF image */
/* 64 */ { 0, "GIF89z", "image/x-compressed-gif", 0, 0, 0 },
/* 65 */ { 0, "GIF", "image/gif", 0, 0, 0 },
/* JPEG image */
/* 66 */ { 0, "\xFF\xD8", "image/jpeg", 0, 0, 0 },
/* ICO image */
/* 67 */ { 2, "\x01\x00", "image/x-icon", 0, 0, 0 },
/* OGG file */
/* 68 */ { 0, "OggS", "application/ogg", 0, 0, 0 },
/* FLV file */
/* 69 */ { 0, "FLV", "video/x-flv", 0, 0, 0 },
/* SWF compressed file */
/* 70 */ { 0, "CWS", "application/x-shockwave-flash", 0, 0, 0 },
/* SWF uncompressed file */
/* 71 */ { 0, "FWS", "application/x-shockwave-flash", 0, 0, 0 }
};
/* Find MIME by extension */
typedef struct tag_mime_ext
{
const char * pattern; /* Extension to match */
HB_USHORT flags; /* flags for confrontation */
const char * mime_type; /* MIME type if complete */
} EXT_MIME_ENTRY;
/* https://www.iana.org/assignments/media-types/media-types.xhtml */
/* keep this table well sorted, it's necessary for binary search algorithm */
static const EXT_MIME_ENTRY s_extMimeTable[] =
{
{ "3dm" , MIME_FLAG_CASEINSENS, "x-world/x-3dmf" },
{ "3dmf" , MIME_FLAG_CASEINSENS, "x-world/x-3dmf" },
{ "3gp" , MIME_FLAG_CASEINSENS, "video/3gpp" },
{ "3gpp" , MIME_FLAG_CASEINSENS, "video/3gpp" },
{ "7z" , MIME_FLAG_CASEINSENS, "application/x-7z-compressed" },
{ "aab" , MIME_FLAG_CASEINSENS, "application/x-authorware-bin" },
{ "aam" , MIME_FLAG_CASEINSENS, "application/x-authorware-map" },
{ "aas" , MIME_FLAG_CASEINSENS, "application/x-authorware-map" },
{ "adr" , MIME_FLAG_CASEINSENS, "application/x-msaddr" },
{ "afl" , MIME_FLAG_CASEINSENS, "video/animaflex" },
{ "ai" , MIME_FLAG_CASEINSENS, "application/postscript" },
{ "aif" , MIME_FLAG_CASEINSENS, "audio/x-aiff" },
{ "aifc" , MIME_FLAG_CASEINSENS, "audio/x-aiff" },
{ "aiff" , MIME_FLAG_CASEINSENS, "audio/x-aiff" },
{ "alt" , MIME_FLAG_CASEINSENS, "application/x-up-alert" },
{ "arj" , MIME_FLAG_CASEINSENS, "application/x-arj" },
{ "asc" , MIME_FLAG_CASEINSENS, "text/plain" },
{ "asd" , MIME_FLAG_CASEINSENS, "application/astound" },
{ "asf" , MIME_FLAG_CASEINSENS, "video/x-ms-asf" },
{ "asn" , MIME_FLAG_CASEINSENS, "application/astound" },
{ "asp" , MIME_FLAG_CASEINSENS, "application/x-asap" },
{ "asx" , MIME_FLAG_CASEINSENS, "video/x-ms-asf" },
{ "asz" , MIME_FLAG_CASEINSENS, "application/astound" },
{ "atom" , MIME_FLAG_CASEINSENS, "application/atom+xml" },
{ "au" , MIME_FLAG_CASEINSENS, "audio/basic" },
{ "avi" , MIME_FLAG_CASEINSENS, "video/x-msvideo" },
{ "axs" , MIME_FLAG_CASEINSENS, "application/olescript" },
{ "bcpio" , MIME_FLAG_CASEINSENS, "application/x-bcpio" },
{ "bin" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "bmp" , MIME_FLAG_CASEINSENS, "image/x-ms-bmp" },
{ "bz2" , MIME_FLAG_CASEINSENS, "application/x-bzip2" },
{ "c" , MIME_FLAG_CASEINSENS, "text/x-csrc" },
{ "c++" , MIME_FLAG_CASEINSENS, "text/x-c++src" },
{ "cco" , MIME_FLAG_CASEINSENS, "application/x-cocoa" },
{ "ccs" , MIME_FLAG_CASEINSENS, "text/ccs" },
{ "cdf" , MIME_FLAG_CASEINSENS, "application/x-netcdf" },
{ "chat" , MIME_FLAG_CASEINSENS, "application/x-chat" },
{ "che" , MIME_FLAG_CASEINSENS, "application/x-up-cacheop" },
{ "cht" , MIME_FLAG_CASEINSENS, "audio/x-dspeech" },
{ "class" , MIME_FLAG_CASESENS , "application/java-vm" },
{ "cnc" , MIME_FLAG_CASEINSENS, "application/x-cnc" },
{ "cod" , MIME_FLAG_CASEINSENS, "image/cis-cod" },
{ "coda" , MIME_FLAG_CASEINSENS, "application/x-coda" },
{ "con" , MIME_FLAG_CASEINSENS, "application/x-connector" },
{ "cpi" , MIME_FLAG_CASEINSENS, "image/cpi" },
{ "cpio" , MIME_FLAG_CASEINSENS, "application/x-cpio" },
{ "cpp" , MIME_FLAG_CASEINSENS, "text/x-c++src" },
{ "crt" , MIME_FLAG_CASEINSENS, "application/x-x509-ca-cert" },
{ "csh" , MIME_FLAG_CASEINSENS, "application/x-csh" },
{ "csm" , MIME_FLAG_CASEINSENS, "application/x-cu-seeme" },
{ "css" , MIME_FLAG_CASEINSENS, "text/css" },
{ "csv" , MIME_FLAG_CASEINSENS, "text/csv" },
{ "cu" , MIME_FLAG_CASEINSENS, "application/x-cu-seeme" },
{ "cxx" , MIME_FLAG_CASEINSENS, "text/x-c++src" },
{ "dbf" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "dcr" , MIME_FLAG_CASEINSENS, "application/x-director" },
{ "deb" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "der" , MIME_FLAG_CASEINSENS, "application/x-x509-ca-cert" },
{ "dig" , MIME_FLAG_CASEINSENS, "multipart/mixed" },
{ "dir" , MIME_FLAG_CASEINSENS, "application/x-director" },
{ "djv" , MIME_FLAG_CASEINSENS, "image/vnd.djvu" },
{ "djvu" , MIME_FLAG_CASEINSENS, "image/vnd.djvu" },
{ "dll" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "dmg" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "doc" , MIME_FLAG_CASEINSENS, "application/msword" },
{ "docx" , MIME_FLAG_CASEINSENS, "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
{ "dsf" , MIME_FLAG_CASEINSENS, "image/x-mgx-dsf" },
{ "dst" , MIME_FLAG_CASEINSENS, "application/tajima" },
{ "dus" , MIME_FLAG_CASEINSENS, "audio/x-dspeech" },
{ "dvi" , MIME_FLAG_CASEINSENS, "application/x-dvi" },
{ "dwf" , MIME_FLAG_CASEINSENS, "drawing/x-dwf" },
{ "dwg" , MIME_FLAG_CASEINSENS, "image/vnd" },
{ "dxf" , MIME_FLAG_CASEINSENS, "image/vnd" },
{ "dxr" , MIME_FLAG_CASEINSENS, "application/x-director" },
{ "ear" , MIME_FLAG_CASEINSENS, "application/java-archive" },
{ "ebk" , MIME_FLAG_CASEINSENS, "application/x-expandedbook" },
{ "eot" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "eps" , MIME_FLAG_CASEINSENS, "application/postscript" },
{ "es" , MIME_FLAG_CASEINSENS, "audio/echospeech" },
{ "etf" , MIME_FLAG_CASEINSENS, "image/x-etf" },
{ "etx" , MIME_FLAG_CASEINSENS, "text/x-setext" },
{ "evy" , MIME_FLAG_CASEINSENS, "application/x-envoy" },
{ "exe" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "fh4" , MIME_FLAG_CASEINSENS, "image/x-freehand" },
{ "fh5" , MIME_FLAG_CASEINSENS, "image/x-freehand" },
{ "fhc" , MIME_FLAG_CASEINSENS, "image/x-freehand" },
{ "fif" , MIME_FLAG_CASEINSENS, "image/fif" },
{ "flv" , MIME_FLAG_CASEINSENS, "video/x-flv" },
{ "fpx" , MIME_FLAG_CASEINSENS, "image/x-fpx" },
{ "frl" , MIME_FLAG_CASEINSENS, "application/freeloader" },
{ "gif" , MIME_FLAG_CASEINSENS, "image/gif" },
{ "gsd" , MIME_FLAG_CASEINSENS, "audio/gsm" },
{ "gsm" , MIME_FLAG_CASEINSENS, "audio/gsm" },
{ "gtar" , MIME_FLAG_CASEINSENS, "application/x-gtar" },
{ "gz" , MIME_FLAG_CASEINSENS, "application/x-gzip" },
{ "h" , MIME_FLAG_CASEINSENS, "text/x-chdr" },
{ "hdf" , MIME_FLAG_CASEINSENS, "application/x-hdf" },
{ "hdml" , MIME_FLAG_CASEINSENS, "text/x-hdml" },
{ "hpp" , MIME_FLAG_CASEINSENS, "text/x-c++hdr" },
{ "hqx" , MIME_FLAG_CASEINSENS, "application/mac-binhex40" },
{ "htc" , MIME_FLAG_CASEINSENS, "text/x-component" },
{ "htm" , MIME_FLAG_CASEINSENS, "text/html" },
{ "html" , MIME_FLAG_CASEINSENS, "text/html" },
{ "hxx" , MIME_FLAG_CASEINSENS, "text/x-c++hdr" },
{ "ica" , MIME_FLAG_CASEINSENS, "application/x-ica" },
{ "ico" , MIME_FLAG_CASEINSENS, "image/x-icon" },
{ "ics" , MIME_FLAG_CASEINSENS, "text/calendar" },
{ "ief" , MIME_FLAG_CASEINSENS, "image/ief" },
{ "img" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "ins" , MIME_FLAG_CASEINSENS, "application/x-NET-Install" },
{ "ips" , MIME_FLAG_CASEINSENS, "application/x-ipscript" },
{ "ipx" , MIME_FLAG_CASEINSENS, "application/x-ipix" },
{ "iso" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "ivr" , MIME_FLAG_CASEINSENS, "i-world/i-vrml" },
{ "jad" , MIME_FLAG_CASEINSENS, "text/vnd.sun.j2me.app-descriptor" },
{ "jar" , MIME_FLAG_CASEINSENS, "application/java-archive" },
{ "jardiff" , MIME_FLAG_CASEINSENS, "application/x-java-archive-diff" },
{ "java" , MIME_FLAG_CASESENS , "text/java" },
{ "jng" , MIME_FLAG_CASEINSENS, "image/x-jng" },
{ "jnlp" , MIME_FLAG_CASEINSENS, "application/x-java-jnlp-file" },
{ "jpe" , MIME_FLAG_CASEINSENS, "image/jpeg" },
{ "jpeg" , MIME_FLAG_CASEINSENS, "image/jpeg" },
{ "jpg" , MIME_FLAG_CASEINSENS, "image/jpeg" },
{ "js" , MIME_FLAG_CASEINSENS, "application/javascript" },
{ "kar" , MIME_FLAG_CASEINSENS, "audio/midi" },
{ "kml" , MIME_FLAG_CASEINSENS, "application/vnd.google-earth.kml+xml" },
{ "kmz" , MIME_FLAG_CASEINSENS, "application/vnd.google-earth.kmz" },
{ "latex" , MIME_FLAG_CASEINSENS, "application/x-latex" },
{ "lha" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "log" , MIME_FLAG_CASEINSENS, "text/plain" },
{ "lzh" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "lzx" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "m3u" , MIME_FLAG_CASEINSENS, "audio/x-mpegurl" },
{ "m4a" , MIME_FLAG_CASEINSENS, "audio/x-m4a" },
{ "m4v" , MIME_FLAG_CASEINSENS, "video/x-m4v" },
{ "man" , MIME_FLAG_CASEINSENS, "application/x-troff-man" },
{ "map" , MIME_FLAG_CASEINSENS, "application/x-httpd-imap" },
{ "markdown", MIME_FLAG_CASEINSENS, "text/x-markdown" },
{ "mbd" , MIME_FLAG_CASEINSENS, "application/mbedlet" },
{ "mcf" , MIME_FLAG_CASEINSENS, "image/vasa" },
{ "md" , MIME_FLAG_CASEINSENS, "text/x-markdown" },
{ "me" , MIME_FLAG_CASEINSENS, "application/x-troff-me" },
{ "mfp" , MIME_FLAG_CASEINSENS, "application/mirage" },
{ "mid" , MIME_FLAG_CASEINSENS, "audio/midi" },
{ "midi" , MIME_FLAG_CASEINSENS, "audio/midi" },
{ "mif" , MIME_FLAG_CASEINSENS, "application/x-mif" },
{ "mml" , MIME_FLAG_CASEINSENS, "text/mathml" },
{ "mng" , MIME_FLAG_CASEINSENS, "video/x-mng" },
{ "mol" , MIME_FLAG_CASEINSENS, "chemical/x-mdl-molfile" },
{ "mov" , MIME_FLAG_CASEINSENS, "video/quicktime" },
{ "movie" , MIME_FLAG_CASEINSENS, "video/x-sgi-movie" },
{ "mp2" , MIME_FLAG_CASEINSENS, "audio/x-mpeg" },
{ "mp3" , MIME_FLAG_CASEINSENS, "audio/mpeg" },
{ "mp4" , MIME_FLAG_CASEINSENS, "video/mp4" },
{ "mpe" , MIME_FLAG_CASEINSENS, "video/mpeg" },
{ "mpeg" , MIME_FLAG_CASEINSENS, "video/mpeg" },
{ "mpg" , MIME_FLAG_CASEINSENS, "video/mpeg" },
{ "mpire" , MIME_FLAG_CASEINSENS, "application/x-mpire" },
{ "mpl" , MIME_FLAG_CASEINSENS, "application/x-mpire" },
{ "ms" , MIME_FLAG_CASEINSENS, "application/x-troff-ms" },
{ "msi" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "msm" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "msp" , MIME_FLAG_CASEINSENS, "application/octet-stream" },
{ "n2p" , MIME_FLAG_CASEINSENS, "application/n2p" },
{ "nc" , MIME_FLAG_CASEINSENS, "application/x-netcdf" },
{ "npx" , MIME_FLAG_CASEINSENS, "application/x-netfpx" },
{ "nsc" , MIME_FLAG_CASEINSENS, "application/x-nschat" },
{ "oda" , MIME_FLAG_CASEINSENS, "application/oda" },
{ "odb" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.database" },
{ "odc" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.chart" },
{ "odf" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.formula" },
{ "odg" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.graphics" },
{ "odi" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.image" },
{ "odm" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.text-master" },
{ "odp" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.presentation" },
{ "ods" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.spreadsheet" },
{ "odt" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.text" },
{ "ofml" , MIME_FLAG_CASEINSENS, "application/fml" },
{ "ogg" , MIME_FLAG_CASEINSENS, "audio/ogg" },
{ "oth" , MIME_FLAG_CASEINSENS, "application/vnd.oasis.opendocument.text-web" },
{ "oxt" , MIME_FLAG_CASEINSENS, "application/vnd.openofficeorg.extension" },
{ "p7s" , MIME_FLAG_CASEINSENS, "application/pkcs7-signature" },
{ "page" , MIME_FLAG_CASEINSENS, "application/x-coda" },
{ "pbm" , MIME_FLAG_CASEINSENS, "image/x-portable-bitmap" },
{ "pdb" , MIME_FLAG_CASEINSENS, "application/x-pilot" },
{ "pdf" , MIME_FLAG_CASEINSENS, "application/pdf" },
{ "pem" , MIME_FLAG_CASEINSENS, "application/x-x509-ca-cert" },
{ "pfr" , MIME_FLAG_CASEINSENS, "application/font-tdpfr" },
{ "pgm" , MIME_FLAG_CASEINSENS, "image/x-portable-graymap" },
{ "pgp" , MIME_FLAG_CASEINSENS, "application/x-pgp-plugin" },
{ "pgr" , MIME_FLAG_CASEINSENS, "text/parsnegar-document" },
{ "php3" , MIME_FLAG_CASEINSENS, "application/x-httpd-php3" },
{ "phtml" , MIME_FLAG_CASEINSENS, "application/x-httpd-php" },
{ "pl" , MIME_FLAG_CASEINSENS, "application/x-perl" },
{ "pm" , MIME_FLAG_CASEINSENS, "application/x-perl" },
{ "png" , MIME_FLAG_CASEINSENS, "image/png" },
{ "pnm" , MIME_FLAG_CASEINSENS, "image/x-portable-anymap" },
{ "pot" , MIME_FLAG_CASEINSENS, "application/mspowerpoint" },
{ "ppm" , MIME_FLAG_CASEINSENS, "image/x-portable-pixmap" },
{ "pps" , MIME_FLAG_CASEINSENS, "application/mspowerpoint" },
{ "ppsx" , MIME_FLAG_CASEINSENS, "application/vnd.openxmlformats-officedocument.presentationml.slideshow" },
{ "ppt" , MIME_FLAG_CASEINSENS, "application/powerpoint" },
{ "pptx" , MIME_FLAG_CASEINSENS, "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
{ "ppz" , MIME_FLAG_CASEINSENS, "application/mspowerpoint" },
{ "pqf" , MIME_FLAG_CASEINSENS, "application/x-cprplayer" },
{ "pqi" , MIME_FLAG_CASEINSENS, "application/cprplayer" },
{ "prc" , MIME_FLAG_CASEINSENS, "application/x-pilot" },
{ "ps" , MIME_FLAG_CASEINSENS, "application/postscript" },
{ "ptlk" , MIME_FLAG_CASEINSENS, "application/listenup" },
{ "push" , MIME_FLAG_CASEINSENS, "multipart/x-mixed-replace" },
{ "qd3" , MIME_FLAG_CASEINSENS, "x-world/x-3dmf" },
{ "qd3d" , MIME_FLAG_CASEINSENS, "x-world/x-3dmf" },
{ "qrt" , MIME_FLAG_CASEINSENS, "application/quest" },
{ "qt" , MIME_FLAG_CASEINSENS, "video/quicktime" },
{ "ra" , MIME_FLAG_CASEINSENS, "audio/x-realaudio" },
{ "ram" , MIME_FLAG_CASEINSENS, "audio/x-realaudio" },
{ "rar" , MIME_FLAG_CASEINSENS, "application/x-rar-compressed" },
{ "ras" , MIME_FLAG_CASEINSENS, "image/x-cmu-raster" },
{ "rgb" , MIME_FLAG_CASEINSENS, "image/x-rgb" },
{ "rip" , MIME_FLAG_CASEINSENS, "image/rip" },
{ "rmf" , MIME_FLAG_CASEINSENS, "audio/x-rmf" },
{ "roff" , MIME_FLAG_CASEINSENS, "application/x-troff" },
{ "rpm" , MIME_FLAG_CASEINSENS, "application/x-redhat-package-manager" },
{ "rrf" , MIME_FLAG_CASEINSENS, "application/x-InstallFromTheWeb" },
{ "rss" , MIME_FLAG_CASEINSENS, "application/rss+xml" },
{ "rst" , MIME_FLAG_CASEINSENS, "text/plain" },
{ "rtc" , MIME_FLAG_CASEINSENS, "application/rtc" },
{ "rtf" , MIME_FLAG_CASEINSENS, "text/rtf" },
{ "rtx" , MIME_FLAG_CASEINSENS, "text/richtext" },
{ "run" , MIME_FLAG_CASEINSENS, "application/x-makeself" },
{ "sca" , MIME_FLAG_CASEINSENS, "application/x-supercard" },
{ "sea" , MIME_FLAG_CASEINSENS, "application/x-sea" },
{ "sh" , MIME_FLAG_CASEINSENS, "application/x-sh" },
{ "shar" , MIME_FLAG_CASEINSENS, "application/x-shar" },
{ "shtml" , MIME_FLAG_CASEINSENS, "text/html" },
{ "shw" , MIME_FLAG_CASEINSENS, "application/presentations" },
{ "sit" , MIME_FLAG_CASEINSENS, "application/x-stuffit" },
{ "sml" , MIME_FLAG_CASEINSENS, "application/fml" },
{ "smp" , MIME_FLAG_CASEINSENS, "application/studiom" },
{ "snd" , MIME_FLAG_CASEINSENS, "audio/basic" },
{ "spc" , MIME_FLAG_CASEINSENS, "text/x-speech" },
{ "spl" , MIME_FLAG_CASEINSENS, "application/futuresplash" },
{ "spr" , MIME_FLAG_CASEINSENS, "application/x-sprite" },
{ "sprite" , MIME_FLAG_CASEINSENS, "application/x-sprite" },
{ "src" , MIME_FLAG_CASEINSENS, "application/x-wais-source" },
{ "stk" , MIME_FLAG_CASEINSENS, "application/hstu" },
{ "stream" , MIME_FLAG_CASEINSENS, "audio/x-qt-stream" },
{ "sv4cpio" , MIME_FLAG_CASEINSENS, "application/x-sv4cpio" },
{ "sv4crc" , MIME_FLAG_CASEINSENS, "application/x-sv4crc" },
{ "svf" , MIME_FLAG_CASEINSENS, "image/vnd" },
{ "svg" , MIME_FLAG_CASEINSENS, "image/svg+xml" },
{ "svgz" , MIME_FLAG_CASEINSENS, "image/svg+xml" },
{ "svh" , MIME_FLAG_CASEINSENS, "image/svh" },
{ "svr" , MIME_FLAG_CASEINSENS, "x-world/x-svr" },
{ "swa" , MIME_FLAG_CASEINSENS, "application/x-director" },
{ "swf" , MIME_FLAG_CASEINSENS, "application/x-shockwave-flash" },
{ "t" , MIME_FLAG_CASEINSENS, "application/x-troff" },
{ "talk" , MIME_FLAG_CASEINSENS, "text/x-speech" },
{ "tar" , MIME_FLAG_CASEINSENS, "application/x-tar" },
{ "tbk" , MIME_FLAG_CASEINSENS, "application/toolbook" },
{ "tcl" , MIME_FLAG_CASEINSENS, "application/x-tcl" },
{ "tex" , MIME_FLAG_CASEINSENS, "application/x-tex" },
{ "texi" , MIME_FLAG_CASEINSENS, "application/x-texinfo" },
{ "texinfo" , MIME_FLAG_CASEINSENS, "application/x-texinfo" },
{ "text" , MIME_FLAG_CASEINSENS, "text/plain" },
{ "tgz" , MIME_FLAG_CASEINSENS, "application/x-gtar" },
{ "tif" , MIME_FLAG_CASEINSENS, "image/tiff" },
{ "tiff" , MIME_FLAG_CASEINSENS, "image/tiff" },
{ "tk" , MIME_FLAG_CASEINSENS, "application/x-tcl" },
{ "tlk" , MIME_FLAG_CASEINSENS, "application/x-tlk" },
{ "tmv" , MIME_FLAG_CASEINSENS, "application/x-Parable-Thing" },
{ "tr" , MIME_FLAG_CASEINSENS, "application/x-troff" },
{ "tsi" , MIME_FLAG_CASEINSENS, "audio/tsplayer" },
{ "tsp" , MIME_FLAG_CASEINSENS, "application/dsptype" },
{ "tsv" , MIME_FLAG_CASEINSENS, "text/tab-separated-values" },
{ "txt" , MIME_FLAG_CASEINSENS, "text/plain" },
{ "ustar" , MIME_FLAG_CASEINSENS, "application/x-ustar" },
{ "vbd" , MIME_FLAG_CASEINSENS, "application/activexdocument" },
{ "vcd" , MIME_FLAG_CASEINSENS, "application/x-cdlink" },
{ "vcf" , MIME_FLAG_CASEINSENS, "text/directory" },
{ "vgm" , MIME_FLAG_CASEINSENS, "video/x-videogram" },
{ "vgp" , MIME_FLAG_CASEINSENS, "video/x-videogram-plugin" },
{ "vgx" , MIME_FLAG_CASEINSENS, "video/x-videogram" },
{ "viv" , MIME_FLAG_CASEINSENS, "video/vnd.vivo" },
{ "vivo" , MIME_FLAG_CASEINSENS, "video/vnd.vivo" },
{ "vmd" , MIME_FLAG_CASEINSENS, "application/vocaltec-media-desc" },
{ "vmf" , MIME_FLAG_CASEINSENS, "application/vocaltec-media-file" },
{ "vox" , MIME_FLAG_CASEINSENS, "audio/voxware" },
{ "vqe" , MIME_FLAG_CASEINSENS, "audio/x-twinvq-plugin" },
{ "vqf" , MIME_FLAG_CASEINSENS, "audio/x-twinvq" },
{ "vql" , MIME_FLAG_CASEINSENS, "audio/x-twinvq" },
{ "vrt" , MIME_FLAG_CASEINSENS, "x-world/x-vrt" },
{ "vts" , MIME_FLAG_CASEINSENS, "workbook/formulaone" },
{ "vtts" , MIME_FLAG_CASEINSENS, "workbook/formulaone" },
{ "waf" , MIME_FLAG_CASEINSENS, "plugin/wanimate" },
{ "wan" , MIME_FLAG_CASEINSENS, "plugin/wanimate" },
{ "war" , MIME_FLAG_CASEINSENS, "application/java-archive" },
{ "wav" , MIME_FLAG_CASEINSENS, "audio/x-wav" },
{ "wbmp" , MIME_FLAG_CASEINSENS, "image/vnd.wap.wbmp" },
{ "webm" , MIME_FLAG_CASEINSENS, "video/webm" },
{ "webp" , MIME_FLAG_CASEINSENS, "image/webp" },
{ "wi" , MIME_FLAG_CASEINSENS, "image/wavelet" },
{ "wid" , MIME_FLAG_CASEINSENS, "application/x-DemoShield" },
{ "wis" , MIME_FLAG_CASEINSENS, "application/x-InstallShield" },
{ "wlt" , MIME_FLAG_CASEINSENS, "application/x-mswallet" },
{ "wml" , MIME_FLAG_CASEINSENS, "text/vnd.wap.wml" },
{ "wmlc" , MIME_FLAG_CASEINSENS, "application/vnd.wap.wmlc" },
{ "wmv" , MIME_FLAG_CASEINSENS, "video/x-ms-wmv" },
{ "wri" , MIME_FLAG_CASEINSENS, "application/write" },
{ "wrl" , MIME_FLAG_CASEINSENS, "x-world/x-vrml" },
{ "wrz" , MIME_FLAG_CASEINSENS, "x-world/x-vrml" },
{ "wtx" , MIME_FLAG_CASEINSENS, "audio/x-wtx" },
{ "xbm" , MIME_FLAG_CASEINSENS, "image/x-xbitmap" },
{ "xdr" , MIME_FLAG_CASEINSENS, "video/x-videogram" },
{ "xhtml" , MIME_FLAG_CASEINSENS, "application/xhtml+xml" },
{ "xls" , MIME_FLAG_CASEINSENS, "application/excel" },
{ "xlsx" , MIME_FLAG_CASEINSENS, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
{ "xlt" , MIME_FLAG_CASEINSENS, "application/xlt" },
{ "xml" , MIME_FLAG_CASEINSENS, "application/xml" },
{ "xpi" , MIME_FLAG_CASEINSENS, "application/x-xpinstall" },
{ "xpm" , MIME_FLAG_CASEINSENS, "image/x-xpixmap" },
{ "xwd" , MIME_FLAG_CASEINSENS, "image/x-xwindowdump" },
{ "z" , MIME_FLAG_CASEINSENS, "application/x-compress" },
{ "zip" , MIME_FLAG_CASEINSENS, "application/zip" },
{ "zpa" , MIME_FLAG_CASEINSENS, "application/pcphoto" }
};
static const char * s_findExtMimeType( const char * szFileExt )
{
HB_UINT uiFirst = 0, uiLast = HB_SIZEOFARRAY( s_extMimeTable );
char szExt[ 16 ];
if( *szFileExt == '.' )
++szFileExt;
hb_strncpyLower( szExt, szFileExt, sizeof( szExt ) - 1 );
do
{
HB_UINT uiMiddle;
int i;
uiMiddle = ( uiFirst + uiLast ) >> 1;
i = strcmp( szExt, s_extMimeTable[ uiMiddle ].pattern );
if( i == 0 )
{
if( s_extMimeTable[ uiMiddle ].flags == MIME_FLAG_CASEINSENS ||
strcmp( szExt, szFileExt ) == 0 )
return s_extMimeTable[ uiMiddle ].mime_type;
break;
}
else if( i < 0 )
uiLast = uiMiddle;
else /* if( i > 0 ) */
uiFirst = uiMiddle + 1;
}
while( uiFirst < uiLast );
return NULL;
}
static const char * s_findMimeStringInTree( const char * cData, HB_SIZE nLen, int iElem )
{
const MIME_ENTRY * elem = s_mimeTable + iElem;
HB_SIZE nPos = elem->pos;
HB_SIZE nDataLen = strlen( elem->pattern );
/* allow \0 to be used for matches */
if( nDataLen == 0 )
nDataLen = 1;
/* trim spaces if required */
while( nPos < nLen &&
( ( ( elem->flags & MIME_FLAG_TRIMSPACES ) != 0 && (
cData[ nPos ] == ' ' || cData[ nPos ] == '\r' || cData[ nPos ] == '\n' ) ) ||
( ( elem->flags & MIME_FLAG_TRIMTABS ) != 0 && cData[ nPos ] == '\t' ) ) )
{
nPos++;
}
if( nPos < nLen && ( nLen - nPos ) >= nDataLen )
{
if( ( elem->flags & MIME_FLAG_CASEINSENS ) != 0 )
{
if( ( *elem->pattern == 0 && cData[ nPos ] == 0 ) || hb_strnicmp( cData + nPos, elem->pattern, nDataLen ) == 0 )
{
/* is this the begin of a match tree? */
if( elem->next != 0 )
return s_findMimeStringInTree( cData, nLen, iElem + elem->next );
else
return elem->mime_type;
}
}
else
{
if( ( *elem->pattern == 0 && cData[ nPos ] == 0 ) || strncmp( cData + nPos, elem->pattern, nDataLen ) == 0 )
{
if( elem->next != 0 )
return s_findMimeStringInTree( cData, nLen, iElem + elem->next );
else
return elem->mime_type;
}
}
}
/* match failed! */
if( elem->alternate != 0 )
return s_findMimeStringInTree( cData, nLen, iElem + elem->alternate );
return NULL; /* give up */
}
static const char * s_findStringMimeType( const char * cData, HB_SIZE nLen )
{
unsigned int uiCount;
for( uiCount = 0; uiCount < HB_SIZEOFARRAY( s_mimeTable ); uiCount++ )
{
const MIME_ENTRY * elem = s_mimeTable + uiCount;
HB_SIZE nPos = elem->pos;
HB_SIZE nDataLen = ( HB_SIZE ) strlen( elem->pattern );
if( ( elem->flags & MIME_FLAG_CONTINUE ) != 0 )
continue;
/* trim spaces if required */
while( nPos < nLen &&
( ( ( elem->flags & MIME_FLAG_TRIMSPACES ) != 0 && (
cData[ nPos ] == ' ' || cData[ nPos ] == '\r' || cData[ nPos ] == '\n' ) ) ||
( ( elem->flags & MIME_FLAG_TRIMTABS ) != 0 && cData[ nPos ] == '\t' ) ) )
{
nPos++;
}
if( nPos >= nLen )
continue;
if( nLen - nPos < nDataLen )
continue;
if( ( elem->flags & MIME_FLAG_CASEINSENS ) != 0 )
{
if( ( *elem->pattern == 0 && cData[ nPos ] == 0 ) || hb_strnicmp( cData + nPos, elem->pattern, nDataLen ) == 0 )
{
/* is this the begin of a match tree? */
if( elem->next != 0 )
return s_findMimeStringInTree( cData, nLen, uiCount + elem->next );
else
return elem->mime_type;
}
}
else
{
if( ( *elem->pattern == 0 && cData[ nPos ] == 0 ) || strncmp( cData + nPos, elem->pattern, nDataLen ) == 0 )
{
if( elem->next != 0 )
return s_findMimeStringInTree( cData, nLen, uiCount + elem->next );
else
return elem->mime_type;
}
}
}
return NULL;
}
static const char * s_findFileMimeType( PHB_FILE fileIn )
{
char buf[ 512 ];
HB_FOFFSET nPos = hb_fileSeek( fileIn, 0, FS_RELATIVE );
HB_SIZE nLen = hb_fileResult( hb_fileReadAt( fileIn, buf, sizeof( buf ), 0 ) );
if( nLen > 0 )
{
hb_fileSeek( fileIn, nPos, FS_SET );
return s_findStringMimeType( buf, nLen );
}
return NULL;
}
HB_FUNC( TIP_MIMETYPE )
{
PHB_ITEM pData = hb_param( 1, HB_IT_STRING );
if( pData )
{
const char * magic_type = s_findStringMimeType( hb_itemGetCPtr( pData ), hb_itemGetCLen( pData ) );
if( magic_type )
hb_retc_const( magic_type );
else if( HB_ISCHAR( 2 ) )
hb_retc( hb_parc( 2 ) );
else
hb_retc_const( "unknown" ); /* FIXME: change to "application/unknown" */
}
else
hb_errRT_BASE_SubstR( EG_ARG, 0, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( TIP_FILENAMEMIMETYPE )
{
const char * fname = hb_parc( 1 );
if( fname )
{
PHB_FNAME pFileName = hb_fsFNameSplit( fname );
const char * ext_type = pFileName->szExtension ? s_findExtMimeType( pFileName->szExtension ) : NULL;
hb_xfree( pFileName );
if( ext_type )
hb_retc_const( ext_type );
else if( HB_ISCHAR( 2 ) )
hb_retc( hb_parc( 2 ) );
else
hb_retc_const( "unknown" ); /* FIXME: change to "application/unknown" */
}
else
hb_errRT_BASE_SubstR( EG_ARG, 0, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( TIP_FILEMIMETYPE )
{
PHB_ITEM pFile = hb_param( 1, HB_IT_STRING | HB_IT_POINTER | HB_IT_NUMERIC );
if( pFile )
{
const char * ext_type = NULL;
const char * magic_type = NULL;
if( HB_IS_STRING( pFile ) )
{
const char * fname = hb_itemGetCPtr( pFile );
PHB_FNAME pFileName = hb_fsFNameSplit( fname );
PHB_FILE fileIn;
ext_type = pFileName->szExtension ? s_findExtMimeType( pFileName->szExtension ) : NULL;
hb_xfree( pFileName );
if( ( fileIn = hb_fileExtOpen( fname, NULL,
FO_READ | FO_SHARED | FO_PRIVATE |
FXO_SHARELOCK,
NULL, NULL ) ) != NULL )
{
magic_type = s_findFileMimeType( fileIn );
hb_fileClose( fileIn );
}
}
else if( hb_fileItemGet( pFile ) )
magic_type = s_findFileMimeType( hb_fileItemGet( pFile ) );
else
{
PHB_FILE fileIn = hb_fileFromHandle( hb_numToHandle( hb_itemGetNInt( pFile ) ) );
magic_type = s_findFileMimeType( fileIn );
hb_fileDetach( fileIn );
}
if( magic_type )
hb_retc_const( magic_type );
else if( ext_type )
hb_retc_const( ext_type );
else if( HB_ISCHAR( 2 ) )
hb_retc( hb_parc( 2 ) );
else
hb_retc_const( "unknown" ); /* FIXME: change to "application/unknown" */
}
else
hb_errRT_BASE_SubstR( EG_ARG, 0, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}