Упаковка и распаковка данных с помощью функций D3D
Упаковка и распаковка данных с помощью функций D3D
Функции Microsoft High Level Shader Language (HLSL) изначально предназначены для работы с шейдерами в различных графических приложениях. Но, как выяснилось, с помощью некоторых из этих функций можно весьма эффективно сжимать данные, а потом распаковывать их.
У нас будут использоваться конструкции для работы с объектами, про которые FASM не знает. Ну да, кто б сомневался.
Code (Assembler) : Убрать нумерацию
- struct D3D_SHADER_DATA
- pBytecode dd ?
- BytecodeLength dd ?
- ends
- ; ID3D10Blob Interface
- struct ID3D10Blob
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; ID3D10Blob
- GetBufferPointer dd ? ; 00Ch
- GetBufferSize dd ? ; 010h
- ends
- D3D_COMPRESS_SHADER_KEEP_ALL_PARTS = 0x00000001
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------------------
- ; Упаковка данных в формате D3D
- ;------------------------------------------------------------
- ; На входе:
- ; lpOut - указатель на исходные данные
- ; dLen - размер исходных данных
- ; lpCompressed - указатель на буфер для упакованных данных
- ; На выходе:
- ; EAX = размер упакованных данных
- ;------------------------------------------------------------
- proc d3d_pack lpInput:DWORD,dLen:DWORD,lpCompressed:DWORD
- pusha
- ; Заполнить структуру D3D_SHADER_DATA
- mov eax,[lpInput]
- mov [dsa.pBytecode],eax
- mov eax,[dLen]
- mov [dsa.BytecodeLength],eax
- ; Упаковать данные
- invoke D3DCompressShaders,1,dsa,\
- D3D_COMPRESS_SHADER_KEEP_ALL_PARTS,blob
- ; Получить указатель на упакованные данные
- mov eax,[blob]
- mov eax,[eax]
- stdcall dword [eax+ID3D10Blob.GetBufferPointer],[blob]
- mov esi,eax
- mov edi,[lpCompressed]
- ; Получить размер упакованных данных
- mov eax,[blob]
- mov eax,[eax]
- stdcall dword [eax+ID3D10Blob.GetBufferSize],[blob]
- mov [esp+28],eax
- ; Записать упакованные данные в буфер
- mov ecx,eax
- rep movsb
- ; Прибраться за собой
- mov eax,[blob]
- mov eax,[eax]
- stdcall dword [eax+ID3D10Blob.Release],[blob]
- popa
- ret
- endp
Обратную распаковку упакованных данных выполняет функция D3DDecompressShaders. Но тут есть одна тонкость, из-за которой пришлось провести некоторое время в отладчике. Дело в том, что упакованные данные предваряются DWORD'ом с размером оригинальных данных, после которых следует маркер "BSCD" и остальная информация. А функция распаковки ожидает, что буфер с упакованными данными начинается сразу с заголовка. Поэтому тут надо решить для себя, как поступить. Или передавать упакованные данные, начиная с 4-го байта, или при распаковке увеличивать адрес указателя на эти же 4 байта. Я выбрал второй вариант, так как информация о размере оригинальных данных в большинстве случаев будет очень кстати.
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------------------
- ; Распаковка данных в формате D3D
- ;------------------------------------------------------------
- ; На входе:
- ; lpCompressed - указатель на упакованные данные
- ; dLen - размер упакованных данных
- ; lpOut - указатель на буфер для распакованных данных
- ; На выходе:
- ; EAX = размер распакованных данных
- ;------------------------------------------------------------
- proc d3d_unpack lpCompressed:DWORD,dLen:DWORD,lpOut:DWORD
- pusha
- mov dword [esp+28],0
- mov eax,[lpCompressed]
- ; Пропустить DWORD с размером данных
- add eax,4
- ; Распаковать данные
- invoke D3DDecompressShaders,eax,[dLen],1,0,0,0,blob,NULL
- or eax,eax
- jnz .loc_exit
- ; Получить указатель на распакованные данные
- mov eax,[blob]
- mov eax,[eax]
- stdcall dword [eax+ID3D10Blob.GetBufferPointer],[blob]
- mov esi,eax
- mov edi,[lpOut]
- ; Получить размер распакованных данных
- mov eax,[blob]
- mov eax,[eax]
- stdcall dword [eax+ID3D10Blob.GetBufferSize],[blob]
- mov [esp+28],eax
- ; Записать распакованные данные в буфер
- mov ecx,eax
- rep movsb
- ; Прибраться за собой
- mov eax,[blob]
- mov eax,[eax]
- stdcall dword [eax+ID3D10Blob.Release],[blob]
- .loc_exit:
- popa
- ret
- endp
В приложении примеры программ с исходными текстами. Это простейший упаковщик данных, работающий через командную строку, и программа, которая извлекает из памяти иконку с помощью D3D-функций, а затем выводит ее на форму.
Просмотров: 596 | Комментариев: 5
Комментарии
Отзывы посетителей сайта о статье
Petya
(14.02.2024 в 16:47):
DRON, а что это за программа на скриншоте? Ни по названию, ни по картинке не ищется.
ManHunter
(13.02.2024 в 10:55):
DRON, ну вот архив с этим микроскопическим cab, там же собранный вручную d3d и пример, который все это распаковывает: https://www.upload.ee/files/16...cab.zip.html
Что интересно, повторить такое сжатие больше не получается.
upd: там иконки разные :)) только сейчас заметил
Что интересно, повторить такое сжатие больше не получается.
upd: там иконки разные :)) только сейчас заметил
DRON
(13.02.2024 в 01:03):
Ну так и вам никто не мешает вызывать FCIAddFile(...,"S0000!",...,TYPE_LZX+LZX_WINDOW_HI) из cabinet.dll
и получить точно те же 1067+36=1103 байт.
Вот специально только что проверил: файлы созданные D3D и напрямую через FCI API совпадают побайтово с точностью до заголовка.
>Обычный makecab жмет тестовую иконку до 324 байт
Что за параметры у makecab? У меня на разных операционках всегда получается 1059 байт.
И вообще 324 байта выглядят сомнительно: https://imgur.com/a/tHfODUj
и получить точно те же 1067+36=1103 байт.
Вот специально только что проверил: файлы созданные D3D и напрямую через FCI API совпадают побайтово с точностью до заголовка.
>Обычный makecab жмет тестовую иконку до 324 байт
Что за параметры у makecab? У меня на разных операционках всегда получается 1059 байт.
И вообще 324 байта выглядят сомнительно: https://imgur.com/a/tHfODUj
ManHunter
(12.02.2024 в 21:06):
Только степень сжатия получается далеко не cab'овская. Обычный makecab жмет тестовую иконку до 324 байт, это даже если не учитывать 32+4 байта заголовка D3D.
А вот если исходный файл переименовать в "S0000!" и упаковать makecab, а потом слепить с заголовком, то такой бутерброд будет прекрасно распаковываться через D3DDecompressShaders.
А вот если исходный файл переименовать в "S0000!" и упаковать makecab, а потом слепить с заголовком, то такой бутерброд будет прекрасно распаковываться через D3DDecompressShaders.
DRON
(12.02.2024 в 19:07):
Нет в природе никакого D3D сжатия: это всего лишь CAB-архив с приклеенным к нему заголовком в ~36 байт.
Потому и маленькие файлы плохо сжимаются: там не только заголовок CAB-архива плюс заголовок файла в нём, но и этот D3D заголовок.
Потому и маленькие файлы плохо сжимаются: там не только заголовок CAB-архива плюс заголовок файла в нём, но и этот D3D заголовок.
Добавить комментарий
Заполните форму для добавления комментария