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