Skip to content

MimeType

Abhinav Dhiman edited this page Sep 11, 2020 · 1 revision

MimeType

public struct MimeType

Properties

mime

Mime type string representation. For example "application/pdf"

let mime:​ String

ext

Mime type extension. For example "pdf"

let ext:​ String

type

Mime type shorthand representation. For example .pdf

let type:​ FileType

all

List of all supported MimeTypes

let all:[MimeType] = [
    MimeType(
      mime:"image/jpeg",
      ext:"jpg",
      type:.jpg,
      bytesCount:3,
      matches:{ bytes, _ in
        return bytes[0...2] == [0xFF, 0xD8, 0xFF]
      }
    ),
    MimeType(
      mime:"image/png",
      ext:"png",
      type:.png,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x89, 0x50, 0x4E, 0x47]
      }
    ),
    MimeType(
      mime:"image/gif",
      ext:"gif",
      type:.gif,
      bytesCount:3,
      matches:{ bytes, _ in
        return bytes[0...2] == [0x47, 0x49, 0x46]
      }
    ),
    MimeType(
      mime:"image/webp",
      ext:"webp",
      type:.webp,
      bytesCount:12,
      matches:{ bytes, _ in
        return bytes[8...11] == [0x57, 0x45, 0x42, 0x50]
      }
    ),
    MimeType(
      mime:"image/flif",
      ext:"flif",
      type:.flif,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x46, 0x4C, 0x49, 0x46]
      }
    ),
    MimeType(
      mime:"image/x-canon-cr2",
      ext:"cr2",
      type:.cr2,
      bytesCount:10,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x49, 0x49, 0x2A, 0x00] || bytes[0...3] == [0x4D, 0x4D, 0x00, 0x2A]) &&
          (bytes[8...9] == [0x43, 0x52])
      }
    ),
    MimeType(
      mime:"image/tiff",
      ext:"tif",
      type:.tif,
      bytesCount:4,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x49, 0x49, 0x2A, 0x00]) ||
          (bytes[0...3] == [0x4D, 0x4D, 0x00, 0x2A])
      }
    ),
    MimeType(
      mime:"image/bmp",
      ext:"bmp",
      type:.bmp,
      bytesCount:2,
      matches:{ bytes, _ in
        return bytes[0...1] == [0x42, 0x4D]
      }
    ),
    MimeType(
      mime:"image/vnd.ms-photo",
      ext:"jxr",
      type:.jxr,
      bytesCount:3,
      matches:{ bytes, _ in
        return bytes[0...2] == [0x49, 0x49, 0xBC]
      }
    ),
    MimeType(
      mime:"image/vnd.adobe.photoshop",
      ext:"psd",
      type:.psd,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x38, 0x42, 0x50, 0x53]
      }
    ),
    MimeType(
      mime:"application/epub+zip",
      ext:"epub",
      type:.epub,
      bytesCount:58,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x50, 0x4B, 0x03, 0x04]) &&
          (bytes[30...57] == [
            0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6C,
            0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x65, 0x70, 0x75, 0x62,
            0x2B, 0x7A, 0x69, 0x70
          ])
      }
    ),

    // Needs to be before `zip` check
    // assumes signed .xpi from addons.mozilla.org
    MimeType(
      mime:"application/x-xpinstall",
      ext:"xpi",
      type:.xpi,
      bytesCount:50,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x50, 0x4B, 0x03, 0x04]) &&
        (bytes[30...49] == [
          0x4D, 0x45, 0x54, 0x41, 0x2D, 0x49, 0x4E, 0x46, 0x2F, 0x6D, 0x6F, 0x7A,
          0x69, 0x6C, 0x6C, 0x61, 0x2E, 0x72, 0x73, 0x61
        ])
      }
    ),
    MimeType(
      mime:"application/zip",
      ext:"zip",
      type:.zip,
      bytesCount:50,
      matches:{ bytes, _ in
        return (bytes[0...1] == [0x50, 0x4B]) &&
          (bytes[2] == 0x3 || bytes[2] == 0x5 || bytes[2] == 0x7) &&
          (bytes[3] == 0x4 || bytes[3] == 0x6 || bytes[3] == 0x8)
      }
    ),
    MimeType(
      mime:"application/x-tar",
      ext:"tar",
      type:.tar,
      bytesCount:262,
      matches:{ bytes, _ in
        return bytes[257...261] == [0x75, 0x73, 0x74, 0x61, 0x72]
      }
    ),
    MimeType(
      mime:"application/x-rar-compressed",
      ext:"rar",
      type:.rar,
      bytesCount:7,
      matches:{ bytes, _ in
        return (bytes[0...5] == [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07]) &&
          (bytes[6] == 0x0 || bytes[6] == 0x1)
      }
    ),
    MimeType(
      mime:"application/gzip",
      ext:"gz",
      type:.gz,
      bytesCount:3,
      matches:{ bytes, _ in
        return bytes[0...2] == [0x1F, 0x8B, 0x08]
      }
    ),
    MimeType(
      mime:"application/x-bzip2",
      ext:"bz2",
      type:.bz2,
      bytesCount:3,
      matches:{ bytes, _ in
        return bytes[0...2] == [0x42, 0x5A, 0x68]
      }
    ),
    MimeType(
      mime:"application/x-7z-compressed",
      ext:"7z",
      type:.sevenZ,
      bytesCount:6,
      matches:{ bytes, _ in
        return bytes[0...5] == [0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]
      }
    ),
    MimeType(
      mime:"application/x-apple-diskimage",
      ext:"dmg",
      type:.dmg,
      bytesCount:2,
      matches:{ bytes, _ in
        return bytes[0...1] == [0x78, 0x01]
      }
    ),
    MimeType(
      mime:"video/mp4",
      ext:"mp4",
      type:.mp4,
      bytesCount:28,
      matches:{ bytes, _ in
        return (bytes[0...2] == [0x00, 0x00, 0x00] && (bytes[3] == 0x18 || bytes[3] == 0x20) && bytes[4...7] == [0x66, 0x74, 0x79, 0x70]) ||
          (bytes[0...3] == [0x33, 0x67, 0x70, 0x35]) ||
          (bytes[0...11] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34, 0x32] &&
            bytes[16...27] == [0x6D, 0x70, 0x34, 0x31, 0x6D, 0x70, 0x34, 0x32, 0x69, 0x73, 0x6F, 0x6D]) ||
          (bytes[0...11] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6F, 0x6D]) ||
          (bytes[0...11] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34, 0x32, 0x00, 0x00, 0x00, 0x00])
      }
    ),
    MimeType(
      mime:"video/x-m4v",
      ext:"m4v",
      type:.m4v,
      bytesCount:11,
      matches:{ bytes, _ in
        return bytes[0...10] == [0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x56]
      }
    ),
    MimeType(
      mime:"audio/midi",
      ext:"mid",
      type:.mid,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x4D, 0x54, 0x68, 0x64]
      }
    ),
    MimeType(
      mime:"video/x-matroska",
      ext:"mkv",
      type:.mkv,
      bytesCount:4,
      matches:{ bytes, mimeDetector in
        guard bytes[0...3] == [0x1A, 0x45, 0xDF, 0xA3] else {
          return false
        }

        let _bytes = Array(mimeDetector.readBytes(count:4100)[4 ..< 4100])
        var idPos = -1

        for i in 0 ..< (_bytes.count - 1) {
          if _bytes[i] == 0x42 && _bytes[i + 1] == 0x82 {
            idPos = i
            break;
          }
        }

        guard idPos > -1 else {
          return false
        }

        let docTypePos = idPos + 3
        let findDocType:(String) -> Bool = { type in
          for i in 0 ..< type.count {
            let index = type.index(type.startIndex, offsetBy:​ i)
            let scalars = String(type[index]).unicodeScalars

            if _bytes[docTypePos + i] != UInt8(scalars[scalars.startIndex].value) {
              return false
            }
          }

          return true
        }

        return findDocType("matroska")
      }
    ),
    MimeType(
      mime:"video/webm",
      ext:"webm",
      type:.webm,
      bytesCount:4,
      matches:{ bytes, mimeDetector in
        guard bytes[0...3] == [0x1A, 0x45, 0xDF, 0xA3] else {
          return false
        }

        let _bytes = Array(mimeDetector.readBytes(count:4100)[4 ..< 4100])
        var idPos = -1

        for i in 0 ..< (_bytes.count - 1) {
          if _bytes[i] == 0x42 && _bytes[i + 1] == 0x82 {
            idPos = i
            break;
          }
        }

        guard idPos > -1 else {
          return false
        }

        let docTypePos = idPos + 3
        let findDocType:(String) -> Bool = { type in
          for i in 0 ..< type.count {
            let index = type.index(type.startIndex, offsetBy:​ i)
            let scalars = String(type[index]).unicodeScalars

            if _bytes[docTypePos + i] != UInt8(scalars[scalars.startIndex].value) {
              return false
            }
          }

          return true
        }

        return findDocType("webm")
      }
    ),
    MimeType(
      mime:"video/quicktime",
      ext:"mov",
      type:.mov,
      bytesCount:8,
      matches:{ bytes, _ in
        return bytes[0...7] == [0x00, 0x00, 0x00, 0x14, 0x66, 0x74, 0x79, 0x70]
      }
    ),
    MimeType(
      mime:"video/x-msvideo",
      ext:"avi",
      type:.avi,
      bytesCount:11,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x52, 0x49, 0x46, 0x46]) &&
          (bytes[8...10] == [0x41, 0x56, 0x49])
      }
    ),
    MimeType(
      mime:"video/x-ms-wmv",
      ext:"wmv",
      type:.wmv,
      bytesCount:10,
      matches:{ bytes, _ in
        return bytes[0...9] == [0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9]
      }
    ),
    MimeType(
      mime:"video/mpeg",
      ext:"mpg",
      type:.mpg,
      bytesCount:4,
      matches:{ bytes, _ in
        guard bytes[0...2] == [0x00, 0x00, 0x01]  else {
          return false
        }

        let hexCode = String(format:"%2X", bytes[3])

        return hexCode.first != nil && hexCode.first! == "B"
      }
    ),
    MimeType(
      mime:"audio/mpeg",
      ext:"mp3",
      type:.mp3,
      bytesCount:3,
      matches:{ bytes, _ in
        return (bytes[0...2] == [0x49, 0x44, 0x33]) ||
          (bytes[0...1] == [0xFF, 0xFB])
      }
    ),
    MimeType(
      mime:"audio/m4a",
      ext:"m4a",
      type:.m4a,
      bytesCount:11,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x4D, 0x34, 0x41, 0x20]) ||
          (bytes[4...10] == [0x66, 0x74, 0x79, 0x70, 0x4D, 0x34, 0x41])
      }
    ),

    // Needs to be before `ogg` check
    MimeType(
      mime:"audio/opus",
      ext:"opus",
      type:.opus,
      bytesCount:36,
      matches:{ bytes, _ in
        return bytes[28...35] == [0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64]
      }
    ),
    MimeType(
      mime:"audio/ogg",
      ext:"ogg",
      type:.ogg,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x4F, 0x67, 0x67, 0x53]
      }
    ),
    MimeType(
      mime:"audio/x-flac",
      ext:"flac",
      type:.flac,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x66, 0x4C, 0x61, 0x43]
      }
    ),
    MimeType(
      mime:"audio/x-wav",
      ext:"wav",
      type:.wav,
      bytesCount:12,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x52, 0x49, 0x46, 0x46]) &&
          (bytes[8...11] == [0x57, 0x41, 0x56, 0x45])
      }
    ),
    MimeType(
      mime:"audio/amr",
      ext:"amr",
      type:.amr,
      bytesCount:6,
      matches:{ bytes, _ in
        return bytes[0...5] == [0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A]
      }
    ),
    MimeType(
      mime:"application/pdf",
      ext:"pdf",
      type:.pdf,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x25, 0x50, 0x44, 0x46]
      }
    ),
    MimeType(
      mime:"application/x-msdownload",
      ext:"exe",
      type:.exe,
      bytesCount:2,
      matches:{ bytes, _ in
        return bytes[0...1] == [0x4D, 0x5A]
      }
    ),
    MimeType(
      mime:"application/x-shockwave-flash",
      ext:"swf",
      type:.swf,
      bytesCount:3,
      matches:{ bytes, _ in
        return (bytes[0] == 0x43 || bytes[0] == 0x46) && (bytes[1...2] == [0x57, 0x53])
      }
    ),
    MimeType(
      mime:"application/rtf",
      ext:"rtf",
      type:.rtf,
      bytesCount:5,
      matches:{ bytes, _ in
        return bytes[0...4] == [0x7B, 0x5C, 0x72, 0x74, 0x66]
      }
    ),
    MimeType(
      mime:"application/font-woff",
      ext:"woff",
      type:.woff,
      bytesCount:8,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x77, 0x4F, 0x46, 0x46]) &&
          ((bytes[4...7] == [0x00, 0x01, 0x00, 0x00]) || (bytes[4...7] == [0x4F, 0x54, 0x54, 0x4F]))
      }
    ),
    MimeType(
      mime:"application/font-woff",
      ext:"woff2",
      type:.woff2,
      bytesCount:8,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x77, 0x4F, 0x46,  0x32]) &&
          ((bytes[4...7] == [0x00, 0x01, 0x00, 0x00]) || (bytes[4...7] == [0x4F, 0x54, 0x54, 0x4F]))
      }
    ),
    MimeType(
      mime:"application/octet-stream",
      ext:"eot",
      type:.eot,
      bytesCount:11,
      matches:{ bytes, _ in
        return (bytes[34...35] == [0x4C, 0x50]) &&
          ((bytes[8...10] == [0x00, 0x00, 0x01]) || (bytes[8...10] == [0x01, 0x00, 0x02]) || (bytes[8...10] == [0x02, 0x00, 0x02]))
      }
    ),
    MimeType(
      mime:"application/font-sfnt",
      ext:"ttf",
      type:.ttf,
      bytesCount:5,
      matches:{ bytes, _ in
        return bytes[0...4] == [0x00, 0x01, 0x00, 0x00, 0x00]
      }
    ),
    MimeType(
      mime:"application/font-sfnt",
      ext:"otf",
      type:.otf,
      bytesCount:5,
      matches:{ bytes, _ in
        return bytes[0...4] == [0x4F, 0x54, 0x54, 0x4F, 0x00]
      }
    ),
    MimeType(
      mime:"image/x-icon",
      ext:"ico",
      type:.ico,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x00, 0x00, 0x01, 0x00]
      }
    ),
    MimeType(
      mime:"video/x-flv",
      ext:"flv",
      type:.flv,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x46, 0x4C, 0x56, 0x01]
      }
    ),
    MimeType(
      mime:"application/postscript",
      ext:"ps",
      type:.ps,
      bytesCount:2,
      matches:{ bytes, _ in
        return bytes[0...1] == [0x25, 0x21]
      }
    ),
    MimeType(
      mime:"application/x-xz",
      ext:"xz",
      type:.xz,
      bytesCount:6,
      matches:{ bytes, _ in
        return bytes[0...5] == [0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00]
      }
    ),
    MimeType(
      mime:"application/x-sqlite3",
      ext:"sqlite",
      type:.sqlite,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x53, 0x51, 0x4C, 0x69]
      }
    ),
    MimeType(
      mime:"application/x-nintendo-nes-rom",
      ext:"nes",
      type:.nes,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x4E, 0x45, 0x53, 0x1A]
      }
    ),
    MimeType(
      mime:"application/x-google-chrome-extension",
      ext:"crx",
      type:.crx,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x43, 0x72, 0x32, 0x34]
      }
    ),
    MimeType(
      mime:"application/vnd.ms-cab-compressed",
      ext:"cab",
      type:.cab,
      bytesCount:4,
      matches:{ bytes, _ in
        return (bytes[0...3] == [0x4D, 0x53, 0x43, 0x46]) || (bytes[0...3] == [0x49, 0x53, 0x63, 0x28])
      }
    ),

    // Needs to be before `ar` check
    MimeType(
      mime:"application/x-deb",
      ext:"deb",
      type:.deb,
      bytesCount:21,
      matches:{ bytes, _ in
        return bytes[0...20] == [
          0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E, 0x0A, 0x64, 0x65, 0x62, 0x69,
          0x61, 0x6E, 0x2D, 0x62, 0x69, 0x6E, 0x61, 0x72, 0x79
        ]
      }
    ),
    MimeType(
      mime:"application/x-unix-archive",
      ext:"ar",
      type:.ar,
      bytesCount:7,
      matches:{ bytes, _ in
        return bytes[0...6] == [0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E]
      }
    ),
    MimeType(
      mime:"application/x-rpm",
      ext:"rpm",
      type:.rpm,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0xED, 0xAB, 0xEE, 0xDB]
      }
    ),
    MimeType(
      mime:"application/x-compress",
      ext:"Z",
      type:.z,
      bytesCount:2,
      matches:{ bytes, _ in
        return (bytes[0...1] == [0x1F, 0xA0]) || (bytes[0...1] == [0x1F, 0x9D])
      }
    ),
    MimeType(
      mime:"application/x-lzip",
      ext:"lz",
      type:.lz,
      bytesCount:4,
      matches:{ bytes, _ in
        return bytes[0...3] == [0x4C, 0x5A, 0x49, 0x50]
      }
    ),
    MimeType(
      mime:"application/x-msi",
      ext:"msi",
      type:.msi,
      bytesCount:8,
      matches:{ bytes, _ in
        return bytes[0...7] == [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1]
      }
    ),
    MimeType(
      mime:"application/mxf",
      ext:"mxf",
      type:.mxf,
      bytesCount:14,
      matches:{ bytes, _ in
        return bytes[0...13] == [0x06, 0x0E, 0x2B, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x01, 0x02 ]
      }
    )
  ]

Methods

matches(bytes:​mimeDetector:​)

Check if the given bytes matches with MimeType it will check for the bytes.count first before delegating the checker function to matches property

public func matches(bytes:[UInt8], mimeDetector:​ MimeDetector) -> Bool

Parameters

  • bytes:​ - bytes:​ Bytes represented with [UInt8]
  • mimeDetector:​ - mimeDetector:​ MimeDetector instance

Returns

Bool

Clone this wiki locally