![]() |
Добро пожаловать, гость ( Вход | Регистрация )
![]() |
-=CHE@TER=- |
![]()
Сообщение
#1
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,371 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 318 раз(а) ![]() |
Delphi programs in API.
На английском. Очень подробно всё описано, плюс есть исходные коды готовых юнитов. Например SmallUtil, в котором есть все частоиспользуемые подпрограммы, и который в размере меньше, чем SysUtils (автор так утверждает - я не проверял). |
![]() ![]() |
-=CHE@TER=- |
![]()
Сообщение
#2
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,371 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 318 раз(а) ![]() |
Недавно я тут писал про утилиту COMPRESS.EXE, сжимающую файлы.
Конечно, сжатие весьма посредственное (мы сейчас рассматриваем классический алгоритм LZSS, а не MS-ZIP, который туда добавили позже) и хорошо жмёт только файлы где есть длинные последовательности из повторяющихся байт, но в общем и целом для некоторых вещей вполне себе подойдёт. Тут главный плюс в том, что распаковщик короткий, легко пишется и не требует дополнительной памяти (ну 4 Кб на циклический буфер - это крохи). Так что можно использовать этот архиватор и созданные им файлы для своих нужд. Но, для начала, давайте взглянем на то, как сжатые файлы создаются. Итак, делаем: COMPRESS.EXE FILENAME.EXT FILENAME.EX_ Что происходит после выполнения этой команды? 1) Создаётся файл FILENAME.EX_ 2) Туда пишется следующий заголовок: CODE CHAR[8] - signature "SZDD\x88\xF0\x27\x33" CHAR - compression algo type - always 'A' (0x41) CHAR - last char of uncompressed file name (example: "test.xyz" -> 'z'); may be null DWORD - unpacked file size Итого, заголовок у нас занимает 14 байт. Отдельно хочу сделать замечание по поводу поля "algo type" (алгоритм сжатия). Если кто-то видел в Интернете исходные коды Windows 2000, то там можно было увидеть такое: CODE #define ALG_FIRST ((BYTE) 'A') // first version algorithm label for Lempel-Ziv #define ALG_LZ ((BYTE) 'B') // new Lempel-Ziv algorithm label #define ALG_LZA ((BYTE) 'C') // Lempel-Ziv with arithmetic encoding algorithm label Однако, сразу после этого шёл define объявлявший валидным только первый алгоритм. Так что на практике первые два поля в заголовке архива - константы и можно смело проверять даже не 8, а первые 9 байт. Поле "last char" утилитой EXPAND.EXE тоже не используется, а COMPRESS.EXE пишет туда ноль (или я так и не понял, как сделать, чтобы оно работало). Так что его можно игнорировать, если, конечно, вы сами не создавали архив и сами же его не распаковываете (точно зная, что поле не пустое). Далее идёт размер распакованного файла и всё. Хочу обратить на это внимание - в архиве нигде не содержится размер сжатых данных - файл читается, пока размер распакованного буфера не достигнет размера распакованного файла из заголовка. 3) В файл пишется упакованное содержимое. 4) Файлу-архиву ставится дата исходного файла - таким "оригинальным образом" в Microsoft сохраняют дату создания файла. Поясню: при распаковке извлечённому файлу выставляется (восстанавливается) дата с файла-архива. Ну вот, теперь мы знаем как это работает и устроено, так что можем делать архивы, линковать в ресурсы к своим программам и "на лету" распаковывать. Вот небольшой код на Delphi делающий распаковку (я переписал его с Си - см. ссылку). Вызывать так: MSLZSSExpandBuff(PackedBuffer, UnpackedBuffer, PackedBufferSize, UnpackedBufferSize); CODE { ported from: http://gnuwin32.sourceforge.net/packages/mscompress.htm } Function MSLZSSGetByte(Var P: Pointer; Var Ps: DWORD): Integer; Begin If Ps > 0 Then Begin result:=Byte(P^); Ps:=Ps - 1; Inc(DWORD(P)); End Else result:=-1; End; Function MSLZSSPutByte(Var U: Pointer; Var Us: DWORD; B: Byte): Boolean; Begin result:=(Us > 0); If result Then Begin Byte(U^):=B; Us:=Us - 1; Inc(DWORD(U)); End; End; Procedure MSLZSSExpandBuff(P, U: Pointer; Ps, Us: DWORD); Var I, J, Len, M, B: Integer; Buff: Array[0..$FFF] Of Byte; Begin FillChar(buff[0], $FFF + 1, 32); I:=($FFF + 1) - 16; While ((Ps > 0) And (Us > 0)) Do Begin B:=MSLZSSGetByte(P, Ps); If B = -1 Then Break; For M:=0 To 7 Do Begin If (B And 1) = 0 Then Begin J:=MSLZSSGetByte(P, Ps); If J = -1 Then Break; Len:=MSLZSSGetByte(P, Ps); If Len = -1 Then Break; J:=J + ((Len And $F0) ShL 4); Len:=(Len And $0F) + 3; While Len > 0 Do Begin Buff[I]:=Buff[J]; If MSLZSSPutByte(U, Us, Buff[I]) = False Then Break; J:=(J + 1) And $FFF; I:=(I + 1) And $FFF; Len:=Len - 1; End; End Else Begin J:=MSLZSSGetByte(P, Ps); If J = -1 Then Break; Buff[I]:=J; If MSLZSSPutByte(U, Us, Buff[I]) = False Then Break; I:=(I + 1) And $FFF; End; B:=B ShR 1; End; // For End; // While End; Спасибо сказали:
|
![]() ![]() |
Упрощённая версия | Сейчас: 30th April 2025 - 21:01 |