Blog. Just Blog

Упаковка и распаковка данных с помощью Delta-функций

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

В комментариях к предыдущей статье подсказали (DRON, спасибо!) еще один вариант компрессии данных, выполняемый штатными средствами системы. Речь идет о технологии Delta Compression, которая используется в первую очередь в обновлениях Windows. Суть этой технологии заключается в том, что берутся два массива информации, будь то файлы или блоки в памяти. Между ними определяются все различия, после применения которых из первого массива получается второй, такие различия называются "дельтой". Затем информация о дельте тщательно упаковывается высокоэффективными алгоритмами, а из упакованных блоков в дальнейшем формируются патчи. Delta Compression доступна в Windows Vista и более новых системах.

Как сжать произвольные данные с помощью Delta-функций? Если взять массив данных и вычислить разницу между ним и "пустым местом", то на выходе мы получим упакованную дельту, которая при применении патча даст в точности исходные данные. Именно это нам и требуется.

Для упаковки данных заполняем структуру DELTA_INPUT, в которую записываем указатель на эти данные и их размер. В качестве источника указываем "пустое место", то есть незаполненную структуру DELTA_INPUT. Затем вызываем функцию CreateDeltaB. Но сперва надо описать нужные структуры и определить константы, которые не знает FASM.
  1. DELTA_FLAG_NONE = 0x00000000
  2. DELTA_FILE_TYPE_RAW = 0x00000001
  3.  
  4. struct DELTA_INPUT
  5.         lpStart  dd ?
  6.         uSize    dd ?
  7.         Editable dd ?
  8. ends
  9.  
  10. struct DELTA_OUTPUT
  11.         lpStart dd ?
  12.         uSize   dd ?
  13. ends
Теперь сама функция упаковки. Обратите внимание, структуры DELTA_INPUT тут не передаются по указателям, а их содержимое кладется на стек напрямую. Флаги тоже имеют размер QWORD вместо привычного DWORD.
  1.         ; lpDelta
  2.         push    diDelta
  3.  
  4.         ; HashAlgId
  5.         push    0
  6.         ; lpTargetFileTime
  7.         push    NULL
  8.  
  9.         ; Empty DELTA_INPUT
  10.         push    0
  11.         push    0
  12.         push    0
  13.  
  14.         ; Empty DELTA_INPUT
  15.         push    0
  16.         push    0
  17.         push    0
  18.  
  19.         ; Empty DELTA_INPUT
  20.         push    0
  21.         push    0
  22.         push    0
  23.  
  24.         ; Target
  25.         push    0
  26.         ; Размер исходных данных
  27.         push    [fsize]
  28.         ; Указатель на исходные данные
  29.         push    [dMem]
  30.  
  31.         ; Source
  32.         push    0
  33.         push    0
  34.         push    0
  35.  
  36.         ; ResetFlags
  37.         push    0
  38.         push    DELTA_FLAG_NONE
  39.  
  40.         ; SetFlags
  41.         push    0
  42.         push    DELTA_FLAG_NONE
  43.  
  44.         ; FileTypeSet
  45.         push    0
  46.         push    DELTA_FILE_TYPE_RAW
  47.  
  48.         ; Сжать данные
  49.         invoke  CreateDeltaB
Поскольку тут большое количество повторяющихся команд PUSH 0, код можно хорошенько оптимизировать по размеру. Читаемость кода, естественно, ухудшится.
  1.         ; Сжать данные
  2.         push    diDelta
  3.         push    12
  4.         pop     ecx
  5. @@:
  6.         push    0
  7.         loop    @b
  8.         ; Размер исходных данных
  9.         push    [fsize]
  10.         ; Указатель на исходные данные
  11.         push    [dMem]
  12.         mov     cl,8
  13. @@:
  14.         push    0
  15.         loop    @b
  16.         push    DELTA_FILE_TYPE_RAW
  17.         invoke  CreateDeltaB
После завершения процесса упаковки структура DELTA_OUTPUT будет заполнена указателем на блок сжатых данных и размером этого блока. Поработав со сжатыми данными, занятую ими память надо освободить командой DeltaFree.

Распаковка выполняется еще проще. Заполняем структуру DELTA_INPUT указателем на сжатые данные и их размером, после этого вызываем функцию ApplyDeltaB. Резервировать память для распакованных данных не требуется, это сделает система. Сохранять размер исходных данных тоже не надо, разве что для каких-то ваших внутренних целей. При распаковке система определяет размер данных самостоятельно.
  1.         ; lpDelta
  2.         push    diTarget
  3.         ; Source
  4.         push    0
  5.         push    xlen
  6.         push    xdata
  7.         ; Empty DELTA_INPUT
  8.         push    0
  9.         push    0
  10.         push    0
  11.         ; ApplyFlags
  12.         push    0
  13.         push    DELTA_FLAG_NONE
  14.         ; Распаковать данные
  15.         invoke  ApplyDeltaB
Когда распакованные данные будут не нужны, занимаемую ими память также надо освободить командой DeltaFree.

Плюсы использования Delta-функций очевидны. Отличная степень сжатия, особенно на файлах большого размера, простота реализации, а главное, не надо выделять дополнительную память под упакованные и распакованные данные, все это сделает система. Что касается недостатков, то, как я уже сказал в начале статьи, Delta-функции доступны только в Windows Vista и выше, именно так написано в официальной документации. Но при этом библиотека msdelta.dll в Windows XP имеется, а описанные в статье функции упаковки и распаковки, соответственно, работают. Ошибка ли это в документации, и насколько полно реализована поддержка Delta Compression в Windows XP, этого я сказать не могу.

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

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

Delta.Pack.Unpack.Demo.zip (6,217 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
ManHunter (14.06.2021 в 15:32):
Может быть
Нет
Petya (14.06.2021 в 14:46):
Несколько не по теме, но в общий ещё оффтопичней.
1) Цикл функций упаковки/распаковки закончен, или у Вас ещё планы есть?
2) Inflate будете расписывать?
ManHunter (11.04.2021 в 12:37):
Ну так напиши распаковщик, вот он и будет.

voffka, спасибо за тестирование, подкорректировал статью.
:( (11.04.2021 в 07:56):
А где же простейший распаковщик данных, работающий через командную строку?
voffka (11.04.2021 в 04:05):
На Windows XP оба примера работают. Так что ХР тоже поддерживается.

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

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

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