Skip to content

Commit 0253ae1

Browse files
committed
MimeDetector: new class to resolve file extensions
1 parent 966c633 commit 0253ae1

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
#pragma once
22
#include "AudioTools/CoreAudio/AudioMetaData/MetaData.h"
3+
#include "AudioTools/CoreAudio/AudioMetaData/MimeDetector.h"
4+
#include "AudioTools/CoreAudio/AudioMetaData/MimeResolver.h"
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#pragma once
2+
3+
#include <ctype.h>
4+
#include <stddef.h>
5+
6+
#include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
7+
#include "AudioTools/CoreAudio/AudioBasic/StrView.h"
8+
9+
namespace audio_tools {
10+
11+
/// extension to mime table (sorted alphabetically)
12+
struct MimeEntry {
13+
const char* ext;
14+
const char* mime;
15+
};
16+
/// Default mime table (sorted alphabetically) stored in program memory
17+
static const MimeEntry mime_table[] = {
18+
{"aac", "audio/aac"},
19+
{"ac3", "audio/ac3"},
20+
{"aiff", "audio/aiff"},
21+
{"aif", "audio/aiff"},
22+
{"aifc", "audio/aiff"},
23+
{"alac", "audio/alac"},
24+
{"amr", "audio/amr"},
25+
{"au", "audio/basic"},
26+
{"caf", "audio/x-caf"},
27+
{"dts", "audio/vnd.dts"},
28+
{"flac", "audio/flac"},
29+
{"m3u", "audio/x-mpegurl"},
30+
{"m3u8", "application/vnd.apple.mpegurl"},
31+
{"m4a", "audio/m4a"},
32+
{"mid", "audio/midi"},
33+
{"midi", "audio/midi"},
34+
{"mka", "audio/x-matroska"},
35+
{"mkv", "video/x-matroska"},
36+
{"mp2", "audio/mpeg"},
37+
{"mp2t", "video/MP2T"},
38+
{"mp3", "audio/mpeg"},
39+
{"mp4", "video/mp4"},
40+
{"mpeg", "audio/mpeg"},
41+
{"oga", "audio/ogg"},
42+
{"ogg", "audio/ogg"},
43+
{"ogv", "video/ogg"},
44+
{"opus", "audio/ogg; codecs=opus"},
45+
{"sid", "audio/prs.sid"},
46+
{"spx", "audio/ogg; codecs=spx"},
47+
{"ts", "video/MP2T"},
48+
{"vorbis", "audio/ogg; codec=vorbis"},
49+
{"wave", "audio/vnd.wave"},
50+
{"wav", "audio/vnd.wave"},
51+
{"webm", "video/webm"},
52+
{"wma", "audio/x-ms-wma"},
53+
{nullptr, nullptr}};
54+
55+
/**
56+
* @class MimeResolver
57+
* @brief Lookup MIME types by file extension.
58+
*
59+
* Small, header-only helper that maps file name extensions (for example
60+
* "mp3" or ".wav") to standardized MIME type strings (for example
61+
* "audio/mpeg" or "audio/vnd.wave"). The resolver performs a
62+
* case-insensitive match and accepts extensions with or without a
63+
* leading '.'.
64+
*
65+
* Behavior:
66+
* - The lookup table is a fixed, const array (`mime_table`) declared above
67+
* the class. Modify that table to add or change mappings.
68+
* - Lookup returns a pointer to a constant string from the table. The
69+
* returned pointer is valid for the lifetime of the program. If no
70+
* mapping is found, the methods return nullptr.
71+
* - Thread-safety: read-only operations are safe for concurrent use.
72+
*
73+
* @ingroup codecs
74+
* @ingroup decoder
75+
* @author Phil Schatzmann
76+
* @copyright GPLv3
77+
*/
78+
class MimeResolver {
79+
public:
80+
/// Return MIME for a filename (looks up extension). Returns nullptr if
81+
/// unknown.
82+
const char* fromFilename(const char* filename) {
83+
if (!filename) return nullptr;
84+
const char* dot = strrchr(filename, '.');
85+
if (!dot || *(dot + 1) == '\0') return nullptr;
86+
return fromExtension(dot + 1);
87+
}
88+
89+
/// Return MIME for an extension (case-insensitive). Returns nullptr if
90+
/// unknown.
91+
const char* fromExtension(const char* extension) {
92+
if (!extension) return nullptr;
93+
// skip leading dot if provided
94+
if (extension[0] == '.') extension++;
95+
StrView extView(extension);
96+
97+
// search in custom table first
98+
for (size_t i = 0; i < custom_mime_table.size(); i++) {
99+
if (extView.equalsIgnoreCase(custom_mime_table[i].ext))
100+
return custom_mime_table[i].mime;
101+
}
102+
103+
// search in default table
104+
for (size_t i = 0; mime_table[i].ext != nullptr; i++) {
105+
if (extView.equalsIgnoreCase(mime_table[i].ext))
106+
return mime_table[i].mime;
107+
}
108+
return nullptr;
109+
}
110+
111+
/// Add custom mime entry (overrides default entries)
112+
void addMimeEntry(const char* ext, const char* mime) {
113+
MimeEntry entry;
114+
entry.ext = ext;
115+
entry.mime = mime;
116+
custom_mime_table.push_back(entry);
117+
}
118+
119+
protected:
120+
Vector<MimeEntry> custom_mime_table;
121+
};
122+
123+
} // namespace audio_tools

0 commit comments

Comments
 (0)