Blog. Just Blog

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

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

Нашел тут в закромах еще один формат трекерной музыки - MO3 (MOdule with MP3) за авторством известного Ian Luck, написавшего музыкальную библиотеку BASS. Вроде бы логично было добавить его в общий список трекерной музыки. Но в процессе исследования выяснились некоторые подробности, которые, я считаю, достойны отдельной статьи. Дело в том, что все данные, в том числе и заголовок, в котором содержится название композиции, упакованы по алгоритму LZ (Lempel-Ziv). Соответственно, чтобы их получить, требуется сперва этот заголовок распаковать. Вот этим и займемся.

Сперва небольшое описание внутреннего формата файла. Сперва идет трехбайтный заголовок "MO3", за которым следует один байт с версией использованного кодировщика. Его значение может быть от 0 до 5, при этом, если значение будет 5, то в заголовке будет присутствовать дополнительная информация, которую надо учитывать при обработке. Следом идет DWORD с размером распакованного заголовка, а дальше как раз или начинаются упакованные данные, или записан еще один дополнительный DWORD с указанием смещения музыки, после которого уже идет заголовок. В заголовке после его распаковки первым делом записано название композиции, это обычная строка в формате ASCIIZ. Что находится после нее нас в рамках данной статьи уже не интересует. Как можно посмотреть в статье про другие форматы трекерной музыки, на название выделяется не так много места, так что и весь заголовок распаковывать не придется. Для работы будет вполне достаточно, например, первых 100h байт файла.
  1.         ; Прочитать начало файла
  2.         invoke  _lopen,fname,OF_READ
  3.         mov     [desc],eax
  4.         invoke  _lread,[desc],buff,100h
  5.         invoke  _lclose,[desc]
  6.  
  7.         ; Проверка на соответствие формата
  8.         mov     esi,buff
  9.         lodsw
  10.         cmp     ax,'MO'
  11.         ; Неизвестный формат файла
  12.         jne     .loc_exit
  13.         lodsb
  14.         cmp     al,'3'
  15.         ; Неизвестный формат файла
  16.         jne     .loc_exit
  17.  
  18.         lodsb
  19.         ; Encoder version 2.4
  20.         cmp     al,5
  21.         ; Неизвестный формат файла
  22.         ja      .loc_exit
  23.         jne     @f
  24.         ; Пропустить еще 4 байта
  25.         lodsd
  26. @@:
  27.         lodsd
  28.         ; ESI -> начало упакованного заголовка
Формат упакованных данных отлично расписан в неофициальной документации, там же есть ссылка на исходники утилиты для декодирования MO3-файлов. Нас интересует только файл с алгоритмом распаковки. На всякий случай я все это продублирую в прилагаемом архиве, а то информация в интернетах имеет неприятную привычку исчезать.

Портированный на Ассемблер алгоритм распаковки будет следующим. lpCompressed - указатель на упакованный заголовок, lpOut - указатель на буфер для приема распакованных данных, dLen - размер данных для распаковки, тут можно указать те же 100h, весь заголовок распаковывать не обязательно.
  1. ;------------------------------------------------------------
  2. ; Распаковка данных в формате MO3
  3. ;------------------------------------------------------------
  4. ; На входе:
  5. ;   lpCompressed - указатель на упакованные данные
  6. ;   dLen - размер упакованных данных
  7. ;   lpOut - указатель на буфер для распакованных данных
  8. ; На выходе:
  9. ;   EAX = размер распакованных данных
  10. ;------------------------------------------------------------
  11. proc mo3_unpack lpCompressed:DWORD, lpOut:DWORD, dLen:DWORD
  12.         locals
  13.                 previousPtr dd ?
  14.                 adjust dd ?
  15.         endl
  16.  
  17.         push    esi
  18.         push    edi
  19.         push    ebx
  20.  
  21.         mov     esi,[lpCompressed]
  22.         mov     edi,[lpOut]
  23.         mov     ebx,[dLen]
  24.  
  25.         mov     [previousPtr],0
  26.         xor     dl,dl
  27.         xor     ecx,ecx
  28. .loc_move_one_byte:
  29.         dec     ebx
  30.         jl      .loc_error
  31.         movsb
  32. .loc_main_loop:
  33.         jle     .loc_success
  34.         call    .READ_CTRL_BIT
  35.         jnb     .loc_move_one_byte
  36.         mov     [adjust],0
  37.         call    .DECODE_CTRL_BITS
  38.         sub     ecx,3
  39.         jnb     @f
  40.         mov     eax,[previousPtr]
  41.         inc     ecx
  42.         jmp     .loc_read_next
  43. @@:
  44.         mov     eax,ecx
  45.         xor     ecx,ecx
  46.         shl     eax,8
  47.         dec     ebx
  48.         jl      .loc_error
  49.         lodsb
  50.         not     eax
  51.         cmp     eax,-1280
  52.         adc     [adjust],1
  53.         cmp     eax,-32000
  54.         adc     [adjust],0
  55.         mov     [previousPtr],eax
  56. .loc_read_next:
  57.         call    .READ_CTRL_BIT
  58.         adc     ecx,ecx
  59.         call    .READ_CTRL_BIT
  60.         adc     ecx,ecx
  61.         jnz     @f
  62.         call    .DECODE_CTRL_BITS
  63.         add     ecx,2
  64. @@:
  65.         add     eax,edi
  66.         cmp     eax,[lpOut]
  67.         jl      .loc_error
  68.         add     ecx,[adjust]
  69.         jle     .loc_error
  70.         xchg    eax,esi
  71.         rep     movsb
  72.         xchg    eax,esi
  73.         jmp     .loc_main_loop
  74. .loc_error:
  75.         mov     eax,-1
  76.         jmp     .loc_unpack_done
  77. .loc_success:
  78.         mov     eax,esi
  79.         sub     eax,[lpCompressed]
  80. .loc_unpack_done:
  81.         pop     ebx
  82.         pop     edi
  83.         pop     esi
  84.         ret
  85.  
  86. .READ_CTRL_BIT:
  87.         add     dl,dl
  88.         jnz     .read_ctrl_bit_1
  89.         dec     ebx
  90.         jl      .read_ctrl_bit_0
  91.         mov     dl,[esi]
  92.         sub     esi,-1
  93.         adc     dl,dl
  94. .read_ctrl_bit_1:
  95.         retn
  96. .read_ctrl_bit_0:
  97.         clc
  98.         retn
  99.  
  100. .DECODE_CTRL_BITS:
  101.         inc     ecx
  102. @@:
  103.         stdcall .READ_CTRL_BIT
  104.         adc     ecx, ecx
  105.         stdcall .READ_CTRL_BIT
  106.         jb      @b
  107.         retn
  108. endp
В приложении пример программы с исходным текстом, которая извлекает название композиции из файла MO3, а также документация по формату, исходники утилиты для распаковки и официальный кодировщик MO3 от Ian Luck.

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

Parse.MO3.Demo.zip (654,315 bytes)


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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (31.08.2024 в 17:31):
Немного причесал код, оформил его в виде отдельной процедуры. Архив обновлен.

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

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

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