Blog. Just Blog

Распаковка данных в формате LZRW1 на Ассемблере

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

Алгоритм компрессии LZRW1 был создан в далеких 90-х годах Ross N. Williams на базе оригинальных алгоритмов серии LZ77. Основной упор при разработке был сделан на максимальную скорость обработки данных, но при этом пришлось пожертвовать степенью сжатия. И действительно, по качеству сжатия LZRW1 недалеко ушел от LZ77, зато даже большие файлы упаковывает буквально за доли секунды.

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

Особенностью этого формата является то, что в процессе распаковки невозможно достоверно определить конец упакованных данных, поэтому в процедуру распаковщика приходится передавать размер упакованных данных в явном виде.
  1. ;------------------------------------------------------------
  2. ; Распаковка данных в формате LZRW1
  3. ;------------------------------------------------------------
  4. ; На входе:
  5. ;   lpCompressed - указатель на упакованные данные
  6. ;   lpOut - указатель на буфер для распакованных данных
  7. ;   dSize - размер упакованных данных
  8. ; На выходе:
  9. ;   EAX = размер распакованных данных
  10. ;------------------------------------------------------------
  11. proc lzrw1_unpack lpCompressed:DWORD, lpOut:DWORD, dSize:DWORD
  12.         pusha
  13.         push    ebp
  14.  
  15.         mov     esi,[lpCompressed]
  16.         mov     edi,[lpOut]
  17.  
  18.         mov     ebp,[dSize]
  19.         add     ebp,esi
  20.  
  21.         lodsd
  22.         xor     eax,eax
  23. .loc_process:
  24.         push    17
  25.         pop     edx
  26.         lodsw
  27.         xchg    ebx,eax
  28. .loc_loop:
  29.         cmp     esi,ebp
  30.         je      .loc_done
  31.         dec     edx
  32.         jz      .loc_process
  33.         shr     ebx,1
  34.         jc      @f
  35.         movsb
  36.         jmp     .loc_loop
  37. @@:
  38.         lodsb
  39.         aam     16
  40.         cwde
  41.         movzx   ecx,al
  42.         inc     ecx
  43.         lodsb
  44.         push    esi
  45.         mov     esi,edi
  46.         sub     esi,eax
  47.         rep     movsb
  48.         pop     esi
  49.         jmp     .loc_loop
  50. .loc_done:
  51.         pop     ebp
  52.         sub     edi,[lpOut]
  53.         mov     [esp+28],edi
  54.         popa
  55.         ret
  56. endp
В качестве параметров передается указатель на упакованные данные, указатель на буфер-приемник и размер упакованных данных. На выходе в регистре EAX возвращается количество байт, которое было извлечено из сжатых данных. Размер принимающего буфера в процессе распаковки никак не проверяется, об этом вы должны позаботиться самостоятельно.

Так как размер исходных данных заранее не определен, перед распаковкой его надо обязательно узнать, чтобы выделить соответствующий объем памяти. Для этого я сделал следующую функцию.
  1. ;------------------------------------------------------------
  2. ; Получение размера распакованных данных
  3. ;------------------------------------------------------------
  4. ; На входе:
  5. ;   lpCompressed - указатель на упакованные данные
  6. ;   dSize - размер упакованных данных
  7. ; На выходе:
  8. ;   EAX = размер распакованных данных
  9. ;------------------------------------------------------------
  10. proc lzrw1_size lpCompressed:DWORD, dSize:DWORD
  11.         pusha
  12.         push    ebp
  13.  
  14.         mov     esi,[lpCompressed]
  15.  
  16.         mov     ebp,[dSize]
  17.         add     ebp,esi
  18.         xor     edi,edi
  19.  
  20.         lodsd
  21.         xor     eax,eax
  22. .loc_process:
  23.         push    17
  24.         pop     edx
  25.         lodsw
  26.         xchg    ebx,eax
  27. .loc_loop:
  28.         cmp     esi,ebp
  29.         je      .loc_done
  30.         dec     edx
  31.         jz      .loc_process
  32.         shr     ebx,1
  33.         jc      @f
  34.         inc     esi
  35.         inc     edi
  36.         jmp     .loc_loop
  37. @@:
  38.         lodsb
  39.         aam     16
  40.         cwde
  41.         movzx   ecx,al
  42.         inc     ecx
  43.         lodsb
  44.         add     edi,ecx
  45.         jmp     .loc_loop
  46. .loc_done:
  47.         pop     ebp
  48.         mov     [esp+28],edi
  49.         popa
  50.         ret
  51. endp
В качестве параметров передается указатель на упакованные данные и их размер, на выходе в регистре EAX количество байт, которое получится после распаковки.

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

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

LZRW1.Unpack.Demo.zip (40,653 bytes)


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

Комментарии

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

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

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

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