Kailo
Участник
- Сообщения
- 194
- Реакции
- 896
Для тех, кого не интересует урок, а нужна только программа, переходите сразу к разделу Программа.
Урок
Продолжим нашу одиссею по внутренностям smx.
Теперь, когда мы знаем структуру smx файлов, было бы не плохо использовать полученные нами знания. И начнем мы со снятия шифровки smx файлов. Важно отметить, что даже без сжатия файл является корректным и может использоваться на сервере.
Напомню, из прошлой статьи мы узнали, что информация в smx файле подвергнута сжатию по алгоритму deflate. Данный алгоритм используется в gzip, но наш файл не соответствует формату gzip, так что он нам не подходит.
Оффтоп
И так, сначала определим порядок действий нашей программы:
1) Получаем путь к файлу, у которого следует убрать сжатие.
2) Открываем файл, получаем его размер и проверяем его на соответствие:
Нам требуется какая-либо реализация алгоритма deflate/inflate), иногда же его называют gzip. К примеру в Lysis от Peace-Maker, используются стандартные методы языка Java, но я пишу свою программу на C++ (в среде Visual Studio Community 2017), у которого нет реализации gzip, так что я решил использовать библиотеку zlib. Тут я к сожалению столкнулся с некоторыми трудностями, т.к. готовых статических версий библиотеки они не предоставляют, а с динамической много проблем и неудобств (компилятор SP так же использует статический метод, а точнее просто копирует необходимые файлы в проект). Так что, я создал отдельный проект статической библиотеки zlib в своем решении, и закинул в него необходимые файлы из исходников zlib 1.2.11. Теперь продолжим:
Теперь немного пояснений, Bytef тип эквивалентный unsigned char, uLongf - unsigned long.
dest - указатель на буфер, куда будет записываться результат
destLen - указатель на переменную, которая хранит размер этого буфера. Указатель т.к. в конце работы она будет перезаписана, и будет указывать размер данных полученных после работы алгоритма.
source - указатель на исходные данные
sourceLen - размер исходных данных
I) Определяем размер данных после снятия сжатия (uncompressedSize), как размер файла без сжатия с вычетом заголовка, imagesize - dataoffs;
II) Выделяем буфер под данные размером uncompressedSize;
III) Получаем указатель на данные, которые нужно разжать, для этого к указателю на начала файла прибавляем смещение до данных: buffer + dataoffs;
IV) Определяем размер данных для разжатия как размер файла за вычетом заголовка, disksize - dataoffs;
V) Запускаем работу алгоритма и потом проверяем, успешно ли выполнено разжатие;
VI) Изменяем значения переменных заголовка, обновляем значения размера (disksize) и сжатия (compression);
VII) Я решил сделать вывод результата без замены исходного файла в uncompressed.smx - записываем измененный заголовок прежнего файла и данные полученные после разжатия.
Здесь аналогичные параметры, только добавляется level - уровень сжатия.
Используется Z_BEST_COMPRESSION, т.к. так же делает оригинальный компилятор.
Для того что бы узнать максимальный требуемый размер буфера данных после сжатия используем
sourceLen - размер данных до сжатия.
I) Определяем размер данных до сжатия (uncompressedSize): disksize - dataoffs;
II) Получаем указатель на данные, которые требуется сжать: buffer + dataoffs;
III) Определяем размер буфера (compressedSize) с помощью compressBound(uncompressedSize);
IV) Выделяем буфер под данные размером compressedSize;
V) Запускаем работу алгоритма и потом проверяем, успешно ли выполнено сжатие;
VI) Изменяем значения переменных заголовка, обновляем значения размера (disksize) и сжатия (compression);
VII) Вывод делается в compressed.smx - записываем измененный заголовок прежнего файла и данные полученные после сжатия.
Советы:
Было важно, чтобы файлы при открытии имели флаг binary (бинарный режим работы с файлом).
Продолжение серии уроков:
продолжение следует...
Можете попрактиковаться в программировании и написать себе такую же программу на нужном вам языке.
Программа
Сжатие будет убрано, если присутствует, и добавлено, если отсутствует.
Использование:
Имя файла передается 1-ым параметром:
Совет: Достаточно будет перетащить мышкой требуемый файл на Decompressor.exe.
В результате работы программы создается uncompressed.smx, если происходит снятие сжатия, или compressed.smx, если происходит добавление сжатия.
Результаты моей работы вы можете на посмотреть на GitHub:
Загрузка готового .exe (windows): Releases · Kailo97/Decompressor · GitHub
Исходные файлы: GitHub - Kailo97/Decompressor: (De)compressor for sourcemod's smx files
Урок
Продолжим нашу одиссею по внутренностям smx.
Теперь, когда мы знаем структуру smx файлов, было бы не плохо использовать полученные нами знания. И начнем мы со снятия шифровки smx файлов. Важно отметить, что даже без сжатия файл является корректным и может использоваться на сервере.
Напомню, из прошлой статьи мы узнали, что информация в smx файле подвергнута сжатию по алгоритму deflate. Данный алгоритм используется в gzip, но наш файл не соответствует формату gzip, так что он нам не подходит.
Оффтоп
Но я все же слышал о людях, которые копируют из smx файла сжатую часть в отдельный файл и прогоняют через gzip, а потом результат возвращают обратно в smx. Что же, тоже вариант, только много мороки, и надо не забыть отредактировать заголовок, но теперь я им точно облегчу жизнь.
И так, сначала определим порядок действий нашей программы:
1) Получаем путь к файлу, у которого следует убрать сжатие.
2) Открываем файл, получаем его размер и проверяем его на соответствие:
a) Размер как минимум больше заголовка;
б) Magic файла соответствует требуемому.
3) Проводим проверку корректности заголовка:б) Magic файла соответствует требуемому.
а) Реальный размер (length) соответствует указному действительному размеру (disksize) в заголовке;
б) Адрес начала данных (dataoffs) меньше реального размера и больше размера заголовка (sizeof(sp_file_hdr_t));
в) Размер файла без сжатия (imagesize) больше чем адрес начала данных.
4) Когда мы убедились в правильности файла (более-менее), проверяем текущие состояние сжатия файла (compression), и в зависимости от этого действуем дальше. Но сначала немного о сжатии и реализации.б) Адрес начала данных (dataoffs) меньше реального размера и больше размера заголовка (sizeof(sp_file_hdr_t));
в) Размер файла без сжатия (imagesize) больше чем адрес начала данных.
Нам требуется какая-либо реализация алгоритма deflate/inflate), иногда же его называют gzip. К примеру в Lysis от Peace-Maker, используются стандартные методы языка Java, но я пишу свою программу на C++ (в среде Visual Studio Community 2017), у которого нет реализации gzip, так что я решил использовать библиотеку zlib. Тут я к сожалению столкнулся с некоторыми трудностями, т.к. готовых статических версий библиотеки они не предоставляют, а с динамической много проблем и неудобств (компилятор SP так же использует статический метод, а точнее просто копирует необходимые файлы в проект). Так что, я создал отдельный проект статической библиотеки zlib в своем решении, и закинул в него необходимые файлы из исходников zlib 1.2.11. Теперь продолжим:
а) Если наш файл сжат по алгоритму gzip (compression == 1):
Функция для разжатия имеет следующей прототип:
PHP:
ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen));
dest - указатель на буфер, куда будет записываться результат
destLen - указатель на переменную, которая хранит размер этого буфера. Указатель т.к. в конце работы она будет перезаписана, и будет указывать размер данных полученных после работы алгоритма.
source - указатель на исходные данные
sourceLen - размер исходных данных
I) Определяем размер данных после снятия сжатия (uncompressedSize), как размер файла без сжатия с вычетом заголовка, imagesize - dataoffs;
II) Выделяем буфер под данные размером uncompressedSize;
III) Получаем указатель на данные, которые нужно разжать, для этого к указателю на начала файла прибавляем смещение до данных: buffer + dataoffs;
IV) Определяем размер данных для разжатия как размер файла за вычетом заголовка, disksize - dataoffs;
V) Запускаем работу алгоритма и потом проверяем, успешно ли выполнено разжатие;
VI) Изменяем значения переменных заголовка, обновляем значения размера (disksize) и сжатия (compression);
VII) Я решил сделать вывод результата без замены исходного файла в uncompressed.smx - записываем измененный заголовок прежнего файла и данные полученные после разжатия.
б) Если наш файл не имеет сжатия:
PHP:
ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level));
Используется Z_BEST_COMPRESSION, т.к. так же делает оригинальный компилятор.
Для того что бы узнать максимальный требуемый размер буфера данных после сжатия используем
PHP:
ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
I) Определяем размер данных до сжатия (uncompressedSize): disksize - dataoffs;
II) Получаем указатель на данные, которые требуется сжать: buffer + dataoffs;
III) Определяем размер буфера (compressedSize) с помощью compressBound(uncompressedSize);
IV) Выделяем буфер под данные размером compressedSize;
V) Запускаем работу алгоритма и потом проверяем, успешно ли выполнено сжатие;
VI) Изменяем значения переменных заголовка, обновляем значения размера (disksize) и сжатия (compression);
VII) Вывод делается в compressed.smx - записываем измененный заголовок прежнего файла и данные полученные после сжатия.
в) А если файл имеет не известный нам тип сжатия, ни чего поделать мы не может и выдаем сообщение об этом.
5) В конце работы программы не забываем отчищать память за собой, если требуется.Советы:
Было важно, чтобы файлы при открытии имели флаг binary (бинарный режим работы с файлом).
Продолжение серии уроков:
продолжение следует...
Можете попрактиковаться в программировании и написать себе такую же программу на нужном вам языке.
Программа
Сжатие будет убрано, если присутствует, и добавлено, если отсутствует.
Использование:
Имя файла передается 1-ым параметром:
C-подобный:
Decompressor.exe <smx file>
В результате работы программы создается uncompressed.smx, если происходит снятие сжатия, или compressed.smx, если происходит добавление сжатия.
Результаты моей работы вы можете на посмотреть на GitHub:
Загрузка готового .exe (windows): Releases · Kailo97/Decompressor · GitHub
Исходные файлы: GitHub - Kailo97/Decompressor: (De)compressor for sourcemod's smx files
Последнее редактирование: