Blog. Just Blog

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

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

APE - формат музыкальных файлов, обработанных при помощи популярного кодека Monkey's Audio. Он позволяет кодировать цифровой звук без потерь при неплохом уровне компрессии данных. Сегодня мы научимся извлекать из этих медиафайлов данные об исполнителе, названии трека и т.п.

Формат хранения метаданных в файлах APE очень похож на формат ID3v1.0, то есть контейнер фиксированного размера находится в конце файла. Но, в отличие от MP3, этот 32-байтный блок данных, называемый APE_TAG_FOOTER, содержит не сами теги, а указатель на большой контейнер произвольного размера, в котором и содержатся все метаданные. APE_TAG_FOOTER в виде структуры можно описать следующим образом:
  1. struct APE_TAG_FOOTER
  2.     m_cID       rb 8 ; 'APETAGEX'
  3.     m_nVersion  dd ? ; APE Tag Version
  4.     m_nSize     dd ? ; Complete size of the tag
  5.     m_nFields   dd ? ; Number of fields in the tag
  6.     m_nFlags    dd ? ; Tag flags
  7.     m_cReserved rb 8 ; Reserved
  8. ends
Он обязательно должен начинаться со строки 'APETAGEX', в поле m_nSize содержится смещение от конца файла, по которому записан блок метаданных, а в m_nFields - количество тегов. Остальные данные нас не интересуют. Таким образом разбор файла APE начинается с проверки его формата и наличия метаданных.
  1.         ; Открыть файл для чтения
  2.         invoke  CreateFile,sample,GENERIC_READ,FILE_SHARE_READ,\
  3.                 0,OPEN_EXISTING,0,0
  4.         mov     [desc],eax
  5.  
  6.         ; Прочитать заголовок файла
  7.         invoke  _lread,[desc],buff,4
  8.  
  9.         ; Проверить корректность файла
  10.         cmp     dword [buff],'MAC '
  11.         jne     loc_close
  12.  
  13.         ; Прочитать APE_TAG_FOOTER
  14.         invoke  _llseek,[desc],-sizeof.APE_TAG_FOOTER,FILE_END
  15.         invoke  _lread,[desc],buff,sizeof.APE_TAG_FOOTER
  16.  
  17.         ; Проверить наличие метаданных
  18.         cmp     dword [buff+APE_TAG_FOOTER.m_cID],'APET'
  19.         jne     loc_close
  20.         cmp     dword [buff+APE_TAG_FOOTER.m_cID+4],'AGEX'
  21.         jne     loc_close
  22.  
  23.         ; Проверить количество тегов
  24.         cmp     dword [buff+APE_TAG_FOOTER.m_nFields],0
  25.         je      loc_close
  26.  
  27.         ; Проверить размер метаданных
  28.         mov     ebx,dword [buff+APE_TAG_FOOTER.m_nSize]
  29.         cmp     ebx,sizeof.APE_TAG_FOOTER
  30.         jbe     loc_close
Резервируем память, передвигаем указатель от конца файла на нужное расстояние, читаем метаданные. Формат этого контейнера в свою очередь напоминает формат Vorbis, когда содержимое тега следует после его названия. Каждый тег имеет структуру: DWORD с размером данных, DWORD с флагами (его можно игнорировать), строка ASCII с именем тега, нулевой байт-разделитель и затем данные тега. Список допустимых названий тегов можно посмотреть здесь. Обработка контейнера с тегами выглядит примерно так:
  1.         ; Выделить память под метаданные
  2.         invoke  GlobalAlloc,GMEM_ZEROINIT,ebx
  3.         mov     [hMem],eax
  4.         invoke  GlobalLock,[hMem]
  5.         mov     [pMem],eax
  6.  
  7.         neg     ebx
  8.         invoke  _llseek,[desc],ebx,FILE_END
  9.         neg     ebx
  10.  
  11.         ; Прочитать метаданные
  12.         invoke  _lread,[desc],[pMem],ebx
  13.  
  14.         ; Количество тегов
  15.         mov     ebx,dword [buff+APE_TAG_FOOTER.m_nFields]
  16.  
  17.         mov     esi,[pMem]
  18. loc_get_tags:
  19.         push    ebx
  20.         ; Размер тега
  21.         mov     ecx,dword[esi]
  22.         add     esi,8
  23.  
  24.         ; Первые 4 символа названия тега
  25.         mov     eax,[esi]
  26.         ; Перевести в нижний регистр
  27.         or      eax,20202020h
  28.         mov     ebx,title
  29.         cmp     eax,'titl'
  30.         je      @f
  31.         mov     ebx,artist
  32.         cmp     eax,'arti'
  33.         je      @f
  34.         mov     ebx,album
  35.         cmp     eax,'albu'
  36.         je      @f
  37.  
  38.         ; Пропустить тег
  39.         push    ecx
  40.         xor     ecx,ecx
  41.         dec     ecx
  42.         ; Найти символ-разделитель
  43.         mov     al,0
  44.         mov     edi,esi
  45.         repne   scasb
  46.         ; Передвинуть указатель на значение тега
  47.         mov     esi,edi
  48.         pop     ecx
  49.         add     esi,ecx
  50.  
  51.         jmp     loc_next_tag
  52. @@:
  53.         ; Найти символ-разделитель
  54.         push    ecx
  55.         xor     ecx,ecx
  56.         dec     ecx
  57.         ; Найти символ-разделитель
  58.         mov     al,0
  59.         mov     edi,esi
  60.         repne   scasb
  61.         ; Передвинуть указатель на значение тега
  62.         mov     esi,edi
  63.         pop     ecx
  64.  
  65.         ; UTF-8 -> юникод
  66.         push    ecx
  67.         invoke  MultiByteToWideChar,CP_UTF8,0,edi,ecx,0,0
  68.         invoke  MultiByteToWideChar,CP_UTF8,0,edi,-1,ebx,eax
  69.         pop     ecx
  70.         ; Перейти к следующему тегу
  71.         add     esi,ecx
  72. loc_next_tag:
  73.         pop     ebx
  74.         ; Все теги обработали?
  75.         dec     ebx
  76.         jnz     loc_get_tags
  77.  
  78.         ; Освободить память
  79.         invoke  GlobalUnlock,[hMem]
  80. loc_close:
  81.         ; Закрыть файл
  82.         invoke  CloseHandle,[desc]
Небольшое замечание. Согласно спецификации, файлы APE могут иметь две версии тегов - описанный ранее ID3v1.0 и новый формат APE. Старый формат метатегов я в дикой природе не встречал, но если вы хотите для своей программы сделать максимально универсальное решение, то это тоже придется учитывать.

Точно такой же формат хранения тегов используют аудиофайлы в формате MPC (маркер "MPCK" в начале файла), WavePack (маркер "wvpk"). Парсинг файлов и разбор метаданных для них выполняется точно так же, как и для APE, разница только в проверочных байтах в начале файла.

В приложении примеры программ с исходными текстами, которые парсят метаданные из APE-, MPC- и WavePack-файлов и выводят их. Тестовый сэмпл есть только для APE, остальные смастерите как-нибудь сами.

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

APE.Metadata.Demo.zip (602,994 bytes)


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

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (24.03.2023 в 11:04):
Добавил в статью информацию о парсинге MPC и WavePack, в архив добавил исходники для работы с ними.
ManHunter (18.11.2022 в 11:16):
Вряд ли. Парсить данные не так сложно, а вот правильно сформировать новые данные для записи в файл - задача на порядок сложнее. Да и готового софта такого завались, как платного, так и бесплатного.
Сергей Озеров (18.11.2022 в 10:42):
Теперь можно конструировать свой редактор тегов ;-)

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

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

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