/*
 *  Copyright (C) 2012-2018 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#include <algorithm>

#include "Mime.h"
#include "FileItem.h"
#include "URIUtils.h"
#include "music/tags/MusicInfoTag.h"
#include "video/VideoInfoTag.h"
#include "URL.h"
#include "utils/StringUtils.h"
#include "filesystem/CurlFile.h"

const std::map<std::string, std::string> CMime::m_mimetypes = 
    {{{"3dm",       "x-world/x-3dmf"},
      {"3dmf",      "x-world/x-3dmf"},
      {"a",         "application/octet-stream"},
      {"aab",       "application/x-authorware-bin"},
      {"aam",       "application/x-authorware-map"},
      {"aas",       "application/x-authorware-seg"},
      {"abc",       "text/vnd.abc"},
      {"acgi",      "text/html"},
      {"afl",       "video/animaflex"},
      {"ai",        "application/postscript"},
      {"aif",       "audio/aiff"},
      {"aifc",      "audio/x-aiff"},
      {"aiff",      "audio/aiff"},
      {"aim",       "application/x-aim"},
      {"aip",       "text/x-audiosoft-intra"},
      {"ani",       "application/x-navi-animation"},
      {"aos",       "application/x-nokia-9000-communicator-add-on-software"},
      {"apng",      "image/apng"},
      {"aps",       "application/mime"},
      {"arc",       "application/octet-stream"},
      {"arj",       "application/arj"},
      {"art",       "image/x-jg"},
      {"arw",       "image/arw"},
      {"asf",       "video/x-ms-asf"},
      {"asm",       "text/x-asm"},
      {"asp",       "text/asp"},
      {"asx",       "video/x-ms-asf"},
      {"au",        "audio/basic"},
      {"avi",       "video/avi"},
      {"avs",       "video/avs-video"},
      {"bcpio",     "application/x-bcpio"},
      {"bin",       "application/octet-stream"},
      {"bm",        "image/bmp"},
      {"bmp",       "image/bmp"},
      {"boo",       "application/book"},
      {"book",      "application/book"},
      {"boz",       "application/x-bzip2"},
      {"bsh",       "application/x-bsh"},
      {"bz",        "application/x-bzip"},
      {"bz2",       "application/x-bzip2"},
      {"c",         "text/plain"},
      {"c++",       "text/plain"},
      {"cat",       "application/vnd.ms-pki.seccat"},
      {"cc",        "text/plain"},
      {"ccad",      "application/clariscad"},
      {"cco",       "application/x-cocoa"},
      {"cdf",       "application/cdf"},
      {"cer",       "application/pkix-cert"},
      {"cer",       "application/x-x509-ca-cert"},
      {"cha",       "application/x-chat"},
      {"chat",      "application/x-chat"},
      {"class",     "application/java"},
      {"com",       "application/octet-stream"},
      {"conf",      "text/plain"},
      {"cpio",      "application/x-cpio"},
      {"cpp",       "text/x-c"},
      {"cpt",       "application/x-cpt"},
      {"crl",       "application/pkcs-crl"},
      {"crt",       "application/pkix-cert"},
      {"cr2",       "image/cr2"},
      {"csh",       "application/x-csh"},
      {"css",       "text/css"},
      {"cxx",       "text/plain"},
      {"dcr",       "application/x-director"},
      {"deepv",     "application/x-deepv"},
      {"def",       "text/plain"},
      {"der",       "application/x-x509-ca-cert"},
      {"dif",       "video/x-dv"},
      {"dir",       "application/x-director"},
      {"dl",        "video/dl"},
      {"divx",      "video/x-msvideo"},
      {"dng",       "image/dng"},
      {"doc",       "application/msword"},
      {"docx",      "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
      {"dot",       "application/msword"},
      {"dp",        "application/commonground"},
      {"drw",       "application/drafting"},
      {"dump",      "application/octet-stream"},
      {"dv",        "video/x-dv"},
      {"dvi",       "application/x-dvi"},
      {"dwf",       "model/vnd.dwf"},
      {"dwg",       "image/vnd.dwg"},
      {"dxf",       "image/vnd.dwg"},
      {"dxr",       "application/x-director"},
      {"el",        "text/x-script.elisp"},
      {"elc",       "application/x-elc"},
      {"env",       "application/x-envoy"},
      {"eps",       "application/postscript"},
      {"es",        "application/x-esrehber"},
      {"etx",       "text/x-setext"},
      {"evy",       "application/envoy"},
      {"exe",       "application/octet-stream"},
      {"f",         "text/x-fortran"},
      {"f77",       "text/x-fortran"},
      {"f90",       "text/x-fortran"},
      {"fdf",       "application/vnd.fdf"},
      {"fif",       "image/fif"},
      {"flac",      "audio/flac"},
      {"fli",       "video/fli"},
      {"flo",       "image/florian"},
      {"flv",       "video/x-flv"},
      {"flx",       "text/vnd.fmi.flexstor"},
      {"fmf",       "video/x-atomic3d-feature"},
      {"for",       "text/plain"},
      {"for",       "text/x-fortran"},
      {"fpx",       "image/vnd.fpx"},
      {"frl",       "application/freeloader"},
      {"funk",      "audio/make"},
      {"g",         "text/plain"},
      {"g3",        "image/g3fax"},
      {"gif",       "image/gif"},
      {"gl",        "video/x-gl"},
      {"gsd",       "audio/x-gsm"},
      {"gsm",       "audio/x-gsm"},
      {"gsp",       "application/x-gsp"},
      {"gss",       "application/x-gss"},
      {"gtar",      "application/x-gtar"},
      {"gz",        "application/x-compressed"},
      {"gzip",      "application/x-gzip"},
      {"h",         "text/plain"},
      {"hdf",       "application/x-hdf"},
      {"heic",      "image/heic"},
      {"heif",      "image/heif"},
      {"help",      "application/x-helpfile"},
      {"hgl",       "application/vnd.hp-hpgl"},
      {"hh",        "text/plain"},
      {"hlb",       "text/x-script"},
      {"hlp",       "application/hlp"},
      {"hpg",       "application/vnd.hp-hpgl"},
      {"hpgl",      "application/vnd.hp-hpgl"},
      {"hqx",       "application/binhex"},
      {"hta",       "application/hta"},
      {"htc",       "text/x-component"},
      {"htm",       "text/html"},
      {"html",      "text/html"},
      {"htmls",     "text/html"},
      {"htt",       "text/webviewhtml"},
      {"htx",       "text/html"},
      {"ice",       "x-conference/x-cooltalk"},
      {"ico",       "image/x-icon"},
      {"idc",       "text/plain"},
      {"ief",       "image/ief"},
      {"iefs",      "image/ief"},
      {"iges",      "application/iges"},
      {"igs",       "application/iges"},
      {"ima",       "application/x-ima"},
      {"imap",      "application/x-httpd-imap"},
      {"inf",       "application/inf"},
      {"ins",       "application/x-internet-signup"},
      {"ip",        "application/x-ip2"},
      {"isu",       "video/x-isvideo"},
      {"it",        "audio/it"},
      {"iv",        "application/x-inventor"},
      {"ivr",       "i-world/i-vrml"},
      {"ivy",       "application/x-livescreen"},
      {"jam",       "audio/x-jam"},
      {"jav",       "text/x-java-source"},
      {"java",      "text/x-java-source"},
      {"jcm",       "application/x-java-commerce"},
      {"jfif",      "image/jpeg"},
      {"jp2",       "image/jp2"},
      {"jfif-tbnl", "image/jpeg"},
      {"jpe",       "image/jpeg"},
      {"jpeg",      "image/jpeg"},
      {"jpg",       "image/jpeg"},
      {"jps",       "image/x-jps"},
      {"js",        "application/javascript"},
      {"json",      "application/json"},
      {"jut",       "image/jutvision"},
      {"kar",       "music/x-karaoke"},
      {"ksh",       "text/x-script.ksh"},
      {"la",        "audio/nspaudio"},
      {"lam",       "audio/x-liveaudio"},
      {"latex",     "application/x-latex"},
      {"lha",       "application/lha"},
      {"lhx",       "application/octet-stream"},
      {"list",      "text/plain"},
      {"lma",       "audio/nspaudio"},
      {"log",       "text/plain"},
      {"lsp",       "application/x-lisp"},
      {"lst",       "text/plain"},
      {"lsx",       "text/x-la-asf"},
      {"ltx",       "application/x-latex"},
      {"lzh",       "application/x-lzh"},
      {"lzx",       "application/lzx"},
      {"m",         "text/x-m"},
      {"m1v",       "video/mpeg"},
      {"m2a",       "audio/mpeg"},
      {"m2v",       "video/mpeg"},
      {"m3u",       "audio/x-mpegurl"},
      {"man",       "application/x-troff-man"},
      {"map",       "application/x-navimap"},
      {"mar",       "text/plain"},
      {"mbd",       "application/mbedlet"},
      {"mc$",       "application/x-magic-cap-package-1.0"},
      {"mcd",       "application/x-mathcad"},
      {"mcf",       "text/mcf"},
      {"mcp",       "application/netmc"},
      {"me",        "application/x-troff-me"},
      {"mht",       "message/rfc822"},
      {"mhtml",     "message/rfc822"},
      {"mid",       "audio/midi"},
      {"midi",      "audio/midi"},
      {"mif",       "application/x-mif"},
      {"mime",      "message/rfc822"},
      {"mjf",       "audio/x-vnd.audioexplosion.mjuicemediafile"},
      {"mjpg",      "video/x-motion-jpeg"},
      {"mka",       "audio/x-matroska"},
      {"mkv",       "video/x-matroska"},
      {"mk3d",      "video/x-matroska-3d"},
      {"mm",        "application/x-meme"},
      {"mme",       "application/base64"},
      {"mod",       "audio/mod"},
      {"moov",      "video/quicktime"},
      {"mov",       "video/quicktime"},
      {"movie",     "video/x-sgi-movie"},
      {"mp2",       "audio/mpeg"},
      {"mp3",       "audio/mpeg3"},
      {"mp4",       "video/mp4"},
      {"mpa",       "audio/mpeg"},
      {"mpc",       "application/x-project"},
      {"mpe",       "video/mpeg"},
      {"mpeg",      "video/mpeg"},
      {"mpg",       "video/mpeg"},
      {"mpga",      "audio/mpeg"},
      {"mpp",       "application/vnd.ms-project"},
      {"mpt",       "application/x-project"},
      {"mpv",       "application/x-project"},
      {"mpx",       "application/x-project"},
      {"mrc",       "application/marc"},
      {"ms",        "application/x-troff-ms"},
      {"mv",        "video/x-sgi-movie"},
      {"my",        "audio/make"},
      {"mzz",       "application/x-vnd.audioexplosion.mzz"},
      {"nap",       "image/naplps"},
      {"naplps",    "image/naplps"},
      {"nc",        "application/x-netcdf"},
      {"ncm",       "application/vnd.nokia.configuration-message"},
      {"nef",       "image/nef"},
      {"nfo",       "text/xml"},
      {"nif",       "image/x-niff"},
      {"niff",      "image/x-niff"},
      {"nix",       "application/x-mix-transfer"},
      {"nsc",       "application/x-conference"},
      {"nvd",       "application/x-navidoc"},
      {"o",         "application/octet-stream"},
      {"oda",       "application/oda"},
      {"ogg",       "audio/ogg"},
      {"omc",       "application/x-omc"},
      {"omcd",      "application/x-omcdatamaker"},
      {"omcr",      "application/x-omcregerator"},
      {"p",         "text/x-pascal"},
      {"p10",       "application/pkcs10"},
      {"p12",       "application/pkcs-12"},
      {"p7a",       "application/x-pkcs7-signature"},
      {"p7c",       "application/pkcs7-mime"},
      {"p7m",       "application/pkcs7-mime"},
      {"p7r",       "application/x-pkcs7-certreqresp"},
      {"p7s",       "application/pkcs7-signature"},
      {"part",      "application/pro_eng"},
      {"pas",       "text/pascal"},
      {"pbm",       "image/x-portable-bitmap"},
      {"pcl",       "application/vnd.hp-pcl"},
      {"pct",       "image/x-pict"},
      {"pcx",       "image/x-pcx"},
      {"pdb",       "chemical/x-pdb"},
      {"pdf",       "application/pdf"},
      {"pfunk",     "audio/make.my.funk"},
      {"pgm",       "image/x-portable-greymap"},
      {"pic",       "image/pict"},
      {"pict",      "image/pict"},
      {"pkg",       "application/x-newton-compatible-pkg"},
      {"pko",       "application/vnd.ms-pki.pko"},
      {"pl",        "text/x-script.perl"},
      {"plx",       "application/x-pixclscript"},
      {"pm",        "text/x-script.perl-module"},
      {"pm4",       "application/x-pagemaker"},
      {"pm5",       "application/x-pagemaker"},
      {"png",       "image/png"},
      {"pnm",       "application/x-portable-anymap"},
      {"pot",       "application/vnd.ms-powerpoint"},
      {"pov",       "model/x-pov"},
      {"ppa",       "application/vnd.ms-powerpoint"},
      {"ppm",       "image/x-portable-pixmap"},
      {"pps",       "application/mspowerpoint"},
      {"ppt",       "application/mspowerpoint"},
      {"ppz",       "application/mspowerpoint"},
      {"pre",       "application/x-freelance"},
      {"prt",       "application/pro_eng"},
      {"ps",        "application/postscript"},
      {"psd",       "application/octet-stream"},
      {"pvu",       "paleovu/x-pv"},
      {"pwz",       "application/vnd.ms-powerpoint"},
      {"py",        "text/x-script.phyton"},
      {"pyc",       "application/x-bytecode.python"},
      {"qcp",       "audio/vnd.qcelp"},
      {"qd3",       "x-world/x-3dmf"},
      {"qd3d",      "x-world/x-3dmf"},
      {"qif",       "image/x-quicktime"},
      {"qt",        "video/quicktime"},
      {"qtc",       "video/x-qtc"},
      {"qti",       "image/x-quicktime"},
      {"qtif",      "image/x-quicktime"},
      {"ra",        "audio/x-realaudio"},
      {"ram",       "audio/x-pn-realaudio"},
      {"ras",       "image/cmu-raster"},
      {"rast",      "image/cmu-raster"},
      {"rexx",      "text/x-script.rexx"},
      {"rf",        "image/vnd.rn-realflash"},
      {"rgb",       "image/x-rgb"},
      {"rm",        "audio/x-pn-realaudio"},
      {"rmi",       "audio/mid"},
      {"rmm",       "audio/x-pn-realaudio"},
      {"rmp",       "audio/x-pn-realaudio"},
      {"rng",       "application/ringing-tones"},
      {"rnx",       "application/vnd.rn-realplayer"},
      {"roff",      "application/x-troff"},
      {"rp",        "image/vnd.rn-realpix"},
      {"rpm",       "audio/x-pn-realaudio-plugin"},
      {"rt",        "text/richtext"},
      {"rtf",       "text/richtext"},
      {"rtx",       "text/richtext"},
      {"rv",        "video/vnd.rn-realvideo"},
      {"s",         "text/x-asm"},
      {"s3m",       "audio/s3m"},
      {"saveme",    "application/octet-stream"},
      {"sbk",       "application/x-tbook"},
      {"scm",       "video/x-scm"},
      {"sdml",      "text/plain"},
      {"sdp",       "application/sdp"},
      {"sdr",       "application/sounder"},
      {"sea",       "application/sea"},
      {"set",       "application/set"},
      {"sgm",       "text/sgml"},
      {"sgml",      "text/sgml"},
      {"sh",        "text/x-script.sh"},
      {"shar",      "application/x-bsh"},
      {"shtml",     "text/x-server-parsed-html"},
      {"sid",       "audio/x-psid"},
      {"sit",       "application/x-stuffit"},
      {"skd",       "application/x-koan"},
      {"skm",       "application/x-koan"},
      {"skp",       "application/x-koan"},
      {"skt",       "application/x-koan"},
      {"sl",        "application/x-seelogo"},
      {"smi",       "application/smil"},
      {"smil",      "application/smil"},
      {"snd",       "audio/basic"},
      {"sol",       "application/solids"},
      {"spc",       "text/x-speech"},
      {"spl",       "application/futuresplash"},
      {"spr",       "application/x-sprite"},
      {"sprite",    "application/x-sprite"},
      {"src",       "application/x-wais-source"},
      {"ssi",       "text/x-server-parsed-html"},
      {"ssm",       "application/streamingmedia"},
      {"sst",       "application/vnd.ms-pki.certstore"},
      {"step",      "application/step"},
      {"stl",       "application/sla"},
      {"stp",       "application/step"},
      {"sup",       "application/x-pgs"},
      {"sv4cpio",   "application/x-sv4cpio"},
      {"sv4crc",    "application/x-sv4crc"},
      {"svf",       "image/vnd.dwg"},
      {"svr",       "application/x-world"},
      {"swf",       "application/x-shockwave-flash"},
      {"t",         "application/x-troff"},
      {"talk",      "text/x-speech"},
      {"tar",       "application/x-tar"},
      {"tbk",       "application/toolbook"},
      {"tcl",       "text/x-script.tcl"},
      {"tcsh",      "text/x-script.tcsh"},
      {"tex",       "application/x-tex"},
      {"texi",      "application/x-texinfo"},
      {"texinfo",   "application/x-texinfo"},
      {"text",      "text/plain"},
      {"tgz",       "application/x-compressed"},
      {"tif",       "image/tiff"},
      {"tiff",      "image/tiff"},
      {"tr",        "application/x-troff"},
      {"ts",        "video/mp2t"},
      {"tsi",       "audio/tsp-audio"},
      {"tsp",       "audio/tsplayer"},
      {"tsv",       "text/tab-separated-values"},
      {"turbot",    "image/florian"},
      {"txt",       "text/plain"},
      {"uil",       "text/x-uil"},
      {"uni",       "text/uri-list"},
      {"unis",      "text/uri-list"},
      {"unv",       "application/i-deas"},
      {"uri",       "text/uri-list"},
      {"uris",      "text/uri-list"},
      {"ustar",     "application/x-ustar"},
      {"uu",        "text/x-uuencode"},
      {"uue",       "text/x-uuencode"},
      {"vcd",       "application/x-cdlink"},
      {"vcs",       "text/x-vcalendar"},
      {"vda",       "application/vda"},
      {"vdo",       "video/vdo"},
      {"vew",       "application/groupwise"},
      {"viv",       "video/vivo"},
      {"vivo",      "video/vivo"},
      {"vmd",       "application/vocaltec-media-desc"},
      {"vmf",       "application/vocaltec-media-file"},
      {"voc",       "audio/voc"},
      {"vos",       "video/vosaic"},
      {"vox",       "audio/voxware"},
      {"vqe",       "audio/x-twinvq-plugin"},
      {"vqf",       "audio/x-twinvq"},
      {"vql",       "audio/x-twinvq-plugin"},
      {"vrml",      "application/x-vrml"},
      {"vrt",       "x-world/x-vrt"},
      {"vsd",       "application/x-visio"},
      {"vst",       "application/x-visio"},
      {"vsw",       "application/x-visio"},
      {"w60",       "application/wordperfect6.0"},
      {"w61",       "application/wordperfect6.1"},
      {"w6w",       "application/msword"},
      {"wav",       "audio/wav"},
      {"wb1",       "application/x-qpro"},
      {"wbmp",      "image/vnd.wap.wbmp"},
      {"web",       "application/vnd.xara"},
      {"webp",      "image/webp"},
      {"wiz",       "application/msword"},
      {"wk1",       "application/x-123"},
      {"wma",       "audio/x-ms-wma"},
      {"wmf",       "windows/metafile"},
      {"wml",       "text/vnd.wap.wml"},
      {"wmlc",      "application/vnd.wap.wmlc"},
      {"wmls",      "text/vnd.wap.wmlscript"},
      {"wmlsc",     "application/vnd.wap.wmlscriptc"},
      {"wmv",       "video/x-ms-wmv"},
      {"word",      "application/msword"},
      {"wp",        "application/wordperfect"},
      {"wp5",       "application/wordperfect"},
      {"wp6",       "application/wordperfect"},
      {"wpd",       "application/wordperfect"},
      {"wq1",       "application/x-lotus"},
      {"wri",       "application/mswrite"},
      {"wrl",       "model/vrml"},
      {"wrz",       "model/vrml"},
      {"wsc",       "text/scriplet"},
      {"wsrc",      "application/x-wais-source"},
      {"wtk",       "application/x-wintalk"},
      {"xbm",       "image/xbm"},
      {"xdr",       "video/x-amt-demorun"},
      {"xgz",       "xgl/drawing"},
      {"xif",       "image/vnd.xiff"},
      {"xl",        "application/excel"},
      {"xla",       "application/excel"},
      {"xlb",       "application/excel"},
      {"xlc",       "application/excel"},
      {"xld",       "application/excel"},
      {"xlk",       "application/excel"},
      {"xll",       "application/excel"},
      {"xlm",       "application/excel"},
      {"xls",       "application/excel"},
      {"xlsx",      "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
      {"xlt",       "application/excel"},
      {"xlv",       "application/excel"},
      {"xlw",       "application/excel"},
      {"xm",        "audio/xm"},
      {"xml",       "text/xml"},
      {"xmz",       "xgl/movie"},
      {"xpix",      "application/x-vnd.ls-xpix"},
      {"xpm",       "image/xpm"},
      {"x-png",     "image/png"},
      {"xspf",      "application/xspf+xml"},
      {"xsr",       "video/x-amt-showrun"},
      {"xvid",      "video/x-msvideo"},
      {"xwd",       "image/x-xwd"},
      {"xyz",       "chemical/x-pdb"},
      {"z",         "application/x-compressed"},
      {"zip",       "application/zip"},
      {"zoo",       "application/octet-stream"},
      {"zsh",       "text/x-script.zsh"}}};

std::string CMime::GetMimeType(const std::string &extension)
{
  if (extension.empty())
    return "";

  std::string ext = extension;
  size_t posNotPoint = ext.find_first_not_of('.');
  if (posNotPoint != std::string::npos && posNotPoint > 0)
    ext = extension.substr(posNotPoint);
  transform(ext.begin(), ext.end(), ext.begin(), ::tolower);

  std::map<std::string, std::string>::const_iterator it = m_mimetypes.find(ext);
  if (it != m_mimetypes.end())
    return it->second;

  return "";
}

std::string CMime::GetMimeType(const CFileItem &item)
{
  std::string path = item.GetDynPath();
  if (item.HasVideoInfoTag() && !item.GetVideoInfoTag()->GetPath().empty())
    path = item.GetVideoInfoTag()->GetPath();
  else if (item.HasMusicInfoTag() && !item.GetMusicInfoTag()->GetURL().empty())
    path = item.GetMusicInfoTag()->GetURL();

  return GetMimeType(URIUtils::GetExtension(path));
}

std::string CMime::GetMimeType(const CURL &url, bool lookup)
{

  std::string strMimeType;

  if( url.IsProtocol("shout") || url.IsProtocol("http") || url.IsProtocol("https"))
  {
    // If lookup is false, bail out early to leave mime type empty
    if (!lookup)
      return strMimeType;

    std::string strmime;
    XFILE::CCurlFile::GetMimeType(url, strmime);

    // try to get mime-type again but with an NSPlayer User-Agent
    // in order for server to provide correct mime-type.  Allows us
    // to properly detect an MMS stream
    if (StringUtils::StartsWithNoCase(strmime, "video/x-ms-"))
      XFILE::CCurlFile::GetMimeType(url, strmime, "NSPlayer/11.00.6001.7000");

    // make sure there are no options set in mime-type
    // mime-type can look like "video/x-ms-asf ; charset=utf8"
    size_t i = strmime.find(';');
    if(i != std::string::npos)
      strmime.erase(i, strmime.length() - i);
    StringUtils::Trim(strmime);
    strMimeType = strmime;
  }
  else
    strMimeType = GetMimeType(url.GetFileType());

  // if it's still empty set to an unknown type
  if (strMimeType.empty())
    strMimeType = "application/octet-stream";

  return strMimeType;
}

CMime::EFileType CMime::GetFileTypeFromMime(const std::string& mimeType)
{
  // based on http://mimesniff.spec.whatwg.org/

  std::string type, subtype;
  if (!parseMimeType(mimeType, type, subtype))
    return FileTypeUnknown;

  if (type == "application")
  {
    if (subtype == "zip")
      return FileTypeZip;
    if (subtype == "x-gzip")
      return FileTypeGZip;
    if (subtype == "x-rar-compressed")
      return FileTypeRar;

    if (subtype == "xml")
      return FileTypeXml;
  }
  else if (type == "text")
  {
    if (subtype == "xml")
      return FileTypeXml;
    if (subtype == "html")
      return FileTypeHtml;
    if (subtype == "plain")
      return FileTypePlainText;
  }
  else if (type == "image")
  {
    if (subtype == "bmp")
      return FileTypeBmp;
    if (subtype == "gif")
      return FileTypeGif;
    if (subtype == "png")
      return FileTypePng;
    if (subtype == "jpeg" || subtype == "pjpeg")
      return FileTypeJpeg;
  }

  if (StringUtils::EndsWith(subtype, "+zip"))
    return FileTypeZip;
  if (StringUtils::EndsWith(subtype, "+xml"))
    return FileTypeXml;

  return FileTypeUnknown;
}

CMime::EFileType CMime::GetFileTypeFromContent(const std::string& fileContent)
{
  // based on http://mimesniff.spec.whatwg.org/#matching-a-mime-type-pattern

  const size_t len = fileContent.length();
  if (len < 2)
    return FileTypeUnknown;

  const unsigned char* const b = (const unsigned char*)fileContent.c_str();

  //! @todo add detection for text types

  // check image types
  if (b[0] == 'B' && b[1] == 'M')
    return FileTypeBmp;
  if (len >= 6 && b[0] == 'G' && b[1] == 'I' && b[2] == 'F' && b[3] == '8' && (b[4] == '7' || b[4] == '9') && b[5] == 'a')
    return FileTypeGif;
  if (len >= 8 && b[0] == 0x89 && b[1] == 'P' && b[2] == 'N' && b[3] == 'G' && b[4] == 0x0D && b[5] == 0x0A && b[6] == 0x1A && b[7] == 0x0A)
    return FileTypePng;
  if (len >= 3 && b[0] == 0xFF && b[1] == 0xD8 && b[2] == 0xFF)
    return FileTypeJpeg;

  // check archive types
  if (len >= 3 && b[0] == 0x1F && b[1] == 0x8B && b[2] == 0x08)
    return FileTypeGZip;
  if (len >= 4 && b[0] == 'P' && b[1] == 'K' && b[2] == 0x03 && b[3] == 0x04)
    return FileTypeZip;
  if (len >= 7 && b[0] == 'R' && b[1] == 'a' && b[2] == 'r' && b[3] == ' ' && b[4] == 0x1A && b[5] == 0x07 && b[6] == 0x00)
    return FileTypeRar;

  //! @todo add detection for other types if required

  return FileTypeUnknown;
}

bool CMime::parseMimeType(const std::string& mimeType, std::string& type, std::string& subtype)
{
  static const char* const whitespaceChars = "\x09\x0A\x0C\x0D\x20"; // tab, LF, FF, CR and space

  type.clear();
  subtype.clear();

  const size_t slashPos = mimeType.find('/');
  if (slashPos == std::string::npos)
    return false;

  type.assign(mimeType, 0, slashPos);
  subtype.assign(mimeType, slashPos + 1, std::string::npos);

  const size_t semicolonPos = subtype.find(';');
  if (semicolonPos != std::string::npos)
    subtype.erase(semicolonPos);

  StringUtils::Trim(type, whitespaceChars);
  StringUtils::Trim(subtype, whitespaceChars);

  if (type.empty() || subtype.empty())
  {
    type.clear();
    subtype.clear();
    return false;
  }

  StringUtils::ToLower(type);
  StringUtils::ToLower(subtype);

  return true;
}
