Blog. Just Blog

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

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

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

Файлы OFR представляют собой контейнеры, внутри которых записаны сжатые исходные данные в формате PCM (RAW) или WAV, соответственно, все метаданные извлекаются из них. Но из исходных форматов метаданные поддерживает только формат WAV. К этому мы еще вернемся, пока же начнем с парсинга внутренней структуры файла OptimFROG. Контейнер состоит из блоков, каждый из которых начинается с 4-байтного идентификатора, за которым следует DWORD с размером содержимого блока и за ним уже следуют сами данные. Первый блок всегда имеет идентификатор "OFR_" (последний символ - пробел), за ним блок "HEAD", в котором могут содержаться метаданные. Потом в файле записаны один или несколько блоков с идентификаторами "COMP" и завершается файл блоком "TAIL", в котором также могут содержаться метаданные. Корректность файла проверяется по идентификатору первого блока. Парсинг заключается в проверке наличия метаданных в блоке "HEAD" и/или "TAIL" и их последующим разбором в точности, как это делается с метаданными файлов WAV. Осталось оформить это в виде кода.
  1.         ; Прочитать заголовок файла
  2.         invoke  _llseek,[desc],0,FILE_BEGIN
  3.         invoke  _lread,[desc],buff,8
  4.         cmp     dword[buff],'OFR '
  5.         jne     loc_close_ofr
  6.         invoke  _llseek,[desc],dword [buff+4],FILE_CURRENT
  7.  
  8. loc_parse_ofr:
  9.         ; Прочитать первые 8 байт блока в контейнере
  10.         invoke  _lread,[desc],buff,8
  11.         cmp     eax,8
  12.         jb      loc_close_ofr
  13.         cmp     dword[buff],'HEAD'
  14.         je      loc_process_head
  15.         cmp     dword[buff],'TAIL'
  16.         je      loc_process_tail
  17.  
  18.         ; Следующий блок
  19.         invoke  _llseek,[desc],dword [buff+4],FILE_CURRENT
  20.         jmp     loc_parse_ofr
  21.  
  22. loc_close_ofr:
  23.         invoke  CloseHandle,[desc]
  24.  
  25.         ; title -> название композиции
  26.         ; artist -> исполнитель
  27.         ; album -> альбом
  28.         ...
  29.         ...
  30.         ...
  31.  
  32.         ;-----------------------------------------
  33.         ; Разбор блока "HEAD"
  34.         ;-----------------------------------------
  35. loc_process_head:
  36.         mov     eax,dword [buff+4]
  37.         mov     [dSize],eax
  38.         ; Прочитать содержимое блока
  39.         invoke  GlobalAlloc,GMEM_ZEROINIT,[dSize]
  40.         mov     [hMem],eax
  41.         invoke  GlobalLock,[hMem]
  42.         mov     [pMem],eax
  43.         ; Прочитать содержимое блока
  44.         invoke  _lread,[desc],[pMem],[dSize]
  45.         cmp     eax,[dSize]
  46.         jb      loc_close_head
  47.  
  48.         ; Проверить корректность данных
  49.         mov     esi,[pMem]
  50.         lodsd
  51.         cmp     eax,'RIFF'
  52.         jne     loc_close_head
  53.         lodsd
  54.         lodsd
  55.         cmp     eax,'WAVE'
  56.         jne     loc_close_head
  57.         lodsd
  58.         lodsd
  59.         add     esi,eax
  60.         mov     eax,esi
  61.         sub     eax,[pMem]
  62.         cmp     eax,[dSize]
  63.         jae     loc_close_head
  64.  
  65.         ; Поискать метаданные
  66.         stdcall parse_block
  67. loc_close_head:
  68.         ; Освободить память
  69.         invoke  GlobalUnlock,[hMem]
  70.         ; Следующий блок
  71.         jmp     loc_parse_ofr
  72.  
  73.         ;-----------------------------------------
  74.         ; Разбор блока "TAIL"
  75.         ;-----------------------------------------
  76. loc_process_tail:
  77.         mov     eax,dword [buff+4]
  78.         mov     [dSize],eax
  79.  
  80.         ; "Хвост" пустой?
  81.         cmp     [dSize],0
  82.         je      loc_close_ofr
  83.  
  84.         ; Прочитать содержимое блока
  85.         invoke  GlobalAlloc,GMEM_ZEROINIT,[dSize]
  86.         mov     [hMem],eax
  87.         invoke  GlobalLock,[hMem]
  88.         mov     [pMem],eax
  89.         ; Прочитать содержимое блока
  90.         invoke  _lread,[desc],[pMem],[dSize]
  91.         cmp     eax,[dSize]
  92.         jb      loc_close_tail
  93.  
  94.         mov     esi,[pMem]
  95.         stdcall parse_block
  96.  
  97. loc_close_tail:
  98.         ; Освободить память
  99.         invoke  GlobalUnlock,[hMem]
  100.         jmp     loc_close_ofr
  101.  
  102.         ;-----------------------------------------
  103.         ; Парсинг содержимого блока
  104.         ;-----------------------------------------
  105. parse_block:
  106.         mov     eax,esi
  107.         sub     eax,[pMem]
  108.         cmp     eax,[dSize]
  109.         jae     parse_block_ret
  110.  
  111.         ; Название секции
  112.         lodsd
  113.         ; Перевести в нижний регистр
  114.         or      eax,20202020h
  115.         ; Метаданные в секции LIST?
  116.         cmp     eax,'list'
  117.         je      loc_read_list
  118.  
  119.         ; Метаданные в секции ID3?
  120.         cmp     eax,'id3 '
  121.         je      loc_read_id3
  122.  
  123.         ; Размер секции
  124.         lodsd
  125.         ; Учесть выравнивание секции
  126.         inc     eax
  127.         and     eax,0FFFFFFFEh
  128.         add     esi,eax
  129.  
  130.         mov     eax,esi
  131.         sub     eax,[pMem]
  132.         cmp     eax,[dSize]
  133.         jb      parse_block
  134.  
  135. parse_block_ret:
  136.         retn
  137.  
  138.         ;----------------------------------------------
  139.         ; Обработка секции LIST
  140.         ;----------------------------------------------
  141. loc_read_list:
  142.         ; Размер секции
  143.         lodsd
  144.         ; Учесть выравнивание секции
  145.         inc     eax
  146.         and     eax,0FFFFFFFEh
  147.         mov     ebx,eax
  148.  
  149.         lodsd
  150.         ; Перевести в нижний регистр
  151.         or      eax,20202020h
  152.         cmp     eax,'info'
  153.         jne     parse_block_ret
  154.  
  155. loc_scan_list_tags:
  156.         ; Все теги обработали?
  157.         mov     eax,esi
  158.         sub     eax,[pMem]
  159.         cmp     eax,ebx
  160.         jae     parse_block_ret
  161.         ; Пропустить финальные нули
  162.         cmp     byte[esi],0
  163.         jne     @f
  164.         inc     esi
  165.         jmp     loc_scan_list_tags
  166. @@:
  167.         ; Наименование тега
  168.         lodsd
  169.         ; Перевести в нижний регистр
  170.         or      eax,20202020h
  171.         mov     edi,album
  172.         cmp     eax,'iprd'
  173.         je      @f
  174.         mov     edi,artist
  175.         cmp     eax,'iart'
  176.         je      @f
  177.         mov     edi,title
  178.         cmp     eax,'inam'
  179.         je      @f
  180.         lodsd
  181.         add     esi,eax
  182.         jmp     loc_scan_list_tags
  183. @@:
  184.         lodsd
  185.  
  186.         ; UTF-8 -> юникод
  187.         push    eax
  188.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,eax,0,0
  189.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,-1,edi,eax
  190.         pop     eax
  191.         ; Следующий тег
  192.         add     esi,eax
  193.  
  194.         jmp     loc_scan_list_tags
  195.  
  196.         ;----------------------------------------------
  197.         ; Обработка секции ID3
  198.         ;----------------------------------------------
  199. loc_read_id3:
  200.         ; Размер секции
  201.         lodsd
  202.         ; Учесть выравнивание секции
  203.         inc     eax
  204.         and     eax,0FFFFFFFEh
  205.         mov     ebx,eax
  206.  
  207.         mov     esi,[pMem]
  208.         ; ID3v2.3
  209.         cmp     dword [esi],0x03334449
  210.         je      @f
  211.         ; ID3v2.4
  212.         cmp     dword [esi],0x04334449
  213.         je      @f
  214.  
  215.         add     esi,ebx
  216.         jmp     parse_block
  217.  
  218. @@:
  219.         add     esi,10
  220. loc_scan_id3_tags:
  221.         ; Все теги обработали?
  222.         mov     eax,esi
  223.         sub     eax,[pMem]
  224.         cmp     eax,ebx
  225.         jae     parse_block_ret
  226.         cmp     byte[esi],0
  227.         je      parse_block_ret
  228.  
  229.         ; Проверить валидность названия тега
  230.         xor     ecx,ecx
  231. loc_check_id3_wav:
  232.         mov     dl,byte[esi+ecx]
  233.         cmp     dl,'0'
  234.         jb      parse_block_ret
  235.         cmp     dl,'9'
  236.         jbe     @f
  237.         cmp     dl,'A'
  238.         jb      parse_block_ret
  239.         cmp     dl,'Z'
  240.         ja      parse_block_ret
  241. @@:
  242.         inc     ecx
  243.         cmp     ecx,4
  244.         jb      loc_check_id3_wav
  245.  
  246.         ; Album
  247.         mov     edi,album
  248.         cmp     dword [esi],'TALB'
  249.         je      @f
  250.         ; Artist
  251.         mov     edi,artist
  252.         cmp     dword [esi],'TPE1'
  253.         je      @f
  254.         ; Title
  255.         mov     edi,title
  256.         cmp     dword [esi],'TIT2'
  257.         je      @f
  258.  
  259.         ; Пропустить тег
  260.         lodsd
  261.         ; Размер данных
  262.         lodsd
  263.         bswap   eax
  264.         add     esi,eax
  265.         lodsw
  266.         jmp     loc_scan_id3_tags
  267. @@:
  268.         lodsd
  269.         ; Размер данных
  270.         lodsd
  271.         bswap   eax
  272.         mov     ecx,eax
  273.         ; Размер без учета байта типа кодировки
  274.         dec     ecx
  275.         lodsw
  276.         ; Тип кодировки строки
  277.         lodsb
  278.         or      al,al
  279.         jz      loc_load_utf8
  280. loc_load_utf16:
  281.         ; Пропустить BOM
  282.         cmp     word[esi],0xFEFF
  283.         jne     @f
  284.         lodsw
  285.         dec     ecx
  286.         dec     ecx
  287. @@:
  288.         ; Просто скопировать строку UTF-16
  289.         rep     movsb
  290.         xor     eax,eax
  291.         stosw
  292.         jmp     loc_scan_id3_tags
  293.  
  294. loc_load_utf8:
  295.         ; UTF-8 -> юникод
  296.         push    ecx
  297.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,ecx,0,0
  298.         invoke  MultiByteToWideChar,CP_UTF8,0,esi,-1,edi,eax
  299.         pop     ecx
  300.         ; Следующий тег
  301.         add     esi,ecx
  302.         jmp     loc_scan_id3_tags
Я постарался учесть все возможные варианты и комбинации метаданных, основываясь на опыте работы с метаданными WAV. Обрабатываются все вложенные секции в блоках "HEAD" и "TAIL", из них извлекаются все доступные данные.

В приложении пример программы с исходным текстом, которая парсит и выводит метаданные из файла в формате OptimFROG.

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

OptimFROG.Metadata.Demo.zip (1,983,611 bytes)


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

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

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

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

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