Blog. Just Blog

Парсинг метаданных файлов TAK на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Парсинг метаданных файлов TAK на Ассемблере
Парсинг метаданных файлов TAK на Ассемблере

TAK (аббревиатура на немецком, которая расшифровывается как "Tom's lossless Audio Compressor") - это алгоритм сжатия аудиофайлов без потерь. Кодек TAK обеспечивает эффективность сжатия на уровне формата APE, достигая при этом скорости декодирования, как у популярного кодека FLAC. Формат достаточно экзотичный, но при этом его понимают некоторые плееры. Но для меня главное, что формат TAK поддерживает метатеги, которые меня интересуют в плане парсинга.

К сожалению, в настоящее время формат считает проприетарным, при этом ни нормальной документации, ни официального описания структуры файлов я не нашел. Пришлось работать с готовыми файлами, благо там ничего особо сложного нет, хотя и без своих заморочек не обошлось. Но обо всем по порядку.

Файл начинается с 4-байтной сигнатуры "tBaK", за которым следует 35h байт служебных данных, назначение которых мне не удалось идентифицировать. Тут важно, что их размер фиксированный. За ними следует заголовок WAV-файла с метаданными. Очень немного напоминает разобранный ранее формат OptimFROG. А вот проблема заключается в том, что размер этого заголовка достоверно установить не удается, в некоторых файлах определенный DWORD соответствует их размеру, но в других там оказывается вообще неправильное значение. По итогу я решил просто читать достаточное количество байт, в которое поместятся метаданные, а затем его парсить, как и в предыдущем примере. Код получился следующим:
  1.         ; Прочитать заголовок файла
  2.         invoke  _llseek,[desc],0,FILE_BEGIN
  3.         invoke  _lread,[desc],buff,39h
  4.         cmp     dword[buff],'tBaK'
  5.         jne     loc_close_tak
  6.  
  7.         ; Прочитать данные WAV
  8.         invoke  _lread,[desc],buff,BUFF_SIZE
  9.  
  10.         ; Проверить корректность данных
  11.         mov     esi,buff
  12.         lodsd
  13.         cmp     eax,'RIFF'
  14.         jne     loc_close_tak
  15.         lodsd
  16.         lodsd
  17.         cmp     eax,'WAVE'
  18.         jne     loc_close_tak
  19.         lodsd
  20.         lodsd
  21.         add     esi,eax
  22. loc_parse_tak:
  23.         ; Название секции
  24.         lodsd
  25.         ; Перевести в нижний регистр
  26.         or      eax,20202020h
  27.         cmp     eax,'data'
  28.         jne     @f
  29.         ; Пропускаем секцию "data", если она есть
  30.         lodsd
  31.         jmp     loc_parse_tak
  32. @@:
  33.         ; Метаданные в секции LIST?
  34.         cmp     eax,'list'
  35.         je      loc_read_list
  36.  
  37.         ; Метаданные в секции ID3?
  38.         cmp     eax,'id3 '
  39.         je      loc_read_id3
  40.  
  41.         ; Неизвестные данные, останавливаем парсинг
  42.         jmp     loc_close_tak
  43.  
  44. loc_read_list:
  45.         ; Размер секции
  46.         lodsd
  47.         ; Учесть выравнивание секции
  48.         inc     eax
  49.         and     eax,0FFFFFFFEh
  50.         mov     ebx,eax
  51.  
  52.         mov     [dPos],esi
  53.  
  54.         lodsd
  55.         ; Перевести в нижний регистр
  56.         or      eax,20202020h
  57.         cmp     eax,'info'
  58.         jne     loc_close_tak
  59.  
  60. loc_scan_list_tags:
  61.         ; Все теги обработали?
  62.         mov     eax,esi
  63.         sub     eax,[dPos]
  64.         cmp     eax,ebx
  65.         jae     loc_parse_tak
  66.         ; Пропустить финальные нули
  67.         cmp     byte[esi],0
  68.         jne     @f
  69.         inc     esi
  70.         jmp     loc_scan_list_tags
  71. @@:
  72.         ; Наименование тега
  73.         lodsd
  74.         ; Перевести в нижний регистр
  75.         or      eax,20202020h
  76.         mov     edi,album
  77.         cmp     eax,'iprd'
  78.         je      @f
  79.         mov     edi,artist
  80.         cmp     eax,'iart'
  81.         je      @f
  82.         mov     edi,title
  83.         cmp     eax,'inam'
  84.         je      @f
  85.         lodsd
  86.         add     esi,eax
  87.         jmp     loc_scan_list_tags
  88. @@:
  89.         lodsd
  90.  
  91.         ; UTF-8 -> юникод
  92.         push    eax
  93.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,eax,0,0
  94.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,-1,edi,eax
  95.         pop     eax
  96.         ; Следующий тег
  97.         add     esi,eax
  98.  
  99.         jmp     loc_scan_list_tags
  100.  
  101.         ;----------------------------------------------
  102.         ; Обработка секции ID3
  103.         ;----------------------------------------------
  104. loc_read_id3:
  105.         ; Размер секции
  106.         lodsd
  107.         ; Учесть выравнивание секции
  108.         inc     eax
  109.         and     eax,0FFFFFFFEh
  110.         mov     ebx,eax
  111.  
  112.         mov     [dPos],esi
  113.  
  114.         ; ID3v2.3
  115.         cmp     dword [esi],0x03334449
  116.         je      @f
  117.         ; ID3v2.4
  118.         cmp     dword [esi],0x04334449
  119.         je      @f
  120.  
  121.         add     esi,ebx
  122.         jmp     loc_parse_tak
  123.  
  124. @@:
  125.         add     esi,10
  126. loc_scan_id3_tags:
  127.         ; Все теги обработали?
  128.         mov     eax,esi
  129.         sub     eax,[dPos]
  130.         cmp     eax,ebx
  131.         jae     loc_parse_tak
  132.         cmp     byte[esi],0
  133.         je      loc_close_tak
  134.  
  135.         ; Проверить валидность названия тега
  136.         xor     ecx,ecx
  137. loc_check_id3_wav:
  138.         mov     dl,byte[esi+ecx]
  139.         cmp     dl,'0'
  140.         jb      loc_close_tak
  141.         cmp     dl,'9'
  142.         jbe     @f
  143.         cmp     dl,'A'
  144.         jb      loc_close_tak
  145.         cmp     dl,'Z'
  146.         ja      loc_close_tak
  147. @@:
  148.         inc     ecx
  149.         cmp     ecx,4
  150.         jb      loc_check_id3_wav
  151.  
  152.         ; Album
  153.         mov     edi,album
  154.         cmp     dword [esi],'TALB'
  155.         je      @f
  156.         ; Artist
  157.         mov     edi,artist
  158.         cmp     dword [esi],'TPE1'
  159.         je      @f
  160.         ; Title
  161.         mov     edi,title
  162.         cmp     dword [esi],'TIT2'
  163.         je      @f
  164.  
  165.         ; Пропустить тег
  166.         lodsd
  167.         ; Размер данных
  168.         lodsd
  169.         bswap   eax
  170.         add     esi,eax
  171.         lodsw
  172.         jmp     loc_scan_id3_tags
  173. @@:
  174.         lodsd
  175.         ; Размер данных
  176.         lodsd
  177.         bswap   eax
  178.         mov     ecx,eax
  179.         ; Размер без учета байта типа кодировки
  180.         dec     ecx
  181.         lodsw
  182.         ; Тип кодировки строки
  183.         lodsb
  184.         or      al,al
  185.         jz      loc_load_utf8
  186. loc_load_utf16:
  187.         ; Пропустить BOM
  188.         cmp     word[esi],0xFEFF
  189.         jne     @f
  190.         lodsw
  191.         dec     ecx
  192.         dec     ecx
  193. @@:
  194.         ; Просто скопировать строку UTF-16
  195.         rep     movsb
  196.         xor     eax,eax
  197.         stosw
  198.         jmp     loc_scan_id3_tags
  199.  
  200. loc_load_utf8:
  201.         ; UTF-8 -> юникод
  202.         push    ecx
  203.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,ecx,0,0
  204.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,-1,edi,eax
  205.         pop     ecx
  206.         ; Следующий тег
  207.         add     esi,ecx
  208.         jmp     loc_scan_id3_tags
  209.  
  210. loc_close_tak:
  211.         invoke  CloseHandle,[desc]
  212.  
  213.         ; title -> название композиции
  214.         ; artist -> исполнитель
  215.         ; album -> альбом 
В приложении пример программы с исходным текстом, которая парсит и выводит метаданные из файла в формате TAK.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

TAK.Metadata.Demo.zip (309,042 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 182 | Комментариев: 2

Комментарии

Отзывы посетителей сайта о статье
ManHunter (30.11.2024 в 15:05):
Не позволяй душе лениться!
Чтоб в ступе воду не толочь,
Душа обязана трудиться
И день и ночь, и день и ночь!
// Николай Заболоцкий

А если серьезно, то разбор метатегов используются у меня как минимум в двух проектах. Ну а раз все равно сделал парсер, то почему бы не поделиться результатами исследований с людьми? Может быть пригодится кому-нибудь еще.
Сергей Озеров (30.11.2024 в 14:58):
Подскажите пожалуйста, а какая практическая польза от этого ? Кроме интересного исследования.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0055 сек.) / Память: 4.5 Mb
Наверх