Парсинг метаданных файлов MO3 на Ассемблере
Парсинг метаданных файлов MO3 на Ассемблере
Нашел тут в закромах еще один формат трекерной музыки - MO3 (MOdule with MP3) за авторством известного Ian Luck, написавшего музыкальную библиотеку BASS. Вроде бы логично было добавить его в общий список трекерной музыки. Но в процессе исследования выяснились некоторые подробности, которые, я считаю, достойны отдельной статьи. Дело в том, что все данные, в том числе и заголовок, в котором содержится название композиции, упакованы по алгоритму LZ (Lempel-Ziv). Соответственно, чтобы их получить, требуется сперва этот заголовок распаковать. Вот этим и займемся.
Сперва небольшое описание внутреннего формата файла. Сперва идет трехбайтный заголовок "MO3", за которым следует один байт с версией использованного кодировщика. Его значение может быть от 0 до 5, при этом, если значение будет 5, то в заголовке будет присутствовать дополнительная информация, которую надо учитывать при обработке. Следом идет DWORD с размером распакованного заголовка, а дальше как раз или начинаются упакованные данные, или записан еще один дополнительный DWORD с указанием смещения музыки, после которого уже идет заголовок. В заголовке после его распаковки первым делом записано название композиции, это обычная строка в формате ASCIIZ. Что находится после нее нас в рамках данной статьи уже не интересует. Как можно посмотреть в статье про другие форматы трекерной музыки, на название выделяется не так много места, так что и весь заголовок распаковывать не придется. Для работы будет вполне достаточно, например, первых 100h байт файла.
Code (Assembler) : Убрать нумерацию
- ; Прочитать начало файла
- invoke _lopen,fname,OF_READ
- mov [desc],eax
- invoke _lread,[desc],buff,100h
- invoke _lclose,[desc]
- ; Проверка на соответствие формата
- mov esi,buff
- lodsw
- cmp ax,'MO'
- ; Неизвестный формат файла
- jne .loc_exit
- lodsb
- cmp al,'3'
- ; Неизвестный формат файла
- jne .loc_exit
- lodsb
- ; Encoder version 2.4
- cmp al,5
- ; Неизвестный формат файла
- ja .loc_exit
- jne @f
- ; Пропустить еще 4 байта
- lodsd
- @@:
- lodsd
- ; ESI -> начало упакованного заголовка
Портированный на Ассемблер алгоритм распаковки будет следующим. lpCompressed - указатель на упакованный заголовок, lpOut - указатель на буфер для приема распакованных данных, dLen - размер данных для распаковки, тут можно указать те же 100h, весь заголовок распаковывать не обязательно.
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------------------
- ; Распаковка данных в формате MO3
- ;------------------------------------------------------------
- ; На входе:
- ; lpCompressed - указатель на упакованные данные
- ; dLen - размер упакованных данных
- ; lpOut - указатель на буфер для распакованных данных
- ; На выходе:
- ; EAX = размер распакованных данных
- ;------------------------------------------------------------
- proc mo3_unpack lpCompressed:DWORD, lpOut:DWORD, dLen:DWORD
- locals
- previousPtr dd ?
- adjust dd ?
- endl
- push esi
- push edi
- push ebx
- mov esi,[lpCompressed]
- mov edi,[lpOut]
- mov ebx,[dLen]
- mov [previousPtr],0
- xor dl,dl
- xor ecx,ecx
- .loc_move_one_byte:
- dec ebx
- jl .loc_error
- movsb
- .loc_main_loop:
- jle .loc_success
- call .READ_CTRL_BIT
- jnb .loc_move_one_byte
- mov [adjust],0
- call .DECODE_CTRL_BITS
- sub ecx,3
- jnb @f
- mov eax,[previousPtr]
- inc ecx
- jmp .loc_read_next
- @@:
- mov eax,ecx
- xor ecx,ecx
- shl eax,8
- dec ebx
- jl .loc_error
- lodsb
- not eax
- cmp eax,-1280
- adc [adjust],1
- cmp eax,-32000
- adc [adjust],0
- mov [previousPtr],eax
- .loc_read_next:
- call .READ_CTRL_BIT
- adc ecx,ecx
- call .READ_CTRL_BIT
- adc ecx,ecx
- jnz @f
- call .DECODE_CTRL_BITS
- add ecx,2
- @@:
- add eax,edi
- cmp eax,[lpOut]
- jl .loc_error
- add ecx,[adjust]
- jle .loc_error
- xchg eax,esi
- rep movsb
- xchg eax,esi
- jmp .loc_main_loop
- .loc_error:
- mov eax,-1
- jmp .loc_unpack_done
- .loc_success:
- mov eax,esi
- sub eax,[lpCompressed]
- .loc_unpack_done:
- pop ebx
- pop edi
- pop esi
- ret
- .READ_CTRL_BIT:
- add dl,dl
- jnz .read_ctrl_bit_1
- dec ebx
- jl .read_ctrl_bit_0
- mov dl,[esi]
- sub esi,-1
- adc dl,dl
- .read_ctrl_bit_1:
- retn
- .read_ctrl_bit_0:
- clc
- retn
- .DECODE_CTRL_BITS:
- inc ecx
- @@:
- stdcall .READ_CTRL_BIT
- adc ecx, ecx
- stdcall .READ_CTRL_BIT
- jb @b
- retn
- endp
Просмотров: 123 | Комментариев: 1
Метки: Assembler, мультимедиа
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(31.08.2024 в 17:31):
Немного причесал код, оформил его в виде отдельной процедуры. Архив обновлен.
Добавить комментарий
Заполните форму для добавления комментария