#include "./signature.h" #include "./matroska/matroskatagid.h" #include #include using namespace CppUtilities; namespace TagParser { /*! * \brief Holds 64-bit signatures. */ enum Sig64 : std::uint64_t { ApeTag = 0x4150455441474558ul, // APETAGEX Ar = 0x213C617263683E0A, Asf1 = 0x3026B2758E66CF11ul, Asf2 = 0xA6D900AA0062CE6Cul, Png = 0x89504E470D0A1A0Aul, RiffAvi = 0x415649204C495354ul, YUV4Mpeg2 = 0x595556344D504547ul, }; /*! * \brief Holds 52-bit signatures. */ enum Sig56 : std::uint64_t { Rar = 0x526172211A0700ul, }; /*! * \brief Holds 48-bit signatures. */ enum Sig48 : std::uint64_t { Gif87a = 0x474946383761ul, Gif89a = 0x474946383961ul, SevenZ = 0x377ABCAF271Cul, Xz = 0xFD377A585A00ul, }; /*! * \brief Holds 40-bit signatures. */ enum Sig40 : std::uint64_t { Aiff = 0x464F524D00ul, }; /*! * \brief Holds 32-bit signatures. */ enum Sig32 : std::uint32_t { Dirac = 0x42424344u, Elf = 0x7F454C46u, Flac = 0x664C6143u, Ivf = 0x444B4946u, JavaClassFile = 0xCAFEBABEu, Ebml = 0x1A45DFA3u, Midi = 0x4D546864u, MonkeysAudio = 0x4D414320u, Mp4 = 0x66747970u, Ogg = 0x4F676753u, PhotoshopDocument = 0x38425053u, QuickTime = 0x6D6F6F76u, Riff = 0x52494646u, RiffWave = 0x57415645u, TiffBigEndian = 0x4D4D002Au, TiffLittleEndian = 0x49492A00u, Utf32Text = 0xFFFE0000u, WavPack = 0x7776706Bu, WindowsIcon = 0x00000100u, Lzip = 0x4C5A4950u, Zip1 = 0x504B0304u, Zip2 = 0x504B0506u, Zip3 = 0x504B0708u, Zstd = 0x28b52ffdu, }; /*! * \brief Holds 24-bit signatures. */ enum Sig24 : std::uint32_t { Bzip2 = 0x425A68u, Flv = 0x464C56u, Gzip = 0x1F8B08u, Id3v2 = 0x494433u, Utf8Text = 0xEFBBBFu, }; /*! * \brief Holds 16-bit signatures. */ enum Sig16 : std::uint16_t { Ac3 = 0x0B77u, Adts = 0xFFF0u, AdtsMask = 0xFFF6u, Jpeg = 0xffd8u, Lha = 0x1FA0u, Lzw = 0x1F9Du, MpegAudioFrames = 0x7FFu, PortableExecutable = 0x4D5Au, Utf16Text = 0xFFFEu, WindowsBitmap = 0x424du, }; /*! * \brief Parses the signature read from the specified \a buffer. * \param buffer Specifies the buffer to read the signature from. * \param bufferSize Specifies the size of \a buffer. * \return Returns the container format denoted by the signature. If the * signature is unknown ContainerFormat::Unknown is returned. */ ContainerFormat parseSignature(std::string_view buffer) { // read signature std::uint64_t sig = 0; if (buffer.size() >= 8) { sig = BE::toInt(buffer.data()); } else if (buffer.size() >= 4) { sig = BE::toInt(buffer.data()); sig <<= 4; } else if (buffer.size() >= 2) { sig = BE::toInt(buffer.data()); sig <<= 6; } else { return ContainerFormat::Unknown; } // return corresponding container format switch (sig) { // check 64-bit signatures case ApeTag: return ContainerFormat::ApeTag; case Ar: return ContainerFormat::Ar; case Asf1: return ContainerFormat::Asf; case Asf2: return ContainerFormat::Asf; case Png: return ContainerFormat::Png; case YUV4Mpeg2: if (buffer.size() >= 10 && buffer[8] == 0x32 && buffer[9] == 0x20) { return ContainerFormat::YUV4Mpeg2; } break; default:; } switch (sig & 0x00000000FFFFFFFF) { // check 32-bit signatures @ bit 31 case Mp4: return ContainerFormat::Mp4; case QuickTime: return ContainerFormat::QuickTime; default:; } switch (sig >> 8) { // check 56-bit signatures case Rar: return ContainerFormat::Rar; default:; } switch (sig >> 16) { // check 48-bit signatures case Gif87a: return ContainerFormat::Gif87a; case Gif89a: return ContainerFormat::Gif89a; case SevenZ: return ContainerFormat::SevenZ; case Xz: return ContainerFormat::Xz; default:; } switch (sig >> 24) { // check 40-bit signatures case Aiff: return ContainerFormat::Aiff; default:; } switch (sig >> 32) { // check 32-bit signatures case Dirac: return ContainerFormat::Dirac; case Elf: return ContainerFormat::Elf; case Flac: return ContainerFormat::Flac; case Ivf: return ContainerFormat::Ivf; case JavaClassFile: return ContainerFormat::JavaClassFile; case Ebml: return ContainerFormat::Ebml; case Midi: return ContainerFormat::Midi; case MonkeysAudio: return ContainerFormat::MonkeysAudio; case Ogg: return ContainerFormat::Ogg; case PhotoshopDocument: return ContainerFormat::PhotoshopDocument; case Riff: if (buffer.size() >= 16 && BE::toInt(buffer.data() + 8) == Sig64::RiffAvi) { return ContainerFormat::RiffAvi; } else if (buffer.size() >= 12 && BE::toInt(buffer.data() + 8) == RiffWave) { return ContainerFormat::RiffWave; } else { return ContainerFormat::Riff; } case TiffBigEndian: return ContainerFormat::TiffBigEndian; case TiffLittleEndian: return ContainerFormat::TiffLittleEndian; case Utf32Text: return ContainerFormat::Utf32Text; case WavPack: return ContainerFormat::WavPack; case WindowsIcon: return ContainerFormat::WindowsIcon; case Lzip: return ContainerFormat::Lzip; case Zip1: case Zip2: case Zip3: return ContainerFormat::Zip; case Zstd: return ContainerFormat::Zstd; default:; } switch (sig >> 40) { // check 24-bit signatures case Bzip2: return ContainerFormat::Bzip2; case Flv: return ContainerFormat::FlashVideo; case Gzip: return ContainerFormat::Gzip; case Id3v2: return ContainerFormat::Id3v2Tag; case Utf8Text: return ContainerFormat::Utf8Text; } switch (sig >> 48) { // check 16-bit signatures case Ac3: return ContainerFormat::Ac3Frames; case Jpeg: return ContainerFormat::Jpeg; case Lha: return ContainerFormat::Lha; case Lzw: return ContainerFormat::Lzw; case PortableExecutable: return ContainerFormat::PortableExecutable; case Utf16Text: return ContainerFormat::Utf16Text; case WindowsBitmap: return ContainerFormat::WindowsBitmap; default:; } // check other signatures if (((sig >> 48) & AdtsMask) == Adts) { return ContainerFormat::Adts; } if ((sig >> 53) == MpegAudioFrames) { return ContainerFormat::MpegAudioFrames; } return ContainerFormat::Unknown; } /*! * \brief Returns the abbreviation of the container format as C-style string considering * the specified media type and version. * \remarks The abbreviation might be used as file extension. * \returns Returns an empty string if no abbreviation is available. */ std::string_view containerFormatAbbreviation(ContainerFormat containerFormat, MediaType mediaType, unsigned int version) { switch (containerFormat) { case ContainerFormat::Ac3Frames: return "ac3"; case ContainerFormat::Ar: return "a"; case ContainerFormat::Asf: return "asf"; case ContainerFormat::Dirac: return "drc"; case ContainerFormat::Elf: return "elf"; case ContainerFormat::Flac: return "flac"; case ContainerFormat::FlashVideo: return "flv"; case ContainerFormat::Gif87a: case ContainerFormat::Gif89a: return "gif"; case ContainerFormat::Ivf: return "ivf"; case ContainerFormat::JavaClassFile: return "class"; case ContainerFormat::Jpeg: return "jpeg"; case ContainerFormat::Lha: return "lzh"; case ContainerFormat::Lzw: return "lzw"; case ContainerFormat::Mp4: switch (mediaType) { case MediaType::Audio: return "m4a"; default: return "mp4"; } case ContainerFormat::Ogg: switch (mediaType) { case MediaType::Video: return "ogv"; default: switch (version) { case static_cast(GeneralMediaFormat::Opus): return "opus"; case static_cast(GeneralMediaFormat::Speex): return "spx"; default: return "ogg"; } } case ContainerFormat::PhotoshopDocument: return "psd"; case ContainerFormat::Png: return "png"; case ContainerFormat::PortableExecutable: return "exe"; case ContainerFormat::Rar: return "rar"; case ContainerFormat::Matroska: switch (mediaType) { case MediaType::Audio: return "mka"; default: return "mkv"; } case ContainerFormat::MpegAudioFrames: switch (version) { case 1: return "mp1"; case 2: return "mp2"; default: return "mp3"; } case ContainerFormat::Riff: return "riff"; case ContainerFormat::RiffWave: return "wav"; case ContainerFormat::RiffAvi: return "avi"; case ContainerFormat::Tar: return "tar"; case ContainerFormat::TiffBigEndian: case ContainerFormat::TiffLittleEndian: return "tiff"; case ContainerFormat::WindowsBitmap: return "bmp"; case ContainerFormat::WindowsIcon: return "ico"; case ContainerFormat::Bzip2: return "bz"; case ContainerFormat::Gzip: return "gz"; case ContainerFormat::Lzip: return "lz"; case ContainerFormat::QuickTime: return "mov"; case ContainerFormat::Zip: return "zip"; case ContainerFormat::SevenZ: return "7z"; case ContainerFormat::Xz: return "xz"; case ContainerFormat::YUV4Mpeg2: return "y4m"; case ContainerFormat::WavPack: return "wv"; case ContainerFormat::MonkeysAudio: return "ape"; case ContainerFormat::Midi: return "mid"; case ContainerFormat::Aiff: return "aiff"; case ContainerFormat::Zstd: return "zst"; default: return ""; } } /*! * \brief Returns the name of the specified container format as C-style string. * * Returns "unknown" if no name is available. */ std::string_view containerFormatName(ContainerFormat containerFormat) { switch (containerFormat) { case ContainerFormat::Ac3Frames: return "raw Dolby Digital"; case ContainerFormat::Adts: return "Audio Data Transport Stream"; case ContainerFormat::Ar: return "Archive (GNU ar)"; case ContainerFormat::Asf: return "Advanced Systems Format"; case ContainerFormat::Dirac: return "raw Dirac"; case ContainerFormat::Elf: return "Executable and Linkable Format"; case ContainerFormat::Flac: return "raw Free Lossless Audio Codec frames"; case ContainerFormat::FlashVideo: return "Flash Video"; case ContainerFormat::Gif87a: case ContainerFormat::Gif89a: return "Graphics Interchange Format"; case ContainerFormat::Ivf: return "IVF"; case ContainerFormat::JavaClassFile: return "Java class file"; case ContainerFormat::Jpeg: return "JPEG File Interchange Format"; case ContainerFormat::Lha: return "LHA compressed file"; case ContainerFormat::Lzw: return "LZW compressed file"; case ContainerFormat::Mp4: return "MPEG-4 Part 14"; case ContainerFormat::Ogg: return "Ogg transport bitstream"; case ContainerFormat::PhotoshopDocument: return "Photoshop document"; case ContainerFormat::Png: return "Portable Network Graphics"; case ContainerFormat::PortableExecutable: return "Portable Executable"; case ContainerFormat::Rar: return "RAR Archive"; case ContainerFormat::Ebml: return "EBML"; case ContainerFormat::Matroska: return "Matroska"; case ContainerFormat::Webm: return "WebM"; case ContainerFormat::MpegAudioFrames: return "MPEG-1 Layer 1/2/3 frames"; case ContainerFormat::Riff: return "Resource Interchange File Format"; case ContainerFormat::RiffWave: return "RIFF/WAVE"; case ContainerFormat::RiffAvi: return "RIFF/Audio Video Interleave"; case ContainerFormat::Tar: return "TAR archive"; case ContainerFormat::TiffBigEndian: case ContainerFormat::TiffLittleEndian: return "Tagged Image File Format"; case ContainerFormat::Utf16Text: return "UTF-16 text"; case ContainerFormat::Utf32Text: return "UTF-32 text"; case ContainerFormat::Utf8Text: return "UTF-8 text"; case ContainerFormat::WavPack: return "WavPack"; case ContainerFormat::WindowsBitmap: return "Microsoft Windows Bitmap"; case ContainerFormat::WindowsIcon: return "Microsoft Windows Icon"; case ContainerFormat::Bzip2: return "bzip2 compressed file"; case ContainerFormat::Gzip: return "gzip compressed file"; case ContainerFormat::Lzip: return "lzip compressed file"; case ContainerFormat::SevenZ: return "7z archive"; case ContainerFormat::QuickTime: return "Quick Time"; case ContainerFormat::Xz: return "xz compressed file"; case ContainerFormat::YUV4Mpeg2: return "YUV4MPEG2"; case ContainerFormat::Zip: return "ZIP archive"; case ContainerFormat::MonkeysAudio: return "Monkey's Audio"; case ContainerFormat::Midi: return "MIDI"; case ContainerFormat::Aiff: return "Audio Interchange File Format"; case ContainerFormat::Zstd: return "Zstandard compressed file"; case ContainerFormat::Id3v2Tag: return "ID3v2 tag"; case ContainerFormat::ApeTag: return "APE tag"; default: return "unknown"; } } /*! * \brief Returns the subversion of the container format as C-style string. * * Returns an empty string if there is no subversion available. */ std::string_view containerFormatSubversion(ContainerFormat containerFormat) { switch (containerFormat) { case ContainerFormat::Gif87a: return "87a"; case ContainerFormat::Gif89a: return "89a"; case ContainerFormat::TiffBigEndian: return "big endian"; case ContainerFormat::TiffLittleEndian: return "little endian"; default: return ""; } } /*! * \brief Returns the MIME-type of the container format as C-style string. * * Returns an empty string if there is no MIME-type available. */ std::string_view containerMimeType(ContainerFormat containerFormat, MediaType mediaType) { switch (containerFormat) { case ContainerFormat::Ac3Frames: return "audio/ac3"; case ContainerFormat::Asf: return "video/x-ms-asf"; case ContainerFormat::Flac: return "audio/flac"; case ContainerFormat::FlashVideo: return "video/x-flv"; case ContainerFormat::Gif87a: case ContainerFormat::Gif89a: return "image/gif"; case ContainerFormat::Jpeg: return "image/jpeg"; case ContainerFormat::Png: return "image/png"; case ContainerFormat::MpegAudioFrames: return "audio/mpeg"; case ContainerFormat::Mp4: switch (mediaType) { case MediaType::Audio: return "audio/mp4"; default: return "video/mp4"; } case ContainerFormat::Ogg: switch (mediaType) { case MediaType::Audio: return "audio/ogg"; default: return "video/ogg"; } case ContainerFormat::Matroska: switch (mediaType) { case MediaType::Audio: return "audio/x-matroska"; default: return "video/x-matroska"; } case ContainerFormat::Midi: return "audio/midi"; case ContainerFormat::Bzip2: return "application/x-bzip"; case ContainerFormat::Gzip: return "application/gzip"; case ContainerFormat::Lha: return "application/x-lzh-compressed"; case ContainerFormat::Rar: return "application/x-rar-compressed"; case ContainerFormat::Lzip: return "application/x-lzip"; case ContainerFormat::QuickTime: return "video/quicktime"; case ContainerFormat::Zip: return "application/zip"; case ContainerFormat::SevenZ: return "application/x-7z-compressed"; case ContainerFormat::Xz: return "application/x-xz"; case ContainerFormat::WindowsBitmap: return "image/bmp"; case ContainerFormat::WindowsIcon: return "image/vnd.microsoft.icon"; case ContainerFormat::Zstd: return "application/zstd"; default: return ""; } } /*! * \brief Returns the general TagTargetLevel for the specified \a container format and raw \a targetLevelValue. */ TagTargetLevel containerTargetLevel(ContainerFormat containerFormat, std::uint64_t targetLevelValue) { switch (containerFormat) { case ContainerFormat::Matroska: case ContainerFormat::Webm: return matroskaTagTargetLevel(targetLevelValue); default: return TagTargetLevel::Unspecified; } } /*! * \brief Returns the raw target level value for the specified \a containerFormat and general \a targetLevel. */ std::uint64_t containerTargetLevelValue(ContainerFormat containerFormat, TagTargetLevel targetLevel) { switch (containerFormat) { case ContainerFormat::Matroska: case ContainerFormat::Webm: return matroskaTagTargetLevelValue(targetLevel); default: return 0; } } } // namespace TagParser