Привет, хабр! Недавно я задался вопросом, сколько байт нужно для правильного определения mime-типа файла.
Прежде всего, погуглив, я не остался доволен полученными ответами и поэтому решил сам провести небольшое исследование на эту тему.
К изучению этого вопроса меня побудила следующая задача: определение MIME-типа файла, расположенного на smb-сервере.
Лучшее, что я придумал, — это скопировать кусок файла на локальную машину и затем на основе этой части попытаться распознать его MIME-тип.
Для начала расскажу, что я гуглил и почему мне это не понравилось: Переполнение стека дает 2 ссылки на Википедию:
- Подпись файла говорит, что в большинстве случаев достаточно 2-4 байт. Однако, к сожалению, это не относится, например, к такому популярному формату, как pdf.
- Список подписей предоставляет некоторый список подписей для файлов разных форматов, но он далеко не полный.
Потом я нашел Подписи файлов , вроде бы здесь все.
Однако вернемся к тому же pdf. Если верить этому источнику, то для определения того, что файл является pdf, достаточно четырёх байт (0x25 0x50 0x44 0x46), однако на основании первых четырёх байтов libmagic сказала, что MIME-тип pdf-файла — text/plain , и из пяти это правильное приложение/pdf. С чем именно это связано, ответить сложно, нужно смотреть исходный код.
Я написал очень небольшую программу, которая считывала все файлы из одного каталога, копировала первые N байт в другой каталог, а затем, используя частичные копии полученных файлов, пыталась определить, что же это было на самом деле.
И так до тех пор, пока MIME-тип части файла не совпадет с MIME-типом оригинала.
По результатам работы программа сообщала, сколько байт необходимо для определения того или иного типа.
Вот его код:
Потом, закинув в папку test-dir кучу разных файлов, я начал экспериментировать.#include <stdio.h> #include <stdlib.h> #include <magic.h> #include <sys/types.h> #include <dirent.h> #include <errno.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define TEST_DIR "test-dir/" #define TMP_DIR "tmp-dir/" magic_t cookie; // Detects how many bytes required for correct MIME-type of this file void detect_size(char *filename) { int bytes = 1; int infd, outfd; char strin[100], strout[100], type[100]; char buf[4096]; strcpy(strin, TEST_DIR); strcat(strin, filename); strcpy(strout, TMP_DIR); strcat(strout, filename); while(1) { // Make a copy of given file infd = open(strin, O_RDONLY); outfd = open(strout, O_RDWR | O_CREAT, 00666); read(infd, &buf, bytes); write(outfd, &buf, bytes); lseek(infd, 0, SEEK_SET); lseek(outfd, 0, SEEK_SET); // Detect mime types of old and new const char *mime_type = magic_descriptor(cookie, infd); strcpy(type, mime_type); mime_type = magic_descriptor(cookie, outfd); // Check if mime type detected correctly if (strcmp(mime_type, type) == 0) { printf("%s detected correctly in %d bytes\n", type, bytes); unlink(strout); return; } unlink(strout); bytes++; } } int main() { DIR *dirfd = opendir(TEST_DIR); struct dirent entry, *result = NULL; cookie = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR); magic_load(cookie, NULL); while(1) { readdir_r(dirfd, &entry, &result); if (result == NULL) break; // No more entries in this directory if (!strcmp(entry.d_name, ".
") || !strcmp(entry.d_name, ".
")) continue; // Ignore ".
" and ".
" detect_size(entry.d_name); } magic_close(cookie); closedir(dirfd); exit(EXIT_SUCCESS); }
Конечно, то, что я сделал, не является полномасштабным и серьезным исследованием, но некоторые результаты все же интересны.
Дайте их краткую характеристику: application/x-sharedlib правильно обнаружен в 18 байтах приложение/мслово обнаружено правильно в 1793 байтах изображение/gif обнаружено правильно в 4 байтах приложение/zip обнаружено правильно в 4 байтах application/x-dosexec правильно обнаружен в 2 байтах application/vnd.oasis.opendocument.presentation правильно обнаружен в 85 байтах text/html правильно обнаружен в 14 байтах изображение/jpeg обнаружено правильно в 2 байтах приложение/x-исполняемый файл правильно обнаружен в 18 байтах text/x-makefile обнаружен правильно в 1594 байтах приложение/x-исполняемый файл правильно обнаружен в 18 байтах application/x-gzip правильно обнаружен в 2 байтах аудио/mpeg правильно обнаружено в 2291 байте text/x-c правильно обнаружен в 27 байтах audio/x-flac правильно обнаружен в 4 байтах приложение/pdf обнаружено правильно в 5 байтах Отмечу некоторые моменты, которые показались мне интересными:
- Ну во-первых, конечно, уже упомянутый pdf, который распознаётся по 5 байтам, а не по 4, как можно было бы ожидать.
- И напоследок хотелось бы отметить, что несмотря на крутость идеи определения типа файла по первым N байтам, она, на мой взгляд, не удалась.
Надеюсь, что эта статья будет кому-то интересна.
Спасибо за внимание.
Теги: #mime-type #C++ #магические числа.
#программирование #C++
-
Учебное Пособие По Языку C
19 Oct, 24 -
На Iphone Будут Игры!
19 Oct, 24 -
Как И Почему Можно Стать Волонтером Google
19 Oct, 24 -
Yahoo! Выпустила Свой Браузер Axis
19 Oct, 24 -
Стартовал Конкурс «Премия Рунета – 2006».
19 Oct, 24 -
Дополнительные Объединения В Sql-Запросах
19 Oct, 24